forked from Orchid/orchid
New plans for macros
About to move them completely to stdlib
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
use never::Never;
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_extension::atom::{Atomic, ReqPck, TypAtom};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_extension::atom::{AtomFactory, Atomic, AtomicFeatures, ReqPck, ToAtom, TypAtom};
|
||||
use orchid_extension::atom_thin::{ThinAtom, ThinVariant};
|
||||
use orchid_extension::conv::{ToExpr, TryFromExpr};
|
||||
use orchid_extension::error::{pack_err, ProjectResult};
|
||||
use orchid_extension::expr::{ExprHandle, GenExpr};
|
||||
use orchid_extension::system::SysCtx;
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::expr::ExprHandle;
|
||||
use ordered_float::NotNan;
|
||||
|
||||
#[derive(Clone, Debug, Coding)]
|
||||
@@ -16,10 +15,10 @@ impl Atomic for Int {
|
||||
type Req = Never;
|
||||
}
|
||||
impl ThinAtom for Int {
|
||||
fn handle_req(&self, _ctx: SysCtx, pck: impl ReqPck<Self>) { pck.never() }
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
|
||||
}
|
||||
impl TryFromExpr for Int {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
|
||||
TypAtom::<Int>::try_from_expr(expr).map(|t| t.value)
|
||||
}
|
||||
}
|
||||
@@ -32,10 +31,10 @@ impl Atomic for Float {
|
||||
type Req = Never;
|
||||
}
|
||||
impl ThinAtom for Float {
|
||||
fn handle_req(&self, _ctx: SysCtx, pck: impl ReqPck<Self>) { pck.never() }
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
|
||||
}
|
||||
impl TryFromExpr for Float {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
|
||||
TypAtom::<Float>::try_from_expr(expr).map(|t| t.value)
|
||||
}
|
||||
}
|
||||
@@ -45,17 +44,17 @@ pub enum Numeric {
|
||||
Float(NotNan<f64>),
|
||||
}
|
||||
impl TryFromExpr for Numeric {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<Self> {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<Self> {
|
||||
Int::try_from_expr(expr.clone()).map(|t| Numeric::Int(t.0)).or_else(|e| {
|
||||
Float::try_from_expr(expr).map(|t| Numeric::Float(t.0)).map_err(|e2| pack_err([e, e2]))
|
||||
Float::try_from_expr(expr).map(|t| Numeric::Float(t.0)).map_err(|e2| [e, e2].concat())
|
||||
})
|
||||
}
|
||||
}
|
||||
impl ToExpr for Numeric {
|
||||
fn to_expr(self) -> GenExpr {
|
||||
impl ToAtom for Numeric {
|
||||
fn to_atom_factory(self) -> AtomFactory {
|
||||
match self {
|
||||
Self::Float(f) => Float(f).to_expr(),
|
||||
Self::Int(i) => Int(i).to_expr(),
|
||||
Self::Float(f) => Float(f).factory(),
|
||||
Self::Int(i) => Int(i).factory(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,27 @@
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::number::{parse_num, NumError, NumErrorKind, Numeric};
|
||||
use orchid_base::error::OrcRes;
|
||||
use orchid_base::number::{num_to_err, parse_num, Numeric};
|
||||
use orchid_extension::atom::AtomicFeatures;
|
||||
use orchid_extension::error::{ProjectError, ProjectResult};
|
||||
use orchid_extension::lexer::{LexContext, Lexer};
|
||||
use orchid_extension::tree::{GenTok, GenTokTree};
|
||||
use ordered_float::NotNan;
|
||||
|
||||
use super::num_atom::{Float, Int};
|
||||
|
||||
struct NumProjError(u32, NumError);
|
||||
impl ProjectError for NumProjError {
|
||||
const DESCRIPTION: &'static str = "Failed to parse number";
|
||||
fn message(&self) -> String {
|
||||
match self.1.kind {
|
||||
NumErrorKind::InvalidDigit => "This character is not meaningful in this base",
|
||||
NumErrorKind::NaN => "Number somehow evaluated to NaN",
|
||||
NumErrorKind::Overflow => "Number literal overflowed its enclosing type",
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
fn one_position(&self) -> Pos {
|
||||
Pos::Range(self.0 + self.1.range.start as u32..self.0 + self.1.range.end as u32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct NumLexer;
|
||||
impl Lexer for NumLexer {
|
||||
const CHAR_FILTER: &'static [RangeInclusive<char>] = &['0'..='9'];
|
||||
fn lex<'a>(all: &'a str, ctx: &'a LexContext<'a>) -> ProjectResult<(&'a str, GenTokTree)> {
|
||||
fn lex<'a>(all: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
|
||||
let ends_at = all.find(|c: char| !c.is_ascii_hexdigit() && !"xX._pP".contains(c));
|
||||
let (chars, tail) = all.split_at(ends_at.unwrap_or(all.len()));
|
||||
let fac = match parse_num(chars) {
|
||||
Ok(Numeric::Float(f)) => Float(f).factory(),
|
||||
Ok(Numeric::Uint(uint)) => Int(uint.try_into().unwrap()).factory(),
|
||||
Ok(Numeric::Decimal(dec)) => Float(NotNan::new(dec.try_into().unwrap()).unwrap()).factory(),
|
||||
Err(e) => return Err(NumProjError(ctx.pos(all), e).pack()),
|
||||
Err(e) => return Err(vec![num_to_err(e, ctx.pos(all))]),
|
||||
};
|
||||
Ok((tail, GenTok::Atom(fac).at(ctx.pos(all)..ctx.pos(tail))))
|
||||
Ok((tail, GenTok::X(fac).at(ctx.pos(all)..ctx.pos(tail))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ use std::sync::Arc;
|
||||
use orchid_base::interner::Tok;
|
||||
use orchid_extension::atom::{AtomDynfo, AtomicFeatures};
|
||||
use orchid_extension::fs::DeclFs;
|
||||
use orchid_extension::fun::Fun;
|
||||
use orchid_extension::system::{System, SystemCard};
|
||||
use orchid_extension::system_ctor::SystemCtor;
|
||||
use orchid_extension::tree::{cnst, module, root_mod, GenMemberKind};
|
||||
use orchid_extension::tree::{comments, fun, module, root_mod, GenMemberKind};
|
||||
|
||||
use crate::number::num_atom::{Float, Int};
|
||||
use crate::string::str_atom::{IntStrAtom, StrAtom};
|
||||
@@ -29,18 +28,14 @@ impl SystemCard for StdSystem {
|
||||
}
|
||||
impl System for StdSystem {
|
||||
fn lexers() -> Vec<orchid_extension::lexer::LexerObj> { vec![&StringLexer] }
|
||||
fn parsers() -> Vec<orchid_extension::parser::ParserObj> { vec![] }
|
||||
fn vfs() -> DeclFs { DeclFs::Mod(&[]) }
|
||||
fn env() -> Vec<(Tok<String>, GenMemberKind)> {
|
||||
vec![
|
||||
root_mod("std", [], [
|
||||
module(true, "string", [], [
|
||||
cnst(true, "concat", Fun::new(|left: OrcString| {
|
||||
Fun::new(move |right: OrcString| {
|
||||
StrAtom::new(Arc::new(left.get_string().to_string() + &right.get_string()))
|
||||
})
|
||||
}))
|
||||
]),
|
||||
])
|
||||
]
|
||||
vec![root_mod("std", [], [module(true, "string", [], [comments(
|
||||
["Concatenate two strings"],
|
||||
fun(true, "concat", |left: OrcString, right: OrcString| {
|
||||
StrAtom::new(Arc::new(left.get_string().to_string() + &right.get_string()))
|
||||
}),
|
||||
)])])]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
use std::num::NonZeroU64;
|
||||
use std::sync::Arc;
|
||||
|
||||
use never::Never;
|
||||
use orchid_api::interner::TStr;
|
||||
use orchid_api_derive::Coding;
|
||||
use orchid_api_traits::{Encode, Request};
|
||||
use orchid_base::error::{mk_err, OrcRes};
|
||||
use orchid_base::id_store::IdStore;
|
||||
use orchid_base::interner::{deintern, Tok};
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::intern;
|
||||
use orchid_base::interner::{deintern, intern, Tok};
|
||||
use orchid_extension::atom::{Atomic, ReqPck, TypAtom};
|
||||
use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
use orchid_extension::conv::TryFromExpr;
|
||||
use orchid_extension::error::{ProjectError, ProjectResult};
|
||||
use orchid_extension::expr::ExprHandle;
|
||||
use orchid_extension::system::SysCtx;
|
||||
|
||||
@@ -34,17 +34,22 @@ impl StrAtom {
|
||||
pub fn new(str: Arc<String>) -> Self { Self(STR_REPO.add(str).id()) }
|
||||
}
|
||||
impl Clone for StrAtom {
|
||||
fn clone(&self) -> Self { Self(STR_REPO.add(STR_REPO.get(self.0).unwrap().clone()).id()) }
|
||||
fn clone(&self) -> Self { Self::new(self.local_value()) }
|
||||
}
|
||||
impl StrAtom {
|
||||
fn try_local_value(&self) -> Option<Arc<String>> { STR_REPO.get(self.0).map(|r| r.clone()) }
|
||||
fn local_value(&self) -> Arc<String> { self.try_local_value().expect("no string found for ID") }
|
||||
}
|
||||
impl OwnedAtom for StrAtom {
|
||||
type Refs = ();
|
||||
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0) }
|
||||
fn same(&self, _ctx: SysCtx, other: &Self) -> bool { self.local_value() == other.local_value() }
|
||||
fn handle_req(&self, _ctx: SysCtx, pck: impl ReqPck<Self>) {
|
||||
self.local_value().encode(pck.unpack().1)
|
||||
fn same(&self, _: SysCtx, other: &Self) -> bool { self.local_value() == other.local_value() }
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>) { self.local_value().encode(pck.unpack().1) }
|
||||
fn serialize(&self, _: SysCtx, sink: &mut (impl io::Write + ?Sized)) -> Self::Refs {
|
||||
self.local_value().encode(sink)
|
||||
}
|
||||
fn deserialize(mut ctx: impl DeserializeCtx, _: Self::Refs) -> Self {
|
||||
Self::new(Arc::new(ctx.read::<String>()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,27 +57,30 @@ impl OwnedAtom for StrAtom {
|
||||
pub struct IntStrAtom(Tok<String>);
|
||||
impl Atomic for IntStrAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = TStr;
|
||||
type Data = orchid_api::TStr;
|
||||
type Req = Never;
|
||||
}
|
||||
impl From<Tok<String>> for IntStrAtom {
|
||||
fn from(value: Tok<String>) -> Self { Self(value) }
|
||||
}
|
||||
impl OwnedAtom for IntStrAtom {
|
||||
type Refs = ();
|
||||
fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(self.0.marker()) }
|
||||
fn handle_req(&self, _ctx: SysCtx, pck: impl ReqPck<Self>) { pck.never() }
|
||||
fn handle_req(&self, pck: impl ReqPck<Self>) { pck.never() }
|
||||
fn print(&self, _ctx: SysCtx) -> String { format!("{:?}i", self.0.as_str()) }
|
||||
fn serialize(&self, _: SysCtx, write: &mut (impl io::Write + ?Sized)) { self.0.encode(write) }
|
||||
fn deserialize(ctx: impl DeserializeCtx, _: ()) -> Self { Self(intern(&ctx.decode::<String>())) }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum OrcString {
|
||||
Val(TypAtom<StrAtom>),
|
||||
Int(Tok<String>),
|
||||
pub enum OrcString<'a> {
|
||||
Val(TypAtom<'a, StrAtom>),
|
||||
Int(TypAtom<'a, IntStrAtom>),
|
||||
}
|
||||
impl OrcString {
|
||||
impl<'a> OrcString<'a> {
|
||||
pub fn get_string(&self) -> Arc<String> {
|
||||
match &self {
|
||||
Self::Int(tok) => tok.arc(),
|
||||
Self::Int(tok) => deintern(tok.value).arc(),
|
||||
Self::Val(atom) => match STR_REPO.get(**atom) {
|
||||
Some(rec) => rec.clone(),
|
||||
None => Arc::new(atom.request(StringGetVal)),
|
||||
@@ -80,23 +88,15 @@ impl OrcString {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<Tok<String>> for OrcString {
|
||||
fn from(value: Tok<String>) -> Self { OrcString::Int(value) }
|
||||
}
|
||||
|
||||
pub struct NotString(Pos);
|
||||
impl ProjectError for NotString {
|
||||
const DESCRIPTION: &'static str = "A string was expected";
|
||||
fn one_position(&self) -> Pos { self.0.clone() }
|
||||
}
|
||||
impl TryFromExpr for OrcString {
|
||||
fn try_from_expr(expr: ExprHandle) -> ProjectResult<OrcString> {
|
||||
impl TryFromExpr for OrcString<'static> {
|
||||
fn try_from_expr(expr: ExprHandle) -> OrcRes<OrcString<'static>> {
|
||||
if let Ok(v) = TypAtom::<StrAtom>::downcast(expr.clone()) {
|
||||
return Ok(OrcString::Val(v));
|
||||
}
|
||||
match TypAtom::<IntStrAtom>::downcast(expr) {
|
||||
Ok(t) => Ok(OrcString::Int(deintern(*t))),
|
||||
Err(e) => Err(NotString(e.0).pack()),
|
||||
Ok(t) => Ok(OrcString::Int(t)),
|
||||
Err(e) => Err(vec![mk_err(intern!(str: "A string was expected"), "", [e.0.clone().into()])]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use orchid_base::intern;
|
||||
use itertools::Itertools;
|
||||
use orchid_base::error::{mk_err, OrcErr, OrcRes};
|
||||
use orchid_base::interner::intern;
|
||||
use orchid_base::location::Pos;
|
||||
use orchid_base::vname;
|
||||
use orchid_base::tree::{vname_tv, wrap_tokv};
|
||||
use orchid_base::{intern, vname};
|
||||
use orchid_extension::atom::AtomicFeatures;
|
||||
use orchid_extension::error::{ErrorSansOrigin, ProjectError, ProjectErrorObj, ProjectResult};
|
||||
use orchid_extension::lexer::{LexContext, Lexer, NotApplicableLexerError};
|
||||
use orchid_extension::tree::{wrap_tokv, GenTok, GenTokTree};
|
||||
use orchid_extension::lexer::{err_lexer_na, LexContext, Lexer};
|
||||
use orchid_extension::tree::{GenTok, GenTokTree};
|
||||
|
||||
use super::str_atom::IntStrAtom;
|
||||
|
||||
@@ -30,34 +30,19 @@ struct StringError {
|
||||
kind: StringErrorKind,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct NotHex;
|
||||
impl ErrorSansOrigin for NotHex {
|
||||
const DESCRIPTION: &'static str = "Expected a hex digit";
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BadCodePoint;
|
||||
impl ErrorSansOrigin for BadCodePoint {
|
||||
const DESCRIPTION: &'static str = "The specified number is not a Unicode code point";
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct BadEscapeSequence;
|
||||
impl ErrorSansOrigin for BadEscapeSequence {
|
||||
const DESCRIPTION: &'static str = "Unrecognized escape sequence";
|
||||
}
|
||||
|
||||
impl StringError {
|
||||
/// Convert into project error for reporting
|
||||
pub fn into_proj(self, pos: u32) -> ProjectErrorObj {
|
||||
pub fn into_proj(self, pos: u32) -> OrcErr {
|
||||
let start = pos + self.pos;
|
||||
let pos = Pos::Range(start..start + 1);
|
||||
match self.kind {
|
||||
StringErrorKind::NotHex => NotHex.bundle(&pos),
|
||||
StringErrorKind::BadCodePoint => BadCodePoint.bundle(&pos),
|
||||
StringErrorKind::BadEscSeq => BadEscapeSequence.bundle(&pos),
|
||||
}
|
||||
mk_err(
|
||||
intern!(str: "Failed to parse string"),
|
||||
match self.kind {
|
||||
StringErrorKind::NotHex => "Expected a hex digit",
|
||||
StringErrorKind::BadCodePoint => "The specified number is not a Unicode code point",
|
||||
StringErrorKind::BadEscSeq => "Unrecognized escape sequence",
|
||||
},
|
||||
[Pos::Range(start..start + 1).into()],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,32 +91,24 @@ fn parse_string(str: &str) -> Result<String, StringError> {
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct NoStringEnd;
|
||||
impl ErrorSansOrigin for NoStringEnd {
|
||||
const DESCRIPTION: &'static str = "String never terminated with \"";
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct StringLexer;
|
||||
impl Lexer for StringLexer {
|
||||
const CHAR_FILTER: &'static [std::ops::RangeInclusive<char>] = &['"'..='"'];
|
||||
fn lex<'a>(
|
||||
all: &'a str,
|
||||
ctx: &'a LexContext<'a>,
|
||||
) -> ProjectResult<(&'a str, GenTokTree)> {
|
||||
let mut tail = all.strip_prefix('"').ok_or_else(|| NotApplicableLexerError.pack())?;
|
||||
let mut parts = vec![];
|
||||
fn lex<'a>(all: &'a str, ctx: &'a LexContext<'a>) -> OrcRes<(&'a str, GenTokTree<'a>)> {
|
||||
let mut tail = all.strip_prefix('"').ok_or_else(err_lexer_na)?;
|
||||
let mut parts = Vec::<GenTokTree<'a>>::new();
|
||||
let mut cur = String::new();
|
||||
let mut errors = vec![];
|
||||
let commit_str = |str: &mut String, tail: &str, err: &mut Vec<ProjectErrorObj>, parts: &mut Vec<GenTokTree>| {
|
||||
let str_val = parse_string(str)
|
||||
.inspect_err(|e| err.push(e.clone().into_proj(ctx.pos(tail) - str.len() as u32)))
|
||||
.unwrap_or_default();
|
||||
let tok = GenTok::Atom(IntStrAtom::from(intern(&*str_val)).factory());
|
||||
parts.push(tok.at(ctx.tok_ran(str.len() as u32, tail)));
|
||||
*str = String::new();
|
||||
};
|
||||
let commit_str =
|
||||
|str: &mut String, tail: &str, err: &mut Vec<OrcErr>, parts: &mut Vec<GenTokTree<'a>>| {
|
||||
let str_val = parse_string(str)
|
||||
.inspect_err(|e| err.push(e.clone().into_proj(ctx.pos(tail) - str.len() as u32)))
|
||||
.unwrap_or_default();
|
||||
let tok = GenTok::X(IntStrAtom::from(intern(&*str_val)).factory());
|
||||
parts.push(tok.at(ctx.tok_ran(str.len() as u32, tail)));
|
||||
*str = String::new();
|
||||
};
|
||||
loop {
|
||||
if let Some(rest) = tail.strip_prefix('"') {
|
||||
commit_str(&mut cur, tail, &mut errors, &mut parts);
|
||||
@@ -139,8 +116,7 @@ impl Lexer for StringLexer {
|
||||
} else if let Some(rest) = tail.strip_prefix('$') {
|
||||
commit_str(&mut cur, tail, &mut errors, &mut parts);
|
||||
parts.push(GenTok::Name(intern!(str: "++")).at(ctx.tok_ran(1, rest)));
|
||||
parts.extend(GenTok::vname(&vname!(std::string::convert))
|
||||
.map(|t| t.at(ctx.tok_ran(1, rest))));
|
||||
parts.extend(vname_tv(&vname!(std::string::convert), ctx.tok_ran(1, rest)));
|
||||
let (new_tail, tree) = ctx.recurse(rest)?;
|
||||
tail = new_tail;
|
||||
parts.push(tree);
|
||||
@@ -156,7 +132,11 @@ impl Lexer for StringLexer {
|
||||
} else {
|
||||
let range = ctx.pos(all)..ctx.pos("");
|
||||
commit_str(&mut cur, tail, &mut errors, &mut parts);
|
||||
return Err(NoStringEnd.bundle(&Pos::Range(range.clone())));
|
||||
return Err(vec![mk_err(
|
||||
intern!(str: "No string end"),
|
||||
"String never terminated with \"",
|
||||
[Pos::Range(range.clone()).into()],
|
||||
)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user