CppASTConverter.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * Copyright (c) 2023, Dan Klishch <danilklishch@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibCore/File.h>
  7. #include "Function.h"
  8. #include "Parser/CppASTConverter.h"
  9. #include "Parser/SpecificationParsing.h"
  10. namespace JSSpecCompiler {
  11. NonnullRefPtr<FunctionDefinition> CppASTConverter::convert()
  12. {
  13. StringView name = m_function->name()->full_name();
  14. Vector<Tree> toplevel_statements;
  15. for (auto const& statement : m_function->definition()->statements()) {
  16. auto maybe_tree = as_nullable_tree(statement);
  17. if (maybe_tree)
  18. toplevel_statements.append(maybe_tree.release_nonnull());
  19. }
  20. auto tree = make_ref_counted<TreeList>(move(toplevel_statements));
  21. Vector<FunctionArgument> arguments;
  22. for (auto const& parameter : m_function->parameters())
  23. arguments.append({ .name = parameter->full_name() });
  24. return make_ref_counted<FunctionDefinition>(
  25. AbstractOperationDeclaration {
  26. .name = MUST(FlyString::from_utf8(name)),
  27. .arguments = move(arguments),
  28. },
  29. Location {},
  30. tree);
  31. }
  32. template<>
  33. NullableTree CppASTConverter::convert_node(Cpp::VariableDeclaration const& variable_declaration)
  34. {
  35. static Tree variable_declaration_present_error
  36. = make_ref_counted<ErrorNode>("Encountered variable declaration with initial value"sv);
  37. if (variable_declaration.initial_value() != nullptr)
  38. return variable_declaration_present_error;
  39. return nullptr;
  40. }
  41. template<>
  42. NullableTree CppASTConverter::convert_node(Cpp::ReturnStatement const& return_statement)
  43. {
  44. return make_ref_counted<ReturnNode>(as_tree(return_statement.value()));
  45. }
  46. template<>
  47. NullableTree CppASTConverter::convert_node(Cpp::FunctionCall const& function_call)
  48. {
  49. Vector<Tree> arguments;
  50. for (auto const& argument : function_call.arguments())
  51. arguments.append(as_tree(argument));
  52. return make_ref_counted<FunctionCall>(as_tree(function_call.callee()), move(arguments));
  53. }
  54. template<>
  55. NullableTree CppASTConverter::convert_node(Cpp::Name const& name)
  56. {
  57. return make_ref_counted<UnresolvedReference>(name.full_name());
  58. }
  59. template<>
  60. NullableTree CppASTConverter::convert_node(Cpp::IfStatement const& if_statement)
  61. {
  62. // NOTE: This is so complicated since we probably want to test IfBranchMergingPass, which
  63. // expects standalone `IfBranch` and `ElseIfBranch` nodes.
  64. Vector<Tree> trees;
  65. Cpp::IfStatement const* current = &if_statement;
  66. while (true) {
  67. auto predicate = as_tree(current->predicate());
  68. auto then_branch = as_possibly_empty_tree(current->then_statement());
  69. if (trees.is_empty())
  70. trees.append(make_ref_counted<IfBranch>(predicate, then_branch));
  71. else
  72. trees.append(make_ref_counted<ElseIfBranch>(predicate, then_branch));
  73. auto else_statement = dynamic_cast<Cpp::IfStatement const*>(current->else_statement());
  74. if (else_statement)
  75. current = else_statement;
  76. else
  77. break;
  78. }
  79. auto else_statement = current->else_statement();
  80. if (else_statement)
  81. trees.append(make_ref_counted<ElseIfBranch>(
  82. nullptr, as_possibly_empty_tree(else_statement)));
  83. return make_ref_counted<TreeList>(move(trees));
  84. }
  85. template<>
  86. NullableTree CppASTConverter::convert_node(Cpp::BlockStatement const& block)
  87. {
  88. Vector<Tree> statements;
  89. for (auto const& statement : block.statements()) {
  90. auto maybe_tree = as_nullable_tree(statement);
  91. if (maybe_tree)
  92. statements.append(maybe_tree.release_nonnull());
  93. }
  94. return make_ref_counted<TreeList>(move(statements));
  95. }
  96. template<>
  97. NullableTree CppASTConverter::convert_node(Cpp::AssignmentExpression const& assignment)
  98. {
  99. // NOTE: Later stages of the compilation process basically treat `BinaryOperator::Declaration`
  100. // the same as `BinaryOperator::Assignment`, so variable shadowing is impossible. The only
  101. // difference in their semantics is that "declarations" define names of local variables.
  102. // Since we are effectively ignoring actual C++ variable declarations, we need to define
  103. // locals somewhere else. Using "declarations" instead of "assignments" here does this job
  104. // cleanly.
  105. return make_ref_counted<BinaryOperation>(
  106. BinaryOperator::Declaration, as_tree(assignment.lhs()), as_tree(assignment.rhs()));
  107. }
  108. template<>
  109. NullableTree CppASTConverter::convert_node(Cpp::NumericLiteral const& literal)
  110. {
  111. // TODO: Numerical literals are not limited to i64.
  112. VERIFY(literal.value().to_number<i64>().has_value());
  113. return make_ref_counted<MathematicalConstant>(MUST(Crypto::BigFraction::from_string(literal.value())));
  114. }
  115. template<>
  116. NullableTree CppASTConverter::convert_node(Cpp::StringLiteral const& literal)
  117. {
  118. return make_ref_counted<StringLiteral>(literal.value());
  119. }
  120. template<>
  121. NullableTree CppASTConverter::convert_node(Cpp::BinaryExpression const& expression)
  122. {
  123. static constexpr auto operator_translation = []() consteval {
  124. Array<BinaryOperator, to_underlying(Cpp::BinaryOp::Arrow) + 1> table;
  125. #define ASSIGN_TRANSLATION(cpp_name, our_name) \
  126. table[to_underlying(Cpp::BinaryOp::cpp_name)] = BinaryOperator::our_name
  127. ASSIGN_TRANSLATION(Addition, Plus);
  128. ASSIGN_TRANSLATION(Subtraction, Minus);
  129. ASSIGN_TRANSLATION(Multiplication, Multiplication);
  130. ASSIGN_TRANSLATION(Division, Division);
  131. ASSIGN_TRANSLATION(Modulo, Invalid);
  132. ASSIGN_TRANSLATION(GreaterThan, CompareGreater);
  133. ASSIGN_TRANSLATION(GreaterThanEquals, Invalid);
  134. ASSIGN_TRANSLATION(LessThan, CompareLess);
  135. ASSIGN_TRANSLATION(LessThanEquals, Invalid);
  136. ASSIGN_TRANSLATION(BitwiseAnd, Invalid);
  137. ASSIGN_TRANSLATION(BitwiseOr, Invalid);
  138. ASSIGN_TRANSLATION(BitwiseXor, Invalid);
  139. ASSIGN_TRANSLATION(LeftShift, Invalid);
  140. ASSIGN_TRANSLATION(RightShift, Invalid);
  141. ASSIGN_TRANSLATION(EqualsEquals, CompareEqual);
  142. ASSIGN_TRANSLATION(NotEqual, CompareNotEqual);
  143. ASSIGN_TRANSLATION(LogicalOr, Invalid);
  144. ASSIGN_TRANSLATION(LogicalAnd, Invalid);
  145. ASSIGN_TRANSLATION(Arrow, Invalid);
  146. #undef ASSIGN_TRANSLATION
  147. return table;
  148. }();
  149. auto translated_operator = operator_translation[to_underlying(expression.op())];
  150. // TODO: Print nicer error.
  151. VERIFY(translated_operator != BinaryOperator::Invalid);
  152. return make_ref_counted<BinaryOperation>(translated_operator, as_tree(expression.lhs()), as_tree(expression.rhs()));
  153. }
  154. NullableTree CppASTConverter::as_nullable_tree(Cpp::Statement const* statement)
  155. {
  156. static Tree unknown_ast_node_error
  157. = make_ref_counted<ErrorNode>("Encountered unknown C++ AST node"sv);
  158. Optional<NullableTree> result;
  159. auto dispatch_convert_if_one_of = [&]<typename... Ts> {
  160. (([&]<typename T> {
  161. if (result.has_value())
  162. return;
  163. auto casted_ptr = dynamic_cast<T const*>(statement);
  164. if (casted_ptr != nullptr)
  165. result = convert_node<T>(*casted_ptr);
  166. }).template operator()<Ts>(),
  167. ...);
  168. };
  169. dispatch_convert_if_one_of.operator()<
  170. Cpp::VariableDeclaration,
  171. Cpp::ReturnStatement,
  172. Cpp::FunctionCall,
  173. Cpp::Name,
  174. Cpp::IfStatement,
  175. Cpp::BlockStatement,
  176. Cpp::AssignmentExpression,
  177. Cpp::NumericLiteral,
  178. Cpp::StringLiteral,
  179. Cpp::BinaryExpression>();
  180. if (result.has_value())
  181. return *result;
  182. return unknown_ast_node_error;
  183. }
  184. Tree CppASTConverter::as_tree(Cpp::Statement const* statement)
  185. {
  186. static Tree empty_tree_error
  187. = make_ref_counted<ErrorNode>("AST conversion unexpectedly produced empty tree"sv);
  188. auto result = as_nullable_tree(statement);
  189. if (result)
  190. return result.release_nonnull();
  191. return empty_tree_error;
  192. }
  193. Tree CppASTConverter::as_possibly_empty_tree(Cpp::Statement const* statement)
  194. {
  195. auto result = as_nullable_tree(statement);
  196. if (result)
  197. return result.release_nonnull();
  198. return make_ref_counted<TreeList>(Vector<Tree> {});
  199. }
  200. CppParsingStep::CppParsingStep()
  201. : CompilationStep("parser"sv)
  202. {
  203. }
  204. CppParsingStep::~CppParsingStep() = default;
  205. void CppParsingStep::run(TranslationUnitRef translation_unit)
  206. {
  207. auto filename = translation_unit->filename();
  208. auto file = Core::File::open_file_or_standard_stream(filename, Core::File::OpenMode::Read).release_value_but_fixme_should_propagate_errors();
  209. m_input = file->read_until_eof().release_value_but_fixme_should_propagate_errors();
  210. Cpp::Preprocessor preprocessor { filename, m_input };
  211. m_parser = adopt_own_if_nonnull(new Cpp::Parser { preprocessor.process_and_lex(), filename });
  212. auto cpp_translation_unit = m_parser->parse();
  213. VERIFY(m_parser->errors().is_empty());
  214. for (auto const& declaration : cpp_translation_unit->declarations()) {
  215. if (declaration->is_function()) {
  216. auto const* cpp_function = AK::verify_cast<Cpp::FunctionDeclaration>(declaration.ptr());
  217. translation_unit->adopt_function(CppASTConverter(cpp_function).convert());
  218. }
  219. }
  220. }
  221. }