/* 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" "gitlab.com/whom/shs/log" ) /* eval N forms. return the last one * * Example: * (progn (print "hello") (print "world") (+ 1 2)) * This example will print "hello world" to stdout and return 3 */ func ShsProgn(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { var res *ast.Token for iter := in; iter != nil; iter = iter.Next { res = iter.Eval(ft, vt, false) } return res } /* return one evaluated form or another based on the boolean statement * arg 1 is a boolean cond, arg 2 is evaluated if the cond is true, arg 3 is evaluated if cond is not true * in total it takes 3 arguments * * Example: * (if (eq (number "3") 3) (print "test passed") (print "test failed")) */ func ShsIf(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { cond := in.Copy() t := cond.Next.Copy() 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 * has rather progn like behavior in that it returns the result of the last form to be evaluated * * Example: * (export cond T) * (while cond (export cond F) (print "will only be printed once") (+ 1 2)) * loop will iter one time, print "will only be printed once" and return 3 */ func ShsWhile(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { cond := in forms := in.Next in.Next = nil var res *ast.Token eval := cond.Eval(ft, vt, false) if eval == nil || eval.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() == ast.TRUE { // 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 }