Skip to content

Commit

Permalink
feat: modulo
Browse files Browse the repository at this point in the history
  • Loading branch information
labasubagia committed May 13, 2024
1 parent 5f33906 commit 9583ef8
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 8 deletions.
18 changes: 10 additions & 8 deletions evaluator/evaluator.go
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ func evalInfixIntegerExpression(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)
Expand Down Expand Up @@ -608,14 +610,6 @@ func evalHashIndexAssignExpression(
return val
}

func isCompoundAssignmentOperator(operator string) bool {
switch operator {
case "+=", "-=", "/=", "*=":
return true
}
return false
}

func evalWhileStatement(node *ast.WhileStatement, env *object.Environment) object.Object {

condition := Eval(node.Condition, env)
Expand Down Expand Up @@ -657,3 +651,11 @@ func isError(obj object.Object) bool {
}
return false
}

func isCompoundAssignmentOperator(operator string) bool {
switch operator {
case "+=", "-=", "/=", "*=", "%=":
return true
}
return false
}
19 changes: 19 additions & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ func TestEvalIntegerExpression(t *testing.T) {
{"3 * 3 * 3 + 10", 37},
{"3 * (3 * 3) + 10", 37},
{"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
{"10 % 5", 0},
{"3 % 2", 1},
{"10 * 5 % 20", 10},
}

for _, tt := range tests {
Expand Down Expand Up @@ -490,6 +493,7 @@ func TestAssignExpressions(t *testing.T) {
{"let x = 5; x *= 10; x", 50},
{"let x = 20; x /= 10; x", 2},
{"let x = 20; x /= 10 / 2; x", 4},
{"let x = 20; x %= 10 / 2; x", 0},

{
`
Expand All @@ -505,6 +509,13 @@ func TestAssignExpressions(t *testing.T) {
`,
-17,
},
{
`
let arr = [1,5,3,4];
arr[2] %= 2
`,
1,
},
{
`
let hash = {"a": 2};
Expand All @@ -521,6 +532,14 @@ func TestAssignExpressions(t *testing.T) {
`,
1,
},
{
`
let hash = {"a": 2};
hash["a"] %= 2;
hash["a"];
`,
0,
},
}
for _, tt := range tests {
testIntegerObject(t, testEval(tt.input), tt.expected)
Expand Down
Binary file modified interactive/interpreter
Binary file not shown.
9 changes: 9 additions & 0 deletions lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ func (l *Lexer) NextToken() token.Token {
} else {
tok = newToken(token.ASTERISK, l.ch)
}
case '%':
if l.peekChar() == '=' {
ch := l.ch
l.readChar()
literal := string(ch) + string(l.ch)
tok = token.Token{Type: token.MODULO_ASSIGN, Literal: literal}
} else {
tok = newToken(token.MODULO, l.ch)
}
case '<':
if l.peekChar() == '=' {
ch := l.ch
Expand Down
13 changes: 13 additions & 0 deletions lexer/lexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func TestNextToken(t *testing.T) {
c *= 3;
d /= 4;
12 % 4;
f %= 4;
# comment at the end 1
# comment at the end 2
`
Expand Down Expand Up @@ -189,6 +192,16 @@ func TestNextToken(t *testing.T) {
{token.INT, "4"},
{token.SEMICOLON, ";"},

{token.INT, "12"},
{token.MODULO, "%"},
{token.INT, "4"},
{token.SEMICOLON, ";"},

{token.IDENT, "f"},
{token.MODULO_ASSIGN, "%="},
{token.INT, "4"},
{token.SEMICOLON, ";"},

{token.EOF, ""},
}

Expand Down
4 changes: 4 additions & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ var precedences = map[token.TokenType]int{
token.MINUS: SUM,
token.SLASH: PRODUCT,
token.ASTERISK: PRODUCT,
token.MODULO: PRODUCT,
token.LPAREN: CALL,
token.LBRACKET: INDEX,
token.ASSIGN: ASSIGN,
token.PLUS_ASSIGN: ASSIGN,
token.MINUS_ASSIGN: ASSIGN,
token.ASTERISK_ASSIGN: ASSIGN,
token.SLASH_ASSIGN: ASSIGN,
token.MODULO_ASSIGN: ASSIGN,
}

type Parser struct {
Expand Down Expand Up @@ -85,6 +87,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.MODULO, p.parseInfixExpression)
p.registerInfix(token.EQ, p.parseInfixExpression)
p.registerInfix(token.NOT_EQ, p.parseInfixExpression)
p.registerInfix(token.LT, p.parseInfixExpression)
Expand All @@ -98,6 +101,7 @@ func New(l *lexer.Lexer) *Parser {
p.registerInfix(token.MINUS_ASSIGN, p.parseAssignExpression)
p.registerInfix(token.ASTERISK_ASSIGN, p.parseAssignExpression)
p.registerInfix(token.SLASH_ASSIGN, p.parseAssignExpression)
p.registerInfix(token.MODULO_ASSIGN, p.parseAssignExpression)

return p
}
Expand Down
2 changes: 2 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ func TestParsingInfixExpressions(t *testing.T) {
{"5 - 5;", 5, "-", 5},
{"5 * 5;", 5, "*", 5},
{"5 / 5;", 5, "/", 5},
{"5 % 5;", 5, "%", 5},
{"5 > 5;", 5, ">", 5},
{"5 >= 5;", 5, ">=", 5},
{"5 < 5;", 5, "<", 5},
Expand Down Expand Up @@ -711,6 +712,7 @@ func TestAssignExpressions(t *testing.T) {
{"c = 5;", "c", "=", "5"},
{"d *= 4;", "d", "*=", "4"},
{"e /= 2;", "e", "/=", "2"},
{"e %= 2;", "e", "%=", "2"},
{"x[2 + 1] = 5 * 3;", "(x[(2 + 1)])", "=", "(5 * 3)"},
}

Expand Down
2 changes: 2 additions & 0 deletions token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (
ASTERISK_ASSIGN = "*="
SLASH = "/"
SLASH_ASSIGN = "/="
MODULO = "%"
MODULO_ASSIGN = "%="
BANG = "!"

LT = "<"
Expand Down

0 comments on commit 9583ef8

Please sign in to comment.