main.rs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. use std::{
  2. fs::{read_to_string, File},
  3. io::Write,
  4. process::exit,
  5. };
  6. use clap::Parser as ClapParser;
  7. use darkfi::{
  8. cli_desc,
  9. zkas::{Analyzer, Compiler, Lexer, Parser, ZkBinary},
  10. };
  11. #[derive(clap::Parser)]
  12. #[clap(name = "zkas", about = cli_desc!(), version)]
  13. struct Args {
  14. /// Place the output into <FILE>
  15. #[clap(short = 'o', value_name = "FILE")]
  16. output: Option<String>,
  17. /// Strip debug symbols
  18. #[clap(short = 's')]
  19. strip: bool,
  20. /// Preprocess only; do not compile
  21. #[clap(short = 'E')]
  22. evaluate: bool,
  23. /// Interactive semantic analysis
  24. #[clap(short = 'i')]
  25. interactive: bool,
  26. /// Examine decoded bytecode
  27. #[clap(short = 'e')]
  28. examine: bool,
  29. /// ZK script to compile
  30. input: String,
  31. }
  32. fn main() {
  33. let args = Args::parse();
  34. let filename = args.input.as_str();
  35. let source = match read_to_string(filename) {
  36. Ok(v) => v,
  37. Err(e) => {
  38. eprintln!("Error: Failed reading from \"{}\". {}", filename, e);
  39. exit(1);
  40. }
  41. };
  42. // Clean up tabs, and convert CRLF to LF.
  43. let source = source.replace('\t', " ").replace("\r\n", "\n");
  44. // The lexer goes over the input file and separates its content into
  45. // tokens that get fed into a parser.
  46. let lexer = Lexer::new(filename, source.chars());
  47. let tokens = lexer.lex();
  48. // The parser goes over the tokens provided by the lexer and builds
  49. // the initial AST, not caring much about the semantics, just enforcing
  50. // syntax and general structure.
  51. let parser = Parser::new(filename, source.chars(), tokens);
  52. let (constants, witnesses, statements) = parser.parse();
  53. // The analyzer goes through the initial AST provided by the parser and
  54. // converts return and variable types to their correct forms, and also
  55. // checks that the semantics of the ZK script are correct.
  56. let mut analyzer = Analyzer::new(filename, source.chars(), constants, witnesses, statements);
  57. analyzer.analyze_types();
  58. if args.interactive {
  59. analyzer.analyze_semantic();
  60. }
  61. if args.evaluate {
  62. println!("{:#?}", analyzer.constants);
  63. println!("{:#?}", analyzer.witnesses);
  64. println!("{:#?}", analyzer.statements);
  65. println!("{:#?}", analyzer.stack);
  66. exit(0);
  67. }
  68. let compiler = Compiler::new(
  69. filename,
  70. source.chars(),
  71. analyzer.constants,
  72. analyzer.witnesses,
  73. analyzer.statements,
  74. analyzer.literals,
  75. !args.strip,
  76. );
  77. let bincode = compiler.compile();
  78. let output = match args.output {
  79. Some(o) => o,
  80. None => format!("{}.bin", args.input),
  81. };
  82. let mut file = match File::create(&output) {
  83. Ok(v) => v,
  84. Err(e) => {
  85. eprintln!("Error: Failed to create \"{}\". {}", output, e);
  86. exit(1);
  87. }
  88. };
  89. if let Err(e) = file.write_all(&bincode) {
  90. eprintln!("Error: Failed to write bincode to \"{}\". {}", output, e);
  91. exit(1);
  92. };
  93. println!("Wrote output to {}", &output);
  94. if args.examine {
  95. let zkbin = ZkBinary::decode(&bincode).unwrap();
  96. println!("{:#?}", zkbin);
  97. }
  98. }