diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h new file mode 100644 index 0000000000..77df78963f --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/AST.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +#include "Forward.h" + +namespace JSSpecCompiler { + +template +RefPtr as(NullableTree const& tree) +{ + return dynamic_cast(tree.ptr()); +} + +// ===== Generic nodes ===== +class Node : public RefCounted { +public: + virtual ~Node() = default; + + void format_tree(StringBuilder& builder); + + virtual bool is_type() { return false; } + +protected: + template + void dump_node(StringBuilder& builder, AK::CheckedFormatString&& fmtstr, Parameters const&... parameters); + + virtual void dump_tree(StringBuilder& builder) = 0; +}; + +class ErrorNode : public Node { +public: + ErrorNode() { } + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +inline Tree const error_tree = make_ref_counted(); + +// ===== Concrete evaluatable nodes ===== +class MathematicalConstant : public Node { +public: + MathematicalConstant(i64 number) + : m_number(number) + { + } + + // TODO: This should be able to hold arbitrary number + i64 m_number; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class StringLiteral : public Node { +public: + StringLiteral(StringView literal) + : m_literal(literal) + { + } + + StringView m_literal; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +#define ENUMERATE_UNARY_OPERATORS(F) \ + F(Invalid) \ + F(Minus) \ + F(AssertCompletion) + +#define ENUMERATE_BINARY_OPERATORS(F) \ + F(Invalid) \ + F(CompareLess) \ + F(CompareGreater) \ + F(CompareNotEqual) \ + F(CompareEqual) \ + F(Assignment) \ + F(Declaration) \ + F(Plus) \ + F(Minus) \ + F(Multiplication) \ + F(Division) \ + F(Comma) \ + F(MemberAccess) \ + F(FunctionCall) \ + F(ArraySubscript) + +#define NAME(name) name, +#define STRINGIFY(name) #name##sv, + +enum class UnaryOperator { + ENUMERATE_UNARY_OPERATORS(NAME) +}; + +inline constexpr StringView unary_operator_names[] = { + ENUMERATE_UNARY_OPERATORS(STRINGIFY) +}; + +enum class BinaryOperator { +#define NAME(name) name, + ENUMERATE_BINARY_OPERATORS(NAME) +}; + +inline constexpr StringView binary_operator_names[] = { + ENUMERATE_BINARY_OPERATORS(STRINGIFY) +}; + +#undef NAME +#undef STRINGIFY + +class BinaryOperation : public Node { +public: + BinaryOperation(BinaryOperator operation, Tree left, Tree right) + : m_operation(operation) + , m_left(left) + , m_right(right) + { + } + + BinaryOperator m_operation; + Tree m_left; + Tree m_right; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class UnaryOperation : public Node { +public: + UnaryOperation(UnaryOperator operation, Tree operand) + : m_operation(operation) + , m_operand(operand) + { + } + + UnaryOperator m_operation; + Tree m_operand; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class IsOneOfOperation : public Node { +public: + IsOneOfOperation(Tree operand, Vector&& compare_values) + : m_operand(operand) + , m_compare_values(move(compare_values)) + { + } + + Tree m_operand; + Vector m_compare_values; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class UnresolvedReference : public Node { +public: + UnresolvedReference(StringView name) + : m_name(name) + { + } + + StringView m_name; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class ReturnExpression : public Node { +public: + ReturnExpression(Tree return_value) + : m_return_value(return_value) + { + } + + Tree m_return_value; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class AssertExpression : public Node { +public: + AssertExpression(Tree condition) + : m_condition(condition) + { + } + + Tree m_condition; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class IfBranch : public Node { +public: + IfBranch(Tree condition, Tree branch) + : m_condition(condition) + , m_branch(branch) + { + } + + Tree m_condition; + Tree m_branch; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class ElseIfBranch : public Node { +public: + ElseIfBranch(Optional condition, Tree branch) + : m_condition(condition) + , m_branch(branch) + { + } + + Optional m_condition; + Tree m_branch; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class TreeList : public Node { +public: + TreeList(Vector&& expressions_) + : m_expressions(move(expressions_)) + { + } + + Vector m_expressions; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class RecordDirectListInitialization : public Node { +public: + struct Argument { + Tree name; + Tree value; + }; + + RecordDirectListInitialization(Tree type_reference, Vector&& arguments) + : m_type_reference(type_reference) + , m_arguments(move(arguments)) + { + } + + Tree m_type_reference; + Vector m_arguments; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class FunctionCall : public Node { +public: + FunctionCall(Tree name, Vector&& arguments) + : m_name(name) + , m_arguments(move(arguments)) + { + } + + Tree m_name; + Vector m_arguments; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class SlotName : public Node { +public: + SlotName(StringView member_name) + : m_member_name(member_name) + { + } + + StringView m_member_name; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class Variable : public Node { +public: + Variable(StringView variable_name) + : m_name(variable_name) + { + } + + StringView m_name; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +class FunctionPointer : public Node { +public: + FunctionPointer(StringView function_name) + : m_function_name(function_name) + { + } + + StringView m_function_name; + +protected: + void dump_tree(StringBuilder& builder) override; +}; + +} + +namespace AK { + +template<> +struct Formatter : Formatter { + ErrorOr format(FormatBuilder& builder, JSSpecCompiler::Tree const& tree) + { + tree->format_tree(builder.builder()); + return {}; + } +}; + +} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp new file mode 100644 index 0000000000..32dd6a1c8e --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/AST/ASTPrinting.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include "AST/AST.h" + +namespace JSSpecCompiler { + +void Node::format_tree(StringBuilder& builder) +{ + static int current_depth = -1; + TemporaryChange depth_change(current_depth, current_depth + 1); + builder.append_repeated(' ', current_depth * 2); + dump_tree(builder); +} + +template +void Node::dump_node(StringBuilder& builder, AK::CheckedFormatString&& fmtstr, Parameters const&... parameters) +{ + builder.append("<"sv); + AK::VariadicFormatParams variadic_format_params { parameters... }; + MUST(AK::vformat(builder, fmtstr.view(), variadic_format_params)); + builder.append(">\n"sv); +} + +void ErrorNode::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "Error"); +} + +void MathematicalConstant::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "MathematicalConstant {}", m_number); +} + +void StringLiteral::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "StringLiteral {}", m_literal); +} + +void BinaryOperation::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "BinaryOperation {}", binary_operator_names[to_underlying(m_operation)]); + m_left->format_tree(builder); + m_right->format_tree(builder); +} + +void UnaryOperation::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "UnaryOperation {}", unary_operator_names[to_underlying(m_operation)]); + m_operand->format_tree(builder); +} + +void IsOneOfOperation::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "IsOneOf"); + m_operand->format_tree(builder); + for (auto const& compare_value : m_compare_values) + compare_value->format_tree(builder); +} + +void UnresolvedReference::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "UnresolvedReference {}", m_name); +} + +void ReturnExpression::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "ReturnExpression"); + m_return_value->format_tree(builder); +} + +void AssertExpression::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "AssertExpression"); + m_condition->format_tree(builder); +} + +void IfBranch::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "IfBranch"); + m_condition->format_tree(builder); + m_branch->format_tree(builder); +} + +void ElseIfBranch::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "ElseIfBranch {}", m_condition.has_value() ? "ElseIf" : "Else"); + if (m_condition.has_value()) + (*m_condition)->format_tree(builder); + m_branch->format_tree(builder); +} + +void TreeList::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "TreeList"); + for (auto const& expression : m_expressions) + expression->format_tree(builder); +} + +void RecordDirectListInitialization::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "RecordDirectListInitialization"); + m_type_reference->format_tree(builder); + for (auto const& argument : m_arguments) + builder.appendff("{}{}", argument.name, argument.value); +} + +void FunctionCall::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "FunctionCall"); + m_name->format_tree(builder); + for (auto const& argument : m_arguments) + argument->format_tree(builder); +} + +void SlotName::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "Slot {}", m_member_name); +} + +void Variable::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "Var {}", m_name); +} + +void FunctionPointer::dump_tree(StringBuilder& builder) +{ + dump_node(builder, "Func {}", m_function_name); +} + +} diff --git a/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h new file mode 100644 index 0000000000..50da4f2b1c --- /dev/null +++ b/Meta/Lagom/Tools/CodeGenerators/JSSpecCompiler/Forward.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, Dan Klishch + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace JSSpecCompiler { + +// AST/AST.h +class NodeSubtreePointer; + +class Node; +using NullableTree = RefPtr; +using Tree = NonnullRefPtr; +class ErrorNode; + +class ScopedBlock; +class MathematicalConstant; +class StringLiteral; +class BinaryOperation; +class UnaryOperation; +class IsOneOfOperation; +class UnresolvedReference; +class ReturnExpression; +class AssertExpression; +class IfBranch; +class ElseIfBranch; +class TreeList; +class RecordDirectListInitialization; +class FunctionCall; +class SlotName; +class Variable; +class FunctionPointer; + +}