From cbb430b47dd4f8f5dab0d43015ebf3669f4b3e9a Mon Sep 17 00:00:00 2001 From: Chuck Smith Date: Fri, 22 Mar 2024 16:49:33 -0400 Subject: [PATCH] moulo --- code/code.go | 2 ++ compiler/compiler.go | 2 ++ compiler/compiler_test.go | 10 ++++++++++ evaluator/evaluator.go | 2 ++ evaluator/evaluator_test.go | 1 + lexer/lexer.go | 2 ++ parser/parser.go | 6 ++++-- token/token.go | 1 + vm/vm.go | 5 ++++- vm/vm_test.go | 1 + 10 files changed, 29 insertions(+), 3 deletions(-) diff --git a/code/code.go b/code/code.go index 104c366..282a348 100644 --- a/code/code.go +++ b/code/code.go @@ -25,6 +25,7 @@ const ( OpSub OpMul OpDiv + OpMod OpTrue OpFalse OpEqual @@ -69,6 +70,7 @@ var definitions = map[Opcode]*Definition{ OpSub: {"OpSub", []int{}}, OpMul: {"OpMul", []int{}}, OpDiv: {"OpDiv", []int{}}, + OpMod: {"OpMod", []int{}}, OpTrue: {"OpTrue", []int{}}, OpFalse: {"OpFalse", []int{}}, OpEqual: {"OpEqual", []int{}}, diff --git a/compiler/compiler.go b/compiler/compiler.go index d4f012d..240bf9f 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -139,6 +139,8 @@ func (c *Compiler) Compile(node ast.Node) error { c.emit(code.OpMul) case "/": c.emit(code.OpDiv) + case "%": + c.emit(code.OpMod) case ">": c.emit(code.OpGreaterThan) case ">=": diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 82ffd41..4c05314 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -77,6 +77,16 @@ func TestIntegerArithmetic(t *testing.T) { code.Make(code.OpPop), }, }, + { + input: "5 % 2", + expectedConstants: []interface{}{5, 2}, + expectedInstructions: []code.Instructions{ + code.Make(code.OpConstant, 0), + code.Make(code.OpConstant, 1), + code.Make(code.OpMod), + code.Make(code.OpPop), + }, + }, { input: "-1", expectedConstants: []interface{}{1}, diff --git a/evaluator/evaluator.go b/evaluator/evaluator.go index fec0b29..abf9725 100644 --- a/evaluator/evaluator.go +++ b/evaluator/evaluator.go @@ -336,6 +336,8 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje return &object.Integer{Value: leftVal * rightVal} case "/": return &object.Integer{Value: leftVal / rightVal} + case "%": + return &object.Integer{Value: leftVal % rightVal} case "<": return nativeBoolToBooleanObject(leftVal < rightVal) case "<=": diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index f633891..a5fad86 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -30,6 +30,7 @@ func TestEvalIntegerExpression(t *testing.T) { {"3 * 3 * 3 + 10", 37}, {"3 * (3 * 3) + 10", 37}, {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50}, + {"5 % 2", 1}, } for _, tt := range tests { diff --git a/lexer/lexer.go b/lexer/lexer.go index 3daef73..6ee2eca 100644 --- a/lexer/lexer.go +++ b/lexer/lexer.go @@ -87,6 +87,8 @@ func (l *Lexer) NextToken() token.Token { } case '*': tok = newToken(token.ASTERISK, l.ch) + case '%': + tok = newToken(token.PERCENT, l.ch) case '<': if l.peekChar() == '=' { l.readChar() diff --git a/parser/parser.go b/parser/parser.go index deb1c01..d09a804 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -14,8 +14,8 @@ const ( ASSIGN // := or = EQUALS // == LESSGREATER // > or < - SUM // + - PRODUCT // * + SUM // + or - + PRODUCT // * or / or % PREFIX // -X or !X CALL // myFunction(X) INDEX // array[index] @@ -34,6 +34,7 @@ var precedences = map[token.TokenType]int{ token.MINUS: SUM, token.SLASH: PRODUCT, token.ASTERISK: PRODUCT, + token.PERCENT: PRODUCT, token.LPAREN: CALL, token.LBRACKET: INDEX, token.DOT: INDEX, @@ -82,6 +83,7 @@ func New(l *lexer.Lexer) *Parser { p.registerInfix(token.MINUS, p.parseInfixExpression) p.registerInfix(token.SLASH, p.parseInfixExpression) p.registerInfix(token.ASTERISK, p.parseInfixExpression) + p.registerInfix(token.PERCENT, p.parseInfixExpression) p.registerInfix(token.EQ, p.parseInfixExpression) p.registerInfix(token.NOT_EQ, p.parseInfixExpression) p.registerInfix(token.LT, p.parseInfixExpression) diff --git a/token/token.go b/token/token.go index 282a839..f5f269f 100644 --- a/token/token.go +++ b/token/token.go @@ -27,6 +27,7 @@ const ( BANG = "!" ASTERISK = "*" SLASH = "/" + PERCENT = "%" LT = "<" LTE = "<=" diff --git a/vm/vm.go b/vm/vm.go index 828f386..5e01216 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -112,7 +112,7 @@ func (vm *VM) Run() error { return err } - case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv: + case code.OpAdd, code.OpSub, code.OpMul, code.OpDiv, code.OpMod: err := vm.executeBinaryOperation(op) if err != nil { return err @@ -543,6 +543,9 @@ func (vm *VM) executeBinaryIntegerOperation(op code.Opcode, left, right object.O result = leftValue * rightValue case code.OpDiv: result = leftValue / rightValue + case code.OpMod: + result = leftValue % rightValue + default: return fmt.Errorf("unknown integer operator: %d", op) } diff --git a/vm/vm_test.go b/vm/vm_test.go index 2e5390d..b992267 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -224,6 +224,7 @@ func TestIntegerArithmetic(t *testing.T) { {"-10", -10}, {"-50 + 100 + -50", 0}, {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50}, + {"5 % 2", 1}, } runVmTests(t, tests)