main.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. fs::{read_to_string, File},
  20. io::Write,
  21. process::exit,
  22. };
  23. use clap::Parser as ClapParser;
  24. use darkfi::{
  25. cli_desc,
  26. zkas::{Analyzer, Compiler, Lexer, Parser, ZkBinary},
  27. };
  28. #[derive(clap::Parser)]
  29. #[clap(name = "zkas", about = cli_desc!(), version)]
  30. struct Args {
  31. /// Place the output into `<FILE>`
  32. #[clap(short = 'o', value_name = "FILE")]
  33. output: Option<String>,
  34. /// Strip debug symbols
  35. #[clap(short = 's')]
  36. strip: bool,
  37. /// Preprocess only; do not compile
  38. #[clap(short = 'E')]
  39. evaluate: bool,
  40. /// Interactive semantic analysis
  41. #[clap(short = 'i')]
  42. interactive: bool,
  43. /// Examine decoded bytecode
  44. #[clap(short = 'e')]
  45. examine: bool,
  46. /// ZK script to compile
  47. input: String,
  48. }
  49. fn main() {
  50. let args = Args::parse();
  51. let filename = args.input.as_str();
  52. let source = match read_to_string(filename) {
  53. Ok(v) => v,
  54. Err(e) => {
  55. eprintln!("Error: Failed reading from \"{}\". {}", filename, e);
  56. exit(1);
  57. }
  58. };
  59. // Clean up tabs, and convert CRLF to LF.
  60. let source = source.replace('\t', " ").replace("\r\n", "\n");
  61. // ANCHOR: zkas
  62. // The lexer goes over the input file and separates its content into
  63. // tokens that get fed into a parser.
  64. let lexer = Lexer::new(filename, source.chars());
  65. let tokens = lexer.lex();
  66. // The parser goes over the tokens provided by the lexer and builds
  67. // the initial AST, not caring much about the semantics, just enforcing
  68. // syntax and general structure.
  69. let parser = Parser::new(filename, source.chars(), tokens);
  70. let (namespace, constants, witnesses, statements) = parser.parse();
  71. // The analyzer goes through the initial AST provided by the parser and
  72. // converts return and variable types to their correct forms, and also
  73. // checks that the semantics of the ZK script are correct.
  74. let mut analyzer = Analyzer::new(filename, source.chars(), constants, witnesses, statements);
  75. analyzer.analyze_types();
  76. if args.interactive {
  77. analyzer.analyze_semantic();
  78. }
  79. if args.evaluate {
  80. println!("{:#?}", analyzer.constants);
  81. println!("{:#?}", analyzer.witnesses);
  82. println!("{:#?}", analyzer.statements);
  83. println!("{:#?}", analyzer.heap);
  84. exit(0);
  85. }
  86. let compiler = Compiler::new(
  87. filename,
  88. source.chars(),
  89. namespace,
  90. analyzer.constants,
  91. analyzer.witnesses,
  92. analyzer.statements,
  93. analyzer.literals,
  94. !args.strip,
  95. );
  96. let bincode = compiler.compile();
  97. // ANCHOR_END: zkas
  98. let output = match args.output {
  99. Some(o) => o,
  100. None => format!("{}.bin", args.input),
  101. };
  102. let mut file = match File::create(&output) {
  103. Ok(v) => v,
  104. Err(e) => {
  105. eprintln!("Error: Failed to create \"{}\". {}", output, e);
  106. exit(1);
  107. }
  108. };
  109. if let Err(e) = file.write_all(&bincode) {
  110. eprintln!("Error: Failed to write bincode to \"{}\". {}", output, e);
  111. exit(1);
  112. };
  113. println!("Wrote output to {}", &output);
  114. if args.examine {
  115. let zkbin = ZkBinary::decode(&bincode).unwrap();
  116. println!("{:#?}", zkbin);
  117. }
  118. }