///|
const VERSION : String = "0.1.1"
///|
priv enum InputSource {
Eval(String)
Stdin
File(String)
}
///|
priv enum CliParseResult {
Error(String)
Run(InputSource)
}
///|
fn scheme_command() -> @argparse.Command {
Command(
"scheme",
about="Run an R6RS Scheme expression or program.",
version="scheme \{VERSION}",
options=[
OptionArg(
"eval",
short='e',
about="Evaluate EXPR and print the result.",
allow_hyphen_values=true,
conflicts_with=["file"],
),
],
positionals=[
PositionArg(
"file",
about="Scheme source file, or - for stdin.",
num_args=ValueRange(lower=0, upper=1),
conflicts_with=["eval"],
),
],
disable_help_subcommand=true,
)
}
///|
fn parse_cli() -> CliParseResult {
let command = scheme_command()
let matches = command.parse() catch { err => return Error(err.to_string()) }
match matches.values.get("eval").unwrap_or([]) {
[source] => Run(Eval(source))
[] =>
match matches.values.get("file").unwrap_or([]) {
[] | ["-"] => Run(Stdin)
[path] => Run(File(path))
_ => Error("scheme: expected at most one FILE")
}
_ => Error("scheme: expected one EXPR after --eval")
}
}
///|
async fn read_program_source(source : InputSource) -> String {
match source {
Eval(source) => source
Stdin => @stdio.stdin.read_all().text()
File(path) => @fs.read_file(path).text()
}
}
///|
async fn eval_and_print(source : String) -> Unit {
try @scheme_r6rs.eval_program(source) catch {
err => {
@stdio.stderr.write("scheme: \{err}\n")
exit_process(1)
}
} noraise {
value => @stdio.stdout.write("\{@scheme_r6rs.value_to_string(value)}\n")
}
}
///|
async fn main {
match parse_cli() {
Error(message) => {
@stdio.stderr.write(message)
if !message.has_suffix("\n") {
@stdio.stderr.write("\n")
}
exit_process(2)
}
Run(input) => {
let source = read_program_source(input) catch {
err => {
@stdio.stderr.write("scheme: \{err}\n")
exit_process(1)
return
}
}
eval_and_print(source)
}
}
}
///|
fn exit_process(code : Int) = "wasi_snapshot_preview1" "proc_exit"