/* 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 . */ package stdlib import ( "os" "fmt" "gitlab.com/whom/shs/ast" "gitlab.com/whom/shs/util" ) /* Makes a FuncTable from all functions in the stdlib * add your function here if you are extending the standard library */ func GenFuncTable() ast.FuncTable { var stdlib ast.FuncTable stdlib = &map[string]*ast.Function{ "if": &ast.Function{ Function: ShsIf, Name: "if", NumArgs: 3, EvalLazy: true, ArgLazy: true, }, "while": &ast.Function{ Function: ShsWhile, Name: "while", NumArgs: -1, EvalLazy: true, ArgLazy: true, }, "progn": &ast.Function{ Function: ShsProgn, Name: "shs_progn", NumArgs: -1, EvalLazy: true, ArgLazy: true, }, "func": &ast.Function{ Function: DeclFunc, Name: "decl_func", Args: []ast.Token_t{ ast.STRING, ast.LIST, ast.LIST, }, EvalLazy: true, }, "len": &ast.Function{ Function: Len, Name: "len", NumArgs: 1, ArgLazy: true, }, "head": &ast.Function{ Function: Head, Name: "head", Args: []ast.Token_t{ ast.LIST, }, }, "tail": &ast.Function{ Function: Tail, Name: "tail", Args: []ast.Token_t{ ast.LIST, }, }, "slice": &ast.Function{ Function: Slice, Name: "slice", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, ast.LIST, }, }, "export": &ast.Function{ Function: Export, Name: "export", EvalLazy: true, Args: []ast.Token_t{ ast.STRING, ast.LIST, }, }, "input": &ast.Function{ Function: Input, Name: "input", Args: []ast.Token_t{ ast.STRING, }, }, "load": &ast.Function{ Function: Load, Name: "load", Args: []ast.Token_t{ ast.STRING, }, }, "bool": &ast.Function{ Function: BoolCast, Name: "bool", Args: []ast.Token_t{ ast.STRING, }, }, "string": &ast.Function{ Function: StrCast, Name: "string", NumArgs: 1, ArgLazy: true, }, "number": &ast.Function{ Function: NumCast, Name: "number", Args: []ast.Token_t{ ast.NUMBER, }, }, "...": &ast.Function{ Function: Expand, Name: "...", Args: []ast.Token_t{ ast.LIST, }, }, "append": &ast.Function{ Function: L_append, Name: "append", NumArgs: -1, ArgLazy: true, }, "join": &ast.Function{ Function: Join, Name: "join", Args: []ast.Token_t{ ast.STRING, ast.LIST, }, }, "split": &ast.Function{ Function: Split, Name: "split", Args: []ast.Token_t{ ast.STRING, ast.STRING, }, }, "substr": &ast.Function{ Function: Substr, Name: "substr", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, ast.STRING, }, }, "exit": &ast.Function{ Function: ExitShell, Name: "exit", Args: []ast.Token_t{}, }, "eq": &ast.Function{ Function: Eq, Name: "==", NumArgs: 2, ArgLazy: true, }, "ne": &ast.Function{ Function: Ne, Name: "!=", NumArgs: 2, ArgLazy: true, }, "<": &ast.Function{ Function: Lt, Name: "<", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, }, }, ">": &ast.Function{ Function: Gt, Name: ">", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, }, }, "<=": &ast.Function{ Function: Lte, Name: "<=", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, }, }, ">=": &ast.Function{ Function: Gte, Name: ">=", Args: []ast.Token_t{ ast.NUMBER, ast.NUMBER, }, }, "!": &ast.Function{ Function: Not, Name: "!", Args: []ast.Token_t{ ast.BOOL, }, }, "+": &ast.Function{ Function: Add, Name: "add", NumArgs: -1, ArgLazy: true, }, "-": &ast.Function{ Function: Sub, Name: "sub", NumArgs: -1, ArgLazy: true, }, "*": &ast.Function{ Function: Mult, Name: "mult", NumArgs: -1, ArgLazy: true, }, "/": &ast.Function{ Function: Div, Name: "div", NumArgs: -1, ArgLazy: true, }, "cd": &ast.Function{ Function: Cd, Name: "changedir", Args: []ast.Token_t{ ast.STRING, }, }, "concat": &ast.Function{ Function: Concat, Name: "concatenate", NumArgs: -1, ArgLazy: true, }, "print": &ast.Function{ Function: PrintStr, Name: "print", Args: []ast.Token_t{ ast.STRING, }, }, "l": &ast.Function{ Function: Call, Name: "call", NumArgs: -1, ArgLazy: true, SymLazy: true, }, "bg": &ast.Function{ Function: Bgcall, Name: "background call", NumArgs: -1, ArgLazy: true, SymLazy: true, }, "fg": &ast.Function{ Function: Fg, Name: "foreground", Args: []ast.Token_t{ ast.NUMBER, }, }, "$": &ast.Function{ Function: ReadCmd, Name: "read cmd", NumArgs: -1, ArgLazy: true, SymLazy: true, }, "?": &ast.Function{ Function: GetExit, Name: "get exit code", Args: []ast.Token_t{}, }, /* USE NATIVE KILL COMMAND. "kill": &ast.Function{ Function: kill, Name: "kill job", Args: 1, }, */ "jobs": &ast.Function{ Function: Jobs, Name: "list jobs", Args: []ast.Token_t{}, }, "info": &ast.Function{ Function: ShInfo, Name: "Shell Info", Args: []ast.Token_t{ ast.SYMBOL, }, }, "fexists": &ast.Function{ Function: Fexists, Name: "file exists", Args: []ast.Token_t{ ast.STRING, }, }, "fread": &ast.Function{ Function: Fread, Name: "read file", Args: []ast.Token_t{ ast.STRING, }, }, "fwrite": &ast.Function{ Function: Fwrite, Name: "write file", Args: []ast.Token_t{ ast.STRING, ast.STRING, }, }, "fappend": &ast.Function{ Function: Fappend, Name: "append to file", Args: []ast.Token_t{ ast.STRING, ast.STRING, }, }, } return stdlib } /* takes no args * exits shell when called * * Example: (exit) */ func ExitShell(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { os.Exit(0) return nil // I hope execution doesnt get here } /* takes one arg, doesnt evaluate it * returns type or metadata * * Example: (info append) */ func ShInfo(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { repr := ast.GetVar(in.Value(), vt) if repr != nil { fmt.Printf("VARIABLE\nTYPE: %s\nVALUE: %s\n", ast.GetTagAsStr(repr.Tag), repr.Value()) return nil } funct := ast.GetFunction(in.Value(), ft) if funct != nil { fmt.Printf("FUNCTION\nNAME: %s\nTIMES CALLED: %s\n\n", funct.Name, funct.TimesCalled) if funct.ArgLazy { fmt.Printf("function does not evaluate args by type\nARG COUNT: %s\n", funct.NumArgs) } else { fmt.Printf("function evaluates args by type\nARGS: ") for _, i := range(funct.Args) { fmt.Printf(ast.GetTagAsStr(i)) } } fmt.Printf("SYMLAZY: %t\n", funct.SymLazy) fmt.Printf("(can undefined symbols be passed in)\n") fmt.Printf("EVALLAZY: %t\n", funct.EvalLazy) fmt.Printf("(are all forms in evaluated before function call)\n") return nil } fmt.Printf("UNKNOWN SYMBOL\n") return nil } /* Takes 1 arg, uses it as a prompt * errs if prompt is not a string or number * gets a line from stdin * returns it as a string * * Example: (print (input)) */ func Input(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { prompt := in.Value() var output string fmt.Printf(prompt) fmt.Scanln(&output) ret := &ast.Token{Tag: ast.STRING} ret.Set(output) return ret } /* Takes 1 arg, returns nil * if arg is a valid existing file than load will execute it as a script * * Example: (load "myscript.shs") */ func Load(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { bp := in.Value() bp = AbsPath(bp) util.LoadScript(bp, vt, ft) return nil }