use std::process::ExitCode;
fn main() -> ExitCode {
nodejs::run_on_js_stack(|| {
let code = run();
nodejs::cache::flush();
code
})
}
fn run() -> ExitCode {
let cli = nodejs::cli::parse();
nodejs::stdlib::process::install_argv();
if cli.lsp {
return match nodejs::lsp::run() {
Ok(()) => ExitCode::SUCCESS,
Err(e) => fail(&e),
};
}
if cli.dap {
return match nodejs::dap::run() {
Ok(()) => ExitCode::SUCCESS,
Err(e) => fail(&e),
};
}
match (cli.eval, cli.print) {
(Some(e), Some(p)) => {
return if last_eval_flag_is_print() {
run_print(&p)
} else {
run_source(&e)
}
}
(Some(e), None) => return run_source(&e),
(None, Some(p)) => return run_print(&p),
(None, None) => {}
}
if cli.file.as_deref() == Some("-") {
return run_stdin();
}
if let Some(file) = cli.file {
if cli.dump_bytecode {
return match dump(&file) {
Ok(()) => ExitCode::SUCCESS,
Err(e) => fail(&e),
};
}
if cli.dump_tokens {
return finish(dump_tokens(&file));
}
if cli.dump_ast {
return finish(dump_ast(&file));
}
if cli.disasm {
return finish(disasm(&file));
}
if cli.tiers {
return finish(tiers(&file));
}
if cli.build {
return match nodejs::aot::build(&file) {
Ok(msg) => {
println!("{msg}");
ExitCode::SUCCESS
}
Err(e) => fail(&e),
};
}
return match nodejs::eval_file(&file) {
Ok(_) => program_status(),
Err(e) => fail_program(&e),
};
}
if cli.repl || atty_stdin() {
nodejs::repl::run();
return ExitCode::SUCCESS;
}
run_stdin()
}
fn run_stdin() -> ExitCode {
let src = std::io::read_to_string(std::io::stdin()).unwrap_or_default();
match nodejs::eval_str_from(&src, "[stdin]") {
Ok(_) => program_status(),
Err(e) => fail_program(&e),
}
}
fn run_source(src: &str) -> ExitCode {
match nodejs::eval_str(src) {
Ok(_) => program_status(),
Err(e) => fail_program(&e),
}
}
fn run_print(src: &str) -> ExitCode {
match nodejs::eval_str_print(src, "[eval]") {
Ok(()) => program_status(),
Err(e) => fail_program(&e),
}
}
fn last_eval_flag_is_print() -> bool {
std::env::args()
.rfind(|a| matches!(a.as_str(), "-e" | "--eval" | "-p" | "--print"))
.map(|a| a == "-p" || a == "--print")
.unwrap_or(false)
}
fn dump(file: &str) -> Result<(), String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
let prog = nodejs::compile(&src)?;
println!("== main ==\n{:#?}", prog.main.ops);
for (name, f) in &prog.functions {
let params: Vec<&str> = f.params.iter().map(|p| p.name.as_str()).collect();
println!(
"== function {name} ({}) ==\n{:#?}",
params.join(", "),
f.chunk.ops
);
}
for (i, t) in prog.tries.iter().enumerate() {
println!("== try #{i} ==\n{:#?}", t.block.ops);
}
Ok(())
}
fn dump_tokens(file: &str) -> Result<(), String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
for t in nodejs::lexer::lex(&src)? {
println!("{}\t{:?}", t.line, t.tok);
}
Ok(())
}
fn dump_ast(file: &str) -> Result<(), String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
let stmts = nodejs::parser::parse(&src)?;
println!("{stmts:#?}");
Ok(())
}
fn disasm(file: &str) -> Result<(), String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
let prog = nodejs::compile(&src)?;
println!("; node fusevm — main\n{}", prog.main.disassemble());
for (name, f) in &prog.functions {
let params: Vec<&str> = f.params.iter().map(|p| p.name.as_str()).collect();
println!(
"; node fusevm — function {name} ({})\n{}",
params.join(", "),
f.chunk.disassemble()
);
}
for (i, t) in prog.tries.iter().enumerate() {
println!("; node fusevm — try #{i}\n{}", t.block.disassemble());
}
Ok(())
}
fn tiers(file: &str) -> Result<(), String> {
let src = std::fs::read_to_string(file).map_err(|e| format!("cannot read {file}: {e}"))?;
println!("{}", nodejs::tiers::report(&src)?);
Ok(())
}
fn finish(r: Result<(), String>) -> ExitCode {
match r {
Ok(()) => ExitCode::SUCCESS,
Err(e) => fail(&e),
}
}
fn atty_stdin() -> bool {
unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}
fn fail(msg: &str) -> ExitCode {
eprintln!("node: {msg}");
ExitCode::FAILURE
}
fn fail_program(msg: &str) -> ExitCode {
let code = nodejs::exit_code_after_failure();
eprintln!("node: {msg}");
ExitCode::from((code & 0xff) as u8)
}
fn program_status() -> ExitCode {
match nodejs::exit_code() {
Some(c) => ExitCode::from((c & 0xff) as u8),
None => ExitCode::SUCCESS,
}
}