New bitwise XOR operator specified by symbol ^ (caret). Iterator dereference is now done by prefixed * (star)

This commit is contained in:
Celestino Amoroso 2025-01-03 07:31:45 +01:00
parent 5ab6876ea1
commit 760c1ee6da
10 changed files with 71 additions and 20 deletions

View File

@ -187,6 +187,8 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) {
v, err = bitwiseAnd(opTerm, leftValue, rightValue) v, err = bitwiseAnd(opTerm, leftValue, rightValue)
case SymVertBarEqual: case SymVertBarEqual:
v, err = bitwiseOr(opTerm, leftValue, rightValue) v, err = bitwiseOr(opTerm, leftValue, rightValue)
case SymCaretEqual:
v, err = bitwiseXor(opTerm, leftValue, rightValue)
case SymDoubleLessEqual: case SymDoubleLessEqual:
v, err = bitLeftShift(opTerm, leftValue, rightValue) v, err = bitLeftShift(opTerm, leftValue, rightValue)
case SymDoubleGreaterEqual: case SymDoubleGreaterEqual:
@ -214,4 +216,5 @@ func init() {
registerTermConstructor(SymDoubleGreaterEqual, newOpAssignTerm) registerTermConstructor(SymDoubleGreaterEqual, newOpAssignTerm)
registerTermConstructor(SymAmpersandEqual, newOpAssignTerm) registerTermConstructor(SymAmpersandEqual, newOpAssignTerm)
registerTermConstructor(SymVertBarEqual, newOpAssignTerm) registerTermConstructor(SymVertBarEqual, newOpAssignTerm)
registerTermConstructor(SymCaretEqual, newOpAssignTerm)
} }

View File

@ -107,9 +107,48 @@ func evalBitwiseOr(ctx ExprContext, opTerm *term) (v any, err error) {
return return
} }
//-------- Bitwise XOR term
func newBitwiseXorTerm(tk *Token) (inst *term) {
return &term{
tk: *tk,
children: make([]*term, 0, 2),
position: posInfix,
priority: priBitwiseOr,
evalFunc: evalBitwiseXor,
}
}
func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) {
var leftInt, rightInt int64
var lok, rok bool
leftInt, lok = leftValue.(int64)
rightInt, rok = rightValue.(int64)
if lok && rok {
v = leftInt ^ rightInt
} else {
err = opTerm.errIncompatibleTypes(leftValue, rightValue)
}
return
}
func evalBitwiseXor(ctx ExprContext, opTerm *term) (v any, err error) {
var leftValue, rightValue any
if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil {
return
}
v, err = bitwiseXor(opTerm, leftValue, rightValue)
return
}
// init // init
func init() { func init() {
registerTermConstructor(SymTilde, newBitwiseNotTerm) registerTermConstructor(SymTilde, newBitwiseNotTerm)
registerTermConstructor(SymAmpersand, newBitwiseAndTerm) registerTermConstructor(SymAmpersand, newBitwiseAndTerm)
registerTermConstructor(SymVertBar, newBitwiseOrTerm) registerTermConstructor(SymVertBar, newBitwiseOrTerm)
registerTermConstructor(SymCaret, newBitwiseXorTerm)
} }

View File

@ -11,7 +11,7 @@ func newIterValueTerm(tk *Token) (inst *term) {
tk: *tk, tk: *tk,
children: make([]*term, 0, 1), children: make([]*term, 0, 1),
position: posPrefix, position: posPrefix,
priority: priIterValue, priority: priDereference,
evalFunc: evalIterValue, evalFunc: evalIterValue,
} }
} }
@ -33,6 +33,6 @@ func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) {
// init // init
func init() { func init() {
// registerTermConstructor(SymOpenClosedRound, newIterValueTerm) // registerTermConstructor(SymOpenClosedRound, newIterValueTerm)
registerTermConstructor(SymCaret, newIterValueTerm) registerTermConstructor(SymDereference, newIterValueTerm)
} }

View File

@ -441,8 +441,10 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
tk.Sym = SymChangeSign tk.Sym = SymChangeSign
} else if tk.Sym == SymPlus { } else if tk.Sym == SymPlus {
tk.Sym = SymUnchangeSign tk.Sym = SymUnchangeSign
} else if tk.IsSymbol(SymStar) {
tk.SetSymbol(SymDereference)
} else if tk.IsSymbol(SymExclamation) { } else if tk.IsSymbol(SymExclamation) {
err = tk.Errorf("postfix opertor %q requires an operand on its left", tk) err = tk.Errorf("postfix opertor %q requires an operand on its left side", tk)
break break
} }
firstToken = false firstToken = false
@ -481,7 +483,7 @@ func (parser *parser) parseGeneral(scanner *scanner, ctx parserContext, termSymb
currentTerm = mapTerm currentTerm = mapTerm
} }
} }
case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual: case SymEqual, SymPlusEqual, SymMinusEqual, SymStarEqual, SymSlashEqual, SymPercEqual, SymAmpersandEqual, SymVertBarEqual, SymDoubleLessEqual, SymDoubleGreaterEqual, SymCaretEqual:
currentTerm, err = tree.addToken(tk) currentTerm, err = tree.addToken(tk)
firstToken = true firstToken = true
case SymFuncDef: case SymFuncDef:
@ -518,14 +520,11 @@ 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.IsOneOfA(SymColon, SymRange) { // Colon outside a selector term acts like a separator
// Colon outside a selector term acts like a separator firstToken = true
firstToken = true }
} }
default: default:
currentTerm, err = tree.addToken(tk) currentTerm, err = tree.addToken(tk)

