mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:47:45 +00:00
LibJS: Lexer and parser support for "switch" statements
This commit is contained in:
parent
70dc80fa47
commit
1923051c5b
7 changed files with 164 additions and 2 deletions
|
@ -871,4 +871,51 @@ Value ThrowStatement::execute(Interpreter& interpreter) const
|
||||||
return interpreter.throw_exception(value);
|
return interpreter.throw_exception(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Value SwitchStatement::execute(Interpreter& interpreter) const
|
||||||
|
{
|
||||||
|
(void)interpreter;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Value SwitchCase::execute(Interpreter& interpreter) const
|
||||||
|
{
|
||||||
|
(void)interpreter;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Value BreakStatement::execute(Interpreter& interpreter) const
|
||||||
|
{
|
||||||
|
(void)interpreter;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchStatement::dump(int indent) const
|
||||||
|
{
|
||||||
|
ASTNode::dump(indent);
|
||||||
|
m_discriminant->dump(indent + 1);
|
||||||
|
for (auto& switch_case : m_cases) {
|
||||||
|
switch_case.dump(indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitchCase::dump(int indent) const
|
||||||
|
{
|
||||||
|
ASTNode::dump(indent);
|
||||||
|
print_indent(indent);
|
||||||
|
if (m_test) {
|
||||||
|
printf("(Test)\n");
|
||||||
|
m_test->dump(indent + 1);
|
||||||
|
} else {
|
||||||
|
printf("(Default)\n");
|
||||||
|
}
|
||||||
|
print_indent(indent);
|
||||||
|
printf("(Consequent)\n");
|
||||||
|
int i = 0;
|
||||||
|
for (auto& statement : m_consequent) {
|
||||||
|
print_indent(indent);
|
||||||
|
printf("[%d]\n", i++);
|
||||||
|
statement.dump(indent + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -496,7 +496,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual const char * class_name() const override { return "NewExpression"; }
|
virtual const char* class_name() const override { return "NewExpression"; }
|
||||||
virtual bool is_new_expression() const override { return true; }
|
virtual bool is_new_expression() const override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -707,4 +707,50 @@ private:
|
||||||
NonnullRefPtr<Expression> m_argument;
|
NonnullRefPtr<Expression> m_argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SwitchCase final : public ASTNode {
|
||||||
|
public:
|
||||||
|
SwitchCase(RefPtr<Expression> test, NonnullRefPtrVector<Statement> consequent)
|
||||||
|
: m_test(move(test))
|
||||||
|
, m_consequent(move(consequent))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dump(int indent) const override;
|
||||||
|
virtual Value execute(Interpreter&) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual const char* class_name() const override { return "SwitchCase"; }
|
||||||
|
|
||||||
|
RefPtr<Expression> m_test;
|
||||||
|
NonnullRefPtrVector<Statement> m_consequent;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SwitchStatement final : public Statement {
|
||||||
|
public:
|
||||||
|
SwitchStatement(NonnullRefPtr<Expression> discriminant, NonnullRefPtrVector<SwitchCase> cases)
|
||||||
|
: m_discriminant(move(discriminant))
|
||||||
|
, m_cases(move(cases))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dump(int indent) const override;
|
||||||
|
virtual Value execute(Interpreter&) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual const char* class_name() const override { return "SwitchStatement"; }
|
||||||
|
|
||||||
|
NonnullRefPtr<Expression> m_discriminant;
|
||||||
|
NonnullRefPtrVector<SwitchCase> m_cases;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BreakStatement final : public Statement {
|
||||||
|
public:
|
||||||
|
BreakStatement() {}
|
||||||
|
|
||||||
|
virtual Value execute(Interpreter&) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual const char* class_name() const override { return "BreakStatement"; }
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,12 @@ Lexer::Lexer(StringView source)
|
||||||
{
|
{
|
||||||
if (s_keywords.is_empty()) {
|
if (s_keywords.is_empty()) {
|
||||||
s_keywords.set("await", TokenType::Await);
|
s_keywords.set("await", TokenType::Await);
|
||||||
|
s_keywords.set("break", TokenType::Break);
|
||||||
|
s_keywords.set("case", TokenType::Case);
|
||||||
s_keywords.set("catch", TokenType::Catch);
|
s_keywords.set("catch", TokenType::Catch);
|
||||||
s_keywords.set("class", TokenType::Class);
|
s_keywords.set("class", TokenType::Class);
|
||||||
s_keywords.set("const", TokenType::Const);
|
s_keywords.set("const", TokenType::Const);
|
||||||
|
s_keywords.set("default", TokenType::Default);
|
||||||
s_keywords.set("delete", TokenType::Delete);
|
s_keywords.set("delete", TokenType::Delete);
|
||||||
s_keywords.set("do", TokenType::Do);
|
s_keywords.set("do", TokenType::Do);
|
||||||
s_keywords.set("else", TokenType::Else);
|
s_keywords.set("else", TokenType::Else);
|
||||||
|
@ -60,12 +63,13 @@ Lexer::Lexer(StringView source)
|
||||||
s_keywords.set("let", TokenType::Let);
|
s_keywords.set("let", TokenType::Let);
|
||||||
s_keywords.set("new", TokenType::New);
|
s_keywords.set("new", TokenType::New);
|
||||||
s_keywords.set("null", TokenType::NullLiteral);
|
s_keywords.set("null", TokenType::NullLiteral);
|
||||||
s_keywords.set("undefined", TokenType::UndefinedLiteral);
|
|
||||||
s_keywords.set("return", TokenType::Return);
|
s_keywords.set("return", TokenType::Return);
|
||||||
|
s_keywords.set("switch", TokenType::Switch);
|
||||||
s_keywords.set("throw", TokenType::Throw);
|
s_keywords.set("throw", TokenType::Throw);
|
||||||
s_keywords.set("true", TokenType::BoolLiteral);
|
s_keywords.set("true", TokenType::BoolLiteral);
|
||||||
s_keywords.set("try", TokenType::Try);
|
s_keywords.set("try", TokenType::Try);
|
||||||
s_keywords.set("typeof", TokenType::Typeof);
|
s_keywords.set("typeof", TokenType::Typeof);
|
||||||
|
s_keywords.set("undefined", TokenType::UndefinedLiteral);
|
||||||
s_keywords.set("var", TokenType::Var);
|
s_keywords.set("var", TokenType::Var);
|
||||||
s_keywords.set("void", TokenType::Void);
|
s_keywords.set("void", TokenType::Void);
|
||||||
s_keywords.set("while", TokenType::While);
|
s_keywords.set("while", TokenType::While);
|
||||||
|
|
|
@ -202,6 +202,10 @@ NonnullRefPtr<Statement> Parser::parse_statement()
|
||||||
return parse_throw_statement();
|
return parse_throw_statement();
|
||||||
case TokenType::Try:
|
case TokenType::Try:
|
||||||
return parse_try_statement();
|
return parse_try_statement();
|
||||||
|
case TokenType::Break:
|
||||||
|
return parse_break_statement();
|
||||||
|
case TokenType::Switch:
|
||||||
|
return parse_switch_statement();
|
||||||
default:
|
default:
|
||||||
if (match_expression())
|
if (match_expression())
|
||||||
return adopt(*new ExpressionStatement(parse_expression(0)));
|
return adopt(*new ExpressionStatement(parse_expression(0)));
|
||||||
|
@ -559,6 +563,13 @@ NonnullRefPtr<ThrowStatement> Parser::parse_throw_statement()
|
||||||
return create_ast_node<ThrowStatement>(parse_expression(0));
|
return create_ast_node<ThrowStatement>(parse_expression(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<BreakStatement> Parser::parse_break_statement()
|
||||||
|
{
|
||||||
|
consume(TokenType::Break);
|
||||||
|
// FIXME: Handle labels.
|
||||||
|
return create_ast_node<BreakStatement>();
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<TryStatement> Parser::parse_try_statement()
|
NonnullRefPtr<TryStatement> Parser::parse_try_statement()
|
||||||
{
|
{
|
||||||
consume(TokenType::Try);
|
consume(TokenType::Try);
|
||||||
|
@ -578,6 +589,43 @@ NonnullRefPtr<TryStatement> Parser::parse_try_statement()
|
||||||
return create_ast_node<TryStatement>(move(block), move(handler), move(finalizer));
|
return create_ast_node<TryStatement>(move(block), move(handler), move(finalizer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<SwitchStatement> Parser::parse_switch_statement()
|
||||||
|
{
|
||||||
|
consume(TokenType::Switch);
|
||||||
|
|
||||||
|
consume(TokenType::ParenOpen);
|
||||||
|
auto determinant = parse_expression(0);
|
||||||
|
consume(TokenType::ParenClose);
|
||||||
|
|
||||||
|
consume(TokenType::CurlyOpen);
|
||||||
|
|
||||||
|
NonnullRefPtrVector<SwitchCase> cases;
|
||||||
|
|
||||||
|
while (match(TokenType::Case) || match(TokenType::Default))
|
||||||
|
cases.append(parse_switch_case());
|
||||||
|
|
||||||
|
consume(TokenType::CurlyClose);
|
||||||
|
|
||||||
|
return create_ast_node<SwitchStatement>(move(determinant), move(cases));
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<SwitchCase> Parser::parse_switch_case()
|
||||||
|
{
|
||||||
|
RefPtr<Expression> test;
|
||||||
|
|
||||||
|
if (consume().type() == TokenType::Case) {
|
||||||
|
test = parse_expression(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
consume(TokenType::Colon);
|
||||||
|
|
||||||
|
NonnullRefPtrVector<Statement> consequent;
|
||||||
|
while (match_statement())
|
||||||
|
consequent.append(parse_statement());
|
||||||
|
|
||||||
|
return create_ast_node<SwitchCase>(move(test), move(consequent));
|
||||||
|
}
|
||||||
|
|
||||||
NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
|
NonnullRefPtr<CatchClause> Parser::parse_catch_clause()
|
||||||
{
|
{
|
||||||
consume(TokenType::Catch);
|
consume(TokenType::Catch);
|
||||||
|
@ -746,6 +794,8 @@ bool Parser::match_statement() const
|
||||||
|| type == TokenType::For
|
|| type == TokenType::For
|
||||||
|| type == TokenType::Const
|
|| type == TokenType::Const
|
||||||
|| type == TokenType::CurlyOpen
|
|| type == TokenType::CurlyOpen
|
||||||
|
|| type == TokenType::Switch
|
||||||
|
|| type == TokenType::Break
|
||||||
|| type == TokenType::Var;
|
|| type == TokenType::Var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,6 +55,9 @@ public:
|
||||||
NonnullRefPtr<ThrowStatement> parse_throw_statement();
|
NonnullRefPtr<ThrowStatement> parse_throw_statement();
|
||||||
NonnullRefPtr<TryStatement> parse_try_statement();
|
NonnullRefPtr<TryStatement> parse_try_statement();
|
||||||
NonnullRefPtr<CatchClause> parse_catch_clause();
|
NonnullRefPtr<CatchClause> parse_catch_clause();
|
||||||
|
NonnullRefPtr<SwitchStatement> parse_switch_statement();
|
||||||
|
NonnullRefPtr<SwitchCase> parse_switch_case();
|
||||||
|
NonnullRefPtr<BreakStatement> parse_break_statement();
|
||||||
|
|
||||||
NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right);
|
NonnullRefPtr<Expression> parse_expression(int min_precedence, Associativity associate = Associativity::Right);
|
||||||
NonnullRefPtr<Expression> parse_primary_expression();
|
NonnullRefPtr<Expression> parse_primary_expression();
|
||||||
|
|
|
@ -51,8 +51,12 @@ const char* Token::name(TokenType type)
|
||||||
return "BracketOpen";
|
return "BracketOpen";
|
||||||
case TokenType::BracketClose:
|
case TokenType::BracketClose:
|
||||||
return "BracketClose";
|
return "BracketClose";
|
||||||
|
case TokenType::Break:
|
||||||
|
return "Break";
|
||||||
case TokenType::Caret:
|
case TokenType::Caret:
|
||||||
return "Caret";
|
return "Caret";
|
||||||
|
case TokenType::Case:
|
||||||
|
return "Case";
|
||||||
case TokenType::Catch:
|
case TokenType::Catch:
|
||||||
return "Catch";
|
return "Catch";
|
||||||
case TokenType::Class:
|
case TokenType::Class:
|
||||||
|
@ -67,6 +71,8 @@ const char* Token::name(TokenType type)
|
||||||
return "CurlyClose";
|
return "CurlyClose";
|
||||||
case TokenType::CurlyOpen:
|
case TokenType::CurlyOpen:
|
||||||
return "CurlyOpen";
|
return "CurlyOpen";
|
||||||
|
case TokenType::Default:
|
||||||
|
return "Default";
|
||||||
case TokenType::Delete:
|
case TokenType::Delete:
|
||||||
return "Delete";
|
return "Delete";
|
||||||
case TokenType::Do:
|
case TokenType::Do:
|
||||||
|
@ -179,6 +185,8 @@ const char* Token::name(TokenType type)
|
||||||
return "SlashEquals";
|
return "SlashEquals";
|
||||||
case TokenType::StringLiteral:
|
case TokenType::StringLiteral:
|
||||||
return "StringLiteral";
|
return "StringLiteral";
|
||||||
|
case TokenType::Switch:
|
||||||
|
return "Switch";
|
||||||
case TokenType::Tilde:
|
case TokenType::Tilde:
|
||||||
return "Tilde";
|
return "Tilde";
|
||||||
case TokenType::Try:
|
case TokenType::Try:
|
||||||
|
|
|
@ -41,7 +41,9 @@ enum class TokenType {
|
||||||
BoolLiteral,
|
BoolLiteral,
|
||||||
BracketClose,
|
BracketClose,
|
||||||
BracketOpen,
|
BracketOpen,
|
||||||
|
Break,
|
||||||
Caret,
|
Caret,
|
||||||
|
Case,
|
||||||
Catch,
|
Catch,
|
||||||
Class,
|
Class,
|
||||||
Colon,
|
Colon,
|
||||||
|
@ -49,6 +51,7 @@ enum class TokenType {
|
||||||
Const,
|
Const,
|
||||||
CurlyClose,
|
CurlyClose,
|
||||||
CurlyOpen,
|
CurlyOpen,
|
||||||
|
Default,
|
||||||
Delete,
|
Delete,
|
||||||
Do,
|
Do,
|
||||||
DoubleAmpersand,
|
DoubleAmpersand,
|
||||||
|
@ -105,6 +108,7 @@ enum class TokenType {
|
||||||
Slash,
|
Slash,
|
||||||
SlashEquals,
|
SlashEquals,
|
||||||
StringLiteral,
|
StringLiteral,
|
||||||
|
Switch,
|
||||||
Throw,
|
Throw,
|
||||||
Tilde,
|
Tilde,
|
||||||
Try,
|
Try,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue