diff --git a/.idea/git_toolbox_prj.xml b/.idea/git_toolbox_prj.xml
new file mode 100644
index 0000000..02b915b
--- /dev/null
+++ b/.idea/git_toolbox_prj.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lexer/lexer.go b/lexer/lexer.go
index d04bd69..30bccf8 100644
--- a/lexer/lexer.go
+++ b/lexer/lexer.go
@@ -25,6 +25,14 @@ func (l *Lexer) readChar() {
l.readPosition += 1
}
+func (l *Lexer) peekChar() byte {
+ if l.readPosition >= len(l.input) {
+ return 0
+ } else {
+ return l.input[l.readPosition]
+ }
+}
+
func (l *Lexer) NextToken() token.Token {
var tok token.Token
@@ -32,17 +40,50 @@ func (l *Lexer) NextToken() token.Token {
switch l.ch {
case '=':
- tok = newToken(token.ASSIGN, l.ch)
+ if l.peekChar() == '=' {
+ ch := l.ch
+ l.readChar()
+ literal := string(ch) + string(l.ch)
+ tok = token.Token{
+ Type: token.EQ,
+ Literal: literal,
+ }
+ } else {
+ tok = newToken(token.ASSIGN, l.ch)
+ }
+ case '+':
+ tok = newToken(token.PLUS, l.ch)
+ case '-':
+ tok = newToken(token.MINUS, l.ch)
+ case '!':
+ if l.peekChar() == '=' {
+ ch := l.ch
+ l.readChar()
+ literal := string(ch) + string(l.ch)
+ tok = token.Token{
+ Type: token.NOT_EQ,
+ Literal: literal,
+ }
+ } else {
+ tok = newToken(token.BANG, l.ch)
+ }
+
+ case '/':
+ tok = newToken(token.SLASH, l.ch)
+ case '*':
+ tok = newToken(token.ASTERISK, l.ch)
+ case '<':
+ tok = newToken(token.LT, l.ch)
+ case '>':
+ tok = newToken(token.GT, l.ch)
case ';':
tok = newToken(token.SEMICOLON, l.ch)
+ case ',':
+ tok = newToken(token.COMMA, l.ch)
case '(':
tok = newToken(token.LPAREN, l.ch)
case ')':
tok = newToken(token.RPAREN, l.ch)
- case ',':
- tok = newToken(token.COMMA, l.ch)
- case '+':
- tok = newToken(token.PLUS, l.ch)
case '{':
tok = newToken(token.LBRACE, l.ch)
case '}':
diff --git a/lexer/lexer_test.go b/lexer/lexer_test.go
index 42a604e..eb6e2cf 100644
--- a/lexer/lexer_test.go
+++ b/lexer/lexer_test.go
@@ -14,6 +14,17 @@ let add = fn(x, y) {
};
let result = add(five, ten);
+!-/*5;
+5 < 10 > 5;
+
+if (5 < 10) {
+ return true;
+} else {
+ return false;
+}
+
+10 == 10;
+10 != 9;
`
tests := []struct {
@@ -56,6 +67,52 @@ let result = add(five, ten);
{token.IDENT, "ten"},
{token.RPAREN, ")"},
{token.SEMICOLON, ";"},
+
+ {token.BANG, "!"},
+ {token.MINUS, "-"},
+ {token.SLASH, "/"},
+ {token.ASTERISK, "*"},
+ {token.INT, "5"},
+ {token.SEMICOLON, ";"},
+ {token.INT, "5"},
+ {token.LT, "<"},
+ {token.INT, "10"},
+ {token.GT, ">"},
+ {token.INT, "5"},
+ {token.SEMICOLON, ";"},
+
+ {token.IF, "if"},
+ {token.LPAREN, "("},
+ {token.INT, "5"},
+ {token.LT, "<"},
+ {token.INT, "10"},
+ {token.RPAREN, ")"},
+ {token.LBRACE, "{"},
+
+ {token.RETURN, "return"},
+ {token.TRUE, "true"},
+ {token.SEMICOLON, ";"},
+
+ {token.RBRACE, "}"},
+ {token.ELSE, "else"},
+ {token.LBRACE, "{"},
+
+ {token.RETURN, "return"},
+ {token.FALSE, "false"},
+ {token.SEMICOLON, ";"},
+
+ {token.RBRACE, "}"},
+
+ {token.INT, "10"},
+ {token.EQ, "=="},
+ {token.INT, "10"},
+ {token.SEMICOLON, ";"},
+
+ {token.INT, "10"},
+ {token.NOT_EQ, "!="},
+ {token.INT, "9"},
+ {token.SEMICOLON, ";"},
+
{token.EOF, ""},
}
diff --git a/token/token.go b/token/token.go
index 76b951a..5cae921 100644
--- a/token/token.go
+++ b/token/token.go
@@ -16,8 +16,18 @@ const (
INT = "INT" // 123456
// Operators
- ASSIGN = "="
- PLUS = "+"
+ ASSIGN = "="
+ PLUS = "+"
+ MINUS = "-"
+ BANG = "!"
+ ASTERISK = "*"
+ SLASH = "/"
+
+ LT = "<"
+ GT = ">"
+
+ EQ = "=="
+ NOT_EQ = "!="
// Delimiters
COMMA = ","
@@ -31,11 +41,21 @@ const (
// Keywords
FUNCTION = "FUNCTION"
LET = "LET"
+ TRUE = "TRUE"
+ FALSE = "FALSE"
+ IF = "IF"
+ ELSE = "ELSE"
+ RETURN = "RETURN"
)
var keywords = map[string]TokenType{
- "fn": FUNCTION,
- "let": LET,
+ "fn": FUNCTION,
+ "let": LET,
+ "true": TRUE,
+ "false": FALSE,
+ "if": IF,
+ "else": ELSE,
+ "return": RETURN,
}
func LookupIdent(ident string) TokenType {