From f3e39e156ce5b112450adffa3c9d725cfefec7ed Mon Sep 17 00:00:00 2001 From: Aidan Date: Mon, 29 Jun 2020 12:26:01 -0700 Subject: [PATCH] bool functions retrofitted for eval change --- ast/token.go | 11 +++ stdlib/bool.go | 169 +++++++++++++++++++++++++++++++++++++++++++++++ stdlib/stdlib.go | 50 ++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 stdlib/bool.go diff --git a/ast/token.go b/ast/token.go index aee78b6..8c15140 100644 --- a/ast/token.go +++ b/ast/token.go @@ -130,6 +130,17 @@ func (t *Token) FmtToken() string { } } +/* Sets the string value for a non-list token + */ +func (t *Token) Set(arg string) bool { + if t.Tag == LIST { + return false + } + + t.inner = arg + return true +} + /* Returns a tag in text */ func GetTagAsStr(tag Token_t) string { diff --git a/stdlib/bool.go b/stdlib/bool.go new file mode 100644 index 0000000..b59e160 --- /dev/null +++ b/stdlib/bool.go @@ -0,0 +1,169 @@ +/* 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 ( + "strconv" + "gitlab.com/whom/shs/log" + "gitlab.com/whom/shs/ast" +) + +func not(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + if in.Tag != ast.BOOL { + log.Log(log.ERR, "non-bool argument to 'not'", "not") + return nil + } + + out := "T" + if in.Value() == "T" { + out = "F" + } + + t := &ast.Token{Tag: ast.BOOL} + t.Set(out) + return t +} + +func eq(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + out := "T" + second := in.Next + + in = in.Eval(ft, vt) + second = second.Eval(ft, vt) + + if in.Tag != second.Tag { + out = "F" + } else { + switch in.Tag { + case ast.LIST: + // returns true if difference found + var consume_list func(*ast.Token, *ast.Token) bool + consume_list = func(l *ast.Token, r *ast.Token) bool { + if (l == nil && r != nil) || (r == nil && l != nil) { + return true + } + + if l.Tag != r.Tag { + return true + } + + l_iter := l + r_iter := r + for l_iter != nil { + if r_iter == nil || l_iter.Tag != r_iter.Tag { + return true + } + + if l_iter.Tag == ast.LIST { + diff := consume_list(l_iter.Expand(), r_iter.Expand()) + if diff { + return true + } + + } else { + if l_iter.Value() != r_iter.Value() { + return true + } + } + + l_iter = l_iter.Next + r_iter = r_iter.Next + } + + if r_iter != nil { + return true + } else { + return false + } + } + + if consume_list(in.Expand(), second.Expand()) { + out = "F" + } + + case ast.NUMBER, ast.STRING, ast.BOOL: + if in.Value() != second.Value() { + out = "F" + } + } + } + + t := &ast.Token{Tag: ast.BOOL} + t.Set(out) + return t +} + +func lt(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + out := "T" + second := in.Next + + in = in.Eval(ft, vt) + second = second.Eval(ft, vt) + + 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) + + if l >= r { + out = "F" + } + + t := &ast.Token{Tag: ast.BOOL} + t.Set(out) + return t +} + +func gt(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + out := "T" + second := in.Next + + in = in.Eval(ft, vt) + second = second.Eval(ft, vt) + + 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) + + if l <= r { + out = "F" + } + + t := &ast.Token{Tag: ast.BOOL} + t.Set(out) + return t +} + +func ne(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + return not(eq(in, vt, ft), vt, ft) +} + +func gte(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + return not(lt(in, vt, ft), vt, ft) +} + +func lte(in *ast.Token, vt ast.VarTable, ft ast.FuncTable) *ast.Token { + return not(gt(in, vt, ft), vt, ft) +} diff --git a/stdlib/stdlib.go b/stdlib/stdlib.go index 97d6018..5f64a42 100644 --- a/stdlib/stdlib.go +++ b/stdlib/stdlib.go @@ -45,6 +45,56 @@ func GenFuncTable() ast.FuncTable { TimesCalled: 0, Args: 0, }, + + "eq": &ast.Function{ + Function: eq, + Name: "==", + TimesCalled: 0, + Args: 2, + }, + + "ne": &ast.Function{ + Function: ne, + Name: "!=", + TimesCalled: 0, + Args: 2, + }, + + "<": &ast.Function{ + Function: lt, + Name: "<", + TimesCalled: 0, + Args: 2, + }, + + ">": &ast.Function{ + Function: gt, + Name: ">", + TimesCalled: 0, + Args: 2, + }, + + "<=": &ast.Function{ + Function: lte, + Name: "<=", + TimesCalled: 0, + Args: 2, + }, + + ">=": &ast.Function{ + Function: gte, + Name: ">=", + TimesCalled: 0, + Args: 2, + }, + + "!": &ast.Function{ + Function: not, + Name: "!", + TimesCalled: 0, + Args: 1, + }, + } return stdlib