proto_to_carbon.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "testing/fuzzing/proto_to_carbon.h"
  5. #include <google/protobuf/text_format.h>
  6. #include <string_view>
  7. #include "llvm/ADT/StringExtras.h"
  8. #include "llvm/Support/raw_ostream.h"
  9. #include "testing/fuzzing/carbon.pb.h"
  10. // This is a test file, so the recursion is okay.
  11. // NOLINTBEGIN(misc-no-recursion)
  12. namespace Carbon {
  13. static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
  14. llvm::raw_ostream& out) -> void;
  15. static auto PatternToCarbon(const Fuzzing::Pattern& pattern,
  16. llvm::raw_ostream& out) -> void;
  17. static auto StatementToCarbon(const Fuzzing::Statement& statement,
  18. llvm::raw_ostream& out) -> void;
  19. static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
  20. llvm::raw_ostream& out) -> void;
  21. // Produces a valid Carbon identifier, which must match the regex
  22. // `[A-Za-z_][A-Za-z0-9_]*`. In the case when `s` is generated by the
  23. // fuzzing framework, it might contain invalid/non-printable characters.
  24. static auto IdentifierToCarbon(std::string_view s, llvm::raw_ostream& out)
  25. -> void {
  26. if (s.empty()) {
  27. out << "EmptyIdentifier";
  28. } else {
  29. if (!llvm::isAlpha(s[0]) && s[0] != '_') {
  30. // Ensures that identifier starts with a valid character.
  31. out << 'x';
  32. }
  33. for (const char c : s) {
  34. if (llvm::isAlnum(c) || c == '_') {
  35. out << c;
  36. } else {
  37. out << llvm::toHex(c);
  38. }
  39. }
  40. }
  41. }
  42. static auto StringLiteralToCarbon(std::string_view s, llvm::raw_ostream& out) {
  43. out << '"';
  44. out.write_escaped(s, /*UseHexEscapes=*/true);
  45. out << '"';
  46. }
  47. static auto LibraryNameToCarbon(const Fuzzing::LibraryName& library,
  48. llvm::raw_ostream& out) -> void {
  49. IdentifierToCarbon(library.package_name(), out);
  50. // Path is optional.
  51. if (library.has_path()) {
  52. out << " library ";
  53. // library.path() is a string literal.
  54. StringLiteralToCarbon(library.path(), out);
  55. }
  56. }
  57. static auto PrefixUnaryOperatorToCarbon(std::string_view op,
  58. const Fuzzing::Expression& arg,
  59. llvm::raw_ostream& out) -> void {
  60. out << op;
  61. ExpressionToCarbon(arg, out);
  62. }
  63. static auto PostfixUnaryOperatorToCarbon(const Fuzzing::Expression& arg,
  64. std::string_view op,
  65. llvm::raw_ostream& out) -> void {
  66. ExpressionToCarbon(arg, out);
  67. out << op;
  68. }
  69. static auto BinaryOperatorToCarbon(const Fuzzing::Expression& lhs,
  70. std::string_view op,
  71. const Fuzzing::Expression& rhs,
  72. llvm::raw_ostream& out) -> void {
  73. ExpressionToCarbon(lhs, out);
  74. out << op;
  75. ExpressionToCarbon(rhs, out);
  76. }
  77. static auto OperatorToCarbon(const Fuzzing::OperatorExpression& operator_expr,
  78. llvm::raw_ostream& out) -> void {
  79. const Fuzzing::Expression& arg0 =
  80. !operator_expr.arguments().empty()
  81. ? operator_expr.arguments(0)
  82. : Fuzzing::Expression::default_instance();
  83. const Fuzzing::Expression& arg1 =
  84. operator_expr.arguments().size() > 1
  85. ? operator_expr.arguments(1)
  86. : Fuzzing::Expression::default_instance();
  87. out << "(";
  88. switch (operator_expr.op()) {
  89. case Fuzzing::OperatorExpression::UnknownOperator:
  90. // `-` is an arbitrary default to avoid getting invalid syntax.
  91. PrefixUnaryOperatorToCarbon("-", arg0, out);
  92. break;
  93. case Fuzzing::OperatorExpression::AddressOf:
  94. PrefixUnaryOperatorToCarbon("&", arg0, out);
  95. break;
  96. case Fuzzing::OperatorExpression::As:
  97. BinaryOperatorToCarbon(arg0, " as ", arg1, out);
  98. break;
  99. case Fuzzing::OperatorExpression::Deref:
  100. PrefixUnaryOperatorToCarbon("*", arg0, out);
  101. break;
  102. case Fuzzing::OperatorExpression::Mul:
  103. BinaryOperatorToCarbon(arg0, " * ", arg1, out);
  104. break;
  105. case Fuzzing::OperatorExpression::Div:
  106. BinaryOperatorToCarbon(arg0, " / ", arg1, out);
  107. break;
  108. case Fuzzing::OperatorExpression::Mod:
  109. BinaryOperatorToCarbon(arg0, " % ", arg1, out);
  110. break;
  111. case Fuzzing::OperatorExpression::Ptr:
  112. PostfixUnaryOperatorToCarbon(arg0, "*", out);
  113. break;
  114. case Fuzzing::OperatorExpression::Neg:
  115. PrefixUnaryOperatorToCarbon("-", arg0, out);
  116. break;
  117. case Fuzzing::OperatorExpression::Sub:
  118. BinaryOperatorToCarbon(arg0, " - ", arg1, out);
  119. break;
  120. case Fuzzing::OperatorExpression::Not:
  121. // Needs a space to 'unglue' from the operand.
  122. PrefixUnaryOperatorToCarbon("not ", arg0, out);
  123. break;
  124. case Fuzzing::OperatorExpression::Add:
  125. BinaryOperatorToCarbon(arg0, " + ", arg1, out);
  126. break;
  127. case Fuzzing::OperatorExpression::And:
  128. BinaryOperatorToCarbon(arg0, " and ", arg1, out);
  129. break;
  130. case Fuzzing::OperatorExpression::Eq:
  131. BinaryOperatorToCarbon(arg0, " == ", arg1, out);
  132. break;
  133. case Fuzzing::OperatorExpression::Less:
  134. BinaryOperatorToCarbon(arg0, " < ", arg1, out);
  135. break;
  136. case Fuzzing::OperatorExpression::LessEq:
  137. BinaryOperatorToCarbon(arg0, " <= ", arg1, out);
  138. break;
  139. case Fuzzing::OperatorExpression::GreaterEq:
  140. BinaryOperatorToCarbon(arg0, " >= ", arg1, out);
  141. break;
  142. case Fuzzing::OperatorExpression::Greater:
  143. BinaryOperatorToCarbon(arg0, " > ", arg1, out);
  144. break;
  145. case Fuzzing::OperatorExpression::Or:
  146. BinaryOperatorToCarbon(arg0, " or ", arg1, out);
  147. break;
  148. case Fuzzing::OperatorExpression::Complement:
  149. PrefixUnaryOperatorToCarbon("^", arg0, out);
  150. break;
  151. case Fuzzing::OperatorExpression::BitwiseAnd:
  152. BinaryOperatorToCarbon(arg0, " & ", arg1, out);
  153. break;
  154. case Fuzzing::OperatorExpression::BitwiseOr:
  155. BinaryOperatorToCarbon(arg0, " | ", arg1, out);
  156. break;
  157. case Fuzzing::OperatorExpression::BitwiseXor:
  158. BinaryOperatorToCarbon(arg0, " ^ ", arg1, out);
  159. break;
  160. case Fuzzing::OperatorExpression::BitShiftLeft:
  161. BinaryOperatorToCarbon(arg0, " << ", arg1, out);
  162. break;
  163. case Fuzzing::OperatorExpression::BitShiftRight:
  164. BinaryOperatorToCarbon(arg0, " >> ", arg1, out);
  165. break;
  166. case Fuzzing::OperatorExpression::NotEq:
  167. BinaryOperatorToCarbon(arg0, " != ", arg1, out);
  168. break;
  169. }
  170. out << ")";
  171. }
  172. static auto FieldInitializerToCarbon(const Fuzzing::FieldInitializer& field,
  173. std::string_view separator,
  174. llvm::raw_ostream& out) -> void {
  175. out << ".";
  176. IdentifierToCarbon(field.name(), out);
  177. out << " " << separator << " ";
  178. ExpressionToCarbon(field.expression(), out);
  179. }
  180. static auto TupleLiteralExpressionToCarbon(
  181. const Fuzzing::TupleLiteralExpression& tuple_literal,
  182. llvm::raw_ostream& out) -> void {
  183. out << "(";
  184. llvm::ListSeparator sep;
  185. for (const auto& field : tuple_literal.fields()) {
  186. out << sep;
  187. ExpressionToCarbon(field, out);
  188. }
  189. if (tuple_literal.fields_size() == 1) {
  190. // Adding a trailing comma so that generated source will be parsed as a
  191. // tuple expression. See docs/design/tuples.md.
  192. out << ", ";
  193. }
  194. out << ")";
  195. }
  196. static auto ExpressionToCarbon(const Fuzzing::Expression& expression,
  197. llvm::raw_ostream& out) -> void {
  198. switch (expression.kind_case()) {
  199. case Fuzzing::Expression::KIND_NOT_SET:
  200. // Arbitrary default for missing expressions to avoid invalid syntax.
  201. out << "true";
  202. break;
  203. case Fuzzing::Expression::kCall: {
  204. const auto& call = expression.call();
  205. ExpressionToCarbon(call.function(), out);
  206. if (call.argument().kind_case() == Fuzzing::Expression::kTupleLiteral) {
  207. TupleLiteralExpressionToCarbon(call.argument().tuple_literal(), out);
  208. } else {
  209. out << "(";
  210. ExpressionToCarbon(call.argument(), out);
  211. out << ")";
  212. }
  213. break;
  214. }
  215. case Fuzzing::Expression::kFunctionType: {
  216. const auto& fun_type = expression.function_type();
  217. out << "__Fn";
  218. TupleLiteralExpressionToCarbon(fun_type.parameter(), out);
  219. out << " -> ";
  220. ExpressionToCarbon(fun_type.return_type(), out);
  221. break;
  222. }
  223. case Fuzzing::Expression::kSimpleMemberAccess: {
  224. const auto& simple_member_access = expression.simple_member_access();
  225. ExpressionToCarbon(simple_member_access.object(), out);
  226. out << ".";
  227. IdentifierToCarbon(simple_member_access.field(), out);
  228. break;
  229. }
  230. case Fuzzing::Expression::kCompoundMemberAccess: {
  231. const auto& simple_member_access = expression.compound_member_access();
  232. ExpressionToCarbon(simple_member_access.object(), out);
  233. out << ".(";
  234. ExpressionToCarbon(simple_member_access.path(), out);
  235. out << ")";
  236. break;
  237. }
  238. case Fuzzing::Expression::kIndex: {
  239. const auto& index = expression.index();
  240. ExpressionToCarbon(index.object(), out);
  241. out << "[";
  242. ExpressionToCarbon(index.offset(), out);
  243. out << "]";
  244. break;
  245. }
  246. case Fuzzing::Expression::kOperator:
  247. OperatorToCarbon(expression.operator_(), out);
  248. break;
  249. case Fuzzing::Expression::kTupleLiteral: {
  250. TupleLiteralExpressionToCarbon(expression.tuple_literal(), out);
  251. break;
  252. }
  253. case Fuzzing::Expression::kStructLiteral: {
  254. const auto& struct_literal = expression.struct_literal();
  255. out << "{";
  256. llvm::ListSeparator sep;
  257. for (const auto& field : struct_literal.fields()) {
  258. out << sep;
  259. FieldInitializerToCarbon(field, "=", out);
  260. }
  261. out << "}";
  262. break;
  263. }
  264. case Fuzzing::Expression::kStructTypeLiteral: {
  265. const auto& struct_type_literal = expression.struct_type_literal();
  266. out << "{";
  267. llvm::ListSeparator sep;
  268. for (const auto& field : struct_type_literal.fields()) {
  269. out << sep;
  270. FieldInitializerToCarbon(field, ":", out);
  271. }
  272. out << "}";
  273. break;
  274. }
  275. case Fuzzing::Expression::kIdentifier: {
  276. const auto& identifier = expression.identifier();
  277. IdentifierToCarbon(identifier.name(), out);
  278. break;
  279. }
  280. case Fuzzing::Expression::kDesignator: {
  281. const auto& designator = expression.designator();
  282. out << ".";
  283. IdentifierToCarbon(designator.name(), out);
  284. break;
  285. }
  286. case Fuzzing::Expression::kIfExpression: {
  287. const auto& if_expression = expression.if_expression();
  288. out << "if ";
  289. ExpressionToCarbon(if_expression.condition(), out);
  290. out << " then ";
  291. ExpressionToCarbon(if_expression.then_expression(), out);
  292. out << " else ";
  293. ExpressionToCarbon(if_expression.else_expression(), out);
  294. break;
  295. }
  296. case Fuzzing::Expression::kBoolTypeLiteral:
  297. out << "bool";
  298. break;
  299. case Fuzzing::Expression::kBoolLiteral: {
  300. const auto& bool_literal = expression.bool_literal();
  301. out << (bool_literal.value() ? "true" : "false");
  302. break;
  303. }
  304. case Fuzzing::Expression::kIntTypeLiteral:
  305. out << "i32";
  306. break;
  307. case Fuzzing::Expression::kIntLiteral: {
  308. out << expression.int_literal().value();
  309. break;
  310. }
  311. case Fuzzing::Expression::kStringLiteral:
  312. StringLiteralToCarbon(expression.string_literal().value(), out);
  313. break;
  314. case Fuzzing::Expression::kStringTypeLiteral:
  315. out << "String";
  316. break;
  317. case Fuzzing::Expression::kTypeTypeLiteral:
  318. out << "type";
  319. break;
  320. case Fuzzing::Expression::kUnimplementedExpression:
  321. // Not really supported.
  322. // This is an arbitrary default to avoid getting invalid syntax.
  323. out << "1 __unimplemented_example_infix 2";
  324. break;
  325. case Fuzzing::Expression::kArrayTypeLiteral: {
  326. const Fuzzing::ArrayTypeLiteral& array_literal =
  327. expression.array_type_literal();
  328. out << "[";
  329. ExpressionToCarbon(array_literal.element_type(), out);
  330. out << ";";
  331. if (array_literal.has_size()) {
  332. out << " ";
  333. ExpressionToCarbon(array_literal.size(), out);
  334. }
  335. out << "]";
  336. break;
  337. }
  338. case Fuzzing::Expression::kWhere: {
  339. const Fuzzing::WhereExpression& where = expression.where();
  340. ExpressionToCarbon(where.base(), out);
  341. out << " where ";
  342. llvm::ListSeparator sep(" and ");
  343. for (const auto& clause : where.clauses()) {
  344. out << sep;
  345. switch (clause.kind_case()) {
  346. case Fuzzing::WhereClause::kImpls:
  347. ExpressionToCarbon(clause.impls().type(), out);
  348. out << " impls ";
  349. ExpressionToCarbon(clause.impls().constraint(), out);
  350. break;
  351. case Fuzzing::WhereClause::kEquals:
  352. ExpressionToCarbon(clause.equals().lhs(), out);
  353. out << " == ";
  354. ExpressionToCarbon(clause.equals().rhs(), out);
  355. break;
  356. case Fuzzing::WhereClause::kRewrite:
  357. out << "." << clause.rewrite().member_name() << " = ";
  358. ExpressionToCarbon(clause.rewrite().replacement(), out);
  359. break;
  360. case Fuzzing::WhereClause::KIND_NOT_SET:
  361. // Arbitrary default to avoid invalid syntax.
  362. out << ".Self == .Self";
  363. break;
  364. }
  365. }
  366. break;
  367. }
  368. }
  369. }
  370. static auto BindingPatternToCarbon(const Fuzzing::BindingPattern& pattern,
  371. llvm::raw_ostream& out) -> void {
  372. IdentifierToCarbon(pattern.name(), out);
  373. out << ": ";
  374. PatternToCarbon(pattern.type(), out);
  375. }
  376. static auto GenericBindingToCarbon(
  377. const Fuzzing::GenericBinding& generic_binding, llvm::raw_ostream& out) {
  378. switch (generic_binding.kind()) {
  379. case Fuzzing::GenericBinding::Checked:
  380. break;
  381. case Fuzzing::GenericBinding::Template:
  382. out << "template ";
  383. break;
  384. }
  385. IdentifierToCarbon(generic_binding.name(), out);
  386. out << ":! ";
  387. ExpressionToCarbon(generic_binding.type(), out);
  388. }
  389. static auto TuplePatternToCarbon(const Fuzzing::TuplePattern& tuple_pattern,
  390. llvm::raw_ostream& out) -> void {
  391. out << "(";
  392. llvm::ListSeparator sep;
  393. for (const auto& field : tuple_pattern.fields()) {
  394. out << sep;
  395. PatternToCarbon(field, out);
  396. }
  397. if (tuple_pattern.fields_size() == 1) {
  398. // Adding a trailing comma so that generated source will be parsed as a
  399. // tuple pattern expression. See docs/design/tuples.md.
  400. out << ", ";
  401. }
  402. out << ")";
  403. }
  404. static auto PatternToCarbon(const Fuzzing::Pattern& pattern,
  405. llvm::raw_ostream& out) -> void {
  406. switch (pattern.kind_case()) {
  407. case Fuzzing::Pattern::KIND_NOT_SET:
  408. // Arbitrary default to avoid getting invalid syntax.
  409. out << "auto";
  410. break;
  411. case Fuzzing::Pattern::kBindingPattern:
  412. BindingPatternToCarbon(pattern.binding_pattern(), out);
  413. break;
  414. case Fuzzing::Pattern::kTuplePattern:
  415. TuplePatternToCarbon(pattern.tuple_pattern(), out);
  416. break;
  417. case Fuzzing::Pattern::kAlternativePattern: {
  418. const auto& alternative_pattern = pattern.alternative_pattern();
  419. ExpressionToCarbon(alternative_pattern.choice_type(), out);
  420. out << ".";
  421. IdentifierToCarbon(alternative_pattern.alternative_name(), out);
  422. TuplePatternToCarbon(alternative_pattern.arguments(), out);
  423. break;
  424. }
  425. // Arbitrary expression.
  426. case Fuzzing::Pattern::kExpressionPattern: {
  427. const auto& expression_pattern = pattern.expression_pattern();
  428. ExpressionToCarbon(expression_pattern.expression(), out);
  429. break;
  430. }
  431. case Fuzzing::Pattern::kAutoPattern:
  432. out << "auto";
  433. break;
  434. case Fuzzing::Pattern::kVarPattern:
  435. out << "var ";
  436. PatternToCarbon(pattern.var_pattern().pattern(), out);
  437. break;
  438. case Fuzzing::Pattern::kGenericBinding:
  439. GenericBindingToCarbon(pattern.generic_binding(), out);
  440. break;
  441. case Fuzzing::Pattern::kAddrPattern:
  442. out << "addr ";
  443. BindingPatternToCarbon(pattern.addr_pattern().binding_pattern(), out);
  444. break;
  445. }
  446. }
  447. static auto BlockStatementToCarbon(const Fuzzing::BlockStatement& block,
  448. llvm::raw_ostream& out) -> void {
  449. out << "{\n";
  450. for (const auto& statement : block.statements()) {
  451. StatementToCarbon(statement, out);
  452. out << "\n";
  453. }
  454. out << "}\n";
  455. }
  456. static auto StatementToCarbon(const Fuzzing::Statement& statement,
  457. llvm::raw_ostream& out) -> void {
  458. switch (statement.kind_case()) {
  459. case Fuzzing::Statement::KIND_NOT_SET:
  460. // Arbitrary default to avoid getting invalid syntax.
  461. out << "true;\n";
  462. break;
  463. case Fuzzing::Statement::kExpressionStatement: {
  464. const auto& expression_statement = statement.expression_statement();
  465. ExpressionToCarbon(expression_statement.expression(), out);
  466. out << ";";
  467. break;
  468. }
  469. case Fuzzing::Statement::kAssign: {
  470. const auto& assign_statement = statement.assign();
  471. ExpressionToCarbon(assign_statement.lhs(), out);
  472. switch (assign_statement.op()) {
  473. case Fuzzing::AssignStatement::Plain:
  474. out << " = ";
  475. break;
  476. case Fuzzing::AssignStatement::Add:
  477. out << " += ";
  478. break;
  479. case Fuzzing::AssignStatement::And:
  480. out << " &= ";
  481. break;
  482. case Fuzzing::AssignStatement::Div:
  483. out << " /= ";
  484. break;
  485. case Fuzzing::AssignStatement::Mod:
  486. out << " %= ";
  487. break;
  488. case Fuzzing::AssignStatement::Mul:
  489. out << " *= ";
  490. break;
  491. case Fuzzing::AssignStatement::Or:
  492. out << " |= ";
  493. break;
  494. case Fuzzing::AssignStatement::ShiftLeft:
  495. out << " <<= ";
  496. break;
  497. case Fuzzing::AssignStatement::ShiftRight:
  498. out << " >>= ";
  499. break;
  500. case Fuzzing::AssignStatement::Sub:
  501. out << " -= ";
  502. break;
  503. case Fuzzing::AssignStatement::Xor:
  504. out << " ^= ";
  505. break;
  506. }
  507. ExpressionToCarbon(assign_statement.rhs(), out);
  508. out << ";";
  509. break;
  510. }
  511. case Fuzzing::Statement::kIncDec: {
  512. const auto& inc_dec_statement = statement.inc_dec();
  513. out << (inc_dec_statement.is_increment() ? "++" : "--");
  514. ExpressionToCarbon(inc_dec_statement.operand(), out);
  515. out << ";";
  516. break;
  517. }
  518. case Fuzzing::Statement::kVariableDefinition: {
  519. const auto& def = statement.variable_definition();
  520. if (def.is_returned()) {
  521. out << "returned ";
  522. }
  523. out << "var ";
  524. PatternToCarbon(def.pattern(), out);
  525. if (def.has_init()) {
  526. out << " = ";
  527. ExpressionToCarbon(def.init(), out);
  528. }
  529. out << ";";
  530. break;
  531. }
  532. case Fuzzing::Statement::kIfStatement: {
  533. const auto& if_statement = statement.if_statement();
  534. out << "if (";
  535. ExpressionToCarbon(if_statement.condition(), out);
  536. out << ") ";
  537. BlockStatementToCarbon(if_statement.then_block(), out);
  538. // `else` is optional.
  539. if (if_statement.has_else_block()) {
  540. out << " else ";
  541. BlockStatementToCarbon(if_statement.else_block(), out);
  542. }
  543. break;
  544. }
  545. case Fuzzing::Statement::kReturnVarStatement: {
  546. out << "return var;";
  547. break;
  548. }
  549. case Fuzzing::Statement::kReturnExpressionStatement: {
  550. const auto& ret = statement.return_expression_statement();
  551. out << "return";
  552. if (!ret.is_omitted_expression()) {
  553. out << " ";
  554. ExpressionToCarbon(ret.expression(), out);
  555. }
  556. out << ";";
  557. break;
  558. }
  559. case Fuzzing::Statement::kBlock:
  560. BlockStatementToCarbon(statement.block(), out);
  561. break;
  562. case Fuzzing::Statement::kWhileStatement: {
  563. const auto& while_statement = statement.while_statement();
  564. out << "while (";
  565. ExpressionToCarbon(while_statement.condition(), out);
  566. out << ") ";
  567. BlockStatementToCarbon(while_statement.body(), out);
  568. break;
  569. }
  570. case Fuzzing::Statement::kForStatement: {
  571. const auto& for_statement = statement.for_statement();
  572. out << "for (";
  573. BindingPatternToCarbon(for_statement.var_decl(), out);
  574. out << " in ";
  575. ExpressionToCarbon(for_statement.target(), out);
  576. out << ") ";
  577. BlockStatementToCarbon(for_statement.body(), out);
  578. break;
  579. }
  580. case Fuzzing::Statement::kMatch: {
  581. const auto& match = statement.match();
  582. out << "match (";
  583. ExpressionToCarbon(match.expression(), out);
  584. out << ") {";
  585. for (const auto& clause : match.clauses()) {
  586. if (clause.is_default()) {
  587. out << "default";
  588. } else {
  589. out << "case ";
  590. PatternToCarbon(clause.pattern(), out);
  591. }
  592. out << " => ";
  593. StatementToCarbon(clause.statement(), out);
  594. }
  595. out << "}";
  596. break;
  597. }
  598. case Fuzzing::Statement::kBreakStatement:
  599. out << "break;";
  600. break;
  601. case Fuzzing::Statement::kContinueStatement:
  602. out << "continue;";
  603. break;
  604. }
  605. }
  606. static auto ReturnTermToCarbon(const Fuzzing::ReturnTerm& return_term,
  607. llvm::raw_ostream& out) -> void {
  608. switch (return_term.kind()) {
  609. case Fuzzing::ReturnTerm::UnknownReturnKind:
  610. case Fuzzing::ReturnTerm::Omitted:
  611. break;
  612. case Fuzzing::ReturnTerm::Auto:
  613. out << " -> auto";
  614. break;
  615. case Fuzzing::ReturnTerm::Expression:
  616. out << " -> ";
  617. ExpressionToCarbon(return_term.type(), out);
  618. break;
  619. }
  620. }
  621. static auto DeclaredNameToCarbon(const Fuzzing::DeclaredName& name,
  622. llvm::raw_ostream& out) -> void {
  623. for (const std::string& qual : name.qualifiers()) {
  624. IdentifierToCarbon(qual, out);
  625. out << ".";
  626. }
  627. IdentifierToCarbon(name.name(), out);
  628. }
  629. static auto DeclarationToCarbon(const Fuzzing::Declaration& declaration,
  630. llvm::raw_ostream& out) -> void {
  631. switch (declaration.kind_case()) {
  632. case Fuzzing::Declaration::KIND_NOT_SET: {
  633. // Arbitrary default to avoid getting invalid syntax.
  634. out << "var x: i32;";
  635. break;
  636. }
  637. case Fuzzing::Declaration::kNamespace: {
  638. out << "namespace ";
  639. DeclaredNameToCarbon(declaration.namespace_().name(), out);
  640. out << ";";
  641. break;
  642. }
  643. case Fuzzing::Declaration::kDestructor: {
  644. const auto& function = declaration.destructor();
  645. out << "destructor";
  646. llvm::ListSeparator sep;
  647. out << "[";
  648. if (function.has_self_pattern()) {
  649. // This is a class method.
  650. out << sep;
  651. PatternToCarbon(function.self_pattern(), out);
  652. }
  653. out << "]";
  654. // Body is optional.
  655. if (function.has_body()) {
  656. out << "\n";
  657. BlockStatementToCarbon(function.body(), out);
  658. } else {
  659. out << ";";
  660. }
  661. break;
  662. }
  663. case Fuzzing::Declaration::kFunction: {
  664. const auto& function = declaration.function();
  665. out << "fn ";
  666. DeclaredNameToCarbon(function.name(), out);
  667. if (!function.deduced_parameters().empty() ||
  668. function.has_self_pattern()) {
  669. out << "[";
  670. llvm::ListSeparator sep;
  671. for (const Fuzzing::GenericBinding& p : function.deduced_parameters()) {
  672. out << sep;
  673. GenericBindingToCarbon(p, out);
  674. }
  675. if (function.has_self_pattern()) {
  676. // This is a class method.
  677. out << sep;
  678. PatternToCarbon(function.self_pattern(), out);
  679. }
  680. out << "]";
  681. }
  682. TuplePatternToCarbon(function.param_pattern(), out);
  683. ReturnTermToCarbon(function.return_term(), out);
  684. // Body is optional.
  685. if (function.has_body()) {
  686. out << "\n";
  687. BlockStatementToCarbon(function.body(), out);
  688. } else {
  689. out << ";";
  690. }
  691. break;
  692. }
  693. case Fuzzing::Declaration::kClassDeclaration: {
  694. const auto& class_declaration = declaration.class_declaration();
  695. out << "class ";
  696. DeclaredNameToCarbon(class_declaration.name(), out);
  697. // type_params is optional.
  698. if (class_declaration.has_type_params()) {
  699. TuplePatternToCarbon(class_declaration.type_params(), out);
  700. }
  701. out << "{\n";
  702. for (const auto& member : class_declaration.members()) {
  703. DeclarationToCarbon(member, out);
  704. out << "\n";
  705. }
  706. out << "}";
  707. break;
  708. }
  709. case Fuzzing::Declaration::kExtendBase: {
  710. const auto& extend_base_declaration = declaration.extend_base();
  711. out << " extend base: ";
  712. ExpressionToCarbon(extend_base_declaration.base_class(), out);
  713. out << ";\n";
  714. break;
  715. }
  716. // EXPERIMENTAL MIXIN FEATURE
  717. case Fuzzing::Declaration::kMixin: {
  718. const auto& mixin_declaration = declaration.mixin();
  719. out << "__mixin ";
  720. DeclaredNameToCarbon(mixin_declaration.name(), out);
  721. // type params are not implemented yet
  722. // if (mixin_declaration.has_params()) {
  723. // TuplePatternToCarbon(mixin_declaration.params(), out);
  724. //}
  725. out << "{\n";
  726. for (const auto& member : mixin_declaration.members()) {
  727. DeclarationToCarbon(member, out);
  728. out << "\n";
  729. }
  730. out << "}";
  731. // TODO: need to handle interface.self()?
  732. break;
  733. }
  734. // EXPERIMENTAL MIXIN FEATURE
  735. case Fuzzing::Declaration::kMix: {
  736. const auto& mix_declaration = declaration.mix();
  737. out << "__mix ";
  738. ExpressionToCarbon(mix_declaration.mixin(), out);
  739. out << ";";
  740. break;
  741. }
  742. case Fuzzing::Declaration::kChoice: {
  743. const auto& choice = declaration.choice();
  744. out << "choice ";
  745. DeclaredNameToCarbon(choice.name(), out);
  746. out << "{";
  747. llvm::ListSeparator sep;
  748. for (const auto& alternative : choice.alternatives()) {
  749. out << sep;
  750. IdentifierToCarbon(alternative.name(), out);
  751. if (alternative.has_signature()) {
  752. TupleLiteralExpressionToCarbon(alternative.signature(), out);
  753. }
  754. }
  755. out << "}";
  756. break;
  757. }
  758. case Fuzzing::Declaration::kVariable: {
  759. const auto& var = declaration.variable();
  760. out << "var ";
  761. BindingPatternToCarbon(var.binding(), out);
  762. // Initializer is optional.
  763. if (var.has_initializer()) {
  764. out << " = ";
  765. ExpressionToCarbon(var.initializer(), out);
  766. }
  767. out << ";";
  768. break;
  769. }
  770. case Fuzzing::Declaration::kLet: {
  771. const auto& let = declaration.let();
  772. out << "let ";
  773. PatternToCarbon(let.pattern(), out);
  774. // TODO: Print out the initializer once it's supported.
  775. // if (let.has_initializer()) {
  776. // out << " = ";
  777. // ExpressionToCarbon(let.initializer(), out);
  778. // }
  779. out << ";";
  780. break;
  781. }
  782. case Fuzzing::Declaration::kInterfaceExtend: {
  783. const auto& extend = declaration.interface_extend();
  784. out << "extend ";
  785. ExpressionToCarbon(extend.base(), out);
  786. out << ";";
  787. break;
  788. }
  789. case Fuzzing::Declaration::kInterfaceRequire: {
  790. const auto& impl = declaration.interface_require();
  791. out << "require ";
  792. ExpressionToCarbon(impl.impl_type(), out);
  793. out << " impls ";
  794. ExpressionToCarbon(impl.constraint(), out);
  795. out << ";";
  796. break;
  797. }
  798. case Fuzzing::Declaration::kInterface: {
  799. const auto& interface = declaration.interface();
  800. out << "interface ";
  801. DeclaredNameToCarbon(interface.name(), out);
  802. out << " {\n";
  803. for (const auto& member : interface.members()) {
  804. DeclarationToCarbon(member, out);
  805. out << "\n";
  806. }
  807. out << "}";
  808. break;
  809. }
  810. case Fuzzing::Declaration::kConstraint: {
  811. const auto& constraint = declaration.constraint();
  812. out << "constraint ";
  813. DeclaredNameToCarbon(constraint.name(), out);
  814. out << " {\n";
  815. for (const auto& member : constraint.members()) {
  816. DeclarationToCarbon(member, out);
  817. out << "\n";
  818. }
  819. out << "}";
  820. break;
  821. }
  822. case Fuzzing::Declaration::kImpl: {
  823. const auto& impl = declaration.impl();
  824. if (impl.kind() == Fuzzing::ImplDeclaration::InternalImpl) {
  825. out << "extend ";
  826. }
  827. out << "impl ";
  828. if (!impl.deduced_parameters().empty()) {
  829. out << "forall [";
  830. llvm::ListSeparator sep;
  831. for (const Fuzzing::GenericBinding& p : impl.deduced_parameters()) {
  832. out << sep;
  833. GenericBindingToCarbon(p, out);
  834. }
  835. out << "] ";
  836. }
  837. if (impl.kind() != Fuzzing::ImplDeclaration::InternalImpl) {
  838. ExpressionToCarbon(impl.impl_type(), out);
  839. out << " ";
  840. }
  841. out << "as ";
  842. ExpressionToCarbon(impl.interface(), out);
  843. out << " {\n";
  844. for (const auto& member : impl.members()) {
  845. DeclarationToCarbon(member, out);
  846. out << "\n";
  847. }
  848. out << "}";
  849. break;
  850. }
  851. case Fuzzing::Declaration::kMatchFirst: {
  852. const auto& match_first = declaration.match_first();
  853. out << "__match_first {\n";
  854. for (const auto& impl : match_first.impl_declarations()) {
  855. DeclarationToCarbon(impl, out);
  856. out << "\n";
  857. }
  858. out << "}";
  859. break;
  860. }
  861. case Fuzzing::Declaration::kAlias: {
  862. const auto& alias = declaration.alias();
  863. out << "alias ";
  864. DeclaredNameToCarbon(alias.name(), out);
  865. out << " = ";
  866. ExpressionToCarbon(alias.target(), out);
  867. out << ";";
  868. break;
  869. }
  870. }
  871. }
  872. auto ProtoToCarbon(const Fuzzing::Carbon& proto, bool maybe_add_main)
  873. -> std::string {
  874. std::string source;
  875. llvm::raw_string_ostream out(source);
  876. out << "// Generated by proto_to_carbon.\n"
  877. "package ";
  878. const auto& unit = proto.compilation_unit();
  879. LibraryNameToCarbon(unit.package_statement(), out);
  880. out << (unit.is_api() ? " api" : " impl") << ";\n\n";
  881. bool has_main = false;
  882. if (!unit.declarations().empty()) {
  883. for (const auto& declaration : unit.declarations()) {
  884. DeclarationToCarbon(declaration, out);
  885. if (declaration.kind_case() == Fuzzing::Declaration::kFunction &&
  886. declaration.function().name().name() == "Main") {
  887. has_main = true;
  888. }
  889. out << "\n";
  890. }
  891. }
  892. if (maybe_add_main && !has_main) {
  893. out << "fn Main() -> i32 { return 0; }\n";
  894. }
  895. return source;
  896. }
  897. auto ParseCarbonTextProto(const std::string& contents)
  898. -> ErrorOr<Fuzzing::Carbon> {
  899. google::protobuf::TextFormat::Parser parser;
  900. Fuzzing::Carbon carbon_proto;
  901. if (!parser.ParseFromString(contents, &carbon_proto)) {
  902. return ErrorBuilder() << "Couldn't parse Carbon text proto";
  903. }
  904. return carbon_proto;
  905. }
  906. } // namespace Carbon
  907. // NOLINTEND(misc-no-recursion)