Lexer test mode works

This commit is contained in:
2024-08-04 23:24:32 +02:00
parent 9d35ba8040
commit 11951ede43
36 changed files with 687 additions and 115 deletions

View File

@@ -108,6 +108,7 @@ pub trait AtomDynfo: Send + Sync + 'static {
fn call(&self, ctx: AtomCtx<'_>, arg: ExprTicket) -> GenExpr;
fn call_ref(&self, ctx: AtomCtx<'_>, arg: ExprTicket) -> GenExpr;
fn same(&self, ctx: AtomCtx<'_>, buf2: &[u8]) -> bool;
fn print(&self, ctx: AtomCtx<'_>) -> String;
fn handle_req(&self, ctx: AtomCtx<'_>, req: &mut dyn Read, rep: &mut dyn Write);
fn command(&self, ctx: AtomCtx<'_>) -> ProjectResult<Option<GenExpr>>;
fn drop(&self, ctx: AtomCtx<'_>);
@@ -127,8 +128,8 @@ impl Clone for AtomFactory {
fn clone(&self) -> Self { AtomFactory(clone_box(&*self.0)) }
}
pub struct ErrorNotCallable;
impl ProjectError for ErrorNotCallable {
pub struct ErrNotCallable;
impl ProjectError for ErrNotCallable {
const DESCRIPTION: &'static str = "This atom is not callable";
}

View File

@@ -11,12 +11,11 @@ use orchid_api_traits::{Decode, Encode};
use orchid_base::id_store::{IdRecord, IdStore};
use crate::atom::{
AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant,
ErrorNotCallable, ErrorNotCommand, ReqPck, RequestPack,
get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant, ErrNotCallable, ErrorNotCommand, ReqPck, RequestPack
};
use crate::error::ProjectResult;
use crate::expr::{bot, ExprHandle, GenExpr};
use crate::system::{atom_info_for, SysCtx};
use crate::system::SysCtx;
pub struct OwnedVariant;
impl AtomicVariant for OwnedVariant {}
@@ -24,7 +23,7 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
fn _factory(self) -> AtomFactory {
AtomFactory::new(move |sys| {
let rec = OBJ_STORE.add(Box::new(self));
let mut data = atom_info_for(sys.dyn_card(), rec.atom_tid()).expect("obj exists").0.enc_vec();
let mut data = get_info::<A>(sys.dyn_card()).0.enc_vec();
rec.id().encode(&mut data);
rec.encode(&mut data);
LocalAtom { drop: true, data }
@@ -35,11 +34,15 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
}
fn with_atom<U>(mut b: &[u8], f: impl FnOnce(IdRecord<'_, Box<dyn DynOwnedAtom>>) -> U) -> U {
f(OBJ_STORE.get(NonZeroU64::decode(&mut b)).expect("Received invalid atom ID"))
let id = NonZeroU64::decode(&mut b);
f(OBJ_STORE.get(id).unwrap_or_else(|| panic!("Received invalid atom ID: {id}")))
}
pub struct OwnedAtomDynfo<T: OwnedAtom>(PhantomData<T>);
impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
fn print(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> String {
with_atom(buf, |a| a.dyn_print(ctx))
}
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(data, _): AtomCtx) -> Box<dyn Any> {
@@ -67,7 +70,7 @@ impl<T: OwnedAtom> AtomDynfo for OwnedAtomDynfo<T> {
pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone + 'static {
fn val(&self) -> Cow<'_, Self::Data>;
#[allow(unused_variables)]
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
fn call_ref(&self, arg: ExprHandle) -> GenExpr { bot(ErrNotCallable) }
fn call(self, arg: ExprHandle) -> GenExpr {
let ctx = arg.get_ctx();
let gcl = self.call_ref(arg);
@@ -87,6 +90,8 @@ pub trait OwnedAtom: Atomic<Variant = OwnedVariant> + Send + Sync + Any + Clone
fn command(self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> { Err(Arc::new(ErrorNotCommand)) }
#[allow(unused_variables)]
fn free(self, ctx: SysCtx) {}
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("OwnedAtom({})", type_name::<Self>()) }
}
pub trait DynOwnedAtom: Send + Sync + 'static {
fn atom_tid(&self) -> TypeId;
@@ -98,6 +103,7 @@ pub trait DynOwnedAtom: Send + Sync + 'static {
fn dyn_handle_req(&self, ctx: SysCtx, req: &mut dyn Read, rep: &mut dyn Write);
fn dyn_command(self: Box<Self>, ctx: SysCtx) -> ProjectResult<Option<GenExpr>>;
fn dyn_free(self: Box<Self>, ctx: SysCtx);
fn dyn_print(&self, ctx: SysCtx) -> String;
}
impl<T: OwnedAtom> DynOwnedAtom for T {
fn atom_tid(&self) -> TypeId { TypeId::of::<T>() }
@@ -123,6 +129,7 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
self.command(ctx)
}
fn dyn_free(self: Box<Self>, ctx: SysCtx) { self.free(ctx) }
fn dyn_print(&self, ctx: SysCtx) -> String { self.print(ctx) }
}
pub(crate) static OBJ_STORE: IdStore<Box<dyn DynOwnedAtom>> = IdStore::new();

View File

@@ -1,5 +1,4 @@
use std::any::{type_name, Any, TypeId};
use std::fmt;
use std::io::Write;
use std::marker::PhantomData;
use std::sync::Arc;
@@ -10,7 +9,7 @@ use orchid_api_traits::{Coding, Decode, Encode};
use crate::atom::{
get_info, AtomCard, AtomCtx, AtomDynfo, AtomFactory, Atomic, AtomicFeaturesImpl, AtomicVariant,
ErrorNotCallable, ReqPck, RequestPack,
ErrNotCallable, ReqPck, RequestPack,
};
use crate::error::ProjectResult;
use crate::expr::{bot, ExprHandle, GenExpr};
@@ -32,11 +31,10 @@ impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant
pub struct ThinAtomDynfo<T: ThinAtom>(PhantomData<T>);
impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn print(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> String { T::decode(&mut &buf[..]).print(ctx) }
fn tid(&self) -> TypeId { TypeId::of::<T>() }
fn name(&self) -> &'static str { type_name::<T>() }
fn decode(&self, AtomCtx(data, _): AtomCtx) -> Box<dyn Any> {
Box::new(T::decode(&mut &data[..]))
}
fn decode(&self, AtomCtx(buf, _): AtomCtx) -> Box<dyn Any> { Box::new(T::decode(&mut &buf[..])) }
fn call(&self, AtomCtx(buf, ctx): AtomCtx, arg: ExprTicket) -> GenExpr {
T::decode(&mut &buf[..]).call(ExprHandle::from_args(ctx, arg))
}
@@ -57,25 +55,24 @@ impl<T: ThinAtom> AtomDynfo for ThinAtomDynfo<T> {
fn command(&self, AtomCtx(buf, ctx): AtomCtx<'_>) -> ProjectResult<Option<GenExpr>> {
T::decode(&mut &buf[..]).command(ctx)
}
fn drop(&self, AtomCtx(buf, _): AtomCtx) {
eprintln!("Received drop signal for non-drop atom {:?}", T::decode(&mut &buf[..]))
fn drop(&self, AtomCtx(buf, ctx): AtomCtx) {
let string_self = T::decode(&mut &buf[..]).print(ctx);
eprintln!("Received drop signal for non-drop atom {string_self:?}")
}
}
pub trait ThinAtom: AtomCard<Data = Self> + Coding + fmt::Debug + Send + Sync + 'static {
pub trait ThinAtom: AtomCard<Data = Self> + Coding + Send + Sync + 'static {
#[allow(unused_variables)]
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrorNotCallable) }
fn call(&self, arg: ExprHandle) -> GenExpr { bot(ErrNotCallable) }
#[allow(unused_variables)]
fn same(&self, ctx: SysCtx, other: &Self) -> bool {
eprintln!(
"Override ThinAtom::same for {} if it can be generated during parsing",
type_name::<Self>()
);
let tname = type_name::<Self>();
eprintln!("Override ThinAtom::same for {tname} if it can be generated during parsing");
false
}
fn handle_req(&self, ctx: SysCtx, pck: impl ReqPck<Self>);
#[allow(unused_variables)]
fn command(&self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> {
Err(Arc::new(ErrorNotCallable))
}
fn command(&self, ctx: SysCtx) -> ProjectResult<Option<GenExpr>> { Err(Arc::new(ErrNotCallable)) }
#[allow(unused_variables)]
fn print(&self, ctx: SysCtx) -> String { format!("ThinAtom({})", type_name::<Self>()) }
}

View File

@@ -1,12 +1,13 @@
use std::io::Write;
use std::num::NonZero;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::{mem, thread};
use std::{mem, process, thread};
use hashbrown::HashMap;
use itertools::Itertools;
use orchid_api::atom::{
Atom, AtomDrop, AtomReq, AtomSame, CallRef, Command, FinalCall, Fwded, NextStep,
Atom, AtomDrop, AtomPrint, AtomReq, AtomSame, CallRef, Command, FinalCall, Fwded, NextStep
};
use orchid_api::interner::Sweep;
use orchid_api::parser::{CharFilter, LexExpr, LexedExpr, ParserReq};
@@ -18,6 +19,7 @@ use orchid_api_traits::{Decode, Encode};
use orchid_base::char_filter::{char_filter_match, char_filter_union, mk_char_filter};
use orchid_base::clone;
use orchid_base::interner::{deintern, init_replica, sweep_replica};
use orchid_base::logging::Logger;
use orchid_base::name::PathSlice;
use orchid_base::reqnot::{ReqNot, Requester};
@@ -31,8 +33,17 @@ use crate::system_ctor::{CtedObj, DynSystemCtor};
use crate::tree::{LazyMemberFactory, TIACtxImpl};
pub struct ExtensionData {
pub thread_name: &'static str,
pub systems: &'static [&'static dyn DynSystemCtor],
}
impl ExtensionData {
pub fn new(thread_name: &'static str, systems: &'static [&'static dyn DynSystemCtor]) -> Self {
Self { thread_name, systems }
}
pub fn main(self) {
extension_main(self)
}
}
pub enum MemberRecord {
Gen(LazyMemberFactory),
@@ -60,7 +71,13 @@ pub fn with_atom_record<T>(
}
pub fn extension_main(data: ExtensionData) {
HostHeader::decode(&mut &recv_parent_msg().unwrap()[..]);
if thread::Builder::new().name(data.thread_name.to_string()).spawn(|| extension_main_logic(data)).unwrap().join().is_err() {
process::exit(-1)
}
}
fn extension_main_logic(data: ExtensionData) {
let HostHeader{ log_strategy } = HostHeader::decode(&mut std::io::stdin().lock());
let mut buf = Vec::new();
let decls = (data.systems.iter().enumerate())
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
@@ -68,21 +85,26 @@ pub fn extension_main(data: ExtensionData) {
.collect_vec();
let systems = Arc::new(Mutex::new(HashMap::<SysId, SystemRecord>::new()));
ExtensionHeader { systems: decls.clone() }.encode(&mut buf);
send_parent_msg(&buf).unwrap();
std::io::stdout().write_all(&buf).unwrap();
std::io::stdout().flush().unwrap();
let exiting = Arc::new(AtomicBool::new(false));
let logger = Arc::new(Logger::new(log_strategy));
let rn = ReqNot::<ExtMsgSet>::new(
|a, _| send_parent_msg(a).unwrap(),
clone!(systems, exiting; move |n, reqnot| match n {
|a, _| {
eprintln!("Upsending {:?}", a);
send_parent_msg(a).unwrap()
},
clone!(systems, exiting, logger; move |n, reqnot| match n {
HostExtNotif::Exit => exiting.store(true, Ordering::Relaxed),
HostExtNotif::SystemDrop(SystemDrop(sys_id)) =>
mem::drop(systems.lock().unwrap().remove(&sys_id)),
HostExtNotif::AtomDrop(AtomDrop(atom)) => {
with_atom_record(&systems, &atom, |rec, cted, data| {
rec.drop(AtomCtx(data, SysCtx{ reqnot, id: atom.owner, cted }))
rec.drop(AtomCtx(data, SysCtx{ reqnot, logger: logger.clone(), id: atom.owner, cted }))
})
}
}),
clone!(systems; move |req| match req.req() {
clone!(systems, logger; move |req| match req.req() {
HostExtReq::Ping(ping@Ping) => req.handle(ping, &()),
HostExtReq::Sweep(sweep@Sweep) => req.handle(sweep, &sweep_replica()),
HostExtReq::NewSystem(new_sys) => {
@@ -90,7 +112,8 @@ pub fn extension_main(data: ExtensionData) {
let cted = data.systems[i].new_system(new_sys);
let mut vfses = HashMap::new();
let lex_filter = cted.inst().dyn_lexers().iter().fold(CharFilter(vec![]), |cf, lx| {
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
let lxcf = mk_char_filter(lx.char_filter().iter().cloned());
char_filter_union(&cf, &lxcf)
});
let mut lazy_mems = HashMap::new();
let const_root = (cted.inst().dyn_env().into_iter())
@@ -141,8 +164,8 @@ pub fn extension_main(data: ExtensionData) {
let tk = req.will_handle_as(lex);
thread::spawn(clone!(systems; move || {
let ctx = LexContext { sys, id, pos, reqnot: req.reqnot(), text: &text };
let first_char = text.chars().next().unwrap();
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), first_char)) {
let trigger_char = text.chars().nth(pos as usize).unwrap();
for lx in lexers.iter().filter(|l| char_filter_match(l.char_filter(), trigger_char)) {
match lx.lex(&text[pos as usize..], &ctx) {
Err(e) if e.as_any_ref().is::<NotApplicableLexerError>() => continue,
Err(e) if e.as_any_ref().is::<CascadingError>() => return req.handle_as(tk, &None),
@@ -155,6 +178,7 @@ pub fn extension_main(data: ExtensionData) {
}
}
}
eprintln!("Got notified about n/a character '{trigger_char}'");
req.handle_as(tk, &None)
}));
},
@@ -162,10 +186,16 @@ pub fn extension_main(data: ExtensionData) {
let systems_g = systems.lock().unwrap();
let atom = atom_req.get_atom();
let sys = &systems_g[&atom.owner];
let ctx = SysCtx { cted: sys.cted.clone(), id: atom.owner, reqnot: req.reqnot() };
let ctx = SysCtx {
cted: sys.cted.clone(),
id: atom.owner,
logger: logger.clone(),
reqnot: req.reqnot()
};
let dynfo = resolv_atom(&*sys.cted.inst(), atom);
let actx = AtomCtx(&atom.data[8..], ctx);
match atom_req {
AtomReq::AtomPrint(print@AtomPrint(_)) => req.handle(print, &dynfo.print(actx)),
AtomReq::AtomSame(same@AtomSame(_, r)) => {
// different systems or different type tags
if atom.owner != r.owner || atom.data[..8] != r.data[..8] {
@@ -195,6 +225,8 @@ pub fn extension_main(data: ExtensionData) {
);
init_replica(rn.clone().map());
while !exiting.load(Ordering::Relaxed) {
rn.receive(recv_parent_msg().unwrap())
let rcvd = recv_parent_msg().unwrap();
// eprintln!("Downsent {rcvd:?}");
rn.receive(rcvd)
}
}

View File

@@ -1,4 +1,5 @@
use std::any::TypeId;
use std::sync::Arc;
use hashbrown::HashMap;
use orchid_api::atom::Atom;
@@ -6,6 +7,7 @@ use orchid_api::proto::ExtMsgSet;
use orchid_api::system::SysId;
use orchid_api_traits::Decode;
use orchid_base::interner::Tok;
use orchid_base::logging::Logger;
use orchid_base::reqnot::ReqNot;
use crate::atom::{get_info, AtomCtx, AtomDynfo, AtomicFeatures, ForeignAtom, TypAtom};
@@ -106,4 +108,5 @@ pub struct SysCtx {
pub reqnot: ReqNot<ExtMsgSet>,
pub id: SysId,
pub cted: CtedObj,
pub logger: Arc<Logger>,
}

View File

@@ -47,7 +47,7 @@ pub fn ph(s: &str) -> OwnedPh {
if konst::string::starts_with(name, "_") {
panic!("Names starting with an underscore indicate a single-name scalar placeholder")
}
OwnedPh { name: intern(name), kind: PlaceholderKind::Vector { nonzero, priority } }
OwnedPh { name: intern(name), kind: PlaceholderKind::Vector { nz: nonzero, prio: priority } }
},
None => match konst::string::strip_prefix(s, "$_") {
Some(name) => OwnedPh { name: intern(name), kind: PlaceholderKind::Name },