diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 37fabfbf47..a3e95974e0 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -33,6 +33,7 @@ namespace JS { HashMap Lexer::s_keywords; +HashMap Lexer::s_three_char_tokens; HashMap Lexer::s_two_char_tokens; HashMap Lexer::s_single_char_tokens; @@ -62,6 +63,11 @@ Lexer::Lexer(StringView source) s_keywords.set("while", TokenType::While); } + if (s_three_char_tokens.is_empty()) { + s_three_char_tokens.set("===", TokenType::EqualsEqualsEquals); + s_three_char_tokens.set("!==", TokenType::ExclamationMarkEqualsEquals); + } + if (s_two_char_tokens.is_empty()) { s_two_char_tokens.set("+=", TokenType::PlusEquals); s_two_char_tokens.set("-=", TokenType::MinusEquals); @@ -174,7 +180,7 @@ Token Lexer::next() } size_t value_start = m_position; - TokenType token_type; + auto token_type = TokenType::Invalid; if (is_identifier_start()) { // identifier or keyword @@ -205,8 +211,23 @@ Token Lexer::next() } else if (m_current_char == EOF) { token_type = TokenType::Eof; } else { + bool found_three_char_token = false; + if (m_position+1 < m_source.length()) { + char secondChar = m_source[m_position]; + char thirdChar = m_source[m_position+1]; + char threeChars[] { (char)m_current_char, secondChar, thirdChar, 0 }; + auto it = s_three_char_tokens.find(threeChars); + if (it != s_three_char_tokens.end()) { + found_three_char_token = true; + consume(); + consume(); + consume(); + token_type = it->value; + } + } + bool found_two_char_token = false; - if (!is_eof()) { + if (!found_three_char_token && !is_eof()) { char secondChar = m_source[m_position]; char twoChars[] { (char)m_current_char, secondChar, 0 }; auto it = s_two_char_tokens.find(twoChars); @@ -218,16 +239,20 @@ Token Lexer::next() } } - if (!found_two_char_token) { + bool found_one_char_token = false; + if (!found_three_char_token && !found_two_char_token) { auto it = s_single_char_tokens.find(m_current_char); if (it != s_single_char_tokens.end()) { + found_one_char_token = true; consume(); token_type = it->value; - } else { - consume(); - token_type = TokenType::Invalid; } } + + if (!found_three_char_token && !found_two_char_token && !found_one_char_token) { + consume(); + token_type = TokenType::Invalid; + } } m_current_token = Token( diff --git a/Libraries/LibJS/Lexer.h b/Libraries/LibJS/Lexer.h index 01d1fdc1ce..a91c85ff37 100644 --- a/Libraries/LibJS/Lexer.h +++ b/Libraries/LibJS/Lexer.h @@ -54,6 +54,7 @@ private: int m_current_char; static HashMap s_keywords; + static HashMap s_three_char_tokens; static HashMap s_two_char_tokens; static HashMap s_single_char_tokens; }; diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 746620484b..8c79857606 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -157,6 +157,12 @@ NonnullOwnPtr Parser::parse_secondary_expression(NonnullOwnPtr(BinaryOp::LessThanEquals, move(lhs), parse_expression()); + case TokenType::EqualsEqualsEquals: + consume(); + return make(BinaryOp::TypedEquals, move(lhs), parse_expression()); + case TokenType::ExclamationMarkEqualsEquals: + consume(); + return make(BinaryOp::TypedInequals, move(lhs), parse_expression()); case TokenType::ParenOpen: return parse_call_expression(move(lhs)); case TokenType::Equals: @@ -276,6 +282,8 @@ bool Parser::match_secondary_expression() const || type == TokenType::Slash || type == TokenType::SlashEquals || type == TokenType::Equals + || type == TokenType::EqualsEqualsEquals + || type == TokenType::ExclamationMarkEqualsEquals || type == TokenType::GreaterThan || type == TokenType::GreaterThanEquals || type == TokenType::LessThan diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index b5c0bc47a1..02d901ee52 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -53,8 +53,10 @@ enum class TokenType { Eof, Equals, EqualsEquals, + EqualsEqualsEquals, ExclamationMark, ExclamationMarkEquals, + ExclamationMarkEqualsEquals, Finally, Function, GreaterThan,