compactp 0.1.0-beta.1

A production-grade parser frontend for the Compact language (Midnight Network)
use crate::Cli;
use crate::error::CliError;
use crate::input::resolve_inputs;
use crate::output::OutputEnvelope;
use serde::Serialize;
use std::path::PathBuf;
use std::time::Instant;

#[derive(Debug, Clone, Serialize)]
struct TokenInfo {
    kind: String,
    text: String,
    offset: u32,
    len: u32,
}

pub fn run(cli: &Cli, paths: &[PathBuf]) -> Result<i32, CliError> {
    let inputs = resolve_inputs(paths, cli.stdin_filename.as_deref())?;

    for input in inputs {
        let start = Instant::now();
        let tokens = compactp_lexer::lex(&input.source);
        let elapsed = start.elapsed();

        match cli.format {
            crate::OutputFormat::Json => {
                let mut offset = 0u32;
                let token_infos: Vec<TokenInfo> = tokens
                    .iter()
                    .map(|(kind, text)| {
                        let len = text.len() as u32;
                        let info = TokenInfo {
                            kind: format!("{kind:?}"),
                            text: text.to_string(),
                            offset,
                            len,
                        };
                        offset += len;
                        info
                    })
                    .collect();

                let timing_ms = cli.timing.then_some(elapsed.as_secs_f64() * 1000.0);
                let envelope = OutputEnvelope::new(input.label.clone(), token_infos, timing_ms);
                crate::output::print_json(&envelope, cli.pretty)?;
            }
            crate::OutputFormat::Human => {
                let mut offset = 0usize;
                for (kind, text) in &tokens {
                    let len = text.len();
                    println!("{kind:?} {offset}..{} {text:?}", offset + len);
                    offset += len;
                }
                if cli.timing {
                    eprintln!("Lexed in {:.2}ms", elapsed.as_secs_f64() * 1000.0);
                }
            }
        }
    }

    Ok(0)
}