| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use std::{
- fs::{read_to_string, File},
- io::Write,
- process::ExitCode,
- };
- use arg::Args;
- use darkfi::{
- zkas::{Analyzer, Compiler, Lexer, Parser, ZkBinary},
- ANSI_LOGO,
- };
- const ABOUT: &str =
- concat!("zkas ", env!("CARGO_PKG_VERSION"), '\n', env!("CARGO_PKG_DESCRIPTION"));
- const USAGE: &str = r#"
- Usage: zkas [OPTIONS] <INPUT>
- Arguments:
- <INPUT> ZK script to compile
- Options:
- -o <FILE> Place the output into <FILE>
- -s Strip debug symbols
- -p Preprocess only; do not compile
- -i Interactive semantic analysis
- -e Examine decoded bytecode
- -h Print this help
- "#;
- fn usage() {
- print!("{}{}\n{}", ANSI_LOGO, ABOUT, USAGE);
- }
- fn main() -> ExitCode {
- let argv;
- let mut pflag = false;
- let mut iflag = false;
- let mut eflag = false;
- let mut sflag = false;
- let mut hflag = false;
- let mut output = String::new();
- {
- let mut args = Args::new().with_cb(|args, flag| match flag {
- 'p' => pflag = true,
- 'i' => iflag = true,
- 'e' => eflag = true,
- 's' => sflag = true,
- 'o' => output = args.eargf().to_string(),
- _ => hflag = true,
- });
- argv = args.parse();
- }
- if hflag || argv.is_empty() {
- usage();
- return ExitCode::FAILURE
- }
- let filename = argv[0].as_str();
- let source = match read_to_string(filename) {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error: Failed reading from \"{}\". {}", filename, e);
- return ExitCode::FAILURE
- }
- };
- // Clean up tabs, and convert CRLF to LF.
- let source = source.replace('\t', " ").replace("\r\n", "\n");
- // ANCHOR: zkas
- // The lexer goes over the input file and separates its content into
- // tokens that get fed into a parser.
- let lexer = Lexer::new(filename, source.chars());
- let tokens = match lexer.lex() {
- Ok(v) => v,
- Err(_) => return ExitCode::FAILURE,
- };
- // The parser goes over the tokens provided by the lexer and builds
- // the initial AST, not caring much about the semantics, just enforcing
- // syntax and general structure.
- let parser = Parser::new(filename, source.chars(), tokens);
- let (namespace, k, constants, witnesses, statements) = match parser.parse() {
- Ok(v) => v,
- Err(_) => return ExitCode::FAILURE,
- };
- // The analyzer goes through the initial AST provided by the parser and
- // converts return and variable types to their correct forms, and also
- // checks that the semantics of the ZK script are correct.
- let mut analyzer = Analyzer::new(filename, source.chars(), constants, witnesses, statements);
- if analyzer.analyze_types().is_err() {
- return ExitCode::FAILURE
- }
- if iflag && analyzer.analyze_semantic().is_err() {
- return ExitCode::FAILURE
- }
- if pflag {
- println!("{:#?}", analyzer.constants);
- println!("{:#?}", analyzer.witnesses);
- println!("{:#?}", analyzer.statements);
- println!("{:#?}", analyzer.heap);
- return ExitCode::SUCCESS
- }
- let compiler = Compiler::new(
- filename,
- source.chars(),
- namespace,
- k,
- analyzer.constants,
- analyzer.witnesses,
- analyzer.statements,
- analyzer.literals,
- !sflag,
- );
- let bincode = match compiler.compile() {
- Ok(v) => v,
- Err(_) => return ExitCode::FAILURE,
- };
- // ANCHOR_END: zkas
- let output = if output.is_empty() { format!("{}.bin", filename) } else { output };
- let mut file = match File::create(&output) {
- Ok(v) => v,
- Err(e) => {
- eprintln!("Error: Failed to create \"{}\". {}", output, e);
- return ExitCode::FAILURE
- }
- };
- if let Err(e) = file.write_all(&bincode) {
- eprintln!("Error: Failed to write bincode to \"{}\". {}", output, e);
- return ExitCode::FAILURE
- };
- println!("Wrote output to {}", &output);
- if eflag {
- let zkbin = ZkBinary::decode(&bincode).unwrap();
- println!("{:#?}", zkbin);
- }
- ExitCode::SUCCESS
- }
|