1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 13:47:45 +00:00

LibJS: Capture source text of FunctionNode and ClassExpression

This commit is contained in:
Linus Groh 2022-01-18 23:46:16 +00:00
parent 95a9f12b97
commit 531d1ac734
3 changed files with 46 additions and 20 deletions

View file

@ -484,6 +484,7 @@ public:
}; };
FlyString const& name() const { return m_name; } FlyString const& name() const { return m_name; }
String const& source_text() const { return m_source_text; }
Statement const& body() const { return *m_body; } Statement const& body() const { return *m_body; }
Vector<Parameter> const& parameters() const { return m_parameters; }; Vector<Parameter> const& parameters() const { return m_parameters; };
i32 function_length() const { return m_function_length; } i32 function_length() const { return m_function_length; }
@ -494,8 +495,9 @@ public:
FunctionKind kind() const { return m_kind; } FunctionKind kind() const { return m_kind; }
protected: protected:
FunctionNode(FlyString name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function) FunctionNode(FlyString name, String source_text, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function)
: m_name(move(name)) : m_name(move(name))
, m_source_text(move(source_text))
, m_body(move(body)) , m_body(move(body))
, m_parameters(move(parameters)) , m_parameters(move(parameters))
, m_function_length(function_length) , m_function_length(function_length)
@ -520,6 +522,7 @@ protected:
private: private:
FlyString m_name; FlyString m_name;
String m_source_text;
NonnullRefPtr<Statement> m_body; NonnullRefPtr<Statement> m_body;
Vector<Parameter> const m_parameters; Vector<Parameter> const m_parameters;
const i32 m_function_length; const i32 m_function_length;
@ -536,9 +539,9 @@ class FunctionDeclaration final
public: public:
static bool must_have_name() { return true; } static bool must_have_name() { return true; }
FunctionDeclaration(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval) FunctionDeclaration(SourceRange source_range, FlyString const& name, String source_text, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval)
: Declaration(source_range) : Declaration(source_range)
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false) , FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, false)
{ {
} }
@ -562,9 +565,9 @@ class FunctionExpression final
public: public:
static bool must_have_name() { return false; } static bool must_have_name() { return false; }
FunctionExpression(SourceRange source_range, FlyString const& name, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function = false) FunctionExpression(SourceRange source_range, FlyString const& name, String source_text, NonnullRefPtr<Statement> body, Vector<Parameter> parameters, i32 function_length, FunctionKind kind, bool is_strict_mode, bool might_need_arguments_object, bool contains_direct_call_to_eval, bool is_arrow_function = false)
: Expression(source_range) : Expression(source_range)
, FunctionNode(name, move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function) , FunctionNode(name, move(source_text), move(body), move(parameters), function_length, kind, is_strict_mode, might_need_arguments_object, contains_direct_call_to_eval, is_arrow_function)
{ {
} }
@ -1232,9 +1235,10 @@ public:
class ClassExpression final : public Expression { class ClassExpression final : public Expression {
public: public:
ClassExpression(SourceRange source_range, String name, RefPtr<FunctionExpression> constructor, RefPtr<Expression> super_class, NonnullRefPtrVector<ClassElement> elements) ClassExpression(SourceRange source_range, String name, String source_text, RefPtr<FunctionExpression> constructor, RefPtr<Expression> super_class, NonnullRefPtrVector<ClassElement> elements)
: Expression(source_range) : Expression(source_range)
, m_name(move(name)) , m_name(move(name))
, m_source_text(move(source_text))
, m_constructor(move(constructor)) , m_constructor(move(constructor))
, m_super_class(move(super_class)) , m_super_class(move(super_class))
, m_elements(move(elements)) , m_elements(move(elements))
@ -1242,6 +1246,7 @@ public:
} }
StringView name() const { return m_name; } StringView name() const { return m_name; }
String const& source_text() const { return m_source_text; }
RefPtr<FunctionExpression> constructor() const { return m_constructor; } RefPtr<FunctionExpression> constructor() const { return m_constructor; }
virtual Completion execute(Interpreter&, GlobalObject&) const override; virtual Completion execute(Interpreter&, GlobalObject&) const override;
@ -1255,6 +1260,7 @@ private:
virtual bool is_class_expression() const override { return true; } virtual bool is_class_expression() const override { return true; }
String m_name; String m_name;
String m_source_text;
RefPtr<FunctionExpression> m_constructor; RefPtr<FunctionExpression> m_constructor;
RefPtr<Expression> m_super_class; RefPtr<Expression> m_super_class;
NonnullRefPtrVector<ClassElement> m_elements; NonnullRefPtrVector<ClassElement> m_elements;

