Skip to content

Commit 7fa4e11

Browse files
committed
Everything math
-> Add logical operators || and && -> Add >= and <= -> Pow (**) and Modulus (%) -> Initialize variables with fanya or acha -> Define functions with fn() or unda()
1 parent 2a95148 commit 7fa4e11

File tree

4 files changed

+88
-4
lines changed

4 files changed

+88
-4
lines changed

evaluator/evaluator.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package evaluator
22

33
import (
44
"fmt"
5+
"math"
56
"strings"
67

78
"github.com/AvicennaJr/Nuru/ast"
@@ -282,6 +283,8 @@ func evalInfixExpression(operator string, left, right object.Object, line int) o
282283

283284
case operator == "!=":
284285
return nativeBoolToBooleanObject(left != right)
286+
case left.Type() == object.BOOLEAN_OBJ && right.Type() == object.BOOLEAN_OBJ:
287+
return evalBooleanInfixExpression(operator, left, right, line)
285288

286289
case left.Type() != right.Type():
287290
return newError("Mstari %d: Aina Hazilingani: %s %s %s",
@@ -304,12 +307,20 @@ func evalIntegerInfixExpression(operator string, left, right object.Object, line
304307
return &object.Integer{Value: leftVal - rightVal}
305308
case "*":
306309
return &object.Integer{Value: leftVal * rightVal}
310+
case "**":
311+
return &object.Integer{Value: int64(math.Pow(float64(leftVal), float64(rightVal)))}
307312
case "/":
308313
return &object.Integer{Value: leftVal / rightVal}
314+
case "%":
315+
return &object.Integer{Value: leftVal % rightVal}
309316
case "<":
310317
return nativeBoolToBooleanObject(leftVal < rightVal)
318+
case "<=":
319+
return nativeBoolToBooleanObject(leftVal <= rightVal)
311320
case ">":
312321
return nativeBoolToBooleanObject(leftVal > rightVal)
322+
case ">=":
323+
return nativeBoolToBooleanObject(leftVal >= rightVal)
313324
case "==":
314325
return nativeBoolToBooleanObject(leftVal == rightVal)
315326
case "!=":
@@ -320,6 +331,19 @@ func evalIntegerInfixExpression(operator string, left, right object.Object, line
320331
}
321332
}
322333

334+
func evalBooleanInfixExpression(operator string, left, right object.Object, line int) object.Object {
335+
leftVal := left.(*object.Boolean).Value
336+
rightVal := right.(*object.Boolean).Value
337+
338+
switch operator {
339+
case "&&":
340+
return nativeBoolToBooleanObject(leftVal && rightVal)
341+
case "||":
342+
return nativeBoolToBooleanObject(leftVal || rightVal)
343+
default:
344+
return newError("Mstarid %d: Opereresheni Haielweki: %s %s %s", line, left.Type(), operator, right.Type())
345+
}
346+
}
323347
func evalIfExpression(ie *ast.IfExpression, env *object.Environment) object.Object {
324348
condition := Eval(ie.Condition, env)
325349

lexer/lexer.go

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,29 @@ func (l *Lexer) NextToken() token.Token {
7777
case '/':
7878
tok = newToken(token.SLASH, l.line, l.ch)
7979
case '*':
80-
tok = newToken(token.ASTERISK, l.line, l.ch)
80+
if l.peekChar() == '*' {
81+
ch := l.ch
82+
l.readChar()
83+
tok = token.Token{Type: token.POW, Literal: string(ch) + string(l.ch), Line: l.line}
84+
} else {
85+
tok = newToken(token.ASTERISK, l.line, l.ch)
86+
}
8187
case '<':
82-
tok = newToken(token.LT, l.line, l.ch)
88+
if l.peekChar() == '=' {
89+
ch := l.ch
90+
l.readChar()
91+
tok = token.Token{Type: token.LTE, Literal: string(ch) + string(l.ch), Line: l.line}
92+
} else {
93+
tok = newToken(token.LT, l.line, l.ch)
94+
}
8395
case '>':
84-
tok = newToken(token.GT, l.line, l.ch)
96+
if l.peekChar() == '=' {
97+
ch := l.ch
98+
l.readChar()
99+
tok = token.Token{Type: token.GTE, Literal: string(ch) + string(l.ch), Line: l.line}
100+
} else {
101+
tok = newToken(token.GT, l.line, l.ch)
102+
}
85103
case '"':
86104
tok.Type = token.STRING
87105
tok.Literal = l.readString()
@@ -94,6 +112,20 @@ func (l *Lexer) NextToken() token.Token {
94112
tok = newToken(token.RBRACKET, l.line, l.ch)
95113
case ':':
96114
tok = newToken(token.COLON, l.line, l.ch)
115+
case '&':
116+
if l.peekChar() == '&' {
117+
ch := l.ch
118+
l.readChar()
119+
tok = token.Token{Type: token.AND, Literal: string(ch) + string(l.ch), Line: l.line}
120+
}
121+
case '|':
122+
if l.peekChar() == '|' {
123+
ch := l.ch
124+
l.readChar()
125+
tok = token.Token{Type: token.OR, Literal: string(ch) + string(l.ch), Line: l.line}
126+
}
127+
case '%':
128+
tok = newToken(token.MODULUS, l.line, l.ch)
97129
case 0:
98130
tok.Literal = ""
99131
tok.Type = token.EOF

parser/parser.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,36 @@ const (
1313
// Think of BODMAS
1414
_ int = iota
1515
LOWEST
16+
COND // OR or AND
1617
ASSIGN // =
1718
EQUALS // ==
1819
LESSGREATER // > OR <
1920
SUM // +
2021
PRODUCT // *
22+
POWER // ** we got the power XD
23+
MODULUS // %
2124
PREFIX // -X OR !X
2225
CALL // myFunction(X)
2326
INDEX // Arrays
2427
)
2528

2629
var precedences = map[token.TokenType]int{
27-
token.ASSIGN: ASSIGN, // Lowest priority
30+
token.AND: COND,
31+
token.OR: COND,
32+
token.ASSIGN: ASSIGN,
2833
token.EQ: EQUALS,
2934
token.NOT_EQ: EQUALS,
3035
token.LT: LESSGREATER,
36+
token.LTE: LESSGREATER,
3137
token.GT: LESSGREATER,
38+
token.GTE: LESSGREATER,
3239
token.PLUS: SUM,
3340
token.MINUS: SUM,
3441
token.SLASH: PRODUCT,
3542
token.ASTERISK: PRODUCT,
43+
token.POW: POWER,
44+
token.MODULUS: MODULUS,
45+
// token.BANG: PREFIX,
3646
token.LPAREN: CALL,
3747
token.LBRACKET: INDEX, // Highest priority
3848
}
@@ -78,14 +88,20 @@ func New(l *lexer.Lexer) *Parser {
7888
p.registerPrefix(token.NULL, p.parseNull)
7989

8090
p.infixParseFns = make(map[token.TokenType]infixParseFn)
91+
p.registerInfix(token.AND, p.parseInfixExpression)
92+
p.registerInfix(token.OR, p.parseInfixExpression)
8193
p.registerInfix(token.PLUS, p.parseInfixExpression)
8294
p.registerInfix(token.MINUS, p.parseInfixExpression)
8395
p.registerInfix(token.SLASH, p.parseInfixExpression)
8496
p.registerInfix(token.ASTERISK, p.parseInfixExpression)
97+
p.registerInfix(token.POW, p.parseInfixExpression)
98+
p.registerInfix(token.MODULUS, p.parseInfixExpression)
8599
p.registerInfix(token.EQ, p.parseInfixExpression)
86100
p.registerInfix(token.NOT_EQ, p.parseInfixExpression)
87101
p.registerInfix(token.LT, p.parseInfixExpression)
102+
p.registerInfix(token.LTE, p.parseInfixExpression)
88103
p.registerInfix(token.GT, p.parseInfixExpression)
104+
p.registerInfix(token.GTE, p.parseInfixExpression)
89105
p.registerInfix(token.LPAREN, p.parseCallExpression)
90106
p.registerInfix(token.LBRACKET, p.parseIndexExpression)
91107
p.registerInfix(token.ASSIGN, p.parseAssignmentExpression)

token/token.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,17 @@ const (
2323
MINUS = "-"
2424
BANG = "!"
2525
ASTERISK = "*"
26+
POW = "**"
2627
SLASH = "/"
28+
MODULUS = "%"
2729
LT = "<"
30+
LTE = "<="
2831
GT = ">"
32+
GTE = ">="
2933
EQ = "=="
3034
NOT_EQ = "!="
35+
AND = "&&"
36+
OR = "||"
3137

3238
//Delimiters
3339
COMMA = ","
@@ -50,18 +56,24 @@ const (
5056
RETURN = "RUDISHA"
5157
WHILE = "WAKATI"
5258
NULL = "TUPU"
59+
BREAK = "SUSA"
60+
CONTINUE = "ENDELEA"
5361
)
5462

5563
var keywords = map[string]TokenType{
5664
"fn": FUNCTION,
65+
"unda": FUNCTION,
5766
"acha": LET,
67+
"fanya": LET,
5868
"kweli": TRUE,
5969
"sikweli": FALSE,
6070
"kama": IF,
6171
"au": ELSE,
6272
"sivyo": ELSE,
6373
"wakati": WHILE,
6474
"rudisha": RETURN,
75+
"susa": BREAK,
76+
"endelea": CONTINUE,
6577
"tupu": NULL,
6678
}
6779

0 commit comments

Comments
 (0)