forked from Orchid/orchid
Returned from Italy
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
pub mod parse_folder;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
@@ -6,6 +8,7 @@ use std::process::{Command, ExitCode};
|
||||
use std::rc::Rc;
|
||||
|
||||
use async_std::io::stdin;
|
||||
use async_std::path::PathBuf;
|
||||
use async_stream::try_stream;
|
||||
use camino::Utf8PathBuf;
|
||||
use clap::{Parser, Subcommand};
|
||||
@@ -27,6 +30,8 @@ use orchid_host::system::init_systems;
|
||||
use substack::Substack;
|
||||
use tokio::task::{LocalSet, spawn_local};
|
||||
|
||||
use crate::parse_folder::parse_folder;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about)]
|
||||
pub struct Args {
|
||||
@@ -54,6 +59,8 @@ pub enum Commands {
|
||||
},
|
||||
Repl,
|
||||
Execute {
|
||||
#[arg(long)]
|
||||
proj: Option<Utf8PathBuf>,
|
||||
#[arg()]
|
||||
code: String,
|
||||
},
|
||||
@@ -117,7 +124,7 @@ async fn main() -> io::Result<ExitCode> {
|
||||
};
|
||||
let reporter = Reporter::new();
|
||||
let pctx = HostParseCtxImpl {
|
||||
reporter: &reporter,
|
||||
rep: &reporter,
|
||||
systems: &systems,
|
||||
ctx: ctx.clone(),
|
||||
src: sym!(usercode; i).await,
|
||||
@@ -155,7 +162,7 @@ async fn main() -> io::Result<ExitCode> {
|
||||
let reporter = Reporter::new();
|
||||
let parse_ctx = HostParseCtxImpl {
|
||||
ctx: ctx.clone(),
|
||||
reporter: &reporter,
|
||||
rep: &reporter,
|
||||
src: path.clone(),
|
||||
systems: &systems[..],
|
||||
};
|
||||
@@ -185,18 +192,29 @@ async fn main() -> io::Result<ExitCode> {
|
||||
ExecResult::Gas(_) => println!("Ran out of gas!"),
|
||||
}
|
||||
},
|
||||
Commands::Execute { code } => {
|
||||
let (root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
||||
Commands::Execute { proj, code } => {
|
||||
let reporter = Reporter::new();
|
||||
let (mut root, systems) = init_systems(&args.system, &extensions).await.unwrap();
|
||||
if let Some(proj_path) = proj {
|
||||
let path = PathBuf::from(proj_path.into_std_path_buf());
|
||||
match parse_folder(&root, path, sym!(src; i).await, &reporter, ctx.clone()).await {
|
||||
Ok(r) => root = r,
|
||||
Err(e) => {
|
||||
eprintln!("{e}");
|
||||
*exit_code1.borrow_mut() = ExitCode::FAILURE;
|
||||
return;
|
||||
},
|
||||
}
|
||||
}
|
||||
let lexemes =
|
||||
lex(i.i(code.trim()).await, sym!(usercode; i).await, &systems, ctx).await.unwrap();
|
||||
if args.logs {
|
||||
println!("lexed: {}", take_first(&ttv_fmt(&lexemes, &FmtCtxImpl { i }).await, true));
|
||||
}
|
||||
let path = sym!(usercode; i).await;
|
||||
let reporter = Reporter::new();
|
||||
let parse_ctx = HostParseCtxImpl {
|
||||
ctx: ctx.clone(),
|
||||
reporter: &reporter,
|
||||
rep: &reporter,
|
||||
src: path.clone(),
|
||||
systems: &systems[..],
|
||||
};
|
||||
|
||||
91
orcx/src/parse_folder.rs
Normal file
91
orcx/src/parse_folder.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use async_std::fs;
|
||||
use async_std::fs::File;
|
||||
use async_std::io::ReadExt;
|
||||
use async_std::path::{Path, PathBuf};
|
||||
use async_std::stream::StreamExt;
|
||||
use futures::FutureExt;
|
||||
use itertools::Itertools;
|
||||
use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_errv, os_str_to_string};
|
||||
use orchid_base::location::SrcRange;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::parse::Snippet;
|
||||
use orchid_host::ctx::Ctx;
|
||||
use orchid_host::lex::lex;
|
||||
use orchid_host::parse::{HostParseCtxImpl, parse_items};
|
||||
use orchid_host::parsed::ParsedModule;
|
||||
use orchid_host::tree::Root;
|
||||
use substack::Substack;
|
||||
|
||||
pub async fn parse_folder(
|
||||
root: &Root,
|
||||
path: PathBuf,
|
||||
ns: Sym,
|
||||
rep: &Reporter,
|
||||
ctx: Ctx,
|
||||
) -> OrcRes<Root> {
|
||||
let parsed_module = (recur(&path, ns.clone(), rep, ctx).await?)
|
||||
.expect("Project folder is a single non-orchid file");
|
||||
return Ok(root.add_parsed(&parsed_module, ns, rep).await);
|
||||
async fn recur(path: &Path, ns: Sym, rep: &Reporter, ctx: Ctx) -> OrcRes<Option<ParsedModule>> {
|
||||
let sr = SrcRange::new(0..0, &ns);
|
||||
if path.is_dir().await {
|
||||
let Some(name_os) = path.file_name() else {
|
||||
return Err(mk_errv(
|
||||
ctx.i.i("Could not read directory name").await,
|
||||
format!("Path {} ends in ..", path.to_string_lossy()),
|
||||
[sr],
|
||||
));
|
||||
};
|
||||
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
||||
let ns = ns.push(name.clone(), &ctx.i).await;
|
||||
let sr = SrcRange::new(0..0, &ns);
|
||||
let mut items = Vec::new();
|
||||
let mut stream = match fs::read_dir(path).await {
|
||||
Err(err) => return Err(async_io_err(err, &ctx.i, [sr]).await),
|
||||
Ok(s) => s,
|
||||
};
|
||||
while let Some(entry_res) = stream.next().await {
|
||||
let entry = match entry_res {
|
||||
Ok(ent) => ent,
|
||||
Err(err) => {
|
||||
rep.report(async_io_err(err, &ctx.i, [sr.clone()]).await);
|
||||
continue;
|
||||
},
|
||||
};
|
||||
match recur(&entry.path(), ns.clone(), rep, ctx.clone()).boxed_local().await {
|
||||
Err(e) => {
|
||||
rep.report(e);
|
||||
continue;
|
||||
},
|
||||
Ok(None) => continue,
|
||||
Ok(Some(module)) => items.push(module.default_item(name.clone(), sr.clone())),
|
||||
}
|
||||
}
|
||||
Ok(Some(ParsedModule::new(items)))
|
||||
} else if path.extension() == Some(OsStr::new("orc")) {
|
||||
let name_os = path.file_stem().expect("If there is an extension, there must be a stem");
|
||||
let name = ctx.i.i(os_str_to_string(name_os, &ctx.i, [sr]).await?).await;
|
||||
let ns = ns.push(name, &ctx.i).await;
|
||||
let sr = SrcRange::new(0..0, &ns);
|
||||
let mut file = match File::open(path).await {
|
||||
Err(e) => return Err(async_io_err(e, &ctx.i, [sr]).await),
|
||||
Ok(file) => file,
|
||||
};
|
||||
let mut text = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut text).await {
|
||||
return Err(async_io_err(e, &ctx.i, [sr]).await);
|
||||
}
|
||||
let systems =
|
||||
ctx.systems.read().await.iter().filter_map(|(_, sys)| sys.upgrade()).collect_vec();
|
||||
let lexemes = lex(ctx.i.i(&text).await, ns.clone(), &systems, &ctx).await?;
|
||||
let hpctx = HostParseCtxImpl { ctx: ctx.clone(), rep, src: ns.clone(), systems: &systems };
|
||||
let Some(fst) = lexemes.first() else { return Ok(Some(ParsedModule::new([]))) };
|
||||
let items = parse_items(&hpctx, Substack::Bottom, Snippet::new(fst, &lexemes)).await?;
|
||||
Ok(Some(ParsedModule::new(items)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user