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, ®istry),
19 Command::Repl {
20 initial_language,
21 detect_language,
22 } => {
23 let language = resolve_language(initial_language, detect_language, None, ®istry)?;
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}