JSSpecCompiler: Add function call canonicalization pass

It simplifies ladders of BinaryOperators nodes in the function call
arguments into nice and neat FunctionCall node. 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))))`.
This commit is contained in:
Dan Klishch 2023-08-18 13:12:53 -04:00 committed by Andrew Kaster
parent 1c4cd34320
commit 72794e7843
Notes: sideshowbarker 2024-07-17 01:04:03 +09:00
4 changed files with 71 additions and 2 deletions

View file

@ -1,6 +1,7 @@
set(SOURCES
AST/AST.cpp
AST/ASTPrinting.cpp
Compiler/FunctionCallCanonicalizationPass.cpp
Compiler/GenericASTPass.cpp
Parser/Lexer.cpp
Parser/ParseError.cpp

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Compiler/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;
}
}

View file

@ -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;
};
}

View file

@ -9,12 +9,16 @@
#include <LibMain/Main.h>
#include <LibXML/Parser/Parser.h>
#include "Compiler/FunctionCallCanonicalizationPass.h"
#include "Function.h"
#include "Parser/SpecParser.h"
ErrorOr<int> serenity_main(Main::Arguments)
{
using namespace JSSpecCompiler;
ExecutionContext context;
auto input = TRY(TRY(Core::File::standard_input())->read_until_eof());
XML::Parser parser { StringView(input.bytes()) };
@ -30,8 +34,12 @@ ErrorOr<int> serenity_main(Main::Arguments)
outln("{}", maybe_function.error()->to_string());
return 1;
}
auto function = maybe_function.value();
auto spec_function = maybe_function.value();
out("{}", function.m_algorithm.m_tree);
auto function = make_ref_counted<JSSpecCompiler::Function>(&context, spec_function.m_name, spec_function.m_algorithm.m_tree);
FunctionCallCanonicalizationPass(function).run();
out("{}", function->m_ast);
return 0;
}