perform arg type checking and evaluation before function call
This commit is contained in:
parent
90284f2d06
commit
ab340ceb0a
9 changed files with 223 additions and 354 deletions
|
|
@ -38,8 +38,18 @@ type Function struct {
|
|||
// number of times user has called this function
|
||||
TimesCalled int
|
||||
|
||||
// number of args required
|
||||
Args int
|
||||
// list of types (LIST, NUMBER, STRING, etc) representing args
|
||||
Args []Token_t
|
||||
NumArgs bool // -1 means infinite
|
||||
|
||||
// lazy arg checking (use NumArgs instead of args)
|
||||
ArgLazy bool
|
||||
|
||||
// dont fail on undefined symbol (passed to eval when parsing args)
|
||||
SymLazy bool
|
||||
|
||||
// dont eval args at all, leave that to the function
|
||||
EvalLazy bool
|
||||
}
|
||||
|
||||
/* holds a mapping of key to function
|
||||
|
|
@ -52,24 +62,52 @@ type FuncTable *map[string]*Function
|
|||
* makes sure correct arguments are passed in
|
||||
*/
|
||||
func (f Function) ParseFunction(args *Token) bool {
|
||||
// handle infinite args
|
||||
if f.Args < 0 {
|
||||
total = len(f.Args)
|
||||
for iter := args; iter != nil; iter = iter.Next {
|
||||
total -= 1
|
||||
if total <= 0 {
|
||||
log.Log(log.ERR,
|
||||
"too many arguments",
|
||||
"ftable")
|
||||
return false
|
||||
}
|
||||
|
||||
if iter.Tag != f.Args[len(f.Args) - total] {
|
||||
log.Log(log.ERR,
|
||||
"argument of type " + GetTagAsStr(iter.Tag) +
|
||||
"passed in when " + GetTagAsStr(f.Args[len(f.Args) - total]) +
|
||||
" was expected",
|
||||
"ftable")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
i := f.Args
|
||||
for iter := args; iter != nil; iter = iter.Next {
|
||||
i -= 1
|
||||
/* same as ParseFunction but only evaluates the number of args
|
||||
*/
|
||||
func (f Function) LazyParseFunction(args *Token) bool {
|
||||
if (f.NumArgs < 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
if i != 0 {
|
||||
total := 0
|
||||
for iter := args; iter != nil; iter = iter.Next {
|
||||
total += 1
|
||||
}
|
||||
|
||||
if total < f.NumArgs {
|
||||
log.Log(log.ERR,
|
||||
"Incorrect number of arguments",
|
||||
"eval")
|
||||
log.Log(log.DEBUG,
|
||||
fmt.Sprintf("Function %s expects %d arguments. You've provided %d arguments.",
|
||||
f.Name, f.Args, f.Args - i),
|
||||
"eval")
|
||||
"expected more arguments, try calling info on function",
|
||||
"ftable")
|
||||
return false
|
||||
}
|
||||
|
||||
if total > f.NumArgs {
|
||||
log.Log(log.ERR,
|
||||
"too many args. try calling info on function",
|
||||
"ftable")
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +118,18 @@ func (f Function) ParseFunction(args *Token) bool {
|
|||
* calls ParseFunction and increments TimesCalled
|
||||
*/
|
||||
func (f Function) CallFunction(args *Token, vt VarTable, ft FuncTable) *Token {
|
||||
if !f.ParseFunction(args) {
|
||||
if not f.EvalLazy {
|
||||
args = args.Eval(ft, vt, !f.SymLazy)
|
||||
}
|
||||
|
||||
passes := false
|
||||
if f.ArgsLazy {
|
||||
passes = LazyParseFunction(args)
|
||||
} else {
|
||||
passes = ParseFunction(args)
|
||||
}
|
||||
|
||||
if passes {
|
||||
log.Log(log.ERR,
|
||||
"Couldnt call " + f.Name,
|
||||
"eval")
|
||||
|
|
|
|||
|
|
@ -36,14 +36,6 @@ import (
|
|||
* Example: (number "3.4")
|
||||
*/
|
||||
func NumCast(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(f, a, false)
|
||||
if in.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"only a string can successfully be cast to a number",
|
||||
"number_cast")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !ast.StrIsNumber(in.Value()) {
|
||||
log.Log(log.ERR,
|
||||
"string failed number cast",
|
||||
|
|
@ -64,9 +56,6 @@ func NumCast(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
|||
*/
|
||||
func Add(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
||||
var res float64
|
||||
|
||||
in = in.Eval(f, a, false)
|
||||
|
||||
for i := in; i != nil; i = i.Next {
|
||||
if i.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR, "Non-number given to ADD", "add")
|
||||
|
|
@ -112,9 +101,6 @@ func Add(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
|||
func Sub(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
||||
var res float64
|
||||
var sub float64
|
||||
|
||||
in = in.Eval(f, a, false)
|
||||
|
||||
for i := in; i != nil; i = i.Next {
|
||||
if i.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR, "Non-number given to SUB", "sub")
|
||||
|
|
@ -166,9 +152,6 @@ func Sub(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
|||
*/
|
||||
func Mult(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
||||
res := 1.0
|
||||
|
||||
in = in.Eval(f, a, false)
|
||||
|
||||
for i := in; i != nil; i = i.Next {
|
||||
if i.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR, "Non-number given to MULT", "mult")
|
||||
|
|
@ -214,9 +197,6 @@ func Mult(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
|||
*/
|
||||
func Div(in *ast.Token, a ast.VarTable, f ast.FuncTable) *ast.Token {
|
||||
var res float64
|
||||
|
||||
in = in.Eval(f, a, false)
|
||||
|
||||
for i := in; i != nil; i = i.Next {
|
||||
inner := 0.0
|
||||
|
||||
|
|
|
|||
|
|
@ -30,14 +30,6 @@ import (
|
|||
* Example: (bool "F")
|
||||
*/
|
||||
func BoolCast(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in.Tag == ast.LIST || in.Tag == ast.NUMBER {
|
||||
log.Log(log.ERR,
|
||||
"only strings successfully cast to bool",
|
||||
"bool cast")
|
||||
return nil
|
||||
}
|
||||
|
||||
body := in.Value()
|
||||
if body != ast.TRUE && body != ast.FALSE {
|
||||
log.Log(log.ERR,
|
||||
|
|
@ -52,13 +44,6 @@ func BoolCast(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
}
|
||||
|
||||
func Not(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
|
||||
if in.Tag != ast.BOOL {
|
||||
log.Log(log.ERR, "non-bool argument to 'not'", "not")
|
||||
return nil
|
||||
}
|
||||
|
||||
out := ast.TRUE
|
||||
if in.Value() == ast.TRUE {
|
||||
out = ast.FALSE
|
||||
|
|
@ -69,10 +54,9 @@ func Not(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
return t
|
||||
}
|
||||
|
||||
// Lazy args this
|
||||
func Eq(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
out := ast.TRUE
|
||||
|
||||
in = in.Eval(ft, vt, false)
|
||||
second := in.Next
|
||||
|
||||
if in.Tag != second.Tag {
|
||||
|
|
@ -155,13 +139,6 @@ func Lt(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
out := ast.TRUE
|
||||
second := in.Next
|
||||
|
||||
in = in.Eval(ft, vt, false)
|
||||
|
||||
if in.Tag != ast.NUMBER || second.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR, "non-number argument to numeric boolean operator", ">/<=")
|
||||
return nil
|
||||
}
|
||||
|
||||
l, _ := strconv.ParseInt(in.Value(), 10, 64)
|
||||
r, _ := strconv.ParseInt(second.Value(), 10, 64)
|
||||
|
||||
|
|
@ -178,13 +155,6 @@ func Gt(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
out := ast.TRUE
|
||||
second := in.Next
|
||||
|
||||
in = in.Eval(ft, vt, false)
|
||||
|
||||
if in.Tag != ast.NUMBER || second.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR, "non-number argument to numeric boolean operator", ">/<=")
|
||||
return nil
|
||||
}
|
||||
|
||||
l, _ := strconv.ParseInt(in.Value(), 10, 64)
|
||||
r, _ := strconv.ParseInt(second.Value(), 10, 64)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,20 +54,6 @@ func AbsPath(arg string) string {
|
|||
* (cd (concat HOME "/go"))
|
||||
*/
|
||||
func Cd(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
|
||||
if in == nil {
|
||||
log.Log(log.ERR,
|
||||
"arguments to cd evaluated to nil!",
|
||||
"cd")
|
||||
return nil
|
||||
}
|
||||
|
||||
if in.Tag == ast.LIST {
|
||||
log.Log(log.ERR, "Couldnt change dir to a list", "cd")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := os.Chdir(in.Value())
|
||||
if err != nil {
|
||||
log.Log(log.ERR, err.Error(), "cd")
|
||||
|
|
@ -84,14 +70,6 @@ func Cd(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* (fexists test)
|
||||
*/
|
||||
func Fexists(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil || in.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"argument to fexists must be a string",
|
||||
"fexists")
|
||||
return nil
|
||||
}
|
||||
|
||||
filename := in.Value()
|
||||
out := ast.TRUE
|
||||
|
||||
|
|
@ -115,7 +93,6 @@ func Fexists(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* (fread (concat HOME ".shsrc"))
|
||||
*/
|
||||
func Fread(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
exists := Fexists(in, vt, ft) // some waste, extra use of Eval
|
||||
if exists == nil || exists.Tag != ast.BOOL || exists.Value() == ast.FALSE {
|
||||
log.Log(log.ERR,
|
||||
|
|
@ -146,26 +123,12 @@ func Fread(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* (fwrite "test" "one two three")
|
||||
*/
|
||||
func Fwrite(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil || in.Tag == ast.SYMBOL || in.Tag == ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"first argument must be a filename",
|
||||
"fwrite")
|
||||
return nil
|
||||
}
|
||||
|
||||
text := in.Next
|
||||
if text == nil || text.Tag == ast.SYMBOL || text.Tag == ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"second argument must be stringable",
|
||||
"fwrite")
|
||||
return nil
|
||||
}
|
||||
|
||||
err := ioutil.WriteFile(
|
||||
AbsPath(in.Value()),
|
||||
[]byte(text.Value()),
|
||||
0644)
|
||||
|
||||
if err != nil {
|
||||
log.Log(log.ERR,
|
||||
"error writing file: " + err.Error(),
|
||||
|
|
@ -183,22 +146,7 @@ func Fwrite(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* (fwrite "test" "one two three")
|
||||
*/
|
||||
func Fappend(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil || in.Tag == ast.SYMBOL || in.Tag == ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"first argument must be a filename",
|
||||
"fappend")
|
||||
return nil
|
||||
}
|
||||
|
||||
text := in.Next
|
||||
if text == nil || text.Tag == ast.SYMBOL || text.Tag == ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"second argument must be stringable",
|
||||
"fappend")
|
||||
return nil
|
||||
}
|
||||
|
||||
exists := Fexists(in, vt, ft)
|
||||
if exists.Value() == ast.FALSE {
|
||||
log.Log(log.ERR,
|
||||
|
|
@ -212,14 +160,15 @@ func Fappend(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
AbsPath(in.Value()),
|
||||
os.O_APPEND|os.O_CREATE|os.O_WRONLY,
|
||||
0644)
|
||||
|
||||
if err != nil {
|
||||
log.Log(log.ERR,
|
||||
"couldnt open file for append: " + err.Error(),
|
||||
"fappend")
|
||||
return nil
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
defer f.Close()
|
||||
if _, err := f.WriteString(text.Value()); err != nil {
|
||||
log.Log(log.ERR,
|
||||
"error appending to file: " + err.Error(),
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@ func DeclFunc(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Tok
|
|||
Function: inner,
|
||||
Name: name.Value(),
|
||||
TimesCalled: 0,
|
||||
Args: numArgs,
|
||||
NumArgs: numArgs,
|
||||
LazyArgs: true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,13 +30,7 @@ import (
|
|||
* in event a not-list is passed in, returns the arg.
|
||||
*/
|
||||
func Expand(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
if input.Tag != ast.LIST {
|
||||
log.Log(log.INFO, "expand called on not a list", "expand")
|
||||
return input
|
||||
}
|
||||
|
||||
return input.Eval(funcs, vars, false).Expand()
|
||||
return input.Expand()
|
||||
}
|
||||
|
||||
/* L_APPEND (append from repl)
|
||||
|
|
@ -45,7 +39,6 @@ func Expand(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token
|
|||
* if no args are a list, a list is made from all args
|
||||
*/
|
||||
func L_append(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
src := input
|
||||
|
||||
if input.Tag != ast.LIST {
|
||||
|
|
@ -74,25 +67,29 @@ func L_append(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Tok
|
|||
}
|
||||
|
||||
/* Len
|
||||
* Returns length of list as a number
|
||||
* Returns nil if not a list
|
||||
* Returns length of list or string as a number
|
||||
* Returns nil if not a list or string
|
||||
*
|
||||
* Example: () -> 0
|
||||
* Example: (1 2 3) -> 3
|
||||
*/
|
||||
func Len(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
if input.Tag != ast.LIST {
|
||||
if input.Tag != ast.LIST && input.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"non-list as parameter to head",
|
||||
"must provide list or strinig",
|
||||
"head")
|
||||
return nil
|
||||
}
|
||||
|
||||
length := 0
|
||||
if input.Tag = ast.STRING {
|
||||
length = len(input.Value())
|
||||
|
||||
} else {
|
||||
for iter := input.Expand(); iter != nil; iter = iter.Next {
|
||||
length += 1
|
||||
}
|
||||
}
|
||||
|
||||
ret := &ast.Token{Tag: ast.NUMBER}
|
||||
ret.Set(fmt.Sprintf("%d", length))
|
||||
|
|
@ -106,14 +103,6 @@ func Len(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
|||
* Example: (head (2 3 4)) -> 2
|
||||
*/
|
||||
func Head(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
if input.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"non-list as parameter to head",
|
||||
"head")
|
||||
return nil
|
||||
}
|
||||
|
||||
li := input.Expand().Copy()
|
||||
if li != nil {
|
||||
li.Next = nil
|
||||
|
|
@ -129,15 +118,6 @@ func Head(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
|||
* Example: (tail (2 3 4)) -> 4
|
||||
*/
|
||||
func Tail(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
if input.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"non-list as parameter to head",
|
||||
"head")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
iter := input.Expand()
|
||||
for iter != nil && iter.Next != nil {
|
||||
iter = iter.Next
|
||||
|
|
@ -158,25 +138,10 @@ func Tail(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
|||
* Example: (slice 0 0 (1 2 3)) -> (1)
|
||||
*/
|
||||
func Slice(input *ast.Token, vars ast.VarTable, funcs ast.FuncTable) *ast.Token {
|
||||
input = input.Eval(funcs, vars, false)
|
||||
start := input
|
||||
end := input.Next
|
||||
source := end.Next
|
||||
|
||||
if start.Tag != ast.NUMBER || end.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR,
|
||||
"start and end must both be integers",
|
||||
"slice")
|
||||
return nil
|
||||
}
|
||||
|
||||
if source.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"non-list as parameter to head",
|
||||
"head")
|
||||
return nil
|
||||
}
|
||||
|
||||
st, err := strconv.ParseInt(start.Value(), 10, 64)
|
||||
en, errr := strconv.ParseInt(end.Value(), 10, 64)
|
||||
|
||||
|
|
|
|||
|
|
@ -225,11 +225,6 @@ func LaunchProcess(
|
|||
* Example (l vim file.txt)
|
||||
*/
|
||||
func Call(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if in.Tag == ast.LIST {
|
||||
log.Log(log.ERR, "couldnt exec, target bin is a list", "call")
|
||||
return nil
|
||||
|
|
@ -261,11 +256,6 @@ func Call(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (bg vim file.txt)
|
||||
*/
|
||||
func Bgcall(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if in.Tag == ast.LIST {
|
||||
log.Log(log.ERR, "couldnt exec, target bin is a list", "call")
|
||||
return nil
|
||||
|
|
@ -304,14 +294,6 @@ func Fg(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
return nil
|
||||
}
|
||||
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in.Tag != ast.NUMBER && in.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"must supply a number or string to fg",
|
||||
"fg")
|
||||
return nil
|
||||
}
|
||||
|
||||
pid, err := strconv.ParseFloat(in.Value(), 64)
|
||||
if err != nil {
|
||||
log.Log(log.ERR,
|
||||
|
|
@ -374,12 +356,6 @@ func Jobs(in *ast.Token, vt ast.VarTable, fg ast.FuncTable) *ast.Token {
|
|||
* Example: ($ echo hello world)
|
||||
*/
|
||||
func ReadCmd(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if in.Tag == ast.LIST {
|
||||
log.Log(log.ERR, "couldnt exec, target bin is a list", "call")
|
||||
return nil
|
||||
|
|
@ -434,13 +410,6 @@ func GetExit(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* (this function not added to functable in stdlib.go)
|
||||
*/
|
||||
func Kill(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
|
||||
if in.Tag == ast.LIST {
|
||||
log.Log(log.ERR, "non-number argument to kill function", "kill")
|
||||
return nil
|
||||
}
|
||||
|
||||
pid, err := strconv.ParseInt(in.Value(), 10, 64)
|
||||
if err != nil {
|
||||
log.Log(log.ERR, "error parsing arg to kill: " + err.Error(), "kill")
|
||||
|
|
|
|||
243
stdlib/stdlib.go
243
stdlib/stdlib.go
|
|
@ -34,274 +34,314 @@ func GenFuncTable() ast.FuncTable {
|
|||
"if": &ast.Function{
|
||||
Function: ShsIf,
|
||||
Name: "if",
|
||||
TimesCalled: 0,
|
||||
Args: 3,
|
||||
NumArgs: 3,
|
||||
EvalLazy true,
|
||||
ArgLazy true
|
||||
},
|
||||
|
||||
"while": &ast.Function{
|
||||
Function: ShsWhile,
|
||||
Name: "while",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
EvalLazy true,
|
||||
ArgLazy true,
|
||||
},
|
||||
|
||||
"progn": &ast.Function{
|
||||
Function: ShsProgn,
|
||||
Name: "shs_progn",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
EvalLazy: true,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"func": &ast.Function{
|
||||
Function: DeclFunc,
|
||||
Name: "decl_func",
|
||||
TimesCalled: 0,
|
||||
Args: 3,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.LIST,
|
||||
ast.LIST
|
||||
},
|
||||
EvalLazy: true,
|
||||
},
|
||||
|
||||
"len": &ast.Function{
|
||||
Function: Len,
|
||||
Name: "len",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
NumArgs: 1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"head": &ast.Function{
|
||||
Function: Head,
|
||||
Name: "head",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"tail": &ast.Function{
|
||||
Function: Tail,
|
||||
Name: "tail",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"slice": &ast.Function{
|
||||
Function: Slice,
|
||||
Name: "slice",
|
||||
TimesCalled: 0,
|
||||
Args: 3,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER,
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"export": &ast.Function{
|
||||
Function: Export,
|
||||
Name: "export",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
LazyEval: true,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"input": &ast.Function{
|
||||
Function: Input,
|
||||
Name: "input",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"load": &ast.Function{
|
||||
Function: Load,
|
||||
Name: "load",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"bool": &ast.Function{
|
||||
Function: BoolCast,
|
||||
Name: "bool",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"string": &ast.Function{
|
||||
Function: StrCast,
|
||||
Name: "string",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
NumArgs: 1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"number": &ast.Function{
|
||||
Function: NumCast,
|
||||
Name: "number",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token{
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
"...": &ast.Function{
|
||||
Function: Expand,
|
||||
Name: "...",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"append": &ast.Function{
|
||||
Function: L_append,
|
||||
Name: "append",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"join": &ast.Function{
|
||||
Function: Join,
|
||||
Name: "join",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.LIST
|
||||
},
|
||||
},
|
||||
|
||||
"split": &ast.Function{
|
||||
Function: Split,
|
||||
Name: "split",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"substr": &ast.Function{
|
||||
Function: Substr,
|
||||
Name: "substr",
|
||||
TimesCalled: 0,
|
||||
Args: 3,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER,
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"exit": &ast.Function{
|
||||
Function: ExitShell,
|
||||
Name: "exit",
|
||||
TimesCalled: 0,
|
||||
Args: 0,
|
||||
Args: []ast.Token_t{},
|
||||
},
|
||||
|
||||
"eq": &ast.Function{
|
||||
Function: Eq,
|
||||
Name: "==",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"ne": &ast.Function{
|
||||
Function: Ne,
|
||||
Name: "!=",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"<": &ast.Function{
|
||||
Function: Lt,
|
||||
Name: "<",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
">": &ast.Function{
|
||||
Function: Gt,
|
||||
Name: ">",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
"<=": &ast.Function{
|
||||
Function: Lte,
|
||||
Name: "<=",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
">=": &ast.Function{
|
||||
Function: Gte,
|
||||
Name: ">=",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.NUMBER,
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
"!": &ast.Function{
|
||||
Function: Not,
|
||||
Name: "!",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.Bool
|
||||
},
|
||||
},
|
||||
|
||||
"+": &ast.Function{
|
||||
Function: Add,
|
||||
Name: "add",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"-": &ast.Function{
|
||||
Function: Sub,
|
||||
Name: "sub",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"*": &ast.Function{
|
||||
Function: Mult,
|
||||
Name: "mult",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"/": &ast.Function{
|
||||
Function: Div,
|
||||
Name: "div",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"cd": &ast.Function{
|
||||
Function: Cd,
|
||||
Name: "changedir",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"concat": &ast.Function{
|
||||
Function: Concat,
|
||||
Name:"concatenate",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
},
|
||||
|
||||
"print": &ast.Function{
|
||||
Function: PrintStr,
|
||||
Name: "print",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"l": &ast.Function{
|
||||
Function: Call,
|
||||
Name: "call",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
SymLazy: true,
|
||||
},
|
||||
|
||||
"bg": &ast.Function{
|
||||
Function: Bgcall,
|
||||
Name: "background call",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumArgs: -1,
|
||||
ArgLazy: true,
|
||||
SymLazy: true,
|
||||
},
|
||||
|
||||
"fg": &ast.Function{
|
||||
Function: Fg,
|
||||
Name: "foreground",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
NumArgs: []ast.Token_t{
|
||||
ast.NUMBER
|
||||
},
|
||||
},
|
||||
|
||||
"$": &ast.Function{
|
||||
Function: ReadCmd,
|
||||
Name: "read cmd",
|
||||
TimesCalled: 0,
|
||||
Args: -1,
|
||||
NumnArgs: -1,
|
||||
ArgLazy: true,
|
||||
SymLazy: true,
|
||||
},
|
||||
|
||||
"?": &ast.Function{
|
||||
Function: GetExit,
|
||||
Name:"get exit code",
|
||||
TimesCalled: 0,
|
||||
Args: 0,
|
||||
Args: ast.Token_t{},
|
||||
},
|
||||
|
||||
/*
|
||||
|
|
@ -309,7 +349,6 @@ func GenFuncTable() ast.FuncTable {
|
|||
"kill": &ast.Function{
|
||||
Function: kill,
|
||||
Name: "kill job",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
},
|
||||
*/
|
||||
|
|
@ -317,43 +356,49 @@ func GenFuncTable() ast.FuncTable {
|
|||
"jobs": &ast.Function{
|
||||
Function: Jobs,
|
||||
Name: "list jobs",
|
||||
TimesCalled: 0,
|
||||
Args: 0,
|
||||
Args: ast.Token_t{},
|
||||
},
|
||||
|
||||
"info": &ast.Function{
|
||||
Function: ShInfo,
|
||||
Name: "Shell Info",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: ast.Token_t{
|
||||
ast.SYMBOL
|
||||
},
|
||||
},
|
||||
|
||||
"fexists": &ast.Function{
|
||||
Function: Fexists,
|
||||
Name: "file exists",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"fread": &ast.Function{
|
||||
Function: Fread,
|
||||
Name: "read file",
|
||||
TimesCalled: 0,
|
||||
Args: 1,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"fwrite": &ast.Function{
|
||||
Function: Fwrite,
|
||||
Name: "write file",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
|
||||
"fappend": &ast.Function{
|
||||
Function: Fappend,
|
||||
Name:"append to file",
|
||||
TimesCalled: 0,
|
||||
Args: 2,
|
||||
Args: []ast.Token_t{
|
||||
ast.STRING,
|
||||
ast.STRING
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -395,10 +440,12 @@ func ShInfo(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
|
||||
funct := ast.GetFunction(in.Value(), ft)
|
||||
if funct != nil {
|
||||
fmt.Printf("FUNCTION\nNAME: %s\nTIMES CALLED: %s\nNUM ARGS: %d\n", funct.Name, funct.TimesCalled, funct.Args)
|
||||
fmt.Printf("FUNCTION\nNAME: %s\nTIMES CALLED: %s\nNUM ARGS: %d\n", funct.Name, funct.TimesCalled, funct.NumArgs)
|
||||
break
|
||||
}
|
||||
|
||||
// TODO: print func args
|
||||
|
||||
fmt.Printf("UNKNOWN SYMBOL\n")
|
||||
}
|
||||
|
||||
|
|
@ -413,14 +460,6 @@ func ShInfo(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (print (input))
|
||||
*/
|
||||
func Input(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in.Tag != ast.STRING && in.Tag != ast.NUMBER {
|
||||
log.Log(log.ERR,
|
||||
"argument to input must be a string or number",
|
||||
"input")
|
||||
return nil
|
||||
}
|
||||
|
||||
prompt := in.Value()
|
||||
var output string
|
||||
|
||||
|
|
@ -438,14 +477,6 @@ func Input(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (load "myscript.shs")
|
||||
*/
|
||||
func Load(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, true)
|
||||
if in.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"argument to load must be a string",
|
||||
"load")
|
||||
return nil
|
||||
}
|
||||
|
||||
bp := in.Value()
|
||||
bp = AbsPath(bp)
|
||||
util.LoadScript(bp, vt, ft)
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ import (
|
|||
* Example: (concat "hello" " " "world")
|
||||
*/
|
||||
func Concat(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
|
||||
var res string
|
||||
for i := in; i != nil; i = i.Next {
|
||||
if i.Tag == ast.LIST {
|
||||
|
|
@ -54,7 +52,7 @@ func Concat(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (string 1) -> 1.0
|
||||
*/
|
||||
func StrCast(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
body := in.Eval(ft, vt, false).String()
|
||||
body := in.String()
|
||||
res := &ast.Token{ Tag: ast.STRING }
|
||||
res.Set(body)
|
||||
return res
|
||||
|
|
@ -67,22 +65,8 @@ func StrCast(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (split "/path/to/file" "/") -> ("path" "to" "file")
|
||||
*/
|
||||
func Split(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil || in.Tag != ast.STRING || in.Next == nil || in.Next.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"Args must be two strings",
|
||||
"split")
|
||||
return nil
|
||||
}
|
||||
|
||||
body := in.Value()
|
||||
delim := in.Next.Value()
|
||||
if len(body) < len(delim) {
|
||||
log.Log(log.DEBUG,
|
||||
"possibly mismatched args" +
|
||||
"delimiter longer than body",
|
||||
"split")
|
||||
}
|
||||
|
||||
var res *ast.Token
|
||||
builder := &res
|
||||
|
|
@ -107,25 +91,11 @@ func Split(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (join ", " ("apple" "ananas" "pear")) -> "apple, ananas, pear"
|
||||
*/
|
||||
func Join(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
in = in.Eval(ft, vt, false)
|
||||
if in == nil || in.Next == nil {
|
||||
log.Log(log.ERR,
|
||||
"one or more arguments evaluated to nil",
|
||||
"join")
|
||||
return nil
|
||||
}
|
||||
|
||||
delim := in
|
||||
strs := in.Next
|
||||
if delim.Tag != ast.STRING || strs.Tag != ast.LIST {
|
||||
log.Log(log.ERR,
|
||||
"first argument must be a string (delimiter) and second argument must be a list (strings)",
|
||||
"join")
|
||||
return nil
|
||||
}
|
||||
|
||||
de := delim.Value()
|
||||
res := ""
|
||||
|
||||
for i := strs.Expand(); i != nil; i = i.Next {
|
||||
if i.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
|
|
@ -155,24 +125,9 @@ func Join(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (substr 1 5 "Linus Torvalds") -> "inus "
|
||||
*/
|
||||
func Substr(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
start := in.Eval(ft, vt, false)
|
||||
if start == nil || start.Next == nil || start.Next.Next == nil {
|
||||
log.Log(log.ERR,
|
||||
"an argument evaluated to nil",
|
||||
"substr")
|
||||
return nil
|
||||
}
|
||||
|
||||
end := start.Next
|
||||
str := end.Next
|
||||
|
||||
if start.Tag != ast.NUMBER || end.Tag != ast.NUMBER || str.Tag != ast.STRING {
|
||||
log.Log(log.ERR,
|
||||
"incorrect types of args",
|
||||
"substr")
|
||||
return nil
|
||||
}
|
||||
|
||||
ed_idx := 0
|
||||
st_idx, err := strconv.Atoi(start.Value())
|
||||
ed_idx, err = strconv.Atoi(end.Value())
|
||||
|
|
@ -226,7 +181,7 @@ func Substr(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
|||
* Example: (print "Line: \n, Tab: \t")
|
||||
*/
|
||||
func PrintStr(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token {
|
||||
body := in.Eval(ft, vt, false).String()
|
||||
body := in.String()
|
||||
if body[0] != body[len(body)-1] && body[0] != '"' {
|
||||
body = "`" + body + "`"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue