mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:07:35 +00:00
JSSpecCompiler: Move passes to Passes subdirectory of Compiler/
This commit is contained in:
parent
61fa00d46c
commit
867ce0df52
8 changed files with 9 additions and 9 deletions
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "Compiler/Passes/FunctionCallCanonicalizationPass.h"
|
||||
#include "AST/AST.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
RecursionDecision FunctionCallCanonicalizationPass::on_entry(Tree tree)
|
||||
{
|
||||
if (auto binary_operation = as<BinaryOperation>(tree); binary_operation) {
|
||||
if (binary_operation->m_operation == BinaryOperator::FunctionCall) {
|
||||
Vector<Tree> arguments;
|
||||
|
||||
auto current_tree = binary_operation->m_right;
|
||||
while (true) {
|
||||
auto argument_tree = as<BinaryOperation>(current_tree);
|
||||
if (!argument_tree || argument_tree->m_operation != BinaryOperator::Comma)
|
||||
break;
|
||||
arguments.append(argument_tree->m_left);
|
||||
current_tree = argument_tree->m_right;
|
||||
}
|
||||
arguments.append(current_tree);
|
||||
|
||||
replace_current_node_with(make_ref_counted<FunctionCall>(binary_operation->m_left, move(arguments)));
|
||||
}
|
||||
}
|
||||
return RecursionDecision::Recurse;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Compiler/GenericASTPass.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
// FunctionCallCanonicalizationPass simplifies ladders of BinaryOperators nodes in the function call
|
||||
// arguments into nice and neat FunctionCall nodes.
|
||||
//
|
||||
// Ladders initially appear since I do not want to complicate expression parser, so it interprets
|
||||
// `f(a, b, c, d)` as `f "function_call_operator" (a, (b, (c, d))))`.
|
||||
class FunctionCallCanonicalizationPass : public GenericASTPass {
|
||||
public:
|
||||
using GenericASTPass::GenericASTPass;
|
||||
|
||||
protected:
|
||||
RecursionDecision on_entry(Tree tree) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
|
||||
#include "AST/AST.h"
|
||||
#include "Compiler/Passes/IfBranchMergingPass.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
RecursionDecision IfBranchMergingPass::on_entry(Tree tree)
|
||||
{
|
||||
if (auto list = as<TreeList>(tree); list) {
|
||||
Vector<Tree> result;
|
||||
Vector<Tree> unmerged_branches;
|
||||
|
||||
auto merge_if_needed = [&] {
|
||||
if (!unmerged_branches.is_empty()) {
|
||||
result.append(merge_branches(unmerged_branches));
|
||||
unmerged_branches.clear();
|
||||
}
|
||||
};
|
||||
|
||||
for (auto const& node : list->m_trees) {
|
||||
if (is<IfBranch>(node.ptr())) {
|
||||
merge_if_needed();
|
||||
unmerged_branches.append(node);
|
||||
} else if (is<ElseIfBranch>(node.ptr())) {
|
||||
unmerged_branches.append(node);
|
||||
} else {
|
||||
merge_if_needed();
|
||||
result.append(node);
|
||||
}
|
||||
}
|
||||
merge_if_needed();
|
||||
|
||||
list->m_trees = move(result);
|
||||
}
|
||||
return RecursionDecision::Recurse;
|
||||
}
|
||||
|
||||
Tree IfBranchMergingPass::merge_branches(Vector<Tree> const& unmerged_branches)
|
||||
{
|
||||
static const Tree error = make_ref_counted<ErrorNode>("Cannot make sense of if-elseif-else chain"sv);
|
||||
|
||||
VERIFY(unmerged_branches.size() >= 1);
|
||||
|
||||
Vector<Tree> conditions;
|
||||
Vector<Tree> branches;
|
||||
NullableTree else_branch;
|
||||
|
||||
if (auto if_branch = as<IfBranch>(unmerged_branches[0]); if_branch) {
|
||||
conditions.append(if_branch->m_condition);
|
||||
branches.append(if_branch->m_branch);
|
||||
} else {
|
||||
return error;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < unmerged_branches.size(); ++i) {
|
||||
auto branch = as<ElseIfBranch>(unmerged_branches[i]);
|
||||
|
||||
if (!branch)
|
||||
return error;
|
||||
|
||||
if (!branch->m_condition) {
|
||||
// There might be situation like:
|
||||
// 1. If <condition>, then
|
||||
// ...
|
||||
// 2. Else,
|
||||
// a. If <condition>, then
|
||||
// ...
|
||||
// 3. Else,
|
||||
// ...
|
||||
auto substep_list = as<TreeList>(branch->m_branch);
|
||||
if (substep_list && substep_list->m_trees.size() == 1) {
|
||||
if (auto nested_if = as<IfBranch>(substep_list->m_trees[0]); nested_if)
|
||||
branch = make_ref_counted<ElseIfBranch>(nested_if->m_condition, nested_if->m_branch);
|
||||
}
|
||||
}
|
||||
|
||||
if (branch->m_condition) {
|
||||
conditions.append(branch->m_condition.release_nonnull());
|
||||
branches.append(branch->m_branch);
|
||||
} else {
|
||||
if (i + 1 != unmerged_branches.size())
|
||||
return error;
|
||||
else_branch = branch->m_branch;
|
||||
}
|
||||
}
|
||||
|
||||
return make_ref_counted<IfElseIfChain>(move(conditions), move(branches), else_branch);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Compiler/GenericASTPass.h"
|
||||
|
||||
namespace JSSpecCompiler {
|
||||
|
||||
// IfBranchMergingPass, unsurprisingly, merges if-elseif-else chains, represented as a separate
|
||||
// nodes after parsing, into one IfElseIfChain node. It also deals with the following nonsense from
|
||||
// the spec:
|
||||
// ```
|
||||
// 1. If <condition>, then
|
||||
// ...
|
||||
// 2. Else,
|
||||
// a. If <condition>, then
|
||||
// ...
|
||||
// 3. Else,
|
||||
// ...
|
||||
// ```
|
||||
class IfBranchMergingPass : public GenericASTPass {
|
||||
public:
|
||||
using GenericASTPass::GenericASTPass;
|
||||
|
||||
protected:
|
||||
RecursionDecision on_entry(Tree tree) override;
|
||||
|
||||
private:
|
||||
static Tree merge_branches(Vector<Tree> const& unmerged_branches);
|
||||
};
|
||||
|
||||
}
|
|
@ -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/Passes/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_translation_unit->function_index;
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue