SHS/stdlib/bool.go

183 lines
4.8 KiB
Go
Raw Normal View History

/* 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 <https://www.gnu.org/licenses/>.
*/
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 {
in = in.Eval(ft, vt, false)
2020-06-29 12:51:41 -07:00
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
}
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 := ast.TRUE
second := in.Next
in = in.Eval(ft, vt, false)
if in.Tag != second.Tag {
out = ast.FALSE
} 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 = ast.FALSE
}
2020-06-29 12:51:41 -07:00
case ast.STRING, ast.BOOL:
if in.Value() != second.Value() {
out = ast.FALSE
}
2020-06-29 12:51:41 -07:00
case ast.NUMBER:
l_val, parse_err := strconv.ParseFloat(in.Value(), 64)
r_val, parse_err := strconv.ParseFloat(second.Value(), 64)
if parse_err != nil {
log.Log(log.ERR,
"error parsing number: "+parse_err.Error(),
"eq")
return nil
}
if l_val != r_val {
out = ast.FALSE
2020-06-29 12:51:41 -07:00
}
}
}
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 := 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)
if l >= r {
out = ast.FALSE
}
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 := 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)
if l <= r {
out = ast.FALSE
}
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)
}