package lexer import ( "monkey/token" "testing" ) func TestNextToken(t *testing.T) { input := `#!./monkey-lang let five = 5; let ten = 10; let add = fn(x, y) { x + y; }; # this is a comment let result = add(five, ten); !-/*5; 5 < 10 > 5; if (5 < 10) { return true; } else { return false; } // this is another comment 10 == 10; 10 != 9; "foobar" "foo bar" [1, 2]; {"foo": "bar"} d.foo ` tests := []struct { expectedType token.TokenType expectedLiteral string }{ {token.COMMENT, "!./monkey-lang"}, {token.LET, "let"}, {token.IDENT, "five"}, {token.ASSIGN, "="}, {token.INT, "5"}, {token.SEMICOLON, ";"}, {token.LET, "let"}, {token.IDENT, "ten"}, {token.ASSIGN, "="}, {token.INT, "10"}, {token.SEMICOLON, ";"}, {token.LET, "let"}, {token.IDENT, "add"}, {token.ASSIGN, "="}, {token.FUNCTION, "fn"}, {token.LPAREN, "("}, {token.IDENT, "x"}, {token.COMMA, ","}, {token.IDENT, "y"}, {token.RPAREN, ")"}, {token.LBRACE, "{"}, {token.IDENT, "x"}, {token.PLUS, "+"}, {token.IDENT, "y"}, {token.SEMICOLON, ";"}, {token.RBRACE, "}"}, {token.SEMICOLON, ";"}, {token.COMMENT, " this is a comment"}, {token.LET, "let"}, {token.IDENT, "result"}, {token.ASSIGN, "="}, {token.IDENT, "add"}, {token.LPAREN, "("}, {token.IDENT, "five"}, {token.COMMA, ","}, {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.COMMENT, " this is another comment"}, {token.INT, "10"}, {token.EQ, "=="}, {token.INT, "10"}, {token.SEMICOLON, ";"}, {token.INT, "10"}, {token.NOT_EQ, "!="}, {token.INT, "9"}, {token.SEMICOLON, ";"}, {token.STRING, "foobar"}, {token.STRING, "foo bar"}, {token.LBRACKET, "["}, {token.INT, "1"}, {token.COMMA, ","}, {token.INT, "2"}, {token.RBRACKET, "]"}, {token.SEMICOLON, ";"}, {token.LBRACE, "{"}, {token.STRING, "foo"}, {token.COLON, ":"}, {token.STRING, "bar"}, {token.RBRACE, "}"}, {token.IDENT, "d"}, {token.DOT, "."}, {token.IDENT, "foo"}, {token.EOF, ""}, } l := New(input) for i, tt := range tests { tok := l.NextToken() if tok.Type != tt.expectedType { t.Fatalf("tests[%d] - tokentype wrong. expected=%q, got=%q", i, tt.expectedType, tok.Type) } if tok.Literal != tt.expectedLiteral { t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q", i, tt.expectedLiteral, tok.Literal) } } } func TestStringEscapes(t *testing.T) { input := `#!./monkey-lang let a = "\"foo\"" let b = "\x00\x0a\x7f" let c = "\r\n\t" ` tests := []struct { expectedType token.TokenType expectedLiteral string }{ {token.COMMENT, "!./monkey-lang"}, {token.LET, "let"}, {token.IDENT, "a"}, {token.ASSIGN, "="}, {token.STRING, "\"foo\""}, {token.LET, "let"}, {token.IDENT, "b"}, {token.ASSIGN, "="}, {token.STRING, "\x00\n\u007f"}, {token.LET, "let"}, {token.IDENT, "c"}, {token.ASSIGN, "="}, {token.STRING, "\r\n\t"}, {token.EOF, ""}, } lexer := New(input) for i, test := range tests { token := lexer.NextToken() if token.Type != test.expectedType { t.Fatalf("tests[%d] - token type wrong. expected=%q, got=%q", i, test.expectedType, token.Type) } if token.Literal != test.expectedLiteral { t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q", i, test.expectedLiteral, token.Literal) } } }