moulo
Some checks failed
Build / build (push) Successful in 9m45s
Test / build (push) Failing after 15m53s

This commit is contained in:
Chuck Smith
2024-03-22 16:49:33 -04:00
parent 6282075e66
commit cbb430b47d
10 changed files with 29 additions and 3 deletions

View File

@@ -25,6 +25,7 @@ const (
OpSub OpSub
OpMul OpMul
OpDiv OpDiv
OpMod
OpTrue OpTrue
OpFalse OpFalse
OpEqual OpEqual
@@ -69,6 +70,7 @@ var definitions = map[Opcode]*Definition{
OpSub: {"OpSub", []int{}}, OpSub: {"OpSub", []int{}},
OpMul: {"OpMul", []int{}}, OpMul: {"OpMul", []int{}},
OpDiv: {"OpDiv", []int{}}, OpDiv: {"OpDiv", []int{}},
OpMod: {"OpMod", []int{}},
OpTrue: {"OpTrue", []int{}}, OpTrue: {"OpTrue", []int{}},
OpFalse: {"OpFalse", []int{}}, OpFalse: {"OpFalse", []int{}},
OpEqual: {"OpEqual", []int{}}, OpEqual: {"OpEqual", []int{}},

View File

@@ -139,6 +139,8 @@ func (c *Compiler) Compile(node ast.Node) error {
c.emit(code.OpMul) c.emit(code.OpMul)
case "/": case "/":
c.emit(code.OpDiv) c.emit(code.OpDiv)
case "%":
c.emit(code.OpMod)
case ">": case ">":
c.emit(code.OpGreaterThan) c.emit(code.OpGreaterThan)
case ">=": case ">=":

View File

@@ -77,6 +77,16 @@ func TestIntegerArithmetic(t *testing.T) {
code.Make(code.OpPop), 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", input: "-1",
expectedConstants: []interface{}{1}, expectedConstants: []interface{}{1},

View File

@@ -336,6 +336,8 @@ func evalIntegerInfixExpression(operator string, left, right object.Object) obje
return &object.Integer{Value: leftVal * rightVal} return &object.Integer{Value: leftVal * rightVal}
case "/": case "/":
return &object.Integer{Value: leftVal / rightVal} return &object.Integer{Value: leftVal / rightVal}
case "%":
return &object.Integer{Value: leftVal % rightVal}
case "<": case "<":
return nativeBoolToBooleanObject(leftVal < rightVal) return nativeBoolToBooleanObject(leftVal < rightVal)
case "<=": case "<=":

View File

@@ -30,6 +30,7 @@ func TestEvalIntegerExpression(t *testing.T) {
{"3 * 3 * 3 + 10", 37}, {"3 * 3 * 3 + 10", 37},
{"3 * (3 * 3) + 10", 37}, {"3 * (3 * 3) + 10", 37},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50}, {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
{"5 % 2", 1},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@@ -87,6 +87,8 @@ func (l *Lexer) NextToken() token.Token {
} }
case '*': case '*':
tok = newToken(token.ASTERISK, l.ch) tok = newToken(token.ASTERISK, l.ch)
case '%':
tok = newToken(token.PERCENT, l.ch)
case '<': case '<':
if l.peekChar() == '=' { if l.peekChar() == '=' {
l.readChar() l.readChar()

View File

@@ -14,8 +14,8 @@ const (
ASSIGN // := or = ASSIGN // := or =
EQUALS // == EQUALS // ==
LESSGREATER // > or < LESSGREATER // > or <
SUM // + SUM // + or -
PRODUCT // * PRODUCT // * or / or %
PREFIX // -X or !X PREFIX // -X or !X
CALL // myFunction(X) CALL // myFunction(X)
INDEX // array[index] INDEX // array[index]
@@ -34,6 +34,7 @@ var precedences = map[token.TokenType]int{
token.MINUS: SUM, token.MINUS: SUM,
token.SLASH: PRODUCT, token.SLASH: PRODUCT,
token.ASTERISK: PRODUCT, token.ASTERISK: PRODUCT,
token.PERCENT: PRODUCT,
token.LPAREN: CALL, token.LPAREN: CALL,
token.LBRACKET: INDEX, token.LBRACKET: INDEX,
token.DOT: INDEX, token.DOT: INDEX,
@@ -82,6 +83,7 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(token.MINUS, p.parseInfixExpression) p.registerInfix(token.MINUS, p.parseInfixExpression)
p.registerInfix(token.SLASH, p.parseInfixExpression) p.registerInfix(token.SLASH, p.parseInfixExpression)
p.registerInfix(token.ASTERISK, p.parseInfixExpression) p.registerInfix(token.ASTERISK, p.parseInfixExpression)
p.registerInfix(token.PERCENT, p.parseInfixExpression)
p.registerInfix(token.EQ, p.parseInfixExpression) p.registerInfix(token.EQ, p.parseInfixExpression)
p.registerInfix(token.NOT_EQ, p.parseInfixExpression) p.registerInfix(token.NOT_EQ, p.parseInfixExpression)
p.registerInfix(token.LT, p.parseInfixExpression) p.registerInfix(token.LT, p.parseInfixExpression)

View File

@@ -27,6 +27,7 @@ const (
BANG = "!" BANG = "!"
ASTERISK = "*" ASTERISK = "*"
SLASH = "/" SLASH = "/"
PERCENT = "%"
LT = "<" LT = "<"
LTE = "<=" LTE = "<="

View File

@@ -112,7 +112,7 @@ func (vm *VM) Run() error {
return err 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) err := vm.executeBinaryOperation(op)
if err != nil { if err != nil {
return err return err
@@ -543,6 +543,9 @@ func (vm *VM) executeBinaryIntegerOperation(op code.Opcode, left, right object.O
result = leftValue * rightValue result = leftValue * rightValue
case code.OpDiv: case code.OpDiv:
result = leftValue / rightValue result = leftValue / rightValue
case code.OpMod:
result = leftValue % rightValue
default: default:
return fmt.Errorf("unknown integer operator: %d", op) return fmt.Errorf("unknown integer operator: %d", op)
} }

View File

@@ -224,6 +224,7 @@ func TestIntegerArithmetic(t *testing.T) {
{"-10", -10}, {"-10", -10},
{"-50 + 100 + -50", 0}, {"-50 + 100 + -50", 0},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50}, {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
{"5 % 2", 1},
} }
runVmTests(t, tests) runVmTests(t, tests)