diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 563a278f848..cf45f31dd5b 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -88,26 +88,41 @@ static String get_function_name(GlobalObject& global_object, Value value) Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return interpreter.execute_statement(global_object, *this); } Value Program::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return interpreter.execute_statement(global_object, *this, ScopeType::Block); } -Value FunctionDeclaration::execute(Interpreter&, GlobalObject&) const +Value FunctionDeclaration::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return js_undefined(); } Value FunctionExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return ScriptFunction::create(global_object, name(), body(), parameters(), function_length(), interpreter.current_scope(), is_strict_mode() || interpreter.vm().in_strict_mode(), m_is_arrow_function); } Value ExpressionStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return m_expression->execute(interpreter, global_object); } @@ -152,6 +167,9 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto& vm = interpreter.vm(); auto [this_value, callee] = compute_this_and_callee(interpreter, global_object); if (vm.exception()) @@ -235,6 +253,9 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj Value ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto value = argument() ? argument()->execute(interpreter, global_object) : js_undefined(); if (interpreter.exception()) return {}; @@ -244,6 +265,9 @@ Value ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_ob Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto predicate_result = m_predicate->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -259,6 +283,9 @@ Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object Value WithStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto object_value = m_object->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -277,6 +304,9 @@ Value WithStatement::execute(Interpreter& interpreter, GlobalObject& global_obje Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + Value last_value = js_undefined(); for (;;) { auto test_result = m_test->execute(interpreter, global_object); @@ -304,6 +334,9 @@ Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_obj Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + Value last_value = js_undefined(); for (;;) { if (interpreter.exception()) @@ -333,10 +366,13 @@ Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_o Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + RefPtr wrapper; if (m_init && m_init->is_variable_declaration() && static_cast(m_init.ptr())->declaration_kind() != DeclarationKind::Var) { - wrapper = create_ast_node(); + wrapper = create_ast_node(source_range()); NonnullRefPtrVector decls; decls.append(*static_cast(m_init.ptr())); wrapper->add_variables(decls); @@ -415,7 +451,7 @@ static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalO auto* variable_declaration = static_cast(node.ptr()); ASSERT(!variable_declaration->declarations().is_empty()); if (variable_declaration->declaration_kind() != DeclarationKind::Var) { - wrapper = create_ast_node(); + wrapper = create_ast_node(node->source_range()); interpreter.enter_scope(*wrapper, ScopeType::Block, global_object); } variable_declaration->execute(interpreter, global_object); @@ -430,6 +466,9 @@ static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalO Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + if (!m_lhs->is_variable_declaration() && !m_lhs->is_identifier()) { // FIXME: Implement "for (foo.bar in baz)", "for (foo[0] in bar)" ASSERT_NOT_REACHED(); @@ -474,6 +513,9 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + if (!m_lhs->is_variable_declaration() && !m_lhs->is_identifier()) { // FIXME: Implement "for (foo.bar of baz)", "for (foo[0] of bar)" ASSERT_NOT_REACHED(); @@ -515,6 +557,9 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj Value BinaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto lhs_result = m_lhs->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -574,6 +619,9 @@ Value BinaryExpression::execute(Interpreter& interpreter, GlobalObject& global_o Value LogicalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto lhs_result = m_lhs->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -631,6 +679,9 @@ Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto& vm = interpreter.vm(); if (m_op == UnaryOp::Delete) { auto reference = m_lhs->to_reference(interpreter, global_object); @@ -713,19 +764,28 @@ Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_ob ASSERT_NOT_REACHED(); } -Value SuperExpression::execute(Interpreter&, GlobalObject&) const +Value SuperExpression::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // The semantics for SuperExpressions are handled in CallExpression::compute_this_and_callee() ASSERT_NOT_REACHED(); } Value ClassMethod::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return m_function->execute(interpreter, global_object); } Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto& vm = interpreter.vm(); Value class_constructor_value = m_constructor->execute(interpreter, global_object); if (interpreter.exception()) @@ -812,6 +872,9 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob Value ClassDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + Value class_constructor = m_class_expression->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -1224,6 +1287,9 @@ void ForOfStatement::dump(int indent) const Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto value = interpreter.vm().get_variable(string(), global_object); if (value.is_empty()) { interpreter.vm().throw_exception(global_object, ErrorType::UnknownIdentifier, string()); @@ -1246,11 +1312,17 @@ void SpreadExpression::dump(int indent) const Value SpreadExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return m_target->execute(interpreter, global_object); } Value ThisExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return interpreter.vm().resolve_this_binding(global_object); } @@ -1261,6 +1333,9 @@ void ThisExpression::dump(int indent) const Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + #define EXECUTE_LHS_AND_RHS() \ do { \ lhs_result = m_lhs->execute(interpreter, global_object); \ @@ -1376,6 +1451,9 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob Value UpdateExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto reference = m_argument->to_reference(interpreter, global_object); if (interpreter.exception()) return {}; @@ -1497,6 +1575,9 @@ void UpdateExpression::dump(int indent) const Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + for (auto& declarator : m_declarations) { if (auto* init = declarator.init()) { auto initalizer_result = init->execute(interpreter, global_object); @@ -1510,8 +1591,11 @@ Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& globa return js_undefined(); } -Value VariableDeclarator::execute(Interpreter&, GlobalObject&) const +Value VariableDeclarator::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // NOTE: VariableDeclarator execution is handled by VariableDeclaration. ASSERT_NOT_REACHED(); } @@ -1568,14 +1652,20 @@ void ExpressionStatement::dump(int indent) const m_expression->dump(indent + 1); } -Value ObjectProperty::execute(Interpreter&, GlobalObject&) const +Value ObjectProperty::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // NOTE: ObjectProperty execution is handled by ObjectExpression. ASSERT_NOT_REACHED(); } Value ObjectExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto* object = Object::create_empty(global_object); for (auto& property : m_properties) { auto key = property.key().execute(interpreter, global_object); @@ -1677,6 +1767,9 @@ String MemberExpression::to_string_approximation() const Value MemberExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto object_value = m_object->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -1704,6 +1797,9 @@ void MetaProperty::dump(int indent) const Value MetaProperty::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + if (m_type == MetaProperty::Type::NewTarget) return interpreter.vm().get_new_target().value_or(js_undefined()); if (m_type == MetaProperty::Type::ImportMeta) @@ -1713,26 +1809,41 @@ Value MetaProperty::execute(Interpreter& interpreter, GlobalObject&) const Value StringLiteral::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return js_string(interpreter.heap(), m_value); } -Value NumericLiteral::execute(Interpreter&, GlobalObject&) const +Value NumericLiteral::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return Value(m_value); } Value BigIntLiteral::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return js_bigint(interpreter.heap(), Crypto::SignedBigInteger::from_base10(m_value.substring(0, m_value.length() - 1))); } -Value BooleanLiteral::execute(Interpreter&, GlobalObject&) const +Value BooleanLiteral::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return Value(m_value); } -Value NullLiteral::execute(Interpreter&, GlobalObject&) const +Value NullLiteral::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return js_null(); } @@ -1742,8 +1853,11 @@ void RegExpLiteral::dump(int indent) const outln("{} (/{}/{})", class_name(), content(), flags()); } -Value RegExpLiteral::execute(Interpreter&, GlobalObject& global_object) const +Value RegExpLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + return RegExpObject::create(global_object, content(), flags()); } @@ -1762,6 +1876,9 @@ void ArrayExpression::dump(int indent) const Value ArrayExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto* array = Array::create(global_object); for (auto& element : m_elements) { auto value = Value(); @@ -1794,6 +1911,9 @@ void TemplateLiteral::dump(int indent) const Value TemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + StringBuilder string_builder; for (auto& expression : m_expressions) { @@ -1822,6 +1942,9 @@ void TaggedTemplateLiteral::dump(int indent) const Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto& vm = interpreter.vm(); auto tag = m_tag->execute(interpreter, global_object); if (vm.exception()) @@ -1897,6 +2020,9 @@ void ThrowStatement::dump(int indent) const Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + interpreter.execute_statement(global_object, m_block, ScopeType::Try); if (auto* exception = interpreter.exception()) { if (m_handler) { @@ -1928,8 +2054,11 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec return js_undefined(); } -Value CatchClause::execute(Interpreter&, GlobalObject&) const +Value CatchClause::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // NOTE: CatchClause execution is handled by TryStatement. ASSERT_NOT_REACHED(); return {}; @@ -1937,6 +2066,9 @@ Value CatchClause::execute(Interpreter&, GlobalObject&) const Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto value = m_argument->execute(interpreter, global_object); if (interpreter.vm().exception()) return {}; @@ -1946,6 +2078,9 @@ Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_obj Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto discriminant_result = m_discriminant->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -1983,8 +2118,11 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob return js_undefined(); } -Value SwitchCase::execute(Interpreter&, GlobalObject&) const +Value SwitchCase::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // NOTE: SwitchCase execution is handled by SwitchStatement. ASSERT_NOT_REACHED(); return {}; @@ -1992,12 +2130,18 @@ Value SwitchCase::execute(Interpreter&, GlobalObject&) const Value BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + interpreter.vm().unwind(ScopeType::Breakable, m_target_label); return js_undefined(); } Value ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + interpreter.vm().unwind(ScopeType::Continuable, m_target_label); return js_undefined(); } @@ -2029,6 +2173,9 @@ void SwitchCase::dump(int indent) const Value ConditionalExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + auto test_result = m_test->execute(interpreter, global_object); if (interpreter.exception()) return {}; @@ -2066,6 +2213,9 @@ void SequenceExpression::dump(int indent) const Value SequenceExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + Value last_value; for (auto& expression : m_expressions) { last_value = expression.execute(interpreter, global_object); @@ -2075,8 +2225,11 @@ Value SequenceExpression::execute(Interpreter& interpreter, GlobalObject& global return last_value; } -Value DebuggerStatement::execute(Interpreter&, GlobalObject&) const +Value DebuggerStatement::execute(Interpreter& interpreter, GlobalObject&) const { + interpreter.enter_node(*this); + ScopeGuard exit_node { [&] { interpreter.exit_node(*this); } }; + // Sorry, no JavaScript debugger available (yet)! return js_undefined(); } diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 51360fb4b88..4924f79ac90 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -36,6 +36,7 @@ #include #include #include +#include namespace JS { @@ -44,9 +45,9 @@ class FunctionDeclaration; template static inline NonnullRefPtr -create_ast_node(Args&&... args) +create_ast_node(SourceRange range, Args&&... args) { - return adopt(*new T(forward(args)...)); + return adopt(*new T(range, forward(args)...)); } class ASTNode : public RefCounted { @@ -67,14 +68,26 @@ public: virtual bool is_expression_statement() const { return false; }; virtual bool is_string_literal() const { return false; }; + const SourceRange& source_range() const { return m_source_range; } + SourceRange& source_range() { return m_source_range; } + protected: - ASTNode() { } + ASTNode(SourceRange source_range) + : m_source_range(move(source_range)) + { + } private: + SourceRange m_source_range; }; class Statement : public ASTNode { public: + Statement(SourceRange source_range) + : ASTNode(move(source_range)) + { + } + const FlyString& label() const { return m_label; } void set_label(FlyString string) { m_label = string; } @@ -84,20 +97,29 @@ protected: class EmptyStatement final : public Statement { public: + EmptyStatement(SourceRange source_range) + : Statement(move(source_range)) + { + } Value execute(Interpreter&, GlobalObject&) const override { return js_undefined(); } const char* class_name() const override { return "EmptyStatement"; } }; class ErrorStatement final : public Statement { public: + ErrorStatement(SourceRange source_range) + : Statement(move(source_range)) + { + } Value execute(Interpreter&, GlobalObject&) const override { return js_undefined(); } const char* class_name() const override { return "ErrorStatement"; } }; class ExpressionStatement final : public Statement { public: - ExpressionStatement(NonnullRefPtr expression) - : m_expression(move(expression)) + ExpressionStatement(SourceRange source_range, NonnullRefPtr expression) + : Statement(move(source_range)) + , m_expression(move(expression)) { } @@ -116,9 +138,9 @@ private: class ScopeNode : public Statement { public: template - T& append(Args&&... args) + T& append(SourceRange range, Args&&... args) { - auto child = create_ast_node(forward(args)...); + auto child = create_ast_node(range, forward(args)...); m_children.append(move(child)); return static_cast(m_children.last()); } @@ -137,7 +159,10 @@ public: const NonnullRefPtrVector& functions() const { return m_functions; } protected: - ScopeNode() { } + ScopeNode(SourceRange source_range) + : Statement(move(source_range)) + { + } private: virtual bool is_scope_node() const final { return true; } @@ -148,7 +173,10 @@ private: class Program final : public ScopeNode { public: - Program() { } + Program(SourceRange source_range) + : ScopeNode(move(source_range)) + { + } virtual Value execute(Interpreter&, GlobalObject&) const override; @@ -164,7 +192,10 @@ private: class BlockStatement final : public ScopeNode { public: - BlockStatement() { } + BlockStatement(SourceRange source_range) + : ScopeNode(move(source_range)) + { + } private: virtual const char* class_name() const override { return "BlockStatement"; } @@ -172,14 +203,27 @@ private: class Expression : public ASTNode { public: + Expression(SourceRange source_range) + : ASTNode(move(source_range)) + { + } virtual Reference to_reference(Interpreter&, GlobalObject&) const; }; class Declaration : public Statement { +public: + Declaration(SourceRange source_range) + : Statement(move(source_range)) + { + } }; class ErrorDeclaration final : public Declaration { public: + ErrorDeclaration(SourceRange source_range) + : Declaration(move(source_range)) + { + } Value execute(Interpreter&, GlobalObject&) const override { return js_undefined(); } const char* class_name() const override { return "ErrorDeclaration"; } }; @@ -228,8 +272,9 @@ class FunctionDeclaration final public: static bool must_have_name() { return true; } - FunctionDeclaration(const FlyString& name, NonnullRefPtr body, Vector parameters, i32 function_length, NonnullRefPtrVector variables, bool is_strict_mode = false) - : FunctionNode(name, move(body), move(parameters), function_length, move(variables), is_strict_mode) + FunctionDeclaration(SourceRange source_range, const FlyString& name, NonnullRefPtr body, Vector parameters, i32 function_length, NonnullRefPtrVector variables, bool is_strict_mode = false) + : Declaration(move(source_range)) + , FunctionNode(name, move(body), move(parameters), function_length, move(variables), is_strict_mode) { } @@ -246,8 +291,9 @@ class FunctionExpression final public: static bool must_have_name() { return false; } - FunctionExpression(const FlyString& name, NonnullRefPtr body, Vector parameters, i32 function_length, NonnullRefPtrVector variables, bool is_strict_mode, bool is_arrow_function = false) - : FunctionNode(name, move(body), move(parameters), function_length, move(variables), is_strict_mode) + FunctionExpression(SourceRange source_range, const FlyString& name, NonnullRefPtr body, Vector parameters, i32 function_length, NonnullRefPtrVector variables, bool is_strict_mode, bool is_arrow_function = false) + : Expression(move(source_range)) + , FunctionNode(name, move(body), move(parameters), function_length, move(variables), is_strict_mode) , m_is_arrow_function(is_arrow_function) { } @@ -263,14 +309,20 @@ private: class ErrorExpression final : public Expression { public: + explicit ErrorExpression(SourceRange source_range) + : Expression(move(source_range)) + { + } + Value execute(Interpreter&, GlobalObject&) const override { return js_undefined(); } const char* class_name() const override { return "ErrorExpression"; } }; class ReturnStatement final : public Statement { public: - explicit ReturnStatement(RefPtr argument) - : m_argument(move(argument)) + explicit ReturnStatement(SourceRange source_range, RefPtr argument) + : Statement(move(source_range)) + , m_argument(move(argument)) { } @@ -287,8 +339,9 @@ private: class IfStatement final : public Statement { public: - IfStatement(NonnullRefPtr predicate, NonnullRefPtr consequent, RefPtr alternate) - : m_predicate(move(predicate)) + IfStatement(SourceRange source_range, NonnullRefPtr predicate, NonnullRefPtr consequent, RefPtr alternate) + : Statement(move(source_range)) + , m_predicate(move(predicate)) , m_consequent(move(consequent)) , m_alternate(move(alternate)) { @@ -311,8 +364,9 @@ private: class WhileStatement final : public Statement { public: - WhileStatement(NonnullRefPtr test, NonnullRefPtr body) - : m_test(move(test)) + WhileStatement(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr body) + : Statement(move(source_range)) + , m_test(move(test)) , m_body(move(body)) { } @@ -332,8 +386,9 @@ private: class DoWhileStatement final : public Statement { public: - DoWhileStatement(NonnullRefPtr test, NonnullRefPtr body) - : m_test(move(test)) + DoWhileStatement(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr body) + : Statement(move(source_range)) + , m_test(move(test)) , m_body(move(body)) { } @@ -353,8 +408,9 @@ private: class WithStatement final : public Statement { public: - WithStatement(NonnullRefPtr object, NonnullRefPtr body) - : m_object(move(object)) + WithStatement(SourceRange source_range, NonnullRefPtr object, NonnullRefPtr body) + : Statement(move(source_range)) + , m_object(move(object)) , m_body(move(body)) { } @@ -374,8 +430,9 @@ private: class ForStatement final : public Statement { public: - ForStatement(RefPtr init, RefPtr test, RefPtr update, NonnullRefPtr body) - : m_init(move(init)) + ForStatement(SourceRange source_range, RefPtr init, RefPtr test, RefPtr update, NonnullRefPtr body) + : Statement(move(source_range)) + , m_init(move(init)) , m_test(move(test)) , m_update(move(update)) , m_body(move(body)) @@ -401,8 +458,9 @@ private: class ForInStatement final : public Statement { public: - ForInStatement(NonnullRefPtr lhs, NonnullRefPtr rhs, NonnullRefPtr body) - : m_lhs(move(lhs)) + ForInStatement(SourceRange source_range, NonnullRefPtr lhs, NonnullRefPtr rhs, NonnullRefPtr body) + : Statement(move(source_range)) + , m_lhs(move(lhs)) , m_rhs(move(rhs)) , m_body(move(body)) { @@ -425,8 +483,9 @@ private: class ForOfStatement final : public Statement { public: - ForOfStatement(NonnullRefPtr lhs, NonnullRefPtr rhs, NonnullRefPtr body) - : m_lhs(move(lhs)) + ForOfStatement(SourceRange source_range, NonnullRefPtr lhs, NonnullRefPtr rhs, NonnullRefPtr body) + : Statement(move(source_range)) + , m_lhs(move(lhs)) , m_rhs(move(rhs)) , m_body(move(body)) { @@ -474,8 +533,9 @@ enum class BinaryOp { class BinaryExpression final : public Expression { public: - BinaryExpression(BinaryOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : m_op(op) + BinaryExpression(SourceRange source_range, BinaryOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) + : Expression(move(source_range)) + , m_op(op) , m_lhs(move(lhs)) , m_rhs(move(rhs)) { @@ -500,8 +560,9 @@ enum class LogicalOp { class LogicalExpression final : public Expression { public: - LogicalExpression(LogicalOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : m_op(op) + LogicalExpression(SourceRange source_range, LogicalOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) + : Expression(move(source_range)) + , m_op(op) , m_lhs(move(lhs)) , m_rhs(move(rhs)) { @@ -530,8 +591,9 @@ enum class UnaryOp { class UnaryExpression final : public Expression { public: - UnaryExpression(UnaryOp op, NonnullRefPtr lhs) - : m_op(op) + UnaryExpression(SourceRange source_range, UnaryOp op, NonnullRefPtr lhs) + : Expression(move(source_range)) + , m_op(op) , m_lhs(move(lhs)) { } @@ -548,8 +610,9 @@ private: class SequenceExpression final : public Expression { public: - SequenceExpression(NonnullRefPtrVector expressions) - : m_expressions(move(expressions)) + SequenceExpression(SourceRange source_range, NonnullRefPtrVector expressions) + : Expression(move(source_range)) + , m_expressions(move(expressions)) { } @@ -564,13 +627,17 @@ private: class Literal : public Expression { protected: - explicit Literal() { } + explicit Literal(SourceRange source_range) + : Expression(move(source_range)) + { + } }; class BooleanLiteral final : public Literal { public: - explicit BooleanLiteral(bool value) - : m_value(value) + explicit BooleanLiteral(SourceRange source_range, bool value) + : Literal(move(source_range)) + , m_value(value) { } @@ -585,8 +652,9 @@ private: class NumericLiteral final : public Literal { public: - explicit NumericLiteral(double value) - : m_value(value) + explicit NumericLiteral(SourceRange source_range, double value) + : Literal(move(source_range)) + , m_value(value) { } @@ -601,8 +669,9 @@ private: class BigIntLiteral final : public Literal { public: - explicit BigIntLiteral(String value) - : m_value(move(value)) + explicit BigIntLiteral(SourceRange source_range, String value) + : Literal(move(source_range)) + , m_value(move(value)) { } @@ -617,8 +686,9 @@ private: class StringLiteral final : public Literal { public: - explicit StringLiteral(String value, bool is_use_strict_directive = false) - : m_value(move(value)) + explicit StringLiteral(SourceRange source_range, String value, bool is_use_strict_directive = false) + : Literal(move(source_range)) + , m_value(move(value)) , m_is_use_strict_directive(is_use_strict_directive) { } @@ -639,7 +709,10 @@ private: class NullLiteral final : public Literal { public: - explicit NullLiteral() { } + explicit NullLiteral(SourceRange source_range) + : Literal(move(source_range)) + { + } virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; @@ -650,8 +723,9 @@ private: class RegExpLiteral final : public Literal { public: - explicit RegExpLiteral(String content, String flags) - : m_content(content) + explicit RegExpLiteral(SourceRange source_range, String content, String flags) + : Literal(move(source_range)) + , m_content(content) , m_flags(flags) { } @@ -671,8 +745,9 @@ private: class Identifier final : public Expression { public: - explicit Identifier(const FlyString& string) - : m_string(string) + explicit Identifier(SourceRange source_range, const FlyString& string) + : Expression(move(source_range)) + , m_string(string) { } @@ -697,8 +772,9 @@ public: Setter, }; - ClassMethod(NonnullRefPtr key, NonnullRefPtr function, Kind kind, bool is_static) - : m_key(move(key)) + ClassMethod(SourceRange source_range, NonnullRefPtr key, NonnullRefPtr function, Kind kind, bool is_static) + : ASTNode(move(source_range)) + , m_key(move(key)) , m_function(move(function)) , m_kind(kind) , m_is_static(is_static) @@ -723,6 +799,11 @@ private: class SuperExpression final : public Expression { public: + SuperExpression(SourceRange source_range) + : Expression(move(source_range)) + { + } + virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; @@ -733,8 +814,9 @@ private: class ClassExpression final : public Expression { public: - ClassExpression(String name, RefPtr constructor, RefPtr super_class, NonnullRefPtrVector methods) - : m_name(move(name)) + ClassExpression(SourceRange source_range, String name, RefPtr constructor, RefPtr super_class, NonnullRefPtrVector methods) + : Expression(move(source_range)) + , m_name(move(name)) , m_constructor(move(constructor)) , m_super_class(move(super_class)) , m_methods(move(methods)) @@ -757,8 +839,9 @@ private: class ClassDeclaration final : public Declaration { public: - ClassDeclaration(NonnullRefPtr class_expression) - : m_class_expression(move(class_expression)) + ClassDeclaration(SourceRange source_range, NonnullRefPtr class_expression) + : Declaration(move(source_range)) + , m_class_expression(move(class_expression)) { } @@ -772,8 +855,9 @@ private: class SpreadExpression final : public Expression { public: - explicit SpreadExpression(NonnullRefPtr target) - : m_target(target) + explicit SpreadExpression(SourceRange source_range, NonnullRefPtr target) + : Expression(move(source_range)) + , m_target(target) { } @@ -789,6 +873,10 @@ private: class ThisExpression final : public Expression { public: + ThisExpression(SourceRange source_range) + : Expression(move(source_range)) + { + } virtual Value execute(Interpreter&, GlobalObject&) const override; virtual void dump(int indent) const override; @@ -803,8 +891,9 @@ public: bool is_spread; }; - CallExpression(NonnullRefPtr callee, Vector arguments = {}) - : m_callee(move(callee)) + CallExpression(SourceRange source_range, NonnullRefPtr callee, Vector arguments = {}) + : Expression(move(source_range)) + , m_callee(move(callee)) , m_arguments(move(arguments)) { } @@ -828,8 +917,8 @@ private: class NewExpression final : public CallExpression { public: - NewExpression(NonnullRefPtr callee, Vector arguments = {}) - : CallExpression(move(callee), move(arguments)) + NewExpression(SourceRange source_range, NonnullRefPtr callee, Vector arguments = {}) + : CallExpression(move(source_range), move(callee), move(arguments)) { } @@ -860,8 +949,9 @@ enum class AssignmentOp { class AssignmentExpression final : public Expression { public: - AssignmentExpression(AssignmentOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) - : m_op(op) + AssignmentExpression(SourceRange source_range, AssignmentOp op, NonnullRefPtr lhs, NonnullRefPtr rhs) + : Expression(move(source_range)) + , m_op(op) , m_lhs(move(lhs)) , m_rhs(move(rhs)) { @@ -885,8 +975,9 @@ enum class UpdateOp { class UpdateExpression final : public Expression { public: - UpdateExpression(UpdateOp op, NonnullRefPtr argument, bool prefixed = false) - : m_op(op) + UpdateExpression(SourceRange source_range, UpdateOp op, NonnullRefPtr argument, bool prefixed = false) + : Expression(move(source_range)) + , m_op(op) , m_argument(move(argument)) , m_prefixed(prefixed) { @@ -911,13 +1002,15 @@ enum class DeclarationKind { class VariableDeclarator final : public ASTNode { public: - VariableDeclarator(NonnullRefPtr id) - : m_id(move(id)) + VariableDeclarator(SourceRange source_range, NonnullRefPtr id) + : ASTNode(move(source_range)) + , m_id(move(id)) { } - VariableDeclarator(NonnullRefPtr id, RefPtr init) - : m_id(move(id)) + VariableDeclarator(SourceRange source_range, NonnullRefPtr id, RefPtr init) + : ASTNode(move(source_range)) + , m_id(move(id)) , m_init(move(init)) { } @@ -937,8 +1030,9 @@ private: class VariableDeclaration final : public Declaration { public: - VariableDeclaration(DeclarationKind declaration_kind, NonnullRefPtrVector declarations) - : m_declaration_kind(declaration_kind) + VariableDeclaration(SourceRange source_range, DeclarationKind declaration_kind, NonnullRefPtrVector declarations) + : Declaration(move(source_range)) + , m_declaration_kind(declaration_kind) , m_declarations(move(declarations)) { } @@ -967,8 +1061,9 @@ public: Spread, }; - ObjectProperty(NonnullRefPtr key, RefPtr value, Type property_type, bool is_method) - : m_key(move(key)) + ObjectProperty(SourceRange source_range, NonnullRefPtr key, RefPtr value, Type property_type, bool is_method) + : ASTNode(move(source_range)) + , m_key(move(key)) , m_value(move(value)) , m_property_type(property_type) , m_is_method(is_method) @@ -999,8 +1094,9 @@ private: class ObjectExpression final : public Expression { public: - ObjectExpression(NonnullRefPtrVector properties = {}) - : m_properties(move(properties)) + ObjectExpression(SourceRange source_range, NonnullRefPtrVector properties = {}) + : Expression(move(source_range)) + , m_properties(move(properties)) { } @@ -1015,8 +1111,9 @@ private: class ArrayExpression final : public Expression { public: - ArrayExpression(Vector> elements) - : m_elements(move(elements)) + ArrayExpression(SourceRange source_range, Vector> elements) + : Expression(move(source_range)) + , m_elements(move(elements)) { } @@ -1033,13 +1130,15 @@ private: class TemplateLiteral final : public Expression { public: - TemplateLiteral(NonnullRefPtrVector expressions) - : m_expressions(move(expressions)) + TemplateLiteral(SourceRange source_range, NonnullRefPtrVector expressions) + : Expression(move(source_range)) + , m_expressions(move(expressions)) { } - TemplateLiteral(NonnullRefPtrVector expressions, NonnullRefPtrVector raw_strings) - : m_expressions(move(expressions)) + TemplateLiteral(SourceRange source_range, NonnullRefPtrVector expressions, NonnullRefPtrVector raw_strings) + : Expression(move(source_range)) + , m_expressions(move(expressions)) , m_raw_strings(move(raw_strings)) { } @@ -1059,8 +1158,9 @@ private: class TaggedTemplateLiteral final : public Expression { public: - TaggedTemplateLiteral(NonnullRefPtr tag, NonnullRefPtr template_literal) - : m_tag(move(tag)) + TaggedTemplateLiteral(SourceRange source_range, NonnullRefPtr tag, NonnullRefPtr template_literal) + : Expression(move(source_range)) + , m_tag(move(tag)) , m_template_literal(move(template_literal)) { } @@ -1077,8 +1177,9 @@ private: class MemberExpression final : public Expression { public: - MemberExpression(NonnullRefPtr object, NonnullRefPtr property, bool computed = false) - : m_object(move(object)) + MemberExpression(SourceRange source_range, NonnullRefPtr object, NonnullRefPtr property, bool computed = false) + : Expression(move(source_range)) + , m_object(move(object)) , m_property(move(property)) , m_computed(computed) { @@ -1112,8 +1213,9 @@ public: ImportMeta, }; - MetaProperty(Type type) - : m_type(type) + MetaProperty(SourceRange source_range, Type type) + : Expression(move(source_range)) + , m_type(type) { } @@ -1128,8 +1230,9 @@ private: class ConditionalExpression final : public Expression { public: - ConditionalExpression(NonnullRefPtr test, NonnullRefPtr consequent, NonnullRefPtr alternate) - : m_test(move(test)) + ConditionalExpression(SourceRange source_range, NonnullRefPtr test, NonnullRefPtr consequent, NonnullRefPtr alternate) + : Expression(move(source_range)) + , m_test(move(test)) , m_consequent(move(consequent)) , m_alternate(move(alternate)) { @@ -1148,8 +1251,9 @@ private: class CatchClause final : public ASTNode { public: - CatchClause(const FlyString& parameter, NonnullRefPtr body) - : m_parameter(parameter) + CatchClause(SourceRange source_range, const FlyString& parameter, NonnullRefPtr body) + : ASTNode(move(source_range)) + , m_parameter(parameter) , m_body(move(body)) { } @@ -1169,8 +1273,9 @@ private: class TryStatement final : public Statement { public: - TryStatement(NonnullRefPtr block, RefPtr handler, RefPtr finalizer) - : m_block(move(block)) + TryStatement(SourceRange source_range, NonnullRefPtr block, RefPtr handler, RefPtr finalizer) + : Statement(move(source_range)) + , m_block(move(block)) , m_handler(move(handler)) , m_finalizer(move(finalizer)) { @@ -1193,8 +1298,9 @@ private: class ThrowStatement final : public Statement { public: - explicit ThrowStatement(NonnullRefPtr argument) - : m_argument(move(argument)) + explicit ThrowStatement(SourceRange source_range, NonnullRefPtr argument) + : Statement(move(source_range)) + , m_argument(move(argument)) { } @@ -1211,8 +1317,9 @@ private: class SwitchCase final : public ASTNode { public: - SwitchCase(RefPtr test, NonnullRefPtrVector consequent) - : m_test(move(test)) + SwitchCase(SourceRange source_range, RefPtr test, NonnullRefPtrVector consequent) + : ASTNode(move(source_range)) + , m_test(move(test)) , m_consequent(move(consequent)) { } @@ -1232,8 +1339,9 @@ private: class SwitchStatement final : public Statement { public: - SwitchStatement(NonnullRefPtr discriminant, NonnullRefPtrVector cases) - : m_discriminant(move(discriminant)) + SwitchStatement(SourceRange source_range, NonnullRefPtr discriminant, NonnullRefPtrVector cases) + : Statement(move(source_range)) + , m_discriminant(move(discriminant)) , m_cases(move(cases)) { } @@ -1250,8 +1358,9 @@ private: class BreakStatement final : public Statement { public: - BreakStatement(FlyString target_label) - : m_target_label(target_label) + BreakStatement(SourceRange source_range, FlyString target_label) + : Statement(move(source_range)) + , m_target_label(target_label) { } @@ -1267,8 +1376,9 @@ private: class ContinueStatement final : public Statement { public: - ContinueStatement(FlyString target_label) - : m_target_label(target_label) + ContinueStatement(SourceRange source_range, FlyString target_label) + : Statement(move(source_range)) + , m_target_label(target_label) { } @@ -1284,7 +1394,10 @@ private: class DebuggerStatement final : public Statement { public: - DebuggerStatement() { } + DebuggerStatement(SourceRange source_range) + : Statement(move(source_range)) + { + } virtual Value execute(Interpreter&, GlobalObject&) const override; diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp index b6a35610e62..c46bf484753 100644 --- a/Libraries/LibJS/Interpreter.cpp +++ b/Libraries/LibJS/Interpreter.cpp @@ -143,6 +143,16 @@ void Interpreter::exit_scope(const ScopeNode& scope_node) vm().unwind(ScopeType::None); } +void Interpreter::enter_node(const ASTNode& node) +{ + vm().push_ast_node(node); +} + +void Interpreter::exit_node(const ASTNode&) +{ + vm().pop_ast_node(); +} + void Interpreter::push_scope(ScopeFrame frame) { m_scope_stack.append(move(frame)); diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h index 9d27ac9c2ce..f32e4e1ccb7 100644 --- a/Libraries/LibJS/Interpreter.h +++ b/Libraries/LibJS/Interpreter.h @@ -77,6 +77,9 @@ public: void enter_scope(const ScopeNode&, ScopeType, GlobalObject&); void exit_scope(const ScopeNode&); + void enter_node(const ASTNode&); + void exit_node(const ASTNode&); + Value execute_statement(GlobalObject&, const Statement&, ScopeType = ScopeType::Block); private: diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index d7896d9c323..2edb9f6bf3c 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -246,8 +246,9 @@ Associativity Parser::operator_associativity(TokenType type) const NonnullRefPtr Parser::parse_program() { + auto rule_start = push_start(); ScopePusher scope(*this, ScopePusher::Var | ScopePusher::Let | ScopePusher::Function); - auto program = adopt(*new Program); + auto program = adopt(*new Program({ rule_start.position(), position() })); bool first = true; while (!done()) { @@ -277,11 +278,13 @@ NonnullRefPtr Parser::parse_program() } else { syntax_error("Unclosed scope"); } + program->source_range().end = position(); return program; } NonnullRefPtr Parser::parse_declaration() { + auto rule_start = push_start(); switch (m_parser_state.m_current_token.type()) { case TokenType::Class: return parse_class_declaration(); @@ -296,12 +299,13 @@ NonnullRefPtr Parser::parse_declaration() default: expected("declaration"); consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); } } NonnullRefPtr Parser::parse_statement() { + auto rule_start = push_start(); switch (m_parser_state.m_current_token.type()) { case TokenType::CurlyOpen: return parse_block_statement(); @@ -335,7 +339,7 @@ NonnullRefPtr Parser::parse_statement() return parse_debugger_statement(); case TokenType::Semicolon: consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); default: if (match(TokenType::Identifier)) { auto result = try_parse_labelled_statement(); @@ -347,16 +351,17 @@ NonnullRefPtr Parser::parse_statement() syntax_error("Function declaration not allowed in single-statement context"); auto expr = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node(move(expr)); + return create_ast_node({ rule_start.position(), position() }, move(expr)); } expected("statement"); consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); } } RefPtr Parser::try_parse_arrow_function_expression(bool expect_parens) { + auto rule_start = push_start(); save_state(); m_parser_state.m_var_scopes.append(NonnullRefPtrVector()); @@ -418,8 +423,8 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe // Esprima generates a single "ArrowFunctionExpression" // with a "body" property. auto return_expression = parse_expression(2); - auto return_block = create_ast_node(); - return_block->append(move(return_expression)); + auto return_block = create_ast_node({ rule_start.position(), position() }); + return_block->append({ rule_start.position(), position() }, move(return_expression)); return return_block; } // Invalid arrow function body @@ -429,7 +434,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe if (!function_body_result.is_null()) { state_rollback_guard.disarm(); auto body = function_body_result.release_nonnull(); - return create_ast_node("", move(body), move(parameters), function_length, m_parser_state.m_var_scopes.take_last(), is_strict, true); + return create_ast_node({ rule_start.position(), position() }, "", move(body), move(parameters), function_length, m_parser_state.m_var_scopes.take_last(), is_strict, true); } return nullptr; @@ -437,6 +442,7 @@ RefPtr Parser::try_parse_arrow_function_expression(bool expe RefPtr Parser::try_parse_labelled_statement() { + auto rule_start = push_start(); save_state(); ArmedScopeGuard state_rollback_guard = [&] { load_state(); @@ -460,6 +466,7 @@ RefPtr Parser::try_parse_labelled_statement() RefPtr Parser::try_parse_new_target_expression() { + auto rule_start = push_start(); save_state(); ArmedScopeGuard state_rollback_guard = [&] { load_state(); @@ -475,16 +482,18 @@ RefPtr Parser::try_parse_new_target_expression() return {}; state_rollback_guard.disarm(); - return create_ast_node(MetaProperty::Type::NewTarget); + return create_ast_node({ rule_start.position(), position() }, MetaProperty::Type::NewTarget); } NonnullRefPtr Parser::parse_class_declaration() { - return create_ast_node(parse_class_expression(true)); + auto rule_start = push_start(); + return create_ast_node({ rule_start.position(), position() }, parse_class_expression(true)); } NonnullRefPtr Parser::parse_class_expression(bool expect_class_name) { + auto rule_start = push_start(); // Classes are always in strict mode. TemporaryChange strict_mode_rollback(m_parser_state.m_strict_mode, true); @@ -537,7 +546,7 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ switch (m_parser_state.m_current_token.type()) { case TokenType::Identifier: name = consume().value(); - property_key = create_ast_node(name); + property_key = create_ast_node({ rule_start.position(), position() }, name); break; case TokenType::StringLiteral: { auto string_literal = parse_string_literal(consume()); @@ -577,7 +586,7 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ if (is_constructor) { constructor = move(function); } else if (!property_key.is_null()) { - methods.append(create_ast_node(property_key.release_nonnull(), move(function), method_kind, is_static)); + methods.append(create_ast_node({ rule_start.position(), position() }, property_key.release_nonnull(), move(function), method_kind, is_static)); } else { syntax_error("No key for class method"); } @@ -590,25 +599,26 @@ NonnullRefPtr Parser::parse_class_expression(bool expect_class_ consume(TokenType::CurlyClose); if (constructor.is_null()) { - auto constructor_body = create_ast_node(); + auto constructor_body = create_ast_node({ rule_start.position(), position() }); if (!super_class.is_null()) { // Set constructor to the result of parsing the source text // constructor(... args){ super (...args);} - auto super_call = create_ast_node(create_ast_node(), Vector { CallExpression::Argument { create_ast_node("args"), true } }); - constructor_body->append(create_ast_node(move(super_call))); + auto super_call = create_ast_node({ rule_start.position(), position() }, create_ast_node({ rule_start.position(), position() }), Vector { CallExpression::Argument { create_ast_node({ rule_start.position(), position() }, "args"), true } }); + constructor_body->append(create_ast_node({ rule_start.position(), position() }, move(super_call))); constructor_body->add_variables(m_parser_state.m_var_scopes.last()); - constructor = create_ast_node(class_name, move(constructor_body), Vector { FunctionNode::Parameter { "args", nullptr, true } }, 0, NonnullRefPtrVector(), true); + constructor = create_ast_node({ rule_start.position(), position() }, class_name, move(constructor_body), Vector { FunctionNode::Parameter { "args", nullptr, true } }, 0, NonnullRefPtrVector(), true); } else { - constructor = create_ast_node(class_name, move(constructor_body), Vector {}, 0, NonnullRefPtrVector(), true); + constructor = create_ast_node({ rule_start.position(), position() }, class_name, move(constructor_body), Vector {}, 0, NonnullRefPtrVector(), true); } } - return create_ast_node(move(class_name), move(constructor), move(super_class), move(methods)); + return create_ast_node({ rule_start.position(), position() }, move(class_name), move(constructor), move(super_class), move(methods)); } NonnullRefPtr Parser::parse_primary_expression() { + auto rule_start = push_start(); if (match_unary_prefixed_expression()) return parse_unary_prefixed_expression(); @@ -626,31 +636,31 @@ NonnullRefPtr Parser::parse_primary_expression() } case TokenType::This: consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); case TokenType::Class: return parse_class_expression(false); case TokenType::Super: consume(); if (!m_parser_state.m_allow_super_property_lookup) syntax_error("'super' keyword unexpected here"); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); case TokenType::Identifier: { auto arrow_function_result = try_parse_arrow_function_expression(false); if (!arrow_function_result.is_null()) return arrow_function_result.release_nonnull(); - return create_ast_node(consume().value()); + return create_ast_node({ rule_start.position(), position() }, consume().value()); } case TokenType::NumericLiteral: - return create_ast_node(consume_and_validate_numeric_literal().double_value()); + return create_ast_node({ rule_start.position(), position() }, consume_and_validate_numeric_literal().double_value()); case TokenType::BigIntLiteral: - return create_ast_node(consume().value()); + return create_ast_node({ rule_start.position(), position() }, consume().value()); case TokenType::BoolLiteral: - return create_ast_node(consume().bool_value()); + return create_ast_node({ rule_start.position(), position() }, consume().bool_value()); case TokenType::StringLiteral: return parse_string_literal(consume()); case TokenType::NullLiteral: consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); case TokenType::CurlyOpen: return parse_object_expression(); case TokenType::Function: @@ -674,19 +684,21 @@ NonnullRefPtr Parser::parse_primary_expression() default: expected("primary expression"); consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); } } NonnullRefPtr Parser::parse_regexp_literal() { + auto rule_start = push_start(); auto content = consume().value(); auto flags = match(TokenType::RegexFlags) ? consume().value() : ""; - return create_ast_node(content.substring_view(1, content.length() - 2), flags); + return create_ast_node({ rule_start.position(), position() }, content.substring_view(1, content.length() - 2), flags); } NonnullRefPtr Parser::parse_unary_prefixed_expression() { + auto rule_start = push_start(); auto precedence = g_operator_precedence.get(m_parser_state.m_current_token.type()); auto associativity = operator_associativity(m_parser_state.m_current_token.type()); switch (m_parser_state.m_current_token.type()) { @@ -698,7 +710,7 @@ NonnullRefPtr Parser::parse_unary_prefixed_expression() // other engines throw ReferenceError for ++foo() if (!rhs->is_identifier() && !rhs->is_member_expression()) syntax_error(String::formatted("Right-hand side of prefix increment operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start); - return create_ast_node(UpdateOp::Increment, move(rhs), true); + return create_ast_node({ rule_start.position(), position() }, UpdateOp::Increment, move(rhs), true); } case TokenType::MinusMinus: { consume(); @@ -708,44 +720,45 @@ NonnullRefPtr Parser::parse_unary_prefixed_expression() // other engines throw ReferenceError for --foo() if (!rhs->is_identifier() && !rhs->is_member_expression()) syntax_error(String::formatted("Right-hand side of prefix decrement operator must be identifier or member expression, got {}", rhs->class_name()), rhs_start); - return create_ast_node(UpdateOp::Decrement, move(rhs), true); + return create_ast_node({ rule_start.position(), position() }, UpdateOp::Decrement, move(rhs), true); } case TokenType::ExclamationMark: consume(); - return create_ast_node(UnaryOp::Not, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Not, parse_expression(precedence, associativity)); case TokenType::Tilde: consume(); - return create_ast_node(UnaryOp::BitwiseNot, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::BitwiseNot, parse_expression(precedence, associativity)); case TokenType::Plus: consume(); - return create_ast_node(UnaryOp::Plus, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Plus, parse_expression(precedence, associativity)); case TokenType::Minus: consume(); - return create_ast_node(UnaryOp::Minus, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Minus, parse_expression(precedence, associativity)); case TokenType::Typeof: consume(); - return create_ast_node(UnaryOp::Typeof, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Typeof, parse_expression(precedence, associativity)); case TokenType::Void: consume(); - return create_ast_node(UnaryOp::Void, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Void, parse_expression(precedence, associativity)); case TokenType::Delete: consume(); - return create_ast_node(UnaryOp::Delete, parse_expression(precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, UnaryOp::Delete, parse_expression(precedence, associativity)); default: expected("primary expression"); consume(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); } } NonnullRefPtr Parser::parse_property_key() { + auto rule_start = push_start(); if (match(TokenType::StringLiteral)) { return parse_string_literal(consume()); } else if (match(TokenType::NumericLiteral)) { - return create_ast_node(consume().double_value()); + return create_ast_node({ rule_start.position(), position() }, consume().double_value()); } else if (match(TokenType::BigIntLiteral)) { - return create_ast_node(consume().value()); + return create_ast_node({ rule_start.position(), position() }, consume().value()); } else if (match(TokenType::BracketOpen)) { consume(TokenType::BracketOpen); auto result = parse_expression(0); @@ -754,12 +767,13 @@ NonnullRefPtr Parser::parse_property_key() } else { if (!match_identifier_name()) expected("IdentifierName"); - return create_ast_node(consume().value()); + return create_ast_node({ rule_start.position(), position() }, consume().value()); } } NonnullRefPtr Parser::parse_object_expression() { + auto rule_start = push_start(); consume(TokenType::CurlyOpen); NonnullRefPtrVector properties; @@ -778,7 +792,7 @@ NonnullRefPtr Parser::parse_object_expression() if (match(TokenType::TripleDot)) { consume(); property_name = parse_expression(4); - properties.append(create_ast_node(*property_name, nullptr, ObjectProperty::Type::Spread, false)); + properties.append(create_ast_node({ rule_start.position(), position() }, *property_name, nullptr, ObjectProperty::Type::Spread, false)); if (!match(TokenType::Comma)) break; consume(TokenType::Comma); @@ -794,8 +808,8 @@ NonnullRefPtr Parser::parse_object_expression() property_type = ObjectProperty::Type::Setter; property_name = parse_property_key(); } else { - property_name = create_ast_node(identifier); - property_value = create_ast_node(identifier); + property_name = create_ast_node({ rule_start.position(), position() }, identifier); + property_value = create_ast_node({ rule_start.position(), position() }, identifier); } } else { property_name = parse_property_key(); @@ -817,7 +831,7 @@ NonnullRefPtr Parser::parse_object_expression() if (property_type == ObjectProperty::Type::Setter) parse_options |= FunctionNodeParseOptions::IsSetterFunction; auto function = parse_function_node(parse_options); - properties.append(create_ast_node(*property_name, function, property_type, true)); + properties.append(create_ast_node({ rule_start.position(), position() }, *property_name, function, property_type, true)); } else if (match(TokenType::Colon)) { if (!property_name) { syntax_error("Expected a property name"); @@ -825,9 +839,9 @@ NonnullRefPtr Parser::parse_object_expression() continue; } consume(); - properties.append(create_ast_node(*property_name, parse_expression(2), property_type, false)); + properties.append(create_ast_node({ rule_start.position(), position() }, *property_name, parse_expression(2), property_type, false)); } else if (property_name && property_value) { - properties.append(create_ast_node(*property_name, *property_value, property_type, false)); + properties.append(create_ast_node({ rule_start.position(), position() }, *property_name, *property_value, property_type, false)); } else { syntax_error("Expected a property"); skip_to_next_property(); @@ -840,11 +854,12 @@ NonnullRefPtr Parser::parse_object_expression() } consume(TokenType::CurlyClose); - return create_ast_node(properties); + return create_ast_node({ rule_start.position(), position() }, properties); } NonnullRefPtr Parser::parse_array_expression() { + auto rule_start = push_start(); consume(TokenType::BracketOpen); Vector> elements; @@ -853,7 +868,7 @@ NonnullRefPtr Parser::parse_array_expression() if (match(TokenType::TripleDot)) { consume(TokenType::TripleDot); - expression = create_ast_node(parse_expression(2)); + expression = create_ast_node({ rule_start.position(), position() }, parse_expression(2)); } else if (match_expression()) { expression = parse_expression(2); } @@ -865,11 +880,12 @@ NonnullRefPtr Parser::parse_array_expression() } consume(TokenType::BracketClose); - return create_ast_node(move(elements)); + return create_ast_node({ rule_start.position(), position() }, move(elements)); } NonnullRefPtr Parser::parse_string_literal(Token token, bool in_template_literal) { + auto rule_start = push_start(); auto status = Token::StringValueStatus::Ok; auto string = token.string_value(status); if (status != Token::StringValueStatus::Ok) { @@ -895,18 +911,19 @@ NonnullRefPtr Parser::parse_string_literal(Token token, bool in_t auto is_use_strict_directive = !in_template_literal && (token.value() == "'use strict'" || token.value() == "\"use strict\""); - return create_ast_node(string, is_use_strict_directive); + return create_ast_node({ rule_start.position(), position() }, string, is_use_strict_directive); } NonnullRefPtr Parser::parse_template_literal(bool is_tagged) { + auto rule_start = push_start(); consume(TokenType::TemplateLiteralStart); NonnullRefPtrVector expressions; NonnullRefPtrVector raw_strings; - auto append_empty_string = [&expressions, &raw_strings, is_tagged]() { - auto string_literal = create_ast_node(""); + auto append_empty_string = [this, &rule_start, &expressions, &raw_strings, is_tagged]() { + auto string_literal = create_ast_node({ rule_start.position(), position() }, ""); expressions.append(string_literal); if (is_tagged) raw_strings.append(string_literal); @@ -920,18 +937,18 @@ NonnullRefPtr Parser::parse_template_literal(bool is_tagged) auto token = consume(); expressions.append(parse_string_literal(token, true)); if (is_tagged) - raw_strings.append(create_ast_node(token.value())); + raw_strings.append(create_ast_node({ rule_start.position(), position() }, token.value())); } else if (match(TokenType::TemplateLiteralExprStart)) { consume(TokenType::TemplateLiteralExprStart); if (match(TokenType::TemplateLiteralExprEnd)) { syntax_error("Empty template literal expression block"); - return create_ast_node(expressions); + return create_ast_node({ rule_start.position(), position() }, expressions); } expressions.append(parse_expression(0)); if (match(TokenType::UnterminatedTemplateLiteral)) { syntax_error("Unterminated template literal"); - return create_ast_node(expressions); + return create_ast_node({ rule_start.position(), position() }, expressions); } consume(TokenType::TemplateLiteralExprEnd); @@ -950,16 +967,17 @@ NonnullRefPtr Parser::parse_template_literal(bool is_tagged) } if (is_tagged) - return create_ast_node(expressions, raw_strings); - return create_ast_node(expressions); + return create_ast_node({ rule_start.position(), position() }, expressions, raw_strings); + return create_ast_node({ rule_start.position(), position() }, expressions); } NonnullRefPtr Parser::parse_expression(int min_precedence, Associativity associativity, Vector forbidden) { + auto rule_start = push_start(); auto expression = parse_primary_expression(); while (match(TokenType::TemplateLiteralStart)) { auto template_literal = parse_template_literal(true); - expression = create_ast_node(move(expression), move(template_literal)); + expression = create_ast_node({ rule_start.position(), position() }, move(expression), move(template_literal)); } while (match_secondary_expression(forbidden)) { int new_precedence = g_operator_precedence.get(m_parser_state.m_current_token.type()); @@ -972,7 +990,7 @@ NonnullRefPtr Parser::parse_expression(int min_precedence, Associati expression = parse_secondary_expression(move(expression), new_precedence, new_associativity); while (match(TokenType::TemplateLiteralStart)) { auto template_literal = parse_template_literal(true); - expression = create_ast_node(move(expression), move(template_literal)); + expression = create_ast_node({ rule_start.position(), position() }, move(expression), move(template_literal)); } } if (match(TokenType::Comma) && min_precedence <= 1) { @@ -982,102 +1000,103 @@ NonnullRefPtr Parser::parse_expression(int min_precedence, Associati consume(); expressions.append(parse_expression(2)); } - expression = create_ast_node(move(expressions)); + expression = create_ast_node({ rule_start.position(), position() }, move(expressions)); } return expression; } NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr lhs, int min_precedence, Associativity associativity) { + auto rule_start = push_start(); switch (m_parser_state.m_current_token.type()) { case TokenType::Plus: consume(); - return create_ast_node(BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Addition, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::PlusEquals: return parse_assignment_expression(AssignmentOp::AdditionAssignment, move(lhs), min_precedence, associativity); case TokenType::Minus: consume(); - return create_ast_node(BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Subtraction, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::MinusEquals: return parse_assignment_expression(AssignmentOp::SubtractionAssignment, move(lhs), min_precedence, associativity); case TokenType::Asterisk: consume(); - return create_ast_node(BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Multiplication, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::AsteriskEquals: return parse_assignment_expression(AssignmentOp::MultiplicationAssignment, move(lhs), min_precedence, associativity); case TokenType::Slash: consume(); - return create_ast_node(BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Division, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::SlashEquals: return parse_assignment_expression(AssignmentOp::DivisionAssignment, move(lhs), min_precedence, associativity); case TokenType::Percent: consume(); - return create_ast_node(BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Modulo, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::PercentEquals: return parse_assignment_expression(AssignmentOp::ModuloAssignment, move(lhs), min_precedence, associativity); case TokenType::DoubleAsterisk: consume(); - return create_ast_node(BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::DoubleAsteriskEquals: return parse_assignment_expression(AssignmentOp::ExponentiationAssignment, move(lhs), min_precedence, associativity); case TokenType::GreaterThan: consume(); - return create_ast_node(BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::GreaterThanEquals: consume(); - return create_ast_node(BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::GreaterThanEquals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::LessThan: consume(); - return create_ast_node(BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::LessThan, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::LessThanEquals: consume(); - return create_ast_node(BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::LessThanEquals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::EqualsEqualsEquals: consume(); - return create_ast_node(BinaryOp::TypedEquals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::TypedEquals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ExclamationMarkEqualsEquals: consume(); - return create_ast_node(BinaryOp::TypedInequals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::TypedInequals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::EqualsEquals: consume(); - return create_ast_node(BinaryOp::AbstractEquals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::AbstractEquals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ExclamationMarkEquals: consume(); - return create_ast_node(BinaryOp::AbstractInequals, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::AbstractInequals, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::In: consume(); - return create_ast_node(BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::In, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::Instanceof: consume(); - return create_ast_node(BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::InstanceOf, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::Ampersand: consume(); - return create_ast_node(BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::AmpersandEquals: return parse_assignment_expression(AssignmentOp::BitwiseAndAssignment, move(lhs), min_precedence, associativity); case TokenType::Pipe: consume(); - return create_ast_node(BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::PipeEquals: return parse_assignment_expression(AssignmentOp::BitwiseOrAssignment, move(lhs), min_precedence, associativity); case TokenType::Caret: consume(); - return create_ast_node(BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::CaretEquals: return parse_assignment_expression(AssignmentOp::BitwiseXorAssignment, move(lhs), min_precedence, associativity); case TokenType::ShiftLeft: consume(); - return create_ast_node(BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ShiftLeftEquals: return parse_assignment_expression(AssignmentOp::LeftShiftAssignment, move(lhs), min_precedence, associativity); case TokenType::ShiftRight: consume(); - return create_ast_node(BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ShiftRightEquals: return parse_assignment_expression(AssignmentOp::RightShiftAssignment, move(lhs), min_precedence, associativity); case TokenType::UnsignedShiftRight: consume(); - return create_ast_node(BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, BinaryOp::UnsignedRightShift, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::UnsignedShiftRightEquals: return parse_assignment_expression(AssignmentOp::UnsignedRightShiftAssignment, move(lhs), min_precedence, associativity); case TokenType::ParenOpen: @@ -1088,10 +1107,10 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr(move(lhs), create_ast_node(consume().value())); + return create_ast_node({ rule_start.position(), position() }, move(lhs), create_ast_node({ rule_start.position(), position() }, consume().value())); case TokenType::BracketOpen: { consume(TokenType::BracketOpen); - auto expression = create_ast_node(move(lhs), parse_expression(0), true); + auto expression = create_ast_node({ rule_start.position(), position() }, move(lhs), parse_expression(0), true); consume(TokenType::BracketClose); return expression; } @@ -1101,27 +1120,27 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtris_identifier() && !lhs->is_member_expression()) syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name())); consume(); - return create_ast_node(UpdateOp::Increment, move(lhs)); + return create_ast_node({ rule_start.position(), position() }, UpdateOp::Increment, move(lhs)); case TokenType::MinusMinus: // FIXME: Apparently for functions this should also not be enforced on a parser level, // other engines throw ReferenceError for foo()-- if (!lhs->is_identifier() && !lhs->is_member_expression()) syntax_error(String::formatted("Left-hand side of postfix increment operator must be identifier or member expression, got {}", lhs->class_name())); consume(); - return create_ast_node(UpdateOp::Decrement, move(lhs)); + return create_ast_node({ rule_start.position(), position() }, UpdateOp::Decrement, move(lhs)); case TokenType::DoubleAmpersand: consume(); - return create_ast_node(LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, LogicalOp::And, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::DoubleAmpersandEquals: return parse_assignment_expression(AssignmentOp::AndAssignment, move(lhs), min_precedence, associativity); case TokenType::DoublePipe: consume(); - return create_ast_node(LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, LogicalOp::Or, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::DoublePipeEquals: return parse_assignment_expression(AssignmentOp::OrAssignment, move(lhs), min_precedence, associativity); case TokenType::DoubleQuestionMark: consume(); - return create_ast_node(LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, LogicalOp::NullishCoalescing, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::DoubleQuestionMarkEquals: return parse_assignment_expression(AssignmentOp::NullishAssignment, move(lhs), min_precedence, associativity); case TokenType::QuestionMark: @@ -1129,12 +1148,13 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr(); + return create_ast_node({ rule_start.position(), position() }); } } NonnullRefPtr Parser::parse_assignment_expression(AssignmentOp assignment_op, NonnullRefPtr lhs, int min_precedence, Associativity associativity) { + auto rule_start = push_start(); ASSERT(match(TokenType::Equals) || match(TokenType::PlusEquals) || match(TokenType::MinusEquals) @@ -1161,11 +1181,12 @@ NonnullRefPtr Parser::parse_assignment_expression(Assignme } else if (m_parser_state.m_strict_mode && lhs->is_call_expression()) { syntax_error("Cannot assign to function call"); } - return create_ast_node(assignment_op, move(lhs), parse_expression(min_precedence, associativity)); + return create_ast_node({ rule_start.position(), position() }, assignment_op, move(lhs), parse_expression(min_precedence, associativity)); } NonnullRefPtr Parser::parse_call_expression(NonnullRefPtr lhs) { + auto rule_start = push_start(); if (!m_parser_state.m_allow_super_constructor_call && lhs->is_super_expression()) syntax_error("'super' keyword unexpected here"); @@ -1187,11 +1208,12 @@ NonnullRefPtr Parser::parse_call_expression(NonnullRefPtr(move(lhs), move(arguments)); + return create_ast_node({ rule_start.position(), position() }, move(lhs), move(arguments)); } NonnullRefPtr Parser::parse_new_expression() { + auto rule_start = push_start(); consume(TokenType::New); auto callee = parse_expression(g_operator_precedence.get(TokenType::New), Associativity::Right, { TokenType::ParenOpen }); @@ -1214,11 +1236,12 @@ NonnullRefPtr Parser::parse_new_expression() consume(TokenType::ParenClose); } - return create_ast_node(move(callee), move(arguments)); + return create_ast_node({ rule_start.position(), position() }, move(callee), move(arguments)); } NonnullRefPtr Parser::parse_return_statement() { + auto rule_start = push_start(); if (!m_parser_state.m_in_function_context && !m_parser_state.m_in_arrow_function_context) syntax_error("'return' not allowed outside of a function"); @@ -1226,28 +1249,30 @@ NonnullRefPtr Parser::parse_return_statement() // Automatic semicolon insertion: terminate statement when return is followed by newline if (m_parser_state.m_current_token.trivia_contains_line_terminator()) - return create_ast_node(nullptr); + return create_ast_node({ rule_start.position(), position() }, nullptr); if (match_expression()) { auto expression = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node(move(expression)); + return create_ast_node({ rule_start.position(), position() }, move(expression)); } consume_or_insert_semicolon(); - return create_ast_node(nullptr); + return create_ast_node({ rule_start.position(), position() }, nullptr); } NonnullRefPtr Parser::parse_block_statement() { + auto rule_start = push_start(); bool dummy = false; return parse_block_statement(dummy); } NonnullRefPtr Parser::parse_block_statement(bool& is_strict) { + auto rule_start = push_start(); ScopePusher scope(*this, ScopePusher::Let); - auto block = create_ast_node(); + auto block = create_ast_node({ rule_start.position(), position() }); consume(TokenType::CurlyOpen); bool first = true; @@ -1286,6 +1311,7 @@ NonnullRefPtr Parser::parse_block_statement(bool& is_strict) template NonnullRefPtr Parser::parse_function_node(u8 parse_options) { + auto rule_start = push_start(); ASSERT(!(parse_options & FunctionNodeParseOptions::IsGetterFunction && parse_options & FunctionNodeParseOptions::IsSetterFunction)); TemporaryChange super_property_access_rollback(m_parser_state.m_allow_super_property_lookup, !!(parse_options & FunctionNodeParseOptions::AllowSuperPropertyLookup)); @@ -1317,11 +1343,12 @@ NonnullRefPtr Parser::parse_function_node(u8 parse_options) auto body = parse_block_statement(is_strict); body->add_variables(m_parser_state.m_var_scopes.last()); body->add_functions(m_parser_state.m_function_scopes.last()); - return create_ast_node(name, move(body), move(parameters), function_length, NonnullRefPtrVector(), is_strict); + return create_ast_node({ rule_start.position(), position() }, name, move(body), move(parameters), function_length, NonnullRefPtrVector(), is_strict); } Vector Parser::parse_function_parameters(int& function_length, u8 parse_options) { + auto rule_start = push_start(); bool has_default_parameter = false; bool has_rest_parameter = false; @@ -1383,6 +1410,7 @@ Vector Parser::parse_function_parameters(int& function_ NonnullRefPtr Parser::parse_variable_declaration(bool for_loop_variable_declaration) { + auto rule_start = push_start(); DeclarationKind declaration_kind; switch (m_parser_state.m_current_token.type()) { @@ -1410,7 +1438,7 @@ NonnullRefPtr Parser::parse_variable_declaration(bool for_l } else if (!for_loop_variable_declaration && declaration_kind == DeclarationKind::Const) { syntax_error("Missing initializer in 'const' variable declaration"); } - declarations.append(create_ast_node(create_ast_node(move(id)), move(init))); + declarations.append(create_ast_node({ rule_start.position(), position() }, create_ast_node({ rule_start.position(), position() }, move(id)), move(init))); if (match(TokenType::Comma)) { consume(); continue; @@ -1420,7 +1448,7 @@ NonnullRefPtr Parser::parse_variable_declaration(bool for_l if (!for_loop_variable_declaration) consume_or_insert_semicolon(); - auto declaration = create_ast_node(declaration_kind, move(declarations)); + auto declaration = create_ast_node({ rule_start.position(), position() }, declaration_kind, move(declarations)); if (declaration_kind == DeclarationKind::Var) m_parser_state.m_var_scopes.last().append(declaration); else @@ -1430,21 +1458,23 @@ NonnullRefPtr Parser::parse_variable_declaration(bool for_l NonnullRefPtr Parser::parse_throw_statement() { + auto rule_start = push_start(); consume(TokenType::Throw); // Automatic semicolon insertion: terminate statement when throw is followed by newline if (m_parser_state.m_current_token.trivia_contains_line_terminator()) { syntax_error("No line break is allowed between 'throw' and its expression"); - return create_ast_node(create_ast_node()); + return create_ast_node({ rule_start.position(), position() }, create_ast_node({ rule_start.position(), position() })); } auto expression = parse_expression(0); consume_or_insert_semicolon(); - return create_ast_node(move(expression)); + return create_ast_node({ rule_start.position(), position() }, move(expression)); } NonnullRefPtr Parser::parse_break_statement() { + auto rule_start = push_start(); consume(TokenType::Break); FlyString target_label; if (match(TokenType::Semicolon)) { @@ -1461,11 +1491,12 @@ NonnullRefPtr Parser::parse_break_statement() if (target_label.is_null() && !m_parser_state.m_in_break_context) syntax_error("Unlabeled 'break' not allowed outside of a loop or switch statement"); - return create_ast_node(target_label); + return create_ast_node({ rule_start.position(), position() }, target_label); } NonnullRefPtr Parser::parse_continue_statement() { + auto rule_start = push_start(); if (!m_parser_state.m_in_continue_context) syntax_error("'continue' not allow outside of a loop"); @@ -1473,7 +1504,7 @@ NonnullRefPtr Parser::parse_continue_statement() FlyString target_label; if (match(TokenType::Semicolon)) { consume(); - return create_ast_node(target_label); + return create_ast_node({ rule_start.position(), position() }, target_label); } if (match(TokenType::Identifier) && !m_parser_state.m_current_token.trivia_contains_line_terminator()) { target_label = consume().value(); @@ -1481,20 +1512,22 @@ NonnullRefPtr Parser::parse_continue_statement() syntax_error(String::formatted("Label '{}' not found", target_label)); } consume_or_insert_semicolon(); - return create_ast_node(target_label); + return create_ast_node({ rule_start.position(), position() }, target_label); } NonnullRefPtr Parser::parse_conditional_expression(NonnullRefPtr test) { + auto rule_start = push_start(); consume(TokenType::QuestionMark); auto consequent = parse_expression(2); consume(TokenType::Colon); auto alternate = parse_expression(2); - return create_ast_node(move(test), move(consequent), move(alternate)); + return create_ast_node({ rule_start.position(), position() }, move(test), move(consequent), move(alternate)); } NonnullRefPtr Parser::parse_try_statement() { + auto rule_start = push_start(); consume(TokenType::Try); auto block = parse_block_statement(); @@ -1512,11 +1545,12 @@ NonnullRefPtr Parser::parse_try_statement() if (!handler && !finalizer) syntax_error("try statement must have a 'catch' or 'finally' clause"); - return create_ast_node(move(block), move(handler), move(finalizer)); + return create_ast_node({ rule_start.position(), position() }, move(block), move(handler), move(finalizer)); } NonnullRefPtr Parser::parse_do_while_statement() { + auto rule_start = push_start(); consume(TokenType::Do); auto body = [&]() -> NonnullRefPtr { @@ -1536,11 +1570,12 @@ NonnullRefPtr Parser::parse_do_while_statement() if (match(TokenType::Semicolon)) consume(); - return create_ast_node(move(test), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(test), move(body)); } NonnullRefPtr Parser::parse_while_statement() { + auto rule_start = push_start(); consume(TokenType::While); consume(TokenType::ParenOpen); @@ -1552,11 +1587,12 @@ NonnullRefPtr Parser::parse_while_statement() TemporaryChange continue_change(m_parser_state.m_in_continue_context, true); auto body = parse_statement(); - return create_ast_node(move(test), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(test), move(body)); } NonnullRefPtr Parser::parse_switch_statement() { + auto rule_start = push_start(); consume(TokenType::Switch); consume(TokenType::ParenOpen); @@ -1579,11 +1615,12 @@ NonnullRefPtr Parser::parse_switch_statement() consume(TokenType::CurlyClose); - return create_ast_node(move(determinant), move(cases)); + return create_ast_node({ rule_start.position(), position() }, move(determinant), move(cases)); } NonnullRefPtr Parser::parse_with_statement() { + auto rule_start = push_start(); consume(TokenType::With); consume(TokenType::ParenOpen); @@ -1592,11 +1629,12 @@ NonnullRefPtr Parser::parse_with_statement() consume(TokenType::ParenClose); auto body = parse_statement(); - return create_ast_node(move(object), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(object), move(body)); } NonnullRefPtr Parser::parse_switch_case() { + auto rule_start = push_start(); RefPtr test; if (consume().type() == TokenType::Case) { @@ -1616,11 +1654,12 @@ NonnullRefPtr Parser::parse_switch_case() break; } - return create_ast_node(move(test), move(consequent)); + return create_ast_node({ rule_start.position(), position() }, move(test), move(consequent)); } NonnullRefPtr Parser::parse_catch_clause() { + auto rule_start = push_start(); consume(TokenType::Catch); String parameter; @@ -1631,18 +1670,19 @@ NonnullRefPtr Parser::parse_catch_clause() } auto body = parse_block_statement(); - return create_ast_node(parameter, move(body)); + return create_ast_node({ rule_start.position(), position() }, parameter, move(body)); } NonnullRefPtr Parser::parse_if_statement() { + auto rule_start = push_start(); auto parse_function_declaration_as_block_statement = [&] { // https://tc39.es/ecma262/#sec-functiondeclarations-in-ifstatement-statement-clauses // Code matching this production is processed as if each matching occurrence of // FunctionDeclaration[?Yield, ?Await, ~Default] was the sole StatementListItem // of a BlockStatement occupying that position in the source code. ScopePusher scope(*this, ScopePusher::Let); - auto block = create_ast_node(); + auto block = create_ast_node({ rule_start.position(), position() }); block->append(parse_declaration()); block->add_functions(m_parser_state.m_function_scopes.last()); return block; @@ -1667,11 +1707,12 @@ NonnullRefPtr Parser::parse_if_statement() else alternate = parse_statement(); } - return create_ast_node(move(predicate), move(*consequent), move(alternate)); + return create_ast_node({ rule_start.position(), position() }, move(predicate), move(*consequent), move(alternate)); } NonnullRefPtr Parser::parse_for_statement() { + auto rule_start = push_start(); auto match_for_in_of = [&]() { return match(TokenType::In) || (match(TokenType::Identifier) && m_parser_state.m_current_token.value() == "of"); }; @@ -1727,11 +1768,12 @@ NonnullRefPtr Parser::parse_for_statement() m_parser_state.m_let_scopes.take_last(); } - return create_ast_node(move(init), move(test), move(update), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(init), move(test), move(update), move(body)); } NonnullRefPtr Parser::parse_for_in_of_statement(NonnullRefPtr lhs) { + auto rule_start = push_start(); if (lhs->is_variable_declaration()) { auto declarations = static_cast(*lhs).declarations(); if (declarations.size() > 1) @@ -1747,15 +1789,16 @@ NonnullRefPtr Parser::parse_for_in_of_statement(NonnullRefPtr(move(lhs), move(rhs), move(body)); - return create_ast_node(move(lhs), move(rhs), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(lhs), move(rhs), move(body)); + return create_ast_node({ rule_start.position(), position() }, move(lhs), move(rhs), move(body)); } NonnullRefPtr Parser::parse_debugger_statement() { + auto rule_start = push_start(); consume(TokenType::Debugger); consume_or_insert_semicolon(); - return create_ast_node(); + return create_ast_node({ rule_start.position(), position() }); } bool Parser::match(TokenType type) const @@ -1969,7 +2012,7 @@ void Parser::expected(const char* what) syntax_error(message); } -Parser::Position Parser::position() const +Position Parser::position() const { return { m_parser_state.m_current_token.line_number(), diff --git a/Libraries/LibJS/Parser.h b/Libraries/LibJS/Parser.h index 6b7a1554afd..0c348924cc6 100644 --- a/Libraries/LibJS/Parser.h +++ b/Libraries/LibJS/Parser.h @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace JS { @@ -102,11 +103,6 @@ public: RefPtr try_parse_labelled_statement(); RefPtr try_parse_new_target_expression(); - struct Position { - size_t line; - size_t column; - }; - struct Error { String message; Optional position; @@ -175,6 +171,30 @@ private: void load_state(); Position position() const; + struct RulePosition { + RulePosition(Parser& parser, Position position) + : m_parser(parser) + , m_position(position) + { + m_parser.m_parser_state.m_rule_starts.append(position); + } + + ~RulePosition() + { + auto last = m_parser.m_parser_state.m_rule_starts.take_last(); + ASSERT(last.line == m_position.line); + ASSERT(last.column == m_position.column); + } + + const Position& position() const { return m_position; } + + private: + Parser& m_parser; + Position m_position; + }; + + [[nodiscard]] RulePosition push_start() { return { *this, position() }; } + struct ParserState { Lexer m_lexer; Token m_current_token; @@ -182,6 +202,7 @@ private: Vector> m_var_scopes; Vector> m_let_scopes; Vector> m_function_scopes; + Vector m_rule_starts; HashTable m_labels_in_scope; bool m_strict_mode { false }; bool m_allow_super_property_lookup { false }; diff --git a/Libraries/LibJS/Runtime/Exception.cpp b/Libraries/LibJS/Runtime/Exception.cpp index 8bcf005c3a5..08c6f6bde97 100644 --- a/Libraries/LibJS/Runtime/Exception.cpp +++ b/Libraries/LibJS/Runtime/Exception.cpp @@ -25,6 +25,7 @@ */ #include +#include #include #include @@ -40,6 +41,13 @@ Exception::Exception(Value value) function_name = ""; m_trace.append(function_name); } + + auto& node_stack = vm().node_stack(); + for (ssize_t i = node_stack.size() - 1; i >= 0; --i) { + auto* node = node_stack[i]; + ASSERT(node); + m_source_ranges.append(node->source_range()); + } } Exception::~Exception() diff --git a/Libraries/LibJS/Runtime/Exception.h b/Libraries/LibJS/Runtime/Exception.h index 630cce9ef6a..2d26447c89e 100644 --- a/Libraries/LibJS/Runtime/Exception.h +++ b/Libraries/LibJS/Runtime/Exception.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace JS { @@ -39,6 +40,7 @@ public: Value value() const { return m_value; } const Vector& trace() const { return m_trace; } + const Vector& source_ranges() const { return m_source_ranges; } private: virtual const char* class_name() const override { return "Exception"; } @@ -46,6 +48,7 @@ private: Value m_value; Vector m_trace; + Vector m_source_ranges; }; } diff --git a/Libraries/LibJS/Runtime/VM.h b/Libraries/LibJS/Runtime/VM.h index 4021c217dc3..320ea53405b 100644 --- a/Libraries/LibJS/Runtime/VM.h +++ b/Libraries/LibJS/Runtime/VM.h @@ -126,10 +126,14 @@ public: void pop_call_frame() { m_call_stack.take_last(); } + void push_ast_node(const ASTNode& node) { m_ast_nodes.append(&node); } + void pop_ast_node() { m_ast_nodes.take_last(); } + CallFrame& call_frame() { return *m_call_stack.last(); } const CallFrame& call_frame() const { return *m_call_stack.last(); } const Vector& call_stack() const { return m_call_stack; } Vector& call_stack() { return m_call_stack; } + const Vector& node_stack() const { return m_ast_nodes; } const ScopeObject* current_scope() const { return call_frame().scope; } ScopeObject* current_scope() { return call_frame().scope; } @@ -249,6 +253,7 @@ private: Vector m_interpreters; Vector m_call_stack; + Vector m_ast_nodes; Value m_last_value; ScopeType m_unwind_until { ScopeType::None }; diff --git a/Libraries/LibJS/SourceRange.h b/Libraries/LibJS/SourceRange.h new file mode 100644 index 00000000000..f0359ab84c9 --- /dev/null +++ b/Libraries/LibJS/SourceRange.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, the SerenityOS developers. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include + +namespace JS { + +struct Position { + size_t line { 0 }; + size_t column { 0 }; +}; + +struct SourceRange { + Position start; + Position end; +}; + +}