This commit is contained in:
2024-07-18 16:07:36 +02:00
parent 949b3758fd
commit cc3699bbe7
31 changed files with 1021 additions and 312 deletions

View File

@@ -1,4 +1,5 @@
use std::io::Write as _;
use std::ops::Deref;
use std::sync::atomic::{AtomicU16, AtomicU32, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Arc, Mutex, RwLock, Weak};
@@ -12,16 +13,16 @@ use orchid_api::atom::{Atom, AtomDrop, AtomSame, CallRef, FinalCall, Fwd, Fwded}
use orchid_api::error::{ErrNotif, ProjErrOrRef, ProjResult, ReportError};
use orchid_api::expr::{Acquire, Expr, ExprNotif, ExprTicket, Release, Relocate};
use orchid_api::interner::IntReq;
use orchid_api::parser::CharFilter;
use orchid_api::parser::{CharFilter, Lexed, SubLexed};
use orchid_api::proto::{
ExtHostNotif, ExtHostReq, ExtensionHeader, HostExtNotif, HostExtReq, HostHeader, HostMsgSet
ExtHostNotif, ExtHostReq, ExtensionHeader, HostExtNotif, HostHeader, HostMsgSet,
};
use orchid_api::system::{NewSystem, SysDeclId, SysId, SystemDecl, SystemDrop};
use orchid_api::tree::{GetConstTree, Tree, TreeId};
use orchid_api_traits::{Coding, Decode, Encode, Request};
use orchid_api_traits::{Coding, Decode, Encode};
use orchid_base::char_filter::char_filter_match;
use orchid_base::clone;
use orchid_base::interner::{deintern, intern};
use orchid_base::interner::{deintern, intern, Tok};
use orchid_base::reqnot::{ReqNot, Requester as _};
use ordered_float::NotNan;
@@ -230,24 +231,28 @@ impl System {
pub fn const_tree(&self) -> Tree {
self.0.ext.0.reqnot.request(GetConstTree(self.0.id, self.0.const_root_id))
}
pub fn request<R: Coding>(&self, req: impl Request<Response = ProjResult<R>> + Into<HostExtReq>) -> ProjResult<R> {
pub fn catch_err<R: Coding>(&self, cb: impl FnOnce() -> ProjResult<R>) -> ProjResult<R> {
let mut errors = Vec::new();
if let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() {
eprintln!("Errors left in queue");
errors.push(err);
}
let value = self.0.ext.0.reqnot.request(req).inspect_err(|e| errors.extend(e.iter().cloned()));
let value = cb().inspect_err(|e| errors.extend(e.iter().cloned()));
while let Ok(err) = self.0.err_rec.lock().unwrap().try_recv() {
errors.push(err);
}
if !errors.is_empty() {
Err(errors)
} else {
value
}
if !errors.is_empty() { Err(errors) } else { value }
}
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) }
pub fn lex(
&self,
source: Tok<String>,
pos: usize,
r: impl FnMut(usize) -> ProjResult<SubLexed>,
) -> ProjResult<Lexed> {
todo!()
}
}
impl fmt::Debug for System {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -263,3 +268,7 @@ impl fmt::Debug for System {
}
}
}
impl Deref for System {
type Target = SystemInstData;
fn deref(&self) -> &Self::Target { self.0.as_ref() }
}

118
orchid-host/src/lex.rs Normal file
View File

