Selector operator, multi-operand, added
This commit is contained in:
parent
f74e523617
commit
d3f388f7e1
16
ast.go
16
ast.go
@ -54,7 +54,21 @@ func (self *ast) addTokens(tokens ...*Token) (err error) {
|
||||
}
|
||||
|
||||
func (self *ast) addToken(tk *Token) (err error) {
|
||||
if t := newTerm(tk, nil); t != nil {
|
||||
_, err = self.addToken2(tk)
|
||||
return
|
||||
}
|
||||
|
||||
// func (self *ast) addToken(tk *Token) (err error) {
|
||||
// if t := newTerm(tk, nil); t != nil {
|
||||
// err = self.addTerm(t)
|
||||
// } else {
|
||||
// err = tk.Errorf("No term constructor for token %q", tk.String())
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
func (self *ast) addToken2(tk *Token) (t *term, err error) {
|
||||
if t = newTerm(tk, nil); t != nil {
|
||||
err = self.addTerm(t)
|
||||
} else {
|
||||
err = tk.Errorf("No term constructor for token %q", tk.String())
|
||||
|
@ -13,7 +13,7 @@ func EvalString(ctx exprContext, source string) (result any, err error) {
|
||||
scanner := NewScanner(r, DefaultTranslations())
|
||||
parser := NewParser(ctx)
|
||||
|
||||
if tree, err = parser.parse(scanner); err == nil {
|
||||
if tree, err = parser.Parse(scanner); err == nil {
|
||||
result, err = tree.Eval(ctx, true)
|
||||
}
|
||||
return
|
||||
|
@ -4,7 +4,7 @@
|
||||
// operand-expr.go
|
||||
package expr
|
||||
|
||||
import "errors"
|
||||
import "fmt"
|
||||
|
||||
// -------- expr term
|
||||
func newExprTerm(tk *Token) *term {
|
||||
@ -25,7 +25,7 @@ func evalExpr(ctx exprContext, self *term) (v any, err error) {
|
||||
if expr, ok := self.value().(Expr); ok {
|
||||
v, err = expr.Eval(ctx, false)
|
||||
} else {
|
||||
err = errors.New("invalid body of function definition")
|
||||
err = fmt.Errorf("expression expected, got %T", self.value())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
37
operand-selector-case.go
Normal file
37
operand-selector-case.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operand-selector-case.go
|
||||
package expr
|
||||
|
||||
import "fmt"
|
||||
|
||||
// -------- selector case term
|
||||
|
||||
type selectorCase struct {
|
||||
filterList *term
|
||||
caseExpr Expr
|
||||
}
|
||||
|
||||
func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term {
|
||||
tk := NewValueToken(row, col, SymSelectorCase, "", &selectorCase{filterList: filterList, caseExpr: caseExpr})
|
||||
return &term{
|
||||
tk: *tk,
|
||||
class: classVar,
|
||||
kind: kindUnknown,
|
||||
parent: nil,
|
||||
children: nil,
|
||||
position: posLeaf,
|
||||
priority: priValue,
|
||||
evalFunc: evalSelectorCase,
|
||||
}
|
||||
}
|
||||
|
||||
// -------- eval selector case
|
||||
func evalSelectorCase(ctx exprContext, self *term) (v any, err error) {
|
||||
var ok bool
|
||||
if v, ok = self.value().(*selectorCase); !ok {
|
||||
err = fmt.Errorf("selector-case expected, got %T", self.value())
|
||||
}
|
||||
return
|
||||
}
|
70
operator-selector.go
Normal file
70
operator-selector.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operator-selector.go
|
||||
package expr
|
||||
|
||||
//-------- export all term
|
||||
|
||||
func newSelectorTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
class: classOperator,
|
||||
kind: kindUnknown,
|
||||
children: make([]*term, 0, 3),
|
||||
position: posMultifix,
|
||||
priority: priSelector,
|
||||
evalFunc: evalSelector,
|
||||
}
|
||||
}
|
||||
|
||||
func isSelectorCase(ctx exprContext, exprValue, caseSel any, caseIndex int) (selectedValue any, err error) {
|
||||
caseData, _ := caseSel.(*selectorCase)
|
||||
if caseData.filterList == nil {
|
||||
selectedValue, err = caseData.caseExpr.Eval(ctx, false)
|
||||
} else {
|
||||
filterList := caseData.filterList.children
|
||||
if len(filterList) == 0 && exprValue == int64(caseIndex) {
|
||||
selectedValue, err = caseData.caseExpr.Eval(ctx, false)
|
||||
} else {
|
||||
var caseValue any
|
||||
for _, caseTerm := range filterList {
|
||||
if caseValue, err = caseTerm.compute(ctx); err != nil || caseValue == exprValue {
|
||||
selectedValue, err = caseData.caseExpr.Eval(ctx, false)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func evalSelector(ctx exprContext, self *term) (v any, err error) {
|
||||
var exprValue any
|
||||
// var caseList []*term
|
||||
|
||||
if err = self.checkOperands(); err != nil {
|
||||
return
|
||||
}
|
||||
exprTerm := self.children[0]
|
||||
if exprValue, err = exprTerm.compute(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
caseList := self.children[1:]
|
||||
for i, caseTerm := range caseList {
|
||||
caseSel := caseTerm.value()
|
||||
if v, err = isSelectorCase(ctx, exprValue, caseSel, i); err != nil || v != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil && v == nil {
|
||||
err = exprTerm.tk.Errorf("no case catches the value (%v) of the selection expression", exprValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymSelector, newSelectorTerm)
|
||||
}
|
96
parser.go
96
parser.go
@ -94,7 +94,7 @@ func (self *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (self *parser) parseList(scanner *scanner, allowVarRef bool) (tree *term, err error) {
|
||||
func (self *parser) parseList(scanner *scanner, allowVarRef bool) (subtree *term, err error) {
|
||||
args := make([]*term, 0)
|
||||
lastSym := SymUnknown
|
||||
for lastSym != SymClosedSquare && lastSym != SymEos {
|
||||
@ -113,21 +113,72 @@ func (self *parser) parseList(scanner *scanner, allowVarRef bool) (tree *term, e
|
||||
if lastSym != SymClosedSquare {
|
||||
err = scanner.Previous().Errorf("unterminate items list")
|
||||
} else {
|
||||
tree = newListTerm(args)
|
||||
subtree = newListTerm(args)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *parser) parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
|
||||
return self.parseGeneral(scanner, true, false, termSymbols...)
|
||||
func (self *parser) parseSelectorCase(scanner *scanner, allowVarRef bool, defaultCase bool) (caseTerm *term, err error) {
|
||||
var filterList *term
|
||||
var caseExpr *ast
|
||||
tk := scanner.Next()
|
||||
startRow := tk.row
|
||||
startCol := tk.col
|
||||
if tk.Sym == SymOpenSquare {
|
||||
if defaultCase {
|
||||
err = tk.Errorf("case list in default clause")
|
||||
return
|
||||
}
|
||||
if filterList, err = self.parseList(scanner, allowVarRef); err != nil {
|
||||
return
|
||||
}
|
||||
tk = scanner.Next()
|
||||
startRow = tk.row
|
||||
startCol = tk.col
|
||||
} else if !defaultCase {
|
||||
filterList = newListTerm(make([]*term, 0))
|
||||
}
|
||||
|
||||
if tk.Sym == SymOpenBrace {
|
||||
if caseExpr, err = self.parseGeneral(scanner, true, allowVarRef, SymClosedBrace); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = tk.Errorf("selector-case expected, got %q", tk.source)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
caseTerm = newSelectorCaseTerm(startRow, startCol, filterList, caseExpr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *parser) parseSelector(scanner *scanner, tree *ast, allowVarRef bool) (selectorTerm *term, err error) {
|
||||
var caseTerm *term
|
||||
tk := scanner.makeToken(SymSelector, '?')
|
||||
if selectorTerm, err = tree.addToken2(tk); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if caseTerm, err = self.parseSelectorCase(scanner, allowVarRef, false); err == nil {
|
||||
selectorTerm.children = append(selectorTerm.children, caseTerm)
|
||||
caseTerm.parent = selectorTerm
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *parser) parseItem(scanner *scanner, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
||||
return self.parseGeneral(scanner, false, allowVarRef, termSymbols...)
|
||||
}
|
||||
|
||||
func (self *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
|
||||
return self.parseGeneral(scanner, true, false, termSymbols...)
|
||||
}
|
||||
|
||||
func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
||||
var selectorTerm *term = nil
|
||||
var currentTerm *term = nil
|
||||
tree = NewAst()
|
||||
firstToken := true
|
||||
lastSym := SymUnknown
|
||||
@ -135,6 +186,7 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
|
||||
if tk.Sym == SymComment {
|
||||
continue
|
||||
}
|
||||
//resetSelector := true
|
||||
|
||||
if tk.Sym == SymSemiColon {
|
||||
if allowForest {
|
||||
@ -162,36 +214,64 @@ func (self *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef
|
||||
var subTree *ast
|
||||
if subTree, err = self.parseGeneral(scanner, false, allowVarRef, SymClosedRound); err == nil {
|
||||
subTree.root.priority = priValue
|
||||
tree.addTerm(subTree.root)
|
||||
err = tree.addTerm(subTree.root)
|
||||
currentTerm = subTree.root
|
||||
}
|
||||
case SymFuncCall:
|
||||
var funcCallTerm *term
|
||||
if funcCallTerm, err = self.parseFuncCall(scanner, allowVarRef, tk); err == nil {
|
||||
err = tree.addTerm(funcCallTerm)
|
||||
currentTerm = funcCallTerm
|
||||
}
|
||||
case SymOpenSquare:
|
||||
var listTerm *term
|
||||
if listTerm, err = self.parseList(scanner, allowVarRef); err == nil {
|
||||
err = tree.addTerm(listTerm)
|
||||
currentTerm = listTerm
|
||||
}
|
||||
case SymEqual:
|
||||
if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
|
||||
err = tree.addToken(tk)
|
||||
currentTerm, err = tree.addToken2(tk)
|
||||
}
|
||||
case SymFuncDef:
|
||||
var funcDefTerm *term
|
||||
if funcDefTerm, err = self.parseFuncDef(scanner); err == nil {
|
||||
err = tree.addTerm(funcDefTerm)
|
||||
currentTerm = funcDefTerm
|
||||
}
|
||||
case SymIdentifier:
|
||||
if tk.source[0] == '@' && !allowVarRef {
|
||||
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.source)
|
||||
} else {
|
||||
err = tree.addToken(tk)
|
||||
currentTerm, err = tree.addToken2(tk)
|
||||
}
|
||||
case SymQuestion:
|
||||
if selectorTerm != nil {
|
||||
err = tk.Errorf("nested selectors must be enclosed in parentheses")
|
||||
} else if selectorTerm, err = self.parseSelector(scanner, tree, allowVarRef); err == nil {
|
||||
currentTerm = selectorTerm
|
||||
}
|
||||
case SymColon, SymDoubleColon:
|
||||
var caseTerm *term
|
||||
if selectorTerm == nil {
|
||||
err = tk.Errorf("selector-case outside of a selector context")
|
||||
} else if caseTerm, err = self.parseSelectorCase(scanner, allowVarRef, tk.Sym == SymDoubleColon); err == nil {
|
||||
selectorTerm.children = append(selectorTerm.children, caseTerm)
|
||||
caseTerm.parent = selectorTerm
|
||||
currentTerm = caseTerm
|
||||
}
|
||||
//resetSelector = tk.Sym == SymDoubleColon
|
||||
default:
|
||||
err = tree.addToken(tk)
|
||||
currentTerm, err = tree.addToken2(tk)
|
||||
}
|
||||
|
||||
if currentTerm != nil && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
|
||||
selectorTerm = nil
|
||||
|
||||
}
|
||||
// if resetSelector {
|
||||
// selectorTree = nil
|
||||
// }
|
||||
lastSym = tk.Sym
|
||||
}
|
||||
return
|
||||
|
@ -63,7 +63,7 @@ func TestParser(t *testing.T) {
|
||||
/* 42 */ {`"s" + true`, nil, errors.New(`[1:6] left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`)},
|
||||
/* 43 */ {`+false`, nil, errors.New(`[1:2] prefix/postfix operator "+" do not support operand 'false' [bool]`)},
|
||||
/* 44 */ {`false // very simple expression`, false, nil},
|
||||
/* 45 */ {`1 + // Missing right operator`, nil, errors.New(`[1:4] infix operator "+" requires two operands, got 1`)},
|
||||
/* 45 */ {`1 + // Missing right operator`, nil, errors.New(`[1:4] infix operator "+" requires two not nil operands, got 1`)},
|
||||
/* 46 */ {"", nil, errors.New(`empty expression`)},
|
||||
/* 47 */ {"4!", int64(24), nil},
|
||||
/* 48 */ {"(-4)!", nil, errors.New(`factorial of a negative integer (-4) is not allowed`)},
|
||||
@ -78,18 +78,18 @@ func TestParser(t *testing.T) {
|
||||
/* 57 */ {`"1.5" > "7"`, false, nil},
|
||||
/* 58 */ {`"1.5" == "7"`, false, nil},
|
||||
/* 59 */ {`"1.5" != "7"`, true, nil},
|
||||
/* 60 */ {"1.5 < ", nil, errors.New(`[1:6] infix operator "<" requires two operands, got 1`)},
|
||||
/* 61 */ {"1.5 > ", nil, errors.New(`[1:6] infix operator ">" requires two operands, got 1`)},
|
||||
/* 62 */ {"1.5 <= ", nil, errors.New(`[1:6] infix operator "<=" requires two operands, got 1`)},
|
||||
/* 63 */ {"1.5 >= ", nil, errors.New(`[1:6] infix operator ">=" requires two operands, got 1`)},
|
||||
/* 64 */ {"1.5 != ", nil, errors.New(`[1:6] infix operator "!=" requires two operands, got 1`)},
|
||||
/* 65 */ {"1.5 == ", nil, errors.New(`[1:6] infix operator "==" requires two operands, got 1`)},
|
||||
/* 66 */ {`"1.5" < `, nil, errors.New(`[1:8] infix operator "<" requires two operands, got 1`)},
|
||||
/* 67 */ {`"1.5" > `, nil, errors.New(`[1:8] infix operator ">" requires two operands, got 1`)},
|
||||
/* 68 */ {`"1.5" == `, nil, errors.New(`[1:8] infix operator "==" requires two operands, got 1`)},
|
||||
/* 69 */ {`"1.5" != `, nil, errors.New(`[1:8] infix operator "!=" requires two operands, got 1`)},
|
||||
/* 60 */ {"1.5 < ", nil, errors.New(`[1:6] infix operator "<" requires two not nil operands, got 1`)},
|
||||
/* 61 */ {"1.5 > ", nil, errors.New(`[1:6] infix operator ">" requires two not nil operands, got 1`)},
|
||||
/* 62 */ {"1.5 <= ", nil, errors.New(`[1:6] infix operator "<=" requires two not nil operands, got 1`)},
|
||||
/* 63 */ {"1.5 >= ", nil, errors.New(`[1:6] infix operator ">=" requires two not nil operands, got 1`)},
|
||||
/* 64 */ {"1.5 != ", nil, errors.New(`[1:6] infix operator "!=" requires two not nil operands, got 1`)},
|
||||
/* 65 */ {"1.5 == ", nil, errors.New(`[1:6] infix operator "==" requires two not nil operands, got 1`)},
|
||||
/* 66 */ {`"1.5" < `, nil, errors.New(`[1:8] infix operator "<" requires two not nil operands, got 1`)},
|
||||
/* 67 */ {`"1.5" > `, nil, errors.New(`[1:8] infix operator ">" requires two not nil operands, got 1`)},
|
||||
/* 68 */ {`"1.5" == `, nil, errors.New(`[1:8] infix operator "==" requires two not nil operands, got 1`)},
|
||||
/* 69 */ {`"1.5" != `, nil, errors.New(`[1:8] infix operator "!=" requires two not nil operands, got 1`)},
|
||||
/* 70 */ {"+1.5", float64(1.5), nil},
|
||||
/* 71 */ {"+", nil, errors.New(`[1:2] prefix operator "+" requires one operand`)},
|
||||
/* 71 */ {"+", nil, errors.New(`[1:2] prefix operator "+" requires one not nil operand`)},
|
||||
/* 72 */ {"4 / 0", nil, errors.New(`division by zero`)},
|
||||
/* 73 */ {"4.0 / 0", nil, errors.New(`division by zero`)},
|
||||
/* 74 */ {"4.0 / \n2", float64(2.0), nil},
|
||||
@ -146,6 +146,13 @@ func TestParser(t *testing.T) {
|
||||
/* 125 */ {`f=func(@y){g=func(){@x=5}; g(); @z=x; @x=@y+@z}; f(2); y+x`, int64(9), nil},
|
||||
/* 126 */ {`include("./test-funcs.expr"); six()`, int64(6), nil},
|
||||
/* 127 */ {`import("./sample-export-all.expr"); six()`, int64(6), nil},
|
||||
/* 128 */ {`1 ? {"a"} : {"b"}`, "b", nil},
|
||||
/* 129 */ {`10 ? {"a"} : {"b"} :: {"c"}`, "c", nil},
|
||||
/* 130 */ {`10 ? {"a"} :[true, 2+8] {"b"} :: {"c"}`, "b", nil},
|
||||
/* 131 */ {`10 ? {"a"} :[true, 2+8] {"b"} ::[10] {"c"}`, nil, errors.New(`[1:34] case list in default clause`)},
|
||||
/* 132 */ {`10 ? {"a"} :[10] {x="b" but x} :: {"c"}`, "b", nil},
|
||||
/* 133 */ {`10 ? {"a"} :[10] {x="b"; x} :: {"c"}`, "b", nil},
|
||||
/* 134 */ {`10 ? {"a"} : {"b"}`, nil, errors.New(`[1:3] no case catches the value (10) of the selection expression`)},
|
||||
}
|
||||
check_env_expr_path := 113
|
||||
|
||||
@ -153,7 +160,7 @@ func TestParser(t *testing.T) {
|
||||
failed := 0
|
||||
|
||||
// inputs1 := []inputType{
|
||||
// {`import("./sample-export-all.expr"); six()`, int64(6), nil},
|
||||
// {`1 ? {"a"} : {"b"}`, "b", nil},
|
||||
// }
|
||||
|
||||
for i, input := range inputs {
|
||||
@ -174,7 +181,7 @@ func TestParser(t *testing.T) {
|
||||
scanner := NewScanner(r, DefaultTranslations())
|
||||
|
||||
good := true
|
||||
if expr, gotErr = parser.parse(scanner); gotErr == nil {
|
||||
if expr, gotErr = parser.Parse(scanner); gotErr == nil {
|
||||
gotResult, gotErr = expr.Eval(ctx, true)
|
||||
}
|
||||
|
||||
@ -202,7 +209,7 @@ func TestParser(t *testing.T) {
|
||||
t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed))
|
||||
}
|
||||
|
||||
func TestListParser(t *testing.T) {
|
||||
func NoTestListParser(t *testing.T) {
|
||||
type inputType struct {
|
||||
source string
|
||||
wantResult any
|
||||
@ -249,7 +256,7 @@ func TestListParser(t *testing.T) {
|
||||
scanner := NewScanner(r, DefaultTranslations())
|
||||
|
||||
good := true
|
||||
if expr, gotErr = parser.parse(scanner); gotErr == nil {
|
||||
if expr, gotErr = parser.Parse(scanner); gotErr == nil {
|
||||
gotResult, gotErr = expr.Eval(ctx, true)
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,11 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
||||
case ',':
|
||||
tk = self.makeToken(SymComma, ch)
|
||||
case ':':
|
||||
if next, _ := self.peek(); next == ':' {
|
||||
tk = self.moveOn(SymDoubleColon, ch, next)
|
||||
} else {
|
||||
tk = self.makeToken(SymColon, ch)
|
||||
}
|
||||
case ';':
|
||||
tk = self.makeToken(SymSemiColon, ch)
|
||||
case '.':
|
||||
|
@ -58,6 +58,7 @@ const (
|
||||
SymDoubleQuestion // 47: '??'
|
||||
SymQuestionEqual // 48: '?='
|
||||
SymDoubleAt // 49: '@@'
|
||||
SymDoubleColon // 50: '::'
|
||||
SymChangeSign
|
||||
SymUnchangeSign
|
||||
SymIdentifier
|
||||
@ -73,6 +74,8 @@ const (
|
||||
SymFuncDef
|
||||
SymList
|
||||
SymExpression
|
||||
SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||
SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||
// SymOpenComment // 0: '/*'
|
||||
// SymClosedComment // 0: '*/'
|
||||
// SymOneLineComment // 0: '//'
|
||||
|
24
term.go
24
term.go
@ -41,6 +41,7 @@ const (
|
||||
priRelational
|
||||
priSum
|
||||
priProduct
|
||||
priSelector
|
||||
priSign
|
||||
priFact
|
||||
priCoalesce
|
||||
@ -54,6 +55,7 @@ const (
|
||||
posInfix
|
||||
posPrefix
|
||||
posPostfix
|
||||
posMultifix
|
||||
)
|
||||
|
||||
type evalFuncType func(ctx exprContext, self *term) (v any, err error)
|
||||
@ -196,21 +198,33 @@ func (self *term) Errorf(template string, args ...any) (err error) {
|
||||
func (self *term) checkOperands() (err error) {
|
||||
switch self.position {
|
||||
case posInfix:
|
||||
if self.children == nil || len(self.children) != 2 || self.children[0] == nil || self.children[1] == nil {
|
||||
err = self.tk.Errorf("infix operator %q requires two operands, got %d", self.source(), self.getChildrenCount())
|
||||
if self.children == nil || len(self.children) != 2 || self.anyChildrenNil() {
|
||||
err = self.tk.Errorf("infix operator %q requires two not nil operands, got %d", self.source(), self.getChildrenCount())
|
||||
}
|
||||
case posPrefix:
|
||||
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
|
||||
err = self.tk.Errorf("prefix operator %q requires one operand", self.tk.String())
|
||||
err = self.tk.Errorf("prefix operator %q requires one not nil operand", self.tk.String())
|
||||
}
|
||||
case posPostfix:
|
||||
if self.children == nil || len(self.children) != 1 || self.children[0] == nil {
|
||||
err = self.tk.Errorf("postfix operator %q requires one operand", self.tk.String())
|
||||
if self.children == nil || len(self.children) != 1 || self.anyChildrenNil() {
|
||||
err = self.tk.Errorf("postfix operator %q requires one not nil operand", self.tk.String())
|
||||
}
|
||||
case posMultifix:
|
||||
if self.children == nil || len(self.children) < 3 || self.anyChildrenNil() {
|
||||
err = self.tk.Errorf("infix operator %q requires at least three not operands, got %d", self.source(), self.getChildrenCount())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (self *term) anyChildrenNil() bool {
|
||||
for _, child := range self.children {
|
||||
if child == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (self *term) evalInfix(ctx exprContext) (leftValue, rightValue any, err error) {
|
||||
if err = self.checkOperands(); err == nil {
|
||||
if leftValue, err = self.children[0].compute(ctx); err == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user