From d91e7eb9796ddaae3e8d932910791931299faa02 Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Sat, 28 Dec 2024 09:17:27 +0100 Subject: [PATCH] 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. --- operator-binary.go | 6 ++-- operator-insert.go | 24 +++++-------- operator-shift.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ scanner.go | 8 +++-- symbol-map.go | 6 ++-- symbol.go | 6 ++-- t_list_test.go | 28 +++++++-------- term.go | 6 +++- 8 files changed, 129 insertions(+), 40 deletions(-) create mode 100644 operator-shift.go diff --git a/operator-binary.go b/operator-binary.go index cfdc3a8..c3b43ab 100644 --- a/operator-binary.go +++ b/operator-binary.go @@ -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, } } diff --git a/operator-insert.go b/operator-insert.go index cb9c560..aef289b 100644 --- a/operator-insert.go +++ b/operator-insert.go @@ -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) } diff --git a/operator-shift.go b/operator-shift.go new file mode 100644 index 0000000..992e083 --- /dev/null +++ b/operator-shift.go @@ -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) +} diff --git a/scanner.go b/scanner.go index bb9151e..e9e52bf 100644 --- a/scanner.go +++ b/scanner.go @@ -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) } diff --git a/symbol-map.go b/symbol-map.go index 4223ec3..5ee8213 100644 --- a/symbol-map.go +++ b/symbol-map.go @@ -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 diff --git a/symbol.go b/symbol.go index b328aa9..88a62ba 100644 --- a/symbol.go +++ b/symbol.go @@ -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 diff --git a/t_list_test.go b/t_list_test.go index e2abb7e..13aea6c 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -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", ".") diff --git a/term.go b/term.go index 11e887f..88a42c7 100644 --- a/term.go +++ b/term.go @@ -15,15 +15,19 @@ const ( priRange priBut priAssign + priInsert priOr priAnd priNot priRelational - priBinary + priBinOr + priBinAnd + priBinNot priSum priProduct priFraction priSelector + priBinShift priSign priFact priIterValue