mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
JSSpecCompiler: Add reference resolving pass
It replaces UnresolvedReference with Variable, FunctionPointer, or SlotName nodes. Also, it gathers all variable names from their declarations.
This commit is contained in:
parent
326bac19d9
commit
81519975c5
Notes:
sideshowbarker
2024-07-17 22:01:16 +09:00
Author: https://github.com/DanShaders Commit: https://github.com/SerenityOS/serenity/commit/81519975c5 Pull-request: https://github.com/SerenityOS/serenity/pull/21005 Reviewed-by: https://github.com/ADKaster ✅
9 changed files with 116 additions and 4 deletions
|
@ -40,6 +40,16 @@ private:
|
|||
Variant<Tree*, NullableTree*> m_tree_ptr;
|
||||
};
|
||||
|
||||
class VariableDeclaration : public RefCounted<VariableDeclaration> {
|
||||
public:
|
||||
VariableDeclaration(StringView name)
|
||||
: m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
StringView m_name;
|
||||
};
|
||||
|
||||
class Node : public RefCounted<Node> {
|
||||
public:
|
||||
virtual ~Node() = default;
|
||||
|
@ -380,12 +390,12 @@ protected:
|
|||
|
||||
class Variable : public Expression {
|
||||
public:
|
||||
Variable(StringView variable_name)
|
||||
: m_name(variable_name)
|
||||
Variable(VariableDeclarationRef variable_declaration)
|
||||
: m_variable_declaration(move(variable_declaration))
|
||||
{
|
||||
}
|
||||
|
||||
StringView m_name;
|
||||
VariableDeclarationRef m_variable_declaration;
|
||||
|
||||
protected:
|
||||
void dump_tree(StringBuilder& builder) override;
|
||||
|
|
|
@ -139,7 +139,7 @@ void SlotName::dump_tree(StringBuilder& builder)
|
|||
|
||||
void Variable::dump_tree(StringBuilder& builder)
|
||||
{
|
||||
dump_node(builder, "Var {}", m_name);
|
||||
dump_node(builder, "Var {}", m_variable_declaration->m_name);
|
||||
}
|
||||
|
||||
void FunctionPointer::dump_tree(StringBuilder& builder)
|
||||
|
|
|
@ -4,6 +4,7 @@ set(SOURCES
|
|||
Compiler/FunctionCallCanonicalizationPass.cpp
|
||||
Compiler/GenericASTPass.cpp
|
||||
Compiler/IfBranchMergingPass.cpp
|
||||
Compiler/ReferenceResolvingPass.cpp
|
||||
Parser/Lexer.cpp
|
||||
Parser/ParseError.cpp
|
||||
Parser/SpecParser.cpp
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
|
||||
#include "AST/AST.h"
|
||||
#include "Compiler/ReferenceResolvingPass.h"
|
||||
#include "Function.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
RecursionDecision ReferenceResolvingPass::on_entry(Tree tree)
|
||||
{
|
||||
if (auto binary_operation = as<BinaryOperation>(tree); binary_operation) {
|
||||
if (binary_operation->m_operation != BinaryOperator::Declaration)
|
||||
return RecursionDecision::Recurse;
|
||||
|
||||
if (auto variable_name = as<UnresolvedReference>(binary_operation->m_left); variable_name) {
|
||||
auto name = variable_name->m_name;
|
||||
if (!m_function->m_local_variables.contains(name))
|
||||
m_function->m_local_variables.set(name, make_ref_counted<VariableDeclaration>(name));
|
||||
}
|
||||
}
|
||||
return RecursionDecision::Recurse;
|
||||
}
|
||||
|
||||
void ReferenceResolvingPass::on_leave(Tree tree)
|
||||
{
|
||||
auto& functions = m_function->m_context->m_functions;
|
||||
|
||||
if (auto reference = as<UnresolvedReference>(tree); reference) {
|
||||
auto name = reference->m_name;
|
||||
|
||||
if (name.starts_with("[["sv) && name.ends_with("]]"sv)) {
|
||||
replace_current_node_with(make_ref_counted<SlotName>(name.substring_view(2, name.length() - 4)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto it = m_function->m_local_variables.find(name); it != m_function->m_local_variables.end()) {
|
||||
replace_current_node_with(make_ref_counted<Variable>(it->value));
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto it = functions.find(name); it != functions.end()) {
|
||||
replace_current_node_with(it->value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Compiler/GenericASTPass.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
// ReferenceResolvingPass collects all variable names declared in the function and replaces
|
||||
// UnresolvedReference nodes with either SlotName, Variable, or FunctionPointer nodes.
|
||||
class ReferenceResolvingPass : public GenericASTPass {
|
||||
public:
|
||||
using GenericASTPass::GenericASTPass;
|
||||
|
||||
protected:
|
||||
RecursionDecision on_entry(Tree tree) override;
|
||||
|
||||
void on_leave(Tree tree) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -12,6 +12,8 @@ namespace JSSpecCompiler {
|
|||
|
||||
// AST/AST.h
|
||||
class NodeSubtreePointer;
|
||||
class VariableDeclaration;
|
||||
using VariableDeclarationRef = NonnullRefPtr<VariableDeclaration>;
|
||||
|
||||
class Node;
|
||||
using NullableTree = RefPtr<Node>;
|
||||
|
|
|
@ -13,6 +13,7 @@ Function::Function(ExecutionContext* context, StringView name, Tree ast)
|
|||
: m_context(context)
|
||||
, m_name(name)
|
||||
, m_ast(move(ast))
|
||||
, m_return_value(make_ref_counted<VariableDeclaration>("$return"sv))
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,8 @@ public:
|
|||
ExecutionContext* m_context;
|
||||
StringView m_name;
|
||||
Tree m_ast;
|
||||
VariableDeclarationRef m_return_value;
|
||||
HashMap<StringView, VariableDeclarationRef> m_local_variables;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "Compiler/FunctionCallCanonicalizationPass.h"
|
||||
#include "Compiler/IfBranchMergingPass.h"
|
||||
#include "Compiler/ReferenceResolvingPass.h"
|
||||
#include "Function.h"
|
||||
#include "Parser/SpecParser.h"
|
||||
|
||||
|
@ -20,6 +21,18 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
|
||||
ExecutionContext context;
|
||||
|
||||
// Functions referenced in DifferenceISODate
|
||||
// TODO: This is here just for testing. In a long run, we need some place, which is not
|
||||
// `serenity_main`, to store built-in functions.
|
||||
auto& functions = context.m_functions;
|
||||
functions.set("CompareISODate"sv, make_ref_counted<FunctionPointer>("CompareISODate"sv));
|
||||
functions.set("CreateDateDurationRecord"sv, make_ref_counted<FunctionPointer>("CreateDateDurationRecord"sv));
|
||||
functions.set("AddISODate"sv, make_ref_counted<FunctionPointer>("AddISODate"sv));
|
||||
functions.set("ISODaysInMonth"sv, make_ref_counted<FunctionPointer>("ISODaysInMonth"sv));
|
||||
functions.set("ISODateToEpochDays"sv, make_ref_counted<FunctionPointer>("ISODateToEpochDays"sv));
|
||||
functions.set("truncate"sv, make_ref_counted<FunctionPointer>("truncate"sv));
|
||||
functions.set("remainder"sv, make_ref_counted<FunctionPointer>("remainder"sv));
|
||||
|
||||
auto input = TRY(TRY(Core::File::standard_input())->read_until_eof());
|
||||
XML::Parser parser { StringView(input.bytes()) };
|
||||
|
||||
|
@ -39,8 +52,12 @@ ErrorOr<int> serenity_main(Main::Arguments)
|
|||
|
||||
auto function = make_ref_counted<JSSpecCompiler::Function>(&context, spec_function.m_name, spec_function.m_algorithm.m_tree);
|
||||
|
||||
for (auto const& argument : spec_function.m_arguments)
|
||||
function->m_local_variables.set(argument.name, make_ref_counted<VariableDeclaration>(argument.name));
|
||||
|
||||
FunctionCallCanonicalizationPass(function).run();
|
||||
IfBranchMergingPass(function).run();
|
||||
ReferenceResolvingPass(function).run();
|
||||
|
||||
out("{}", function->m_ast);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue