Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cesquivias/rash
A *nix shell written in Racket
https://github.com/cesquivias/rash
Last synced: 2 months ago
JSON representation
A *nix shell written in Racket
- Host: GitHub
- URL: https://github.com/cesquivias/rash
- Owner: cesquivias
- Created: 2014-09-11T06:45:15.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2016-12-21T05:30:34.000Z (about 8 years ago)
- Last Synced: 2024-08-03T22:06:07.965Z (6 months ago)
- Language: Racket
- Size: 21.5 KB
- Stars: 20
- Watchers: 5
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.org
Awesome Lists containing this project
- awesome-racket-and-scheme - rash
README
#+title: Racket Shell (rash)
#+options: num:nil html-postamble:nilRash is command line shell built on top of the Racket programming environment with the entire power of the platform available.
The default language is based on lisp. Language extensions can be loaded dynamically.
* Examples
#+begin_src shell-script
#!/usr/bin/env racket
#lang rashecho Hello World
echo "Hello in a string!"(~> (echo Piping Example) (wc -c))
#+end_src* Goals
- Take advantage of Racket's language capabilities to create an easy-to-use shell.
- An intuitive syntax that's memorable and doesn't require an [[http://www.tldp.org/LDP/abs/html/][38 chapter guide]].
- Extendable language through Racket's language creation libraries.* Non Goals
- Lean, mean memory usage
The Racket VM takes more memory than bash or other shells. All things being equal, a process should take as much memory as needed and no more but spending effort to cut down rash's memory usage isn't a priority.* Motivation
All current shells have a line when scripts become too complicated, and you need to switch from bash/zsh/fish to a more general purpose scripting language like Perl/Python/Ruby. Current shell languages provide robust programming environment to grow hackish, one-off scripts into large, robust programs.The switch to "scripting" languages has its own problems. Although you now have a language that provides useful data structures and paradigms for more complex problems, job control and process pipelining takes a backseat. Spawning processes and redirecting output become second-class citizens. If they weren't, why not use Python as a login shell?
Rash tries to bridge this gap using the Racket programming environment. Racket is uniquely positioned to tackle this problem. The programming environment is built with the purpose of creating domain specific languages (DSLs) to solve specific technical problems while still having the full power of Racket at your disposal. Rash is just a DSL in Racket specifically designed to be a command line shell; that is, it's emphasis is on spawning jobs and redirecting IO.
* Getting Started
** Installation
Rash requires the Racket programming environment[fn:1]. You can download the latest version from [[http://download.racket-lang.org/][Racket's download page]].
** Custom functions
You can expand Rash's functionality by writing your own custom functions. Racket's default syntax for creating functions works perfectly.
#+begin_src scheme
#!/usr/bin/env racket
#lang rash(define (racket-file? fname)
(string-ref fname ".rkt"))#+end_src
* Under the Hood
Rash is built from three abstraction layers. Each level removes some of Racket's complexity to focus on tasks done in a shell. From the topmost abstraction layer:
- Reader
- Module language
- Library
The reader and module language sections plugs into Racket's langauge creation tools. Read the [[http://docs.racket-lang.org/guide/languages.html][Creating Languages]] section of the [[http://docs.racket-lang.org/guide/index.html][Racket Guide]] for an introduction.
** Reader
The job of the reader is to take a stream of bytes and create an abstract syntax tree. Rash is different from Racket in that it uses newlines as a statement separator while Racket uses parentheses to delimit all expressions.Rash only has 3 main datatypes the reader handles:
- String :: Nearly all tokens read by the reader will be converted to a Racket string. For example, a simple line like =echo Hello world= is of strings.
- Symbol :: (Not Yet Implemented) When a token begins with $ it is a symbol. Symbols will be resolved later on as either a Racket variable or a system variable.
- Expression :: When Rash sees an open parenthesis it reads the input as a normal Racket s-expression. All the power of Racket is available here.
** Module Language
The module language level specifies how Rash expressions are evaluated and what the builtin functions are provided. Rash's evaluation is similar typical Racket but contains a sepcial twist: strings as procedures.From the [[Reader]] all top-level expressions that aren't variables or Racket expressions are read in as strings. Strings are used as paths to external programs. That is, when Rash sees you are trying to evaluate an procedure call with a string as a procedure it will look for an executable file with name in your PATH environment variable and start a process of that executable.[fn:2]
There are some special cases like the pipe operator (=~>=) that circumvent this.
The other duty of the module language is to provide all the necessary built-in functions that Rash provides to be a useful, convenient shell language. These builtins are functions like =cd=, =export= and other common shell builtins written at the library level.[fn:3] These builtins come from either Rash's library or from [[http://docs.racket-lang.org/reference/][Racket's standard library]]. Because Rash exposes [[http://docs.racket-lang.org/reference/require.html][=require=]], any other library or code written for the Racket environment is available in Rash.
** Library
At its lowest level, Rash is just a Racket library with convenience functions and macros to spawn a new process, pipe processes together. When using Rash, these functions are considered the builtins that do not spawn a new process.Because the whole power of Racket is available when using Rash, functionality that other shell environments have to provide are not implemented in Rash's library; those builtins like conditionals and loops are provided by Racket.
* Footnotes
[fn:1] TODO: Determine the minimum version of Racket required.
[fn:2] TODO: Handle absolute and relative paths for executables.
[fn:3] TODO: Provide link to doc page for all builtins.