updated readme to improve documentation
This commit is contained in:
parent
c2b86b7f4d
commit
87b11cff7a
1 changed files with 103 additions and 41 deletions
144
Readme.md
144
Readme.md
|
|
@ -2,86 +2,147 @@
|
||||||
Syntactically Homogeneous Shell
|
Syntactically Homogeneous Shell
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
This shell was created to have extremely simple syntax. S-Expressions were chosen to represent statements and the scope of language features were constrained to what could be considered practical for daily shell use. This program is meant to be practical for administrators and daily power users. It can be used for both system administration (as one might use bash or zsh) as well as for the creation of simple programs.
|
This shell was created to have extremely simple syntax. S-Expressions were chosen to represent statements and the scope of the language features were constrained to what could be considered practical for daily shell use. This program is meant to be practical for administrators and daily power users. It can be used for both system administration (as one might use bash or zsh) as well as for the creation of simple programs as one might use Python, Racket, or Visual Basic.
|
||||||
|
|
||||||
## Basic Syntax
|
## Basic Syntax
|
||||||
When in doubt the `print_ast` utility can be used to examine the output of the Lex+Parse process. Here you can spot any bugs regarding syntax.
|
When in doubt the `print_ast` utility can be used to examine the output of the Lexing and Parsing process. Here you can spot any bugs regarding syntax.
|
||||||
|
`$ print_ast (example invocation`
|
||||||
|
|
||||||
### Lists
|
### Lists
|
||||||
Any sequence of items within a set of parenthesis is a list
|
Any sequence of items within a set of parenthesis is a list.
|
||||||
`(1 "two" three 4)`
|
|
||||||
|
|
||||||
Lists can be infinitely nested
|
For Example: `(1 "two" three 4)`
|
||||||
`("one" (2 3 4 (5)))`
|
|
||||||
|
Lists can be infinitely nested: `("one" (2 3 4 (5)))`
|
||||||
|
|
||||||
### Data types
|
### Data types
|
||||||
We use the following data types
|
Elements in a list can be one of the following data types:
|
||||||
* Number: 1, 2.0, etc
|
* **Number**: A number can be written in one of the following formats:
|
||||||
* String: "this is a string" (string delimiters: ' " \`)
|
- integers: 1, 2, 3, etc...
|
||||||
* Bool: T or F
|
- rational numbers: 1.22, 2.24, etc...
|
||||||
* Symbol: a string with no delimiters
|
* **String**: Strings must use one of the following delimiters:
|
||||||
* List: a sequence of elements within parenthesis
|
- "this string is a proper string"
|
||||||
|
- 'this is also a proper string'
|
||||||
|
- \` this is another proper string\`
|
||||||
|
* **Boolean**: Boolean values can take the following forms:
|
||||||
|
- true: "T"
|
||||||
|
- false: "F"
|
||||||
|
* **Symbol**:
|
||||||
|
- A symbol looks like a string without delimiters.
|
||||||
|
- A symbol denotes a variable or a function.
|
||||||
|
* **List**: Any combination of multiple items seperated by a space.
|
||||||
|
|
||||||
### Function calls
|
### Function calls
|
||||||
Any list beginning in a symbol will be considered a function call.
|
Any list beginning in a symbol will be considered a function call. This departs from traditional lisps, and a user may typically expect to be able to start a list with a variable. Given the current architecture this pattern must be maintained in order to enable shell functionality. Thus, from within the `shs_repl` utility unknown symbols will be assumed to be system binaries.
|
||||||
From within the `shs_repl` utility, unknown symbols will be assumed to be system binaries.
|
|
||||||
|
|
||||||
`(append () 1 2 3)`
|
Function call: `(append () 1 2 3)`
|
||||||
`(vim Readme.md)`
|
|
||||||
`(if (eq "example" (fread 'test_file')) (print "test worked) (rm -rf /))`
|
System binary call: `(vim Readme.md)`
|
||||||
|
|
||||||
|
Control flow statement (enabled by function call): `(if (eq "example" (fread 'test_file')) (print "test worked) (rm -rf /))`
|
||||||
|
|
||||||
|
There may be alternative REPLs, officially or from community members, that do not exhibit this behavior.
|
||||||
|
|
||||||
### Variable declaration
|
### Variable declaration
|
||||||
There are a few ways to export variables
|
Export is used to define variables.
|
||||||
* export: `(export NAME (value))`
|
|
||||||
* let: `(let ((var1 val1) (var2 val2)) (form_to_be_evaluated))`
|
|
||||||
|
|
||||||
Currently, let has yet to be implemented
|
`(export NAME (value))`
|
||||||
|
|
||||||
|
Users may also leverage the `export` function to create aliases in the SHS shell.
|
||||||
|
|
||||||
|
```
|
||||||
|
(export vim nvim)
|
||||||
|
(vim /path/to/file.c)
|
||||||
|
```
|
||||||
|
|
||||||
|
The above example will call exec with the arguments "nvim" and "/path/to/file.c".
|
||||||
|
|
||||||
### Function declaration
|
### Function declaration
|
||||||
Use the `func` function from the stdlib:
|
Use the `func` function from the stdlib:
|
||||||
`(func name (var1, var2, var3) (form_to_be_evaluated))`
|
|
||||||
In this case, `(form_to_be_evaluated)` will not be evaluated until the function is called.
|
Example call: `(func name (var1, var2, var3) (form_to_be_evaluated))`
|
||||||
|
|
||||||
|
In the above example, a function is defined with the following attributes:
|
||||||
|
- The function is named "name".
|
||||||
|
- The function takes three arguments: arg1, arg2, and arg3.
|
||||||
|
- When the function is called, "(form_to_be_evaluated)" is evaluated.
|
||||||
|
|
||||||
|
SHS will only lex (form_to_be_evaluated). It will not parse or execute it until the function is invoked.
|
||||||
|
|
||||||
|
In the below example a function named addthree is defined. The function takes three arguments, and returns the sum of them.
|
||||||
|
|
||||||
|
```
|
||||||
|
(func addthree (a b c) (+ a b c))
|
||||||
|
(addthree 2 3 4)
|
||||||
|
Output: 9
|
||||||
|
```
|
||||||
|
|
||||||
### Control flow
|
### Control flow
|
||||||
See `stdlib/control_flow.go`. We have if, while, and progn forms:
|
SHS currently uses the following control flow forms for daily use. Although, it is not hard to create your own in the SHS source code.
|
||||||
`(if (cond) (then) (else))`
|
#### if statements
|
||||||
`(when (cond) (form1)....... (formN))`
|
The if form takes 3 arguments. It evaluates the first (the condition) if it evaluates to true (T) it evaluates the second argument. If the first argument evaluates to false (F) the `if` routine then evaluates the third argument. The argument that is not used will not be parsed or evaluated. The whole statement will, however, be lexed.
|
||||||
`(progn (form1)..... (formN))`
|
|
||||||
If and While should be self explanatory. For those new to LISP, the rough idea of progn is to evaluate a sequence of N forms and return the result of the final one.
|
```
|
||||||
We also have functioning implementations of map and reduce in the stdlib (incomplete)
|
(if (cond) (then) (else))
|
||||||
|
(if (= 1 1.0) (print "numbers are equal") (print "numbers are not equal"))
|
||||||
|
```
|
||||||
|
|
||||||
|
#### while loops
|
||||||
|
The while loop takes N arguments. The first argument, the conditional, must evaluate to a boolean value (T or F). If the first argument is evaluated to T, all subsequent arguments are evaluated. If the first argument evaluates to F, while returns. Finally, the conditional is re-evaluated and the loop begins again.
|
||||||
|
|
||||||
|
```
|
||||||
|
(while (cond) (form1)....... (formN))
|
||||||
|
|
||||||
|
(export iter 1)
|
||||||
|
(while (< iter 4)
|
||||||
|
(print (concat "current iteration: "
|
||||||
|
(string iter)))
|
||||||
|
(export iter
|
||||||
|
(+ iter 1)))
|
||||||
|
|
||||||
|
Output:
|
||||||
|
current iteration: 1
|
||||||
|
current iteration: 2
|
||||||
|
current iteration: 3
|
||||||
|
```
|
||||||
|
|
||||||
## Comments
|
## Comments
|
||||||
The standard delimiter for comments is ;
|
The standard delimiter for comments is ;
|
||||||
any characters after a semicolon will be ignored until end of line
|
Any characters after a semicolon will be ignored until end of line. Semicolons found in strings will not be considered comment delimiters.
|
||||||
|
|
||||||
|
```
|
||||||
|
; this comment explains the value in myvar
|
||||||
|
(export myvar "testvar")
|
||||||
|
```
|
||||||
|
|
||||||
## How to build
|
## How to build
|
||||||
### Compiling/Installation
|
### Compiling/Installation
|
||||||
- For now simply run `go install cmd/...` for each utility you wish to use. If you have GOPATH and GOBIN set it should be usable from PATH
|
- For now simply run `go install ./cmd/shs` for each utility you wish to use. If you have $GOPATH and $GOBIN set in your shell it should be usable with $PATH.
|
||||||
|
|
||||||
### Adding SHS to your application
|
### Adding SHS to your application
|
||||||
|
Here are some important tips for integrating an SHS REPL into another codebase.
|
||||||
|
|
||||||
* Make sure to set ast.SyncTablesWithOSEnviron, ast.ExecWhenFuncUndef. All of which control integrations with the underlying system.
|
* Make sure to set ast.SyncTablesWithOSEnviron, ast.ExecWhenFuncUndef. All of which control integrations with the underlying system.
|
||||||
- If you do not want the user to be able to set environment variables set ast.SyncTablesWithOSEnviron to false.
|
- If you do not want the user to be able to set environment variables set ast.SyncTablesWithOSEnviron to false.
|
||||||
- If you do not want the user to be able to call binaries from the host system, set ast.ExecWhenFuncUndef to false.
|
- If you do not want the user to be able to call binaries from the host system, set ast.ExecWhenFuncUndef to false.
|
||||||
- Get text you are interested in parsing
|
- Create a new VarTable and FuncTable (see ast/var_table.go and ast/func_table.go).
|
||||||
- Create a new VarTable and FuncTable (see ast/var_table.go and ast/func_table.go)
|
- Make sure to adhere to the terms and conditions stated in the GPLv3.
|
||||||
- Call `Lex(text)` on the `text` you want to evaluate to recieve a tree of parsed lexemes.
|
- *OVERRIDE THE STDLIB GenFuncTable FUNCTION.* You very likely do NOT want an available function to call system binaries in your embedded shell. Make sure the stdlib Call function is not included in your GenFuncTable inplementation.
|
||||||
- Call `tree.Eval(FuncTable, VarTable, false)` where tree is the returned data from Lex, and the final boolean argument is whether or not to convert unknown symbols to strings. (this is a helpful option if you are writing functions such as those in stdlib/call.go, or any funciton in which you may want to be able to edit and transform the final ast based on your own varaiable table)
|
|
||||||
- Make sure the GPLv3 is adhered to
|
|
||||||
- *OVERRIDE THE STDLIB GenFuncTable FUNCTION.* You very likely do NOT want an available function to call system binaries in your embedded shell. Make sure the stdlib Call function is not included.
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
* variables exported in the repl, if of types string or number, will result in a corresponding variable added to the Environment.
|
* Variables exported in the REPL, if of type string or number, will result in a corresponding environment variable.
|
||||||
* one can write arbitrary shs script into `.shsrc` including function and variable declarations
|
* One can write arbitrary shs script into `.shsrc` including function and variable declarations
|
||||||
* of note are the following variables
|
* Particularly useful are the following variables:
|
||||||
- `SH_LOGGING` Sets the log level (from 0 to 3)
|
- `SH_LOGGING` Sets the log level (from 0 to 3)
|
||||||
- `SHS_STATIC_PROMPT` Sets the prompt
|
- `SHS_STATIC_PROMPT` Sets the prompt
|
||||||
- `SH_HIST_FILE` Sets the history file
|
- `SH_HIST_FILE` Sets the history file
|
||||||
- `SH_DEBUG_MODE` Adds additional debug output for the lexer (high clutter)
|
- `SH_DEBUG_MODE` Adds additional debug output for the lexer (high clutter)
|
||||||
* additionally, the repl will evaluate any function you define as `_SH_PROMPT` before the shell prompt
|
* Additionally, the REPL will evaluate any function you define as `_SH_PROMPT` before the shell prompt.
|
||||||
- if defined, the function will be evaluated before printing the prompt
|
- if defined, the function will be evaluated before printing the prompt
|
||||||
- the function will be given 0 arguments
|
- the function will be given 0 arguments
|
||||||
- if the function does not return a string, its output will be discarded
|
- if the function does not return a string, its output will be discarded
|
||||||
- afterwards, the repl will print the values in `SHS_STATIC_PROMPT`
|
- afterwards, the repl will print the values in `SHS_STATIC_PROMPT`
|
||||||
|
|
||||||
Here is an example of a shs configuration file:
|
Here is an example of a shs configuration file:
|
||||||
```lisp
|
```lisp
|
||||||
(export GOPATH (concat HOME "/go"))
|
(export GOPATH (concat HOME "/go"))
|
||||||
|
|
@ -95,6 +156,7 @@ Here is an example of a shs configuration file:
|
||||||
```
|
```
|
||||||
|
|
||||||
## The Docs
|
## The Docs
|
||||||
|
What follows are links to documentation for the code and interfaces used by SHS. This documentation is automatically generated by godoc, and in times of transition may not be complete.
|
||||||
- [Documentation on language interpreter](https://godoc.org/gitlab.com/whom/shs/ast)
|
- [Documentation on language interpreter](https://godoc.org/gitlab.com/whom/shs/ast)
|
||||||
- [Documentation on logging module](https://godoc.org/gitlab.com/whom/shs/log)
|
- [Documentation on logging module](https://godoc.org/gitlab.com/whom/shs/log)
|
||||||
- [Documentation on configuration module](https://godoc.org/gitlab.com/whom/shs/config)
|
- [Documentation on configuration module](https://godoc.org/gitlab.com/whom/shs/config)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue