// Part of the Carbon Language project, under the Apache License v2.0 with LLVM // Exceptions. See /LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include "executable_semantics/fuzzing/ast_to_proto.h" #include #include "executable_semantics/ast/declaration.h" #include "executable_semantics/ast/expression.h" #include "llvm/Support/Casting.h" namespace Carbon { using ::llvm::cast; static auto ExpressionToProto(const Expression& expression) -> Fuzzing::Expression; static auto PatternToProto(const Pattern& pattern) -> Fuzzing::Pattern; static auto StatementToProto(const Statement& statement) -> Fuzzing::Statement; static auto DeclarationToProto(const Declaration& declaration) -> Fuzzing::Declaration; static auto LibraryNameToProto(const LibraryName& library_name) -> Fuzzing::LibraryName { Fuzzing::LibraryName library_name_proto; library_name_proto.set_package_name(library_name.package); if (!library_name.path.empty()) { library_name_proto.set_path(library_name.path); } return library_name_proto; } static auto OperatorToProtoEnum(const Operator op) -> Fuzzing::PrimitiveOperatorExpression::Operator { switch (op) { case Operator::AddressOf: return Fuzzing::PrimitiveOperatorExpression::AddressOf; case Operator::Deref: return Fuzzing::PrimitiveOperatorExpression::Deref; case Operator::Neg: return Fuzzing::PrimitiveOperatorExpression::Neg; case Operator::Not: return Fuzzing::PrimitiveOperatorExpression::Not; case Operator::Ptr: return Fuzzing::PrimitiveOperatorExpression::Ptr; case Operator::Add: return Fuzzing::PrimitiveOperatorExpression::Add; case Operator::And: return Fuzzing::PrimitiveOperatorExpression::And; case Operator::Eq: return Fuzzing::PrimitiveOperatorExpression::Eq; case Operator::Mul: return Fuzzing::PrimitiveOperatorExpression::Mul; case Operator::Or: return Fuzzing::PrimitiveOperatorExpression::Or; case Operator::Sub: return Fuzzing::PrimitiveOperatorExpression::Sub; } } static auto FieldInitializerToProto(const FieldInitializer& field) -> Fuzzing::FieldInitializer { Fuzzing::FieldInitializer field_proto; field_proto.set_name(field.name()); *field_proto.mutable_expression() = ExpressionToProto(field.expression()); return field_proto; } static auto TupleLiteralExpressionToProto(const TupleLiteral& tuple_literal) -> Fuzzing::TupleLiteralExpression { Fuzzing::TupleLiteralExpression tuple_literal_proto; for (Nonnull field : tuple_literal.fields()) { *tuple_literal_proto.add_fields() = ExpressionToProto(*field); } return tuple_literal_proto; } static auto ExpressionToProto(const Expression& expression) -> Fuzzing::Expression { Fuzzing::Expression expression_proto; switch (expression.kind()) { case ExpressionKind::InstantiateImpl: { // UNDER CONSTRUCTION break; } case ExpressionKind::CallExpression: { const auto& call = cast(expression); auto* call_proto = expression_proto.mutable_call(); *call_proto->mutable_function() = ExpressionToProto(call.function()); *call_proto->mutable_argument() = ExpressionToProto(call.argument()); break; } case ExpressionKind::FunctionTypeLiteral: { const auto& fun_type = cast(expression); auto* fun_type_proto = expression_proto.mutable_function_type(); *fun_type_proto->mutable_parameter() = ExpressionToProto(fun_type.parameter()); *fun_type_proto->mutable_return_type() = ExpressionToProto(fun_type.return_type()); break; } case ExpressionKind::FieldAccessExpression: { const auto& field_access = cast(expression); auto* field_access_proto = expression_proto.mutable_field_access(); field_access_proto->set_field(field_access.field()); *field_access_proto->mutable_aggregate() = ExpressionToProto(field_access.aggregate()); break; } case ExpressionKind::IndexExpression: { const auto& index = cast(expression); auto* index_proto = expression_proto.mutable_index(); *index_proto->mutable_aggregate() = ExpressionToProto(index.aggregate()); *index_proto->mutable_offset() = ExpressionToProto(index.offset()); break; } case ExpressionKind::PrimitiveOperatorExpression: { const auto& primitive_operator = cast(expression); auto* operator_proto = expression_proto.mutable_primitive_operator(); operator_proto->set_op(OperatorToProtoEnum(primitive_operator.op())); for (Nonnull arg : primitive_operator.arguments()) { *operator_proto->add_arguments() = ExpressionToProto(*arg); } break; } case ExpressionKind::TupleLiteral: *expression_proto.mutable_tuple_literal() = TupleLiteralExpressionToProto(cast(expression)); break; case ExpressionKind::StructLiteral: { const auto& struct_literal = cast(expression); auto* struct_literal_proto = expression_proto.mutable_struct_literal(); for (const FieldInitializer& field : struct_literal.fields()) { *struct_literal_proto->add_fields() = FieldInitializerToProto(field); } break; } case ExpressionKind::StructTypeLiteral: { const auto& struct_type_literal = cast(expression); auto* struct_type_literal_proto = expression_proto.mutable_struct_type_literal(); for (const FieldInitializer& field : struct_type_literal.fields()) { *struct_type_literal_proto->add_fields() = FieldInitializerToProto(field); } break; } case ExpressionKind::IdentifierExpression: { const auto& identifier = cast(expression); auto* identifier_proto = expression_proto.mutable_identifier(); identifier_proto->set_name(identifier.name()); break; } case ExpressionKind::IntrinsicExpression: { const auto& intrinsic = cast(expression); auto* intrinsic_proto = expression_proto.mutable_intrinsic(); switch (intrinsic.intrinsic()) { case IntrinsicExpression::Intrinsic::Print: intrinsic_proto->set_intrinsic(Fuzzing::IntrinsicExpression::Print); break; } *intrinsic_proto->mutable_argument() = TupleLiteralExpressionToProto(intrinsic.args()); break; } case ExpressionKind::IfExpression: { const auto& if_expression = cast(expression); auto* if_proto = expression_proto.mutable_if_expression(); *if_proto->mutable_condition() = ExpressionToProto(if_expression.condition()); *if_proto->mutable_then_expression() = ExpressionToProto(if_expression.then_expression()); *if_proto->mutable_else_expression() = ExpressionToProto(if_expression.else_expression()); break; } case ExpressionKind::BoolTypeLiteral: expression_proto.mutable_bool_type_literal(); break; case ExpressionKind::BoolLiteral: expression_proto.mutable_bool_literal()->set_value( cast(expression).value()); break; case ExpressionKind::IntTypeLiteral: expression_proto.mutable_int_type_literal(); break; case ExpressionKind::IntLiteral: expression_proto.mutable_int_literal()->set_value( cast(expression).value()); break; case ExpressionKind::StringLiteral: expression_proto.mutable_string_literal()->set_value( cast(expression).value()); break; case ExpressionKind::StringTypeLiteral: expression_proto.mutable_string_type_literal(); break; case ExpressionKind::ContinuationTypeLiteral: expression_proto.mutable_continuation_type_literal(); break; case ExpressionKind::TypeTypeLiteral: expression_proto.mutable_type_type_literal(); break; case ExpressionKind::UnimplementedExpression: expression_proto.mutable_unimplemented_expression(); break; case ExpressionKind::ArrayTypeLiteral: { const auto& array_literal = cast(expression); Fuzzing::ArrayTypeLiteral* array_literal_proto = expression_proto.mutable_array_type_literal(); *array_literal_proto->mutable_element_type() = ExpressionToProto(array_literal.element_type_expression()); *array_literal_proto->mutable_size() = ExpressionToProto(array_literal.size_expression()); break; } } return expression_proto; } static auto BindingPatternToProto(const BindingPattern& pattern) -> Fuzzing::BindingPattern { Fuzzing::BindingPattern pattern_proto; pattern_proto.set_name(pattern.name()); *pattern_proto.mutable_type() = PatternToProto(pattern.type()); return pattern_proto; } static auto GenericBindingToProto(const GenericBinding& binding) -> Fuzzing::GenericBinding { Fuzzing::GenericBinding binding_proto; binding_proto.set_name(binding.name()); *binding_proto.mutable_type() = ExpressionToProto(binding.type()); return binding_proto; } static auto TuplePatternToProto(const TuplePattern& tuple_pattern) -> Fuzzing::TuplePattern { Fuzzing::TuplePattern tuple_pattern_proto; for (Nonnull field : tuple_pattern.fields()) { *tuple_pattern_proto.add_fields() = PatternToProto(*field); } return tuple_pattern_proto; } static auto PatternToProto(const Pattern& pattern) -> Fuzzing::Pattern { Fuzzing::Pattern pattern_proto; switch (pattern.kind()) { case PatternKind::GenericBinding: { const auto& binding = cast(pattern); *pattern_proto.mutable_generic_binding() = GenericBindingToProto(binding); break; } case PatternKind::BindingPattern: { const auto& binding = cast(pattern); *pattern_proto.mutable_binding_pattern() = BindingPatternToProto(binding); break; } case PatternKind::TuplePattern: *pattern_proto.mutable_tuple_pattern() = TuplePatternToProto(cast(pattern)); break; case PatternKind::AlternativePattern: { const auto& alternative = cast(pattern); auto* alternative_proto = pattern_proto.mutable_alternative_pattern(); alternative_proto->set_alternative_name(alternative.alternative_name()); *alternative_proto->mutable_choice_type() = ExpressionToProto(alternative.choice_type()); *alternative_proto->mutable_arguments() = TuplePatternToProto(alternative.arguments()); break; } case PatternKind::ExpressionPattern: *pattern_proto.mutable_expression_pattern()->mutable_expression() = ExpressionToProto(cast(pattern).expression()); break; case PatternKind::AutoPattern: pattern_proto.mutable_auto_pattern(); break; case PatternKind::VarPattern: *pattern_proto.mutable_var_pattern()->mutable_pattern() = PatternToProto(cast(pattern).pattern()); break; } return pattern_proto; } static auto BlockStatementToProto(const Block& block) -> Fuzzing::BlockStatement { Fuzzing::BlockStatement block_proto; for (Nonnull statement : block.statements()) { *block_proto.add_statements() = StatementToProto(*statement); } return block_proto; } static auto StatementToProto(const Statement& statement) -> Fuzzing::Statement { Fuzzing::Statement statement_proto; switch (statement.kind()) { case StatementKind::ExpressionStatement: *statement_proto.mutable_expression_statement()->mutable_expression() = ExpressionToProto(cast(statement).expression()); break; case StatementKind::Assign: { const auto& assign = cast(statement); auto* assign_proto = statement_proto.mutable_assign(); *assign_proto->mutable_lhs() = ExpressionToProto(assign.lhs()); *assign_proto->mutable_rhs() = ExpressionToProto(assign.rhs()); break; } case StatementKind::VariableDefinition: { const auto& def = cast(statement); auto* def_proto = statement_proto.mutable_variable_definition(); *def_proto->mutable_pattern() = PatternToProto(def.pattern()); *def_proto->mutable_init() = ExpressionToProto(def.init()); break; } case StatementKind::If: { const auto& if_stmt = cast(statement); auto* if_proto = statement_proto.mutable_if_statement(); *if_proto->mutable_condition() = ExpressionToProto(if_stmt.condition()); *if_proto->mutable_then_block() = BlockStatementToProto(if_stmt.then_block()); if (if_stmt.else_block().has_value()) { *if_proto->mutable_else_block() = BlockStatementToProto(**if_stmt.else_block()); } break; } case StatementKind::Return: { const auto& ret = cast(statement); auto* ret_proto = statement_proto.mutable_return_statement(); if (!ret.is_omitted_expression()) { *ret_proto->mutable_expression() = ExpressionToProto(ret.expression()); } else { ret_proto->set_is_omitted_expression(true); } break; } case StatementKind::Block: *statement_proto.mutable_block() = BlockStatementToProto(cast(statement)); break; case StatementKind::While: { const auto& while_stmt = cast(statement); auto* while_proto = statement_proto.mutable_while_statement(); *while_proto->mutable_condition() = ExpressionToProto(while_stmt.condition()); *while_proto->mutable_body() = BlockStatementToProto(while_stmt.body()); break; } case StatementKind::Match: { const auto& match = cast(statement); auto* match_proto = statement_proto.mutable_match(); *match_proto->mutable_expression() = ExpressionToProto(match.expression()); for (const Match::Clause& clause : match.clauses()) { auto* clause_proto = match_proto->add_clauses(); const bool is_default_clause = clause.pattern().kind() == PatternKind::BindingPattern && cast(clause.pattern()).name() == AnonymousName; if (is_default_clause) { clause_proto->set_is_default(true); } else { *clause_proto->mutable_pattern() = PatternToProto(clause.pattern()); } *clause_proto->mutable_statement() = StatementToProto(clause.statement()); } break; } case StatementKind::Continuation: { const auto& continuation = cast(statement); auto* continuation_proto = statement_proto.mutable_continuation(); continuation_proto->set_name(continuation.name()); *continuation_proto->mutable_body() = BlockStatementToProto(continuation.body()); break; } case StatementKind::Run: *statement_proto.mutable_run()->mutable_argument() = ExpressionToProto(cast(statement).argument()); break; case StatementKind::Await: // Initializes with the default value; there's nothing to set. statement_proto.mutable_await_statement(); break; case StatementKind::Break: // Initializes with the default value; there's nothing to set. statement_proto.mutable_break_statement(); break; case StatementKind::Continue: // Initializes with the default value; there's nothing to set. statement_proto.mutable_continue_statement(); break; } return statement_proto; } static auto ReturnTermToProto(const ReturnTerm& return_term) -> Fuzzing::ReturnTerm { Fuzzing::ReturnTerm return_term_proto; if (return_term.is_omitted()) { return_term_proto.set_kind(Fuzzing::ReturnTerm::Omitted); } else if (return_term.is_auto()) { return_term_proto.set_kind(Fuzzing::ReturnTerm::Auto); } else { return_term_proto.set_kind(Fuzzing::ReturnTerm::Expression); *return_term_proto.mutable_type() = ExpressionToProto(**return_term.type_expression()); } return return_term_proto; } static auto DeclarationToProto(const Declaration& declaration) -> Fuzzing::Declaration { Fuzzing::Declaration declaration_proto; switch (declaration.kind()) { case DeclarationKind::FunctionDeclaration: { const auto& function = cast(declaration); auto* function_proto = declaration_proto.mutable_function(); function_proto->set_name(function.name()); for (Nonnull binding : function.deduced_parameters()) { *function_proto->add_deduced_parameters() = GenericBindingToProto(*binding); } if (function.is_method()) { *function_proto->mutable_me_pattern() = BindingPatternToProto(function.me_pattern()); } *function_proto->mutable_param_pattern() = TuplePatternToProto(function.param_pattern()); *function_proto->mutable_return_term() = ReturnTermToProto(function.return_term()); if (function.body().has_value()) { *function_proto->mutable_body() = BlockStatementToProto(**function.body()); } break; } case DeclarationKind::ClassDeclaration: { const auto& class_decl = cast(declaration); auto* class_proto = declaration_proto.mutable_class_declaration(); class_proto->set_name(class_decl.name()); if (class_decl.type_params().has_value()) { *class_proto->mutable_type_params() = TuplePatternToProto(**class_decl.type_params()); } for (Nonnull member : class_decl.members()) { *class_proto->add_members() = DeclarationToProto(*member); } break; } case DeclarationKind::ChoiceDeclaration: { const auto& choice = cast(declaration); auto* choice_proto = declaration_proto.mutable_choice(); choice_proto->set_name(choice.name()); for (Nonnull alternative : choice.alternatives()) { auto* alternative_proto = choice_proto->add_alternatives(); alternative_proto->set_name(alternative->name()); *alternative_proto->mutable_signature() = ExpressionToProto(alternative->signature()); } break; } case DeclarationKind::VariableDeclaration: { const auto& var = cast(declaration); auto* var_proto = declaration_proto.mutable_variable(); *var_proto->mutable_binding() = BindingPatternToProto(var.binding()); if (var.has_initializer()) { *var_proto->mutable_initializer() = ExpressionToProto(var.initializer()); } break; } case DeclarationKind::InterfaceDeclaration: { const auto& interface = cast(declaration); auto* interface_proto = declaration_proto.mutable_interface(); interface_proto->set_name(interface.name()); for (const auto& member : interface.members()) { *interface_proto->add_members() = DeclarationToProto(*member); } *interface_proto->mutable_self() = GenericBindingToProto(*interface.self()); break; } case DeclarationKind::ImplDeclaration: { const auto& impl = cast(declaration); auto* impl_proto = declaration_proto.mutable_impl(); switch (impl.kind()) { case ImplKind::InternalImpl: impl_proto->set_kind(Fuzzing::ImplDeclaration::InternalImpl); break; case ImplKind::ExternalImpl: impl_proto->set_kind(Fuzzing::ImplDeclaration::ExternalImpl); break; } *impl_proto->mutable_impl_type() = ExpressionToProto(*impl.impl_type()); *impl_proto->mutable_interface() = ExpressionToProto(impl.interface()); for (const auto& member : impl.members()) { *impl_proto->add_members() = DeclarationToProto(*member); } break; } } return declaration_proto; } Fuzzing::CompilationUnit AstToProto(const AST& ast) { Fuzzing::CompilationUnit compilation_unit; *compilation_unit.mutable_package_statement() = LibraryNameToProto(ast.package); compilation_unit.set_is_api(ast.is_api); for (const Declaration* declaration : ast.declarations) { *compilation_unit.add_declarations() = DeclarationToProto(*declaration); } return compilation_unit; } } // namespace Carbon