@@ -0,0 +1,118 @@
use orchid_api::tree::Paren;
use orchid_base::intern;
use orchid_base::interner::Tok;
use orchid_base::location::Pos;
use orchid_base::number::parse_num;
use crate::extension::System;
use crate::results::{mk_err, num_to_err, OwnedResult};
use crate::tree::{OwnedTok, OwnedTokTree};
pub struct LexCtx<'a> {
pub systems: &'a [System],
pub source: Tok<String>,
pub src: &'a str,
}
impl<'a> LexCtx<'a> {
pub fn get_pos(&self) -> u32 { self.source.len() as u32 - self.src.len() as u32 }
pub fn strip_prefix(&mut self, tgt: &str) -> bool {
if let Some(src) = self.src.strip_prefix(tgt) {
self.src = src;
return true;
}
false
}
pub fn strip_char(&mut self, tgt: char) -> bool {
if let Some(src) = self.src.strip_prefix(tgt) {
self.src = src;
return true;
}
false
}
pub fn trim(&mut self, filter: impl Fn(char) -> bool) {
self.src = self.src.trim_start_matches(filter);
}
pub fn trim_ws(&mut self, br: bool) {
self.trim(|c| c.is_whitespace() && br || !"\r\n".contains(c))
}
pub fn get_start_matches(&mut self, filter: impl Fn(char) -> bool) -> &'a str {
let rest = self.src.trim_start_matches(filter);
let matches = &self.src[..self.src.len() - rest.len()];
self.src = rest;
matches
}
}
const PARENS: &[(char, char, Paren)] =
&[('(', ')', Paren::Round), ('[', ']', Paren::Square), ('{', '}', Paren::Curly)];
pub fn lex_tok(ctx: &mut LexCtx, br: bool) -> OwnedResult<OwnedTokTree> {
assert!(
!ctx.src.is_empty() && !ctx.src.starts_with(char::is_whitespace),
"Lexing empty string or whitespace to token! Invocations of lex_tok should check for empty string"
);
for (open, close, paren) in PARENS {
let paren_pos = ctx.get_pos();
if ctx.strip_char(*open) {
let mut body = Vec::new();
return loop {
ctx.trim_ws(true);
if ctx.strip_char(*close) {
break Ok(OwnedTokTree {
tok: OwnedTok::S(paren.clone(), body),
range: paren_pos..ctx.get_pos(),
});
} else if ctx.src.is_empty() {
return Err(vec![mk_err(
intern!(str: "unclosed paren"),
format!("this {open} has no matching {close}"),
[Pos::Range(paren_pos..paren_pos + 1).into()],
)]);
}
body.push(lex_tok(ctx, true)?);
};
}
}
if ctx.strip_char('\\') {
let bs_pos = ctx.get_pos() - 1;
let mut arg = Vec::new();
loop {
ctx.trim_ws(true);
if ctx.strip_char('.') {
break;
} else if ctx.src.is_empty() {
return Err(vec![mk_err(
intern!(str: "Unclosed lambda"),
"Lambdae started with \\ should separate arguments from body with .",
[Pos::Range(bs_pos..bs_pos + 1).into()],
)]);
}
arg.push(lex_tok(ctx, true)?);
}
let mut body = Vec::new();
return loop {
ctx.trim_ws(br);
let pos_before_end = ctx.get_pos();
if !br && ctx.strip_char('\n')
|| PARENS.iter().any(|(_, e, _)| ctx.strip_char(*e))
|| ctx.src.is_empty()
{
break Ok(OwnedTokTree { tok: OwnedTok::Lambda(arg, body), range: bs_pos..pos_before_end });
}
body.push(lex_tok(ctx, br)?);
};
}
if ctx.src.starts_with(char::is_numeric) {
let num_pos = ctx.get_pos();
let num_str = ctx.get_start_matches(|c| c.is_alphanumeric() || "._".contains(c));
return Ok(OwnedTokTree {
range: num_pos..ctx.get_pos(),
tok: match parse_num(num_str) {
Err(e) => OwnedTok::Bottom(num_to_err(e, num_pos)),
Ok(v) => todo!(),
},
});
}
for sys in ctx.systems {}
todo!()
}

View File

@@ -1,3 +1,6 @@
pub mod child;
pub mod expr;
pub mod extension;
pub mod lex;
pub mod results;
pub mod tree;

View File

@@ -0,0 +1,36 @@
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()],
}
}

24
orchid-host/src/tree.rs Normal file
View File

@@ -0,0 +1,24 @@
use std::ops::Range;
use orchid_api::tree::Paren;
use orchid_base::error::OwnedError;
use orchid_base::name::VName;
use orchid_base::tokens::OwnedPh;
use crate::extension::AtomHand;
#[derive(Clone)]
pub struct OwnedTokTree {
pub tok: OwnedTok,
pub range: Range<u32>,
}
#[derive(Clone)]
pub enum OwnedTok {
Lambda(Vec<OwnedTokTree>, Vec<OwnedTokTree>),
Name(VName),
S(Paren, Vec<OwnedTokTree>),
Atom(AtomHand),
Ph(OwnedPh),
Bottom(OwnedError),
}