瀏覽代碼

LibJS: Track which Identifier nodes refer to function arguments

This patch adds an "argument index" field to Identifier AST nodes.
If the Identifier refers to a function parameter in the currently
open function scope, we stash the index of the parameter here.

This will allow us to implement much faster direct access to function
argument variables.
Andreas Kling 4 年之前
父節點
當前提交
481cef59b6

+ 4 - 1
Userland/Libraries/LibJS/AST.cpp

@@ -1313,7 +1313,10 @@ Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object)
 void Identifier::dump(int indent) const
 {
     print_indent(indent);
-    outln("Identifier \"{}\"", m_string);
+    if (m_argument_index.has_value())
+        outln("Identifier \"{}\" (argument #{})", m_string, m_argument_index.value());
+    else
+        outln("Identifier \"{}\"", m_string);
 }
 
 void SpreadExpression::dump(int indent) const

+ 6 - 3
Userland/Libraries/LibJS/AST.h

@@ -768,13 +768,15 @@ private:
 
 class Identifier final : public Expression {
 public:
-    explicit Identifier(SourceRange source_range, FlyString const& string)
-        : Expression(move(source_range))
-        , m_string(string)
+    explicit Identifier(SourceRange source_range, FlyString string, Optional<size_t> argument_index = {})
+        : Expression(source_range)
+        , m_string(move(string))
+        , m_argument_index(move(argument_index))
     {
     }
 
     FlyString const& string() const { return m_string; }
+    Optional<size_t> const& argument_index() const { return m_argument_index; }
 
     virtual Value execute(Interpreter&, GlobalObject&) const override;
     virtual void dump(int indent) const override;
@@ -785,6 +787,7 @@ private:
     virtual bool is_identifier() const override { return true; }
 
     FlyString m_string;
+    Optional<size_t> m_argument_index;
 };
 
 class ClassMethod final : public ASTNode {

+ 26 - 1
Userland/Libraries/LibJS/Parser.cpp

@@ -382,6 +382,8 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
     if (function_length == -1)
         function_length = parameters.size();
 
+    m_parser_state.function_parameters.append(parameters);
+
     auto old_labels_in_scope = move(m_parser_state.m_labels_in_scope);
     ScopeGuard guard([&]() {
         m_parser_state.m_labels_in_scope = move(old_labels_in_scope);
@@ -411,6 +413,8 @@ RefPtr<FunctionExpression> Parser::try_parse_arrow_function_expression(bool expe
         return nullptr;
     }();
 
+    m_parser_state.function_parameters.take_last();
+
     if (!function_body_result.is_null()) {
         state_rollback_guard.disarm();
         discard_saved_state();
@@ -651,7 +655,23 @@ NonnullRefPtr<Expression> Parser::parse_primary_expression()
 
             set_try_parse_arrow_function_expression_failed_at_position(position(), true);
         }
-        return create_ast_node<Identifier>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, consume().value());
+        auto string = consume().value();
+        Optional<size_t> argument_index;
+        if (!m_parser_state.function_parameters.is_empty()) {
+            size_t i = 0;
+            for (auto& parameter : m_parser_state.function_parameters.last()) {
+                parameter.binding.visit(
+                    [&](FlyString const& name) {
+                        if (name == string) {
+                            argument_index = i;
+                        }
+                    },
+                    [&](BindingPattern const&) {
+                    });
+                ++i;
+            }
+        }
+        return create_ast_node<Identifier>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, string, argument_index);
     }
     case TokenType::NumericLiteral:
         return create_ast_node<NumericLiteral>({ m_parser_state.m_current_token.filename(), rule_start.position(), position() }, consume_and_validate_numeric_literal().double_value());
@@ -1386,8 +1406,13 @@ NonnullRefPtr<FunctionNodeType> Parser::parse_function_node(u8 parse_options)
         m_parser_state.m_labels_in_scope = move(old_labels_in_scope);
     });
 
+    m_parser_state.function_parameters.append(parameters);
+
     bool is_strict = false;
     auto body = parse_block_statement(is_strict);
+
+    m_parser_state.function_parameters.take_last();
+
     body->add_variables(m_parser_state.m_var_scopes.last());
     body->add_functions(m_parser_state.m_function_scopes.last());
     return create_ast_node<FunctionNodeType>(

+ 3 - 0
Userland/Libraries/LibJS/Parser.h

@@ -196,6 +196,9 @@ private:
         Vector<NonnullRefPtrVector<VariableDeclaration>> m_var_scopes;
         Vector<NonnullRefPtrVector<VariableDeclaration>> m_let_scopes;
         Vector<NonnullRefPtrVector<FunctionDeclaration>> m_function_scopes;
+
+        Vector<Vector<FunctionNode::Parameter>&> function_parameters;
+
         HashTable<StringView> m_labels_in_scope;
         bool m_strict_mode { false };
         bool m_allow_super_property_lookup { false };