View File

@ -177,7 +177,11 @@ func (scanner *scanner) fetchNextToken() (tk *Token) {
case ',': case ',':
tk = scanner.makeToken(SymComma, ch) tk = scanner.makeToken(SymComma, ch)
case '^': case '^':
tk = scanner.makeToken(SymCaret, ch) if next, _ := scanner.peek(); next == '=' {
tk = scanner.moveOn(SymCaretEqual, ch, next)
} else {
tk = scanner.makeToken(SymCaret, ch)
}
case ':': case ':':
if next, _ := scanner.peek(); next == ':' { if next, _ := scanner.peek(); next == ':' {
tk = scanner.moveOn(SymDoubleColon, ch, next) tk = scanner.moveOn(SymDoubleColon, ch, next)

View File

@ -100,8 +100,9 @@ func init() {
SymDoubleGreaterEqual: {">>=", symClassOperator, posInfix}, // 64: '>>=' SymDoubleGreaterEqual: {">>=", symClassOperator, posInfix}, // 64: '>>='
SymAmpersandEqual: {"&=", symClassOperator, posInfix}, // 65: '&=' SymAmpersandEqual: {"&=", symClassOperator, posInfix}, // 65: '&='
SymVertBarEqual: {"|=", symClassOperator, posInfix}, // 65: '|=' SymVertBarEqual: {"|=", symClassOperator, posInfix}, // 65: '|='
SymPlusGreater: {"+>", symClassOperator, posInfix}, // 66: '+>' SymCaretEqual: {"^=", symClassOperator, posInfix}, // 66: '^='
SymLessPlus: {"<+", symClassOperator, posInfix}, // 67: '<+' SymPlusGreater: {"+>", symClassOperator, posInfix}, // 67: '+>'
SymLessPlus: {"<+", symClassOperator, posInfix}, // 68: '<+'
// SymChangeSign // SymChangeSign
// SymUnchangeSign // SymUnchangeSign
// SymIdentifier // SymIdentifier

View File

@ -75,10 +75,12 @@ const (
SymDoubleGreaterEqual // 64: '>>=' SymDoubleGreaterEqual // 64: '>>='
SymAmpersandEqual // 65: '&=' SymAmpersandEqual // 65: '&='
SymVertBarEqual // 65: '|=' SymVertBarEqual // 65: '|='
SymPlusGreater // 66: '+>' SymCaretEqual // 66: '^='
SymLessPlus // 67: '<+' SymPlusGreater // 67: '+>'
SymLessPlus // 68: '<+'
SymChangeSign SymChangeSign
SymUnchangeSign SymUnchangeSign
SymDereference
SymIdentifier SymIdentifier
SymBool SymBool
SymInteger SymInteger

View File

@ -9,10 +9,10 @@ import "testing"
func TestIteratorParser(t *testing.T) { func TestIteratorParser(t *testing.T) {
section := "Iterator" section := "Iterator"
inputs := []inputType{ inputs := []inputType{
/* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); ^it`, int64(0), nil}, /* 1 */ {`include "test-resources/iterator.expr"; it=$(ds,3); *it`, int64(0), nil},
/* 2 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil}, /* 2 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++`, int64(1), nil},
/* 3 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(3), nil}, /* 3 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; #it`, int64(3), nil},
/* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; ^it`, int64(0), nil}, /* 4 */ {`include "test-resources/iterator.expr"; it=$(ds,3); it++; it++; it.reset; *it`, int64(0), nil},
/* 5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil}, /* 5 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); add(it)`, int64(6), nil},
/* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil}, /* 6 */ {`builtin "math.arith"; include "test-resources/iterator.expr"; it=$(ds,3); mul(it)`, int64(0), nil},
/* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil}, /* 7 */ {`builtin "math.arith"; include "test-resources/file-reader.expr"; it=$(ds,"test-resources/int.list"); mul(it)`, int64(12000), nil},

View File

@ -28,6 +28,9 @@ func TestOperator(t *testing.T) {
/* 15 */ {`0o10`, int64(8), nil}, /* 15 */ {`0o10`, int64(8), nil},
/* 16 */ {`0b10`, int64(2), nil}, /* 16 */ {`0b10`, int64(2), nil},
/* 17 */ {`~true`, nil, `[1:2] prefix/postfix operator "~" do not support operand 'true' [bool]`}, /* 17 */ {`~true`, nil, `[1:2] prefix/postfix operator "~" do not support operand 'true' [bool]`},
/* 18 */ {`1^2`, int64(3), nil},
/* 19 */ {`3^2`, int64(1), nil},
/* 19 */ {`a=1; a^=2`, int64(3), nil},
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")

View File

@ -142,6 +142,6 @@ func TestGeneralParser(t *testing.T) {
} }
// t.Setenv("EXPR_PATH", ".") // t.Setenv("EXPR_PATH", ".")
//runTestSuiteSpec(t, section, inputs, 130) // runTestSuiteSpec(t, section, inputs, 114)
runTestSuite(t, section, inputs) runTestSuite(t, section, inputs)
} }