mirror of
https://github.com/RGBCube/serenity
synced 2025-07-02 22:42:08 +00:00
LibJS: Add operator precedence parsing
Obey precedence and associativity rules when parsing expressions with chained operators.
This commit is contained in:
parent
f347dd5c5e
commit
15d5b2d29e
8 changed files with 281 additions and 53 deletions
|
@ -42,31 +42,41 @@ Lexer::Lexer(StringView source)
|
|||
, m_current_token(TokenType::Eof, StringView(nullptr), StringView(nullptr))
|
||||
{
|
||||
if (s_keywords.is_empty()) {
|
||||
s_keywords.set("true", TokenType::BoolLiteral);
|
||||
s_keywords.set("false", TokenType::BoolLiteral);
|
||||
s_keywords.set("await", TokenType::Await);
|
||||
s_keywords.set("catch", TokenType::Catch);
|
||||
s_keywords.set("class", TokenType::Class);
|
||||
s_keywords.set("const", TokenType::Const);
|
||||
s_keywords.set("delete", TokenType::Delete);
|
||||
s_keywords.set("do", TokenType::Do);
|
||||
s_keywords.set("else", TokenType::Else);
|
||||
s_keywords.set("false", TokenType::BoolLiteral);
|
||||
s_keywords.set("finally", TokenType::Finally);
|
||||
s_keywords.set("for", TokenType::For);
|
||||
s_keywords.set("function", TokenType::Function);
|
||||
s_keywords.set("if", TokenType::If);
|
||||
s_keywords.set("in", TokenType::In);
|
||||
s_keywords.set("instanceof", TokenType::Instanceof);
|
||||
s_keywords.set("interface", TokenType::Interface);
|
||||
s_keywords.set("let", TokenType::Let);
|
||||
s_keywords.set("new", TokenType::New);
|
||||
s_keywords.set("null", TokenType::NullLiteral);
|
||||
s_keywords.set("return", TokenType::Return);
|
||||
s_keywords.set("true", TokenType::BoolLiteral);
|
||||
s_keywords.set("try", TokenType::Try);
|
||||
s_keywords.set("typeof", TokenType::Typeof);
|
||||
s_keywords.set("var", TokenType::Var);
|
||||
s_keywords.set("void", TokenType::Void);
|
||||
s_keywords.set("while", TokenType::While);
|
||||
s_keywords.set("yield", TokenType::Yield);
|
||||
}
|
||||
|
||||
if (s_three_char_tokens.is_empty()) {
|
||||
s_three_char_tokens.set("===", TokenType::EqualsEqualsEquals);
|
||||
s_three_char_tokens.set("!==", TokenType::ExclamationMarkEqualsEquals);
|
||||
s_three_char_tokens.set("**=", TokenType::AsteriskAsteriskEquals);
|
||||
s_three_char_tokens.set("<<=", TokenType::ShiftLeftEquals);
|
||||
s_three_char_tokens.set(">>=", TokenType::ShiftRightEquals);
|
||||
s_three_char_tokens.set(">>>", TokenType::UnsignedShiftRight);
|
||||
}
|
||||
|
||||
if (s_two_char_tokens.is_empty()) {
|
||||
|
@ -79,12 +89,15 @@ Lexer::Lexer(StringView source)
|
|||
s_two_char_tokens.set("|=", TokenType::PipeEquals);
|
||||
s_two_char_tokens.set("&&", TokenType::DoubleAmpersand);
|
||||
s_two_char_tokens.set("||", TokenType::DoublePipe);
|
||||
s_two_char_tokens.set("??", TokenType::DoubleQuestionMark);
|
||||
s_two_char_tokens.set("**", TokenType::DoubleAsterisk);
|
||||
s_two_char_tokens.set("==", TokenType::EqualsEquals);
|
||||
s_two_char_tokens.set("!=", TokenType::ExclamationMarkEquals);
|
||||
s_two_char_tokens.set("--", TokenType::MinusMinus);
|
||||
s_two_char_tokens.set("++", TokenType::PlusPlus);
|
||||
s_two_char_tokens.set("<<", TokenType::ShiftLeft);
|
||||
s_two_char_tokens.set(">>", TokenType::ShiftRight);
|
||||
s_two_char_tokens.set("?.", TokenType::QuestionMarkPeriod);
|
||||
}
|
||||
|
||||
if (s_single_char_tokens.is_empty()) {
|
||||
|
@ -92,6 +105,7 @@ Lexer::Lexer(StringView source)
|
|||
s_single_char_tokens.set('*', TokenType::Asterisk);
|
||||
s_single_char_tokens.set('[', TokenType::BracketOpen);
|
||||
s_single_char_tokens.set(']', TokenType::BracketClose);
|
||||
s_single_char_tokens.set('^', TokenType::Caret);
|
||||
s_single_char_tokens.set(',', TokenType::Comma);
|
||||
s_single_char_tokens.set('{', TokenType::CurlyOpen);
|
||||
s_single_char_tokens.set('}', TokenType::CurlyClose);
|
||||
|
@ -107,6 +121,7 @@ Lexer::Lexer(StringView source)
|
|||
s_single_char_tokens.set('?', TokenType::QuestionMark);
|
||||
s_single_char_tokens.set(';', TokenType::Semicolon);
|
||||
s_single_char_tokens.set('/', TokenType::Slash);
|
||||
s_single_char_tokens.set('~', TokenType::Tilde);
|
||||
s_single_char_tokens.set('<', TokenType::LessThan);
|
||||
s_single_char_tokens.set('>', TokenType::GreaterThan);
|
||||
}
|
||||
|
@ -213,8 +228,25 @@ Token Lexer::next()
|
|||
} else if (m_current_char == EOF) {
|
||||
token_type = TokenType::Eof;
|
||||
} else {
|
||||
// There is only one four-char operator: >>>=
|
||||
bool found_four_char_token = false;
|
||||
if (m_position + 2 < m_source.length()) {
|
||||
if (m_current_char == '>'
|
||||
&& m_source[m_position] == '>'
|
||||
&& m_source[m_position + 1] == '>'
|
||||
&& m_source[m_position + 2] == '=') {
|
||||
|
||||
found_four_char_token = true;
|
||||
consume();
|
||||
consume();
|
||||
consume();
|
||||
consume();
|
||||
token_type = TokenType::UnsignedShiftRightEquals;
|
||||
}
|
||||
}
|
||||
|
||||
bool found_three_char_token = false;
|
||||
if (m_position + 1 < m_source.length()) {
|
||||
if (!found_four_char_token && m_position + 1 < m_source.length()) {
|
||||
char second_char = m_source[m_position];
|
||||
char third_char = m_source[m_position + 1];
|
||||
char three_chars[] { (char)m_current_char, second_char, third_char, 0 };
|
||||
|
@ -229,7 +261,7 @@ Token Lexer::next()
|
|||
}
|
||||
|
||||
bool found_two_char_token = false;
|
||||
if (!found_three_char_token && m_position < m_source.length()) {
|
||||
if (!found_four_char_token && !found_three_char_token && m_position < m_source.length()) {
|
||||
char second_char = m_source[m_position];
|
||||
char two_chars[] { (char)m_current_char, second_char, 0 };
|
||||
auto it = s_two_char_tokens.find(two_chars);
|
||||
|
@ -242,7 +274,7 @@ Token Lexer::next()
|
|||
}
|
||||
|
||||
bool found_one_char_token = false;
|
||||
if (!found_three_char_token && !found_two_char_token) {
|
||||
if (!found_four_char_token && !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;
|
||||
|
@ -251,7 +283,7 @@ Token Lexer::next()
|
|||
}
|
||||
}
|
||||
|
||||
if (!found_three_char_token && !found_two_char_token && !found_one_char_token) {
|
||||
if (!found_four_char_token && !found_three_char_token && !found_two_char_token && !found_one_char_token) {
|
||||
consume();
|
||||
token_type = TokenType::Invalid;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue