run/
app.rs

1use std::io::{self, Write};
2
3use anyhow::{Context, Result};
4
5use crate::cli::{Command, ExecutionSpec};
6use crate::engine::{
7    ExecutionPayload, LanguageRegistry, default_language, detect_language_for_source,
8    ensure_known_language,
9};
10use crate::language::LanguageSpec;
11use crate::repl;
12use crate::version;
13
14pub fn run(command: Command) -> Result<i32> {
15    let registry = LanguageRegistry::bootstrap();
16
17    match command {
18        Command::Execute(spec) => execute_once(spec, &registry),
19        Command::Repl {
20            initial_language,
21            detect_language,
22        } => {
23            let language = resolve_language(initial_language, detect_language, None, &registry)?;
24            repl::run_repl(language, registry, detect_language)
25        }
26        Command::ShowVersion => {
27            println!("{}", version::describe());
28            Ok(0)
29        }
30    }
31}
32
33fn execute_once(spec: ExecutionSpec, registry: &LanguageRegistry) -> Result<i32> {
34    let payload = ExecutionPayload::from_input_source(&spec.source)
35        .context("failed to materialize execution payload")?;
36    let language = resolve_language(
37        spec.language,
38        spec.detect_language,
39        Some(&payload),
40        registry,
41    )?;
42
43    let engine = registry
44        .resolve(&language)
45        .context("failed to resolve language engine")?;
46
47    engine.validate().ok();
48    let outcome = engine.execute(&payload)?;
49
50    if !outcome.stdout.is_empty() {
51        print!("{}", outcome.stdout);
52        io::stdout().flush().ok();
53    }
54    if !outcome.stderr.is_empty() {
55        eprint!("{}", outcome.stderr);
56        io::stderr().flush().ok();
57    }
58
59    Ok(outcome
60        .exit_code
61        .unwrap_or(if outcome.success() { 0 } else { 1 }))
62}
63
64fn resolve_language(
65    explicit: Option<LanguageSpec>,
66    allow_detect: bool,
67    payload: Option<&ExecutionPayload>,
68    registry: &LanguageRegistry,
69) -> Result<LanguageSpec> {
70    if let Some(spec) = explicit {
71        ensure_known_language(&spec, registry)?;
72        return Ok(spec);
73    }
74
75    if allow_detect {
76        if let Some(payload) = payload {
77            if let Some(detected) = detect_language_for_source(payload, registry) {
78                return Ok(detected);
79            }
80        }
81    }
82
83    let default = LanguageSpec::new(default_language());
84    ensure_known_language(&default, registry)?;
85    Ok(default)
86}