laconic 2.0.0

Interpreter for Laconic expressions and scripts, both as a library component and command-line executable
Documentation
use std::env::args;
use std::fs::read_to_string;
use laconic::Interpreter;

fn main() {
    let mut script = String::new();
    let mut show_before = false;
    let mut show_after = false;
    let mut do_execute = true;
    let mut expect_file_name = false;
    let mut be_quiet = false;
    let mut ignore_errors = false;

    for arg_tuple in args().enumerate() {
        match arg_tuple {
            (0, _) => (),
            (_, arg) =>  {
                if !arg.starts_with('-') {
                    if expect_file_name {
                        expect_file_name = false;

                        match read_to_string(&arg) {
                            Ok(content) => script.push_str(&content),
                            Err(msg) => panic!("Error while reading {}: {}", &arg, msg),
                        }
                    } else {
                        script.push_str(&arg);
                    }
                } else {
                    if arg.contains('a') {
                        show_after = true;
                    }

                    if arg.contains('b') {
                        show_before = true;
                    }

                    if arg.contains('n') {
                        do_execute = false;
                    }

                    if arg.contains('q') {
                        be_quiet = true;
                    }

                    if arg.contains('I') {
                        ignore_errors = true;
                    }

                    if arg.contains('i') && !expect_file_name {
                        expect_file_name = true;
                    }
                }
            },
        }
    }

    if !script.is_empty() {
        let mut interpreter = Interpreter::new_stdio_filesys();

        if ignore_errors {
            interpreter.suppress_exit_on_error(true);
        }

        let exe_result = interpreter.execute_opts(
            script,
            do_execute,
            show_before,
            show_after
        );

        if !(interpreter.is_quiet() || be_quiet) {
            match exe_result {
                Ok(outcome) => {
                        println!("{}", outcome.string_representation())
                },
                Err(err) => println!("{err:?}"),
            }
        }
    } else {
        show_syntax();
    }
}

fn show_syntax() {
    println!("Usage: laconic <options> 'script'");
    println!();
    println!("Options :");
    println!("    -n    Don't execute the script");
    println!("    -b    Show the script as a tree of operators before execution.");
    println!("    -a    Show the script as a tree of operators after  execution.");
    println!("    -i    Include the contents of a file into the script.");
    println!("    -q    Don't print the outcome or error messages to standard output.");
    println!("            (Output of the w operator will still be printed.)");
    println!("    -I    Ignore errors: don't stop execution immediately when an error occurs.");
    println!();
    println!("Options can be combined:");
    println!("    laconic -bn '*440 ^2 /1 12");
    println!("    won't calculate, but will show the operators tree of a calculation");
    println!("    of the first semitone higher than the diapason.");
    println!();
    println!("E.g. : laconic ' $0 1 $1 0 W!>v0 4 ;+:1 v0 +:0 1 v1'");
    println!("       will yield 10 (summation of 4)");
    println!("In a shell that supports multi-line commands,");
    println!("the script can be split over multiple lines, e.g.:");
    println!();
    println!("laconic");
    println!("' $0 1'");
    println!("' $1 0'");
    println!("' W'");
    println!("'   !>v0 4'");
    println!("'   ;'");
    println!("'     +:1 v0'");
    println!("'     +:0 1'");
    println!("' v1'");
    println!();
    println!("Statements in a script file can be included in the script");
    println!("using the -i parameter:");
    println!();
    println!("Statements in the command line before the -i parameter ");
    println!("will be included before the script file's statements;");
    println!("Statements in the command line after the -i parameter ");
    println!("will be included after the script file's statements.");
    println!();
    println!("E.g. :");
    println!("      given script file clearStack.lac having the statements");
    println!();
    println!("          Wk,k");
    println!();
    println!("      the below command");
    println!();
    println!("          $ laconic 'o§fmt 0 K(10 20 30 40) wk,' -i clearStack.lac 'wk,'");
    println!();
    println!("      will output:");
    println!();
    println!("          4");
    println!("          0");
    println!();
    println!("It's even possible to include multiple script files this way: e.g.:");
    println!();
    println!("          $ laconic -i script1.lac -i script2.lac '[c Statements ...]' -i script3.lac '[c Other statements ...]'");
    println!();
}