Files
orchid/orcx/src/main.rs
2025-02-02 10:20:03 +01:00

104 lines
3.0 KiB
Rust

use std::fs::File;
use std::io::Read;
use std::mem;
use std::process::Command;
use std::rc::Rc;
use async_stream::try_stream;
use camino::Utf8PathBuf;
use clap::{Parser, Subcommand};
use futures::{Stream, TryStreamExt, io};
use orchid_base::clone;
use orchid_base::error::ReporterImpl;
use orchid_base::logging::{LogStrategy, Logger};
use orchid_base::parse::Snippet;
use orchid_base::tree::ttv_fmt;
use orchid_host::ctx::Ctx;
use orchid_host::extension::Extension;
use orchid_host::lex::lex;
use orchid_host::parse::{self, ParseCtx, ParseCtxImpl, parse_items};
use orchid_host::subprocess::ext_command;
use orchid_host::system::init_systems;
use substack::Substack;
use tokio::task::{LocalSet, spawn_local};
#[derive(Parser, Debug)]
#[command(version, about, long_about)]
pub struct Args {
#[arg(short, long)]
extension: Vec<Utf8PathBuf>,
#[arg(short, long)]
system: Vec<String>,
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand, Debug)]
pub enum Commands {
Lex {
#[arg(short, long)]
file: Utf8PathBuf,
},
Parse {
#[arg(short, long)]
file: Utf8PathBuf,
},
}
fn get_all_extensions<'a>(
args: &'a Args,
logger: &'a Logger,
ctx: &'a Ctx,
) -> impl Stream<Item = io::Result<Extension>> + 'a {
try_stream! {
for exe in args.extension.iter() {
let init = ext_command(Command::new(exe.as_os_str()), logger.clone(), ctx.clone()).await
.unwrap();
let ext = Extension::new(init, logger.clone(), ctx.clone())?;
spawn_local(clone!(ext; async move { loop { ext.recv_one().await }}));
yield ext
}
}
}
#[tokio::main(flavor = "current_thread")]
async fn main() {
LocalSet::new()
.run_until(async {
let args = Args::parse();
let ctx = &Ctx::new(Rc::new(|fut| mem::drop(spawn_local(fut))));
let logger = Logger::new(LogStrategy::Discard);
let extensions =
get_all_extensions(&args, &logger, ctx).try_collect::<Vec<Extension>>().await.unwrap();
match args.command {
Commands::Lex { file } => {
let systems = init_systems(&args.system, &extensions).await.unwrap();
let mut file = File::open(file.as_std_path()).unwrap();
let mut buf = String::new();
file.read_to_string(&mut buf).unwrap();
let lexemes = lex(ctx.i.i(&buf).await, &systems, ctx).await.unwrap();
println!("{}", ttv_fmt(&lexemes).await)
},
Commands::Parse { file } => {
let systems = init_systems(&args.system, &extensions).await.unwrap();
let mut file = File::open(file.as_std_path()).unwrap();
let mut buf = String::new();
file.read_to_string(&mut buf).unwrap();
let lexemes = lex(ctx.i.i(&buf).await, &systems, ctx).await.unwrap();
let Some(first) = lexemes.first() else {
println!("File empty!");
return;
};
let reporter = ReporterImpl::new();
let pctx = ParseCtxImpl { reporter: &reporter, systems: &systems };
let snip = Snippet::new(first, &lexemes, &ctx.i);
let ptree = parse_items(&pctx, Substack::Bottom, snip).await.unwrap();
for item in ptree {
println!("{item:?}")
}
},
}
})
.await
}