Updated readme's, add prototype function declaration operation
This commit is contained in:
parent
c90d445d7d
commit
19a16d8de0
5 changed files with 137 additions and 4 deletions
13
Readme.md
13
Readme.md
|
|
@ -47,18 +47,25 @@ See `stdlib/control_flow.go`. We have if and while forms:
|
|||
`(if (cond) (then) (else))`
|
||||
`(when (cond) (form1)....... (formN))`
|
||||
|
||||
We also have functioning implementations of map and reduce in the stdlib
|
||||
We also have functioning implementations of map and reduce in the stdlib (incomplete)
|
||||
|
||||
## How to build
|
||||
### 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
|
||||
|
||||
### Adding SHS to your application
|
||||
- TODO: write a how to here
|
||||
* 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 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)
|
||||
- Call `Lex(text)` on the `text` you want to evaluate to recieve a tree of parsed lexemes.
|
||||
- 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
|
||||
* variables exported in the repl, if of types string or number, will result in a corresponding variable added to the Environment.
|
||||
* one can write arbitrary shs script into `.shsrc` including function and variable declarations
|
||||
* of note are the following variables
|
||||
- `SH_LOGGING` Sets the log level (from 0 to 3)
|
||||
|
|
@ -72,7 +79,7 @@ Here is an example of a shs configuration file:
|
|||
(export "PATH" (concat PATH ":" GOBIN))
|
||||
(export "GIT_TERMINAL_PROMPT" 1)
|
||||
(export "SH_HIST_FILE" (concat HOME "/.shs_hist"))
|
||||
(export "SH_LOGGING" 3)
|
||||
(export "SH_LOGGING" 0)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
|
|
|||
|
|
@ -121,3 +121,15 @@ func DeleteVarTable(table VarTable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveVar(arg string, table VarTable) {
|
||||
if SyncTablesWithOSEnviron {
|
||||
err := os.Unsetenv(arg)
|
||||
if err != nil {
|
||||
log.Log(log.DEBUG,
|
||||
"Failed to remove "+arg+" from env: "+err.Error(),
|
||||
"vartable")
|
||||
}
|
||||
}
|
||||
delete(*table, arg)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ The standard library is loaded during the init step of the repl (or interpreter
|
|||
[Tokens](https://git.callpipe.com/aidan/shs/-/blob/master/ast/token.go) are a rudimentary linked list of parsed [Lexemes](https://en.wikipedia.org/wiki/Lexeme). In the ast package there are definitions for Tokens, as well as code for the combined Lex/Parse loop that creates them. Tokens are built in a way that makes operating over them with either recursive or iterative alrogithms easy. When consuming Tokens, one can expect their type by looking at the Tag field. The data stored in the Inner field will be either a string or a \*Token depending on what Tag is. You can expect a \*Token if the Tag field is ast.LIST, and a string in all other cases. If the Tag field is ast.SYMBOL you can look it up in the VarTable or the FuncTable. The VarTable will return either a \*Token (if the symbol is a Variable) or *nil* if nothing is found. The FuncTable will return either a \*Function (if there is a match) or it will return *nil*.
|
||||
P.S.: Ideally a token should not be re-used. You may consider them disposable. It is up to you to make sure that any Token you edit/reuse remains consistant with the type declared in its TAG. Make sure to differentiate between NUMBER and STRING with the `ast.StrIsNumber(arg string) bool` function.
|
||||
## Adding a function
|
||||
There are two ways to define functions: Either by writing it in shs code (using the 'func' function) or by extending the standard library. The steps below assume you are extending the standard library.
|
||||
1. *Write your function in the form of an `ast.Operation`.* Any function that has the defined signature can be an Operation.
|
||||
2. *Create a `Function` to encapsulate your `Operation`.* Make sure to set the `args` and `name` fields. Args will be used to validate function calls and Name will be used in debug/log output.
|
||||
3. *Add your `Function` to the `FuncTable`.* Make sure your `Operations`s get added to the table generated in `GenFuncTable`.
|
||||
|
|
|
|||
106
stdlib/funcs.go
Normal file
106
stdlib/funcs.go
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/* SHS: Syntactically Homogeneous Shell
|
||||
* Copyright (C) 2019 Aidan Hahn
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package stdlib
|
||||
|
||||
import (
|
||||
"gitlab.com/whom/shs/ast"
|
||||
"gitlab.com/whom/shs/log"
|
||||
)
|
||||
|
||||
func decl_func(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
name := input
|
||||
if name.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"non string handed to name arg",
|
||||
"func")
|
||||
return nil
|
||||
}
|
||||
|
||||
var numArgs int
|
||||
args := name.Next
|
||||
if args.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"argument 2 of func must be a flat list of argument symbols",
|
||||
"func")
|
||||
return nil
|
||||
}
|
||||
|
||||
form := args.Next
|
||||
if form.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"argument 3 of func must be a form to be evaluated",
|
||||
"func")
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := args.Expand(); i != nil; i = i.Next {
|
||||
if i.Tag != ast.SYMBOL {
|
||||
log.Log(log.ERR,
|
||||
"all args in user defined functions must be declared in the form of symbols",
|
||||
"func")
|
||||
return nil
|
||||
}
|
||||
numArgs += 1
|
||||
}
|
||||
|
||||
ASTSYNCSTATE := ast.SyncTablesWithOSEnviron
|
||||
inner := func(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil {
|
||||
log.Log(log.ERR,
|
||||
"error parsing arguments",
|
||||
name.Value())
|
||||
return nil
|
||||
}
|
||||
|
||||
ast.SyncTablesWithOSEnviron = false
|
||||
key_iter := args.Expand()
|
||||
val_iter := in
|
||||
|
||||
for key_iter != nil {
|
||||
if val_iter == nil {
|
||||
log.Log(log.ERR,
|
||||
"Not enough arguments supplied",
|
||||
name.Value())
|
||||
}
|
||||
|
||||
ast.SetVar(key_iter.Value(), val_iter, vt)
|
||||
key_iter = key_iter.Next
|
||||
val_iter = val_iter.Next
|
||||
}
|
||||
|
||||
ast.SyncTablesWithOSEnviron = ASTSYNCSTATE
|
||||
ret := form.Eval(ft, vt, false)
|
||||
ast.SyncTablesWithOSEnviron = false
|
||||
for i := args.Expand(); i != nil; i = i.Next {
|
||||
ast.RemoveVar(i.Value(), vt)
|
||||
}
|
||||
|
||||
ast.SyncTablesWithOSEnviron = ASTSYNCSTATE
|
||||
return ret
|
||||
}
|
||||
|
||||
(*funcs)[name.Value()] = &ast.Function{
|
||||
Function: inner,
|
||||
Name: name.Value(),
|
||||
TimesCalled: 0,
|
||||
Args: numArgs,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -48,6 +48,13 @@ func GenFuncTable() ast.FuncTable {
|
|||
Args: -1,
|
||||
},
|
||||
|
||||
"func": &ast.Function{
|
||||
Function: decl_func,
|
||||
Name: "decl_func",
|
||||
TimesCalled: 0,
|
||||
Args: 3,
|
||||
},
|
||||
|
||||
"export": &ast.Function{
|
||||
Function: export,
|
||||
Name: "export",
|
||||
|
|
@ -55,7 +62,7 @@ func GenFuncTable() ast.FuncTable {
|
|||
Args: 2,
|
||||
},
|
||||
|
||||
"input": &ast.Function{
|
||||
"input": &ast.Function{
|
||||
Function: input,
|
||||
Name: "input",
|
||||
TimesCalled: 0,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue