| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025 |
- // 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 "testing/fuzzing/proto_to_carbon.h"
- #include <google/protobuf/text_format.h>
- #include <string_view>
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/Support/raw_ostream.h"
- #include "testing/fuzzing/carbon.pb.h"
- namespace Carbon {
- static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
- llvm::raw_ostream& out) -> void;
- static auto PatternToCarbon(const Fuzzing::Pattern& pattern,
- llvm::raw_ostream& out) -> void;
- static auto StatementToCarbon(const Fuzzing::Statement& statement,
- llvm::raw_ostream& out) -> void;
- static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
- llvm::raw_ostream& out) -> void;
- // Produces a valid Carbon identifier, which must match the regex
- // `[A-Za-z_][A-Za-z0-9_]*`. In the case when `s` is generated by the
- // fuzzing framework, it might contain invalid/non-printable characters.
- static auto IdentifierToCarbon(std::string_view s, llvm::raw_ostream& out)
- -> void {
- if (s.empty()) {
- out << "EmptyIdentifier";
- } else {
- if (!llvm::isAlpha(s[0]) && s[0] != '_') {
- // Ensures that identifier starts with a valid character.
- out << 'x';
- }
- for (const char c : s) {
- if (llvm::isAlnum(c) || c == '_') {
- out << c;
- } else {
- out << llvm::toHex(c);
- }
- }
- }
- }
- static auto StringLiteralToCarbon(std::string_view s, llvm::raw_ostream& out) {
- out << '"';
- out.write_escaped(s, /*UseHexEscapes=*/true);
- out << '"';
- }
- static auto LibraryNameToCarbon(const Fuzzing::LibraryName& library,
- llvm::raw_ostream& out) -> void {
- IdentifierToCarbon(library.package_name(), out);
- // Path is optional.
- if (library.has_path()) {
- out << " library ";
- // library.path() is a string literal.
- StringLiteralToCarbon(library.path(), out);
- }
- }
- static auto PrefixUnaryOperatorToCarbon(std::string_view op,
- const Fuzzing::Expression& arg,
- llvm::raw_ostream& out) -> void {
- out << op;
- ExpressionToCarbon(arg, out);
- }
- static auto PostfixUnaryOperatorToCarbon(const Fuzzing::Expression& arg,
- std::string_view op,
- llvm::raw_ostream& out) -> void {
- ExpressionToCarbon(arg, out);
- out << op;
- }
- static auto BinaryOperatorToCarbon(const Fuzzing::Expression& lhs,
- std::string_view op,
- const Fuzzing::Expression& rhs,
- llvm::raw_ostream& out) -> void {
- ExpressionToCarbon(lhs, out);
- out << op;
- ExpressionToCarbon(rhs, out);
- }
- static auto OperatorToCarbon(const Fuzzing::OperatorExpression& operator_expr,
- llvm::raw_ostream& out) -> void {
- const Fuzzing::Expression& arg0 =
- !operator_expr.arguments().empty()
- ? operator_expr.arguments(0)
- : Fuzzing::Expression::default_instance();
- const Fuzzing::Expression& arg1 =
- operator_expr.arguments().size() > 1
- ? operator_expr.arguments(1)
- : Fuzzing::Expression::default_instance();
- out << "(";
- switch (operator_expr.op()) {
- case Fuzzing::OperatorExpression::UnknownOperator:
- // `-` is an arbitrary default to avoid getting invalid syntax.
- PrefixUnaryOperatorToCarbon("-", arg0, out);
- break;
- case Fuzzing::OperatorExpression::AddressOf:
- PrefixUnaryOperatorToCarbon("&", arg0, out);
- break;
- case Fuzzing::OperatorExpression::As:
- BinaryOperatorToCarbon(arg0, " as ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Deref:
- PrefixUnaryOperatorToCarbon("*", arg0, out);
- break;
- case Fuzzing::OperatorExpression::Mul:
- BinaryOperatorToCarbon(arg0, " * ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Div:
- BinaryOperatorToCarbon(arg0, " / ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Mod:
- BinaryOperatorToCarbon(arg0, " % ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Ptr:
- PostfixUnaryOperatorToCarbon(arg0, "*", out);
- break;
- case Fuzzing::OperatorExpression::Neg:
- PrefixUnaryOperatorToCarbon("-", arg0, out);
- break;
- case Fuzzing::OperatorExpression::Sub:
- BinaryOperatorToCarbon(arg0, " - ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Not:
- // Needs a space to 'unglue' from the operand.
- PrefixUnaryOperatorToCarbon("not ", arg0, out);
- break;
- case Fuzzing::OperatorExpression::Add:
- BinaryOperatorToCarbon(arg0, " + ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::And:
- BinaryOperatorToCarbon(arg0, " and ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Eq:
- BinaryOperatorToCarbon(arg0, " == ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Less:
- BinaryOperatorToCarbon(arg0, " < ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::LessEq:
- BinaryOperatorToCarbon(arg0, " <= ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::GreaterEq:
- BinaryOperatorToCarbon(arg0, " >= ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Greater:
- BinaryOperatorToCarbon(arg0, " > ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Or:
- BinaryOperatorToCarbon(arg0, " or ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::Complement:
- PrefixUnaryOperatorToCarbon("^", arg0, out);
- break;
- case Fuzzing::OperatorExpression::BitwiseAnd:
- BinaryOperatorToCarbon(arg0, " & ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::BitwiseOr:
- BinaryOperatorToCarbon(arg0, " | ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::BitwiseXor:
- BinaryOperatorToCarbon(arg0, " ^ ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::BitShiftLeft:
- BinaryOperatorToCarbon(arg0, " << ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::BitShiftRight:
- BinaryOperatorToCarbon(arg0, " >> ", arg1, out);
- break;
- case Fuzzing::OperatorExpression::NotEq:
- BinaryOperatorToCarbon(arg0, " != ", arg1, out);
- break;
- }
- out << ")";
- }
- static auto FieldInitializerToCarbon(const Fuzzing::FieldInitializer& field,
- std::string_view separator,
- llvm::raw_ostream& out) -> void {
- out << ".";
- IdentifierToCarbon(field.name(), out);
- out << " " << separator << " ";
- ExpressionToCarbon(field.expression(), out);
- }
- static auto TupleLiteralExpressionToCarbon(
- const Fuzzing::TupleLiteralExpression& tuple_literal,
- llvm::raw_ostream& out) -> void {
- out << "(";
- llvm::ListSeparator sep;
- for (const auto& field : tuple_literal.fields()) {
- out << sep;
- ExpressionToCarbon(field, out);
- }
- if (tuple_literal.fields_size() == 1) {
- // Adding a trailing comma so that generated source will be parsed as a
- // tuple expression. See docs/design/tuples.md.
- out << ", ";
- }
- out << ")";
- }
- static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
- llvm::raw_ostream& out) -> void {
- switch (expression.kind_case()) {
- case Fuzzing::Expression::KIND_NOT_SET:
- // Arbitrary default for missing expressions to avoid invalid syntax.
- out << "true";
- break;
- case Fuzzing::Expression::kCall: {
- const auto& call = expression.call();
- ExpressionToCarbon(call.function(), out);
- if (call.argument().kind_case() == Fuzzing::Expression::kTupleLiteral) {
- TupleLiteralExpressionToCarbon(call.argument().tuple_literal(), out);
- } else {
- out << "(";
- ExpressionToCarbon(call.argument(), out);
- out << ")";
- }
- break;
- }
- case Fuzzing::Expression::kFunctionType: {
- const auto& fun_type = expression.function_type();
- out << "__Fn";
- TupleLiteralExpressionToCarbon(fun_type.parameter(), out);
- out << " -> ";
- ExpressionToCarbon(fun_type.return_type(), out);
- break;
- }
- case Fuzzing::Expression::kSimpleMemberAccess: {
- const auto& simple_member_access = expression.simple_member_access();
- ExpressionToCarbon(simple_member_access.object(), out);
- out << ".";
- IdentifierToCarbon(simple_member_access.field(), out);
- break;
- }
- case Fuzzing::Expression::kCompoundMemberAccess: {
- const auto& simple_member_access = expression.compound_member_access();
- ExpressionToCarbon(simple_member_access.object(), out);
- out << ".(";
- ExpressionToCarbon(simple_member_access.path(), out);
- out << ")";
- break;
- }
- case Fuzzing::Expression::kIndex: {
- const auto& index = expression.index();
- ExpressionToCarbon(index.object(), out);
- out << "[";
- ExpressionToCarbon(index.offset(), out);
- out << "]";
- break;
- }
- case Fuzzing::Expression::kOperator:
- OperatorToCarbon(expression.operator_(), out);
- break;
- case Fuzzing::Expression::kTupleLiteral: {
- TupleLiteralExpressionToCarbon(expression.tuple_literal(), out);
- break;
- }
- case Fuzzing::Expression::kStructLiteral: {
- const auto& struct_literal = expression.struct_literal();
- out << "{";
- llvm::ListSeparator sep;
- for (const auto& field : struct_literal.fields()) {
- out << sep;
- FieldInitializerToCarbon(field, "=", out);
- }
- out << "}";
- break;
- }
- case Fuzzing::Expression::kStructTypeLiteral: {
- const auto& struct_type_literal = expression.struct_type_literal();
- out << "{";
- llvm::ListSeparator sep;
- for (const auto& field : struct_type_literal.fields()) {
- out << sep;
- FieldInitializerToCarbon(field, ":", out);
- }
- out << "}";
- break;
- }
- case Fuzzing::Expression::kIdentifier: {
- const auto& identifier = expression.identifier();
- IdentifierToCarbon(identifier.name(), out);
- break;
- }
- case Fuzzing::Expression::kDesignator: {
- const auto& designator = expression.designator();
- out << ".";
- IdentifierToCarbon(designator.name(), out);
- break;
- }
- case Fuzzing::Expression::kIfExpression: {
- const auto& if_expression = expression.if_expression();
- out << "if ";
- ExpressionToCarbon(if_expression.condition(), out);
- out << " then ";
- ExpressionToCarbon(if_expression.then_expression(), out);
- out << " else ";
- ExpressionToCarbon(if_expression.else_expression(), out);
- break;
- }
- case Fuzzing::Expression::kBoolTypeLiteral:
- out << "bool";
- break;
- case Fuzzing::Expression::kBoolLiteral: {
- const auto& bool_literal = expression.bool_literal();
- out << (bool_literal.value() ? "true" : "false");
- break;
- }
- case Fuzzing::Expression::kIntTypeLiteral:
- out << "i32";
- break;
- case Fuzzing::Expression::kIntLiteral: {
- out << expression.int_literal().value();
- break;
- }
- case Fuzzing::Expression::kStringLiteral:
- StringLiteralToCarbon(expression.string_literal().value(), out);
- break;
- case Fuzzing::Expression::kStringTypeLiteral:
- out << "String";
- break;
- case Fuzzing::Expression::kTypeTypeLiteral:
- out << "type";
- break;
- case Fuzzing::Expression::kUnimplementedExpression:
- // Not really supported.
- // This is an arbitrary default to avoid getting invalid syntax.
- out << "1 __unimplemented_example_infix 2";
- break;
- case Fuzzing::Expression::kArrayTypeLiteral: {
- const Fuzzing::ArrayTypeLiteral& array_literal =
- expression.array_type_literal();
- out << "[";
- ExpressionToCarbon(array_literal.element_type(), out);
- out << ";";
- if (array_literal.has_size()) {
- out << " ";
- ExpressionToCarbon(array_literal.size(), out);
- }
- out << "]";
- break;
- }
- case Fuzzing::Expression::kWhere: {
- const Fuzzing::WhereExpression& where = expression.where();
- ExpressionToCarbon(where.base(), out);
- out << " where ";
- llvm::ListSeparator sep(" and ");
- for (const auto& clause : where.clauses()) {
- out << sep;
- switch (clause.kind_case()) {
- case Fuzzing::WhereClause::kImpls:
- ExpressionToCarbon(clause.impls().type(), out);
- out << " impls ";
- ExpressionToCarbon(clause.impls().constraint(), out);
- break;
- case Fuzzing::WhereClause::kEquals:
- ExpressionToCarbon(clause.equals().lhs(), out);
- out << " == ";
- ExpressionToCarbon(clause.equals().rhs(), out);
- break;
- case Fuzzing::WhereClause::kRewrite:
- out << "." << clause.rewrite().member_name() << " = ";
- ExpressionToCarbon(clause.rewrite().replacement(), out);
- break;
- case Fuzzing::WhereClause::KIND_NOT_SET:
- // Arbitrary default to avoid invalid syntax.
- out << ".Self == .Self";
- break;
- }
- }
- break;
- }
- }
- }
- static auto BindingPatternToCarbon(const Fuzzing::BindingPattern& pattern,
- llvm::raw_ostream& out) -> void {
- IdentifierToCarbon(pattern.name(), out);
- out << ": ";
- PatternToCarbon(pattern.type(), out);
- }
- static auto GenericBindingToCarbon(
- const Fuzzing::GenericBinding& generic_binding, llvm::raw_ostream& out) {
- switch (generic_binding.kind()) {
- case Fuzzing::GenericBinding::Checked:
- break;
- case Fuzzing::GenericBinding::Template:
- out << "template ";
- break;
- }
- IdentifierToCarbon(generic_binding.name(), out);
- out << ":! ";
- ExpressionToCarbon(generic_binding.type(), out);
- }
- static auto TuplePatternToCarbon(const Fuzzing::TuplePattern& tuple_pattern,
- llvm::raw_ostream& out) -> void {
- out << "(";
- llvm::ListSeparator sep;
- for (const auto& field : tuple_pattern.fields()) {
- out << sep;
- PatternToCarbon(field, out);
- }
- if (tuple_pattern.fields_size() == 1) {
- // Adding a trailing comma so that generated source will be parsed as a
- // tuple pattern expression. See docs/design/tuples.md.
- out << ", ";
- }
- out << ")";
- }
- static auto PatternToCarbon(const Fuzzing::Pattern& pattern,
- llvm::raw_ostream& out) -> void {
- switch (pattern.kind_case()) {
- case Fuzzing::Pattern::KIND_NOT_SET:
- // Arbitrary default to avoid getting invalid syntax.
- out << "auto";
- break;
- case Fuzzing::Pattern::kBindingPattern:
- BindingPatternToCarbon(pattern.binding_pattern(), out);
- break;
- case Fuzzing::Pattern::kTuplePattern:
- TuplePatternToCarbon(pattern.tuple_pattern(), out);
- break;
- case Fuzzing::Pattern::kAlternativePattern: {
- const auto& alternative_pattern = pattern.alternative_pattern();
- ExpressionToCarbon(alternative_pattern.choice_type(), out);
- out << ".";
- IdentifierToCarbon(alternative_pattern.alternative_name(), out);
- TuplePatternToCarbon(alternative_pattern.arguments(), out);
- break;
- }
- // Arbitrary expression.
- case Fuzzing::Pattern::kExpressionPattern: {
- const auto& expression_pattern = pattern.expression_pattern();
- ExpressionToCarbon(expression_pattern.expression(), out);
- break;
- }
- case Fuzzing::Pattern::kAutoPattern:
- out << "auto";
- break;
- case Fuzzing::Pattern::kVarPattern:
- out << "var ";
- PatternToCarbon(pattern.var_pattern().pattern(), out);
- break;
- case Fuzzing::Pattern::kGenericBinding:
- GenericBindingToCarbon(pattern.generic_binding(), out);
- break;
- case Fuzzing::Pattern::kAddrPattern:
- out << "addr ";
- BindingPatternToCarbon(pattern.addr_pattern().binding_pattern(), out);
- break;
- }
- }
- static auto BlockStatementToCarbon(const Fuzzing::BlockStatement& block,
- llvm::raw_ostream& out) -> void {
- out << "{\n";
- for (const auto& statement : block.statements()) {
- StatementToCarbon(statement, out);
- out << "\n";
- }
- out << "}\n";
- }
- static auto StatementToCarbon(const Fuzzing::Statement& statement,
- llvm::raw_ostream& out) -> void {
- switch (statement.kind_case()) {
- case Fuzzing::Statement::KIND_NOT_SET:
- // Arbitrary default to avoid getting invalid syntax.
- out << "true;\n";
- break;
- case Fuzzing::Statement::kExpressionStatement: {
- const auto& expression_statement = statement.expression_statement();
- ExpressionToCarbon(expression_statement.expression(), out);
- out << ";";
- break;
- }
- case Fuzzing::Statement::kAssign: {
- const auto& assign_statement = statement.assign();
- ExpressionToCarbon(assign_statement.lhs(), out);
- switch (assign_statement.op()) {
- case Fuzzing::AssignStatement::Plain:
- out << " = ";
- break;
- case Fuzzing::AssignStatement::Add:
- out << " += ";
- break;
- case Fuzzing::AssignStatement::And:
- out << " &= ";
- break;
- case Fuzzing::AssignStatement::Div:
- out << " /= ";
- break;
- case Fuzzing::AssignStatement::Mod:
- out << " %= ";
- break;
- case Fuzzing::AssignStatement::Mul:
- out << " *= ";
- break;
- case Fuzzing::AssignStatement::Or:
- out << " |= ";
- break;
- case Fuzzing::AssignStatement::ShiftLeft:
- out << " <<= ";
- break;
- case Fuzzing::AssignStatement::ShiftRight:
- out << " >>= ";
- break;
- case Fuzzing::AssignStatement::Sub:
- out << " -= ";
- break;
- case Fuzzing::AssignStatement::Xor:
- out << " ^= ";
- break;
- }
- ExpressionToCarbon(assign_statement.rhs(), out);
- out << ";";
- break;
- }
- case Fuzzing::Statement::kIncDec: {
- const auto& inc_dec_statement = statement.inc_dec();
- out << (inc_dec_statement.is_increment() ? "++" : "--");
- ExpressionToCarbon(inc_dec_statement.operand(), out);
- out << ";";
- break;
- }
- case Fuzzing::Statement::kVariableDefinition: {
- const auto& def = statement.variable_definition();
- if (def.is_returned()) {
- out << "returned ";
- }
- out << "var ";
- PatternToCarbon(def.pattern(), out);
- if (def.has_init()) {
- out << " = ";
- ExpressionToCarbon(def.init(), out);
- }
- out << ";";
- break;
- }
- case Fuzzing::Statement::kIfStatement: {
- const auto& if_statement = statement.if_statement();
- out << "if (";
- ExpressionToCarbon(if_statement.condition(), out);
- out << ") ";
- BlockStatementToCarbon(if_statement.then_block(), out);
- // `else` is optional.
- if (if_statement.has_else_block()) {
- out << " else ";
- BlockStatementToCarbon(if_statement.else_block(), out);
- }
- break;
- }
- case Fuzzing::Statement::kReturnVarStatement: {
- out << "return var;";
- break;
- }
- case Fuzzing::Statement::kReturnExpressionStatement: {
- const auto& ret = statement.return_expression_statement();
- out << "return";
- if (!ret.is_omitted_expression()) {
- out << " ";
- ExpressionToCarbon(ret.expression(), out);
- }
- out << ";";
- break;
- }
- case Fuzzing::Statement::kBlock:
- BlockStatementToCarbon(statement.block(), out);
- break;
- case Fuzzing::Statement::kWhileStatement: {
- const auto& while_statement = statement.while_statement();
- out << "while (";
- ExpressionToCarbon(while_statement.condition(), out);
- out << ") ";
- BlockStatementToCarbon(while_statement.body(), out);
- break;
- }
- case Fuzzing::Statement::kForStatement: {
- const auto& for_statement = statement.for_statement();
- out << "for (";
- BindingPatternToCarbon(for_statement.var_decl(), out);
- out << " in ";
- ExpressionToCarbon(for_statement.target(), out);
- out << ") ";
- BlockStatementToCarbon(for_statement.body(), out);
- break;
- }
- case Fuzzing::Statement::kMatch: {
- const auto& match = statement.match();
- out << "match (";
- ExpressionToCarbon(match.expression(), out);
- out << ") {";
- for (const auto& clause : match.clauses()) {
- if (clause.is_default()) {
- out << "default";
- } else {
- out << "case ";
- PatternToCarbon(clause.pattern(), out);
- }
- out << " => ";
- StatementToCarbon(clause.statement(), out);
- }
- out << "}";
- break;
- }
- case Fuzzing::Statement::kBreakStatement:
- out << "break;";
- break;
- case Fuzzing::Statement::kContinueStatement:
- out << "continue;";
- break;
- }
- }
- static auto ReturnTermToCarbon(const Fuzzing::ReturnTerm& return_term,
- llvm::raw_ostream& out) -> void {
- switch (return_term.kind()) {
- case Fuzzing::ReturnTerm::UnknownReturnKind:
- case Fuzzing::ReturnTerm::Omitted:
- break;
- case Fuzzing::ReturnTerm::Auto:
- out << " -> auto";
- break;
- case Fuzzing::ReturnTerm::Expression:
- out << " -> ";
- ExpressionToCarbon(return_term.type(), out);
- break;
- }
- }
- static auto DeclaredNameToCarbon(const Fuzzing::DeclaredName& name,
- llvm::raw_ostream& out) -> void {
- for (const std::string& qual : name.qualifiers()) {
- IdentifierToCarbon(qual, out);
- out << ".";
- }
- IdentifierToCarbon(name.name(), out);
- }
- static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
- llvm::raw_ostream& out) -> void {
- switch (declaration.kind_case()) {
- case Fuzzing::Declaration::KIND_NOT_SET: {
- // Arbitrary default to avoid getting invalid syntax.
- out << "var x: i32;";
- break;
- }
- case Fuzzing::Declaration::kNamespace: {
- out << "namespace ";
- DeclaredNameToCarbon(declaration.namespace_().name(), out);
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kDestructor: {
- const auto& function = declaration.destructor();
- out << "destructor";
- llvm::ListSeparator sep;
- out << "[";
- if (function.has_self_pattern()) {
- // This is a class method.
- out << sep;
- PatternToCarbon(function.self_pattern(), out);
- }
- out << "]";
- // Body is optional.
- if (function.has_body()) {
- out << "\n";
- BlockStatementToCarbon(function.body(), out);
- } else {
- out << ";";
- }
- break;
- }
- case Fuzzing::Declaration::kFunction: {
- const auto& function = declaration.function();
- out << "fn ";
- DeclaredNameToCarbon(function.name(), out);
- if (!function.deduced_parameters().empty() ||
- function.has_self_pattern()) {
- out << "[";
- llvm::ListSeparator sep;
- for (const Fuzzing::GenericBinding& p : function.deduced_parameters()) {
- out << sep;
- GenericBindingToCarbon(p, out);
- }
- if (function.has_self_pattern()) {
- // This is a class method.
- out << sep;
- PatternToCarbon(function.self_pattern(), out);
- }
- out << "]";
- }
- TuplePatternToCarbon(function.param_pattern(), out);
- ReturnTermToCarbon(function.return_term(), out);
- // Body is optional.
- if (function.has_body()) {
- out << "\n";
- BlockStatementToCarbon(function.body(), out);
- } else {
- out << ";";
- }
- break;
- }
- case Fuzzing::Declaration::kClassDeclaration: {
- const auto& class_declaration = declaration.class_declaration();
- out << "class ";
- DeclaredNameToCarbon(class_declaration.name(), out);
- // type_params is optional.
- if (class_declaration.has_type_params()) {
- TuplePatternToCarbon(class_declaration.type_params(), out);
- }
- out << "{\n";
- for (const auto& member : class_declaration.members()) {
- DeclarationToCarbon(member, out);
- out << "\n";
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kExtendBase: {
- const auto& extend_base_declaration = declaration.extend_base();
- out << " extend base: ";
- ExpressionToCarbon(extend_base_declaration.base_class(), out);
- out << ";\n";
- break;
- }
- // EXPERIMENTAL MIXIN FEATURE
- case Fuzzing::Declaration::kMixin: {
- const auto& mixin_declaration = declaration.mixin();
- out << "__mixin ";
- DeclaredNameToCarbon(mixin_declaration.name(), out);
- // type params are not implemented yet
- // if (mixin_declaration.has_params()) {
- // TuplePatternToCarbon(mixin_declaration.params(), out);
- //}
- out << "{\n";
- for (const auto& member : mixin_declaration.members()) {
- DeclarationToCarbon(member, out);
- out << "\n";
- }
- out << "}";
- // TODO: need to handle interface.self()?
- break;
- }
- // EXPERIMENTAL MIXIN FEATURE
- case Fuzzing::Declaration::kMix: {
- const auto& mix_declaration = declaration.mix();
- out << "__mix ";
- ExpressionToCarbon(mix_declaration.mixin(), out);
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kChoice: {
- const auto& choice = declaration.choice();
- out << "choice ";
- DeclaredNameToCarbon(choice.name(), out);
- out << "{";
- llvm::ListSeparator sep;
- for (const auto& alternative : choice.alternatives()) {
- out << sep;
- IdentifierToCarbon(alternative.name(), out);
- if (alternative.has_signature()) {
- TupleLiteralExpressionToCarbon(alternative.signature(), out);
- }
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kVariable: {
- const auto& var = declaration.variable();
- out << "var ";
- BindingPatternToCarbon(var.binding(), out);
- // Initializer is optional.
- if (var.has_initializer()) {
- out << " = ";
- ExpressionToCarbon(var.initializer(), out);
- }
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kLet: {
- const auto& let = declaration.let();
- out << "let ";
- PatternToCarbon(let.pattern(), out);
- // TODO: Print out the initializer once it's supported.
- // if (let.has_initializer()) {
- // out << " = ";
- // ExpressionToCarbon(let.initializer(), out);
- // }
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kInterfaceExtend: {
- const auto& extend = declaration.interface_extend();
- out << "extend ";
- ExpressionToCarbon(extend.base(), out);
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kInterfaceRequire: {
- const auto& impl = declaration.interface_require();
- out << "require ";
- ExpressionToCarbon(impl.impl_type(), out);
- out << " impls ";
- ExpressionToCarbon(impl.constraint(), out);
- out << ";";
- break;
- }
- case Fuzzing::Declaration::kInterface: {
- const auto& interface = declaration.interface();
- out << "interface ";
- DeclaredNameToCarbon(interface.name(), out);
- out << " {\n";
- for (const auto& member : interface.members()) {
- DeclarationToCarbon(member, out);
- out << "\n";
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kConstraint: {
- const auto& constraint = declaration.constraint();
- out << "constraint ";
- DeclaredNameToCarbon(constraint.name(), out);
- out << " {\n";
- for (const auto& member : constraint.members()) {
- DeclarationToCarbon(member, out);
- out << "\n";
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kImpl: {
- const auto& impl = declaration.impl();
- if (impl.kind() == Fuzzing::ImplDeclaration::InternalImpl) {
- out << "extend ";
- }
- out << "impl ";
- if (!impl.deduced_parameters().empty()) {
- out << "forall [";
- llvm::ListSeparator sep;
- for (const Fuzzing::GenericBinding& p : impl.deduced_parameters()) {
- out << sep;
- GenericBindingToCarbon(p, out);
- }
- out << "] ";
- }
- if (impl.kind() != Fuzzing::ImplDeclaration::InternalImpl) {
- ExpressionToCarbon(impl.impl_type(), out);
- out << " ";
- }
- out << "as ";
- ExpressionToCarbon(impl.interface(), out);
- out << " {\n";
- for (const auto& member : impl.members()) {
- DeclarationToCarbon(member, out);
- out << "\n";
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kMatchFirst: {
- const auto& match_first = declaration.match_first();
- out << "__match_first {\n";
- for (const auto& impl : match_first.impl_declarations()) {
- DeclarationToCarbon(impl, out);
- out << "\n";
- }
- out << "}";
- break;
- }
- case Fuzzing::Declaration::kAlias: {
- const auto& alias = declaration.alias();
- out << "alias ";
- DeclaredNameToCarbon(alias.name(), out);
- out << " = ";
- ExpressionToCarbon(alias.target(), out);
- out << ";";
- break;
- }
- }
- }
- auto ProtoToCarbon(const Fuzzing::Carbon& proto, bool maybe_add_main)
- -> std::string {
- std::string source;
- llvm::raw_string_ostream out(source);
- out << "// Generated by proto_to_carbon.\n"
- "package ";
- const auto& unit = proto.compilation_unit();
- LibraryNameToCarbon(unit.package_statement(), out);
- out << (unit.is_api() ? " api" : " impl") << ";\n\n";
- bool has_main = false;
- if (!unit.declarations().empty()) {
- for (const auto& declaration : unit.declarations()) {
- DeclarationToCarbon(declaration, out);
- if (declaration.kind_case() == Fuzzing::Declaration::kFunction &&
- declaration.function().name().name() == "Main") {
- has_main = true;
- }
- out << "\n";
- }
- }
- if (maybe_add_main && !has_main) {
- out << "fn Main() -> i32 { return 0; }\n";
- }
- return source;
- }
- auto ParseCarbonTextProto(const std::string& contents)
- -> ErrorOr<Fuzzing::Carbon> {
- google::protobuf::TextFormat::Parser parser;
- Fuzzing::Carbon carbon_proto;
- if (!parser.ParseFromString(contents, &carbon_proto)) {
- return ErrorBuilder() << "Couldn't parse Carbon text proto";
- }
- return carbon_proto;
- }
- } // namespace Carbon
|