Compare commits
No commits in common. "6211be8a8f583f3cf3f2c9a4015495cec7acd57b" and "5da5a61a4247211bc56b109a776f2a853ef99c75" have entirely different histories.
6211be8a8f
...
5da5a61a42
@ -44,7 +44,7 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu
|
|||||||
var expr *ast
|
var expr *ast
|
||||||
scanner := NewScanner(file, DefaultTranslations())
|
scanner := NewScanner(file, DefaultTranslations())
|
||||||
parser := NewParser()
|
parser := NewParser()
|
||||||
if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, SymEos); err == nil {
|
if expr, err = parser.parseGeneral(scanner, true, true); err == nil {
|
||||||
result, err = expr.Eval(ctx)
|
result, err = expr.Eval(ctx)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -50,9 +50,9 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
|
|||||||
} else if s[0] == '+' {
|
} else if s[0] == '+' {
|
||||||
s = s[1:]
|
s = s[1:]
|
||||||
}
|
}
|
||||||
// if strings.HasSuffix(s, "()") {
|
// if strings.HasSuffix(s, "()") {
|
||||||
// s = s[0 : len(s)-2]
|
// s = s[0 : len(s)-2]
|
||||||
// }
|
// }
|
||||||
s = strings.TrimSuffix(s, "()")
|
s = strings.TrimSuffix(s, "()")
|
||||||
parts = strings.SplitN(s, ".", 2)
|
parts = strings.SplitN(s, ".", 2)
|
||||||
if num, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
|
if num, err = strconv.ParseInt(parts[0], 10, 64); err != nil {
|
||||||
@ -124,7 +124,7 @@ func (f *FractionType) String() string {
|
|||||||
func (f *FractionType) ToString(opt FmtOpt) string {
|
func (f *FractionType) ToString(opt FmtOpt) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
if opt&MultiLine == 0 {
|
if opt&MultiLine == 0 {
|
||||||
sb.WriteString(fmt.Sprintf("%d:%d", f.num, f.den))
|
sb.WriteString(fmt.Sprintf("%d|%d", f.num, f.den))
|
||||||
} else {
|
} else {
|
||||||
var s, num string
|
var s, num string
|
||||||
if f.num < 0 && opt&TTY == 0 {
|
if f.num < 0 && opt&TTY == 0 {
|
||||||
|
6
go.mod
6
go.mod
@ -1,7 +1,3 @@
|
|||||||
module git.portale-stac.it/go-pkg/expr
|
module git.portale-stac.it/go-pkg/expr
|
||||||
|
|
||||||
go 1.22.0
|
go 1.21.6
|
||||||
|
|
||||||
toolchain go1.23.3
|
|
||||||
|
|
||||||
require golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d
|
|
||||||
|
4
go.sum
4
go.sum
@ -1,4 +0,0 @@
|
|||||||
github.com/yqylovy/goimportdot v0.0.0-20170519021755-eb181a7eeabe h1:bWYrKmmfv37uNgXTdwkLSKYiYPJ1yfWmjBnvtMyAYzk=
|
|
||||||
github.com/yqylovy/goimportdot v0.0.0-20170519021755-eb181a7eeabe/go.mod h1:alTKUpAJ/zbp17qvZwcFNwzufrb5DljMDY4mgJlIHao=
|
|
||||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d h1:0olWaB5pg3+oychR51GUVCEsGkeCU/2JxjBgIo4f3M0=
|
|
||||||
golang.org/x/exp v0.0.0-20241204233417-43b7b7cde48d/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
|
@ -99,106 +99,7 @@ func evalAssign(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------- assign term
|
|
||||||
|
|
||||||
func newOpAssignTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priAssign,
|
|
||||||
evalFunc: evalOpAssign,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term) (value any, err error) {
|
|
||||||
var collectionValue, keyListValue, keyValue any
|
|
||||||
var keyList *ListType
|
|
||||||
var ok bool
|
|
||||||
|
|
||||||
if collectionValue, err = collectionTerm.compute(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if keyListValue, err = keyListTerm.compute(ctx); err != nil {
|
|
||||||
return
|
|
||||||
} else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 {
|
|
||||||
err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, TypeName(keyListValue))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if keyValue = (*keyList)[0]; keyValue == nil {
|
|
||||||
err = keyListTerm.Errorf("index/key is nil")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch collection := collectionValue.(type) {
|
|
||||||
case *ListType:
|
|
||||||
if index, ok := keyValue.(int64); ok {
|
|
||||||
value = (*collection)[index]
|
|
||||||
} else {
|
|
||||||
err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, TypeName(keyValue))
|
|
||||||
}
|
|
||||||
case *DictType:
|
|
||||||
value = (*collection)[keyValue]
|
|
||||||
default:
|
|
||||||
err = collectionTerm.Errorf("collection expected")
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAssignValue(ctx ExprContext, leftTerm *term) (value any, err error) {
|
|
||||||
if leftTerm.symbol() == SymIndex {
|
|
||||||
value, err = getCollectionItemValue(ctx, leftTerm.children[0], leftTerm.children[1])
|
|
||||||
} else {
|
|
||||||
value, _ = ctx.GetVar(leftTerm.source())
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
|
|
||||||
var rightValue, leftValue any
|
|
||||||
if err = opTerm.checkOperands(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leftTerm := opTerm.children[0]
|
|
||||||
leftSym := leftTerm.symbol()
|
|
||||||
if leftSym != SymVariable && leftSym != SymIndex {
|
|
||||||
err = leftTerm.tk.Errorf("left operand of %q must be a variable or a collection's item", opTerm.tk.source)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rightChild := opTerm.children[1]
|
|
||||||
|
|
||||||
if rightValue, err = rightChild.compute(ctx); err == nil {
|
|
||||||
if leftValue, err = getAssignValue(ctx, leftTerm); err == nil {
|
|
||||||
switch opTerm.symbol() {
|
|
||||||
case SymPlusEqual:
|
|
||||||
v, err = sumValues(opTerm, leftValue, rightValue)
|
|
||||||
case SymMinusEqual:
|
|
||||||
v, err = diffValues(opTerm, leftValue, rightValue)
|
|
||||||
case SymStarEqual:
|
|
||||||
v, err = mulValues(opTerm, leftValue, rightValue)
|
|
||||||
case SymSlashEqual:
|
|
||||||
v, err = divValues(opTerm, leftValue, rightValue)
|
|
||||||
case SymPercEqual:
|
|
||||||
v, err = remainderValues(opTerm, leftValue, rightValue)
|
|
||||||
default:
|
|
||||||
err = opTerm.Errorf("unsupported assign operator %q", opTerm.source())
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
err = assignValue(ctx, leftTerm, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
registerTermConstructor(SymEqual, newAssignTerm)
|
registerTermConstructor(SymEqual, newAssignTerm)
|
||||||
registerTermConstructor(SymPlusEqual, newOpAssignTerm)
|
|
||||||
registerTermConstructor(SymMinusEqual, newOpAssignTerm)
|
|
||||||
registerTermConstructor(SymStarEqual, newOpAssignTerm)
|
|
||||||
registerTermConstructor(SymSlashEqual, newOpAssignTerm)
|
|
||||||
}
|
}
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// operator-binary.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
//-------- NOT term
|
|
||||||
|
|
||||||
func newBinNotTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 1),
|
|
||||||
position: posPrefix,
|
|
||||||
priority: priNot,
|
|
||||||
evalFunc: evalBinaryNot,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalBinaryNot(ctx ExprContext, opTerm *term) (v any, err error) {
|
|
||||||
var value any
|
|
||||||
|
|
||||||
if value, err = opTerm.evalPrefix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if IsInteger(value) {
|
|
||||||
i, _ := value.(int64)
|
|
||||||
v = ^i
|
|
||||||
} else {
|
|
||||||
err = opTerm.errIncompatibleType(value)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------- Binary AND term
|
|
||||||
|
|
||||||
func newBinAndTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priAnd,
|
|
||||||
evalFunc: evalBinaryAnd,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalBinaryAnd(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
var leftInt, rightInt int64
|
|
||||||
var lok, rok bool
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leftInt, lok = leftValue.(int64)
|
|
||||||
rightInt, rok = rightValue.(int64)
|
|
||||||
|
|
||||||
if lok && rok {
|
|
||||||
v = leftInt & rightInt
|
|
||||||
} else {
|
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------- Binary OR term
|
|
||||||
|
|
||||||
func newBinOrTerm(tk *Token) (inst *term) {
|
|
||||||
return &term{
|
|
||||||
tk: *tk,
|
|
||||||
children: make([]*term, 0, 2),
|
|
||||||
position: posInfix,
|
|
||||||
priority: priOr,
|
|
||||||
evalFunc: evalBinaryOr,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalBinaryOr(ctx ExprContext, self *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
var leftInt, rightInt int64
|
|
||||||
var lok, rok bool
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
leftInt, lok = leftValue.(int64)
|
|
||||||
rightInt, rok = rightValue.(int64)
|
|
||||||
|
|
||||||
if lok && rok {
|
|
||||||
v = leftInt | rightInt
|
|
||||||
} else {
|
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
|
||||||
func init() {
|
|
||||||
registerTermConstructor(SymTilde, newBinNotTerm)
|
|
||||||
registerTermConstructor(SymAmpersand, newBinAndTerm)
|
|
||||||
registerTermConstructor(SymVertBar, newBinOrTerm)
|
|
||||||
}
|
|
@ -49,23 +49,18 @@ func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
den = -den
|
den = -den
|
||||||
num = -num
|
num = -num
|
||||||
}
|
}
|
||||||
if num != 0 {
|
g := gcd(num, den)
|
||||||
g := gcd(num, den)
|
num = num / g
|
||||||
num = num / g
|
den = den / g
|
||||||
den = den / g
|
if den == 1 {
|
||||||
if den == 1 {
|
v = num
|
||||||
v = num
|
|
||||||
} else {
|
|
||||||
v = &FractionType{num, den}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
v = &FractionType{0, den}
|
v = &FractionType{num, den}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
// registerTermConstructor(SymVertBar, newFractionTerm)
|
registerTermConstructor(SymVertBar, newFractionTerm)
|
||||||
registerTermConstructor(SymColon, newFractionTerm)
|
|
||||||
}
|
}
|
||||||
|
@ -113,9 +113,6 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
} else if IsDict(leftValue) {
|
} else if IsDict(leftValue) {
|
||||||
d := leftValue.(*DictType)
|
d := leftValue.(*DictType)
|
||||||
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
v, err = getDictItem(d, indexTerm, indexList, rightValue)
|
||||||
} else {
|
|
||||||
rightChild := opTerm.children[1]
|
|
||||||
err = rightChild.Errorf("invalid index type: %v", (*indexList)[0])
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -40,10 +40,6 @@ func evalInsert(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
if opTerm.children[1].symbol() == SymVariable {
|
if opTerm.children[1].symbol() == SymVariable {
|
||||||
ctx.UnsafeSetVar(opTerm.children[1].source(), v)
|
ctx.UnsafeSetVar(opTerm.children[1].source(), v)
|
||||||
}
|
}
|
||||||
} else if IsInteger(leftValue) && IsInteger(rightValue) {
|
|
||||||
leftInt := leftValue.(int64)
|
|
||||||
rightInt := rightValue.(int64)
|
|
||||||
v = leftInt >> rightInt
|
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@ -64,10 +60,6 @@ func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
if opTerm.children[0].symbol() == SymVariable {
|
if opTerm.children[0].symbol() == SymVariable {
|
||||||
ctx.UnsafeSetVar(opTerm.children[0].source(), v)
|
ctx.UnsafeSetVar(opTerm.children[0].source(), v)
|
||||||
}
|
}
|
||||||
} else if IsInteger(leftValue) && IsInteger(rightValue) {
|
|
||||||
leftInt := leftValue.(int64)
|
|
||||||
rightInt := rightValue.(int64)
|
|
||||||
v = leftInt << rightInt
|
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
|
|
||||||
func newMultiplyTerm(tk *Token) (inst *term) {
|
func newMultiplyTerm(tk *Token) (inst *term) {
|
||||||
return &term{
|
return &term{
|
||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priProduct,
|
priority: priProduct,
|
||||||
@ -21,7 +21,13 @@ func newMultiplyTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
|
func evalMultiply(ctx ExprContext, prodTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if IsString(leftValue) && IsInteger(rightValue) {
|
if IsString(leftValue) && IsInteger(rightValue) {
|
||||||
s, _ := leftValue.(string)
|
s, _ := leftValue.(string)
|
||||||
n, _ := rightValue.(int64)
|
n, _ := rightValue.(int64)
|
||||||
@ -37,26 +43,16 @@ func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
|
|||||||
v = leftInt * rightInt
|
v = leftInt * rightInt
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = prodTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalMultiply(ctx ExprContext, prodTerm *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return mulValues(prodTerm, leftValue, rightValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------- divide term
|
//-------- divide term
|
||||||
|
|
||||||
func newDivideTerm(tk *Token) (inst *term) {
|
func newDivideTerm(tk *Token) (inst *term) {
|
||||||
return &term{
|
return &term{
|
||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priProduct,
|
priority: priProduct,
|
||||||
@ -64,7 +60,13 @@ func newDivideTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
|
func evalDivide(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
|
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
|
||||||
if IsFloat(leftValue) || IsFloat(rightValue) {
|
if IsFloat(leftValue) || IsFloat(rightValue) {
|
||||||
d := numAsFloat(rightValue)
|
d := numAsFloat(rightValue)
|
||||||
@ -89,16 +91,6 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalDivide(ctx ExprContext, opTerm *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return divValues(opTerm, leftValue, rightValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------- divide as float term
|
//-------- divide as float term
|
||||||
|
|
||||||
func newDivideAsFloatTerm(tk *Token) (inst *term) {
|
func newDivideAsFloatTerm(tk *Token) (inst *term) {
|
||||||
@ -135,14 +127,21 @@ func evalDivideAsFloat(ctx ExprContext, floatDivTerm *term) (v any, err error) {
|
|||||||
|
|
||||||
func newRemainderTerm(tk *Token) (inst *term) {
|
func newRemainderTerm(tk *Token) (inst *term) {
|
||||||
return &term{
|
return &term{
|
||||||
tk: *tk,
|
tk: *tk,
|
||||||
children: make([]*term, 0, 2),
|
children: make([]*term, 0, 2),
|
||||||
position: posInfix,
|
position: posInfix,
|
||||||
priority: priProduct,
|
priority: priProduct,
|
||||||
evalFunc: evalRemainder,
|
evalFunc: evalReminder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) {
|
|
||||||
|
func evalReminder(ctx ExprContext, ramainderTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = ramainderTerm.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if IsInteger(leftValue) && IsInteger(rightValue) {
|
if IsInteger(leftValue) && IsInteger(rightValue) {
|
||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
if rightInt == 0 {
|
if rightInt == 0 {
|
||||||
@ -152,21 +151,11 @@ func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error)
|
|||||||
v = leftInt % rightInt
|
v = leftInt % rightInt
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = ramainderTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalRemainder(ctx ExprContext, remainderTerm *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = remainderTerm.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return remainderValues(remainderTerm, leftValue, rightValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
registerTermConstructor(SymStar, newMultiplyTerm)
|
registerTermConstructor(SymStar, newMultiplyTerm)
|
||||||
|
@ -34,16 +34,12 @@ func newRangeTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func changeColonToRange(t *term) {
|
|
||||||
if t.tk.IsSymbol(SymColon) {
|
|
||||||
t.tk.Sym = SymRange
|
|
||||||
t.evalFunc = evalRange
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func evalRange(ctx ExprContext, opTerm *term) (v any, err error) {
|
func evalRange(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||||
var leftValue, rightValue any
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
// if err = self.checkOperands(); err != nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
if len(opTerm.children) == 0 {
|
if len(opTerm.children) == 0 {
|
||||||
leftValue = int64(0)
|
leftValue = int64(0)
|
||||||
rightValue = int64(-1)
|
rightValue = int64(-1)
|
||||||
@ -56,8 +52,7 @@ func evalRange(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !(IsInteger(leftValue) && IsInteger(rightValue)) {
|
if !(IsInteger(leftValue) && IsInteger(rightValue)) {
|
||||||
// err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
err = errRangeInvalidSpecification(opTerm)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,15 +63,7 @@ func evalRange(ctx ExprContext, opTerm *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func errRangeInvalidSpecification(t *term) error {
|
|
||||||
return t.Errorf("invalid range specification")
|
|
||||||
}
|
|
||||||
|
|
||||||
func errRangeUnexpectedExpression(t *term) error {
|
|
||||||
return t.Errorf("unexpected range expression")
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
registerTermConstructor(SymRange, newRangeTerm)
|
registerTermConstructor(SymColon, newRangeTerm)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,13 @@ func newPlusTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) {
|
func evalPlus(ctx ExprContext, plusTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = plusTerm.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (IsString(leftValue) && isNumberString(rightValue)) || (IsString(rightValue) && isNumberString(leftValue)) {
|
if (IsString(leftValue) && isNumberString(rightValue)) || (IsString(rightValue) && isNumberString(leftValue)) {
|
||||||
v = fmt.Sprintf("%v%v", leftValue, rightValue)
|
v = fmt.Sprintf("%v%v", leftValue, rightValue)
|
||||||
} else if IsNumber(leftValue) && IsNumber(rightValue) {
|
} else if IsNumber(leftValue) && IsNumber(rightValue) {
|
||||||
@ -53,22 +59,10 @@ func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) {
|
|||||||
c := leftDict.clone()
|
c := leftDict.clone()
|
||||||
c.merge(rightDict)
|
c.merge(rightDict)
|
||||||
v = c
|
v = c
|
||||||
} else if isFraction(leftValue) && isFraction(rightValue) {
|
|
||||||
v, err = sumAnyFract(leftValue, rightValue)
|
|
||||||
} else {
|
} else {
|
||||||
err = plusTerm.errIncompatibleTypes(leftValue, rightValue)
|
err = plusTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
return v, err
|
return
|
||||||
}
|
|
||||||
|
|
||||||
func evalPlus(ctx ExprContext, plusTerm *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = plusTerm.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return sumValues(plusTerm, leftValue, rightValue)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------- minus term
|
//-------- minus term
|
||||||
@ -83,7 +77,13 @@ func newMinusTerm(tk *Token) (inst *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
|
func evalMinus(ctx ExprContext, minusTerm *term) (v any, err error) {
|
||||||
|
var leftValue, rightValue any
|
||||||
|
|
||||||
|
if leftValue, rightValue, err = minusTerm.evalInfix(ctx); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
|
if isNumOrFract(leftValue) && isNumOrFract(rightValue) {
|
||||||
if IsFloat(leftValue) || IsFloat(rightValue) {
|
if IsFloat(leftValue) || IsFloat(rightValue) {
|
||||||
v = numAsFloat(leftValue) - numAsFloat(rightValue)
|
v = numAsFloat(leftValue) - numAsFloat(rightValue)
|
||||||
@ -110,16 +110,6 @@ func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func evalMinus(ctx ExprContext, minusTerm *term) (v any, err error) {
|
|
||||||
var leftValue, rightValue any
|
|
||||||
|
|
||||||
if leftValue, rightValue, err = minusTerm.evalInfix(ctx); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return diffValues(minusTerm, leftValue, rightValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
func init() {
|
func init() {
|
||||||
registerTermConstructor(SymPlus, newPlusTerm)
|
registerTermConstructor(SymPlus, newPlusTerm)
|
||||||
|
234
parser.go
234
parser.go
@ -6,46 +6,10 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"golang.org/x/exp/constraints"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- parser
|
//-------- parser
|
||||||
|
|
||||||
type parserContext uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
parserNoFlags = 0
|
|
||||||
allowMultiExpr parserContext = 1 << iota
|
|
||||||
allowVarRef
|
|
||||||
selectorContext
|
|
||||||
listContext // squareContext for list
|
|
||||||
indexContext // squareContext for index
|
|
||||||
allowIndex // allow index in squareContext
|
|
||||||
squareContext = listContext | indexContext // Square parenthesis for list or index
|
|
||||||
)
|
|
||||||
|
|
||||||
func hasFlag[T constraints.Unsigned](set T, singleFlag T) bool {
|
|
||||||
return (set & singleFlag) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func addFlags[T constraints.Unsigned](set T, flags T) T {
|
|
||||||
return set | flags
|
|
||||||
}
|
|
||||||
|
|
||||||
func addFlagsCond[T constraints.Unsigned](set T, flags T, cond bool) (newSet T) {
|
|
||||||
if cond {
|
|
||||||
newSet = set | flags
|
|
||||||
} else {
|
|
||||||
newSet = set
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func remFlags[T constraints.Unsigned](set T, flags T) T {
|
|
||||||
return set & (^flags)
|
|
||||||
}
|
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,13 +24,13 @@ func (parser *parser) Next(scanner *scanner) (tk *Token) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseFuncCall(scanner *scanner, ctx parserContext, tk *Token) (tree *term, err error) {
|
func (parser *parser) parseFuncCall(scanner *scanner, allowVarRef bool, tk *Token) (tree *term, err error) {
|
||||||
args := make([]*term, 0, 10)
|
args := make([]*term, 0, 10)
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
lastSym := SymUnknown
|
lastSym := SymUnknown
|
||||||
for lastSym != SymClosedRound && lastSym != SymEos {
|
for lastSym != SymClosedRound && lastSym != SymEos {
|
||||||
var subTree *ast
|
var subTree *ast
|
||||||
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedRound); err != nil {
|
if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
prev := scanner.Previous()
|
prev := scanner.Previous()
|
||||||
@ -113,7 +77,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
|
|||||||
if tk.Sym == SymEqual {
|
if tk.Sym == SymEqual {
|
||||||
var paramExpr *ast
|
var paramExpr *ast
|
||||||
defaultParamsStarted = true
|
defaultParamsStarted = true
|
||||||
if paramExpr, err = parser.parseItem(scanner, parserNoFlags, SymComma, SymClosedRound); err != nil {
|
if paramExpr, err = parser.parseItem(scanner, false, SymComma, SymClosedRound); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
param.forceChild(paramExpr.root)
|
param.forceChild(paramExpr.root)
|
||||||
@ -136,7 +100,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
if tk.IsSymbol(SymOpenBrace) {
|
if tk.IsSymbol(SymOpenBrace) {
|
||||||
body, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, SymClosedBrace)
|
body, err = parser.parseGeneral(scanner, true, true, SymClosedBrace)
|
||||||
} else {
|
} else {
|
||||||
err = tk.ErrorExpectedGot("{")
|
err = tk.ErrorExpectedGot("{")
|
||||||
}
|
}
|
||||||
@ -162,33 +126,27 @@ func paramAlreadyDefined(args []*term, param *term) (position int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseList(scanner *scanner, ctx parserContext) (listTerm *term, err error) {
|
func (parser *parser) parseList(scanner *scanner, parsingIndeces bool, allowVarRef bool) (subtree *term, err error) {
|
||||||
r, c := scanner.lastPos()
|
r, c := scanner.lastPos()
|
||||||
args := make([]*term, 0)
|
args := make([]*term, 0)
|
||||||
lastSym := SymUnknown
|
lastSym := SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
itemCtx := remFlags(ctx, allowIndex)
|
|
||||||
for lastSym != SymClosedSquare && lastSym != SymEos {
|
for lastSym != SymClosedSquare && lastSym != SymEos {
|
||||||
|
var subTree *ast
|
||||||
zeroRequired := scanner.current.Sym == SymColon
|
zeroRequired := scanner.current.Sym == SymColon
|
||||||
var itemTree *ast
|
if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedSquare); err == nil {
|
||||||
if itemTree, err = parser.parseItem(scanner, itemCtx, SymComma, SymClosedSquare); err == nil {
|
root := subTree.root
|
||||||
root := itemTree.root
|
|
||||||
if root != nil {
|
if root != nil {
|
||||||
if hasFlag(ctx, allowIndex) && root.symbol() == SymColon {
|
if !parsingIndeces && root.symbol() == SymColon {
|
||||||
changeColonToRange(root)
|
err = root.Errorf("unexpected range expression")
|
||||||
}
|
|
||||||
if !hasFlag(ctx, allowIndex) && root.symbol() == SymRange {
|
|
||||||
// err = root.Errorf("unexpected range expression")
|
|
||||||
err = errRangeUnexpectedExpression(root)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
args = append(args, root)
|
args = append(args, root)
|
||||||
if hasFlag(ctx, allowIndex) && root.symbol() == SymRange && zeroRequired { //len(root.children) == 0 {
|
if parsingIndeces && root.symbol() == SymColon && zeroRequired { //len(root.children) == 0 {
|
||||||
if len(root.children) == 1 {
|
if len(root.children) == 1 {
|
||||||
root.children = append(root.children, root.children[0])
|
root.children = append(root.children, root.children[0])
|
||||||
} else if len(root.children) > 1 {
|
} else if len(root.children) > 1 {
|
||||||
// err = root.Errorf("invalid range specification")
|
err = root.Errorf("invalid range specification")
|
||||||
err = errRangeInvalidSpecification(root)
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
zeroTk := NewValueToken(root.tk.row, root.tk.col, SymInteger, "0", int64(0))
|
zeroTk := NewValueToken(root.tk.row, root.tk.col, SymInteger, "0", int64(0))
|
||||||
@ -205,28 +163,26 @@ func (parser *parser) parseList(scanner *scanner, ctx parserContext) (listTerm *
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
lastSym = scanner.Previous().Sym
|
lastSym = scanner.Previous().Sym
|
||||||
if itemExpected = lastSym == SymComma; itemExpected {
|
itemExpected = lastSym == SymComma
|
||||||
remFlags(ctx, allowIndex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if lastSym != SymClosedSquare {
|
if lastSym != SymClosedSquare {
|
||||||
err = scanner.Previous().ErrorExpectedGot("]")
|
err = scanner.Previous().ErrorExpectedGot("]")
|
||||||
} else {
|
} else {
|
||||||
listTerm = newListTerm(r, c, args)
|
subtree = newListTerm(r, c, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseIterDef(scanner *scanner, ctx parserContext) (subtree *term, err error) {
|
func (parser *parser) parseIterDef(scanner *scanner, allowVarRef bool) (subtree *term, err error) {
|
||||||
tk := scanner.Previous()
|
tk := scanner.Previous()
|
||||||
args := make([]*term, 0)
|
args := make([]*term, 0)
|
||||||
lastSym := SymUnknown
|
lastSym := SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
for lastSym != SymClosedRound && lastSym != SymEos {
|
for lastSym != SymClosedRound && lastSym != SymEos {
|
||||||
var subTree *ast
|
var subTree *ast
|
||||||
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedRound); err == nil {
|
if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedRound); err == nil {
|
||||||
if subTree.root != nil {
|
if subTree.root != nil {
|
||||||
args = append(args, subTree.root)
|
args = append(args, subTree.root)
|
||||||
} else if itemExpected {
|
} else if itemExpected {
|
||||||
@ -272,7 +228,7 @@ func (parser *parser) parseDictKey(scanner *scanner) (key any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subtree *term, err error) {
|
func (parser *parser) parseDictionary(scanner *scanner, allowVarRef bool) (subtree *term, err error) {
|
||||||
args := make(map[any]*term, 0)
|
args := make(map[any]*term, 0)
|
||||||
lastSym := SymUnknown
|
lastSym := SymUnknown
|
||||||
itemExpected := false
|
itemExpected := false
|
||||||
@ -289,7 +245,7 @@ func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subt
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if subTree, err = parser.parseItem(scanner, ctx, SymComma, SymClosedBrace); err == nil {
|
if subTree, err = parser.parseItem(scanner, allowVarRef, SymComma, SymClosedBrace); err == nil {
|
||||||
if subTree.root != nil {
|
if subTree.root != nil {
|
||||||
args[key] = subTree.root
|
args[key] = subTree.root
|
||||||
} else /*if key != nil*/ {
|
} else /*if key != nil*/ {
|
||||||
@ -308,15 +264,15 @@ func (parser *parser) parseDictionary(scanner *scanner, ctx parserContext) (subt
|
|||||||
err = scanner.Previous().ErrorExpectedGot("}")
|
err = scanner.Previous().ErrorExpectedGot("}")
|
||||||
} else {
|
} else {
|
||||||
subtree = newDictTerm(args)
|
subtree = newDictTerm(args)
|
||||||
|
// subtree = newMapTerm(args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, defaultCase bool) (caseTerm *term, err error) {
|
func (parser *parser) parseSelectorCase(scanner *scanner, allowVarRef bool, defaultCase bool) (caseTerm *term, err error) {
|
||||||
var filterList *term
|
var filterList *term
|
||||||
var caseExpr *ast
|
var caseExpr *ast
|
||||||
ctx = remFlags(ctx, allowIndex)
|
|
||||||
tk := parser.Next(scanner)
|
tk := parser.Next(scanner)
|
||||||
startRow := tk.row
|
startRow := tk.row
|
||||||
startCol := tk.col
|
startCol := tk.col
|
||||||
@ -325,7 +281,7 @@ func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, def
|
|||||||
err = tk.Errorf("case list in default clause")
|
err = tk.Errorf("case list in default clause")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if filterList, err = parser.parseList(scanner, remFlags(ctx, allowIndex)); err != nil {
|
if filterList, err = parser.parseList(scanner, false, allowVarRef); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tk = parser.Next(scanner)
|
tk = parser.Next(scanner)
|
||||||
@ -336,7 +292,7 @@ func (parser *parser) parseSelectorCase(scanner *scanner, ctx parserContext, def
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tk.Sym == SymOpenBrace {
|
if tk.Sym == SymOpenBrace {
|
||||||
if caseExpr, err = parser.parseGeneral(scanner, ctx|allowMultiExpr, SymClosedBrace); err != nil {
|
if caseExpr, err = parser.parseGeneral(scanner, true, allowVarRef, SymClosedBrace); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -362,28 +318,25 @@ func addSelectorCase(selectorTerm, caseTerm *term) {
|
|||||||
caseTerm.parent = selectorTerm
|
caseTerm.parent = selectorTerm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseSelector(scanner *scanner, tree *ast, ctx parserContext) (selectorTerm *term, err error) {
|
func (parser *parser) parseSelector(scanner *scanner, tree *ast, allowVarRef bool) (selectorTerm *term, err error) {
|
||||||
var caseTerm *term
|
var caseTerm *term
|
||||||
|
|
||||||
ctx = remFlags(ctx, allowIndex)
|
|
||||||
tk := scanner.makeToken(SymSelector, '?')
|
tk := scanner.makeToken(SymSelector, '?')
|
||||||
if selectorTerm, err = tree.addToken(tk); err != nil {
|
if selectorTerm, err = tree.addToken(tk); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if caseTerm, err = parser.parseSelectorCase(scanner, ctx|allowVarRef, false); err == nil {
|
if caseTerm, err = parser.parseSelectorCase(scanner, allowVarRef, false); err == nil {
|
||||||
addSelectorCase(selectorTerm, caseTerm)
|
addSelectorCase(selectorTerm, caseTerm)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) parseItem(scanner *scanner, ctx parserContext, termSymbols ...Symbol) (tree *ast, err error) {
|
func (parser *parser) parseItem(scanner *scanner, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
||||||
return parser.parseGeneral(scanner, ctx|allowVarRef, termSymbols...)
|
return parser.parseGeneral(scanner, false, allowVarRef, termSymbols...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (parser *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
|
func (parser *parser) Parse(scanner *scanner, termSymbols ...Symbol) (tree *ast, err error) {
|
||||||
termSymbols = append(termSymbols, SymEos)
|
return parser.parseGeneral(scanner, true, false, termSymbols...)
|
||||||
return parser.parseGeneral(scanner, allowMultiExpr, termSymbols...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func couldBeACollection(t *term) bool {
|
func couldBeACollection(t *term) bool {
|
||||||
@ -394,22 +347,15 @@ func couldBeACollection(t *term) bool {
|
|||||||
return sym == SymList || sym == SymString || sym == SymDict || sym == SymExpression || sym == SymVariable
|
return sym == SymList || sym == SymString || sym == SymDict || sym == SymExpression || sym == SymVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
func listSubTree(tree *ast, listTerm *term, allowIndeces bool) (root *term, err error) {
|
// func areSymbolsOutOfCtx(tk *Token, ctxTerm *term, syms ...Symbol) bool {
|
||||||
var tk *Token
|
// var areOut = false
|
||||||
if allowIndeces {
|
// if ctxTerm != nil {
|
||||||
tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.source())
|
// areOut = tk.IsOneOf(syms)
|
||||||
root = newTerm(tk)
|
// }
|
||||||
if err = tree.addTerm(root); err == nil {
|
// return areOut
|
||||||
err = tree.addTerm(listTerm)
|
// }
|
||||||
}
|
|
||||||
} else {
|
|
||||||
root = listTerm
|
|
||||||
err = tree.addTerm(listTerm)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymbols ...Symbol) (tree *ast, err error) {
|
func (parser *parser) parseGeneral(scanner *scanner, allowForest bool, allowVarRef bool, termSymbols ...Symbol) (tree *ast, err error) {
|
||||||
var selectorTerm *term = nil
|
var selectorTerm *term = nil
|
||||||
var currentTerm *term = nil
|
var currentTerm *term = nil
|
||||||
var tk *Token
|
var tk *Token
|
||||||
@ -423,7 +369,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
if tk.Sym == SymSemiColon {
|
if tk.Sym == SymSemiColon {
|
||||||
if hasFlag(ctx, allowMultiExpr) {
|
if allowForest {
|
||||||
tree.ToForest()
|
tree.ToForest()
|
||||||
firstToken = true
|
firstToken = true
|
||||||
currentTerm = nil
|
currentTerm = nil
|
||||||
@ -448,36 +394,47 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
|
|||||||
switch tk.Sym {
|
switch tk.Sym {
|
||||||
case SymOpenRound:
|
case SymOpenRound:
|
||||||
var subTree *ast
|
var subTree *ast
|
||||||
if subTree, err = parser.parseGeneral(scanner, ctx, SymClosedRound); err == nil {
|
if subTree, err = parser.parseGeneral(scanner, false, allowVarRef, SymClosedRound); err == nil {
|
||||||
subTree.root.priority = priValue
|
subTree.root.priority = priValue
|
||||||
err = tree.addTerm(newExprTerm(subTree.root))
|
err = tree.addTerm(newExprTerm(subTree.root))
|
||||||
currentTerm = subTree.root
|
currentTerm = subTree.root
|
||||||
}
|
}
|
||||||
case SymFuncCall:
|
case SymFuncCall:
|
||||||
var funcCallTerm *term
|
var funcCallTerm *term
|
||||||
if funcCallTerm, err = parser.parseFuncCall(scanner, ctx, tk); err == nil {
|
if funcCallTerm, err = parser.parseFuncCall(scanner, allowVarRef, tk); err == nil {
|
||||||
err = tree.addTerm(funcCallTerm)
|
err = tree.addTerm(funcCallTerm)
|
||||||
currentTerm = funcCallTerm
|
currentTerm = funcCallTerm
|
||||||
}
|
}
|
||||||
case SymOpenSquare:
|
case SymOpenSquare:
|
||||||
var listTerm *term
|
var listTerm *term
|
||||||
newCtx := addFlagsCond(addFlags(ctx, squareContext), allowIndex, couldBeACollection(currentTerm))
|
parsingIndeces := couldBeACollection(currentTerm)
|
||||||
if listTerm, err = parser.parseList(scanner, newCtx); err == nil {
|
if listTerm, err = parser.parseList(scanner, parsingIndeces, allowVarRef); err == nil {
|
||||||
currentTerm, err = listSubTree(tree, listTerm, hasFlag(newCtx, allowIndex))
|
if parsingIndeces {
|
||||||
|
indexTk := NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.source())
|
||||||
|
indexTerm := newTerm(indexTk)
|
||||||
|
if err = tree.addTerm(indexTerm); err == nil {
|
||||||
|
err = tree.addTerm(listTerm)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = tree.addTerm(listTerm)
|
||||||
|
}
|
||||||
|
currentTerm = listTerm
|
||||||
}
|
}
|
||||||
case SymOpenBrace:
|
case SymOpenBrace:
|
||||||
if currentTerm != nil && currentTerm.symbol() == SymColon {
|
if currentTerm != nil && currentTerm.symbol() == SymColon {
|
||||||
err = currentTerm.Errorf(`selector-case outside of a selector context`)
|
err = currentTerm.Errorf(`selector-case outside of a selector context`)
|
||||||
} else {
|
} else {
|
||||||
var mapTerm *term
|
var mapTerm *term
|
||||||
if mapTerm, err = parser.parseDictionary(scanner, ctx); err == nil {
|
if mapTerm, err = parser.parseDictionary(scanner, allowVarRef); err == nil {
|
||||||
err = tree.addTerm(mapTerm)
|
err = tree.addTerm(mapTerm)
|
||||||
currentTerm = mapTerm
|
currentTerm = mapTerm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual:
|
case SymEqual:
|
||||||
|
// if err = checkPrevSymbol(lastSym, SymIdentifier, tk); err == nil {
|
||||||
currentTerm, err = tree.addToken(tk)
|
currentTerm, err = tree.addToken(tk)
|
||||||
firstToken = true
|
firstToken = true
|
||||||
|
// }
|
||||||
case SymFuncDef:
|
case SymFuncDef:
|
||||||
var funcDefTerm *term
|
var funcDefTerm *term
|
||||||
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
|
if funcDefTerm, err = parser.parseFuncDef(scanner); err == nil {
|
||||||
@ -486,25 +443,24 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
|
|||||||
}
|
}
|
||||||
case SymDollarRound:
|
case SymDollarRound:
|
||||||
var iterDefTerm *term
|
var iterDefTerm *term
|
||||||
if iterDefTerm, err = parser.parseIterDef(scanner, ctx); err == nil {
|
if iterDefTerm, err = parser.parseIterDef(scanner, allowVarRef); err == nil {
|
||||||
err = tree.addTerm(iterDefTerm)
|
err = tree.addTerm(iterDefTerm)
|
||||||
currentTerm = iterDefTerm
|
currentTerm = iterDefTerm
|
||||||
}
|
}
|
||||||
case SymIdentifier:
|
case SymIdentifier:
|
||||||
if tk.source[0] == '@' && !hasFlag(ctx, allowVarRef) {
|
if tk.source[0] == '@' && !allowVarRef {
|
||||||
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.source)
|
err = tk.Errorf("variable references are not allowed in top level expressions: %q", tk.source)
|
||||||
} else {
|
} else {
|
||||||
currentTerm, err = tree.addToken(tk)
|
currentTerm, err = tree.addToken(tk)
|
||||||
}
|
}
|
||||||
case SymQuestion:
|
case SymQuestion:
|
||||||
if selectorTerm, err = parser.parseSelector(scanner, tree, ctx); err == nil {
|
if selectorTerm, err = parser.parseSelector(scanner, tree, allowVarRef); err == nil {
|
||||||
currentTerm = selectorTerm
|
currentTerm = selectorTerm
|
||||||
addFlags(ctx, selectorContext)
|
|
||||||
}
|
}
|
||||||
case SymColon, SymDoubleColon:
|
case SymColon, SymDoubleColon:
|
||||||
var caseTerm *term
|
var caseTerm *term
|
||||||
if selectorTerm != nil {
|
if selectorTerm != nil {
|
||||||
if caseTerm, err = parser.parseSelectorCase(scanner, ctx, tk.Sym == SymDoubleColon); err == nil {
|
if caseTerm, err = parser.parseSelectorCase(scanner, allowVarRef, tk.Sym == SymDoubleColon); err == nil {
|
||||||
addSelectorCase(selectorTerm, caseTerm)
|
addSelectorCase(selectorTerm, caseTerm)
|
||||||
currentTerm = caseTerm
|
currentTerm = caseTerm
|
||||||
if tk.Sym == SymDoubleColon {
|
if tk.Sym == SymDoubleColon {
|
||||||
@ -512,38 +468,80 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if hasFlag(ctx, allowIndex) {
|
|
||||||
// tk.Sym = SymRange
|
|
||||||
// }
|
|
||||||
currentTerm, err = tree.addToken(tk)
|
currentTerm, err = tree.addToken(tk)
|
||||||
}
|
}
|
||||||
if tk.IsOneOfA(SymColon, SymRange) {
|
if tk.IsSymbol(SymColon) {
|
||||||
// Colon outside a selector term acts like a separator
|
// Colon outside a selector term acts like a separator
|
||||||
firstToken = true
|
firstToken = true
|
||||||
}
|
}
|
||||||
|
case SymPlusEqual, SymMinusEqual, SymStarEqual:
|
||||||
|
currentTerm, err = parser.expandOpAssign(scanner, tree, tk, allowVarRef)
|
||||||
default:
|
default:
|
||||||
currentTerm, err = tree.addToken(tk)
|
currentTerm, err = tree.addToken(tk)
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentTerm != nil && currentTerm.tk.Sym != SymSelector && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
|
if currentTerm != nil && currentTerm.tk.Sym != SymSelector && currentTerm.parent != nil && currentTerm.parent.tk.Sym != SymSelector {
|
||||||
selectorTerm = nil
|
selectorTerm = nil
|
||||||
remFlags(ctx, selectorContext)
|
|
||||||
}
|
}
|
||||||
// lastSym = tk.Sym
|
// lastSym = tk.Sym
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if !tk.IsOneOf(termSymbols) {
|
err = tk.Error()
|
||||||
var symDesc string
|
}
|
||||||
if tk.IsSymbol(SymError) {
|
return
|
||||||
symDesc = tk.ErrorText()
|
}
|
||||||
} else {
|
|
||||||
symDesc = SymToString(tk.Sym)
|
// func checkPrevSymbol(lastSym, wantedSym Symbol, tk *Token) (err error) {
|
||||||
}
|
// if lastSym != wantedSym {
|
||||||
err = tk.ErrorExpectedGotStringWithPrefix("expected one of", SymListToString(termSymbols, true), symDesc)
|
// err = fmt.Errorf(`assign operator (%q) must be preceded by a variable`, tk.source)
|
||||||
} else {
|
// }
|
||||||
err = tk.Error()
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
func (parser *parser) expandOpAssign(scanner *scanner, tree *ast, tk *Token, allowVarRef bool) (t *term, err error) {
|
||||||
|
var opSym Symbol
|
||||||
|
var opString string
|
||||||
|
|
||||||
|
if tree.root != nil {
|
||||||
|
switch tk.Sym {
|
||||||
|
case SymPlusEqual:
|
||||||
|
opString = "+"
|
||||||
|
opSym = SymPlus
|
||||||
|
case SymMinusEqual:
|
||||||
|
opString = "-"
|
||||||
|
opSym = SymMinus
|
||||||
|
case SymStarEqual:
|
||||||
|
opString = "*"
|
||||||
|
opSym = SymStar
|
||||||
|
default:
|
||||||
|
err = tk.Errorf("unsopported operator %q", tk.source)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
leftExpr := tree.root.Clone()
|
||||||
|
leftExpr.setParent(nil)
|
||||||
|
if t, err = tree.addToken(NewToken(tk.row, tk.col, SymEqual, "=")); err == nil {
|
||||||
|
t = leftExpr
|
||||||
|
if err = tree.addTerm(leftExpr); err == nil {
|
||||||
|
if t, err = tree.addToken(NewToken(tk.row, tk.col, opSym, opString)); err == nil {
|
||||||
|
|
||||||
|
var subTree *ast
|
||||||
|
if subTree, err = parser.parseGeneral(scanner, false, allowVarRef, SymSemiColon, SymClosedRound, SymClosedBrace, SymClosedSquare); err == nil {
|
||||||
|
if scanner.Previous().IsOneOfA(SymSemiColon, SymClosedRound, SymClosedBrace, SymClosedSquare) {
|
||||||
|
if err = scanner.UnreadToken(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subTree.root.priority = priValue
|
||||||
|
err = tree.addTerm(newExprTerm(subTree.root))
|
||||||
|
t = subTree.root
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = tk.Errorf("left operand of %q must be a variable or a variable expression", tk)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
10
scanner.go
10
scanner.go
@ -40,9 +40,9 @@ func DefaultTranslations() map[Symbol]Symbol {
|
|||||||
SymKwAnd: SymAnd,
|
SymKwAnd: SymAnd,
|
||||||
SymDoubleVertBar: SymOr,
|
SymDoubleVertBar: SymOr,
|
||||||
SymKwOr: SymOr,
|
SymKwOr: SymOr,
|
||||||
// SymTilde: SymNot,
|
SymTilde: SymNot,
|
||||||
SymKwNot: SymNot,
|
SymKwNot: SymNot,
|
||||||
SymLessGreater: SymNotEqual,
|
SymLessGreater: SymNotEqual,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,8 +149,6 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
|
|||||||
if next, _ := scanner.peek(); next == '*' {
|
if next, _ := scanner.peek(); next == '*' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.fetchBlockComment()
|
tk = scanner.fetchBlockComment()
|
||||||
} else if next, _ = scanner.peek(); next == '=' {
|
|
||||||
tk = scanner.moveOn(SymSlashEqual, ch, next)
|
|
||||||
} else if next == '/' {
|
} else if next == '/' {
|
||||||
scanner.readChar()
|
scanner.readChar()
|
||||||
tk = scanner.fetchOnLineComment()
|
tk = scanner.fetchOnLineComment()
|
||||||
@ -592,7 +590,7 @@ func (scanner *scanner) fetchString(termCh byte) (tk *Token) {
|
|||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
tk = scanner.makeErrorToken(errors.New(string(termCh)))
|
tk = scanner.makeErrorToken(errors.New("missing string termination \""))
|
||||||
} else {
|
} else {
|
||||||
tk = scanner.makeErrorToken(err)
|
tk = scanner.makeErrorToken(err)
|
||||||
}
|
}
|
||||||
|
181
symbol-map.go
181
symbol-map.go
@ -1,181 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// Symbol.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var symbolMap map[Symbol]symbolSpec
|
|
||||||
|
|
||||||
type symbolClass int16
|
|
||||||
|
|
||||||
const (
|
|
||||||
symClassOperator symbolClass = iota
|
|
||||||
symClassPostOp
|
|
||||||
symClassIdentifier
|
|
||||||
symClassDelimiter
|
|
||||||
symClassParenthesis
|
|
||||||
symClassDeclaration
|
|
||||||
symClassValue
|
|
||||||
symClassOther
|
|
||||||
)
|
|
||||||
|
|
||||||
type symbolSpec struct {
|
|
||||||
repr string
|
|
||||||
kind symbolClass
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
|
|
||||||
symbolMap = map[Symbol]symbolSpec{
|
|
||||||
SymUnknown: {"<unknown>", symClassOther}, // -1: Unknown symbol
|
|
||||||
SymNone: {"<null>", symClassOther}, // 0: Null value for variable of type symbol
|
|
||||||
SymError: {"<error>", symClassOther}, // 1: Error reading from stream
|
|
||||||
SymEos: {"<eos>", symClassOther}, // 2: End of stream
|
|
||||||
SymMinus: {"-", symClassOperator}, // 3: '-'
|
|
||||||
SymMinusEqual: {"-=", symClassOperator}, // 4: '-='
|
|
||||||
SymDoubleMinus: {"--", symClassOperator}, // 5: '--'
|
|
||||||
SymPlus: {"+", symClassOperator}, // 6: '+'
|
|
||||||
SymPlusEqual: {"+=", symClassOperator}, // 7: '+='
|
|
||||||
SymDoublePlus: {"++", symClassOperator}, // 8: '++'
|
|
||||||
SymStar: {"*", symClassOperator}, // 9: '*'
|
|
||||||
SymDoubleStar: {"**", symClassOperator}, // 10: '**'
|
|
||||||
SymSlash: {"/", symClassOperator}, // 11: '/'
|
|
||||||
SymBackSlash: {"\\", symClassOperator}, // 12: '\'
|
|
||||||
SymVertBar: {"|", symClassOperator}, // 13: '|'
|
|
||||||
SymDoubleVertBar: {"||", symClassOperator}, // 14: '||'
|
|
||||||
SymComma: {",", symClassOperator}, // 15: ','
|
|
||||||
SymColon: {":", symClassOperator}, // 16: ':'
|
|
||||||
SymSemiColon: {";", symClassOperator}, // 17: ';'
|
|
||||||
SymDot: {".", symClassOperator}, // 18: '.'
|
|
||||||
SymDotSlash: {"./", symClassOperator}, // 19: './'
|
|
||||||
SymQuote: {"'", symClassDelimiter}, // 20: '\''
|
|
||||||
SymDoubleQuote: {"\"", symClassDelimiter}, // 21: '"'
|
|
||||||
SymBackTick: {"`", symClassOperator}, // 22: '`'
|
|
||||||
SymExclamation: {"!", symClassPostOp}, // 23: '!'
|
|
||||||
SymQuestion: {"?", symClassOperator}, // 24: '?'
|
|
||||||
SymAmpersand: {"&", symClassOperator}, // 25: '&'
|
|
||||||
SymDoubleAmpersand: {"&&", symClassOperator}, // 26: '&&'
|
|
||||||
SymPercent: {"%", symClassOperator}, // 27: '%'
|
|
||||||
SymAt: {"@", symClassOperator}, // 28: '@'
|
|
||||||
SymUndescore: {"_", symClassOperator}, // 29: '_'
|
|
||||||
SymEqual: {"=", symClassOperator}, // 30: '='
|
|
||||||
SymDoubleEqual: {"==", symClassOperator}, // 31: '=='
|
|
||||||
SymLess: {"<", symClassOperator}, // 32: '<'
|
|
||||||
SymLessOrEqual: {"<=", symClassOperator}, // 33: '<='
|
|
||||||
SymGreater: {">", symClassOperator}, // 34: '>'
|
|
||||||
SymGreaterOrEqual: {">=", symClassOperator}, // 35: '>='
|
|
||||||
SymLessGreater: {"<>", symClassOperator}, // 36: '<>'
|
|
||||||
SymNotEqual: {"!=", symClassOperator}, // 37: '!='
|
|
||||||
SymDollar: {"$", symClassOperator}, // 38: '$'
|
|
||||||
SymHash: {"#", symClassOperator}, // 39: '#'
|
|
||||||
SymOpenRound: {"(", symClassParenthesis}, // 40: '('
|
|
||||||
SymClosedRound: {")", symClassParenthesis}, // 41: ')'
|
|
||||||
SymOpenSquare: {"[", symClassParenthesis}, // 42: '['
|
|
||||||
SymClosedSquare: {"]", symClassParenthesis}, // 43: ']'
|
|
||||||
SymOpenBrace: {"{", symClassParenthesis}, // 44: '{'
|
|
||||||
SymClosedBrace: {"}", symClassParenthesis}, // 45: '}'
|
|
||||||
SymTilde: {"~", symClassOperator}, // 46: '~'
|
|
||||||
SymDoubleQuestion: {"??", symClassOperator}, // 47: '??'
|
|
||||||
SymQuestionEqual: {"?=", symClassOperator}, // 48: '?='
|
|
||||||
SymQuestionExclam: {"?!", symClassOperator}, // 49: '?!'
|
|
||||||
SymDoubleAt: {"@@", symClassOperator}, // 50: '@@'
|
|
||||||
SymDoubleColon: {"::", symClassOperator}, // 51: '::'
|
|
||||||
SymInsert: {">>", symClassOperator}, // 52: '>>'
|
|
||||||
SymAppend: {"<<", symClassOperator}, // 53: '<<'
|
|
||||||
SymCaret: {"^", symClassOperator}, // 54: '^'
|
|
||||||
SymDollarRound: {"$(", symClassOperator}, // 55: '$('
|
|
||||||
SymOpenClosedRound: {"()", symClassPostOp}, // 56: '()'
|
|
||||||
SymDoubleDollar: {"$$", symClassOperator}, // 57: '$$'
|
|
||||||
SymDoubleDot: {"..", symClassOperator}, // 58: '..'
|
|
||||||
SymTripleDot: {"...", symClassOperator}, // 59: '...'
|
|
||||||
SymStarEqual: {"*=", symClassOperator}, // 60: '*='
|
|
||||||
SymSlashEqual: {"/=", symClassOperator}, // 61: '/='
|
|
||||||
SymPercEqual: {"%=", symClassOperator}, // 62: '%='
|
|
||||||
// SymChangeSign
|
|
||||||
// SymUnchangeSign
|
|
||||||
// SymIdentifier
|
|
||||||
// SymBool
|
|
||||||
// SymInteger
|
|
||||||
// SymVariable
|
|
||||||
// SymFloat
|
|
||||||
// SymFraction
|
|
||||||
// SymString
|
|
||||||
// SymIterator
|
|
||||||
// SymOr: "or",
|
|
||||||
// SymAnd: "and",
|
|
||||||
// SymNot: "not",
|
|
||||||
// SymComment
|
|
||||||
// SymFuncCall
|
|
||||||
// SymFuncDef
|
|
||||||
// SymList
|
|
||||||
// SymDict
|
|
||||||
// SymIndex
|
|
||||||
// SymExpression
|
|
||||||
// SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
|
||||||
// SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
|
||||||
// // SymOpenComment // 0: '/*'
|
|
||||||
// // SymClosedComment // 0: '*/'
|
|
||||||
// // SymOneLineComment // 0: '//'
|
|
||||||
// keywordBase
|
|
||||||
SymKwAnd: {"and", symClassOperator},
|
|
||||||
SymKwNot: {"not", symClassOperator},
|
|
||||||
SymKwOr: {"or", symClassOperator},
|
|
||||||
SymKwBut: {"but", symClassOperator},
|
|
||||||
SymKwFunc: {"func(", symClassDeclaration},
|
|
||||||
SymKwBuiltin: {"builtin", symClassOperator},
|
|
||||||
SymKwPlugin: {"plugin", symClassOperator},
|
|
||||||
SymKwIn: {"in", symClassOperator},
|
|
||||||
SymKwInclude: {"include", symClassOperator},
|
|
||||||
SymKwNil: {"nil", symClassValue},
|
|
||||||
SymKwUnset: {"unset", symClassOperator},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SymToString(sym Symbol) string {
|
|
||||||
if s, ok := symbolMap[sym]; ok {
|
|
||||||
return s.repr
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func SymListToString(symList []Symbol, quote bool) string {
|
|
||||||
var sb strings.Builder
|
|
||||||
if len(symList) == 0 {
|
|
||||||
sb.WriteString("<nothing>")
|
|
||||||
} else {
|
|
||||||
for _, sym := range symList {
|
|
||||||
if sb.Len() > 0 {
|
|
||||||
sb.WriteByte(',')
|
|
||||||
sb.WriteByte(' ')
|
|
||||||
}
|
|
||||||
if quote {
|
|
||||||
sb.WriteByte('`')
|
|
||||||
}
|
|
||||||
sb.WriteString(SymToString(sym))
|
|
||||||
if quote {
|
|
||||||
sb.WriteByte('`')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func StringEndsWithOperator(s string) bool {
|
|
||||||
return endingOperator(s) != SymNone
|
|
||||||
}
|
|
||||||
|
|
||||||
func endingOperator(s string) (sym Symbol) {
|
|
||||||
sym = SymNone
|
|
||||||
lower := strings.ToLower(s)
|
|
||||||
for symbol, spec := range symbolMap {
|
|
||||||
if spec.kind == symClassOperator && strings.HasSuffix(lower, spec.repr) {
|
|
||||||
sym = symbol
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
@ -69,8 +69,6 @@ const (
|
|||||||
SymDoubleDot // 58: '..'
|
SymDoubleDot // 58: '..'
|
||||||
SymTripleDot // 59: '...'
|
SymTripleDot // 59: '...'
|
||||||
SymStarEqual // 60: '*='
|
SymStarEqual // 60: '*='
|
||||||
SymSlashEqual // 61: '/='
|
|
||||||
SymPercEqual // 62: '%='
|
|
||||||
SymChangeSign
|
SymChangeSign
|
||||||
SymUnchangeSign
|
SymUnchangeSign
|
||||||
SymIdentifier
|
SymIdentifier
|
||||||
@ -90,7 +88,6 @@ const (
|
|||||||
SymList
|
SymList
|
||||||
SymDict
|
SymDict
|
||||||
SymIndex
|
SymIndex
|
||||||
SymRange // [index : index]
|
|
||||||
SymExpression
|
SymExpression
|
||||||
SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
SymSelector // <selector> ::= <expr> "?" <selector-case> {":" <selector-case>} ["::" <default-selector-case>]
|
||||||
SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
SymSelectorCase // <selector-case> ::= [<list>] "{" <multi-expr> "}"
|
||||||
|
@ -30,9 +30,9 @@ func TestFuncBase(t *testing.T) {
|
|||||||
/* 16 */ {`isString("3" + 1)`, true, nil},
|
/* 16 */ {`isString("3" + 1)`, true, nil},
|
||||||
/* 17 */ {`isList(["3", 1])`, true, nil},
|
/* 17 */ {`isList(["3", 1])`, true, nil},
|
||||||
/* 18 */ {`isDict({"a":"3", "b":1})`, true, nil},
|
/* 18 */ {`isDict({"a":"3", "b":1})`, true, nil},
|
||||||
/* 19 */ {`isFract(1:3)`, true, nil},
|
/* 19 */ {`isFract(1|3)`, true, nil},
|
||||||
/* 20 */ {`isFract(3:1)`, false, nil},
|
/* 20 */ {`isFract(3|1)`, false, nil},
|
||||||
/* 21 */ {`isRational(3:1)`, true, nil},
|
/* 21 */ {`isRational(3|1)`, true, nil},
|
||||||
/* 22 */ {`fract("2.2(3)")`, newFraction(67, 30), nil},
|
/* 22 */ {`fract("2.2(3)")`, newFraction(67, 30), nil},
|
||||||
/* 23 */ {`fract("1.21(3)")`, newFraction(91, 75), nil},
|
/* 23 */ {`fract("1.21(3)")`, newFraction(91, 75), nil},
|
||||||
/* 24 */ {`fract(1.21(3))`, newFraction(91, 75), nil},
|
/* 24 */ {`fract(1.21(3))`, newFraction(91, 75), nil},
|
||||||
@ -41,26 +41,26 @@ func TestFuncBase(t *testing.T) {
|
|||||||
/* 27 */ {`dec(2.0)`, float64(2), nil},
|
/* 27 */ {`dec(2.0)`, float64(2), nil},
|
||||||
/* 28 */ {`dec("2.0")`, float64(2), nil},
|
/* 28 */ {`dec("2.0")`, float64(2), nil},
|
||||||
/* 29 */ {`dec(true)`, float64(1), nil},
|
/* 29 */ {`dec(true)`, float64(1), nil},
|
||||||
/* 30 */ {`dec(true")`, nil, "[1:11] expected one of `,`, `)`, got `\"`"},
|
/* 30 */ {`dec(true")`, nil, `[1:11] missing string termination "`},
|
||||||
/* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`},
|
/* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`},
|
||||||
/* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`},
|
/* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`},
|
||||||
/* 33 */ {`isBool(false)`, true, nil},
|
/* 33 */ {`isBool(false)`, true, nil},
|
||||||
/* 34 */ {`fract(1:2)`, newFraction(1, 2), nil},
|
/* 34 */ {`fract(1|2)`, newFraction(1, 2), nil},
|
||||||
/* 35 */ {`fract(12,2)`, newFraction(6, 1), nil},
|
/* 35 */ {`fract(12,2)`, newFraction(6, 1), nil},
|
||||||
/* 36 */ {`bool(2)`, true, nil},
|
/* 36 */ {`bool(2)`, true, nil},
|
||||||
/* 37 */ {`bool(1:2)`, true, nil},
|
/* 37 */ {`bool(1|2)`, true, nil},
|
||||||
/* 38 */ {`bool(1.0)`, true, nil},
|
/* 38 */ {`bool(1.0)`, true, nil},
|
||||||
/* 39 */ {`bool("1")`, true, nil},
|
/* 39 */ {`bool("1")`, true, nil},
|
||||||
/* 40 */ {`bool(false)`, false, nil},
|
/* 40 */ {`bool(false)`, false, nil},
|
||||||
/* 41 */ {`bool([1])`, nil, `bool(): can't convert list to bool`},
|
/* 41 */ {`bool([1])`, nil, `bool(): can't convert list to bool`},
|
||||||
/* 42 */ {`dec(false)`, float64(0), nil},
|
/* 42 */ {`dec(false)`, float64(0), nil},
|
||||||
/* 43 */ {`dec(1:2)`, float64(0.5), nil},
|
/* 43 */ {`dec(1|2)`, float64(0.5), nil},
|
||||||
/* 44 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
|
/* 44 */ {`dec([1])`, nil, `dec(): can't convert list to float`},
|
||||||
// /* 45 */ {`string([1])`, nil, `string(): can't convert list to string`},
|
// /* 45 */ {`string([1])`, nil, `string(): can't convert list to string`},
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("EXPR_PATH", ".")
|
t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 30)
|
//runTestSuiteSpec(t, section, inputs, 10)
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
@ -17,13 +17,13 @@ func TestExpr(t *testing.T) {
|
|||||||
/* 3 */ {`builtin "os.file"; f=fileOpen("test-file.txt"); line=fileReadText(f); fileClose(f); line`, "uno", nil},
|
/* 3 */ {`builtin "os.file"; f=fileOpen("test-file.txt"); line=fileReadText(f); fileClose(f); line`, "uno", nil},
|
||||||
/* 4 */ {`mynot=func(v){int(v)?{true}::{false}}; mynot(0)`, true, nil},
|
/* 4 */ {`mynot=func(v){int(v)?{true}::{false}}; mynot(0)`, true, nil},
|
||||||
/* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
|
/* 5 */ {`1 ? {1} : [1+0] {3*(1+1)}`, int64(6), nil},
|
||||||
/* 6 */ {`a=3; a+=1; a`, int64(4), nil},
|
/* 6 */ {`a=3; a+=1`, int64(4), nil},
|
||||||
/* 7 */ {`a=3; a-=1; a`, int64(2), nil},
|
/* 7 */ {`a=3; a-=1`, int64(2), nil},
|
||||||
/* 8 */ {`a=3; a*=2; a`, int64(6), nil},
|
/* 8 */ {`a=3; a*=2`, int64(6), nil},
|
||||||
/* 9 */ {`v=[10,20,30]; v[0]+=1; v[0]`, int64(11), nil},
|
/* 9 */ {`v=[10,20,30]; v[0]+=1; v[0]`, int64(11), nil},
|
||||||
/* 10 */ {`r={"a":10}; r["a"]+=1; r["a"]`, int64(11), nil},
|
/* 10 */ {`r={"a":10}; r["a"]+=1; r["a"]`, int64(11), nil},
|
||||||
/* 11 */ {`a=3; a/=2`, int64(1), nil},
|
/* 11 */ {`a=3; a/=2`, nil, `[1:8] left operand of "=" must be a variable or a collection's item`},
|
||||||
/* 12 */ {`*=2`, nil, `[1:2] infix operator "*=" requires two non-nil operands, got 1`},
|
/* 12 */ {`*=2`, nil, `[1:2] left operand of "*=" must be a variable or a variable expression`},
|
||||||
/* 13 */ {`a=3; a*=2+1; a`, int64(9), nil},
|
/* 13 */ {`a=3; a*=2+1; a`, int64(9), nil},
|
||||||
/* 14 */ {`a=3; (a*=2)+1; a`, int64(6), nil},
|
/* 14 */ {`a=3; (a*=2)+1; a`, int64(6), nil},
|
||||||
/* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
|
/* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`},
|
||||||
@ -44,6 +44,6 @@ func TestExpr(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 6, 7, 8, 9)
|
// runTestSuiteSpec(t, section, inputs, 17)
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
@ -11,39 +11,35 @@ import (
|
|||||||
func TestFractionsParser(t *testing.T) {
|
func TestFractionsParser(t *testing.T) {
|
||||||
section := "Fraction"
|
section := "Fraction"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`1:2`, newFraction(1, 2), nil},
|
/* 1 */ {`1|2`, newFraction(1, 2), nil},
|
||||||
/* 2 */ {`1:2 + 1`, newFraction(3, 2), nil},
|
/* 2 */ {`1|2 + 1`, newFraction(3, 2), nil},
|
||||||
/* 3 */ {`1:2 - 1`, newFraction(-1, 2), nil},
|
/* 3 */ {`1|2 - 1`, newFraction(-1, 2), nil},
|
||||||
/* 4 */ {`1:2 * 1`, newFraction(1, 2), nil},
|
/* 4 */ {`1|2 * 1`, newFraction(1, 2), nil},
|
||||||
/* 5 */ {`1:2 * 2:3`, newFraction(2, 6), nil},
|
/* 5 */ {`1|2 * 2|3`, newFraction(2, 6), nil},
|
||||||
/* 6 */ {`1:2 / 2:3`, newFraction(3, 4), nil},
|
/* 6 */ {`1|2 / 2|3`, newFraction(3, 4), nil},
|
||||||
/* 7 */ {`1:"5"`, nil, `denominator must be integer, got string (5)`},
|
/* 7 */ {`1|"5"`, nil, `denominator must be integer, got string (5)`},
|
||||||
/* 8 */ {`"1":5`, nil, `numerator must be integer, got string (1)`},
|
/* 8 */ {`"1"|5`, nil, `numerator must be integer, got string (1)`},
|
||||||
/* 9 */ {`1:+5`, newFraction(1, 5), nil},
|
/* 9 */ {`1|+5`, nil, `[1:3] infix operator "|" requires two non-nil operands, got 1`},
|
||||||
/* 10 */ {`1:(-2)`, newFraction(-1, 2), nil},
|
/* 10 */ {`1|(-2)`, newFraction(-1, 2), nil},
|
||||||
/* 11 */ {`builtin "math.arith"; add(1:2, 2:3)`, newFraction(7, 6), nil},
|
/* 11 */ {`builtin "math.arith"; add(1|2, 2|3)`, newFraction(7, 6), nil},
|
||||||
/* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil},
|
/* 12 */ {`builtin "math.arith"; add(1|2, 1.0, 2)`, float64(3.5), nil},
|
||||||
/* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, newFraction(2, 6), nil},
|
/* 13 */ {`builtin "math.arith"; mul(1|2, 2|3)`, newFraction(2, 6), nil},
|
||||||
/* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil},
|
/* 14 */ {`builtin "math.arith"; mul(1|2, 1.0, 2)`, float64(1.0), nil},
|
||||||
/* 15 */ {`1:0`, nil, `division by zero`},
|
/* 15 */ {`1|0`, nil, `division by zero`},
|
||||||
/* 16 */ {`fract(-0.5)`, newFraction(-1, 2), nil},
|
/* 16 */ {`fract(-0.5)`, newFraction(-1, 2), nil},
|
||||||
/* 17 */ {`fract("")`, (*FractionType)(nil), `bad syntax`},
|
/* 17 */ {`fract("")`, (*FractionType)(nil), `bad syntax`},
|
||||||
/* 18 */ {`fract("-1")`, newFraction(-1, 1), nil},
|
/* 18 */ {`fract("-1")`, newFraction(-1, 1), nil},
|
||||||
/* 19 */ {`fract("+1")`, newFraction(1, 1), nil},
|
/* 19 */ {`fract("+1")`, newFraction(1, 1), nil},
|
||||||
/* 20 */ {`fract("1a")`, (*FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`},
|
/* 20 */ {`fract("1a")`, (*FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`},
|
||||||
/* 21 */ {`fract(1,0)`, nil, `fract(): division by zero`},
|
/* 21 */ {`fract(1,0)`, nil, `fract(): division by zero`},
|
||||||
/* 22 */ {`string(1:2)`, "1:2", nil},
|
/* 22 */ {`string(1|2)`, "1|2", nil},
|
||||||
/* 23 */ {`1+1:2+0.5`, float64(2), nil},
|
|
||||||
/* 24 */ {`1:(2-2)`, nil, `division by zero`},
|
|
||||||
/* 25 */ {`[0,1][1-1]:1`, newFraction(0, 1), nil},
|
|
||||||
}
|
}
|
||||||
// runTestSuiteSpec(t, section, inputs, 25)
|
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFractionToStringSimple(t *testing.T) {
|
func TestFractionToStringSimple(t *testing.T) {
|
||||||
source := newFraction(1, 2)
|
source := newFraction(1, 2)
|
||||||
want := "1:2"
|
want := "1|2"
|
||||||
got := source.ToString(0)
|
got := source.ToString(0)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf(`(1,2) -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
t.Errorf(`(1,2) -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
||||||
|
@ -16,13 +16,11 @@ func TestCollections(t *testing.T) {
|
|||||||
/* 3 */ {`"abcdef"[1:]`, "bcdef", nil},
|
/* 3 */ {`"abcdef"[1:]`, "bcdef", nil},
|
||||||
/* 4 */ {`"abcdef"[:]`, "abcdef", nil},
|
/* 4 */ {`"abcdef"[:]`, "abcdef", nil},
|
||||||
// /* 5 */ {`[0,1,2,3,4][:]`, ListType{int64(0), int64(1), int64(2), int64(3), int64(4)}, nil},
|
// /* 5 */ {`[0,1,2,3,4][:]`, ListType{int64(0), int64(1), int64(2), int64(3), int64(4)}, nil},
|
||||||
/* 5 */ {`"abcdef"[1:2:3]`, nil, `[1:14] invalid range specification`},
|
/* 5 */ {`"abcdef"[1:2:3]`, nil, `[1:14] left operand '(1, 2)' [pair] and right operand '3' [integer] are not compatible with operator ":"`},
|
||||||
/* 6 */ {`"abcdef"[((1>0)?{1}:{0}):3]`, "bc", nil},
|
|
||||||
/* 7 */ {`"abcdef"[[0,1][0]:1]`, "a", nil},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Setenv("EXPR_PATH", ".")
|
t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
// runTestSuiteSpec(t, section, inputs, 5)
|
// parserTestSpec(t, section, inputs, 5)
|
||||||
runTestSuite(t, section, inputs)
|
runTestSuite(t, section, inputs)
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,9 @@ func TestListParser(t *testing.T) {
|
|||||||
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
|
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
|
||||||
/* 26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
/* 26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||||
/* 27 */ {`["a", "b", "c"] << ;`, nil, `[1:18] infix operator "<<" requires two non-nil operands, got 1`},
|
/* 27 */ {`["a", "b", "c"] << ;`, nil, `[1:18] infix operator "<<" requires two non-nil operands, got 1`},
|
||||||
/* 28 */ {`2 << 3;`, int64(16), nil},
|
/* 28 */ {`2 << 3;`, nil, `[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator "<<"`},
|
||||||
/* 29 */ {`but >> ["a", "b", "c"]`, nil, `[1:6] infix operator ">>" requires two non-nil operands, got 0`},
|
/* 29 */ {`but >> ["a", "b", "c"]`, nil, `[1:6] infix operator ">>" requires two non-nil operands, got 0`},
|
||||||
/* 30 */ {`2 >> 3;`, int64(0), nil},
|
/* 30 */ {`2 >> 3;`, nil, `[1:4] left operand '2' [integer] and right operand '3' [integer] are not compatible with operator ">>"`},
|
||||||
/* 31 */ {`a=[1,2]; a<<3`, newListA(int64(1), int64(2), int64(3)), nil},
|
/* 31 */ {`a=[1,2]; a<<3`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||||
/* 33 */ {`a=[1,2]; 5>>a`, newListA(int64(5), int64(1), int64(2)), nil},
|
/* 33 */ {`a=[1,2]; 5>>a`, newListA(int64(5), int64(1), int64(2)), nil},
|
||||||
/* 34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
|
/* 34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
|
||||||
|
@ -77,7 +77,7 @@ func TestGeneralParser(t *testing.T) {
|
|||||||
/* 63 */ {`"1.5" == `, nil, `[1:8] infix operator "==" requires two non-nil operands, got 1`},
|
/* 63 */ {`"1.5" == `, nil, `[1:8] infix operator "==" requires two non-nil operands, got 1`},
|
||||||
/* 64 */ {`"1.5" != `, nil, `[1:8] infix operator "!=" requires two non-nil operands, got 1`},
|
/* 64 */ {`"1.5" != `, nil, `[1:8] infix operator "!=" requires two non-nil operands, got 1`},
|
||||||
/* 65 */ {"+1.5", float64(1.5), nil},
|
/* 65 */ {"+1.5", float64(1.5), nil},
|
||||||
/* 66 */ {"+", nil, `[1:2] prefix operator "+" requires one non-nil operand`},
|
/* 66 */ {"+", nil, `[1:2] prefix operator "+" requires one not nil operand`},
|
||||||
/* 67 */ {"4 / 0", nil, `division by zero`},
|
/* 67 */ {"4 / 0", nil, `division by zero`},
|
||||||
/* 68 */ {"4.0 / 0", nil, `division by zero`},
|
/* 68 */ {"4.0 / 0", nil, `division by zero`},
|
||||||
/* 69 */ {"4.0 / \n2", float64(2.0), nil},
|
/* 69 */ {"4.0 / \n2", float64(2.0), nil},
|
||||||
@ -94,10 +94,10 @@ func TestGeneralParser(t *testing.T) {
|
|||||||
/* 80 */ {`5 % 2.0`, nil, `[1:4] left operand '5' [integer] and right operand '2' [float] are not compatible with operator "%"`},
|
/* 80 */ {`5 % 2.0`, nil, `[1:4] left operand '5' [integer] and right operand '2' [float] are not compatible with operator "%"`},
|
||||||
/* 81 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil},
|
/* 81 */ {`"a" < "b" AND NOT (2 < 1)`, true, nil},
|
||||||
/* 82 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil},
|
/* 82 */ {`"a" < "b" AND NOT (2 == 1)`, true, nil},
|
||||||
/* 83 */ {`"a" < "b" AND NOT 2 == 1`, true, nil},
|
/* 83 */ {`"a" < "b" AND ~ 2 == 1`, true, nil},
|
||||||
/* 84 */ {`NOT 2 > 1`, false, nil},
|
/* 84 */ {`~ 2 > 1`, false, nil},
|
||||||
/* 85 */ {`nOT true && true`, false, nil},
|
/* 85 */ {`~ true && true`, false, nil},
|
||||||
/* 86 */ {`NOT false || true`, true, nil},
|
/* 86 */ {`~ false || true`, true, nil},
|
||||||
/* 87 */ {`false but true`, true, nil},
|
/* 87 */ {`false but true`, true, nil},
|
||||||
/* 88 */ {`2+3 but 5*2`, int64(10), nil},
|
/* 88 */ {`2+3 but 5*2`, int64(10), nil},
|
||||||
/* 89 */ {`x=2`, int64(2), nil},
|
/* 89 */ {`x=2`, int64(2), nil},
|
||||||
@ -132,13 +132,15 @@ func TestGeneralParser(t *testing.T) {
|
|||||||
/* 118 */ {`{"key":}`, nil, "[1:9] expected `dictionary-value`, got `}`"},
|
/* 118 */ {`{"key":}`, nil, "[1:9] expected `dictionary-value`, got `}`"},
|
||||||
/* 119 */ {`{}`, &DictType{}, nil},
|
/* 119 */ {`{}`, &DictType{}, nil},
|
||||||
/* 120 */ {`v=10; v++; v`, int64(11), nil},
|
/* 120 */ {`v=10; v++; v`, int64(11), nil},
|
||||||
/* 121 */ {`1.2()`, newFraction(6, 5), nil},
|
/* 121 */ {`1+1|2+0.5`, float64(2), nil},
|
||||||
/* 122 */ {`x="abc"; x ?! #x`, int64(3), nil},
|
/* 122 */ {`1.2()`, newFraction(6, 5), nil},
|
||||||
/* 123 */ {`x ?! #x`, nil, `[1:7] prefix/postfix operator "#" do not support operand '<nil>' [nil]`},
|
/* 123 */ {`1|(2-2)`, nil, `division by zero`},
|
||||||
/* 124 */ {`x ?! (x+1)`, nil, nil},
|
/* 124 */ {`x="abc"; x ?! #x`, int64(3), nil},
|
||||||
/* 125 */ {`"abx" ?! (x+1)`, nil, `[1:6] left operand of "?!" must be a variable`},
|
/* 125 */ {`x ?! #x`, nil, `[1:7] prefix/postfix operator "#" do not support operand '<nil>' [nil]`},
|
||||||
/* 126 */ {`"abx" ?? "pqr"`, nil, `[1:6] left operand of "??" must be a variable`},
|
/* 126 */ {`x ?! (x+1)`, nil, nil},
|
||||||
/* 127 */ {`"abx" ?= "pqr"`, nil, `[1:6] left operand of "?=" must be a variable`},
|
/* 127 */ {`"abx" ?! (x+1)`, nil, `[1:6] left operand of "?!" must be a variable`},
|
||||||
|
/* 128 */ {`"abx" ?? "pqr"`, nil, `[1:6] left operand of "??" must be a variable`},
|
||||||
|
/* 129 */ {`"abx" ?= "pqr"`, nil, `[1:6] left operand of "?=" must be a variable`},
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Setenv("EXPR_PATH", ".")
|
// t.Setenv("EXPR_PATH", ".")
|
||||||
|
@ -21,9 +21,9 @@ func TestRelational(t *testing.T) {
|
|||||||
/* 8 */ {`true != false`, true, nil},
|
/* 8 */ {`true != false`, true, nil},
|
||||||
/* 9 */ {`1.0 != 3.0-2`, false, nil},
|
/* 9 */ {`1.0 != 3.0-2`, false, nil},
|
||||||
/* 10 */ {`[1,2] != [2,1]`, true, nil},
|
/* 10 */ {`[1,2] != [2,1]`, true, nil},
|
||||||
/* 11 */ {`1:2 == 1:3`, false, nil},
|
/* 11 */ {`1|2 == 1|3`, false, nil},
|
||||||
/* 12 */ {`1:2 != 1:3`, true, nil},
|
/* 12 */ {`1|2 != 1|3`, true, nil},
|
||||||
/* 13 */ {`1:2 == 4:8`, true, nil},
|
/* 13 */ {`1|2 == 4|8`, true, nil},
|
||||||
/* 14 */ {`1 < 8`, true, nil},
|
/* 14 */ {`1 < 8`, true, nil},
|
||||||
/* 15 */ {`1 <= 8`, true, nil},
|
/* 15 */ {`1 <= 8`, true, nil},
|
||||||
/* 16 */ {`"a" < "b"`, true, nil},
|
/* 16 */ {`"a" < "b"`, true, nil},
|
||||||
@ -32,10 +32,10 @@ func TestRelational(t *testing.T) {
|
|||||||
/* 19 */ {`1.0 <= 8`, true, nil},
|
/* 19 */ {`1.0 <= 8`, true, nil},
|
||||||
/* 20 */ {`1.0 <= 1.0`, true, nil},
|
/* 20 */ {`1.0 <= 1.0`, true, nil},
|
||||||
/* 21 */ {`1.0 == 1`, true, nil},
|
/* 21 */ {`1.0 == 1`, true, nil},
|
||||||
/* 22 */ {`1:2 < 1:3`, false, nil},
|
/* 22 */ {`1|2 < 1|3`, false, nil},
|
||||||
/* 23 */ {`1:2 <= 1:3`, false, nil},
|
/* 23 */ {`1|2 <= 1|3`, false, nil},
|
||||||
/* 24 */ {`1:2 > 1:3`, true, nil},
|
/* 24 */ {`1|2 > 1|3`, true, nil},
|
||||||
/* 25 */ {`1:2 >= 1:3`, true, nil},
|
/* 25 */ {`1|2 >= 1|3`, true, nil},
|
||||||
/* 26 */ {`[1,2,3] > [2]`, true, nil},
|
/* 26 */ {`[1,2,3] > [2]`, true, nil},
|
||||||
/* 27 */ {`[1,2,3] > [9]`, false, nil},
|
/* 27 */ {`[1,2,3] > [9]`, false, nil},
|
||||||
/* 28 */ {`[1,2,3] >= [6]`, false, nil},
|
/* 28 */ {`[1,2,3] >= [6]`, false, nil},
|
||||||
|
8
term.go
8
term.go
@ -62,8 +62,8 @@ func (s *term) Clone() (d *term) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
d = &term{
|
d = &term{
|
||||||
tk: *s.tk.Clone(),
|
tk: *s.tk.Clone(),
|
||||||
parent: s.parent,
|
parent: s.parent,
|
||||||
children: children,
|
children: children,
|
||||||
position: s.position,
|
position: s.position,
|
||||||
priority: s.priority,
|
priority: s.priority,
|
||||||
@ -211,11 +211,11 @@ func (term *term) checkOperands() (err error) {
|
|||||||
}
|
}
|
||||||
case posPrefix:
|
case posPrefix:
|
||||||
if term.children == nil || len(term.children) != 1 || term.children[0] == nil {
|
if term.children == nil || len(term.children) != 1 || term.children[0] == nil {
|
||||||
err = term.tk.Errorf("prefix operator %q requires one non-nil operand", term.tk.String())
|
err = term.tk.Errorf("prefix operator %q requires one not nil operand", term.tk.String())
|
||||||
}
|
}
|
||||||
case posPostfix:
|
case posPostfix:
|
||||||
if term.children == nil || len(term.children) != 1 || term.anyChildrenNil() {
|
if term.children == nil || len(term.children) != 1 || term.anyChildrenNil() {
|
||||||
err = term.tk.Errorf("postfix operator %q requires one non-nil operand", term.tk.String())
|
err = term.tk.Errorf("postfix operator %q requires one not nil operand", term.tk.String())
|
||||||
}
|
}
|
||||||
case posMultifix:
|
case posMultifix:
|
||||||
if term.children == nil || len(term.children) < 3 || term.anyChildrenNil() {
|
if term.children == nil || len(term.children) < 3 || term.anyChildrenNil() {
|
||||||
|
15
token.go
15
token.go
@ -93,15 +93,6 @@ func (tk *Token) Error() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) ErrorText() (err string) {
|
|
||||||
if tk.Sym == SymError {
|
|
||||||
if msg, ok := tk.Value.(error); ok {
|
|
||||||
err = msg.Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tk *Token) Errors(msg string) (err error) {
|
func (tk *Token) Errors(msg string) (err error) {
|
||||||
err = fmt.Errorf("[%d:%d] %v", tk.row, tk.col, msg)
|
err = fmt.Errorf("[%d:%d] %v", tk.row, tk.col, msg)
|
||||||
return
|
return
|
||||||
@ -113,10 +104,6 @@ func (tk *Token) ErrorExpectedGot(symbol string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tk *Token) ErrorExpectedGotString(symbol, got string) (err error) {
|
func (tk *Token) ErrorExpectedGotString(symbol, got string) (err error) {
|
||||||
return tk.ErrorExpectedGotStringWithPrefix("expected", symbol, got)
|
err = fmt.Errorf("[%d:%d] expected `%s`, got `%s`", tk.row, tk.col, symbol, got)
|
||||||
}
|
|
||||||
|
|
||||||
func (tk *Token) ErrorExpectedGotStringWithPrefix(prefix, symbol, got string) (err error) {
|
|
||||||
err = fmt.Errorf("[%d:%d] %s %s, got `%s`", tk.row, tk.col, prefix, symbol, got)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user