diff --git a/operator-prod.go b/operator-prod.go index 6ba840c..f1ecbaa 100644 --- a/operator-prod.go +++ b/operator-prod.go @@ -125,9 +125,45 @@ func evalDivideAsFloat(ctx exprContext, self *term) (v any, err error) { return } +//-------- reminder term + +func newReminderTerm(tk *Token) (inst *term) { + return &term{ + tk: *tk, + class: classOperator, + kind: kindUnknown, + children: make([]*term, 0, 2), + position: posInfix, + priority: priProduct, + evalFunc: evalReminder, + } +} + +func evalReminder(ctx exprContext, self *term) (v any, err error) { + var leftValue, rightValue any + + if leftValue, rightValue, err = self.evalInfix(ctx); err != nil { + return + } + + if isInteger(leftValue) && isInteger(rightValue) { + rightInt, _ := rightValue.(int64) + if rightInt == 0 { + err = errors.New("division by zero") + } else { + leftInt, _ := leftValue.(int64) + v = leftInt % rightInt + } + } else { + err = self.errIncompatibleTypes(leftValue, rightValue) + } + return +} + // init func init() { registerTermConstructor(SymStar, newMultiplyTerm) registerTermConstructor(SymSlash, newDivideTerm) registerTermConstructor(SymDotSlash, newDivideAsFloatTerm) + registerTermConstructor(SymPercent, newReminderTerm) } diff --git a/parser_test.go b/parser_test.go index fa954d9..bb5ecac 100644 --- a/parser_test.go +++ b/parser_test.go @@ -187,6 +187,10 @@ func TestParser(t *testing.T) { /* 79 */ {`1 / 2`, int64(0), nil}, /* 80 */ {`1.0 / 2`, float64(0.5), nil}, /* 81 */ {`1 ./ 2`, float64(0.5), nil}, + /* 82 */ {`5 % 2`, int64(1), nil}, + /* 83 */ {`5 % (-2)`, int64(1), nil}, + /* 84 */ {`-5 % 2`, int64(-1), nil}, + /* 85 */ {`5 % 2.0`, nil, errors.New(`left operand '5' [int64] is not compatible with right operand '2' [float64] with respect to operator "%"`)}, } parser := NewParser(ctx)