1use std::{
20 fs::{read_to_string, File},
21 io::Write,
22 process::ExitCode,
23};
24
25use arg::Args;
26
27use darkfi::{
28 zkas::{Analyzer, Compiler, Lexer, Parser, ZkBinary},
29 ANSI_LOGO,
30};
31
32const ABOUT: &str =
33 concat!("zkas ", env!("CARGO_PKG_VERSION"), '\n', env!("CARGO_PKG_DESCRIPTION"));
34
35const USAGE: &str = r#"
36Usage: zkas [OPTIONS] <INPUT>
37
38Arguments:
39 <INPUT> ZK script to compile
40
41Options:
42 -o <FILE> Place the output into <FILE>
43 -s Strip debug symbols
44 -p Preprocess only; do not compile
45 -i Interactive semantic analysis
46 -e Examine decoded bytecode
47 -h Print this help
48"#;
49
50fn usage() {
51 print!("{}{}\n{}", ANSI_LOGO, ABOUT, USAGE);
52}
53
54fn main() -> ExitCode {
55 let argv;
56 let mut pflag = false;
57 let mut iflag = false;
58 let mut eflag = false;
59 let mut sflag = false;
60 let mut hflag = false;
61 let mut output = String::new();
62
63 {
64 let mut args = Args::new().with_cb(|args, flag| match flag {
65 'p' => pflag = true,
66 'i' => iflag = true,
67 'e' => eflag = true,
68 's' => sflag = true,
69 'o' => output = args.eargf().to_string(),
70 _ => hflag = true,
71 });
72
73 argv = args.parse();
74 }
75
76 if hflag || argv.is_empty() {
77 usage();
78 return ExitCode::FAILURE
79 }
80
81 let filename = argv[0].as_str();
82 let source = match read_to_string(filename) {
83 Ok(v) => v,
84 Err(e) => {
85 eprintln!("Error: Failed reading from \"{}\". {}", filename, e);
86 return ExitCode::FAILURE
87 }
88 };
89
90 let source = source.replace('\t', " ").replace("\r\n", "\n");
92
93 let lexer = Lexer::new(filename, source.chars());
97 let tokens = match lexer.lex() {
98 Ok(v) => v,
99 Err(_) => return ExitCode::FAILURE,
100 };
101
102 let parser = Parser::new(filename, source.chars(), tokens);
106 let (namespace, k, constants, witnesses, statements) = match parser.parse() {
107 Ok(v) => v,
108 Err(_) => return ExitCode::FAILURE,
109 };
110
111 let mut analyzer = Analyzer::new(filename, source.chars(), constants, witnesses, statements);
115 if analyzer.analyze_types().is_err() {
116 return ExitCode::FAILURE
117 }
118
119 if iflag && analyzer.analyze_semantic().is_err() {
120 return ExitCode::FAILURE
121 }
122
123 if pflag {
124 println!("{:#?}", analyzer.constants);
125 println!("{:#?}", analyzer.witnesses);
126 println!("{:#?}", analyzer.statements);
127 println!("{:#?}", analyzer.heap);
128 return ExitCode::SUCCESS
129 }
130
131 let compiler = Compiler::new(
132 filename,
133 source.chars(),
134 namespace,
135 k,
136 analyzer.constants,
137 analyzer.witnesses,
138 analyzer.statements,
139 analyzer.literals,
140 !sflag,
141 );
142
143 let bincode = match compiler.compile() {
144 Ok(v) => v,
145 Err(_) => return ExitCode::FAILURE,
146 };
147 let output = if output.is_empty() { format!("{}.bin", filename) } else { output };
150
151 let mut file = match File::create(&output) {
152 Ok(v) => v,
153 Err(e) => {
154 eprintln!("Error: Failed to create \"{}\". {}", output, e);
155 return ExitCode::FAILURE
156 }
157 };
158
159 if let Err(e) = file.write_all(&bincode) {
160 eprintln!("Error: Failed to write bincode to \"{}\". {}", output, e);
161 return ExitCode::FAILURE
162 };
163
164 println!("Wrote output to {}", &output);
165
166 if eflag {
167 let zkbin = ZkBinary::decode(&bincode).unwrap();
168 println!("{:#?}", zkbin);
169 }
170
171 ExitCode::SUCCESS
172}