The list operator '<<' (append) and '>>' (prepend) have been replaced
with the new operators '<+' and '+>' respectively. '<<' and '>>' are now used only for left and right binary shit respectively. Further, their priority has been increased moving them to a higher priority than that of the assignment operator.
This commit is contained in:
parent
cca3b76baa
commit
d91e7eb979
@ -11,7 +11,7 @@ func newBinNotTerm(tk *Token) (inst *term) {
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 1),
|
||||
position: posPrefix,
|
||||
priority: priBinary,
|
||||
priority: priBinNot,
|
||||
evalFunc: evalBinaryNot,
|
||||
}
|
||||
}
|
||||
@ -39,7 +39,7 @@ func newBinAndTerm(tk *Token) (inst *term) {
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priBinary,
|
||||
priority: priBinAnd,
|
||||
evalFunc: evalBinaryAnd,
|
||||
}
|
||||
}
|
||||
@ -71,7 +71,7 @@ func newBinOrTerm(tk *Token) (inst *term) {
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priBinary,
|
||||
priority: priBinOr,
|
||||
evalFunc: evalBinaryOr,
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,15 @@
|
||||
// operator-insert.go
|
||||
package expr
|
||||
|
||||
//-------- insert term
|
||||
//-------- prepend term
|
||||
|
||||
func newInsertTerm(tk *Token) (inst *term) {
|
||||
func newPrependTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priAssign,
|
||||
evalFunc: evalInsert,
|
||||
priority: priInsert,
|
||||
evalFunc: evalPrepend,
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,12 +21,12 @@ func newAppendTerm(tk *Token) (inst *term) {
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priAssign,
|
||||
priority: priInsert,
|
||||
evalFunc: evalAppend,
|
||||
}
|
||||
}
|
||||
|
||||
func evalInsert(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
|
||||
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
|
||||
@ -40,10 +40,6 @@ func evalInsert(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
if opTerm.children[1].symbol() == SymVariable {
|
||||
ctx.UnsafeSetVar(opTerm.children[1].source(), v)
|
||||
}
|
||||
} else if IsInteger(leftValue) && IsInteger(rightValue) {
|
||||
leftInt := leftValue.(int64)
|
||||
rightInt := rightValue.(int64)
|
||||
v = leftInt >> rightInt
|
||||
} else {
|
||||
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 {
|
||||
ctx.UnsafeSetVar(opTerm.children[0].source(), v)
|
||||
}
|
||||
} else if IsInteger(leftValue) && IsInteger(rightValue) {
|
||||
leftInt := leftValue.(int64)
|
||||
rightInt := rightValue.(int64)
|
||||
v = leftInt << rightInt
|
||||
} else {
|
||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
@ -94,6 +86,6 @@ func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymInsert, newInsertTerm)
|
||||
registerTermConstructor(SymAppend, newAppendTerm)
|
||||
registerTermConstructor(SymPlusGreater, newPrependTerm)
|
||||
registerTermConstructor(SymLessPlus, newAppendTerm)
|
||||
}
|
||||
|
85
operator-shift.go
Normal file
85
operator-shift.go
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||
// All rights reserved.
|
||||
|
||||
// operator-shift.go
|
||||
package expr
|
||||
|
||||
//-------- shift term
|
||||
|
||||
func newRightShiftTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priBinShift,
|
||||
evalFunc: evalRightShift,
|
||||
}
|
||||
}
|
||||
|
||||
func evalRightShift(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
|
||||
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if IsInteger(leftValue) && IsInteger(rightValue) {
|
||||
leftInt := leftValue.(int64)
|
||||
rightInt := rightValue.(int64)
|
||||
v = leftInt >> rightInt
|
||||
} else {
|
||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func newLeftShiftTerm(tk *Token) (inst *term) {
|
||||
return &term{
|
||||
tk: *tk,
|
||||
children: make([]*term, 0, 2),
|
||||
position: posInfix,
|
||||
priority: priBinShift,
|
||||
evalFunc: evalLeftShift,
|
||||
}
|
||||
}
|
||||
|
||||
func evalLeftShift(ctx ExprContext, opTerm *term) (v any, err error) {
|
||||
var leftValue, rightValue any
|
||||
|
||||
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if IsInteger(leftValue) && IsInteger(rightValue) {
|
||||
leftInt := leftValue.(int64)
|
||||
rightInt := rightValue.(int64)
|
||||
v = leftInt << rightInt
|
||||
} else {
|
||||
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// func evalAssignAppend(ctx ExprContext, self *term) (v any, err error) {
|
||||
// var leftValue, rightValue any
|
||||
|
||||
// if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
|
||||
// return
|
||||
// }
|
||||
|
||||
// if IsList(leftValue) {
|
||||
// list, _ := leftValue.(*ListType)
|
||||
// newList := append(*list, rightValue)
|
||||
// v = &newList
|
||||
// if
|
||||
// } else {
|
||||
// err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// init
|
||||
func init() {
|
||||
registerTermConstructor(SymDoubleGreater, newRightShiftTerm)
|
||||
registerTermConstructor(SymDoubleLess, newLeftShiftTerm)
|
||||
}
|
@ -124,6 +124,8 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
|
||||
tk = scanner.moveOn(SymDoublePlus, ch, next)
|
||||
} else if next == '=' {
|
||||
tk = scanner.moveOn(SymPlusEqual, ch, next)
|
||||
} else if next == '>' {
|
||||
tk = scanner.moveOn(SymPlusGreater, ch, next)
|
||||
} else {
|
||||
tk = scanner.makeToken(SymPlus, ch)
|
||||
}
|
||||
@ -265,9 +267,11 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymLessOrEqual, ch, next)
|
||||
} else if next == '<' {
|
||||
tk = scanner.moveOn(SymAppend, ch, next)
|
||||
tk = scanner.moveOn(SymDoubleLess, ch, next)
|
||||
} else if next == '>' {
|
||||
tk = scanner.moveOn(SymLessGreater, ch, next)
|
||||
} else if next == '+' {
|
||||
tk = scanner.moveOn(SymLessPlus, ch, next)
|
||||
} else {
|
||||
tk = scanner.makeToken(SymLess, ch)
|
||||
}
|
||||
@ -275,7 +279,7 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
|
||||
if next, _ := scanner.peek(); next == '=' {
|
||||
tk = scanner.moveOn(SymGreaterOrEqual, ch, next)
|
||||
} else if next == '>' {
|
||||
tk = scanner.moveOn(SymInsert, ch, next)
|
||||
tk = scanner.moveOn(SymDoubleGreater, ch, next)
|
||||
} else {
|
||||
tk = scanner.makeToken(SymGreater, ch)
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ func init() {
|
||||
SymQuestionExclam: {"?!", symClassOperator}, // 49: '?!'
|
||||
SymDoubleAt: {"@@", symClassOperator}, // 50: '@@'
|
||||
SymDoubleColon: {"::", symClassOperator}, // 51: '::'
|
||||
SymInsert: {">>", symClassOperator}, // 52: '>>'
|
||||
SymAppend: {"<<", symClassOperator}, // 53: '<<'
|
||||
SymDoubleGreater: {">>", symClassOperator}, // 52: '>>'
|
||||
SymDoubleLess: {"<<", symClassOperator}, // 53: '<<'
|
||||
SymCaret: {"^", symClassOperator}, // 54: '^'
|
||||
SymDollarRound: {"$(", symClassOperator}, // 55: '$('
|
||||
SymOpenClosedRound: {"()", symClassPostOp}, // 56: '()'
|
||||
@ -95,6 +95,8 @@ func init() {
|
||||
SymStarEqual: {"*=", symClassOperator}, // 60: '*='
|
||||
SymSlashEqual: {"/=", symClassOperator}, // 61: '/='
|
||||
SymPercEqual: {"%=", symClassOperator}, // 62: '%='
|
||||
SymPlusGreater: {"+>", symClassOperator}, // 63: '+>'
|
||||
SymLessPlus: {"<+", symClassOperator}, // 64: '<+'
|
||||
// SymChangeSign
|
||||
// SymUnchangeSign
|
||||
// SymIdentifier
|
||||
|
@ -60,8 +60,8 @@ const (
|
||||
SymQuestionExclam // 49: '?!'
|
||||
SymDoubleAt // 50: '@@'
|
||||
SymDoubleColon // 51: '::'
|
||||
SymInsert // 52: '>>'
|
||||
SymAppend // 53: '<<'
|
||||
SymDoubleGreater // 52: '>>'
|
||||
SymDoubleLess // 53: '<<'
|
||||
SymCaret // 54: '^'
|
||||
SymDollarRound // 55: '$('
|
||||
SymOpenClosedRound // 56: '()'
|
||||
@ -71,6 +71,8 @@ const (
|
||||
SymStarEqual // 60: '*='
|
||||
SymSlashEqual // 61: '/='
|
||||
SymPercEqual // 62: '%='
|
||||
SymPlusGreater // 63: '+>'
|
||||
SymLessPlus // 64: '<+'
|
||||
SymChangeSign
|
||||
SymUnchangeSign
|
||||
SymIdentifier
|
||||
|
@ -23,8 +23,8 @@ func TestListParser(t *testing.T) {
|
||||
/* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
|
||||
/* 10 */ {`add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`},
|
||||
/* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
|
||||
/* 12 */ {`[1,2,3] << 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
/* 13 */ {`2-1 >> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 12 */ {`[1,2,3] <+ 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
/* 13 */ {`2-1 +> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 14 */ {`[1,2,3][1]`, int64(2), nil},
|
||||
/* 15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil},
|
||||
/* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
|
||||
@ -33,8 +33,8 @@ func TestListParser(t *testing.T) {
|
||||
/* 19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil},
|
||||
/* 20 */ {`#["a", "b", "c"]`, int64(3), nil},
|
||||
/* 21 */ {`"b" in ["a", "b", "c"]`, true, nil},
|
||||
/* 22 */ {`a=[1,2]; (a)<<3`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 23 */ {`a=[1,2]; (a)<<3; a`, newListA(int64(1), int64(2)), nil},
|
||||
/* 22 */ {`a=[1,2]; (a)<+3`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 23 */ {`a=[1,2]; (a)<+3; a`, newListA(int64(1), int64(2)), nil},
|
||||
/* 24 */ {`["a","b","c","d"][1]`, "b", nil},
|
||||
/* 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},
|
||||
@ -42,16 +42,16 @@ func TestListParser(t *testing.T) {
|
||||
/* 28 */ {`2 << 3;`, int64(16), nil},
|
||||
/* 29 */ {`but >> ["a", "b", "c"]`, nil, `[1:6] infix operator ">>" requires two non-nil operands, got 0`},
|
||||
/* 30 */ {`2 >> 3;`, int64(0), 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},
|
||||
/* 34 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
|
||||
/* 35 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
|
||||
/* 36 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [list]`},
|
||||
/* 37 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
|
||||
/* 38 */ {`[0,1,2,3,4][2:3]`, newListA(int64(2)), nil},
|
||||
/* 39 */ {`[0,1,2,3,4][3:-1]`, newListA(int64(3)), nil},
|
||||
/* 40 */ {`[0,1,2,3,4][-3:-1]`, newListA(int64(2), int64(3)), nil},
|
||||
/* 41 */ {`[0,1,2,3,4][0:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
/* 31 */ {`a=[1,2]; a<+3`, newListA(int64(1), int64(2), int64(3)), nil},
|
||||
/* 32 */ {`a=[1,2]; 5+>a`, newListA(int64(5), int64(1), int64(2)), nil},
|
||||
/* 33 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil},
|
||||
/* 34 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
|
||||
/* 35 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [list]`},
|
||||
/* 36 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
|
||||
/* 37 */ {`[0,1,2,3,4][2:3]`, newListA(int64(2)), nil},
|
||||
/* 38 */ {`[0,1,2,3,4][3:-1]`, newListA(int64(3)), nil},
|
||||
/* 30 */ {`[0,1,2,3,4][-3:-1]`, newListA(int64(2), int64(3)), nil},
|
||||
/* 40 */ {`[0,1,2,3,4][0:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
|
||||
}
|
||||
|
||||
// t.Setenv("EXPR_PATH", ".")
|
||||
|
Loading…
Reference in New Issue
Block a user