diff --git a/.cargo/config.toml b/.cargo/config.toml index 5dcce32..e452f15 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -6,6 +6,7 @@ orcxdb = "xtask orcxdb" [env] CARGO_WORKSPACE_DIR = { value = "", relative = true } ORCHID_EXTENSIONS = "target/debug/orchid_std" +#ORCHID_EXTENSIONS = "target/debug/orchid-std-piped" ORCHID_DEFAULT_SYSTEMS = "orchid::std;orchid::macros" ORCHID_LOG_BUFFERS = "true" RUST_BACKTRACE = "1" diff --git a/orchid-extension/src/atom_owned.rs b/orchid-extension/src/atom_owned.rs index 6bb9fd3..8db4d1a 100644 --- a/orchid-extension/src/atom_owned.rs +++ b/orchid-extension/src/atom_owned.rs @@ -18,7 +18,7 @@ use memo_map::MemoMap; use never::Never; use orchid_api_traits::{Decode, Encode, enc_vec}; use orchid_base::error::OrcRes; -use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit, take_first}; +use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit, Format, take_first}; use orchid_base::logging::log; use orchid_base::name::Sym; use task_local::task_local; @@ -93,10 +93,28 @@ impl AtomDynfo for OwnedAtomDynfo { }) } fn call(&self, AtomCtx(_, id): AtomCtx, arg: Expr) -> LocalBoxFuture<'_, GExpr> { - Box::pin(async move { take_atom(id.unwrap()).await.dyn_call(arg).await }) + Box::pin(async move { + writeln!( + log("msg"), + "owned call {} {}", + take_first(&AtomReadGuard::new(id.unwrap()).await.dyn_print().await, false), + take_first(&arg.print(&FmtCtxImpl::default()).await, true), + ) + .await; + take_atom(id.unwrap()).await.dyn_call(arg).await + }) } fn call_ref<'a>(&'a self, AtomCtx(_, id): AtomCtx<'a>, arg: Expr) -> LocalBoxFuture<'a, GExpr> { - Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_call_ref(arg).await }) + Box::pin(async move { + writeln!( + log("msg"), + "owned call_ref {} {}", + take_first(&AtomReadGuard::new(id.unwrap()).await.dyn_print().await, false), + take_first(&arg.print(&FmtCtxImpl::default()).await, true), + ) + .await; + AtomReadGuard::new(id.unwrap()).await.dyn_call_ref(arg).await + }) } fn print(&self, AtomCtx(_, id): AtomCtx<'_>) -> LocalBoxFuture<'_, FmtUnit> { Box::pin(async move { AtomReadGuard::new(id.unwrap()).await.dyn_print().await }) diff --git a/orchid-host/src/expr.rs b/orchid-host/src/expr.rs index ce32d39..264eece 100644 --- a/orchid-host/src/expr.rs +++ b/orchid-host/src/expr.rs @@ -103,18 +103,24 @@ impl Expr { } impl Format for Expr { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { - return print_expr(self, c, Substack::Bottom).await; + return print_expr(self, c, Substack::Bottom, &[]).await; } } -async fn print_expr<'a>( +pub async fn print_expr<'a>( expr: &'a Expr, c: &'a (impl FmtCtx + ?Sized + 'a), visited: Substack<'_, api::ExprTicket>, + id_only: &[api::ExprTicket], ) -> FmtUnit { if visited.iter().any(|id| id == &expr.id()) { return "CYCLIC_EXPR".to_string().into(); } - print_exprkind(&*expr.kind().read().await, c, visited.push(expr.id())).boxed_local().await + if id_only.iter().any(|id| id == &expr.id()) { + return format!("{:?}", expr.id()).into(); + } + print_exprkind(&*expr.kind().read().await, c, visited.push(expr.id()), id_only) + .boxed_local() + .await } #[derive(Clone, Debug)] @@ -138,13 +144,14 @@ impl ExprKind { } impl Format for ExprKind { async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit { - print_exprkind(self, c, Substack::Bottom).await + print_exprkind(self, c, Substack::Bottom, &[]).await } } async fn print_exprkind<'a>( ek: &ExprKind, c: &'a (impl FmtCtx + ?Sized + 'a), visited: Substack<'_, api::ExprTicket>, + id_only: &[api::ExprTicket], ) -> FmtUnit { match &ek { ExprKind::Arg => "Arg".to_string().into(), @@ -156,10 +163,10 @@ async fn print_exprkind<'a>( ExprKind::Call(f, x) => tl_cache!(Rc: Rc::new(Variants::default() .unbounded("{0b} {1l}") .bounded("({0b} {1})"))) - .units([print_expr(f, c, visited).await, print_expr(x, c, visited).await]), + .units([print_expr(f, c, visited, id_only).await, print_expr(x, c, visited, id_only).await]), ExprKind::Identity(id) => tl_cache!(Rc: Rc::new(Variants::default().bounded("{{{0}}}"))).units([print_expr( - id, c, visited, + id, c, visited, id_only, ) .boxed_local() .await]), @@ -167,14 +174,14 @@ async fn print_exprkind<'a>( ExprKind::Lambda(None, body) => tl_cache!(Rc: Rc::new(Variants::default() // .unbounded("\\.{0l}") .bounded("(\\.{0b})"))) - .units([print_expr(body, c, visited).await]), + .units([print_expr(body, c, visited, id_only).await]), ExprKind::Lambda(Some(path), body) => tl_cache!(Rc: Rc::new(Variants::default() // .unbounded("\\{0b}. {1l}") .bounded("(\\{0b}. {1b})"))) - .units([format!("{path}").into(), print_expr(body, c, visited).await]), + .units([format!("{path}").into(), print_expr(body, c, visited, id_only).await]), ExprKind::Seq(l, r) => tl_cache!(Rc: Rc::new(Variants::default().bounded("[{0b}]{1l}"))) - .units([print_expr(l, c, visited).await, print_expr(r, c, visited).await]), + .units([print_expr(l, c, visited, id_only).await, print_expr(r, c, visited, id_only).await]), } } diff --git a/orchid-host/src/extension.rs b/orchid-host/src/extension.rs index 55ce7ce..5e30d77 100644 --- a/orchid-host/src/extension.rs +++ b/orchid-host/src/extension.rs @@ -102,11 +102,7 @@ impl Extension { this.0.ctx.exprs.give_expr(target) }, api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => { - if this.is_own_sys(rel.0).await { - this.0.ctx.exprs.take_expr(rel.1); - } else { - writeln!(log("warn"), "Not our system {:?}", rel.0).await - } + this.0.ctx.exprs.take_expr(rel.1); }, api::ExtHostNotif::Log(api::Log { category, message }) => write!(log(&es(category).await), "{message}").await, @@ -130,7 +126,7 @@ impl Extension { // Atom printing and interning is never reported because it generates too much // noise if !matches!(req, api::ExtHostReq::ExtAtomPrint(_)) - || matches!(req, api::ExtHostReq::IntReq(_)) + && !matches!(req, api::ExtHostReq::IntReq(_)) { writeln!(log("msg"), "Host received request {req:?}").await; } @@ -299,14 +295,6 @@ impl Extension { pub fn ctx(&self) -> &Ctx { &self.0.ctx } pub fn system_ctors(&self) -> impl Iterator { self.0.systems.iter() } #[must_use] - pub async fn is_own_sys(&self, id: api::SysId) -> bool { - let Some(sys) = self.ctx().system_inst(id).await else { - writeln!(log("warn"), "Invalid system ID {id:?}").await; - return false; - }; - Rc::ptr_eq(&self.0, &sys.ext().0) - } - #[must_use] pub fn next_pars(&self) -> NonZeroU64 { let mut next_pars = self.0.next_pars.borrow_mut(); *next_pars = next_pars.checked_add(1).unwrap_or(NonZeroU64::new(1).unwrap()); diff --git a/orchid-std/Cargo.toml b/orchid-std/Cargo.toml index 2491d81..fe47b1f 100644 --- a/orchid-std/Cargo.toml +++ b/orchid-std/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2024" [[bin]] -name = "orchid-std-dbg" +name = "orchid-std-piped" path = "src/main.rs" [lib] diff --git a/orcx/src/main.rs b/orcx/src/main.rs index 1ab5b39..4cbba17 100644 --- a/orcx/src/main.rs +++ b/orcx/src/main.rs @@ -187,261 +187,251 @@ async fn main() -> io::Result { let logger = get_logger(&args); let logger2 = logger.clone(); unsafe { STARTUP = Some(Instant::now()) }; - local_set.spawn_local(async move { + local_set.spawn_local(with_stash(async move { let ctx = &Ctx::new(SpawnerImpl, logger2); - with_stash(async { - let extensions = - get_all_extensions(&args, ctx).try_collect::>().await.unwrap(); - time_print(&args, "Extensions loaded"); - 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(is(&buf).await, sym!(usercode), &systems, ctx).await.unwrap(); - println!("{}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl::default()).await, true)) - }, - 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(is(&buf).await, sym!(usercode), &systems, ctx).await.unwrap(); - let Some(first) = lexemes.first() else { - println!("File empty!"); - return; + let extensions = get_all_extensions(&args, ctx).try_collect::>().await.unwrap(); + time_print(&args, "Extensions loaded"); + 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(is(&buf).await, sym!(usercode), &systems, ctx).await.unwrap(); + println!("{}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl::default()).await, true)) + }, + 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(is(&buf).await, sym!(usercode), &systems, ctx).await.unwrap(); + let Some(first) = lexemes.first() else { + println!("File empty!"); + return; + }; + let pctx = HostParseCtxImpl { systems: &systems, ctx: ctx.clone(), src: sym!(usercode) }; + let snip = Snippet::new(first, &lexemes); + match with_reporter(parse_items(&pctx, Substack::Bottom, snip)).await.unwrap() { + Err(errv) => { + eprintln!("{errv}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + }, + Ok(ptree) if ptree.is_empty() => { + eprintln!("File empty only after parsing, but no errors were reported"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + }, + Ok(ptree) => + for item in ptree { + println!("{}", take_first(&item.print(&FmtCtxImpl::default()).await, true)) + }, + }; + }, + Commands::Repl => { + let mut counter = 0; + let mut imports = Vec::new(); + let usercode_path = sym!(usercode); + let mut stdin = BufReader::new(stdin()); + loop { + counter += 1; + let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap(); + print!("\\.> "); + std::io::stdout().flush().unwrap(); + let mut prompt = String::new(); + stdin.read_line(&mut prompt).await.unwrap(); + let name = is(&format!("_{counter}")).await; + let path = usercode_path.suffix([name.clone()]).await; + let mut lexemes = + lex(is(prompt.trim()).await, path.clone(), &systems, ctx).await.unwrap(); + let Some(discr) = lexemes.first() else { continue }; + writeln!( + log("debug"), + "lexed: {}", + take_first(&ttv_fmt(&lexemes, &FmtCtxImpl::default()).await, true) + ) + .await; + let prefix_sr = SrcRange::zw(path.clone(), 0); + let process_lexemes = async |lexemes: &[ParsTokTree]| { + let snippet = Snippet::new(&lexemes[0], lexemes); + let parse_ctx = + HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] }; + match try_with_reporter(parse_item(&parse_ctx, Substack::Bottom, vec![], snippet)).await + { + Ok(items) => Some(items), + Err(e) => { + eprintln!("{e}"); + None + }, + } }; - let pctx = HostParseCtxImpl { systems: &systems, ctx: ctx.clone(), src: sym!(usercode) }; - let snip = Snippet::new(first, &lexemes); - match with_reporter(parse_items(&pctx, Substack::Bottom, snip)).await.unwrap() { + let add_imports = |items: &mut Vec, imports: &[Import]| { + items.extend(imports.iter().map(|import| Item::new(import.sr.clone(), import.clone()))); + }; + if discr.is_kw(is("import").await) { + let Some(import_lines) = process_lexemes(&lexemes).await else { continue }; + imports.extend(import_lines.into_iter().map(|it| match it.kind { + ItemKind::Import(imp) => imp, + _ => panic!("Expected imports from import line"), + })); + continue; + } + if !discr.is_kw(is("let").await) { + let prefix = [is("export").await, is("let").await, name.clone(), is("=").await]; + lexemes.splice(0..0, prefix.map(|n| Token::Name(n).at(prefix_sr.clone()))); + } + let Some(mut new_lines) = process_lexemes(&lexemes).await else { continue }; + let const_decl = new_lines.iter().exactly_one().expect("Multiple lines from let"); + let input_sr = const_decl.sr.map_range(|_| 0..0); + let const_name = match &const_decl.kind { + ItemKind::Member(ParsedMember { name: const_name, .. }) => const_name.clone(), + _ => panic!("Expected exactly one constant declaration from let"), + }; + add_imports(&mut new_lines, &imports); + imports.push(Import::new(input_sr.clone(), VPath::new(path.segs()), const_name.clone())); + let new_module = ParsedModule::new(true, new_lines); + match with_reporter(root.add_parsed(&new_module, path.clone())).await { + Ok(new) => root = new, Err(errv) => { eprintln!("{errv}"); *exit_code1.borrow_mut() = ExitCode::FAILURE; - }, - Ok(ptree) if ptree.is_empty() => { - eprintln!("File empty only after parsing, but no errors were reported"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - }, - Ok(ptree) => - for item in ptree { - println!("{}", take_first(&item.print(&FmtCtxImpl::default()).await, true)) - }, - }; - }, - Commands::Repl => { - let mut counter = 0; - let mut imports = Vec::new(); - let usercode_path = sym!(usercode); - let mut stdin = BufReader::new(stdin()); - loop { - counter += 1; - let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap(); - print!("\\.> "); - std::io::stdout().flush().unwrap(); - let mut prompt = String::new(); - stdin.read_line(&mut prompt).await.unwrap(); - let name = is(&format!("_{counter}")).await; - let path = usercode_path.suffix([name.clone()]).await; - let mut lexemes = - lex(is(prompt.trim()).await, path.clone(), &systems, ctx).await.unwrap(); - let Some(discr) = lexemes.first() else { continue }; - writeln!( - log("debug"), - "lexed: {}", - take_first(&ttv_fmt(&lexemes, &FmtCtxImpl::default()).await, true) - ) - .await; - let prefix_sr = SrcRange::zw(path.clone(), 0); - let process_lexemes = async |lexemes: &[ParsTokTree]| { - let snippet = Snippet::new(&lexemes[0], lexemes); - let parse_ctx = - HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] }; - match try_with_reporter(parse_item(&parse_ctx, Substack::Bottom, vec![], snippet)) - .await - { - Ok(items) => Some(items), - Err(e) => { - eprintln!("{e}"); - None - }, - } - }; - let add_imports = |items: &mut Vec, imports: &[Import]| { - items - .extend(imports.iter().map(|import| Item::new(import.sr.clone(), import.clone()))); - }; - if discr.is_kw(is("import").await) { - let Some(import_lines) = process_lexemes(&lexemes).await else { continue }; - imports.extend(import_lines.into_iter().map(|it| match it.kind { - ItemKind::Import(imp) => imp, - _ => panic!("Expected imports from import line"), - })); - continue; - } - if !discr.is_kw(is("let").await) { - let prefix = [is("export").await, is("let").await, name.clone(), is("=").await]; - lexemes.splice(0..0, prefix.map(|n| Token::Name(n).at(prefix_sr.clone()))); - } - let Some(mut new_lines) = process_lexemes(&lexemes).await else { continue }; - let const_decl = new_lines.iter().exactly_one().expect("Multiple lines from let"); - let input_sr = const_decl.sr.map_range(|_| 0..0); - let const_name = match &const_decl.kind { - ItemKind::Member(ParsedMember { name: const_name, .. }) => const_name.clone(), - _ => panic!("Expected exactly one constant declaration from let"), - }; - add_imports(&mut new_lines, &imports); - imports.push(Import::new( - input_sr.clone(), - VPath::new(path.segs()), - const_name.clone(), - )); - let new_module = ParsedModule::new(true, new_lines); - match with_reporter(root.add_parsed(&new_module, path.clone())).await { - Ok(new) => root = new, - Err(errv) => { - eprintln!("{errv}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - return; - }, - } - eprintln!("parsed"); - let entrypoint = - ExprKind::Const(path.suffix([const_name.clone()]).await).at(input_sr.pos()); - let mut xctx = ExecCtx::new(root.clone(), entrypoint).await; - eprintln!("executed"); - xctx.set_gas(Some(1000)); - xctx.execute().await; - match xctx.result() { - ExecResult::Value(val) => println!( - "{const_name} = {}", - take_first(&val.print(&FmtCtxImpl::default()).await, false) - ), - ExecResult::Err(e) => println!("error: {e}"), - ExecResult::Gas(_) => println!("Ran out of gas!"), - } - } - }, - Commands::ModTree { proj, prefix } => { - let (mut root, _systems) = init_systems(&args.system, &extensions).await.unwrap(); - if let Some(proj_path) = proj { - let path = proj_path.into_std_path_buf(); - match try_with_reporter(parse_folder(&root, path, sym!(src), ctx.clone())).await { - Ok(r) => root = r, - Err(e) => { - eprintln!("{e}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - return; - }, - } - } - let prefix = match prefix { - Some(pref) => VPath::parse(&pref).await, - None => VPath::new([]), - }; - let root_data = root.0.read().await; - print_mod(&root_data.root, prefix, &root_data).await; - async fn print_mod(module: &Module, path: VPath, root: &RootData) { - let indent = " ".repeat(path.len()); - for (key, tgt) in &module.imports { - match tgt { - Ok(tgt) => println!("{indent}import {key} => {}", tgt.target), - Err(opts) => println!( - "{indent}import {key} conflicts between {}", - opts.iter().map(|i| &i.target).join(" ") - ), - } - } - for (key, mem) in &module.members { - let new_path = path.clone().name_with_suffix(key.clone()).to_sym().await; - match mem.kind(root.ctx.clone(), &root.consts).await { - MemberKind::Module(module) => { - println!("{indent}module {key} {{"); - print_mod(module, VPath::new(new_path.segs()), root).boxed_local().await; - println!("{indent}}}") - }, - MemberKind::Const => { - let value = root.consts.get(&new_path).expect("Missing const!"); - println!("{indent}const {key} = {}", fmt(value).await) - }, - } - } - } - }, - Commands::Exec { proj, code } => { - let path = sym!(usercode); - let prefix_sr = SrcRange::zw(path.clone(), 0); - let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap(); - if let Some(proj_path) = proj { - let path = proj_path.into_std_path_buf(); - match try_with_reporter(parse_folder(&root, path, sym!(src), ctx.clone())).await { - Ok(r) => root = r, - Err(e) => { - eprintln!("{e}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - return; - }, - } - } - let mut lexemes = match lex(is(code.trim()).await, path.clone(), &systems, ctx).await { - Ok(lexemes) => { - writeln!( - log("debug"), - "lexed: {}", - fmt_v::(lexemes.iter()).await.join(" ") - ) - .await; - lexemes - }, - Err(e) => { - eprintln!("{e}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; return; }, - }; - let parse_ctx = - HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] }; - let prefix = [is("export").await, is("let").await, is("entrypoint").await, is("=").await]; - lexemes.splice(0..0, prefix.map(|n| Token::Name(n).at(prefix_sr.clone()))); - let snippet = Snippet::new(&lexemes[0], &lexemes); - let entrypoint = match try_with_reporter(parse_item( - &parse_ctx, - Substack::Bottom, - vec![], - snippet, - )) - .await - { - Ok(items) => ParsedModule::new(true, items), - Err(e) => { - eprintln!("{e}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - return; - }, - }; - let root = match with_reporter(root.add_parsed(&entrypoint, path.clone())).await { - Err(e) => { - eprintln!("{e}"); - *exit_code1.borrow_mut() = ExitCode::FAILURE; - return; - }, - Ok(new_root) => new_root, - }; - let expr = ExprKind::Const(sym!(usercode::entrypoint)).at(prefix_sr.pos()); - let mut xctx = ExecCtx::new(root, expr).await; - xctx.set_gas(Some(10_000)); + } + eprintln!("parsed"); + let entrypoint = + ExprKind::Const(path.suffix([const_name.clone()]).await).at(input_sr.pos()); + let mut xctx = ExecCtx::new(root.clone(), entrypoint).await; + eprintln!("executed"); + xctx.set_gas(Some(1000)); xctx.execute().await; match xctx.result() { - ExecResult::Value(val) => - println!("{}", take_first(&val.print(&FmtCtxImpl::default()).await, false)), + ExecResult::Value(val) => println!( + "{const_name} = {}", + take_first(&val.print(&FmtCtxImpl::default()).await, false) + ), ExecResult::Err(e) => println!("error: {e}"), ExecResult::Gas(_) => println!("Ran out of gas!"), } - }, - } - }) - .await; - }); + } + }, + Commands::ModTree { proj, prefix } => { + let (mut root, _systems) = init_systems(&args.system, &extensions).await.unwrap(); + if let Some(proj_path) = proj { + let path = proj_path.into_std_path_buf(); + match try_with_reporter(parse_folder(&root, path, sym!(src), ctx.clone())).await { + Ok(r) => root = r, + Err(e) => { + eprintln!("{e}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + return; + }, + } + } + let prefix = match prefix { + Some(pref) => VPath::parse(&pref).await, + None => VPath::new([]), + }; + let root_data = root.0.read().await; + print_mod(&root_data.root, prefix, &root_data).await; + async fn print_mod(module: &Module, path: VPath, root: &RootData) { + let indent = " ".repeat(path.len()); + for (key, tgt) in &module.imports { + match tgt { + Ok(tgt) => println!("{indent}import {key} => {}", tgt.target), + Err(opts) => println!( + "{indent}import {key} conflicts between {}", + opts.iter().map(|i| &i.target).join(" ") + ), + } + } + for (key, mem) in &module.members { + let new_path = path.clone().name_with_suffix(key.clone()).to_sym().await; + match mem.kind(root.ctx.clone(), &root.consts).await { + MemberKind::Module(module) => { + println!("{indent}module {key} {{"); + print_mod(module, VPath::new(new_path.segs()), root).boxed_local().await; + println!("{indent}}}") + }, + MemberKind::Const => { + let value = root.consts.get(&new_path).expect("Missing const!"); + println!("{indent}const {key} = {}", fmt(value).await) + }, + } + } + } + }, + Commands::Exec { proj, code } => { + let path = sym!(usercode); + let prefix_sr = SrcRange::zw(path.clone(), 0); + let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap(); + if let Some(proj_path) = proj { + let path = proj_path.into_std_path_buf(); + match try_with_reporter(parse_folder(&root, path, sym!(src), ctx.clone())).await { + Ok(r) => root = r, + Err(e) => { + eprintln!("{e}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + return; + }, + } + } + let mut lexemes = match lex(is(code.trim()).await, path.clone(), &systems, ctx).await { + Ok(lexemes) => { + writeln!( + log("debug"), + "lexed: {}", + fmt_v::(lexemes.iter()).await.join(" ") + ) + .await; + lexemes + }, + Err(e) => { + eprintln!("{e}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + return; + }, + }; + let parse_ctx = + HostParseCtxImpl { ctx: ctx.clone(), src: path.clone(), systems: &systems[..] }; + let prefix = [is("export").await, is("let").await, is("entrypoint").await, is("=").await]; + lexemes.splice(0..0, prefix.map(|n| Token::Name(n).at(prefix_sr.clone()))); + let snippet = Snippet::new(&lexemes[0], &lexemes); + let entrypoint = match try_with_reporter(parse_item( + &parse_ctx, + Substack::Bottom, + vec![], + snippet, + )) + .await + { + Ok(items) => ParsedModule::new(true, items), + Err(e) => { + eprintln!("{e}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + return; + }, + }; + let root = match with_reporter(root.add_parsed(&entrypoint, path.clone())).await { + Err(e) => { + eprintln!("{e}"); + *exit_code1.borrow_mut() = ExitCode::FAILURE; + return; + }, + Ok(new_root) => new_root, + }; + let expr = ExprKind::Const(sym!(usercode::entrypoint)).at(prefix_sr.pos()); + let mut xctx = ExecCtx::new(root, expr).await; + xctx.set_gas(Some(10_000)); + xctx.execute().await; + match xctx.result() { + ExecResult::Value(val) => + println!("{}", take_first(&val.print(&FmtCtxImpl::default()).await, false)), + ExecResult::Err(e) => println!("error: {e}"), + ExecResult::Gas(_) => println!("Ran out of gas!"), + } + }, + } + })); with_interner(local_interner(), with_logger(logger, local_set)).await; let x = *exit_code.borrow(); Ok(x)