From a216d9af410cfabb3a30f94d8c0ffa059654cf0d Mon Sep 17 00:00:00 2001 From: Aidan Date: Tue, 30 Jun 2020 20:27:12 -0700 Subject: [PATCH] add rudimentary control flow --- ast/var_table.go | 7 ++++ stdlib/control_flow.go | 82 ++++++++++++++++++++++++++++++++++++++++++ stdlib/stdlib.go | 27 +++++++++++++- 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 stdlib/control_flow.go diff --git a/ast/var_table.go b/ast/var_table.go index ae0519a..4b91a18 100644 --- a/ast/var_table.go +++ b/ast/var_table.go @@ -91,6 +91,10 @@ func GetVarFromTables(arg string, library []VarTable) *Token { } func InitVarTable(table VarTable) { + if !SyncTablesWithOSEnviron { + return + } + for _, val := range os.Environ() { variable := strings.Split(val, "=") t := &Token{inner: variable[1]} @@ -100,6 +104,9 @@ func InitVarTable(table VarTable) { t.Tag = STRING } + if variable[0] == "HOME" { + SetVar('~', t, table) + } SetVar(variable[0], t, table) } } diff --git a/stdlib/control_flow.go b/stdlib/control_flow.go new file mode 100644 index 0000000..e937a17 --- /dev/null +++ b/stdlib/control_flow.go @@ -0,0 +1,82 @@ +/* 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 "gitlab.com/whom/shs/ast" + +/* return one evaluated form or another based on the boolean statement + */ +func shs_if(in *ast.Token, vt VarTable, ft FuncTable) *ast.Token { + cond := in + t := cond.Next + f := t.Next + cond.Next = nil + t.Next = nil + + cond = cond.Eval(ft, vt, false) + if cond == nil || cond.Tag != ast.BOOL { + log.Log(log.ERR, + "first argument to if must be a bool statement", + "if") + return nil + } + + switch cond.Value() { + case ast.TRUE: + return t + + case ast.FALSE: + return f + + default: + log.Log(log.ERR, + "improper bool!", + "if") + return nil + } +} + +/* continually eval n forms while element #1 evals to T + */ +func shs_while(in *ast.Token, vt VarTable, ft FuncTable) *ast.Token { + cond := in + forms := in.Next + in.Next = nil + var res *ast.Token + + eval := cond.Eval(ft, vt, false) + if cond == nil || cond.Tag != ast.BOOL { + log.Log(log.ERR, + "first argument to while must be a bool statement", + "while") + return nil + } + + // slight downside here: doesnt log when the wrong tag is set + for eval.Tag == ast.BOOL && eval.Value() == 'T' { + // eval all forms + for i := forms; i != nil; i = i.Next { + res = i.Eval(ft, vt, false) + } + + // retest eval + eval := cond.Eval(ft, vt, false) + } + + return res +} diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index 0bd2b40..f5cdd7d 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -26,7 +26,28 @@ import ( func GenFuncTable() ast.FuncTable { var stdlib ast.FuncTable stdlib = &map[string]*ast.Function{ - "...": &ast.Function{ + "if": &ast.Function{ + Function: shs_if, + Name: "if", + TimesCalled: 0, + Args: 3, + }, + + "while": &ast.Function{ + Function: shs_while, + Name: "while", + TimesCalled: 0, + Args: -1, + }, + + "eval": &ast.Function{ + Function: eval, + Name: "eval", + TimesCalled: 0, + Args: -1, + }, + + "...": &ast.Function{ Function: expand, Name: "...", TimesCalled: 0, @@ -242,3 +263,7 @@ func sh_info(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { return nil } + +func eval(in *ast.Token, vt ast.VarTable, ft ast.VarTable) *ast.Token { + return in.Eval(ft, vt, false) +}