Traditional route appears to work
Beginnings of dylib extensions, entirely untestted
This commit is contained in:
@@ -7,13 +7,15 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
async-fn-stream = { version = "0.1.0", path = "../async-fn-stream" }
|
||||
camino = "1.1.9"
|
||||
clap = { version = "4.5.24", features = ["derive", "env"] }
|
||||
ctrlc = "3.4.5"
|
||||
camino = "1.2.2"
|
||||
clap = { version = "4.5.54", features = ["derive", "env"] }
|
||||
ctrlc = "3.5.1"
|
||||
futures = "0.3.31"
|
||||
itertools = "0.14.0"
|
||||
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
||||
orchid-host = { version = "0.1.0", path = "../orchid-host" }
|
||||
orchid-host = { version = "0.1.0", path = "../orchid-host", features = [
|
||||
"tokio",
|
||||
] }
|
||||
substack = "1.1.1"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
tokio = { version = "1.49.0", features = ["full"] }
|
||||
|
||||
544
orcx/src/main.rs
544
orcx/src/main.rs
@@ -1,3 +1,5 @@
|
||||
use orchid_base::logging::Logger;
|
||||
use tokio::time::Instant;
|
||||
pub mod parse_folder;
|
||||
|
||||
use std::cell::RefCell;
|
||||
@@ -17,9 +19,10 @@ use orchid_base::format::{FmtCtxImpl, Format, fmt, fmt_v, take_first};
|
||||
use orchid_base::interner::local_interner::local_interner;
|
||||
use orchid_base::interner::{is, with_interner};
|
||||
use orchid_base::location::SrcRange;
|
||||
use orchid_base::logging::{LogStrategy, Logger, with_logger};
|
||||
use orchid_base::logging::{log, with_logger};
|
||||
use orchid_base::name::{NameLike, VPath};
|
||||
use orchid_base::parse::{Import, Snippet};
|
||||
use orchid_base::stash::with_stash;
|
||||
use orchid_base::sym;
|
||||
use orchid_base::tree::{Token, ttv_fmt};
|
||||
use orchid_host::ctx::{Ctx, JoinHandle, Spawner};
|
||||
@@ -27,6 +30,7 @@ use orchid_host::execute::{ExecCtx, ExecResult};
|
||||
use orchid_host::expr::ExprKind;
|
||||
use orchid_host::extension::Extension;
|
||||
use orchid_host::lex::lex;
|
||||
use orchid_host::logger::LoggerImpl;
|
||||
use orchid_host::parse::{HostParseCtxImpl, parse_item, parse_items};
|
||||
use orchid_host::parsed::{Item, ItemKind, ParsTokTree, ParsedMember, ParsedModule};
|
||||
use orchid_host::subprocess::ext_command;
|
||||
@@ -45,12 +49,12 @@ pub struct Args {
|
||||
extension: Vec<Utf8PathBuf>,
|
||||
#[arg(short, long, env = "ORCHID_DEFAULT_SYSTEMS", value_delimiter = ';')]
|
||||
system: Vec<String>,
|
||||
#[arg(short, long)]
|
||||
logs: bool,
|
||||
#[arg(short, long)]
|
||||
msg_logs: bool,
|
||||
#[arg(short, long, default_value = "off", default_missing_value = "stderr")]
|
||||
logs: Vec<String>,
|
||||
#[command(subcommand)]
|
||||
command: Commands,
|
||||
#[arg(long, action)]
|
||||
time: bool,
|
||||
}
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
@@ -78,6 +82,20 @@ pub enum Commands {
|
||||
},
|
||||
}
|
||||
|
||||
static mut STARTUP: Option<Instant> = None;
|
||||
fn time_print(args: &Args, msg: &str) {
|
||||
if !args.time {
|
||||
return;
|
||||
}
|
||||
let ms = unsafe { STARTUP }.unwrap().elapsed().as_millis();
|
||||
let secs = ms / 1000;
|
||||
let mins = secs / 60;
|
||||
if mins == 0 {
|
||||
eprintln!("{secs}.{ms:>40} {msg}");
|
||||
}
|
||||
eprintln!("{mins}:{secs:>2}.{ms:>40} {msg}")
|
||||
}
|
||||
|
||||
fn get_all_extensions<'a>(
|
||||
args: &'a Args,
|
||||
ctx: &'a Ctx,
|
||||
@@ -92,6 +110,38 @@ fn get_all_extensions<'a>(
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_log_dest(dest: &str) -> orchid_api::LogStrategy {
|
||||
if dest == "off" {
|
||||
orchid_api::LogStrategy::Discard
|
||||
} else if dest == "stderr" {
|
||||
orchid_api::LogStrategy::Default
|
||||
} else if let Some(path) = dest.strip_prefix('>') {
|
||||
orchid_api::LogStrategy::File { path: path.to_string(), append: true }
|
||||
} else {
|
||||
orchid_api::LogStrategy::File { path: dest.to_string(), append: false }
|
||||
}
|
||||
}
|
||||
|
||||
fn get_logger(args: &Args) -> LoggerImpl {
|
||||
let mut logger = LoggerImpl::default();
|
||||
for cmd in &args.logs {
|
||||
match cmd.split_once(">") {
|
||||
None => logger.set_default(parse_log_dest(cmd)),
|
||||
Some((category, dest)) => logger.set_category(category, parse_log_dest(dest)),
|
||||
}
|
||||
}
|
||||
if !logger.has_category("warn") {
|
||||
logger.set_category("warn", logger.strat("debug"));
|
||||
}
|
||||
if !logger.has_category("error") {
|
||||
logger.set_category("error", logger.strat("warn"));
|
||||
}
|
||||
if !logger.has_category("msg") {
|
||||
logger.set_category("msg", orchid_api::LogStrategy::Discard);
|
||||
}
|
||||
logger
|
||||
}
|
||||
|
||||
struct JoinHandleImpl(tokio::task::JoinHandle<()>);
|
||||
impl JoinHandle for JoinHandleImpl {
|
||||
fn abort(&self) { self.0.abort() }
|
||||
@@ -109,258 +159,270 @@ impl Spawner for SpawnerImpl {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> io::Result<ExitCode> {
|
||||
eprintln!("orcx launched");
|
||||
eprintln!("Orcx was made by Lawrence Bethlenfalvy");
|
||||
let args = Args::parse();
|
||||
let exit_code = Rc::new(RefCell::new(ExitCode::SUCCESS));
|
||||
let local_set = LocalSet::new();
|
||||
let exit_code1 = exit_code.clone();
|
||||
let args = Args::parse();
|
||||
let logger = Logger::new(if args.logs { LogStrategy::StdErr } else { LogStrategy::Discard });
|
||||
let cx_logger = logger.clone();
|
||||
let msg_logger =
|
||||
Logger::new(if args.msg_logs { LogStrategy::StdErr } else { LogStrategy::Discard });
|
||||
let logger = get_logger(&args);
|
||||
let logger2 = logger.clone();
|
||||
unsafe { STARTUP = Some(Instant::now()) };
|
||||
local_set.spawn_local(async move {
|
||||
let ctx = &Ctx::new(msg_logger.clone(), SpawnerImpl);
|
||||
let extensions = get_all_extensions(&args, 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(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 };
|
||||
if args.logs {
|
||||
println!(
|
||||
"lexed: {}",
|
||||
take_first(&ttv_fmt(&lexemes, &FmtCtxImpl::default()).await, true)
|
||||
);
|
||||
}
|
||||
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 ctx = &Ctx::new(SpawnerImpl, logger2);
|
||||
with_stash(async {
|
||||
let extensions =
|
||||
get_all_extensions(&args, ctx).try_collect::<Vec<Extension>>().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 add_imports = |items: &mut Vec<Item>, 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,
|
||||
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 add_imports = |items: &mut Vec<Item>, 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::<ParsTokTree>(lexemes.iter()).await.join(" ")
|
||||
)
|
||||
.await;
|
||||
lexemes
|
||||
},
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
*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));
|
||||
};
|
||||
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!(
|
||||
"{const_name} = {}",
|
||||
take_first(&val.print(&FmtCtxImpl::default()).await, false)
|
||||
),
|
||||
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!"),
|
||||
}
|
||||
}
|
||||
},
|
||||
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 } => {
|
||||
eprintln!("exec branch");
|
||||
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) => {
|
||||
if args.logs {
|
||||
println!("lexed: {}", fmt_v::<ParsTokTree>(lexemes.iter()).await.join(" "));
|
||||
}
|
||||
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!"),
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
.await;
|
||||
});
|
||||
with_interner(local_interner(), with_logger(cx_logger, local_set)).await;
|
||||
with_interner(local_interner(), with_logger(logger, local_set)).await;
|
||||
let x = *exit_code.borrow();
|
||||
Ok(x)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user