View file

@ -702,7 +702,11 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
} }
save_state(); save_state();
auto rule_start = push_start(); auto rule_start = (expect_parens && !is_async)
// Someone has consumed the opening parenthesis for us! Start there.
? RulePosition { *this, m_rule_starts.last() }
// We've not encountered one yet, so the rule start is actually here.
: push_start();
ArmedScopeGuard state_rollback_guard = [&] { ArmedScopeGuard state_rollback_guard = [&] {
load_state(); load_state();
@ -819,9 +823,12 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
} }
} }
auto function_start_offset = rule_start.position().offset;
auto function_end_offset = position().offset - m_state.current_token.trivia().length();
auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) };
return create_ast_node<FunctionExpression>( return create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, "", move(body), { m_state.current_token.filename(), rule_start.position(), position() }, "", move(source_text),
move(parameters), function_length, function_kind, body->in_strict_mode(), move(body), move(parameters), function_length, function_kind, body->in_strict_mode(),
/* might_need_arguments_object */ false, contains_direct_call_to_eval, /* is_arrow_function */ true); /* might_need_arguments_object */ false, contains_direct_call_to_eval, /* is_arrow_function */ true);
} }
@ -1066,6 +1073,8 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
continue; continue;
} }
auto function_start = position();
if (match(TokenType::Async)) { if (match(TokenType::Async)) {
auto lookahead_token = next_token(); auto lookahead_token = next_token();
if (lookahead_token.type() != TokenType::Semicolon && lookahead_token.type() != TokenType::CurlyClose if (lookahead_token.type() != TokenType::Semicolon && lookahead_token.type() != TokenType::CurlyClose
@ -1086,6 +1095,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
if (match(TokenType::Identifier)) { if (match(TokenType::Identifier)) {
consume(); consume();
is_static = true; is_static = true;
function_start = position();
if (match(TokenType::Async)) { if (match(TokenType::Async)) {
consume(); consume();
is_async = true; is_async = true;
@ -1242,7 +1252,7 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
parse_options |= FunctionNodeParseOptions::IsGeneratorFunction; parse_options |= FunctionNodeParseOptions::IsGeneratorFunction;
if (is_async) if (is_async)
parse_options |= FunctionNodeParseOptions::IsAsyncFunction; parse_options |= FunctionNodeParseOptions::IsAsyncFunction;
auto function = parse_function_node<FunctionExpression>(parse_options); auto function = parse_function_node<FunctionExpression>(parse_options, function_start);
if (is_constructor) { if (is_constructor) {
constructor = move(function); constructor = move(function);
} else if (!property_key.is_null()) { } else if (!property_key.is_null()) {
@ -1295,13 +1305,13 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
constructor_body->append(create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(super_call))); constructor_body->append(create_ast_node<ReturnStatement>({ m_state.current_token.filename(), rule_start.position(), position() }, move(super_call)));
constructor = create_ast_node<FunctionExpression>( constructor = create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), { m_state.current_token.filename(), rule_start.position(), position() }, class_name, "",
Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, FunctionKind::Normal, move(constructor_body), Vector { FunctionNode::Parameter { FlyString { "args" }, nullptr, true } }, 0, FunctionKind::Normal,
/* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false);
} else { } else {
constructor = create_ast_node<FunctionExpression>( constructor = create_ast_node<FunctionExpression>(
{ m_state.current_token.filename(), rule_start.position(), position() }, class_name, move(constructor_body), { m_state.current_token.filename(), rule_start.position(), position() }, class_name, "",
Vector<FunctionNode::Parameter> {}, 0, FunctionKind::Normal, move(constructor_body), Vector<FunctionNode::Parameter> {}, 0, FunctionKind::Normal,
/* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false); /* is_strict_mode */ true, /* might_need_arguments_object */ false, /* contains_direct_call_to_eval */ false);
} }
} }
@ -1316,7 +1326,11 @@ NonnullRefPtr<ClassExpression> Parser::parse_class_expression(bool expect_class_
syntax_error(String::formatted("Reference to undeclared private field or method '{}'", private_name)); syntax_error(String::formatted("Reference to undeclared private field or method '{}'", private_name));
} }
return create_ast_node<ClassExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(class_name), move(constructor), move(super_class), move(elements)); auto function_start_offset = rule_start.position().offset;
auto function_end_offset = position().offset - m_state.current_token.trivia().length();
auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) };
return create_ast_node<ClassExpression>({ m_state.current_token.filename(), rule_start.position(), position() }, move(class_name), move(source_text), move(constructor), move(super_class), move(elements));
} }
Parser::PrimaryExpressionParseResult Parser::parse_primary_expression() Parser::PrimaryExpressionParseResult Parser::parse_primary_expression()
@ -1640,6 +1654,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
} }
auto type = m_state.current_token.type(); auto type = m_state.current_token.type();
auto function_start = position();
if (match(TokenType::Async)) { if (match(TokenType::Async)) {
auto lookahead_token = next_token(); auto lookahead_token = next_token();
@ -1701,7 +1716,7 @@ NonnullRefPtr<ObjectExpression> Parser::parse_object_expression()
parse_options |= FunctionNodeParseOptions::IsGeneratorFunction; parse_options |= FunctionNodeParseOptions::IsGeneratorFunction;
if (function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator) if (function_kind == FunctionKind::Async || function_kind == FunctionKind::AsyncGenerator)
parse_options |= FunctionNodeParseOptions::IsAsyncFunction; parse_options |= FunctionNodeParseOptions::IsAsyncFunction;
auto function = parse_function_node<FunctionExpression>(parse_options); auto function = parse_function_node<FunctionExpression>(parse_options, function_start);
properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_name, function, property_type, true)); properties.append(create_ast_node<ObjectProperty>({ m_state.current_token.filename(), rule_start.position(), position() }, *property_name, function, property_type, true));
} else if (match(TokenType::Colon)) { } else if (match(TokenType::Colon)) {
if (!property_name) { if (!property_name) {
@ -2451,9 +2466,11 @@ NonnullRefPtr<BlockStatement> Parser::parse_block_statement()
} }
template<typename FunctionNodeType> template<typename FunctionNodeType>
NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options) NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options, Optional<Position> const& function_start)
{ {
auto rule_start = push_start(); auto rule_start = function_start.has_value()
? RulePosition { *this, *function_start }
: push_start();
VERIFY(!(parse_options & FunctionNodeParseOptions::IsGetterFunction && parse_options & FunctionNodeParseOptions::IsSetterFunction)); VERIFY(!(parse_options & FunctionNodeParseOptions::IsGetterFunction && parse_options & FunctionNodeParseOptions::IsSetterFunction));
TemporaryChange super_property_access_rollback(m_state.allow_super_property_lookup, !!(parse_options & FunctionNodeParseOptions::AllowSuperPropertyLookup)); TemporaryChange super_property_access_rollback(m_state.allow_super_property_lookup, !!(parse_options & FunctionNodeParseOptions::AllowSuperPropertyLookup));
@ -2529,9 +2546,12 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
if (has_strict_directive) if (has_strict_directive)
check_identifier_name_for_assignment_validity(name, true); check_identifier_name_for_assignment_validity(name, true);
auto function_start_offset = rule_start.position().offset;
auto function_end_offset = position().offset - m_state.current_token.trivia().length();
auto source_text = String { m_state.lexer.source().substring_view(function_start_offset, function_end_offset - function_start_offset) };
return create_ast_node<FunctionNodeType>( return create_ast_node<FunctionNodeType>(
{ m_state.current_token.filename(), rule_start.position(), position() }, { m_state.current_token.filename(), rule_start.position(), position() },
name, move(body), move(parameters), function_length, name, move(source_text), move(body), move(parameters), function_length,
function_kind, has_strict_directive, m_state.function_might_need_arguments_object, function_kind, has_strict_directive, m_state.function_might_need_arguments_object,
contains_direct_call_to_eval); contains_direct_call_to_eval);
} }

View file

@ -45,7 +45,7 @@ public:
NonnullRefPtr<Program> parse_program(bool starts_in_strict_mode = false); NonnullRefPtr<Program> parse_program(bool starts_in_strict_mode = false);
template<typename FunctionNodeType> template<typename FunctionNodeType>
NonnullRefPtr<FunctionNodeType> parse_function_node(u8 parse_options = FunctionNodeParseOptions::CheckForFunctionAndName); NonnullRefPtr<FunctionNodeType> parse_function_node(u8 parse_options = FunctionNodeParseOptions::CheckForFunctionAndName, Optional<Position> const& function_start = {});
Vector<FunctionNode::Parameter> parse_formal_parameters(int& function_length, u8 parse_options = 0); Vector<FunctionNode::Parameter> parse_formal_parameters(int& function_length, u8 parse_options = 0);
enum class AllowDuplicates { enum class AllowDuplicates {