New plans for macros
About to move them completely to stdlib
This commit is contained in:
@@ -10,8 +10,12 @@ pub struct SharedChild {
|
||||
debug: Option<(String, Mutex<Box<dyn fmt::Write>>)>,
|
||||
}
|
||||
impl SharedChild {
|
||||
pub fn new(command: &mut process::Command, debug: Option<(&str, impl fmt::Write + 'static)>) -> io::Result<Self> {
|
||||
let mut child = command.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()).spawn()?;
|
||||
pub fn new(
|
||||
command: &mut process::Command,
|
||||
debug: Option<(&str, impl fmt::Write + 'static)>,
|
||||
) -> io::Result<Self> {
|
||||
let mut child =
|
||||
command.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()).spawn()?;
|
||||
let stdin = Mutex::new(child.stdin.take().expect("Piped stdin above"));
|
||||
let stdout = Mutex::new(child.stdout.take().expect("Piped stdout above"));
|
||||
let debug = debug.map(|(n, w)| (n.to_string(), Mutex::new(Box::new(w) as Box<dyn fmt::Write>)));
|
||||
|
||||
@@ -4,8 +4,8 @@ use std::sync::{Arc, RwLock};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
use orchid_api::expr::{Expr, ExprTicket};
|
||||
|
||||
use crate::api;
|
||||
use crate::extension::{AtomHand, System};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -16,20 +16,22 @@ pub struct RtExpr {
|
||||
impl RtExpr {
|
||||
pub fn as_atom(&self) -> Option<AtomHand> { todo!() }
|
||||
pub fn strong_count(&self) -> usize { todo!() }
|
||||
pub fn id(&self) -> ExprTicket {
|
||||
ExprTicket(
|
||||
pub fn id(&self) -> api::ExprTicket {
|
||||
api::ExprTicket(
|
||||
NonZeroU64::new(self.data.as_ref() as *const () as usize as u64)
|
||||
.expect("this is a ref, it cannot be null")
|
||||
.expect("this is a ref, it cannot be null"),
|
||||
)
|
||||
}
|
||||
pub fn canonicalize(&self) -> ExprTicket {
|
||||
pub fn canonicalize(&self) -> api::ExprTicket {
|
||||
if !self.is_canonical.swap(true, Ordering::Relaxed) {
|
||||
KNOWN_EXPRS.write().unwrap().entry(self.id()).or_insert_with(|| self.clone());
|
||||
}
|
||||
self.id()
|
||||
}
|
||||
pub fn resolve(tk: ExprTicket) -> Option<Self> { KNOWN_EXPRS.read().unwrap().get(&tk).cloned() }
|
||||
pub fn from_api(api: Expr, sys: &System) -> Self {
|
||||
pub fn resolve(tk: api::ExprTicket) -> Option<Self> {
|
||||
KNOWN_EXPRS.read().unwrap().get(&tk).cloned()
|
||||
}
|
||||
pub fn from_api(api: api::Expr, sys: &System) -> Self {
|
||||
Self { data: Arc::default(), is_canonical: Arc::default() }
|
||||
}
|
||||
}
|
||||
@@ -46,5 +48,5 @@ impl Drop for RtExpr {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref KNOWN_EXPRS: RwLock<HashMap<ExprTicket, RtExpr>> = RwLock::default();
|
||||
static ref KNOWN_EXPRS: RwLock<HashMap<api::ExprTicket, RtExpr>> = RwLock::default();
|
||||
}
|
||||
|
||||
@@ -1,82 +1,89 @@
|
||||
use orchid_api::logging::Log;
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::msg::{recv_msg, send_msg};
|
||||
use substack::{Stackframe, Substack};
|
||||
use orchid_base::intern;
|
||||
use std::collections::VecDeque;
|
||||
use std::io::{stderr, BufRead, BufReader, Write as _};
|
||||
use std::num::NonZero;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::process::ChildStdin;
|
||||
use std::ops::{Deref, Range};
|
||||
use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, Ordering};
|
||||
use std::sync::mpsc::{sync_channel, SyncSender};
|
||||
use std::sync::{Arc, Mutex, OnceLock, RwLock, Weak};
|
||||
use std::{fmt, io, process, thread};
|
||||
use std::{fmt, io, thread};
|
||||
|
||||
use derive_destructure::destructure;
|
||||
use hashbrown::hash_map::Entry;
|
||||
use hashbrown::HashMap;
|
||||
use itertools::Itertools;
|
||||
use lazy_static::lazy_static;
|
||||
use orchid_api::atom::{Atom, AtomDrop, AtomPrint, AtomSame, CallRef, FinalCall, Fwd, Fwded};
|
||||
use orchid_api::error::ProjResult;
|
||||
use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate};
|
||||
use orchid_api::interner::IntReq;
|
||||
use orchid_api::parser::{CharFilter, LexExpr, LexedExpr, ParsId, SubLex, SubLexed};
|
||||
use orchid_api::proto::{
|
||||
ExtHostNotif, ExtHostReq, ExtensionHeader, HostExtNotif, HostHeader, HostMsgSet,
|
||||
};
|
||||
use orchid_api::system::{NewSystem, SysDeclId, SysId, SystemDecl, SystemDrop};
|
||||
use orchid_api::tree::{GetMember, Member, MemberKind, TreeId};
|
||||
use orchid_api_traits::{Decode, Encode, Request};
|
||||
use orchid_api_traits::{enc_vec, Decode, Request};
|
||||
use orchid_base::char_filter::char_filter_match;
|
||||
use orchid_base::clone;
|
||||
use orchid_base::error::{errv_from_apiv, mk_err, OrcRes};
|
||||
use orchid_base::interner::{deintern, intern, Tok};
|
||||
use orchid_base::logging::Logger;
|
||||
use orchid_base::reqnot::{ReqNot, Requester as _};
|
||||
use orchid_base::tree::{ttv_from_api, AtomInTok};
|
||||
use ordered_float::NotNan;
|
||||
use substack::{Stackframe, Substack};
|
||||
|
||||
use crate::api;
|
||||
use crate::expr::RtExpr;
|
||||
use crate::tree::OwnedMember;
|
||||
use crate::tree::{Member, ParsTokTree};
|
||||
|
||||
#[derive(Debug, destructure)]
|
||||
pub struct AtomData {
|
||||
owner: System,
|
||||
drop: bool,
|
||||
drop: Option<api::AtomId>,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
impl AtomData {
|
||||
fn api(self) -> Atom {
|
||||
fn api(self) -> api::Atom {
|
||||
let (owner, drop, data) = self.destructure();
|
||||
Atom { data, drop, owner: owner.id() }
|
||||
api::Atom { data, drop, owner: owner.id() }
|
||||
}
|
||||
fn api_ref(&self) -> Atom {
|
||||
Atom { data: self.data.clone(), drop: self.drop, owner: self.owner.id() }
|
||||
fn api_ref(&self) -> api::Atom {
|
||||
api::Atom { data: self.data.clone(), drop: self.drop, owner: self.owner.id() }
|
||||
}
|
||||
}
|
||||
impl Drop for AtomData {
|
||||
fn drop(&mut self) {
|
||||
self.owner.reqnot().notify(AtomDrop(Atom {
|
||||
owner: self.owner.id(),
|
||||
data: self.data.clone(),
|
||||
drop: true,
|
||||
}))
|
||||
if let Some(id) = self.drop {
|
||||
self.owner.reqnot().notify(api::AtomDrop(self.owner.id(), id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AtomHand(Arc<AtomData>);
|
||||
impl AtomHand {
|
||||
pub fn from_api(Atom { data, drop, owner }: Atom) -> Self {
|
||||
fn create_new(api::Atom { data, drop, owner }: api::Atom) -> Self {
|
||||
let owner = System::resolve(owner).expect("Atom owned by non-existing system");
|
||||
Self(Arc::new(AtomData { data, drop, owner }))
|
||||
}
|
||||
pub fn call(self, arg: RtExpr) -> Expr {
|
||||
pub fn from_api(atom: api::Atom) -> Self {
|
||||
if let Some(id) = atom.drop {
|
||||
lazy_static! {
|
||||
static ref OWNED_ATOMS: Mutex<HashMap<(api::SysId, api::AtomId), Weak<AtomData>>> =
|
||||
Mutex::default();
|
||||
}
|
||||
let owner = atom.owner;
|
||||
let mut owned_g = OWNED_ATOMS.lock().unwrap();
|
||||
if let Some(data) = owned_g.get(&(owner, id)) {
|
||||
if let Some(atom) = data.upgrade() {
|
||||
return Self(atom);
|
||||
}
|
||||
}
|
||||
let new = Self::create_new(atom);
|
||||
owned_g.insert((owner, id), Arc::downgrade(&new.0));
|
||||
new
|
||||
} else {
|
||||
Self::create_new(atom)
|
||||
}
|
||||
}
|
||||
pub fn call(self, arg: RtExpr) -> api::Expr {
|
||||
let owner_sys = self.0.owner.clone();
|
||||
let reqnot = owner_sys.reqnot();
|
||||
let ticket = owner_sys.give_expr(arg.canonicalize(), || arg);
|
||||
match Arc::try_unwrap(self.0) {
|
||||
Ok(data) => reqnot.request(FinalCall(data.api(), ticket)),
|
||||
Err(hand) => reqnot.request(CallRef(hand.api_ref(), ticket)),
|
||||
Ok(data) => reqnot.request(api::FinalCall(data.api(), ticket)),
|
||||
Err(hand) => reqnot.request(api::CallRef(hand.api_ref(), ticket)),
|
||||
}
|
||||
}
|
||||
pub fn same(&self, other: &AtomHand) -> bool {
|
||||
@@ -84,13 +91,34 @@ impl AtomHand {
|
||||
if other.0.owner.id() != owner {
|
||||
return false;
|
||||
}
|
||||
self.0.owner.reqnot().request(AtomSame(self.0.api_ref(), other.0.api_ref()))
|
||||
self.0.owner.reqnot().request(api::AtomSame(self.0.api_ref(), other.0.api_ref()))
|
||||
}
|
||||
pub fn req(&self, req: Vec<u8>) -> Vec<u8> {
|
||||
self.0.owner.reqnot().request(Fwded(self.0.api_ref(), req))
|
||||
self.0.owner.reqnot().request(api::Fwded(self.0.api_ref(), req))
|
||||
}
|
||||
pub fn api_ref(&self) -> Atom { self.0.api_ref() }
|
||||
pub fn print(&self) -> String { self.0.owner.reqnot().request(AtomPrint(self.0.api_ref())) }
|
||||
pub fn api_ref(&self) -> api::Atom { self.0.api_ref() }
|
||||
pub fn print(&self) -> String { self.0.owner.reqnot().request(api::AtomPrint(self.0.api_ref())) }
|
||||
}
|
||||
impl AtomInTok for AtomHand {
|
||||
type Context = ();
|
||||
fn from_api(atom: &orchid_api::Atom, _: Range<u32>, (): &mut Self::Context) -> Self {
|
||||
Self::from_api(atom.clone())
|
||||
}
|
||||
fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
||||
}
|
||||
impl fmt::Display for AtomHand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.print()) }
|
||||
}
|
||||
|
||||
/// The 3 primary contact points with an extension are
|
||||
/// - send a message
|
||||
/// - wait for a message to arrive
|
||||
/// - wait for the extension to stop after exit (this is the implicit Drop)
|
||||
///
|
||||
/// There are no ordering guarantees about these
|
||||
pub trait ExtensionPort: Send + Sync {
|
||||
fn send(&self, msg: &[u8]);
|
||||
fn receive(&self) -> Option<Vec<u8>>;
|
||||
}
|
||||
|
||||
/// Data held about an Extension. This is refcounted within [Extension]. It's
|
||||
@@ -99,25 +127,25 @@ impl AtomHand {
|
||||
/// upgrading fails.
|
||||
#[derive(destructure)]
|
||||
pub struct ExtensionData {
|
||||
child: Mutex<process::Child>,
|
||||
child_stdin: Mutex<ChildStdin>,
|
||||
reqnot: ReqNot<HostMsgSet>,
|
||||
port: Arc<dyn ExtensionPort>,
|
||||
// child: Mutex<process::Child>,
|
||||
// child_stdin: Mutex<ChildStdin>,
|
||||
reqnot: ReqNot<api::HostMsgSet>,
|
||||
systems: Vec<SystemCtor>,
|
||||
logger: Logger,
|
||||
}
|
||||
impl Drop for ExtensionData {
|
||||
fn drop(&mut self) {
|
||||
self.reqnot.notify(HostExtNotif::Exit);
|
||||
self.child.lock().unwrap().wait().expect("Extension exited with error");
|
||||
self.reqnot.notify(api::HostExtNotif::Exit);
|
||||
}
|
||||
}
|
||||
|
||||
fn acq_expr(sys: SysId, extk: ExprTicket) {
|
||||
fn acq_expr(sys: api::SysId, extk: api::ExprTicket) {
|
||||
(System::resolve(sys).expect("Expr acq'd by invalid system"))
|
||||
.give_expr(extk, || RtExpr::resolve(extk).expect("Invalid expr acq'd"));
|
||||
}
|
||||
|
||||
fn rel_expr(sys: SysId, extk: ExprTicket) {
|
||||
fn rel_expr(sys: api::SysId, extk: api::ExprTicket) {
|
||||
let sys = System::resolve(sys).unwrap();
|
||||
let mut exprs = sys.0.exprs.write().unwrap();
|
||||
exprs.entry(extk).and_replace_entry_with(|_, (rc, rt)| {
|
||||
@@ -128,89 +156,88 @@ fn rel_expr(sys: SysId, extk: ExprTicket) {
|
||||
#[derive(Clone)]
|
||||
pub struct Extension(Arc<ExtensionData>);
|
||||
impl Extension {
|
||||
pub fn new(mut cmd: process::Command, logger: Logger) -> io::Result<Self> {
|
||||
let mut child = cmd
|
||||
.stdin(process::Stdio::piped())
|
||||
.stdout(process::Stdio::piped())
|
||||
.stderr(process::Stdio::piped())
|
||||
.spawn()?;
|
||||
let mut child_stdin = child.stdin.take().unwrap();
|
||||
let mut child_stdout = child.stdout.take().unwrap();
|
||||
let child_stderr = child.stderr.take().unwrap();
|
||||
thread::Builder::new().name("stderr forwarder".to_string()).spawn(|| {
|
||||
let mut reader = BufReader::new(child_stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
if 0 == reader.read_line(&mut buf).unwrap() {
|
||||
break;
|
||||
}
|
||||
stderr().write_all(buf.as_bytes()).unwrap();
|
||||
}
|
||||
}).unwrap();
|
||||
HostHeader{ log_strategy: logger.strat() }.encode(&mut child_stdin);
|
||||
let eh = ExtensionHeader::decode(&mut child_stdout);
|
||||
|
||||
pub fn new_process(port: Arc<dyn ExtensionPort>, logger: Logger) -> io::Result<Self> {
|
||||
port.send(&enc_vec(&api::HostHeader { log_strategy: logger.strat() }));
|
||||
let header_reply = port.receive().expect("Extension exited immediately");
|
||||
let eh = api::ExtensionHeader::decode(&mut &header_reply[..]);
|
||||
let ret = Arc::new_cyclic(|weak: &Weak<ExtensionData>| ExtensionData {
|
||||
logger,
|
||||
child: Mutex::new(child),
|
||||
child_stdin: Mutex::new(child_stdin),
|
||||
port: port.clone(),
|
||||
reqnot: ReqNot::new(
|
||||
clone!(weak; move |sfn, _| {
|
||||
eprintln!("Downsending {:?}", sfn);
|
||||
send_msg(&mut *weak.upgrade().unwrap().child_stdin.lock().unwrap(), sfn).unwrap();
|
||||
let data = weak.upgrade().unwrap();
|
||||
data.logger.log_buf("Downsending", sfn);
|
||||
data.port.send(sfn);
|
||||
}),
|
||||
clone!(weak; move |notif, _| match notif {
|
||||
ExtHostNotif::ExprNotif(ExprNotif::Acquire(Acquire(sys, extk))) => acq_expr(sys, extk),
|
||||
ExtHostNotif::ExprNotif(ExprNotif::Release(Release(sys, extk))) => rel_expr(sys, extk),
|
||||
ExtHostNotif::ExprNotif(ExprNotif::Relocate(Relocate { dec, inc, expr })) => {
|
||||
acq_expr(inc, expr);
|
||||
rel_expr(dec, expr);
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => acq_expr(acq.0, acq.1),
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => rel_expr(rel.0, rel.1),
|
||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||
acq_expr(mov.inc, mov.expr);
|
||||
rel_expr(mov.dec, mov.expr);
|
||||
},
|
||||
ExtHostNotif::AdviseSweep(_advice) => eprintln!("Sweep advice is unsupported"),
|
||||
ExtHostNotif::Log(Log(str)) => weak.upgrade().unwrap().logger.log(str),
|
||||
api::ExtHostNotif::Log(api::Log(str)) => weak.upgrade().unwrap().logger.log(str),
|
||||
}),
|
||||
|req| match req.req() {
|
||||
ExtHostReq::Ping(ping) => req.handle(ping, &()),
|
||||
ExtHostReq::IntReq(IntReq::InternStr(s)) => req.handle(s, &intern(&**s.0).marker()),
|
||||
ExtHostReq::IntReq(IntReq::InternStrv(v)) => req.handle(v, &intern(&*v.0).marker()),
|
||||
ExtHostReq::IntReq(IntReq::ExternStr(si)) => req.handle(si, &deintern(si.0).arc()),
|
||||
ExtHostReq::IntReq(IntReq::ExternStrv(vi)) =>
|
||||
req.handle(vi, &Arc::new(deintern(vi.0).iter().map(|t| t.marker()).collect_vec())),
|
||||
ExtHostReq::Fwd(fw @ Fwd(atom, _body)) => {
|
||||
api::ExtHostReq::Ping(ping) => req.handle(ping, &()),
|
||||
api::ExtHostReq::IntReq(intreq) => match intreq {
|
||||
api::IntReq::InternStr(s) => req.handle(s, &intern(&**s.0).marker()),
|
||||
api::IntReq::InternStrv(v) => req.handle(v, &intern(&*v.0).marker()),
|
||||
api::IntReq::ExternStr(si) => req.handle(si, &deintern(si.0).arc()),
|
||||
api::IntReq::ExternStrv(vi) =>
|
||||
req.handle(vi, &Arc::new(deintern(vi.0).iter().map(|t| t.marker()).collect_vec())),
|
||||
}
|
||||
api::ExtHostReq::Fwd(fw @ api::Fwd(atom, _body)) => {
|
||||
let sys = System::resolve(atom.owner).unwrap();
|
||||
thread::spawn(clone!(fw; move || {
|
||||
req.handle(&fw, &sys.reqnot().request(Fwded(fw.0.clone(), fw.1.clone())))
|
||||
}));
|
||||
req.handle(fw, &sys.reqnot().request(api::Fwded(fw.0.clone(), fw.1.clone())))
|
||||
},
|
||||
ExtHostReq::SubLex(sl) => {
|
||||
let lex_g = LEX_RECUR.lock().unwrap();
|
||||
api::ExtHostReq::SubLex(sl) => {
|
||||
let (rep_in, rep_out) = sync_channel(0);
|
||||
let lex_g = LEX_RECUR.lock().unwrap();
|
||||
let req_in = lex_g.get(&sl.id).expect("Sublex for nonexistent lexid");
|
||||
req_in.send(ReqPair(sl.clone(), rep_in)).unwrap();
|
||||
req.handle(sl, &rep_out.recv().unwrap())
|
||||
},
|
||||
_ => todo!(),
|
||||
api::ExtHostReq::ExprReq(api::ExprReq::Inspect(ins@api::Inspect(tk))) => {
|
||||
let expr = RtExpr::resolve(*tk);
|
||||
req.handle(ins, &api::Details{
|
||||
refcount: 1,
|
||||
expr: api::Expr{
|
||||
location: api::Location::None,
|
||||
clause: api::Clause::Bottom(vec![
|
||||
mk_err(
|
||||
intern!(str: "Unsupported"),
|
||||
"Inspecting clauses is unsupported at the moment",
|
||||
[]
|
||||
)
|
||||
.to_api()
|
||||
])
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
),
|
||||
systems: eh.systems.into_iter().map(|decl| SystemCtor { decl, ext: weak.clone() }).collect(),
|
||||
});
|
||||
let weak = Arc::downgrade(&ret);
|
||||
let prog_pbuf = PathBuf::from(cmd.get_program());
|
||||
let prog = prog_pbuf.file_stem().unwrap_or(cmd.get_program()).to_string_lossy();
|
||||
thread::Builder::new().name(format!("host-end:{}", prog)).spawn(move || {
|
||||
loop {
|
||||
let ingress = recv_msg(&mut child_stdout).expect("could not receive");
|
||||
if let Some(sys) = weak.upgrade() {
|
||||
sys.reqnot.receive(ingress);
|
||||
}
|
||||
}
|
||||
}).unwrap();
|
||||
thread::Builder::new()
|
||||
.name(format!("host-end:{}", eh.name))
|
||||
.spawn::<_, Option<()>>(move || loop {
|
||||
// thread will exit if either the peer exits or the extension object is dropped.
|
||||
// It holds a strong reference to the port so the port's destructor will not be called
|
||||
// until the
|
||||
let msg = port.receive()?;
|
||||
weak.upgrade()?.reqnot.receive(msg);
|
||||
})
|
||||
.unwrap();
|
||||
Ok(Self(ret))
|
||||
}
|
||||
pub fn systems(&self) -> impl Iterator<Item = &SystemCtor> { self.0.systems.iter() }
|
||||
}
|
||||
|
||||
pub struct SystemCtor {
|
||||
decl: SystemDecl,
|
||||
decl: api::SystemDecl,
|
||||
ext: Weak<ExtensionData>,
|
||||
}
|
||||
impl SystemCtor {
|
||||
@@ -225,44 +252,48 @@ impl SystemCtor {
|
||||
debug_assert_eq!(depends.len(), self.decl.depends.len(), "Wrong number of deps provided");
|
||||
let ext = self.ext.upgrade().expect("SystemCtor should be freed before Extension");
|
||||
static NEXT_ID: AtomicU16 = AtomicU16::new(1);
|
||||
let id = SysId(NonZero::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).expect("next_id wrapped"));
|
||||
let sys_inst = ext.reqnot.request(NewSystem { depends, id, system: self.decl.id });
|
||||
let id =
|
||||
api::SysId(NonZero::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).expect("next_id wrapped"));
|
||||
let sys_inst = ext.reqnot.request(api::NewSystem { depends, id, system: self.decl.id });
|
||||
let data = System(Arc::new(SystemInstData {
|
||||
decl_id: self.decl.id,
|
||||
ext: Extension(ext),
|
||||
exprs: RwLock::default(),
|
||||
lex_filter: sys_inst.lex_filter,
|
||||
const_root: OnceLock::new(),
|
||||
line_types: sys_inst.line_types.into_iter().map(deintern).collect(),
|
||||
id,
|
||||
}));
|
||||
let root = (sys_inst.const_root.into_iter())
|
||||
.map(|(k, v)| OwnedMember::from_api(Member { public: true, name: k, kind: v }, &data))
|
||||
.collect_vec();
|
||||
data.0.const_root.set(root).unwrap();
|
||||
.map(|(k, v)| Member::from_api(api::Member { exported: true, name: k, kind: v }, &data))
|
||||
.collect_vec();
|
||||
data.0.const_root.set(root).unwrap();
|
||||
inst_g.insert(id, data.clone());
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref SYSTEM_INSTS: RwLock<HashMap<SysId, System>> = RwLock::default();
|
||||
static ref LEX_RECUR: Mutex<HashMap<ParsId, SyncSender<ReqPair<SubLex>>>> = Mutex::default();
|
||||
static ref SYSTEM_INSTS: RwLock<HashMap<api::SysId, System>> = RwLock::default();
|
||||
static ref LEX_RECUR: Mutex<HashMap<api::ParsId, SyncSender<ReqPair<api::SubLex>>>> =
|
||||
Mutex::default();
|
||||
}
|
||||
|
||||
pub struct ReqPair<R: Request>(R, pub SyncSender<R::Response>);
|
||||
|
||||
#[derive(destructure)]
|
||||
pub struct SystemInstData {
|
||||
exprs: RwLock<HashMap<ExprTicket, (AtomicU32, RtExpr)>>,
|
||||
exprs: RwLock<HashMap<api::ExprTicket, (AtomicU32, RtExpr)>>,
|
||||
ext: Extension,
|
||||
decl_id: SysDeclId,
|
||||
lex_filter: CharFilter,
|
||||
id: SysId,
|
||||
const_root: OnceLock<Vec<OwnedMember>>,
|
||||
decl_id: api::SysDeclId,
|
||||
lex_filter: api::CharFilter,
|
||||
id: api::SysId,
|
||||
const_root: OnceLock<Vec<Member>>,
|
||||
line_types: Vec<Tok<String>>,
|
||||
}
|
||||
impl Drop for SystemInstData {
|
||||
fn drop(&mut self) {
|
||||
self.ext.0.reqnot.notify(SystemDrop(self.id));
|
||||
self.ext.0.reqnot.notify(api::SystemDrop(self.id));
|
||||
if let Ok(mut g) = SYSTEM_INSTS.write() {
|
||||
g.remove(&self.id);
|
||||
}
|
||||
@@ -271,22 +302,26 @@ impl Drop for SystemInstData {
|
||||
#[derive(Clone)]
|
||||
pub struct System(Arc<SystemInstData>);
|
||||
impl System {
|
||||
pub fn id(&self) -> SysId { self.id }
|
||||
fn resolve(id: SysId) -> Option<System> { SYSTEM_INSTS.read().unwrap().get(&id).cloned() }
|
||||
fn reqnot(&self) -> &ReqNot<HostMsgSet> { &self.0.ext.0.reqnot }
|
||||
fn give_expr(&self, ticket: ExprTicket, get_expr: impl FnOnce() -> RtExpr) -> ExprTicket {
|
||||
pub fn id(&self) -> api::SysId { self.id }
|
||||
fn resolve(id: api::SysId) -> Option<System> { SYSTEM_INSTS.read().unwrap().get(&id).cloned() }
|
||||
fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { &self.0.ext.0.reqnot }
|
||||
fn give_expr(
|
||||
&self,
|
||||
ticket: api::ExprTicket,
|
||||
get_expr: impl FnOnce() -> RtExpr,
|
||||
) -> api::ExprTicket {
|
||||
match self.0.exprs.write().unwrap().entry(ticket) {
|
||||
Entry::Occupied(mut oe) => {
|
||||
oe.get_mut().0.fetch_add(1, Ordering::Relaxed);
|
||||
},
|
||||
Entry::Vacant(v) => {
|
||||
v.insert((AtomicU32::new(1), get_expr()));
|
||||
}
|
||||
},
|
||||
}
|
||||
ticket
|
||||
}
|
||||
pub fn get_tree(&self, id: TreeId) -> MemberKind {
|
||||
self.reqnot().request(GetMember(self.0.id, id))
|
||||
pub fn get_tree(&self, id: api::TreeId) -> api::MemberKind {
|
||||
self.reqnot().request(api::GetMember(self.0.id, id))
|
||||
}
|
||||
pub fn has_lexer(&self) -> bool { !self.0.lex_filter.0.is_empty() }
|
||||
pub fn can_lex(&self, c: char) -> bool { char_filter_match(&self.0.lex_filter, c) }
|
||||
@@ -296,11 +331,11 @@ impl System {
|
||||
&self,
|
||||
source: Tok<String>,
|
||||
pos: u32,
|
||||
mut r: impl FnMut(u32) -> Option<SubLexed> + Send,
|
||||
) -> ProjResult<Option<LexedExpr>> {
|
||||
mut r: impl FnMut(u32) -> Option<api::SubLexed> + Send,
|
||||
) -> api::OrcResult<Option<api::LexedExpr>> {
|
||||
// get unique lex ID
|
||||
static LEX_ID: AtomicU64 = AtomicU64::new(1);
|
||||
let id = ParsId(NonZero::new(LEX_ID.fetch_add(1, Ordering::Relaxed)).unwrap());
|
||||
let id = api::ParsId(NonZero::new(LEX_ID.fetch_add(1, Ordering::Relaxed)).unwrap());
|
||||
thread::scope(|s| {
|
||||
// create and register channel
|
||||
let (req_in, req_out) = sync_channel(0);
|
||||
@@ -312,12 +347,23 @@ impl System {
|
||||
}
|
||||
});
|
||||
// Pass control to extension
|
||||
let ret = self.reqnot().request(LexExpr { id, pos, sys: self.id(), text: source.marker() });
|
||||
let ret =
|
||||
self.reqnot().request(api::LexExpr { id, pos, sys: self.id(), text: source.marker() });
|
||||
// collect sender to unblock recursion handler thread before returning
|
||||
LEX_RECUR.lock().unwrap().remove(&id);
|
||||
ret.transpose()
|
||||
}) // exit recursion handler thread
|
||||
}
|
||||
pub fn can_parse(&self, line_type: Tok<String>) -> bool { self.line_types.contains(&line_type) }
|
||||
pub fn line_types(&self) -> impl Iterator<Item = Tok<String>> + '_ {
|
||||
self.line_types.iter().cloned()
|
||||
}
|
||||
pub fn parse(&self, line: Vec<ParsTokTree>) -> OrcRes<Vec<ParsTokTree>> {
|
||||
let line = line.iter().map(|t| t.to_api(&mut |n, _| match *n {})).collect_vec();
|
||||
let parsed = (self.reqnot().request(api::ParseLine { sys: self.id(), line }))
|
||||
.map_err(|e| errv_from_apiv(e.iter()))?;
|
||||
Ok(ttv_from_api(parsed, &mut ()))
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for System {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
@@ -341,12 +387,12 @@ impl Deref for System {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SysResolvErr {
|
||||
Loop(Vec<String>),
|
||||
Missing(String)
|
||||
Missing(String),
|
||||
}
|
||||
|
||||
pub fn init_systems(tgts: &[String], exts: &[Extension]) -> Result<Vec<System>, SysResolvErr> {
|
||||
let mut to_load = HashMap::<&str, &SystemCtor>::new();
|
||||
let mut to_find = tgts.iter().map(|s| s.as_str()).collect::<VecDeque::<&str>>();
|
||||
let mut to_find = tgts.iter().map(|s| s.as_str()).collect::<VecDeque<&str>>();
|
||||
while let Some(target) = to_find.pop_front() {
|
||||
if to_load.contains_key(target) {
|
||||
continue;
|
||||
@@ -360,17 +406,18 @@ pub fn init_systems(tgts: &[String], exts: &[Extension]) -> Result<Vec<System>,
|
||||
}
|
||||
let mut to_load_ordered = Vec::new();
|
||||
fn walk_deps<'a>(
|
||||
graph: &mut HashMap::<&str, &'a SystemCtor>,
|
||||
graph: &mut HashMap<&str, &'a SystemCtor>,
|
||||
list: &mut Vec<&'a SystemCtor>,
|
||||
chain: Stackframe<&str>
|
||||
chain: Stackframe<&str>,
|
||||
) -> Result<(), SysResolvErr> {
|
||||
if let Some(ctor) = graph.remove(chain.item) {
|
||||
// if the above is none, the system is already queued. Missing systems are detected above
|
||||
// if the above is none, the system is already queued. Missing systems are
|
||||
// detected above
|
||||
for dep in ctor.decl.depends.iter() {
|
||||
if Substack::Frame(chain).iter().any(|c| c == dep) {
|
||||
let mut circle = vec![dep.to_string()];
|
||||
circle.extend(Substack::Frame(chain).iter().map(|s| s.to_string()));
|
||||
return Err(SysResolvErr::Loop(circle))
|
||||
return Err(SysResolvErr::Loop(circle));
|
||||
}
|
||||
walk_deps(graph, list, Substack::Frame(chain).new_frame(dep))?
|
||||
}
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::Arc;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use orchid_api::parser::SubLexed;
|
||||
use orchid_api::system::SysId;
|
||||
use orchid_api::tree::{Token, TokenTree, TreeTicket};
|
||||
use orchid_base::error::OwnedError;
|
||||
use orchid_base::error::{mk_err, OrcErr, OrcRes};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::{deintern, intern, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
||||
use orchid_base::tokens::{OwnedPh, PARENS};
|
||||
|
||||
use crate::api;
|
||||
use crate::extension::{AtomHand, System};
|
||||
use crate::results::{mk_err, OwnedResult};
|
||||
use crate::tree::{OwnedTok, OwnedTokTree};
|
||||
use crate::tree::{ParsTok, ParsTokTree};
|
||||
|
||||
pub struct LexCtx<'a> {
|
||||
pub systems: &'a [System],
|
||||
pub source: &'a Tok<String>,
|
||||
pub tail: &'a str,
|
||||
pub sub_trees: &'a mut HashMap<TreeTicket, OwnedTokTree>,
|
||||
pub sub_trees: &'a mut HashMap<api::TreeTicket, ParsTokTree>,
|
||||
}
|
||||
impl<'a> LexCtx<'a> {
|
||||
pub fn push<'b>(&'b mut self, pos: u32) -> LexCtx<'b>
|
||||
@@ -42,12 +41,12 @@ impl<'a> LexCtx<'a> {
|
||||
}
|
||||
false
|
||||
}
|
||||
pub fn add_subtree(&mut self, subtree: OwnedTokTree) -> TreeTicket {
|
||||
let next_idx = TreeTicket(NonZeroU64::new(self.sub_trees.len() as u64 + 1).unwrap());
|
||||
pub fn add_subtree(&mut self, subtree: ParsTokTree) -> api::TreeTicket {
|
||||
let next_idx = api::TreeTicket(NonZeroU64::new(self.sub_trees.len() as u64 + 1).unwrap());
|
||||
self.sub_trees.insert(next_idx, subtree);
|
||||
next_idx
|
||||
}
|
||||
pub fn rm_subtree(&mut self, ticket: TreeTicket) -> OwnedTokTree {
|
||||
pub fn rm_subtree(&mut self, ticket: api::TreeTicket) -> ParsTokTree {
|
||||
self.sub_trees.remove(&ticket).unwrap()
|
||||
}
|
||||
pub fn strip_char(&mut self, tgt: char) -> bool {
|
||||
@@ -69,7 +68,7 @@ impl<'a> LexCtx<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
pub fn lex_once(ctx: &mut LexCtx) -> OrcRes<ParsTokTree> {
|
||||
let start = ctx.get_pos();
|
||||
assert!(
|
||||
!ctx.tail.is_empty() && !ctx.tail.starts_with(unrep_space),
|
||||
@@ -77,9 +76,9 @@ pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
Invocations of lex_tok should check for empty string"
|
||||
);
|
||||
let tok = if ctx.strip_prefix("\r\n") || ctx.strip_prefix("\r") || ctx.strip_prefix("\n") {
|
||||
OwnedTok::BR
|
||||
ParsTok::BR
|
||||
} else if ctx.strip_prefix("::") {
|
||||
OwnedTok::NS
|
||||
ParsTok::NS
|
||||
} else if ctx.strip_prefix("--[") {
|
||||
let (cmt, tail) = ctx.tail.split_once("]--").ok_or_else(|| {
|
||||
vec![mk_err(
|
||||
@@ -89,11 +88,11 @@ pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
)]
|
||||
})?;
|
||||
ctx.set_tail(tail);
|
||||
OwnedTok::Comment(cmt.to_string())
|
||||
ParsTok::Comment(Arc::new(cmt.to_string()))
|
||||
} else if let Some(tail) = ctx.tail.strip_prefix("--").filter(|t| !t.starts_with(op_char)) {
|
||||
let end = tail.find(['\n', '\r']).map_or(tail.len(), |n| n - 1);
|
||||
ctx.push_pos(end as u32);
|
||||
OwnedTok::Comment(tail[2..end].to_string())
|
||||
ParsTok::Comment(Arc::new(tail[2..end].to_string()))
|
||||
} else if ctx.strip_char('\\') {
|
||||
let mut arg = Vec::new();
|
||||
ctx.trim_ws();
|
||||
@@ -108,7 +107,7 @@ pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
arg.push(lex_once(ctx)?);
|
||||
ctx.trim_ws();
|
||||
}
|
||||
OwnedTok::Lambda(arg)
|
||||
ParsTok::LambdaHead(arg)
|
||||
} else if let Some((lp, rp, paren)) = PARENS.iter().find(|(lp, ..)| ctx.strip_char(*lp)) {
|
||||
let mut body = Vec::new();
|
||||
ctx.trim_ws();
|
||||
@@ -123,31 +122,32 @@ pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
body.push(lex_once(ctx)?);
|
||||
ctx.trim_ws();
|
||||
}
|
||||
OwnedTok::S(paren.clone(), body)
|
||||
ParsTok::S(paren.clone(), body)
|
||||
} else {
|
||||
for sys in ctx.systems {
|
||||
let mut errors = Vec::new();
|
||||
if ctx.tail.starts_with(|c| sys.can_lex(c)) {
|
||||
let lexed = sys.lex(ctx.source.clone(), ctx.get_pos(), |pos| {
|
||||
let mut sub_ctx = ctx.push(pos);
|
||||
let ott = lex_once(&mut sub_ctx).inspect_err(|e| errors.extend(e.iter().cloned())).ok()?;
|
||||
Some(SubLexed { pos: sub_ctx.get_pos(), ticket: sub_ctx.add_subtree(ott) })
|
||||
let ott =
|
||||
lex_once(&mut sub_ctx).inspect_err(|e| errors.extend(e.iter().cloned())).ok()?;
|
||||
Some(api::SubLexed { pos: sub_ctx.get_pos(), ticket: sub_ctx.add_subtree(ott) })
|
||||
});
|
||||
match lexed {
|
||||
Ok(None) if errors.is_empty() => continue,
|
||||
Ok(None) => return Err(errors),
|
||||
Err(e) => return Err(e.into_iter().map(|e| OwnedError::from_api(&e)).collect()),
|
||||
Err(e) => return Err(e.into_iter().map(|e| OrcErr::from_api(&e)).collect()),
|
||||
Ok(Some(lexed)) => {
|
||||
ctx.set_pos(lexed.pos);
|
||||
return Ok(tt_to_owned(&lexed.expr, sys.id(), ctx))
|
||||
return Ok(tt_to_owned(&lexed.expr, ctx));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
if ctx.tail.starts_with(name_start) {
|
||||
OwnedTok::Name(intern(ctx.get_start_matches(name_char)))
|
||||
ParsTok::Name(intern(ctx.get_start_matches(name_char)))
|
||||
} else if ctx.tail.starts_with(op_char) {
|
||||
OwnedTok::Name(intern(ctx.get_start_matches(op_char)))
|
||||
ParsTok::Name(intern(ctx.get_start_matches(op_char)))
|
||||
} else {
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Unrecognized character"),
|
||||
@@ -156,37 +156,29 @@ pub fn lex_once(ctx: &mut LexCtx) -> OwnedResult<OwnedTokTree> {
|
||||
)]);
|
||||
}
|
||||
};
|
||||
Ok(OwnedTokTree { tok, range: start..ctx.get_pos() })
|
||||
Ok(ParsTokTree { tok, range: start..ctx.get_pos() })
|
||||
}
|
||||
|
||||
fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
|
||||
fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() }
|
||||
fn op_char(c: char) -> bool { !name_char(c) && !c.is_whitespace() && !"()[]{}\\".contains(c) }
|
||||
fn unrep_space(c: char) -> bool { c.is_whitespace() && !"\r\n".contains(c) }
|
||||
|
||||
fn tt_to_owned(api: &TokenTree, sys: SysId, ctx: &mut LexCtx<'_>) -> OwnedTokTree {
|
||||
fn tt_to_owned(api: &api::TokenTree, ctx: &mut LexCtx<'_>) -> ParsTokTree {
|
||||
let tok = match &api.token {
|
||||
Token::Atom(atom) => OwnedTok::Atom(AtomHand::from_api(atom.clone().associate(sys))),
|
||||
Token::Ph(ph) => OwnedTok::Ph(OwnedPh::from_api(ph.clone())),
|
||||
Token::Bottom(err) => OwnedTok::Bottom(err.iter().map(OwnedError::from_api).collect()),
|
||||
Token::Lambda(arg) => OwnedTok::Lambda(arg.iter().map(|t| tt_to_owned(t, sys, ctx)).collect()),
|
||||
Token::Name(name) => OwnedTok::Name(deintern(*name)),
|
||||
Token::S(p, b) => OwnedTok::S(p.clone(), b.iter().map(|t| tt_to_owned(t, sys, ctx)).collect()),
|
||||
Token::Slot(id) => return ctx.rm_subtree(*id),
|
||||
Token::BR => OwnedTok::BR,
|
||||
Token::NS => OwnedTok::NS,
|
||||
api::Token::Atom(atom) => ParsTok::Atom(AtomHand::from_api(atom.clone())),
|
||||
api::Token::Ph(ph) => ParsTok::Ph(OwnedPh::from_api(ph.clone())),
|
||||
api::Token::Bottom(err) => ParsTok::Bottom(err.iter().map(OrcErr::from_api).collect()),
|
||||
api::Token::Lambda(arg) =>
|
||||
ParsTok::LambdaHead(arg.iter().map(|t| tt_to_owned(t, ctx)).collect()),
|
||||
api::Token::Name(name) => ParsTok::Name(deintern(*name)),
|
||||
api::Token::S(p, b) => ParsTok::S(p.clone(), b.iter().map(|t| tt_to_owned(t, ctx)).collect()),
|
||||
api::Token::Slot(id) => return ctx.rm_subtree(*id),
|
||||
api::Token::BR => ParsTok::BR,
|
||||
api::Token::NS => ParsTok::NS,
|
||||
api::Token::Comment(c) => ParsTok::Comment(c.clone()),
|
||||
};
|
||||
OwnedTokTree { range: api.range.clone(), tok }
|
||||
ParsTokTree { range: api.range.clone(), tok }
|
||||
}
|
||||
|
||||
pub fn lex(text: Tok<String>, systems: &[System]) -> OwnedResult<Vec<OwnedTokTree>> {
|
||||
pub fn lex(text: Tok<String>, systems: &[System]) -> OrcRes<Vec<ParsTokTree>> {
|
||||
let mut sub_trees = HashMap::new();
|
||||
let mut ctx = LexCtx {
|
||||
source: &text,
|
||||
sub_trees: &mut sub_trees,
|
||||
tail: &text[..],
|
||||
systems,
|
||||
};
|
||||
let mut ctx = LexCtx { source: &text, sub_trees: &mut sub_trees, tail: &text[..], systems };
|
||||
let mut tokv = Vec::new();
|
||||
ctx.trim(unrep_space);
|
||||
while !ctx.tail.is_empty() {
|
||||
@@ -194,4 +186,4 @@ pub fn lex(text: Tok<String>, systems: &[System]) -> OwnedResult<Vec<OwnedTokTre
|
||||
ctx.trim(unrep_space);
|
||||
}
|
||||
Ok(tokv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use orchid_api as api;
|
||||
|
||||
pub mod child;
|
||||
pub mod expr;
|
||||
pub mod extension;
|
||||
pub mod lex;
|
||||
pub mod results;
|
||||
pub mod tree;
|
||||
pub mod parse;
|
||||
pub mod tree;
|
||||
pub mod subprocess;
|
||||
|
||||
@@ -1,33 +1,187 @@
|
||||
use std::{iter, thread};
|
||||
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use orchid_base::error::{mk_err, OrcErr, OrcRes, Reporter};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::parse::{
|
||||
expect_end, expect_tok, line_items, parse_multiname, strip_fluff, try_pop_no_fluff, Comment, CompName, Snippet
|
||||
};
|
||||
use orchid_base::tree::{Paren, TokTree, Token};
|
||||
|
||||
use crate::tree::{OwnedItem, OwnedModule, OwnedTok, OwnedTokTree};
|
||||
use crate::extension::{AtomHand, System};
|
||||
use crate::tree::{Item, ItemKind, Macro, Member, MemberKind, Module, ParsTokTree};
|
||||
|
||||
pub struct ParseCtx<'a> {
|
||||
tokens: &'a [OwnedTokTree]
|
||||
type ParsSnippet<'a> = Snippet<'a, 'static, AtomHand, Never>;
|
||||
|
||||
pub trait ParseCtx: Send + Sync {
|
||||
fn systems(&self) -> impl Iterator<Item = &System>;
|
||||
fn reporter(&self) -> &impl Reporter;
|
||||
}
|
||||
|
||||
pub fn split_br(ctx: ParseCtx) -> impl Iterator<Item = ParseCtx> {
|
||||
ctx.tokens.split(|t| matches!(t.tok, OwnedTok::BR)).map(|tokens| ParseCtx { tokens })
|
||||
pub fn parse_items(ctx: &impl ParseCtx, items: ParsSnippet) -> OrcRes<Vec<Item>> {
|
||||
let lines = line_items(items);
|
||||
let mut ok = iter::from_fn(|| None).take(lines.len()).collect_vec();
|
||||
thread::scope(|s| {
|
||||
let mut threads = Vec::new();
|
||||
for (slot, (cmts, item)) in ok.iter_mut().zip(lines.into_iter()) {
|
||||
threads.push(s.spawn(move || {
|
||||
*slot = Some(parse_item(ctx, cmts, item)?);
|
||||
Ok::<(), Vec<OrcErr>>(())
|
||||
}))
|
||||
}
|
||||
for t in threads {
|
||||
t.join().unwrap().err().into_iter().flatten().for_each(|e| ctx.reporter().report(e))
|
||||
}
|
||||
});
|
||||
Ok(ok.into_iter().flatten().flatten().collect_vec())
|
||||
}
|
||||
|
||||
pub fn strip_br(tt: &OwnedTokTree) -> Option<OwnedTokTree> {
|
||||
let tok = match &tt.tok {
|
||||
OwnedTok::BR => return None,
|
||||
OwnedTok::Lambda(arg) => OwnedTok::Lambda(arg.iter().filter_map(strip_br).collect()),
|
||||
OwnedTok::S(p, b) => OwnedTok::S(p.clone(), b.iter().filter_map(strip_br).collect()),
|
||||
t => t.clone(),
|
||||
pub fn parse_item(
|
||||
ctx: &impl ParseCtx,
|
||||
comments: Vec<Comment>,
|
||||
item: ParsSnippet,
|
||||
) -> OrcRes<Vec<Item>> {
|
||||
match item.pop_front() {
|
||||
Some((TokTree { tok: Token::Name(n), .. }, postdisc)) => match n {
|
||||
n if *n == intern!(str: "export") => match try_pop_no_fluff(postdisc)? {
|
||||
(TokTree { tok: Token::Name(n), .. }, postdisc) =>
|
||||
parse_item_2(ctx, comments, true, n.clone(), postdisc),
|
||||
(TokTree { tok: Token::NS, .. }, postdisc) => {
|
||||
let (exports, surplus) = parse_multiname(ctx.reporter(), postdisc)?;
|
||||
let mut ok = Vec::new();
|
||||
exports.into_iter().for_each(|e| match (&e.path.as_slice(), e.name) {
|
||||
([], Some(n)) => ok.push(Item {
|
||||
comments: comments.clone(),
|
||||
pos: e.pos.clone(),
|
||||
kind: ItemKind::Export(n),
|
||||
}),
|
||||
(_, Some(_)) => ctx.reporter().report(mk_err(
|
||||
intern!(str: "Compound export"),
|
||||
"Cannot export compound names (names containing the :: separator)",
|
||||
[e.pos.into()],
|
||||
)),
|
||||
(_, None) => ctx.reporter().report(mk_err(
|
||||
intern!(str: "Wildcard export"),
|
||||
"Exports cannot contain the globstar *",
|
||||
[e.pos.into()],
|
||||
)),
|
||||
});
|
||||
expect_end(surplus)?;
|
||||
Ok(ok)
|
||||
},
|
||||
(bogus, _) => Err(vec![mk_err(
|
||||
intern!(str: "Malformed export"),
|
||||
"`export` can either prefix other lines or list names inside ::( ) or ::[ ]",
|
||||
[Pos::Range(bogus.range.clone()).into()],
|
||||
)]),
|
||||
},
|
||||
n if *n == intern!(str: "import") => parse_import(ctx, postdisc).map(|v| {
|
||||
Vec::from_iter(v.into_iter().map(|t| Item {
|
||||
comments: comments.clone(),
|
||||
pos: Pos::Range(postdisc.pos()),
|
||||
kind: ItemKind::Import(t),
|
||||
}))
|
||||
}),
|
||||
n => parse_item_2(ctx, comments, false, n.clone(), postdisc),
|
||||
},
|
||||
Some(_) => Err(vec![mk_err(
|
||||
intern!(str: "Expected a line type"),
|
||||
"All lines must begin with a keyword",
|
||||
[Pos::Range(item.pos()).into()],
|
||||
)]),
|
||||
None => unreachable!("These lines are filtered and aggregated in earlier stages"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_import(ctx: &impl ParseCtx, tail: ParsSnippet) -> OrcRes<Vec<CompName>> {
|
||||
let (imports, surplus) = parse_multiname(ctx.reporter(), tail)?;
|
||||
expect_end(surplus)?;
|
||||
Ok(imports)
|
||||
}
|
||||
|
||||
pub fn parse_item_2(
|
||||
ctx: &impl ParseCtx,
|
||||
comments: Vec<Comment>,
|
||||
exported: bool,
|
||||
discr: Tok<String>,
|
||||
tail: ParsSnippet,
|
||||
) -> OrcRes<Vec<Item>> {
|
||||
let kind = if discr == intern!(str: "mod") {
|
||||
let (name, body) = parse_module(ctx, tail)?;
|
||||
ItemKind::Member(Member::new(exported, name, MemberKind::Mod(body)))
|
||||
} else if discr == intern!(str: "const") {
|
||||
let (name, val) = parse_const(tail)?;
|
||||
ItemKind::Member(Member::new(exported, name, MemberKind::Const(val)))
|
||||
} else if discr == intern!(str: "macro") {
|
||||
ItemKind::Rule(parse_macro(tail)?)
|
||||
} else if let Some(sys) = ctx.systems().find(|s| s.can_parse(discr.clone())) {
|
||||
let line = sys.parse(tail.to_vec())?;
|
||||
return parse_items(ctx, Snippet::new(tail.prev(), &line))
|
||||
} else {
|
||||
let ext_lines = ctx.systems().flat_map(System::line_types).join(", ");
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Unrecognized line type"),
|
||||
format!("Line types are: const, mod, macro, grammar, {ext_lines}"),
|
||||
[Pos::Range(tail.prev().range.clone()).into()]
|
||||
)])
|
||||
};
|
||||
Some(OwnedTokTree { tok, range: tt.range.clone() })
|
||||
Ok(vec![Item { comments, pos: Pos::Range(tail.pos()), kind }])
|
||||
}
|
||||
|
||||
pub fn parse_items(ctx: ParseCtx) -> Vec<OwnedItem> {
|
||||
todo!()
|
||||
pub fn parse_module(
|
||||
ctx: &impl ParseCtx,
|
||||
tail: ParsSnippet,
|
||||
) -> OrcRes<(Tok<String>, Module)> {
|
||||
let (name, tail) = match try_pop_no_fluff(tail)? {
|
||||
(TokTree { tok: Token::Name(n), .. }, tail) => (n.clone(), tail),
|
||||
(tt, _) =>
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Missing module name"),
|
||||
format!("A name was expected, {tt} was found"),
|
||||
[Pos::Range(tt.range.clone()).into()],
|
||||
)]),
|
||||
};
|
||||
let (body, surplus) = match try_pop_no_fluff(tail)? {
|
||||
(TokTree { tok: Token::S(Paren::Round, b), .. }, tail) => (b, tail),
|
||||
(tt, _) =>
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Expected module body"),
|
||||
format!("A ( block ) was expected, {tt} was found"),
|
||||
[Pos::Range(tt.range.clone()).into()],
|
||||
)]),
|
||||
};
|
||||
let items = parse_items(ctx, ParsSnippet::new(surplus.prev(), body))?;
|
||||
Ok((name, Module { imports: vec![], items }))
|
||||
}
|
||||
|
||||
pub fn parse_item(ctx: ParseCtx) -> OwnedItem {
|
||||
todo!()
|
||||
pub fn parse_const(tail: ParsSnippet) -> OrcRes<(Tok<String>, Vec<ParsTokTree>)> {
|
||||
let (name, tail) = match try_pop_no_fluff(tail)? {
|
||||
(TokTree { tok: Token::Name(n), .. }, tail) => (n.clone(), tail),
|
||||
(tt, _) =>
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Missing module name"),
|
||||
format!("A name was expected, {tt} was found"),
|
||||
[Pos::Range(tt.range.clone()).into()],
|
||||
)]),
|
||||
};
|
||||
let tail = match try_pop_no_fluff(tail)? {
|
||||
(TokTree { tok: Token::Name(n), .. }, tail) if *n == intern!(str: ":=") => tail,
|
||||
(tt, _) =>
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "Missing walrus := separator"),
|
||||
format!("Expected operator := , found {tt}"),
|
||||
[Pos::Range(tt.range.clone()).into()],
|
||||
)]),
|
||||
};
|
||||
try_pop_no_fluff(tail)?;
|
||||
Ok((name, tail.iter().flat_map(strip_fluff).collect_vec()))
|
||||
}
|
||||
|
||||
pub fn parse_module(ctx: ParseCtx) -> (Tok<String>, OwnedModule) {
|
||||
todo!()
|
||||
pub fn parse_macro(tail: ParsSnippet) -> OrcRes<Macro> {
|
||||
let tail = expect_tok(tail, intern!(str: "prio"))?;
|
||||
let (prio, tail) = ((), ());
|
||||
todo!();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use orchid_base::error::{ErrorPosition, OwnedError};
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::number::{NumError, NumErrorKind};
|
||||
|
||||
pub type OwnedResult<T> = Result<T, Vec<OwnedError>>;
|
||||
|
||||
pub fn mk_err(
|
||||
description: Tok<String>,
|
||||
message: impl AsRef<str>,
|
||||
posv: impl IntoIterator<Item = ErrorPosition>,
|
||||
) -> OwnedError {
|
||||
OwnedError {
|
||||
description,
|
||||
message: Arc::new(message.as_ref().to_string()),
|
||||
positions: posv.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_to_err(NumError { kind, range }: NumError, offset: u32) -> OwnedError {
|
||||
OwnedError {
|
||||
description: intern!(str: "Failed to parse number"),
|
||||
message: Arc::new(
|
||||
match kind {
|
||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||
NumErrorKind::Overflow => "The number being described is too large or too accurate",
|
||||
}
|
||||
.to_string(),
|
||||
),
|
||||
positions: vec![Pos::Range(offset + range.start as u32..offset + range.end as u32).into()],
|
||||
}
|
||||
}
|
||||
53
orchid-host/src/subprocess.rs
Normal file
53
orchid-host/src/subprocess.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use std::{io::{self, BufRead as _}, path::PathBuf, process, sync::Mutex, thread};
|
||||
|
||||
use orchid_base::{logging::Logger, msg::{recv_msg, send_msg}};
|
||||
|
||||
use crate::extension::ExtensionPort;
|
||||
|
||||
pub struct Subprocess {
|
||||
child: Mutex<process::Child>,
|
||||
stdin: Mutex<process::ChildStdin>,
|
||||
stdout: Mutex<process::ChildStdout>,
|
||||
}
|
||||
impl Subprocess {
|
||||
pub fn new(mut cmd: process::Command, logger: Logger) -> io::Result<Self> {
|
||||
let prog_pbuf = PathBuf::from(cmd.get_program());
|
||||
let prog = prog_pbuf.file_stem().unwrap_or(cmd.get_program()).to_string_lossy().to_string();
|
||||
let mut child = cmd
|
||||
.stdin(process::Stdio::piped())
|
||||
.stdout(process::Stdio::piped())
|
||||
.stderr(process::Stdio::piped())
|
||||
.spawn()?;
|
||||
let stdin = child.stdin.take().unwrap();
|
||||
let stdout = child.stdout.take().unwrap();
|
||||
let child_stderr = child.stderr.take().unwrap();
|
||||
thread::Builder::new()
|
||||
.name(format!("stderr-fwd:{prog}"))
|
||||
.spawn(move || {
|
||||
let mut reader = io::BufReader::new(child_stderr);
|
||||
loop {
|
||||
let mut buf = String::new();
|
||||
if 0 == reader.read_line(&mut buf).unwrap() {
|
||||
break;
|
||||
}
|
||||
logger.log(buf);
|
||||
}
|
||||
})?;
|
||||
Ok(Self{ child: Mutex::new(child), stdin: Mutex::new(stdin), stdout: Mutex::new(stdout) })
|
||||
}
|
||||
}
|
||||
impl Drop for Subprocess {
|
||||
fn drop(&mut self) {
|
||||
self.child.lock().unwrap().wait().expect("Extension exited with error");
|
||||
}
|
||||
}
|
||||
impl ExtensionPort for Subprocess {
|
||||
fn send(&self, msg: &[u8]) { send_msg(&mut *self.stdin.lock().unwrap(), msg).unwrap() }
|
||||
fn receive(&self) -> Option<Vec<u8>> {
|
||||
match recv_msg(&mut *self.stdout.lock().unwrap()) {
|
||||
Ok(msg) => Some(msg),
|
||||
Err(e) if e.kind() == io::ErrorKind::BrokenPipe => None,
|
||||
Err(e) => panic!("Failed to read from stdout: {}, {e}", e.kind()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,210 +1,124 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt::{Display, Write};
|
||||
use std::ops::Range;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
use itertools::Itertools;
|
||||
use never::Never;
|
||||
use orchid_api::tree::{Item, ItemKind, Macro, Member, MemberKind, Module, Paren, Token, TokenTree, TreeId, TreeTicket};
|
||||
use orchid_base::error::OwnedError;
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::interner::{deintern, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::name::Sym;
|
||||
use orchid_base::tokens::{OwnedPh, PARENS};
|
||||
use orchid_base::parse::{Comment, CompName};
|
||||
use orchid_base::tree::{ttv_from_api, TokTree, Token};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use crate::api;
|
||||
use crate::expr::RtExpr;
|
||||
use crate::extension::{AtomHand, System};
|
||||
use crate::results::OwnedResult;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OwnedTokTree {
|
||||
pub tok: OwnedTok,
|
||||
pub range: Range<u32>,
|
||||
}
|
||||
impl OwnedTokTree {
|
||||
pub fn from_api<E>(
|
||||
tt: &TokenTree,
|
||||
sys: &System,
|
||||
do_slot: &mut impl FnMut(&TreeTicket, Range<u32>) -> Result<Self, E>,
|
||||
) -> Result<Self, E> {
|
||||
let tok = match &tt.token {
|
||||
Token::Atom(a) => OwnedTok::Atom(AtomHand::from_api(a.clone().associate(sys.id()))),
|
||||
Token::BR => OwnedTok::BR,
|
||||
Token::NS => OwnedTok::NS,
|
||||
Token::Bottom(e) => OwnedTok::Bottom(e.iter().map(OwnedError::from_api).collect_vec()),
|
||||
Token::Lambda(arg) => OwnedTok::Lambda(Self::v_from_api(arg, sys, do_slot)?),
|
||||
Token::Name(name) => OwnedTok::Name(deintern(*name)),
|
||||
Token::Ph(ph) => OwnedTok::Ph(OwnedPh::from_api(ph.clone())),
|
||||
Token::S(par, b) => OwnedTok::S(par.clone(), Self::v_from_api(b, sys, do_slot)?),
|
||||
Token::Slot(id) => return do_slot(id, tt.range.clone()),
|
||||
};
|
||||
Ok(Self { range: tt.range.clone(), tok })
|
||||
}
|
||||
|
||||
pub fn v_from_api<E>(
|
||||
tokv: impl IntoIterator<Item: Borrow<TokenTree>>,
|
||||
sys: &System,
|
||||
do_slot: &mut impl FnMut(&TreeTicket, Range<u32>) -> Result<Self, E>,
|
||||
) -> Result<Vec<Self>, E> {
|
||||
tokv.into_iter().map(|t| Self::from_api(t.borrow(), sys, do_slot)).collect()
|
||||
}
|
||||
}
|
||||
impl Display for OwnedTokTree {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.tok) }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum OwnedTok {
|
||||
Comment(String),
|
||||
Lambda(Vec<OwnedTokTree>),
|
||||
Name(Tok<String>),
|
||||
NS,
|
||||
BR,
|
||||
S(Paren, Vec<OwnedTokTree>),
|
||||
Atom(AtomHand),
|
||||
Ph(OwnedPh),
|
||||
Bottom(Vec<OwnedError>),
|
||||
}
|
||||
impl Display for OwnedTok {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
thread_local! {
|
||||
static PAREN_LEVEL: RefCell<usize> = 0.into();
|
||||
}
|
||||
fn get_indent() -> usize { PAREN_LEVEL.with_borrow(|t| *t) }
|
||||
fn with_indent<T>(f: impl FnOnce() -> T) -> T {
|
||||
PAREN_LEVEL.with_borrow_mut(|t| *t += 1);
|
||||
let r = f();
|
||||
PAREN_LEVEL.with_borrow_mut(|t| *t -= 1);
|
||||
r
|
||||
}
|
||||
match self {
|
||||
Self::Atom(ah) => f.write_str(&indent(&ah.print(), get_indent(), false)),
|
||||
Self::BR => write!(f, "\n{}", " ".repeat(get_indent())),
|
||||
Self::Bottom(err) => write!(f, "Botttom({})",
|
||||
err.iter().map(|e| format!("{}: {}", e.description, e.message)).join(", ")
|
||||
),
|
||||
Self::Comment(c) => write!(f, "--[{c}]--"),
|
||||
Self::Lambda(arg) => with_indent(|| write!(f, "\\ {} .", fmt_tt_v(arg))),
|
||||
Self::NS => f.write_str("::"),
|
||||
Self::Name(n) => f.write_str(n),
|
||||
Self::Ph(ph) => write!(f, "{ph}"),
|
||||
Self::S(p, b) => {
|
||||
let (lp, rp, _) = PARENS.iter().find(|(_, _, par)| par == p).unwrap();
|
||||
f.write_char(*lp)?;
|
||||
with_indent(|| f.write_str(&fmt_tt_v(b)))?;
|
||||
f.write_char(*rp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt_tt_v<'a>(ttv: impl IntoIterator<Item = &'a OwnedTokTree>) -> String {
|
||||
ttv.into_iter().join(" ")
|
||||
}
|
||||
|
||||
pub fn indent(s: &str, lvl: usize, first: bool) -> String {
|
||||
if first {
|
||||
s.replace("\n", &("\n".to_string() + &" ".repeat(lvl)))
|
||||
} else if let Some((fst, rest)) = s.split_once('\n') {
|
||||
fst.to_string() + "\n" + &indent(rest, lvl, true)
|
||||
} else {
|
||||
s.to_string()
|
||||
}
|
||||
}
|
||||
pub type ParsTokTree = TokTree<'static, AtomHand, Never>;
|
||||
pub type ParsTok = Token<'static, AtomHand, Never>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedItem {
|
||||
pub struct Item {
|
||||
pub pos: Pos,
|
||||
pub kind: OwnedItemKind,
|
||||
pub comments: Vec<Comment>,
|
||||
pub kind: ItemKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OwnedItemKind {
|
||||
Raw(Vec<OwnedTokTree>),
|
||||
Member(OwnedMember),
|
||||
Rule(OwnedMacro),
|
||||
pub enum ItemKind {
|
||||
Raw(Vec<ParsTokTree>),
|
||||
Member(Member),
|
||||
Export(Tok<String>),
|
||||
Rule(Macro),
|
||||
Import(CompName),
|
||||
}
|
||||
|
||||
fn slot_panic(_: &TreeTicket, _: Range<u32>) -> Result<OwnedTokTree, Never> {
|
||||
panic!("No slots allowed at item stage")
|
||||
}
|
||||
|
||||
impl OwnedItem {
|
||||
pub fn from_api(tree: Item, sys: &System) -> Self {
|
||||
impl Item {
|
||||
pub fn from_api(tree: api::Item, sys: &System) -> Self {
|
||||
let kind = match tree.kind {
|
||||
ItemKind::Raw(tokv) =>
|
||||
OwnedItemKind::Raw(OwnedTokTree::v_from_api::<Never>(tokv, sys, &mut slot_panic).unwrap()),
|
||||
ItemKind::Member(m) => OwnedItemKind::Member(OwnedMember::from_api(m, sys)),
|
||||
ItemKind::Rule(r) => OwnedItemKind::Rule(OwnedMacro::from_api(r, sys)),
|
||||
api::ItemKind::Raw(tokv) => ItemKind::Raw(ttv_from_api(tokv, &mut ())),
|
||||
api::ItemKind::Member(m) => ItemKind::Member(Member::from_api(m, sys)),
|
||||
api::ItemKind::Rule(r) => ItemKind::Rule(Macro::from_api(r)),
|
||||
api::ItemKind::Import(i) => ItemKind::Import(CompName::from_api(i)),
|
||||
api::ItemKind::Export(e) => ItemKind::Export(deintern(e)),
|
||||
};
|
||||
Self { pos: Pos::from_api(&tree.location), kind }
|
||||
let comments = tree
|
||||
.comments
|
||||
.into_iter()
|
||||
.map(|(text, l)| Comment { text, pos: Pos::from_api(&l) })
|
||||
.collect_vec();
|
||||
Self { pos: Pos::from_api(&tree.location), comments, kind }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedMember {
|
||||
pub public: bool,
|
||||
pub struct Member {
|
||||
pub exported: bool,
|
||||
pub name: Tok<String>,
|
||||
pub kind: OnceLock<OMemKind>,
|
||||
pub kind: OnceLock<MemberKind>,
|
||||
pub lazy: Mutex<Option<LazyMemberHandle>>,
|
||||
}
|
||||
impl OwnedMember {
|
||||
pub fn from_api(Member{ public, name, kind }: Member, sys: &System) -> Self {
|
||||
impl Member {
|
||||
pub fn from_api(api::Member { exported: public, name, kind }: api::Member, sys: &System) -> Self {
|
||||
let (kind, lazy) = match kind {
|
||||
MemberKind::Const(c) => (OnceLock::from(OMemKind::Const(RtExpr::from_api(c, sys))), None),
|
||||
MemberKind::Module(m) => (OnceLock::from(OMemKind::Mod(OwnedModule::from_api(m, sys))), None),
|
||||
MemberKind::Lazy(id) => (OnceLock::new(), Some(LazyMemberHandle(id, sys.clone())))
|
||||
api::MemberKind::Const(c) =>
|
||||
(OnceLock::from(MemberKind::PreCnst(RtExpr::from_api(c, sys))), None),
|
||||
api::MemberKind::Module(m) =>
|
||||
(OnceLock::from(MemberKind::Mod(Module::from_api(m, sys))), None),
|
||||
api::MemberKind::Lazy(id) => (OnceLock::new(), Some(LazyMemberHandle(id, sys.clone()))),
|
||||
};
|
||||
OwnedMember { public, name: deintern(name), kind, lazy: Mutex::new(lazy) }
|
||||
Member { exported: public, name: deintern(name), kind, lazy: Mutex::new(lazy) }
|
||||
}
|
||||
pub fn new(public: bool, name: Tok<String>, kind: MemberKind) -> Self {
|
||||
Member { exported: public, name, kind: OnceLock::from(kind), lazy: Mutex::default() }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OMemKind {
|
||||
Const(RtExpr),
|
||||
Mod(OwnedModule),
|
||||
pub enum MemberKind {
|
||||
Const(Vec<ParsTokTree>),
|
||||
PreCnst(RtExpr),
|
||||
Mod(Module),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedModule {
|
||||
pub struct Module {
|
||||
pub imports: Vec<Sym>,
|
||||
pub items: Vec<OwnedItem>,
|
||||
pub items: Vec<Item>,
|
||||
}
|
||||
impl OwnedModule {
|
||||
pub fn from_api(m: Module, sys: &System) -> Self {
|
||||
impl Module {
|
||||
pub fn from_api(m: api::Module, sys: &System) -> Self {
|
||||
Self {
|
||||
imports: m.imports.into_iter().map(|m| Sym::from_tok(deintern(m)).unwrap()).collect_vec(),
|
||||
items: m.items.into_iter().map(|i| OwnedItem::from_api(i, sys)).collect_vec(),
|
||||
items: m.items.into_iter().map(|i| Item::from_api(i, sys)).collect_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OwnedMacro {
|
||||
pub struct Macro {
|
||||
pub priority: NotNan<f64>,
|
||||
pub pattern: Vec<OwnedTokTree>,
|
||||
pub template: Vec<OwnedTokTree>,
|
||||
pub pattern: Vec<ParsTokTree>,
|
||||
pub template: Vec<ParsTokTree>,
|
||||
}
|
||||
impl OwnedMacro {
|
||||
pub fn from_api(m: Macro, sys: &System) -> Self {
|
||||
impl Macro {
|
||||
pub fn from_api(m: api::Macro) -> Self {
|
||||
Self {
|
||||
priority: m.priority,
|
||||
pattern: OwnedTokTree::v_from_api(m.pattern, sys, &mut slot_panic).unwrap(),
|
||||
template: OwnedTokTree::v_from_api(m.template, sys, &mut slot_panic).unwrap(),
|
||||
pattern: ttv_from_api(m.pattern, &mut ()),
|
||||
template: ttv_from_api(m.template, &mut ()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LazyMemberHandle(TreeId, System);
|
||||
pub struct LazyMemberHandle(api::TreeId, System);
|
||||
impl LazyMemberHandle {
|
||||
pub fn run(self) -> OwnedResult<OMemKind> {
|
||||
pub fn run(self) -> OrcRes<MemberKind> {
|
||||
match self.1.get_tree(self.0) {
|
||||
MemberKind::Const(c) => Ok(OMemKind::Const(RtExpr::from_api(c, &self.1))),
|
||||
MemberKind::Module(m) => Ok(OMemKind::Mod(OwnedModule::from_api(m, &self.1))),
|
||||
MemberKind::Lazy(id) => Self(id, self.1).run()
|
||||
api::MemberKind::Const(c) => Ok(MemberKind::PreCnst(RtExpr::from_api(c, &self.1))),
|
||||
api::MemberKind::Module(m) => Ok(MemberKind::Mod(Module::from_api(m, &self.1))),
|
||||
api::MemberKind::Lazy(id) => Self(id, self.1).run(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user