From f8f65053bdbc086e132db5cb620fc4b0789a13b1 Mon Sep 17 00:00:00 2001 From: Stephan Unverwerth Date: Mon, 13 Apr 2020 00:42:14 +0200 Subject: [PATCH] LibJS: Parse "this" as ThisExpression --- Libraries/LibJS/AST.cpp | 10 ++++++++++ Libraries/LibJS/AST.h | 9 +++++++++ Libraries/LibJS/Interpreter.cpp | 4 ---- Libraries/LibJS/Lexer.cpp | 1 + Libraries/LibJS/Parser.cpp | 29 ++++++++++++++++------------- Libraries/LibJS/Token.h | 1 + 6 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 427594753ed..15974de8b95 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -662,6 +662,16 @@ void Identifier::dump(int indent) const printf("Identifier \"%s\"\n", m_string.characters()); } +Value ThisExpression::execute(Interpreter& interpreter) const +{ + return interpreter.this_value(); +} + +void ThisExpression::dump(int indent) const +{ + ASTNode::dump(indent); +} + Value AssignmentExpression::execute(Interpreter& interpreter) const { auto rhs_result = m_rhs->execute(interpreter); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index fe4d806e14a..01e15a6832b 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -502,6 +502,15 @@ private: FlyString m_string; }; +class ThisExpression final : public Expression { +public: + virtual Value execute(Interpreter&) const override; + virtual void dump(int indent) const override; + +private: + virtual const char* class_name() const override { return "ThisExpression"; } +}; + class CallExpression : public Expression { public: CallExpression(NonnullRefPtr callee, NonnullRefPtrVector arguments = {}) diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index bd2d4eaa48f..c3b74cff9c0 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -158,10 +158,6 @@ void Interpreter::set_variable(const FlyString& name, Value value, bool first_as Optional Interpreter::get_variable(const FlyString& name) { - static FlyString this_name = "this"; - if (name == this_name) - return this_value(); - for (ssize_t i = m_scope_stack.size() - 1; i >= 0; --i) { auto& scope = m_scope_stack.at(i); auto value = scope.variables.get(name); diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 75ec759f3f9..fc16cb239e8 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -66,6 +66,7 @@ Lexer::Lexer(StringView source) s_keywords.set("null", TokenType::NullLiteral); s_keywords.set("return", TokenType::Return); s_keywords.set("switch", TokenType::Switch); + s_keywords.set("this", TokenType::This); s_keywords.set("throw", TokenType::Throw); s_keywords.set("true", TokenType::BoolLiteral); s_keywords.set("try", TokenType::Try); diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index eb0b679fb37..57538ab644f 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -317,6 +317,9 @@ NonnullRefPtr Parser::parse_primary_expression() consume(TokenType::ParenClose); return expression; } + case TokenType::This: + consume(); + return create_ast_node(); case TokenType::Identifier: { auto arrow_function_result = try_parse_arrow_function_expression(false); if (!arrow_function_result.is_null()) { @@ -400,14 +403,13 @@ NonnullRefPtr Parser::parse_object_expression() m_parser_state.m_has_errors = true; auto& current_token = m_parser_state.m_current_token; fprintf(stderr, "Error: Unexpected token %s as member in object initialization. Expected a numeric literal, string literal or identifier (line: %zu, column: %zu))\n", - current_token.name(), - current_token.line_number(), - current_token.line_column()); + current_token.name(), + current_token.line_number(), + current_token.line_column()); consume(); continue; } - if (match(TokenType::Colon)) { consume(TokenType::Colon); properties.set(property_name, parse_expression(0)); @@ -487,7 +489,7 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr(BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity)); - case TokenType::DoubleAsterisk: + case TokenType::DoubleAsterisk: consume(); return create_ast_node(BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::GreaterThan: @@ -905,6 +907,7 @@ bool Parser::match_expression() const || type == TokenType::BracketOpen || type == TokenType::ParenOpen || type == TokenType::Function + || type == TokenType::This || match_unary_prefixed_expression(); } @@ -997,10 +1000,10 @@ Token Parser::consume(TokenType type) m_parser_state.m_has_errors = true; auto& current_token = m_parser_state.m_current_token; fprintf(stderr, "Error: Unexpected token %s. Expected %s (line: %zu, column: %zu))\n", - current_token.name(), - Token::name(type), - current_token.line_number(), - current_token.line_column()); + current_token.name(), + Token::name(type), + current_token.line_number(), + current_token.line_column()); } return consume(); } @@ -1010,10 +1013,10 @@ void Parser::expected(const char* what) m_parser_state.m_has_errors = true; auto& current_token = m_parser_state.m_current_token; fprintf(stderr, "Error: Unexpected token %s. Expected %s (line: %zu, column: %zu)\n", - current_token.name(), - what, - current_token.line_number(), - current_token.line_column()); + current_token.name(), + what, + current_token.line_number(), + current_token.line_column()); } void Parser::save_state() diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index ac442136ad0..36c6d210c35 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -111,6 +111,7 @@ namespace JS { __ENUMERATE_JS_TOKEN(SlashEquals) \ __ENUMERATE_JS_TOKEN(StringLiteral) \ __ENUMERATE_JS_TOKEN(Switch) \ + __ENUMERATE_JS_TOKEN(This) \ __ENUMERATE_JS_TOKEN(Throw) \ __ENUMERATE_JS_TOKEN(Tilde) \ __ENUMERATE_JS_TOKEN(Try) \