forked from Orchid/orchid
Compare commits
1 Commits
ctx-refact
...
ipc-refact
| Author | SHA1 | Date | |
|---|---|---|---|
| 7971a2b4eb |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -969,6 +969,7 @@ name = "orchid-api"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
|
"itertools",
|
||||||
"orchid-api-derive",
|
"orchid-api-derive",
|
||||||
"orchid-api-traits",
|
"orchid-api-traits",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
@@ -1113,6 +1114,7 @@ dependencies = [
|
|||||||
"ctrlc",
|
"ctrlc",
|
||||||
"futures",
|
"futures",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"orchid-api",
|
||||||
"orchid-base",
|
"orchid-base",
|
||||||
"orchid-host",
|
"orchid-host",
|
||||||
"substack",
|
"substack",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ ordered-float = "5.0.0"
|
|||||||
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
orchid-api-traits = { version = "0.1.0", path = "../orchid-api-traits" }
|
||||||
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
orchid-api-derive = { version = "0.1.0", path = "../orchid-api-derive" }
|
||||||
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
futures = { version = "0.3.31", features = ["std"], default-features = false }
|
||||||
|
itertools = "0.14.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test_executors = "0.3.2"
|
test_executors = "0.3.2"
|
||||||
|
|||||||
@@ -1,14 +1,28 @@
|
|||||||
|
use std::fmt;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ExprTicket, Expression, ExtHostReq, FormattingUnit, HostExtNotif, HostExtReq, OrcResult, SysId,
|
ExprTicket, Expression, ExtHostReq, FormattingUnit, HostExtReq, OrcResult, SysId, TStrv,
|
||||||
TVec,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type AtomData = Vec<u8>;
|
#[derive(Clone, Coding)]
|
||||||
|
pub struct AtomData(pub Vec<u8>);
|
||||||
|
impl fmt::Debug for AtomData {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let mut byte_strings = self.0.iter().map(|b| format!("{b:02x}"));
|
||||||
|
if self.0.len() < 32 {
|
||||||
|
write!(f, "AtomData({})", byte_strings.join(" "))
|
||||||
|
} else {
|
||||||
|
let data_table =
|
||||||
|
byte_strings.chunks(32).into_iter().map(|mut chunk| chunk.join(" ")).join("\n");
|
||||||
|
write!(f, "AtomData(\n{}\n)", data_table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Unique ID associated with atoms that have an identity
|
/// Unique ID associated with atoms that have an identity
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
@@ -16,7 +30,7 @@ pub struct AtomId(pub NonZeroU64);
|
|||||||
|
|
||||||
/// An atom owned by an implied system. Usually used in responses from a system.
|
/// An atom owned by an implied system. Usually used in responses from a system.
|
||||||
/// This has the same semantics as [Atom] except in that the owner is implied.
|
/// This has the same semantics as [Atom] except in that the owner is implied.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct LocalAtom {
|
pub struct LocalAtom {
|
||||||
pub drop: Option<AtomId>,
|
pub drop: Option<AtomId>,
|
||||||
pub data: AtomData,
|
pub data: AtomData,
|
||||||
@@ -27,7 +41,7 @@ impl LocalAtom {
|
|||||||
|
|
||||||
/// An atom representation that can be serialized and sent around. Atoms
|
/// An atom representation that can be serialized and sent around. Atoms
|
||||||
/// represent the smallest increment of work.
|
/// represent the smallest increment of work.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct Atom {
|
pub struct Atom {
|
||||||
/// Instance ID of the system that created the atom
|
/// Instance ID of the system that created the atom
|
||||||
pub owner: SysId,
|
pub owner: SysId,
|
||||||
@@ -49,7 +63,7 @@ pub struct Atom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to apply an atom as a function to an expression
|
/// Attempt to apply an atom as a function to an expression
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct CallRef(pub Atom, pub ExprTicket);
|
pub struct CallRef(pub Atom, pub ExprTicket);
|
||||||
impl Request for CallRef {
|
impl Request for CallRef {
|
||||||
@@ -59,14 +73,14 @@ impl Request for CallRef {
|
|||||||
/// Attempt to apply an atom as a function, consuming the atom and enabling the
|
/// Attempt to apply an atom as a function, consuming the atom and enabling the
|
||||||
/// library to reuse its datastructures rather than duplicating them. This is an
|
/// library to reuse its datastructures rather than duplicating them. This is an
|
||||||
/// optimization over [CallRef] followed by [AtomDrop].
|
/// optimization over [CallRef] followed by [AtomDrop].
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct FinalCall(pub Atom, pub ExprTicket);
|
pub struct FinalCall(pub Atom, pub ExprTicket);
|
||||||
impl Request for FinalCall {
|
impl Request for FinalCall {
|
||||||
type Response = Expression;
|
type Response = Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct SerializeAtom(pub Atom);
|
pub struct SerializeAtom(pub Atom);
|
||||||
impl Request for SerializeAtom {
|
impl Request for SerializeAtom {
|
||||||
@@ -81,16 +95,16 @@ impl Request for DeserAtom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A request blindly routed to the system that provides an atom.
|
/// A request blindly routed to the system that provides an atom.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct Fwded(pub Atom, pub TVec, pub Vec<u8>);
|
pub struct Fwded(pub Atom, pub TStrv, pub Vec<u8>);
|
||||||
impl Request for Fwded {
|
impl Request for Fwded {
|
||||||
type Response = Option<Vec<u8>>;
|
type Response = Option<Vec<u8>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(ExtHostReq)]
|
#[extends(ExtHostReq)]
|
||||||
pub struct Fwd(pub Atom, pub TVec, pub Vec<u8>);
|
pub struct Fwd(pub Atom, pub TStrv, pub Vec<u8>);
|
||||||
impl Request for Fwd {
|
impl Request for Fwd {
|
||||||
type Response = Option<Vec<u8>>;
|
type Response = Option<Vec<u8>>;
|
||||||
}
|
}
|
||||||
@@ -100,7 +114,7 @@ pub enum NextStep {
|
|||||||
Continue(Expression),
|
Continue(Expression),
|
||||||
Halt,
|
Halt,
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct Command(pub Atom);
|
pub struct Command(pub Atom);
|
||||||
impl Request for Command {
|
impl Request for Command {
|
||||||
@@ -111,17 +125,20 @@ impl Request for Command {
|
|||||||
/// isn't referenced anywhere. This should have no effect if the atom's `drop`
|
/// isn't referenced anywhere. This should have no effect if the atom's `drop`
|
||||||
/// flag is false.
|
/// flag is false.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
||||||
#[extends(HostExtNotif)]
|
#[extends(HostExtReq)]
|
||||||
pub struct AtomDrop(pub SysId, pub AtomId);
|
pub struct AtomDrop(pub SysId, pub AtomId);
|
||||||
|
impl Request for AtomDrop {
|
||||||
|
type Response = ();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(AtomReq, HostExtReq)]
|
#[extends(AtomReq, HostExtReq)]
|
||||||
pub struct AtomPrint(pub Atom);
|
pub struct AtomPrint(pub Atom);
|
||||||
impl Request for AtomPrint {
|
impl Request for AtomPrint {
|
||||||
type Response = FormattingUnit;
|
type Response = FormattingUnit;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(ExtHostReq)]
|
#[extends(ExtHostReq)]
|
||||||
pub struct ExtAtomPrint(pub Atom);
|
pub struct ExtAtomPrint(pub Atom);
|
||||||
impl Request for ExtAtomPrint {
|
impl Request for ExtAtomPrint {
|
||||||
@@ -129,7 +146,7 @@ impl Request for ExtAtomPrint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Requests that apply to an existing atom instance
|
/// Requests that apply to an existing atom instance
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(HostExtReq)]
|
#[extends(HostExtReq)]
|
||||||
#[extendable]
|
#[extendable]
|
||||||
pub enum AtomReq {
|
pub enum AtomReq {
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
|
use std::fmt;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
|
|
||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
use crate::{Atom, ExtHostNotif, ExtHostReq, Location, OrcError, SysId, TVec};
|
use crate::{Atom, ExtHostNotif, ExtHostReq, Location, OrcError, SysId, TStrv};
|
||||||
|
|
||||||
/// An arbitrary ID associated with an expression on the host side. Incoming
|
/// An arbitrary ID associated with an expression on the host side. Incoming
|
||||||
/// tickets always come with some lifetime guarantee, which can be extended with
|
/// tickets always come with some lifetime guarantee, which can be extended with
|
||||||
/// [Acquire].
|
/// [Acquire].
|
||||||
///
|
///
|
||||||
/// The ID is globally unique within its lifetime, but may be reused.
|
/// The ID is globally unique within its lifetime, but may be reused.
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
pub struct ExprTicket(pub NonZeroU64);
|
pub struct ExprTicket(pub NonZeroU64);
|
||||||
|
impl fmt::Debug for ExprTicket {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "ExprTicket({:x})", self.0.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Acquire a strong reference to an expression. This keeps it alive until a
|
/// Acquire a strong reference to an expression. This keeps it alive until a
|
||||||
/// corresponding [Release] is emitted. The number of times a system has
|
/// corresponding [Release] is emitted. The number of times a system has
|
||||||
@@ -62,7 +68,7 @@ pub enum ExpressionKind {
|
|||||||
Arg(u64),
|
Arg(u64),
|
||||||
/// Insert the specified host-expression in the template here. When the clause
|
/// Insert the specified host-expression in the template here. When the clause
|
||||||
/// is used in the const tree, this variant is forbidden.
|
/// is used in the const tree, this variant is forbidden.
|
||||||
Slot(ExprTicket),
|
Slot { tk: ExprTicket, by_value: bool },
|
||||||
/// The lhs must be fully processed before the rhs can be processed.
|
/// The lhs must be fully processed before the rhs can be processed.
|
||||||
/// Equivalent to Haskell's function of the same name
|
/// Equivalent to Haskell's function of the same name
|
||||||
Seq(Box<Expression>, Box<Expression>),
|
Seq(Box<Expression>, Box<Expression>),
|
||||||
@@ -72,7 +78,7 @@ pub enum ExpressionKind {
|
|||||||
/// Because the atom is newly constructed, it also must belong to this system.
|
/// Because the atom is newly constructed, it also must belong to this system.
|
||||||
NewAtom(Atom),
|
NewAtom(Atom),
|
||||||
/// A reference to a constant
|
/// A reference to a constant
|
||||||
Const(TVec),
|
Const(TStrv),
|
||||||
/// A static runtime error.
|
/// A static runtime error.
|
||||||
Bottom(Vec<OrcError>),
|
Bottom(Vec<OrcError>),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ impl Request for ExternStr {
|
|||||||
#[extends(IntReq, ExtHostReq)]
|
#[extends(IntReq, ExtHostReq)]
|
||||||
pub struct InternStrv(pub Vec<TStr>);
|
pub struct InternStrv(pub Vec<TStr>);
|
||||||
impl Request for InternStrv {
|
impl Request for InternStrv {
|
||||||
type Response = TVec;
|
type Response = TStrv;
|
||||||
}
|
}
|
||||||
/// replica -> master to find the vector of interned strings corresponding to a
|
/// replica -> master to find the vector of interned strings corresponding to a
|
||||||
/// token
|
/// token
|
||||||
@@ -57,7 +57,7 @@ impl Request for InternStrv {
|
|||||||
/// See [IntReq]
|
/// See [IntReq]
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(IntReq, ExtHostReq)]
|
#[extends(IntReq, ExtHostReq)]
|
||||||
pub struct ExternStrv(pub TVec);
|
pub struct ExternStrv(pub TStrv);
|
||||||
impl Request for ExternStrv {
|
impl Request for ExternStrv {
|
||||||
type Response = Vec<TStr>;
|
type Response = Vec<TStr>;
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ pub struct TStr(pub NonZeroU64);
|
|||||||
|
|
||||||
/// A substitute for an interned string sequence in serialized datastructures.
|
/// A substitute for an interned string sequence in serialized datastructures.
|
||||||
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
pub struct TVec(pub NonZeroU64);
|
pub struct TStrv(pub NonZeroU64);
|
||||||
|
|
||||||
/// A request to sweep the replica. The master will not be sweeped until all
|
/// A request to sweep the replica. The master will not be sweeped until all
|
||||||
/// replicas respond, as it must retain everything the replicas retained
|
/// replicas respond, as it must retain everything the replicas retained
|
||||||
@@ -84,5 +84,5 @@ impl Request for Sweep {
|
|||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct Retained {
|
pub struct Retained {
|
||||||
pub strings: Vec<TStr>,
|
pub strings: Vec<TStr>,
|
||||||
pub vecs: Vec<TVec>,
|
pub vecs: Vec<TStrv>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::ops::RangeInclusive;
|
|||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
use crate::{ExtHostReq, HostExtReq, OrcResult, ParsId, SysId, TStr, TVec, TokenTree};
|
use crate::{ExtHostReq, HostExtReq, OrcResult, ParsId, SysId, TStr, TStrv, TokenTree};
|
||||||
|
|
||||||
/// - All ranges contain at least one character
|
/// - All ranges contain at least one character
|
||||||
/// - All ranges are in increasing characeter order
|
/// - All ranges are in increasing characeter order
|
||||||
@@ -19,7 +19,7 @@ pub struct LexExpr {
|
|||||||
pub text: TStr,
|
pub text: TStr,
|
||||||
pub pos: u32,
|
pub pos: u32,
|
||||||
/// Source root module path
|
/// Source root module path
|
||||||
pub src: TVec,
|
pub src: TStrv,
|
||||||
}
|
}
|
||||||
impl Request for LexExpr {
|
impl Request for LexExpr {
|
||||||
type Response = Option<OrcResult<LexedExpr>>;
|
type Response = Option<OrcResult<LexedExpr>>;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
|
|
||||||
use crate::{TStr, TVec};
|
use crate::{TStr, TStrv};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub enum Location {
|
pub enum Location {
|
||||||
@@ -21,12 +21,12 @@ pub enum Location {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct SourceRange {
|
pub struct SourceRange {
|
||||||
pub path: TVec,
|
pub path: TStrv,
|
||||||
pub range: Range<u32>,
|
pub range: Range<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding)]
|
#[derive(Clone, Debug, Coding)]
|
||||||
pub struct CodeGenInfo {
|
pub struct CodeGenInfo {
|
||||||
pub generator: TVec,
|
pub generator: TStrv,
|
||||||
pub details: TStr,
|
pub details: TStr,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy};
|
|||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Expression, ExtHostReq, HostExtReq, OrcResult, SourceRange, SysId, TStr, TVec, TokenTree,
|
Expression, ExtHostReq, HostExtReq, OrcResult, SourceRange, SysId, TStr, TStrv, TokenTree,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
@@ -24,10 +24,10 @@ pub struct ParsedConstId(pub NonZeroU64);
|
|||||||
pub struct ParseLine {
|
pub struct ParseLine {
|
||||||
pub sys: SysId,
|
pub sys: SysId,
|
||||||
/// The immediately enclosing module path
|
/// The immediately enclosing module path
|
||||||
pub module: TVec,
|
pub module: TStrv,
|
||||||
/// The root module path for the snipppet of source code, prefix of
|
/// The root module path for the snipppet of source code, prefix of
|
||||||
/// [ParseLine#module]
|
/// [ParseLine#module]
|
||||||
pub src: TVec,
|
pub src: TStrv,
|
||||||
pub comments: Vec<Comment>,
|
pub comments: Vec<Comment>,
|
||||||
pub exported: bool,
|
pub exported: bool,
|
||||||
pub idx: u16,
|
pub idx: u16,
|
||||||
@@ -68,10 +68,7 @@ pub enum ParsedMemberKind {
|
|||||||
/// the macro engine could run here.
|
/// the macro engine could run here.
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(HostExtReq)]
|
#[extends(HostExtReq)]
|
||||||
pub struct FetchParsedConst {
|
pub struct FetchParsedConst(pub SysId, pub ParsedConstId);
|
||||||
pub sys: SysId,
|
|
||||||
pub id: ParsedConstId,
|
|
||||||
}
|
|
||||||
impl Request for FetchParsedConst {
|
impl Request for FetchParsedConst {
|
||||||
type Response = Expression;
|
type Response = Expression;
|
||||||
}
|
}
|
||||||
@@ -97,9 +94,9 @@ pub struct Comment {
|
|||||||
pub struct ResolveNames {
|
pub struct ResolveNames {
|
||||||
pub sys: SysId,
|
pub sys: SysId,
|
||||||
pub constid: ParsedConstId,
|
pub constid: ParsedConstId,
|
||||||
pub names: Vec<TVec>,
|
pub names: Vec<TStrv>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request for ResolveNames {
|
impl Request for ResolveNames {
|
||||||
type Response = Vec<OrcResult<TVec>>;
|
type Response = Vec<OrcResult<TStrv>>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,14 +120,14 @@ pub enum HostExtReq {
|
|||||||
ParseLine(parser::ParseLine),
|
ParseLine(parser::ParseLine),
|
||||||
FetchParsedConst(parser::FetchParsedConst),
|
FetchParsedConst(parser::FetchParsedConst),
|
||||||
GetMember(tree::GetMember),
|
GetMember(tree::GetMember),
|
||||||
|
SystemDrop(system::SystemDrop),
|
||||||
|
AtomDrop(atom::AtomDrop),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notifications sent from the host to the extension
|
/// Notifications sent from the host to the extension
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extendable]
|
#[extendable]
|
||||||
pub enum HostExtNotif {
|
pub enum HostExtNotif {
|
||||||
SystemDrop(system::SystemDrop),
|
|
||||||
AtomDrop(atom::AtomDrop),
|
|
||||||
/// The host can assume that after this notif is sent, a correctly written
|
/// The host can assume that after this notif is sent, a correctly written
|
||||||
/// extension will eventually exit.
|
/// extension will eventually exit.
|
||||||
Exit,
|
Exit,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy};
|
|||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
use crate::{CharFilter, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr, TVec};
|
use crate::{CharFilter, ExtHostReq, HostExtReq, MemberKind, TStr, TStrv};
|
||||||
|
|
||||||
/// ID of a system type
|
/// ID of a system type
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
|
||||||
@@ -63,12 +63,15 @@ pub struct NewSystemResponse {
|
|||||||
pub lex_filter: CharFilter,
|
pub lex_filter: CharFilter,
|
||||||
pub line_types: Vec<TStr>,
|
pub line_types: Vec<TStr>,
|
||||||
pub const_root: HashMap<TStr, MemberKind>,
|
pub const_root: HashMap<TStr, MemberKind>,
|
||||||
pub prelude: Vec<TVec>,
|
pub prelude: Vec<TStrv>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(HostExtNotif)]
|
#[extends(HostExtReq)]
|
||||||
pub struct SystemDrop(pub SysId);
|
pub struct SystemDrop(pub SysId);
|
||||||
|
impl Request for SystemDrop {
|
||||||
|
type Response = ();
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Debug, Coding, Hierarchy)]
|
||||||
#[extends(SysReq, HostExtReq)]
|
#[extends(SysReq, HostExtReq)]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::rc::Rc;
|
|||||||
use orchid_api_derive::{Coding, Hierarchy};
|
use orchid_api_derive::{Coding, Hierarchy};
|
||||||
use orchid_api_traits::Request;
|
use orchid_api_traits::Request;
|
||||||
|
|
||||||
use crate::{ExprTicket, Expression, ExtHostReq, HostExtReq, OrcError, SysId, TStr, TVec};
|
use crate::{ExprTicket, Expression, ExtHostReq, HostExtReq, OrcError, SysId, TStr, TStrv};
|
||||||
|
|
||||||
/// A token tree from a lexer recursion request. Its lifetime is the lex call,
|
/// A token tree from a lexer recursion request. Its lifetime is the lex call,
|
||||||
/// the lexer can include it in its output or discard it by implication.
|
/// the lexer can include it in its output or discard it by implication.
|
||||||
@@ -92,7 +92,7 @@ impl Request for GetMember {
|
|||||||
/// an atom call.
|
/// an atom call.
|
||||||
#[derive(Clone, Copy, Debug, Coding, Hierarchy)]
|
#[derive(Clone, Copy, Debug, Coding, Hierarchy)]
|
||||||
#[extends(ExtHostReq)]
|
#[extends(ExtHostReq)]
|
||||||
pub struct LsModule(pub SysId, pub TVec);
|
pub struct LsModule(pub SysId, pub TStrv);
|
||||||
impl Request for LsModule {
|
impl Request for LsModule {
|
||||||
type Response = Result<ModuleInfo, LsModuleError>;
|
type Response = Result<ModuleInfo, LsModuleError>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ name = "orchid-base"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[features]
|
|
||||||
mocks = []
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
use std::any::{TypeId, type_name};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use orchid_api_traits::MsgSet;
|
|
||||||
|
|
||||||
use crate::error::Reporter;
|
|
||||||
use crate::interner::Interner;
|
|
||||||
use crate::reqnot::{Client, DynClient};
|
|
||||||
|
|
||||||
pub trait CtxDyn {
|
|
||||||
fn i(&self) -> Interner;
|
|
||||||
fn rep(&self) -> &Reporter;
|
|
||||||
fn client(&self, msg_set: TypeId) -> Option<Rc<dyn DynClient>>;
|
|
||||||
fn msg_set_type(&self) -> TypeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Ctx(Rc<dyn CtxDyn>);
|
|
||||||
impl Ctx {
|
|
||||||
pub fn i(&self) -> Interner { self.0.i() }
|
|
||||||
pub fn rep(&self) -> &Reporter { self.0.rep() }
|
|
||||||
pub fn client<T: MsgSet>(&self) -> Client<T> {
|
|
||||||
let Some(dyn_client) = self.0.client(TypeId::of::<T>()) else {
|
|
||||||
panic!("Incorrect message set {} passed", type_name::<T>());
|
|
||||||
};
|
|
||||||
Client(dyn_client, PhantomData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,14 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt;
|
||||||
use std::ops::{Add, AddAssign, Deref};
|
use std::ops::Add;
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use async_fn_stream::stream;
|
use futures::future::join_all;
|
||||||
use async_once_cell::{Lazy, OnceCell};
|
|
||||||
use futures::future::{join_all, ready};
|
|
||||||
use futures::lock::Mutex;
|
|
||||||
use futures::{Stream, StreamExt, stream};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::format::{FmtCtx, FmtUnit, Format};
|
|
||||||
use crate::interner::{IStr, Interner};
|
|
||||||
use crate::location::Pos;
|
use crate::location::Pos;
|
||||||
|
|
||||||
/// A point of interest in resolving the error, such as the point where
|
/// A point of interest in resolving the error, such as the point where
|
||||||
@@ -58,126 +50,40 @@ impl fmt::Display for ErrPos {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct SingleError {
|
pub struct OrcErr {
|
||||||
pub description: IStr,
|
pub description: Tok<String>,
|
||||||
pub message: Arc<String>,
|
pub message: Arc<String>,
|
||||||
pub positions: Vec<ErrPos>,
|
pub positions: Vec<ErrPos>,
|
||||||
}
|
}
|
||||||
impl fmt::Display for SingleError {
|
impl OrcErr {
|
||||||
|
fn to_api(&self) -> api::OrcError {
|
||||||
|
api::OrcError {
|
||||||
|
description: self.description.to_api(),
|
||||||
|
message: self.message.clone(),
|
||||||
|
locations: self.positions.iter().map(ErrPos::to_api).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn from_api(api: &api::OrcError, i: &Interner) -> Self {
|
||||||
|
Self {
|
||||||
|
description: Tok::from_api(api.description, i).await,
|
||||||
|
message: api.message.clone(),
|
||||||
|
positions: join_all(api.locations.iter().map(|e| ErrPos::from_api(e, i))).await,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialEq<Tok<String>> for OrcErr {
|
||||||
|
fn eq(&self, other: &Tok<String>) -> bool { self.description == *other }
|
||||||
|
}
|
||||||
|
impl From<OrcErr> for Vec<OrcErr> {
|
||||||
|
fn from(value: OrcErr) -> Self { vec![value] }
|
||||||
|
}
|
||||||
|
impl fmt::Display for OrcErr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let pstr = self.positions.iter().map(|p| format!("{p}")).join("; ");
|
let pstr = self.positions.iter().map(|p| format!("{p}")).join("; ");
|
||||||
write!(f, "{}: {} @ {}", self.description, self.message, pstr)
|
write!(f, "{}: {} @ {}", self.description, self.message, pstr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OrcErr {
|
|
||||||
singles: OnceCell<OwnedOrcErr>,
|
|
||||||
futures: Mutex<Vec<Pin<Box<dyn Future<Output = OwnedOrcErr>>>>>,
|
|
||||||
}
|
|
||||||
impl OrcErr {
|
|
||||||
pub async fn into_owned(self) -> OwnedOrcErr {
|
|
||||||
self.to_owned().await;
|
|
||||||
self.singles.into_inner().expect("Initialized above")
|
|
||||||
}
|
|
||||||
pub async fn to_owned(&self) -> &OwnedOrcErr {
|
|
||||||
self
|
|
||||||
.singles
|
|
||||||
.get_or_init(async {
|
|
||||||
let results = join_all(self.futures.lock().await.drain(..)).await;
|
|
||||||
OwnedOrcErr(results.iter().flat_map(|err| err.0.iter()).cloned().collect())
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
fn into_futures(self) -> Vec<Pin<Box<dyn Future<Output = OwnedOrcErr>>>> {
|
|
||||||
match self.singles.into_inner() {
|
|
||||||
Some(val) => vec![Box::pin(ready(val))],
|
|
||||||
None => self.futures.into_inner(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<OwnedOrcErr> for OrcErr {
|
|
||||||
fn from(value: OwnedOrcErr) -> Self {
|
|
||||||
Self { singles: OnceCell::from(value), futures: Mutex::new(vec![]) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Future<Output = OrcErr> + 'static> From<T> for OrcErr {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self {
|
|
||||||
singles: OnceCell::new(),
|
|
||||||
futures: Mutex::new(vec![Box::pin(async { value.await.into_owned().await })]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Add for OrcErr {
|
|
||||||
type Output = Self;
|
|
||||||
fn add(mut self, mut rhs: Self) -> Self::Output {
|
|
||||||
if let (Some(l), Some(r)) = (self.singles.get_mut(), rhs.singles.get_mut()) {
|
|
||||||
l.0.extend(r.0.drain(..));
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
Self {
|
|
||||||
singles: OnceCell::new(),
|
|
||||||
futures: Mutex::new(self.into_futures().into_iter().chain(rhs.into_futures()).collect()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl AddAssign for OrcErr {
|
|
||||||
fn add_assign(&mut self, mut rhs: Self) {
|
|
||||||
if let (Some(l), Some(r)) = (self.singles.get_mut(), rhs.singles.get_mut()) {
|
|
||||||
l.0.extend(r.0.drain(..));
|
|
||||||
} else {
|
|
||||||
let mut temp = Self { futures: Mutex::default(), singles: OnceCell::new() };
|
|
||||||
std::mem::swap(self, &mut temp);
|
|
||||||
self.futures.get_mut().extend(temp.into_futures().into_iter().chain(rhs.into_futures()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Format for OrcErr {
|
|
||||||
async fn print<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
|
||||||
format!("{}", self.to_owned().await).into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct OwnedOrcErr(Vec<SingleError>);
|
|
||||||
impl OwnedOrcErr {
|
|
||||||
pub fn to_api(&self) -> Vec<api::OrcError> {
|
|
||||||
self
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.map(|err| api::OrcError {
|
|
||||||
description: err.description.to_api(),
|
|
||||||
message: err.message.clone(),
|
|
||||||
locations: err.positions.iter().map(|pos| pos.to_api()).collect(),
|
|
||||||
})
|
|
||||||
.collect_vec()
|
|
||||||
}
|
|
||||||
pub async fn from_api(api: impl IntoIterator<Item = &api::OrcError>, i: &Interner) -> Self {
|
|
||||||
Self(
|
|
||||||
join_all(api.into_iter().map(|e| async {
|
|
||||||
SingleError {
|
|
||||||
description: i.es(e.description).await,
|
|
||||||
message: e.message.clone(),
|
|
||||||
positions: join_all(e.locations.iter().map(|pos| ErrPos::from_api(pos, i))).await,
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
.await,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Display for OwnedOrcErr {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.0.iter().join("\n"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl fmt::Debug for OwnedOrcErr {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "OwnedOrcErr({self}") }
|
|
||||||
}
|
|
||||||
impl Add for OwnedOrcErr {
|
|
||||||
type Output = Self;
|
|
||||||
fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EmptyErrv;
|
pub struct EmptyErrv;
|
||||||
impl fmt::Display for EmptyErrv {
|
impl fmt::Display for EmptyErrv {
|
||||||
@@ -186,7 +92,70 @@ impl fmt::Display for EmptyErrv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type OrcRes<T> = Result<T, OrcErr>;
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct OrcErrv(Vec<OrcErr>);
|
||||||
|
impl OrcErrv {
|
||||||
|
pub fn new(errors: impl IntoIterator<Item = OrcErr>) -> Result<Self, EmptyErrv> {
|
||||||
|
let v = errors.into_iter().collect_vec();
|
||||||
|
if v.is_empty() { Err(EmptyErrv) } else { Ok(Self(v)) }
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn extended<T>(mut self, errors: impl IntoIterator<Item = T>) -> Self
|
||||||
|
where Self: Extend<T> {
|
||||||
|
self.extend(errors);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn len(&self) -> usize { self.0.len() }
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||||
|
#[must_use]
|
||||||
|
pub fn any(&self, f: impl FnMut(&OrcErr) -> bool) -> bool { self.0.iter().any(f) }
|
||||||
|
#[must_use]
|
||||||
|
pub fn keep_only(self, f: impl FnMut(&OrcErr) -> bool) -> Option<Self> {
|
||||||
|
let v = self.0.into_iter().filter(f).collect_vec();
|
||||||
|
if v.is_empty() { None } else { Some(Self(v)) }
|
||||||
|
}
|
||||||
|
#[must_use]
|
||||||
|
pub fn one(&self) -> Option<&OrcErr> { (self.0.len() == 1).then(|| &self.0[9]) }
|
||||||
|
pub fn pos_iter(&self) -> impl Iterator<Item = ErrPos> + '_ {
|
||||||
|
self.0.iter().flat_map(|e| e.positions.iter().cloned())
|
||||||
|
}
|
||||||
|
pub fn to_api(&self) -> Vec<api::OrcError> { self.0.iter().map(OrcErr::to_api).collect() }
|
||||||
|
pub async fn from_api<'a>(
|
||||||
|
api: impl IntoIterator<Item = &'a api::OrcError>,
|
||||||
|
i: &Interner,
|
||||||
|
) -> Self {
|
||||||
|
Self(join_all(api.into_iter().map(|e| OrcErr::from_api(e, i))).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<OrcErr> for OrcErrv {
|
||||||
|
fn from(value: OrcErr) -> Self { Self(vec![value]) }
|
||||||
|
}
|
||||||
|
impl Add for OrcErrv {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Self) -> Self::Output { Self(self.0.into_iter().chain(rhs.0).collect_vec()) }
|
||||||
|
}
|
||||||
|
impl Extend<OrcErr> for OrcErrv {
|
||||||
|
fn extend<T: IntoIterator<Item = OrcErr>>(&mut self, iter: T) { self.0.extend(iter) }
|
||||||
|
}
|
||||||
|
impl Extend<OrcErrv> for OrcErrv {
|
||||||
|
fn extend<T: IntoIterator<Item = OrcErrv>>(&mut self, iter: T) {
|
||||||
|
self.0.extend(iter.into_iter().flatten())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl IntoIterator for OrcErrv {
|
||||||
|
type IntoIter = std::vec::IntoIter<OrcErr>;
|
||||||
|
type Item = OrcErr;
|
||||||
|
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||||
|
}
|
||||||
|
impl fmt::Display for OrcErrv {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0.iter().join("\n"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type OrcRes<T> = Result<T, OrcErrv>;
|
||||||
|
|
||||||
pub fn join_ok<T, U>(left: OrcRes<T>, right: OrcRes<U>) -> OrcRes<(T, U)> {
|
pub fn join_ok<T, U>(left: OrcRes<T>, right: OrcRes<U>) -> OrcRes<(T, U)> {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
@@ -222,80 +191,62 @@ macro_rules! join_ok {
|
|||||||
(@VALUES) => { Ok(()) };
|
(@VALUES) => { Ok(()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
pub fn mk_errv_floating(description: Tok<String>, message: impl AsRef<str>) -> OrcErrv {
|
||||||
pub fn mk_err_floating(
|
mk_errv::<Pos>(description, message, [])
|
||||||
&self,
|
}
|
||||||
description: impl AsRef<str> + 'static,
|
|
||||||
message: impl AsRef<str> + 'static,
|
pub fn mk_errv<I: Into<ErrPos>>(
|
||||||
) -> OrcErr {
|
description: Tok<String>,
|
||||||
self.mk_err::<Pos>(description, message, [])
|
message: impl AsRef<str>,
|
||||||
|
posv: impl IntoIterator<Item = I>,
|
||||||
|
) -> OrcErrv {
|
||||||
|
OrcErr {
|
||||||
|
description,
|
||||||
|
message: Arc::new(message.as_ref().to_string()),
|
||||||
|
positions: posv.into_iter().map_into().collect(),
|
||||||
}
|
}
|
||||||
pub fn mk_err<I: Into<ErrPos>>(
|
.into()
|
||||||
&self,
|
}
|
||||||
description: impl AsRef<str> + 'static,
|
|
||||||
message: impl AsRef<str> + 'static,
|
pub async fn async_io_err<I: Into<ErrPos>>(
|
||||||
posv: impl IntoIterator<Item = I> + 'static,
|
err: std::io::Error,
|
||||||
) -> OrcErr {
|
i: &Interner,
|
||||||
let i = self.i();
|
posv: impl IntoIterator<Item = I>,
|
||||||
async move {
|
) -> OrcErrv {
|
||||||
OwnedOrcErr(vec![SingleError {
|
mk_errv(i.i(&err.kind().to_string()).await, err.to_string(), posv)
|
||||||
description: i.is(description.as_ref()).await,
|
}
|
||||||
message: Arc::new(message.as_ref().to_string()),
|
|
||||||
positions: posv.into_iter().map_into().collect(),
|
pub async fn os_str_to_string<'a, I: Into<ErrPos>>(
|
||||||
}])
|
str: &'a OsStr,
|
||||||
.into()
|
i: &Interner,
|
||||||
}
|
posv: impl IntoIterator<Item = I>,
|
||||||
.into()
|
) -> OrcRes<&'a str> {
|
||||||
}
|
match str.to_str() {
|
||||||
pub async fn async_io_err<I: Into<ErrPos>>(
|
Some(str) => Ok(str),
|
||||||
&self,
|
None => Err(mk_errv(
|
||||||
err: std::io::Error,
|
i.i("Non-unicode string").await,
|
||||||
posv: impl IntoIterator<Item = I> + 'static,
|
format!("{str:?} is not representable as unicode"),
|
||||||
) -> OrcErr {
|
posv,
|
||||||
self.mk_err(err.kind().to_string(), err.to_string(), posv)
|
)),
|
||||||
}
|
|
||||||
pub fn os_str_to_string<'a, I: Into<ErrPos>>(
|
|
||||||
&self,
|
|
||||||
str: &'a OsStr,
|
|
||||||
posv: impl IntoIterator<Item = I> + 'static,
|
|
||||||
) -> OrcRes<&'a str> {
|
|
||||||
match str.to_str() {
|
|
||||||
Some(str) => Ok(str),
|
|
||||||
None => Err(self.mk_err(
|
|
||||||
"Non-unicode string",
|
|
||||||
format!("{str:?} is not representable as unicode"),
|
|
||||||
posv,
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Reporter {
|
pub struct Reporter {
|
||||||
errors: RefCell<Option<OrcErr>>,
|
errors: RefCell<Vec<OrcErr>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reporter {
|
impl Reporter {
|
||||||
pub fn report(&self, e: impl Into<OrcErr>) {
|
pub fn report(&self, e: impl Into<OrcErrv>) { self.errors.borrow_mut().extend(e.into()) }
|
||||||
match &mut *self.errors.borrow_mut() {
|
pub fn new() -> Self { Self { errors: RefCell::new(vec![]) } }
|
||||||
slot @ None => *slot = Some(e.into()),
|
pub fn errv(self) -> Option<OrcErrv> { OrcErrv::new(self.errors.into_inner()).ok() }
|
||||||
Some(err) => *err += e.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn new() -> Self { Self { errors: RefCell::new(None) } }
|
|
||||||
pub fn res(self) -> Result<(), OrcErr> {
|
|
||||||
match self.errors.into_inner() {
|
|
||||||
Some(e) => Err(e),
|
|
||||||
None => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn merge<T>(self, res: OrcRes<T>) -> OrcRes<T> {
|
pub fn merge<T>(self, res: OrcRes<T>) -> OrcRes<T> {
|
||||||
match (res, self.res()) {
|
match (res, self.errv()) {
|
||||||
(res, Ok(())) => res,
|
(res, None) => res,
|
||||||
(Ok(_), Err(e)) => Err(e),
|
(Ok(_), Some(errv)) => Err(errv),
|
||||||
(Err(e), Err(e2)) => Err(e + e2),
|
(Err(e), Some(errv)) => Err(e + errv),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn is_empty(&self) -> bool { self.errors.borrow().is_none() }
|
pub fn is_empty(&self) -> bool { self.errors.borrow().is_empty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Reporter {
|
impl Default for Reporter {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
use std::any::Any;
|
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::hash::{BuildHasher as _, Hash};
|
use std::hash::BuildHasher as _;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic;
|
use std::sync::atomic;
|
||||||
use std::{fmt, hash};
|
use std::{fmt, hash};
|
||||||
|
|
||||||
use futures::future::LocalBoxFuture;
|
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
@@ -17,460 +15,296 @@ use orchid_api_traits::Request;
|
|||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::reqnot::{DynRequester, Requester};
|
use crate::reqnot::{DynRequester, Requester};
|
||||||
|
|
||||||
// /// Clippy crashes while verifying `Tok: Sized` without this and I cba to
|
/// Clippy crashes while verifying `Tok: Sized` without this and I cba to create
|
||||||
// create /// a minimal example
|
/// a minimal example
|
||||||
// #[derive(Clone)]
|
#[derive(Clone)]
|
||||||
// struct ForceSized<T>(T);
|
struct ForceSized<T>(T);
|
||||||
|
|
||||||
// #[derive(Clone)]
|
#[derive(Clone)]
|
||||||
// pub struct Tok<T: Interned> {
|
pub struct Tok<T: Interned> {
|
||||||
// data: Rc<T>,
|
data: Rc<T>,
|
||||||
// marker: ForceSized<T::Marker>,
|
marker: ForceSized<T::Marker>,
|
||||||
// }
|
}
|
||||||
// impl<T: Interned> Tok<T> {
|
impl<T: Interned> Tok<T> {
|
||||||
// pub fn new(data: Rc<T>, marker: T::Marker) -> Self { Self { data, marker:
|
pub fn new(data: Rc<T>, marker: T::Marker) -> Self { Self { data, marker: ForceSized(marker) } }
|
||||||
// ForceSized(marker) } } pub fn to_api(&self) -> T::Marker { self.marker.0 }
|
pub fn to_api(&self) -> T::Marker { self.marker.0 }
|
||||||
// pub async fn from_api<M>(marker: M, i: &Interner) -> Self
|
pub async fn from_api<M>(marker: M, i: &Interner) -> Self
|
||||||
// where M: InternMarker<Interned = T> {
|
where M: InternMarker<Interned = T> {
|
||||||
// i.ex(marker).await
|
i.ex(marker).await
|
||||||
// }
|
}
|
||||||
// pub fn rc(&self) -> Rc<T> { self.data.clone() }
|
pub fn rc(&self) -> Rc<T> { self.data.clone() }
|
||||||
// }
|
}
|
||||||
// impl<T: Interned> Deref for Tok<T> {
|
impl<T: Interned> Deref for Tok<T> {
|
||||||
// type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
// fn deref(&self) -> &Self::Target { self.data.as_ref() }
|
fn deref(&self) -> &Self::Target { self.data.as_ref() }
|
||||||
// }
|
}
|
||||||
// impl<T: Interned> Ord for Tok<T> {
|
impl<T: Interned> Ord for Tok<T> {
|
||||||
// fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.to_api().cmp(&other.to_api()) }
|
||||||
// self.to_api().cmp(&other.to_api()) } }
|
}
|
||||||
// impl<T: Interned> PartialOrd for Tok<T> {
|
impl<T: Interned> PartialOrd for Tok<T> {
|
||||||
// fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
||||||
// Some(self.cmp(other)) } }
|
}
|
||||||
// impl<T: Interned> Eq for Tok<T> {}
|
impl<T: Interned> Eq for Tok<T> {}
|
||||||
// impl<T: Interned> PartialEq for Tok<T> {
|
impl<T: Interned> PartialEq for Tok<T> {
|
||||||
// fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
|
fn eq(&self, other: &Self) -> bool { self.cmp(other).is_eq() }
|
||||||
// }
|
}
|
||||||
// impl<T: Interned> hash::Hash for Tok<T> {
|
impl<T: Interned> hash::Hash for Tok<T> {
|
||||||
// fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
|
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.to_api().hash(state) }
|
||||||
// }
|
}
|
||||||
// impl<T: Interned + fmt::Display> fmt::Display for Tok<T> {
|
impl<T: Interned + fmt::Display> fmt::Display for Tok<T> {
|
||||||
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
// write!(f, "{}", &*self.data)
|
write!(f, "{}", &*self.data)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
|
impl<T: Interned + fmt::Debug> fmt::Debug for Tok<T> {
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref())
|
write!(f, "Token({} -> {:?})", self.to_api().get_id(), self.data.as_ref())
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug +
|
pub trait Interned: Eq + hash::Hash + Clone + fmt::Debug + Internable<Interned = Self> {
|
||||||
// Internable<Interned = Self> { type Marker: InternMarker<Interned = Self> +
|
type Marker: InternMarker<Interned = Self> + Sized;
|
||||||
// Sized; fn intern(
|
fn intern(
|
||||||
// self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||||
// ) -> impl Future<Output = Self::Marker>;
|
) -> impl Future<Output = Self::Marker>;
|
||||||
// fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
fn bimap(interner: &mut TypedInterners) -> &mut Bimap<Self>;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub trait Internable: fmt::Debug {
|
pub trait Internable: fmt::Debug {
|
||||||
// type Interned: Interned;
|
type Interned: Interned;
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned>;
|
fn get_owned(&self) -> Rc<Self::Interned>;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash
|
pub trait InternMarker: Copy + PartialEq + Eq + PartialOrd + Ord + hash::Hash + Sized {
|
||||||
// + Sized { type Interned: Interned<Marker = Self>;
|
type Interned: Interned<Marker = Self>;
|
||||||
// /// Only called on replicas
|
/// Only called on replicas
|
||||||
// fn resolve(self, i: &Interner) -> impl Future<Output = Tok<Self::Interned>>;
|
fn resolve(self, i: &Interner) -> impl Future<Output = Tok<Self::Interned>>;
|
||||||
// fn get_id(self) -> NonZeroU64;
|
fn get_id(self) -> NonZeroU64;
|
||||||
// fn from_id(id: NonZeroU64) -> Self;
|
fn from_id(id: NonZeroU64) -> Self;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl Interned for String {
|
impl Interned for String {
|
||||||
// type Marker = api::TStr;
|
type Marker = api::TStr;
|
||||||
// async fn intern(
|
async fn intern(
|
||||||
// self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||||
// ) -> Self::Marker {
|
) -> Self::Marker {
|
||||||
// req.request(api::InternStr(self.to_string())).await
|
req.request(api::InternStr(self.to_string())).await
|
||||||
// }
|
}
|
||||||
// fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut
|
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.strings }
|
||||||
// interners.strings } }
|
}
|
||||||
// impl InternMarker for api::TStr {
|
impl InternMarker for api::TStr {
|
||||||
// type Interned = String;
|
type Interned = String;
|
||||||
// async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||||
// Tok::new(Rc::new(i.0.master.as_ref().unwrap().
|
Tok::new(Rc::new(i.0.master.as_ref().unwrap().request(api::ExternStr(self)).await), self)
|
||||||
// request(api::ExternStr(self)).await), self) }
|
}
|
||||||
// fn get_id(self) -> NonZeroU64 { self.0 }
|
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||||
// fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||||
// }
|
}
|
||||||
// impl Internable for str {
|
impl Internable for str {
|
||||||
// type Interned = String;
|
type Interned = String;
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
||||||
// }
|
}
|
||||||
// impl Internable for String {
|
impl Internable for String {
|
||||||
// type Interned = String;
|
type Interned = String;
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_string()) }
|
||||||
// }
|
}
|
||||||
|
|
||||||
// impl Interned for Vec<IStr> {
|
impl Interned for Vec<Tok<String>> {
|
||||||
// type Marker = api::TStrv;
|
type Marker = api::TStrv;
|
||||||
// async fn intern(
|
async fn intern(
|
||||||
// self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
// req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
req: &(impl DynRequester<Transfer = api::IntReq> + ?Sized),
|
||||||
// ) -> Self::Marker {
|
) -> Self::Marker {
|
||||||
// req.request(api::InternStrv(self.iter().map(|t|
|
req.request(api::InternStrv(self.iter().map(|t| t.to_api()).collect())).await
|
||||||
// t.to_api()).collect())).await }
|
}
|
||||||
// fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut
|
fn bimap(interners: &mut TypedInterners) -> &mut Bimap<Self> { &mut interners.vecs }
|
||||||
// interners.vecs } }
|
}
|
||||||
// impl InternMarker for api::TStrv {
|
impl InternMarker for api::TStrv {
|
||||||
// type Interned = Vec<IStr>;
|
type Interned = Vec<Tok<String>>;
|
||||||
// async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
async fn resolve(self, i: &Interner) -> Tok<Self::Interned> {
|
||||||
// let rep =
|
let rep = i.0.master.as_ref().unwrap().request(api::ExternStrv(self)).await;
|
||||||
// i.0.master.as_ref().unwrap().request(api::ExternStrv(self)).await; let data
|
let data = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await;
|
||||||
// = futures::future::join_all(rep.into_iter().map(|m| i.ex(m))).await;
|
Tok::new(Rc::new(data), self)
|
||||||
// Tok::new(Rc::new(data), self)
|
}
|
||||||
// }
|
fn get_id(self) -> NonZeroU64 { self.0 }
|
||||||
// fn get_id(self) -> NonZeroU64 { self.0 }
|
fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
||||||
// fn from_id(id: NonZeroU64) -> Self { Self(id) }
|
}
|
||||||
// }
|
impl Internable for [Tok<String>] {
|
||||||
// impl Internable for [IStr] {
|
type Interned = Vec<Tok<String>>;
|
||||||
// type Interned = Vec<IStr>;
|
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
}
|
||||||
// }
|
impl<const N: usize> Internable for [Tok<String>; N] {
|
||||||
// impl<const N: usize> Internable for [IStr; N] {
|
type Interned = Vec<Tok<String>>;
|
||||||
// type Interned = Vec<IStr>;
|
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
}
|
||||||
// }
|
impl Internable for Vec<Tok<String>> {
|
||||||
// impl Internable for Vec<IStr> {
|
type Interned = Vec<Tok<String>>;
|
||||||
// type Interned = Vec<IStr>;
|
fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
||||||
// fn get_owned(&self) -> Rc<Self::Interned> { Rc::new(self.to_vec()) }
|
}
|
||||||
// }
|
|
||||||
// impl Internable for Vec<api::TStr> {
|
// impl Internable for Vec<api::TStr> {
|
||||||
// type Interned = Vec<IStr>;
|
// type Interned = Vec<Tok<String>>;
|
||||||
// fn get_owned(&self) -> Arc<Self::Interned> {
|
// fn get_owned(&self) -> Arc<Self::Interned> {
|
||||||
// Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
// Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// impl Internable for [api::TStr] {
|
// impl Internable for [api::TStr] {
|
||||||
// type Interned = Vec<IStr>;
|
// type Interned = Vec<Tok<String>>;
|
||||||
// fn get_owned(&self) -> Arc<Self::Interned> {
|
// fn get_owned(&self) -> Arc<Self::Interned> {
|
||||||
// Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
// Arc::new(self.iter().map(|ts| deintern(*ts)).collect())
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
macro_rules! token_def {
|
/// The number of references held to any token by the interner.
|
||||||
($type:ident, $trait:ident, $deref:ty, $api_repr:ty, $type_name:expr) => {
|
const BASE_RC: usize = 3;
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct $type(Rc<dyn $trait>);
|
#[test]
|
||||||
impl $type {
|
fn base_rc_correct() {
|
||||||
pub fn new<T: $trait + 'static>(t: T) -> Self { Self(Rc::new(t) as _) }
|
let tok = Tok::new(Rc::new("foo".to_string()), api::TStr(1.try_into().unwrap()));
|
||||||
pub fn to_api(&self) -> $api_repr { self.0.to_api() }
|
let mut bimap = Bimap::default();
|
||||||
pub fn inner(&self) -> &dyn Any { self.0.as_ref() }
|
bimap.insert(tok.clone());
|
||||||
fn addr(&self) -> usize { Rc::as_ptr(&self.0).addr() }
|
assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the current instance");
|
||||||
}
|
|
||||||
pub trait $trait: Deref<Target = $deref> + Any {
|
|
||||||
fn to_api(&self) -> $api_repr;
|
|
||||||
}
|
|
||||||
impl Deref for $type {
|
|
||||||
type Target = $deref;
|
|
||||||
fn deref(&self) -> &Self::Target { self.0.deref() }
|
|
||||||
}
|
|
||||||
impl Eq for $type {}
|
|
||||||
impl PartialEq for $type {
|
|
||||||
fn eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.0, &other.0) }
|
|
||||||
}
|
|
||||||
impl Ord for $type {
|
|
||||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.addr().cmp(&other.addr()) }
|
|
||||||
}
|
|
||||||
impl PartialOrd for $type {
|
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }
|
|
||||||
}
|
|
||||||
impl Hash for $type {
|
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.addr().hash(state) }
|
|
||||||
}
|
|
||||||
impl std::fmt::Debug for $type {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_tuple($type_name).field(&self.to_api().0).field(&self.deref()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
token_def!(IStr, IStrDyn, str, api::TStr, "IStr");
|
pub struct Bimap<T: Interned> {
|
||||||
impl std::fmt::Display for IStr {
|
intern: HashMap<Rc<T>, Tok<T>>,
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.deref()) }
|
by_id: HashMap<T::Marker, Tok<T>>,
|
||||||
|
}
|
||||||
|
impl<T: Interned> Bimap<T> {
|
||||||
|
pub fn insert(&mut self, token: Tok<T>) {
|
||||||
|
self.intern.insert(token.data.clone(), token.clone());
|
||||||
|
self.by_id.insert(token.to_api(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_marker(&self, marker: T::Marker) -> Option<Tok<T>> { self.by_id.get(&marker).cloned() }
|
||||||
|
|
||||||
|
pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
|
||||||
|
where T: Borrow<Q> {
|
||||||
|
(self.intern.raw_entry())
|
||||||
|
.from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q)
|
||||||
|
.map(|p| p.1.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
||||||
|
(self.intern)
|
||||||
|
.extract_if(|k, _| Rc::strong_count(k) == BASE_RC)
|
||||||
|
.map(|(_, v)| {
|
||||||
|
self.by_id.remove(&v.to_api());
|
||||||
|
v.to_api()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
||||||
|
self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) || retained.contains(&v.to_api()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token_def!(IVec, IVecDyn, [IStr], api::TVec, "IVec");
|
impl<T: Interned> Default for Bimap<T> {
|
||||||
|
fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new() } }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub trait UpComm {
|
||||||
pub struct Interner(Rc<dyn InternerDyn>);
|
fn up<R: Request>(&self, req: R) -> R::Response;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TypedInterners {
|
||||||
|
strings: Bimap<String>,
|
||||||
|
vecs: Bimap<Vec<Tok<String>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InternerData {
|
||||||
|
interners: Mutex<TypedInterners>,
|
||||||
|
master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
||||||
|
}
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Interner(Rc<InternerData>);
|
||||||
impl Interner {
|
impl Interner {
|
||||||
pub fn new<T: InternerDyn + 'static>(t: T) -> Self { Self(Rc::new(t) as _) }
|
pub fn new_master() -> Self { Self::default() }
|
||||||
pub async fn is(&self, s: &(impl Borrow<str> + ?Sized)) -> IStr {
|
pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static) -> Self {
|
||||||
IStr(self.0.is(s.borrow()).await)
|
Self(Rc::new(InternerData { master: Some(Box::new(req)), interners: Mutex::default() }))
|
||||||
}
|
}
|
||||||
pub async fn iv(&self, s: &(impl Borrow<[IStr]> + ?Sized)) -> IVec {
|
/// Intern some data; query its identifier if not known locally
|
||||||
IVec(self.0.iv(s.borrow()).await)
|
pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> + ?Sized)) -> Tok<T> {
|
||||||
|
let data = t.get_owned();
|
||||||
|
let mut g = self.0.interners.lock().await;
|
||||||
|
let typed = T::bimap(&mut g);
|
||||||
|
if let Some(tok) = typed.by_value(&data) {
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
let marker = match &self.0.master {
|
||||||
|
Some(c) => data.clone().intern(&**c).await,
|
||||||
|
None =>
|
||||||
|
T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1, atomic::Ordering::Relaxed)).unwrap()),
|
||||||
|
};
|
||||||
|
let tok = Tok::new(data, marker);
|
||||||
|
T::bimap(&mut g).insert(tok.clone());
|
||||||
|
tok
|
||||||
|
}
|
||||||
|
/// Extern an identifier; query the data it represents if not known locally
|
||||||
|
pub async fn ex<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
|
||||||
|
if let Some(tok) = M::Interned::bimap(&mut *self.0.interners.lock().await).by_marker(marker) {
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
assert!(self.0.master.is_some(), "ID not in local interner and this is master");
|
||||||
|
let token = marker.resolve(self).await;
|
||||||
|
M::Interned::bimap(&mut *self.0.interners.lock().await).insert(token.clone());
|
||||||
|
token
|
||||||
|
}
|
||||||
|
pub async fn sweep_replica(&self) -> api::Retained {
|
||||||
|
assert!(self.0.master.is_some(), "Not a replica");
|
||||||
|
let mut g = self.0.interners.lock().await;
|
||||||
|
api::Retained { strings: g.strings.sweep_replica(), vecs: g.vecs.sweep_replica() }
|
||||||
|
}
|
||||||
|
pub async fn sweep_master(&self, retained: api::Retained) {
|
||||||
|
assert!(self.0.master.is_none(), "Not master");
|
||||||
|
let mut g = self.0.interners.lock().await;
|
||||||
|
g.strings.sweep_master(retained.strings.into_iter().collect());
|
||||||
|
g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
||||||
}
|
}
|
||||||
pub async fn es(&self, m: api::TStr) -> IStr { IStr(self.0.es(m).await) }
|
|
||||||
pub async fn ev(&self, m: api::TVec) -> IVec { IVec(self.0.ev(m).await) }
|
|
||||||
}
|
}
|
||||||
pub trait InternerDyn {
|
impl fmt::Debug for Interner {
|
||||||
fn is(&self, s: &str) -> LocalBoxFuture<Rc<dyn IStrDyn>>;
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fn iv(&self, v: &[IStr]) -> LocalBoxFuture<Rc<dyn IVecDyn>>;
|
write!(f, "Interner{{ replica: {} }}", self.0.master.is_none())
|
||||||
fn es(&self, m: api::TStr) -> LocalBoxFuture<Rc<dyn IStrDyn>>;
|
}
|
||||||
fn ev(&self, m: api::TVec) -> LocalBoxFuture<Rc<dyn IVecDyn>>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "mocks", test))]
|
static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1);
|
||||||
pub mod test {
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) {
|
||||||
|
into.strings = into.strings.iter().chain(&from.strings).copied().unique().collect();
|
||||||
|
into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
use std::sync::atomic::AtomicU64;
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
use orchid_api_traits::{Decode, enc_vec};
|
||||||
|
use test_executors::spin_on;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::testing::AsyncMonitor;
|
use crate::api;
|
||||||
|
|
||||||
pub(crate) struct DummyIStr(NonZeroU64, String);
|
#[test]
|
||||||
impl Deref for DummyIStr {
|
fn test_i() {
|
||||||
type Target = str;
|
let i = Interner::new_master();
|
||||||
fn deref(&self) -> &Self::Target { &self.1 }
|
let _: Tok<String> = spin_on(i.i("foo"));
|
||||||
}
|
let _: Tok<Vec<Tok<String>>> = spin_on(i.i(&[spin_on(i.i("bar")), spin_on(i.i("baz"))]));
|
||||||
impl IStrDyn for DummyIStr {
|
|
||||||
fn to_api(&self) -> api::TStr { api::TStr(self.0) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct DummyIStrv(NonZeroU64, Vec<IStr>);
|
#[test]
|
||||||
impl Deref for DummyIStrv {
|
fn test_coding() {
|
||||||
type Target = [IStr];
|
spin_on(async {
|
||||||
fn deref(&self) -> &Self::Target { &self.1 }
|
let coded = api::TStr(NonZero::new(3u64).unwrap());
|
||||||
|
let mut enc = &enc_vec(&coded).await[..];
|
||||||
|
api::TStr::decode(Pin::new(&mut enc)).await;
|
||||||
|
assert_eq!(enc, [], "Did not consume all of {enc:?}")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
impl IVecDyn for DummyIStrv {
|
|
||||||
fn to_api(&self) -> api::TVec { api::TVec(self.0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct DummyInterner(
|
|
||||||
RefCell<(
|
|
||||||
HashMap<String, NonZeroU64>,
|
|
||||||
HashMap<NonZeroU64, Rc<DummyIStr>>,
|
|
||||||
HashMap<NonZeroU64, Rc<DummyIStrv>>,
|
|
||||||
)>,
|
|
||||||
AsyncMonitor<InternerEvent>,
|
|
||||||
);
|
|
||||||
pub enum InternerEvent {
|
|
||||||
ExternStr(Rc<DummyIStr>),
|
|
||||||
ExternVec(Rc<DummyIStrv>),
|
|
||||||
InternStr { token: Rc<DummyIStr>, new: bool },
|
|
||||||
InternVec { token: Rc<DummyIStrv>, new: bool },
|
|
||||||
}
|
|
||||||
impl DummyInterner {
|
|
||||||
pub fn new(monitor: AsyncMonitor<InternerEvent>) -> Interner {
|
|
||||||
Interner(Rc::new(Self(RefCell::default(), monitor)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl InternerDyn for DummyInterner {
|
|
||||||
fn es(&self, m: api::TStr) -> LocalBoxFuture<Rc<dyn IStrDyn>> {
|
|
||||||
let state = self.0.borrow();
|
|
||||||
let istr = state.1.get(&m.0).unwrap_or_else(|| panic!("Externed nonexistent {m:?}")).clone();
|
|
||||||
Box::pin(async {
|
|
||||||
self.1.notify(InternerEvent::ExternStr(istr.clone())).await;
|
|
||||||
istr as Rc<dyn IStrDyn>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn ev(&self, m: api::TVec) -> LocalBoxFuture<Rc<dyn IVecDyn>> {
|
|
||||||
let state = self.0.borrow();
|
|
||||||
let ivec = state.2.get(&m.0).unwrap_or_else(|| panic!("Externed nonexistent {m:?}")).clone();
|
|
||||||
Box::pin(async {
|
|
||||||
self.1.notify(InternerEvent::ExternVec(ivec.clone())).await;
|
|
||||||
ivec as Rc<dyn IVecDyn>
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn is(&self, s: &str) -> LocalBoxFuture<Rc<dyn IStrDyn>> {
|
|
||||||
let mut this = self.0.borrow_mut();
|
|
||||||
let id = *(this.0.entry(format!("{s:?}")))
|
|
||||||
.or_insert_with(|| NonZero::new(COUNTER.fetch_add(1, atomic::Ordering::Relaxed)).unwrap());
|
|
||||||
let (tok, new) = match this.1.entry(id) {
|
|
||||||
hashbrown::hash_map::Entry::Occupied(ent) => (ent.get().clone(), false),
|
|
||||||
hashbrown::hash_map::Entry::Vacant(ent) =>
|
|
||||||
(ent.insert(Rc::new(DummyIStr(id, s.to_string()))).clone(), true),
|
|
||||||
};
|
|
||||||
Box::pin(async move {
|
|
||||||
self.1.notify(InternerEvent::InternStr { token: tok.clone(), new }).await;
|
|
||||||
tok as _
|
|
||||||
})
|
|
||||||
}
|
|
||||||
fn iv(&self, s: &[IStr]) -> LocalBoxFuture<Rc<dyn IVecDyn>> {
|
|
||||||
let mut this = self.0.borrow_mut();
|
|
||||||
let id = *(this.0.entry(format!("{s:?}")))
|
|
||||||
.or_insert_with(|| NonZero::new(COUNTER.fetch_add(1, atomic::Ordering::Relaxed)).unwrap());
|
|
||||||
let (tok, new) = match this.2.entry(id) {
|
|
||||||
hashbrown::hash_map::Entry::Occupied(ent) => (ent.get().clone(), false),
|
|
||||||
hashbrown::hash_map::Entry::Vacant(ent) =>
|
|
||||||
(ent.insert(Rc::new(DummyIStrv(id, s.to_vec()))).clone(), true),
|
|
||||||
};
|
|
||||||
Box::pin(async move {
|
|
||||||
self.1.notify(InternerEvent::InternVec { token: tok.clone(), new }).await;
|
|
||||||
tok as _
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static COUNTER: AtomicU64 = AtomicU64::new(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// /// The number of references held to any token by the interner.
|
|
||||||
// const BASE_RC: usize = 3;
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn base_rc_correct() {
|
|
||||||
// let tok = Tok::new(Rc::new("foo".to_string()),
|
|
||||||
// api::TStr(1.try_into().unwrap())); let mut bimap = Bimap::default();
|
|
||||||
// bimap.insert(tok.clone());
|
|
||||||
// assert_eq!(Rc::strong_count(&tok.data), BASE_RC + 1, "the bimap plus the
|
|
||||||
// current instance"); }
|
|
||||||
|
|
||||||
// pub struct Bimap<K, V, Tok> {
|
|
||||||
// intern: HashMap<V, Tok>,
|
|
||||||
// by_id: HashMap<K, Tok>,
|
|
||||||
// }
|
|
||||||
// impl<K> Bimap<T> {
|
|
||||||
// pub fn insert(&mut self, token: Tok<T>) {
|
|
||||||
// self.intern.insert(token.data.clone(), token.clone());
|
|
||||||
// self.by_id.insert(token.to_api(), token);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn by_marker(&self, marker: T::Marker) -> Option<Tok<T>> {
|
|
||||||
// self.by_id.get(&marker).cloned() }
|
|
||||||
|
|
||||||
// pub fn by_value<Q: Eq + hash::Hash>(&self, q: &Q) -> Option<Tok<T>>
|
|
||||||
// where T: Borrow<Q> {
|
|
||||||
// (self.intern.raw_entry())
|
|
||||||
// .from_hash(self.intern.hasher().hash_one(q), |k| k.as_ref().borrow() == q)
|
|
||||||
// .map(|p| p.1.clone())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn sweep_replica(&mut self) -> Vec<T::Marker> {
|
|
||||||
// (self.intern)
|
|
||||||
// .extract_if(|k, _| Rc::strong_count(k) == BASE_RC)
|
|
||||||
// .map(|(_, v)| {
|
|
||||||
// self.by_id.remove(&v.to_api());
|
|
||||||
// v.to_api()
|
|
||||||
// })
|
|
||||||
// .collect()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn sweep_master(&mut self, retained: HashSet<T::Marker>) {
|
|
||||||
// self.intern.retain(|k, v| BASE_RC < Rc::strong_count(k) ||
|
|
||||||
// retained.contains(&v.to_api())) }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<T: Interned> Default for Bimap<T> {
|
|
||||||
// fn default() -> Self { Self { by_id: HashMap::new(), intern: HashMap::new()
|
|
||||||
// } } }
|
|
||||||
|
|
||||||
// pub trait UpComm {
|
|
||||||
// fn up<R: Request>(&self, req: R) -> R::Response;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[derive(Default)]
|
|
||||||
// pub struct TypedInterners {
|
|
||||||
// strings: Bimap<String>,
|
|
||||||
// vecs: Bimap<Vec<IStr>>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[derive(Default)]
|
|
||||||
// pub struct InternerData {
|
|
||||||
// interners: Mutex<TypedInterners>,
|
|
||||||
// master: Option<Box<dyn DynRequester<Transfer = api::IntReq>>>,
|
|
||||||
// }
|
|
||||||
// #[derive(Clone, Default)]
|
|
||||||
// pub struct Interner(Rc<InternerData>);
|
|
||||||
// impl Interner {
|
|
||||||
// pub fn new_master() -> Self { Self::default() }
|
|
||||||
// pub fn new_replica(req: impl DynRequester<Transfer = api::IntReq> + 'static)
|
|
||||||
// -> Self { Self(Rc::new(InternerData { master: Some(Box::new(req)),
|
|
||||||
// interners: Mutex::default() })) }
|
|
||||||
// /// Intern some data; query its identifier if not known locally
|
|
||||||
// pub async fn i<T: Interned>(&self, t: &(impl Internable<Interned = T> +
|
|
||||||
// ?Sized)) -> Tok<T> { let data = t.get_owned();
|
|
||||||
// let mut g = self.0.interners.lock().await;
|
|
||||||
// let typed = T::bimap(&mut g);
|
|
||||||
// if let Some(tok) = typed.by_value(&data) {
|
|
||||||
// return tok;
|
|
||||||
// }
|
|
||||||
// let marker = match &self.0.master {
|
|
||||||
// Some(c) => data.clone().intern(&**c).await,
|
|
||||||
// None =>
|
|
||||||
// T::Marker::from_id(NonZeroU64::new(ID.fetch_add(1,
|
|
||||||
// atomic::Ordering::Relaxed)).unwrap()), };
|
|
||||||
// let tok = Tok::new(data, marker);
|
|
||||||
// T::bimap(&mut g).insert(tok.clone());
|
|
||||||
// tok
|
|
||||||
// }
|
|
||||||
// /// Extern an identifier; query the data it represents if not known locally
|
|
||||||
// pub async fn ex<M: InternMarker>(&self, marker: M) -> Tok<M::Interned> {
|
|
||||||
// if let Some(tok) = M::Interned::bimap(&mut
|
|
||||||
// *self.0.interners.lock().await).by_marker(marker) { return tok;
|
|
||||||
// }
|
|
||||||
// assert!(self.0.master.is_some(), "ID not in local interner and this is
|
|
||||||
// master"); let token = marker.resolve(self).await;
|
|
||||||
// M::Interned::bimap(&mut
|
|
||||||
// *self.0.interners.lock().await).insert(token.clone()); token
|
|
||||||
// }
|
|
||||||
// pub async fn sweep_replica(&self) -> api::Retained {
|
|
||||||
// assert!(self.0.master.is_some(), "Not a replica");
|
|
||||||
// let mut g = self.0.interners.lock().await;
|
|
||||||
// api::Retained { strings: g.strings.sweep_replica(), vecs:
|
|
||||||
// g.vecs.sweep_replica() } }
|
|
||||||
// pub async fn sweep_master(&self, retained: api::Retained) {
|
|
||||||
// assert!(self.0.master.is_none(), "Not master");
|
|
||||||
// let mut g = self.0.interners.lock().await;
|
|
||||||
// g.strings.sweep_master(retained.strings.into_iter().collect());
|
|
||||||
// g.vecs.sweep_master(retained.vecs.into_iter().collect());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// impl fmt::Debug for Interner {
|
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
// write!(f, "Interner{{ replica: {} }}", self.0.master.is_none())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// static ID: atomic::AtomicU64 = atomic::AtomicU64::new(1);
|
|
||||||
|
|
||||||
// pub fn merge_retained(into: &mut api::Retained, from: &api::Retained) {
|
|
||||||
// into.strings =
|
|
||||||
// into.strings.iter().chain(&from.strings).copied().unique().collect();
|
|
||||||
// into.vecs = into.vecs.iter().chain(&from.vecs).copied().unique().collect();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[cfg(test)]
|
|
||||||
// mod test {
|
|
||||||
// use std::num::NonZero;
|
|
||||||
// use std::pin::Pin;
|
|
||||||
|
|
||||||
// use orchid_api_traits::{Decode, enc_vec};
|
|
||||||
// use test_executors::spin_on;
|
|
||||||
|
|
||||||
// use super::*;
|
|
||||||
// use crate::api;
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_i() {
|
|
||||||
// let i = Interner::new_master();
|
|
||||||
// let _: IStr = spin_on(i.i("foo"));
|
|
||||||
// let _: Tok<Vec<IStr>> = spin_on(i.i(&[spin_on(i.i("bar")),
|
|
||||||
// spin_on(i.i("baz"))])); }
|
|
||||||
|
|
||||||
// #[test]
|
|
||||||
// fn test_coding() {
|
|
||||||
// spin_on(async {
|
|
||||||
// let coded = api::TStr(NonZero::new(3u64).unwrap());
|
|
||||||
// let mut enc = &enc_vec(&coded).await[..];
|
|
||||||
// api::TStr::decode(Pin::new(&mut enc)).await;
|
|
||||||
// assert_eq!(enc, [], "Did not consume all of {enc:?}")
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ pub mod builtin;
|
|||||||
pub mod char_filter;
|
pub mod char_filter;
|
||||||
pub mod clone;
|
pub mod clone;
|
||||||
pub mod combine;
|
pub mod combine;
|
||||||
pub mod ctx;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
@@ -26,7 +25,6 @@ pub mod pure_seq;
|
|||||||
pub mod reqnot;
|
pub mod reqnot;
|
||||||
pub mod sequence;
|
pub mod sequence;
|
||||||
pub mod side;
|
pub mod side;
|
||||||
pub mod testing;
|
|
||||||
mod tl_cache;
|
mod tl_cache;
|
||||||
pub mod tokens;
|
pub mod tokens;
|
||||||
pub mod tree;
|
pub mod tree;
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ use std::ops::Range;
|
|||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use crate::error::ErrPos;
|
use crate::error::ErrPos;
|
||||||
use crate::interner::{IStr, Interner};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::name::Sym;
|
use crate::name::Sym;
|
||||||
use crate::{api, match_mapping, sym};
|
use crate::{api, match_mapping, sym};
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
pub trait GetSrc = FnMut(&Sym) -> IStr;
|
pub trait GetSrc = FnMut(&Sym) -> Tok<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -131,21 +131,24 @@ pub struct CodeGenInfo {
|
|||||||
/// formatted like a Rust namespace
|
/// formatted like a Rust namespace
|
||||||
pub generator: Sym,
|
pub generator: Sym,
|
||||||
/// Unformatted user message with relevant circumstances and parameters
|
/// Unformatted user message with relevant circumstances and parameters
|
||||||
pub details: IStr,
|
pub details: Tok<String>,
|
||||||
}
|
}
|
||||||
impl CodeGenInfo {
|
impl CodeGenInfo {
|
||||||
/// A codegen marker with no user message and parameters
|
/// A codegen marker with no user message and parameters
|
||||||
pub async fn new_short(generator: Sym, i: &Interner) -> Self {
|
pub async fn new_short(generator: Sym, i: &Interner) -> Self {
|
||||||
Self { generator, details: i.is("").await }
|
Self { generator, details: i.i("").await }
|
||||||
}
|
}
|
||||||
/// A codegen marker with a user message or parameters
|
/// A codegen marker with a user message or parameters
|
||||||
pub async fn new_details(generator: Sym, details: impl AsRef<str>, i: &Interner) -> Self {
|
pub async fn new_details(generator: Sym, details: impl AsRef<str>, i: &Interner) -> Self {
|
||||||
Self { generator, details: i.is(details.as_ref()).await }
|
Self { generator, details: i.i(details.as_ref()).await }
|
||||||
}
|
}
|
||||||
/// Syntactic location
|
/// Syntactic location
|
||||||
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
pub fn pos(&self) -> Pos { Pos::Gen(self.clone()) }
|
||||||
pub async fn from_api(api: &api::CodeGenInfo, i: &Interner) -> Self {
|
pub async fn from_api(api: &api::CodeGenInfo, i: &Interner) -> Self {
|
||||||
Self { generator: Sym::from_api(api.generator, i).await, details: i.es(api.details).await }
|
Self {
|
||||||
|
generator: Sym::from_api(api.generator, i).await,
|
||||||
|
details: Tok::from_api(api.details, i).await,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn to_api(&self) -> api::CodeGenInfo {
|
pub fn to_api(&self) -> api::CodeGenInfo {
|
||||||
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
|
api::CodeGenInfo { generator: self.generator.to_api(), details: self.details.to_api() }
|
||||||
|
|||||||
@@ -12,48 +12,52 @@ use itertools::Itertools;
|
|||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::interner::{IStr, IVec, Interner};
|
use crate::interner::{InternMarker, Interner, Tok};
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
/// Traits that all name iterators should implement
|
/// Traits that all name iterators should implement
|
||||||
pub trait NameIter = Iterator<Item = IStr> + DoubleEndedIterator + ExactSizeIterator;
|
pub trait NameIter = Iterator<Item = Tok<String>> + DoubleEndedIterator + ExactSizeIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A token path which may be empty. [VName] is the non-empty version
|
/// A token path which may be empty. [VName] is the non-empty version
|
||||||
#[derive(Clone, Default, Hash, PartialEq, Eq)]
|
#[derive(Clone, Default, Hash, PartialEq, Eq)]
|
||||||
pub struct VPath(Vec<IStr>);
|
pub struct VPath(Vec<Tok<String>>);
|
||||||
impl VPath {
|
impl VPath {
|
||||||
/// Collect segments into a vector
|
/// Collect segments into a vector
|
||||||
pub fn new(items: impl IntoIterator<Item = IStr>) -> Self { Self(items.into_iter().collect()) }
|
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
|
Self(items.into_iter().collect())
|
||||||
|
}
|
||||||
/// Number of path segments
|
/// Number of path segments
|
||||||
pub fn len(&self) -> usize { self.0.len() }
|
pub fn len(&self) -> usize { self.0.len() }
|
||||||
/// Whether there are any path segments. In other words, whether this is a
|
/// Whether there are any path segments. In other words, whether this is a
|
||||||
/// valid name
|
/// valid name
|
||||||
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
pub fn is_empty(&self) -> bool { self.len() == 0 }
|
||||||
/// Prepend some tokens to the path
|
/// Prepend some tokens to the path
|
||||||
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> Self {
|
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
Self(items.into_iter().chain(self.0).collect())
|
Self(items.into_iter().chain(self.0).collect())
|
||||||
}
|
}
|
||||||
/// Append some tokens to the path
|
/// Append some tokens to the path
|
||||||
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> Self {
|
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
Self(self.0.into_iter().chain(items).collect())
|
Self(self.0.into_iter().chain(items).collect())
|
||||||
}
|
}
|
||||||
/// Partition the string by `::` namespace separators
|
/// Partition the string by `::` namespace separators
|
||||||
pub async fn parse(s: &str, i: &Interner) -> Self {
|
pub async fn parse(s: &str, i: &Interner) -> Self {
|
||||||
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.is(s))).await })
|
Self(if s.is_empty() { vec![] } else { join_all(s.split("::").map(|s| i.i(s))).await })
|
||||||
}
|
}
|
||||||
/// Walk over the segments
|
/// Walk over the segments
|
||||||
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> { self.0.iter().map(|s| s.as_ref()) }
|
pub fn str_iter(&self) -> impl Iterator<Item = &'_ str> {
|
||||||
|
Box::new(self.0.iter().map(|s| s.as_str()))
|
||||||
|
}
|
||||||
/// Try to convert into non-empty version
|
/// Try to convert into non-empty version
|
||||||
pub fn into_name(self) -> Result<VName, EmptyNameError> { VName::new(self.0) }
|
pub fn into_name(self) -> Result<VName, EmptyNameError> { VName::new(self.0) }
|
||||||
/// Add a token to the path. Since now we know that it can't be empty, turn it
|
/// Add a token to the path. Since now we know that it can't be empty, turn it
|
||||||
/// into a name.
|
/// into a name.
|
||||||
pub fn name_with_suffix(self, name: IStr) -> VName {
|
pub fn name_with_suffix(self, name: Tok<String>) -> VName {
|
||||||
VName(self.into_iter().chain([name]).collect())
|
VName(self.into_iter().chain([name]).collect())
|
||||||
}
|
}
|
||||||
/// Add a token to the beginning of the. Since now we know that it can't be
|
/// Add a token to the beginning of the. Since now we know that it can't be
|
||||||
/// empty, turn it into a name.
|
/// empty, turn it into a name.
|
||||||
pub fn name_with_prefix(self, name: IStr) -> VName {
|
pub fn name_with_prefix(self, name: Tok<String>) -> VName {
|
||||||
VName([name].into_iter().chain(self).collect())
|
VName([name].into_iter().chain(self).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +65,7 @@ impl VPath {
|
|||||||
pub async fn from_path(path: &Path, ext: &str, i: &Interner) -> Option<(Self, bool)> {
|
pub async fn from_path(path: &Path, ext: &str, i: &Interner) -> Option<(Self, bool)> {
|
||||||
async fn to_vpath(p: &Path, i: &Interner) -> Option<VPath> {
|
async fn to_vpath(p: &Path, i: &Interner) -> Option<VPath> {
|
||||||
let tok_opt_v =
|
let tok_opt_v =
|
||||||
join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.is(s))))).await;
|
join_all(p.iter().map(|c| OptionFuture::from(c.to_str().map(|s| i.i(s))))).await;
|
||||||
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
|
tok_opt_v.into_iter().collect::<Option<_>>().map(VPath)
|
||||||
}
|
}
|
||||||
match path.extension().map(|s| s.to_str()) {
|
match path.extension().map(|s| s.to_str()) {
|
||||||
@@ -79,28 +83,30 @@ impl fmt::Display for VPath {
|
|||||||
write!(f, "{}", self.str_iter().join("::"))
|
write!(f, "{}", self.str_iter().join("::"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl FromIterator<IStr> for VPath {
|
impl FromIterator<Tok<String>> for VPath {
|
||||||
fn from_iter<T: IntoIterator<Item = IStr>>(iter: T) -> Self { Self(iter.into_iter().collect()) }
|
fn from_iter<T: IntoIterator<Item = Tok<String>>>(iter: T) -> Self {
|
||||||
|
Self(iter.into_iter().collect())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl IntoIterator for VPath {
|
impl IntoIterator for VPath {
|
||||||
type Item = IStr;
|
type Item = Tok<String>;
|
||||||
type IntoIter = vec::IntoIter<Self::Item>;
|
type IntoIter = vec::IntoIter<Self::Item>;
|
||||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||||
}
|
}
|
||||||
impl Borrow<[IStr]> for VPath {
|
impl Borrow<[Tok<String>]> for VPath {
|
||||||
fn borrow(&self) -> &[IStr] { &self.0[..] }
|
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
|
||||||
}
|
}
|
||||||
impl Deref for VPath {
|
impl Deref for VPath {
|
||||||
type Target = [IStr];
|
type Target = [Tok<String>];
|
||||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Index<T> for VPath
|
impl<T> Index<T> for VPath
|
||||||
where [IStr]: Index<T>
|
where [Tok<String>]: Index<T>
|
||||||
{
|
{
|
||||||
type Output = <[IStr] as Index<T>>::Output;
|
type Output = <[Tok<String>] as Index<T>>::Output;
|
||||||
|
|
||||||
fn index(&self, index: T) -> &Self::Output { &Borrow::<[IStr]>::borrow(self)[index] }
|
fn index(&self, index: T) -> &Self::Output { &Borrow::<[Tok<String>]>::borrow(self)[index] }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A mutable representation of a namespaced identifier of at least one segment.
|
/// A mutable representation of a namespaced identifier of at least one segment.
|
||||||
@@ -110,11 +116,11 @@ where [IStr]: Index<T>
|
|||||||
/// See also [Sym] for the immutable representation, and [VPath] for possibly
|
/// See also [Sym] for the immutable representation, and [VPath] for possibly
|
||||||
/// empty values
|
/// empty values
|
||||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct VName(Vec<IStr>);
|
pub struct VName(Vec<Tok<String>>);
|
||||||
impl VName {
|
impl VName {
|
||||||
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
|
/// Assert that the sequence isn't empty and wrap it in [VName] to represent
|
||||||
/// this invariant
|
/// this invariant
|
||||||
pub fn new(items: impl IntoIterator<Item = IStr>) -> Result<Self, EmptyNameError> {
|
pub fn new(items: impl IntoIterator<Item = Tok<String>>) -> Result<Self, EmptyNameError> {
|
||||||
let data: Vec<_> = items.into_iter().collect();
|
let data: Vec<_> = items.into_iter().collect();
|
||||||
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
if data.is_empty() { Err(EmptyNameError) } else { Ok(Self(data)) }
|
||||||
}
|
}
|
||||||
@@ -122,27 +128,27 @@ impl VName {
|
|||||||
name: impl IntoIterator<Item = api::TStr>,
|
name: impl IntoIterator<Item = api::TStr>,
|
||||||
i: &Interner,
|
i: &Interner,
|
||||||
) -> Result<Self, EmptyNameError> {
|
) -> Result<Self, EmptyNameError> {
|
||||||
Self::new(join_all(name.into_iter().map(|m| i.es(m))).await)
|
Self::new(join_all(name.into_iter().map(|m| Tok::from_api(m, i))).await)
|
||||||
}
|
}
|
||||||
/// Unwrap the enclosed vector
|
/// Unwrap the enclosed vector
|
||||||
pub fn into_vec(self) -> Vec<IStr> { self.0 }
|
pub fn into_vec(self) -> Vec<Tok<String>> { self.0 }
|
||||||
/// Get a reference to the enclosed vector
|
/// Get a reference to the enclosed vector
|
||||||
pub fn vec(&self) -> &Vec<IStr> { &self.0 }
|
pub fn vec(&self) -> &Vec<Tok<String>> { &self.0 }
|
||||||
/// Mutable access to the underlying vector. To ensure correct results, this
|
/// Mutable access to the underlying vector. To ensure correct results, this
|
||||||
/// must never be empty.
|
/// must never be empty.
|
||||||
pub fn vec_mut(&mut self) -> &mut Vec<IStr> { &mut self.0 }
|
pub fn vec_mut(&mut self) -> &mut Vec<Tok<String>> { &mut self.0 }
|
||||||
/// Intern the name and return a [Sym]
|
/// Intern the name and return a [Sym]
|
||||||
pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.iv(&self.0[..]).await) }
|
pub async fn to_sym(&self, i: &Interner) -> Sym { Sym(i.i(&self.0[..]).await) }
|
||||||
/// If this name has only one segment, return it
|
/// If this name has only one segment, return it
|
||||||
pub fn as_root(&self) -> Option<IStr> { self.0.iter().exactly_one().ok().cloned() }
|
pub fn as_root(&self) -> Option<Tok<String>> { self.0.iter().exactly_one().ok().cloned() }
|
||||||
/// Prepend the segments to this name
|
/// Prepend the segments to this name
|
||||||
#[must_use = "This is a pure function"]
|
#[must_use = "This is a pure function"]
|
||||||
pub fn prefix(self, items: impl IntoIterator<Item = IStr>) -> Self {
|
pub fn prefix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
Self(items.into_iter().chain(self.0).collect())
|
Self(items.into_iter().chain(self.0).collect())
|
||||||
}
|
}
|
||||||
/// Append the segments to this name
|
/// Append the segments to this name
|
||||||
#[must_use = "This is a pure function"]
|
#[must_use = "This is a pure function"]
|
||||||
pub fn suffix(self, items: impl IntoIterator<Item = IStr>) -> Self {
|
pub fn suffix(self, items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
Self(self.0.into_iter().chain(items).collect())
|
Self(self.0.into_iter().chain(items).collect())
|
||||||
}
|
}
|
||||||
/// Read a `::` separated namespaced name
|
/// Read a `::` separated namespaced name
|
||||||
@@ -153,7 +159,7 @@ impl VName {
|
|||||||
Self::parse(s, i).await.expect("empty literal !?")
|
Self::parse(s, i).await.expect("empty literal !?")
|
||||||
}
|
}
|
||||||
/// Obtain an iterator over the segments of the name
|
/// Obtain an iterator over the segments of the name
|
||||||
pub fn iter(&self) -> impl Iterator<Item = IStr> + '_ { self.0.iter().cloned() }
|
pub fn iter(&self) -> impl Iterator<Item = Tok<String>> + '_ { self.0.iter().cloned() }
|
||||||
}
|
}
|
||||||
impl fmt::Debug for VName {
|
impl fmt::Debug for VName {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "VName({self})") }
|
||||||
@@ -164,22 +170,22 @@ impl fmt::Display for VName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl IntoIterator for VName {
|
impl IntoIterator for VName {
|
||||||
type Item = IStr;
|
type Item = Tok<String>;
|
||||||
type IntoIter = vec::IntoIter<Self::Item>;
|
type IntoIter = vec::IntoIter<Self::Item>;
|
||||||
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
|
||||||
}
|
}
|
||||||
impl<T> Index<T> for VName
|
impl<T> Index<T> for VName
|
||||||
where [IStr]: Index<T>
|
where [Tok<String>]: Index<T>
|
||||||
{
|
{
|
||||||
type Output = <[IStr] as Index<T>>::Output;
|
type Output = <[Tok<String>] as Index<T>>::Output;
|
||||||
|
|
||||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||||
}
|
}
|
||||||
impl Borrow<[IStr]> for VName {
|
impl Borrow<[Tok<String>]> for VName {
|
||||||
fn borrow(&self) -> &[IStr] { self.0.borrow() }
|
fn borrow(&self) -> &[Tok<String>] { self.0.borrow() }
|
||||||
}
|
}
|
||||||
impl Deref for VName {
|
impl Deref for VName {
|
||||||
type Target = [IStr];
|
type Target = [Tok<String>];
|
||||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,9 +193,11 @@ impl Deref for VName {
|
|||||||
/// empty sequence
|
/// empty sequence
|
||||||
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, Copy, Clone, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct EmptyNameError;
|
pub struct EmptyNameError;
|
||||||
impl TryFrom<&[IStr]> for VName {
|
impl TryFrom<&[Tok<String>]> for VName {
|
||||||
type Error = EmptyNameError;
|
type Error = EmptyNameError;
|
||||||
fn try_from(value: &[IStr]) -> Result<Self, Self::Error> { Self::new(value.iter().cloned()) }
|
fn try_from(value: &[Tok<String>]) -> Result<Self, Self::Error> {
|
||||||
|
Self::new(value.iter().cloned())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interned representation of a namespaced identifier.
|
/// An interned representation of a namespaced identifier.
|
||||||
@@ -198,36 +206,36 @@ impl TryFrom<&[IStr]> for VName {
|
|||||||
///
|
///
|
||||||
/// See also [VName]
|
/// See also [VName]
|
||||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Sym(IVec);
|
pub struct Sym(Tok<Vec<Tok<String>>>);
|
||||||
impl Sym {
|
impl Sym {
|
||||||
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
/// Assert that the sequence isn't empty, intern it and wrap it in a [Sym] to
|
||||||
/// represent this invariant
|
/// represent this invariant
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
v: impl IntoIterator<Item = IStr>,
|
v: impl IntoIterator<Item = Tok<String>>,
|
||||||
i: &Interner,
|
i: &Interner,
|
||||||
) -> Result<Self, EmptyNameError> {
|
) -> Result<Self, EmptyNameError> {
|
||||||
let items = v.into_iter().collect_vec();
|
let items = v.into_iter().collect_vec();
|
||||||
Self::from_tok(i.iv(&items).await)
|
Self::from_tok(i.i(&items).await)
|
||||||
}
|
}
|
||||||
/// Read a `::` separated namespaced name.
|
/// Read a `::` separated namespaced name.
|
||||||
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
pub async fn parse(s: &str, i: &Interner) -> Result<Self, EmptyNameError> {
|
||||||
Ok(Sym(i.iv(&VName::parse(s, i).await?.into_vec()).await))
|
Ok(Sym(i.i(&VName::parse(s, i).await?.into_vec()).await))
|
||||||
}
|
}
|
||||||
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
/// Assert that a token isn't empty, and wrap it in a [Sym]
|
||||||
pub fn from_tok(t: IVec) -> Result<Self, EmptyNameError> {
|
pub fn from_tok(t: Tok<Vec<Tok<String>>>) -> Result<Self, EmptyNameError> {
|
||||||
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
if t.is_empty() { Err(EmptyNameError) } else { Ok(Self(t)) }
|
||||||
}
|
}
|
||||||
/// Grab the interner token
|
/// Grab the interner token
|
||||||
pub fn tok(&self) -> IVec { self.0.clone() }
|
pub fn tok(&self) -> Tok<Vec<Tok<String>>> { self.0.clone() }
|
||||||
/// Get a number unique to this name suitable for arbitrary ordering.
|
/// Get a number unique to this name suitable for arbitrary ordering.
|
||||||
pub fn id(&self) -> NonZeroU64 { self.0.to_api().0 }
|
pub fn id(&self) -> NonZeroU64 { self.0.to_api().get_id() }
|
||||||
/// Extern the sym for editing
|
/// Extern the sym for editing
|
||||||
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
pub fn to_vname(&self) -> VName { VName(self[..].to_vec()) }
|
||||||
pub async fn from_api(marker: api::TVec, i: &Interner) -> Sym {
|
pub async fn from_api(marker: api::TStrv, i: &Interner) -> Sym {
|
||||||
Self::from_tok(i.ev(marker).await).expect("Empty sequence found for serialized Sym")
|
Self::from_tok(Tok::from_api(marker, i).await).expect("Empty sequence found for serialized Sym")
|
||||||
}
|
}
|
||||||
pub fn to_api(&self) -> api::TVec { self.tok().to_api() }
|
pub fn to_api(&self) -> api::TStrv { self.tok().to_api() }
|
||||||
pub async fn suffix(&self, tokv: impl IntoIterator<Item = IStr>, i: &Interner) -> Sym {
|
pub async fn suffix(&self, tokv: impl IntoIterator<Item = Tok<String>>, i: &Interner) -> Sym {
|
||||||
Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap()
|
Self::new(self.0.iter().cloned().chain(tokv), i).await.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,17 +248,17 @@ impl fmt::Display for Sym {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T> Index<T> for Sym
|
impl<T> Index<T> for Sym
|
||||||
where [IStr]: Index<T>
|
where [Tok<String>]: Index<T>
|
||||||
{
|
{
|
||||||
type Output = <[IStr] as Index<T>>::Output;
|
type Output = <[Tok<String>] as Index<T>>::Output;
|
||||||
|
|
||||||
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
fn index(&self, index: T) -> &Self::Output { &self.deref()[index] }
|
||||||
}
|
}
|
||||||
impl Borrow<[IStr]> for Sym {
|
impl Borrow<[Tok<String>]> for Sym {
|
||||||
fn borrow(&self) -> &[IStr] { &self.0[..] }
|
fn borrow(&self) -> &[Tok<String>] { &self.0[..] }
|
||||||
}
|
}
|
||||||
impl Deref for Sym {
|
impl Deref for Sym {
|
||||||
type Target = [IStr];
|
type Target = [Tok<String>];
|
||||||
fn deref(&self) -> &Self::Target { self.borrow() }
|
fn deref(&self) -> &Self::Target { self.borrow() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,15 +266,15 @@ impl Deref for Sym {
|
|||||||
/// handled together in datastructures. The names can never be empty
|
/// handled together in datastructures. The names can never be empty
|
||||||
#[allow(clippy::len_without_is_empty)] // never empty
|
#[allow(clippy::len_without_is_empty)] // never empty
|
||||||
pub trait NameLike:
|
pub trait NameLike:
|
||||||
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[IStr]>
|
'static + Clone + Eq + Hash + fmt::Debug + fmt::Display + Borrow<[Tok<String>]>
|
||||||
{
|
{
|
||||||
/// Convert into held slice
|
/// Convert into held slice
|
||||||
fn as_slice(&self) -> &[IStr] { Borrow::<[IStr]>::borrow(self) }
|
fn as_slice(&self) -> &[Tok<String>] { Borrow::<[Tok<String>]>::borrow(self) }
|
||||||
/// Get iterator over tokens
|
/// Get iterator over tokens
|
||||||
fn segs(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() }
|
fn segs(&self) -> impl NameIter + '_ { self.as_slice().iter().cloned() }
|
||||||
/// Get iterator over string segments
|
/// Get iterator over string segments
|
||||||
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ {
|
fn str_iter(&self) -> impl Iterator<Item = &'_ str> + '_ {
|
||||||
self.as_slice().iter().map(|t| t.as_ref())
|
self.as_slice().iter().map(|t| t.as_str())
|
||||||
}
|
}
|
||||||
/// Fully resolve the name for printing
|
/// Fully resolve the name for printing
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -278,19 +286,19 @@ pub trait NameLike:
|
|||||||
NonZeroUsize::try_from(self.segs().count()).expect("NameLike never empty")
|
NonZeroUsize::try_from(self.segs().count()).expect("NameLike never empty")
|
||||||
}
|
}
|
||||||
/// Like slice's `split_first` except we know that it always returns Some
|
/// Like slice's `split_first` except we know that it always returns Some
|
||||||
fn split_first_seg(&self) -> (IStr, &[IStr]) {
|
fn split_first_seg(&self) -> (Tok<String>, &[Tok<String>]) {
|
||||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||||
(foot.clone(), torso)
|
(foot.clone(), torso)
|
||||||
}
|
}
|
||||||
/// Like slice's `split_last` except we know that it always returns Some
|
/// Like slice's `split_last` except we know that it always returns Some
|
||||||
fn split_last_seg(&self) -> (IStr, &[IStr]) {
|
fn split_last_seg(&self) -> (Tok<String>, &[Tok<String>]) {
|
||||||
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
let (foot, torso) = self.as_slice().split_last().expect("NameLike never empty");
|
||||||
(foot.clone(), torso)
|
(foot.clone(), torso)
|
||||||
}
|
}
|
||||||
/// Get the first element
|
/// Get the first element
|
||||||
fn first_seg(&self) -> IStr { self.split_first_seg().0 }
|
fn first_seg(&self) -> Tok<String> { self.split_first_seg().0 }
|
||||||
/// Get the last element
|
/// Get the last element
|
||||||
fn last_seg(&self) -> IStr { self.split_last_seg().0 }
|
fn last_seg(&self) -> Tok<String> { self.split_last_seg().0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameLike for Sym {}
|
impl NameLike for Sym {}
|
||||||
@@ -305,9 +313,9 @@ impl NameLike for VName {}
|
|||||||
macro_rules! sym {
|
macro_rules! sym {
|
||||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||||
$crate::name::Sym::from_tok(
|
$crate::name::Sym::from_tok(
|
||||||
$i.iv(&[
|
$i.i(&[
|
||||||
$i.is(stringify!($seg1)).await
|
$i.i(stringify!($seg1)).await
|
||||||
$( , $i.is(stringify!($seg)).await )*
|
$( , $i.i(stringify!($seg)).await )*
|
||||||
])
|
])
|
||||||
.await
|
.await
|
||||||
).unwrap()
|
).unwrap()
|
||||||
@@ -323,8 +331,8 @@ macro_rules! sym {
|
|||||||
macro_rules! vname {
|
macro_rules! vname {
|
||||||
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
($seg1:tt $( :: $seg:tt)* ; $i:expr) => { async {
|
||||||
$crate::name::VName::new([
|
$crate::name::VName::new([
|
||||||
$i.is(stringify!($seg1)).await
|
$i.i(stringify!($seg1)).await
|
||||||
$( , $i.is(stringify!($seg)).await )*
|
$( , $i.i(stringify!($seg)).await )*
|
||||||
]).unwrap()
|
]).unwrap()
|
||||||
} };
|
} };
|
||||||
}
|
}
|
||||||
@@ -336,8 +344,8 @@ macro_rules! vname {
|
|||||||
macro_rules! vpath {
|
macro_rules! vpath {
|
||||||
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async {
|
($seg1:tt $( :: $seg:tt)+ ; $i:expr) => { async {
|
||||||
$crate::name::VPath(vec![
|
$crate::name::VPath(vec![
|
||||||
$i.is(stringify!($seg1)).await
|
$i.i(stringify!($seg1)).await
|
||||||
$( , $i.is(stringify!($seg)).await )+
|
$( , $i.i(stringify!($seg)).await )+
|
||||||
])
|
])
|
||||||
} };
|
} };
|
||||||
() => {
|
() => {
|
||||||
@@ -352,37 +360,35 @@ mod test {
|
|||||||
use test_executors::spin_on;
|
use test_executors::spin_on;
|
||||||
|
|
||||||
use super::{NameLike, Sym, VName};
|
use super::{NameLike, Sym, VName};
|
||||||
use crate::interner::test::DummyInterner;
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::interner::{IStr, Interner};
|
|
||||||
use crate::name::VPath;
|
use crate::name::VPath;
|
||||||
use crate::testing::AsyncMonitor;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn recur() {
|
fn recur() {
|
||||||
spin_on(async {
|
spin_on(async {
|
||||||
let i = DummyInterner::new(AsyncMonitor::default());
|
let i = Interner::new_master();
|
||||||
let myname = vname!(foo::bar; i).await;
|
let myname = vname!(foo::bar; i).await;
|
||||||
let _borrowed_slice: &[IStr] = myname.borrow();
|
let _borrowed_slice: &[Tok<String>] = myname.borrow();
|
||||||
let _deref_pathslice: &[IStr] = &myname;
|
let _deref_pathslice: &[Tok<String>] = &myname;
|
||||||
let _as_slice_out: &[IStr] = myname.as_slice();
|
let _as_slice_out: &[Tok<String>] = myname.as_slice();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn literals() {
|
fn literals() {
|
||||||
spin_on(async {
|
spin_on(async {
|
||||||
let i = DummyInterner::new(AsyncMonitor::default());
|
let i = Interner::new_master();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sym!(foo::bar::baz; i).await,
|
sym!(foo::bar::baz; i).await,
|
||||||
Sym::new([i.is("foo").await, i.is("bar").await, i.is("baz").await], &i).await.unwrap()
|
Sym::new([i.i("foo").await, i.i("bar").await, i.i("baz").await], &i).await.unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vname!(foo::bar::baz; i).await,
|
vname!(foo::bar::baz; i).await,
|
||||||
VName::new([i.is("foo").await, i.is("bar").await, i.is("baz").await]).unwrap()
|
VName::new([i.i("foo").await, i.i("bar").await, i.i("baz").await]).unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vpath!(foo::bar::baz; i).await,
|
vpath!(foo::bar::baz; i).await,
|
||||||
VPath::new([i.is("foo").await, i.is("bar").await, i.is("baz").await])
|
VPath::new([i.i("foo").await, i.i("bar").await, i.i("baz").await])
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use std::ops::Range;
|
|||||||
|
|
||||||
use ordered_float::NotNan;
|
use ordered_float::NotNan;
|
||||||
|
|
||||||
use crate::ctx::Ctx;
|
use crate::error::{OrcErrv, mk_errv};
|
||||||
use crate::error::OrcErr;
|
use crate::interner::Interner;
|
||||||
use crate::location::SrcRange;
|
use crate::location::SrcRange;
|
||||||
use crate::name::Sym;
|
use crate::name::Sym;
|
||||||
|
|
||||||
@@ -55,14 +55,14 @@ pub struct NumError {
|
|||||||
pub kind: NumErrorKind,
|
pub kind: NumErrorKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn num_to_errv(
|
pub async fn num_to_errv(
|
||||||
NumError { kind, range }: NumError,
|
NumError { kind, range }: NumError,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
source: &Sym,
|
source: &Sym,
|
||||||
ctx: &Ctx,
|
i: &Interner,
|
||||||
) -> OrcErr {
|
) -> OrcErrv {
|
||||||
ctx.mk_err(
|
mk_errv(
|
||||||
"Failed to parse number",
|
i.i("Failed to parse number").await,
|
||||||
match kind {
|
match kind {
|
||||||
NumErrorKind::NaN => "NaN emerged during parsing",
|
NumErrorKind::NaN => "NaN emerged during parsing",
|
||||||
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
NumErrorKind::InvalidDigit => "non-digit character encountered",
|
||||||
|
|||||||
@@ -1,21 +1,34 @@
|
|||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::error::{OrcErrv, OrcRes, Reporter, mk_errv};
|
||||||
use crate::error::{OrcErr, OrcRes, Reporter};
|
|
||||||
use crate::format::{FmtCtx, FmtUnit, Format, fmt};
|
use crate::format::{FmtCtx, FmtUnit, Format, fmt};
|
||||||
use crate::interner::{IStr, Interner};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::location::SrcRange;
|
use crate::location::SrcRange;
|
||||||
use crate::name::{Sym, VName, VPath};
|
use crate::name::{Sym, VName, VPath};
|
||||||
use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_fmt, ttv_range};
|
use crate::tree::{ExprRepr, ExtraTok, Paren, TokTree, Token, ttv_fmt, ttv_range};
|
||||||
|
|
||||||
|
pub trait ParseCtx {
|
||||||
|
#[must_use]
|
||||||
|
fn i(&self) -> &Interner;
|
||||||
|
#[must_use]
|
||||||
|
fn rep(&self) -> &Reporter;
|
||||||
|
}
|
||||||
|
pub struct ParseCtxImpl<'a> {
|
||||||
|
pub i: &'a Interner,
|
||||||
|
pub r: &'a Reporter,
|
||||||
|
}
|
||||||
|
impl ParseCtx for ParseCtxImpl<'_> {
|
||||||
|
fn i(&self) -> &Interner { self.i }
|
||||||
|
fn rep(&self) -> &Reporter { self.r }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
|
pub fn name_start(c: char) -> bool { c.is_alphabetic() || c == '_' }
|
||||||
pub fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() }
|
pub fn name_char(c: char) -> bool { name_start(c) || c.is_numeric() }
|
||||||
pub fn op_char(c: char) -> bool { !name_char(c) && !c.is_whitespace() && !"()[]{}\\".contains(c) }
|
pub fn op_char(c: char) -> bool { !name_char(c) && !c.is_whitespace() && !"()[]{}\\".contains(c) }
|
||||||
@@ -90,22 +103,22 @@ impl<A: ExprRepr, X: ExtraTok> Format for Snippet<'_, A, X> {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Comment {
|
pub struct Comment {
|
||||||
pub text: IStr,
|
pub text: Tok<String>,
|
||||||
pub sr: SrcRange,
|
pub sr: SrcRange,
|
||||||
}
|
}
|
||||||
impl Comment {
|
impl Comment {
|
||||||
// XXX: which of these four are actually used?
|
// XXX: which of these four are actually used?
|
||||||
pub async fn from_api(c: &api::Comment, src: Sym, cx: &Ctx) -> Self {
|
pub async fn from_api(c: &api::Comment, src: Sym, i: &Interner) -> Self {
|
||||||
Self { text: cx.i().es(c.text).await, sr: SrcRange::new(c.range.clone(), &src) }
|
Self { text: i.ex(c.text).await, sr: SrcRange::new(c.range.clone(), &src) }
|
||||||
}
|
}
|
||||||
pub async fn from_tk(tk: &TokTree<impl ExprRepr, impl ExtraTok>, cx: &Ctx) -> Option<Self> {
|
pub async fn from_tk(tk: &TokTree<impl ExprRepr, impl ExtraTok>, i: &Interner) -> Option<Self> {
|
||||||
match &tk.tok {
|
match &tk.tok {
|
||||||
Token::Comment(text) => Some(Self { text: cx.i().is(&**text).await, sr: tk.sr.clone() }),
|
Token::Comment(text) => Some(Self { text: i.i(&**text).await, sr: tk.sr.clone() }),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn to_tk<A: ExprRepr, X: ExtraTok>(&self) -> TokTree<A, X> {
|
pub fn to_tk<R: ExprRepr, X: ExtraTok>(&self) -> TokTree<R, X> {
|
||||||
TokTree { tok: Token::Comment(Rc::new(self.text.to_string())), sr: self.sr.clone() }
|
TokTree { tok: Token::Comment(self.text.rc().clone()), sr: self.sr.clone() }
|
||||||
}
|
}
|
||||||
pub fn to_api(&self) -> api::Comment {
|
pub fn to_api(&self) -> api::Comment {
|
||||||
api::Comment { range: self.sr.range(), text: self.text.to_api() }
|
api::Comment { range: self.sr.range(), text: self.text.to_api() }
|
||||||
@@ -117,7 +130,7 @@ impl fmt::Display for Comment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>(
|
pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>(
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
snip: Snippet<'a, A, X>,
|
snip: Snippet<'a, A, X>,
|
||||||
) -> Vec<Parsed<'a, Vec<Comment>, A, X>> {
|
) -> Vec<Parsed<'a, Vec<Comment>, A, X>> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
@@ -133,7 +146,7 @@ pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>(
|
|||||||
Some(i) => {
|
Some(i) => {
|
||||||
let (cmts, tail) = line.split_at(i);
|
let (cmts, tail) = line.split_at(i);
|
||||||
let comments = join_all(comments.drain(..).chain(cmts.cur).map(|t| async {
|
let comments = join_all(comments.drain(..).chain(cmts.cur).map(|t| async {
|
||||||
Comment::from_tk(t, ctx).await.expect("All are comments checked above")
|
Comment::from_tk(t, ctx.i()).await.expect("All are comments checked above")
|
||||||
}))
|
}))
|
||||||
.await;
|
.await;
|
||||||
items.push(Parsed { output: comments, tail });
|
items.push(Parsed { output: comments, tail });
|
||||||
@@ -144,50 +157,56 @@ pub async fn line_items<'a, A: ExprRepr, X: ExtraTok>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn try_pop_no_fluff<'a, A: ExprRepr, X: ExtraTok>(
|
pub async fn try_pop_no_fluff<'a, A: ExprRepr, X: ExtraTok>(
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
snip: Snippet<'a, A, X>,
|
snip: Snippet<'a, A, X>,
|
||||||
) -> ParseRes<'a, &'a TokTree<A, X>, A, X> {
|
) -> ParseRes<'a, &'a TokTree<A, X>, A, X> {
|
||||||
match snip.skip_fluff().pop_front() {
|
match snip.skip_fluff().pop_front() {
|
||||||
Some((output, tail)) => Ok(Parsed { output, tail }),
|
Some((output, tail)) => Ok(Parsed { output, tail }),
|
||||||
None => Err(
|
None => Err(mk_errv(
|
||||||
ctx.mk_err("Unexpected end", "Line ends abruptly; more tokens were expected", [snip.sr()]),
|
ctx.i().i("Unexpected end").await,
|
||||||
),
|
"Line ends abruptly; more tokens were expected",
|
||||||
|
[snip.sr()],
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn expect_end(ctx: &Ctx, snip: Snippet<'_, impl ExprRepr, impl ExtraTok>) -> OrcRes<()> {
|
pub async fn expect_end(
|
||||||
|
ctx: &impl ParseCtx,
|
||||||
|
snip: Snippet<'_, impl ExprRepr, impl ExtraTok>,
|
||||||
|
) -> OrcRes<()> {
|
||||||
match snip.skip_fluff().get(0) {
|
match snip.skip_fluff().get(0) {
|
||||||
Some(surplus) =>
|
Some(surplus) => Err(mk_errv(
|
||||||
Err(ctx.mk_err("Extra code after end of line", "Code found after the end of the line", [
|
ctx.i().i("Extra code after end of line").await,
|
||||||
surplus.sr.pos(),
|
"Code found after the end of the line",
|
||||||
])),
|
[surplus.sr.pos()],
|
||||||
|
)),
|
||||||
None => Ok(()),
|
None => Ok(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn expect_tok<'a, A: ExprRepr, X: ExtraTok>(
|
pub async fn expect_tok<'a, A: ExprRepr, X: ExtraTok>(
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
snip: Snippet<'a, A, X>,
|
snip: Snippet<'a, A, X>,
|
||||||
tok: IStr,
|
tok: Tok<String>,
|
||||||
) -> ParseRes<'a, (), A, X> {
|
) -> ParseRes<'a, (), A, X> {
|
||||||
let Parsed { output: head, tail } = try_pop_no_fluff(ctx, snip).await?;
|
let Parsed { output: head, tail } = try_pop_no_fluff(ctx, snip).await?;
|
||||||
match &head.tok {
|
match &head.tok {
|
||||||
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
|
Token::Name(n) if *n == tok => Ok(Parsed { output: (), tail }),
|
||||||
t => Err(ctx.mk_err(
|
t => Err(mk_errv(
|
||||||
"Expected specific keyword",
|
ctx.i().i("Expected specific keyword").await,
|
||||||
format!("Expected {tok} but found {:?}", fmt(t, &ctx.i()).await),
|
format!("Expected {tok} but found {:?}", fmt(t, ctx.i()).await),
|
||||||
[head.sr()],
|
[head.sr()],
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn token_errv<A: ExprRepr, X: ExtraTok>(
|
pub async fn token_errv<A: ExprRepr, X: ExtraTok>(
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
tok: &TokTree<A, X>,
|
tok: &TokTree<A, X>,
|
||||||
description: &'static str,
|
description: &'static str,
|
||||||
message: impl FnOnce(&str) -> String,
|
message: impl FnOnce(&str) -> String,
|
||||||
) -> OrcErr {
|
) -> OrcErrv {
|
||||||
ctx.mk_err(description, message(&fmt(tok, &ctx.i()).await), [tok.sr.pos()])
|
mk_errv(ctx.i().i(description).await, message(&fmt(tok, ctx.i()).await), [tok.sr.pos()])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Parsed<'a, T, H: ExprRepr, X: ExtraTok> {
|
pub struct Parsed<'a, T, H: ExprRepr, X: ExtraTok> {
|
||||||
@@ -198,12 +217,12 @@ pub struct Parsed<'a, T, H: ExprRepr, X: ExtraTok> {
|
|||||||
pub type ParseRes<'a, T, H, X> = OrcRes<Parsed<'a, T, H, X>>;
|
pub type ParseRes<'a, T, H, X> = OrcRes<Parsed<'a, T, H, X>>;
|
||||||
|
|
||||||
pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
|
pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
tail: Snippet<'a, A, X>,
|
tail: Snippet<'a, A, X>,
|
||||||
) -> ParseRes<'a, Vec<Import>, A, X> {
|
) -> ParseRes<'a, Vec<Import>, A, X> {
|
||||||
let Some((tt, tail)) = tail.skip_fluff().pop_front() else {
|
let Some((tt, tail)) = tail.skip_fluff().pop_front() else {
|
||||||
return Err(ctx.mk_err(
|
return Err(mk_errv(
|
||||||
"Expected token",
|
ctx.i().i("Expected token").await,
|
||||||
"Expected a name, a parenthesized list of names, or a globstar.",
|
"Expected a name, a parenthesized list of names, or a globstar.",
|
||||||
[tail.sr().pos()],
|
[tail.sr().pos()],
|
||||||
));
|
));
|
||||||
@@ -212,14 +231,17 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
|
|||||||
#[allow(clippy::type_complexity)] // it's an internal function
|
#[allow(clippy::type_complexity)] // it's an internal function
|
||||||
pub async fn rec<A: ExprRepr, X: ExtraTok>(
|
pub async fn rec<A: ExprRepr, X: ExtraTok>(
|
||||||
tt: &TokTree<A, X>,
|
tt: &TokTree<A, X>,
|
||||||
ctx: &Ctx,
|
ctx: &impl ParseCtx,
|
||||||
) -> OrcRes<Vec<(Vec<IStr>, Option<IStr>, SrcRange)>> {
|
) -> OrcRes<Vec<(Vec<Tok<String>>, Option<Tok<String>>, SrcRange)>> {
|
||||||
let ttpos = tt.sr.pos();
|
let ttpos = tt.sr.pos();
|
||||||
match &tt.tok {
|
match &tt.tok {
|
||||||
Token::NS(ns, body) => {
|
Token::NS(ns, body) => {
|
||||||
if !ns.starts_with(name_start) {
|
if !ns.starts_with(name_start) {
|
||||||
let err = ctx.mk_err("Unexpected name prefix", "Only names can precede ::", [ttpos]);
|
ctx.rep().report(mk_errv(
|
||||||
ctx.rep().report(err)
|
ctx.i().i("Unexpected name prefix").await,
|
||||||
|
"Only names can precede ::",
|
||||||
|
[ttpos],
|
||||||
|
))
|
||||||
};
|
};
|
||||||
let out = Box::pin(rec(body, ctx)).await?;
|
let out = Box::pin(rec(body, ctx)).await?;
|
||||||
Ok(out.into_iter().update(|i| i.0.push(ns.clone())).collect_vec())
|
Ok(out.into_iter().update(|i| i.0.push(ns.clone())).collect_vec())
|
||||||
@@ -242,9 +264,9 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
|
|||||||
Ok(o)
|
Ok(o)
|
||||||
},
|
},
|
||||||
t => {
|
t => {
|
||||||
return Err(ctx.mk_err(
|
return Err(mk_errv(
|
||||||
"Unrecognized name end",
|
ctx.i().i("Unrecognized name end").await,
|
||||||
format!("Names cannot end with {:?} tokens", fmt(t, &ctx.i()).await),
|
format!("Names cannot end with {:?} tokens", fmt(t, ctx.i()).await),
|
||||||
[ttpos],
|
[ttpos],
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@@ -263,7 +285,7 @@ pub async fn parse_multiname<'a, A: ExprRepr, X: ExtraTok>(
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
pub path: VPath,
|
pub path: VPath,
|
||||||
pub name: Option<IStr>,
|
pub name: Option<Tok<String>>,
|
||||||
pub sr: SrcRange,
|
pub sr: SrcRange,
|
||||||
}
|
}
|
||||||
impl Import {
|
impl Import {
|
||||||
@@ -274,14 +296,14 @@ impl Import {
|
|||||||
None => self.path.into_name().expect("Import cannot be empty"),
|
None => self.path.into_name().expect("Import cannot be empty"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(sr: SrcRange, path: VPath, name: IStr) -> Self {
|
pub fn new(sr: SrcRange, path: VPath, name: Tok<String>) -> Self {
|
||||||
Import { path, name: Some(name), sr }
|
Import { path, name: Some(name), sr }
|
||||||
}
|
}
|
||||||
pub fn new_glob(sr: SrcRange, path: VPath) -> Self { Import { path, name: None, sr } }
|
pub fn new_glob(sr: SrcRange, path: VPath) -> Self { Import { path, name: None, sr } }
|
||||||
}
|
}
|
||||||
impl Display for Import {
|
impl Display for Import {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}::{}", self.path, self.name.as_deref().unwrap_or("*"))
|
write!(f, "{}::{}", self.path.iter().join("::"), self.name.as_ref().map_or("*", |t| t.as_str()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,18 @@
|
|||||||
use std::any::Any;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::{BitAnd, Deref};
|
use std::ops::{BitAnd, Deref};
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use derive_destructure::destructure;
|
use derive_destructure::destructure;
|
||||||
use dyn_clone::{DynClone, clone_box};
|
use dyn_clone::{DynClone, clone_box};
|
||||||
use futures::channel::mpsc::{self, Sender};
|
use futures::channel::mpsc;
|
||||||
use futures::channel::oneshot;
|
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use futures::{AsyncBufRead, AsyncWrite, SinkExt, Stream, StreamExt};
|
use futures::{SinkExt, StreamExt};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request};
|
use orchid_api_traits::{Channel, Coding, Decode, Encode, MsgSet, Request};
|
||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
@@ -26,71 +22,6 @@ use crate::logging::Logger;
|
|||||||
|
|
||||||
pub struct Receipt<'a>(PhantomData<&'a mut ()>);
|
pub struct Receipt<'a>(PhantomData<&'a mut ()>);
|
||||||
|
|
||||||
/// This object holds an exclusive lock on the outbound pipe.
|
|
||||||
pub trait DynRequestWriter {
|
|
||||||
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite>;
|
|
||||||
/// Release the outbound pipe and wait for the response to begin.
|
|
||||||
fn get_response(self: Box<Self>) -> Pin<Box<dyn Future<Output = Box<dyn DynResponseHandle>>>>;
|
|
||||||
}
|
|
||||||
/// This object holds an exclusive lock on the inbound pipe.
|
|
||||||
pub trait DynResponseHandle {
|
|
||||||
fn reader(&mut self) -> Pin<&mut dyn AsyncBufRead>;
|
|
||||||
fn finish(self: Box<Self>) -> Pin<Box<dyn Future<Output = ()>>>;
|
|
||||||
}
|
|
||||||
/// This object holds an exclusive lock on the outbound pipe.
|
|
||||||
pub trait DynNotifWriter {
|
|
||||||
fn writer(&mut self) -> Pin<&mut dyn AsyncWrite>;
|
|
||||||
fn finish(self: Box<Self>) -> Pin<Box<dyn Future<Output = ()>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait DynClient {
|
|
||||||
fn request(&self) -> Pin<Box<dyn Future<Output = Box<dyn DynRequestWriter>>>>;
|
|
||||||
fn notif(&self) -> Pin<Box<dyn Future<Output = Box<dyn DynNotifWriter>>>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Client<T: MsgSet>(pub(crate) Rc<dyn DynClient>, pub(crate) PhantomData<T>);
|
|
||||||
impl<T: MsgSet> Client<T> {
|
|
||||||
pub async fn notify<Notif: Into<<T::Out as Channel>::Notif>>(&self, notif: Notif) {
|
|
||||||
let mut notif_writer = self.0.notif().await;
|
|
||||||
notif.into().encode(notif_writer.writer()).await;
|
|
||||||
notif_writer.finish().await;
|
|
||||||
}
|
|
||||||
pub async fn request<Req: Request + Into<<T::Out as Channel>::Req>>(
|
|
||||||
&self,
|
|
||||||
req: Req,
|
|
||||||
) -> Req::Response {
|
|
||||||
let root_req = req.into();
|
|
||||||
let mut req_writer = self.0.request().await;
|
|
||||||
root_req.encode(req_writer.writer()).await;
|
|
||||||
let mut req_hand = req_writer.get_response().await;
|
|
||||||
let res = Req::Response::decode(req_hand.reader()).await;
|
|
||||||
req_hand.finish().await;
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DuplexServerState {
|
|
||||||
pending_outbound: HashMap<u64, Box<dyn FnOnce(&mut dyn AsyncBufRead)>>,
|
|
||||||
sender: Pin<Box<dyn AsyncWrite>>,
|
|
||||||
receiver: Pin<Box<dyn AsyncBufRead>>,
|
|
||||||
}
|
|
||||||
pub enum ServerEvent<T: MsgSet> {
|
|
||||||
Notif(<T::In as Channel>::Notif),
|
|
||||||
Req(RequestHandle<T>, <T::In as Channel>::Req),
|
|
||||||
}
|
|
||||||
pub async fn run_duplex_server<T: MsgSet>(
|
|
||||||
sender: Pin<Box<dyn AsyncWrite>>,
|
|
||||||
receiver: Pin<Box<dyn AsyncBufRead>>,
|
|
||||||
) -> (impl Stream<Item = ServerEvent<T>>, Client<T>) {
|
|
||||||
let sender = Rc::new(Mutex::new(sender));
|
|
||||||
let receiver = Rc::new(Mutex::new(receiver));
|
|
||||||
let pending_outbound = Rc::new(Mutex::new(HashMap::new()));
|
|
||||||
}
|
|
||||||
pub struct DuplexServer(Rc<Mutex<DuplexServerState>>);
|
|
||||||
impl DuplexServer {
|
|
||||||
pub fn receive(msg: )
|
|
||||||
}
|
|
||||||
|
|
||||||
trait_set! {
|
trait_set! {
|
||||||
pub trait SendFn<T: MsgSet> =
|
pub trait SendFn<T: MsgSet> =
|
||||||
for<'a> FnMut(&'a [u8], ReqNot<T>) -> LocalBoxFuture<'a, ()>
|
for<'a> FnMut(&'a [u8], ReqNot<T>) -> LocalBoxFuture<'a, ()>
|
||||||
@@ -109,32 +40,27 @@ fn get_id(message: &[u8]) -> (u64, &[u8]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait ReqHandlish {
|
pub trait ReqHandlish {
|
||||||
fn defer_drop(&self, val: impl Any + 'static)
|
fn defer(&self, cb: impl Future<Output = ()> + 'static)
|
||||||
where Self: Sized {
|
where Self: Sized {
|
||||||
self.defer_drop_objsafe(Box::new(val));
|
self.defer_objsafe(Box::pin(cb));
|
||||||
}
|
}
|
||||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>);
|
fn defer_objsafe(&self, val: Pin<Box<dyn Future<Output = ()>>>);
|
||||||
}
|
}
|
||||||
impl ReqHandlish for &'_ dyn ReqHandlish {
|
impl ReqHandlish for &'_ dyn ReqHandlish {
|
||||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>) { (**self).defer_drop_objsafe(val) }
|
fn defer_objsafe(&self, val: Pin<Box<dyn Future<Output = ()>>>) { (**self).defer_objsafe(val) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
pub struct RequestHandle<MS: MsgSet> {
|
pub struct RequestHandle<'a, MS: MsgSet> {
|
||||||
defer_drop: RefCell<Vec<Box<dyn Any>>>,
|
defer: RefCell<Vec<Pin<Box<dyn Future<Output = ()>>>>>,
|
||||||
fulfilled: AtomicBool,
|
fulfilled: AtomicBool,
|
||||||
id: u64,
|
id: u64,
|
||||||
|
_reqlt: PhantomData<&'a mut ()>,
|
||||||
parent: ReqNot<MS>,
|
parent: ReqNot<MS>,
|
||||||
}
|
}
|
||||||
impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
|
impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
|
||||||
fn new(parent: ReqNot<MS>, id: u64) -> Self {
|
fn new(parent: ReqNot<MS>, id: u64) -> Self {
|
||||||
Self {
|
Self { defer: RefCell::default(), fulfilled: false.into(), _reqlt: PhantomData, parent, id }
|
||||||
defer_drop: RefCell::default(),
|
|
||||||
fulfilled: false.into(),
|
|
||||||
_reqlt: PhantomData,
|
|
||||||
parent,
|
|
||||||
id,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
|
pub fn reqnot(&self) -> ReqNot<MS> { self.parent.clone() }
|
||||||
pub async fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt<'a> {
|
pub async fn handle<U: Request>(&self, _: &U, rep: &U::Response) -> Receipt<'a> {
|
||||||
@@ -150,13 +76,19 @@ impl<'a, MS: MsgSet + 'static> RequestHandle<'a, MS> {
|
|||||||
response.encode(Pin::new(&mut buf)).await;
|
response.encode(Pin::new(&mut buf)).await;
|
||||||
let mut send = clone_box(&*self.reqnot().0.lock().await.send);
|
let mut send = clone_box(&*self.reqnot().0.lock().await.send);
|
||||||
(send)(&buf, self.parent.clone()).await;
|
(send)(&buf, self.parent.clone()).await;
|
||||||
|
let deferred = mem::take(&mut *self.defer.borrow_mut());
|
||||||
|
for item in deferred {
|
||||||
|
item.await
|
||||||
|
}
|
||||||
Receipt(PhantomData)
|
Receipt(PhantomData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
|
impl<MS: MsgSet> ReqHandlish for RequestHandle<'_, MS> {
|
||||||
fn defer_drop_objsafe(&self, val: Box<dyn Any>) { self.defer_drop.borrow_mut().push(val); }
|
fn defer_objsafe(&self, val: Pin<Box<dyn Future<Output = ()>>>) {
|
||||||
|
self.defer.borrow_mut().push(val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<MS: MsgSet> Drop for RequestHandle<MS> {
|
impl<MS: MsgSet> Drop for RequestHandle<'_, MS> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let done = self.fulfilled.load(Ordering::Relaxed);
|
let done = self.fulfilled.load(Ordering::Relaxed);
|
||||||
debug_assert!(done, "Request {} dropped without response", self.id)
|
debug_assert!(done, "Request {} dropped without response", self.id)
|
||||||
@@ -190,7 +122,7 @@ impl<T: MsgSet> ReqNot<T> {
|
|||||||
notif: impl NotifFn<T>,
|
notif: impl NotifFn<T>,
|
||||||
req: impl ReqFn<T>,
|
req: impl ReqFn<T>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let this = Self(
|
Self(
|
||||||
Arc::new(Mutex::new(ReqNotData {
|
Arc::new(Mutex::new(ReqNotData {
|
||||||
id: 1,
|
id: 1,
|
||||||
send: Box::new(send),
|
send: Box::new(send),
|
||||||
@@ -199,13 +131,7 @@ impl<T: MsgSet> ReqNot<T> {
|
|||||||
responses: HashMap::new(),
|
responses: HashMap::new(),
|
||||||
})),
|
})),
|
||||||
logger,
|
logger,
|
||||||
);
|
)
|
||||||
let (sig_send, sig_recv) = std::sync::mpsc::sync_channel(0);
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
std::thread::sleep(Duration::from_secs(10));
|
|
||||||
sig_send.send(()).expect("Crash!");
|
|
||||||
});
|
|
||||||
this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Can be called from a polling thread or dispatched in any other way
|
/// Can be called from a polling thread or dispatched in any other way
|
||||||
@@ -309,7 +235,10 @@ impl<This: DynRequester + ?Sized> Requester for This {
|
|||||||
async fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response {
|
async fn request<R: Request + Into<Self::Transfer>>(&self, data: R) -> R::Response {
|
||||||
let req = format!("{data:?}");
|
let req = format!("{data:?}");
|
||||||
let rep = R::Response::decode(Pin::new(&mut &self.raw_request(data.into()).await[..])).await;
|
let rep = R::Response::decode(Pin::new(&mut &self.raw_request(data.into()).await[..])).await;
|
||||||
writeln!(self.logger(), "Request {req} got response {rep:?}");
|
let req_str = req.to_string();
|
||||||
|
if !req_str.starts_with("AtomPrint") && !req_str.starts_with("ExtAtomPrint") {
|
||||||
|
writeln!(self.logger(), "Request {req} got response {rep:?}");
|
||||||
|
}
|
||||||
rep
|
rep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
#![cfg(any(feature = "mocks", test))]
|
|
||||||
|
|
||||||
use std::future::ready;
|
|
||||||
use std::pin::Pin;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct AsyncMonitor<E: 'static>(Rc<dyn Fn(E) -> Pin<Box<dyn Future<Output = ()>>>>);
|
|
||||||
impl<E: 'static> AsyncMonitor<E> {
|
|
||||||
pub fn new<F: AsyncFn(E) -> () + 'static>(f: F) -> Self {
|
|
||||||
let f_rc = Rc::new(f);
|
|
||||||
AsyncMonitor(Rc::new(move |e| {
|
|
||||||
let f_rc = f_rc.clone();
|
|
||||||
Box::pin(async move { f_rc(e).await })
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
pub async fn notify(&self, e: E) -> () { (self.0)(e).await }
|
|
||||||
}
|
|
||||||
impl<E: 'static> Default for AsyncMonitor<E> {
|
|
||||||
fn default() -> Self { Self(Rc::new(|_| Box::pin(ready(())))) }
|
|
||||||
}
|
|
||||||
impl<E: 'static> Clone for AsyncMonitor<E> {
|
|
||||||
fn clone(&self) -> Self { Self(self.0.clone()) }
|
|
||||||
}
|
|
||||||
@@ -12,9 +12,9 @@ use never::Never;
|
|||||||
use orchid_api_traits::Coding;
|
use orchid_api_traits::Coding;
|
||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
|
|
||||||
use crate::error::OwnedOrcErr;
|
use crate::error::OrcErrv;
|
||||||
use crate::format::{FmtCtx, FmtUnit, Format, Variants};
|
use crate::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||||
use crate::interner::{IStr, Interner};
|
use crate::interner::{Interner, Tok};
|
||||||
use crate::location::{Pos, SrcRange};
|
use crate::location::{Pos, SrcRange};
|
||||||
use crate::name::{Sym, VName, VPath};
|
use crate::name::{Sym, VName, VPath};
|
||||||
use crate::parse::Snippet;
|
use crate::parse::Snippet;
|
||||||
@@ -113,11 +113,11 @@ impl<H: ExprRepr, X: ExtraTok> TokTree<H, X> {
|
|||||||
let pos = SrcRange::new(tt.range.clone(), src);
|
let pos = SrcRange::new(tt.range.clone(), src);
|
||||||
let tok = match_mapping!(&tt.token, api::Token => Token::<H, X> {
|
let tok = match_mapping!(&tt.token, api::Token => Token::<H, X> {
|
||||||
BR,
|
BR,
|
||||||
NS(n => i.es(*n).await,
|
NS(n => Tok::from_api(*n, i).await,
|
||||||
b => Box::new(Self::from_api(b, hctx, xctx, src, i).boxed_local().await)),
|
b => Box::new(Self::from_api(b, hctx, xctx, src, i).boxed_local().await)),
|
||||||
Bottom(e => OwnedOrcErr::from_api(e, i).await),
|
Bottom(e => OrcErrv::from_api(e, i).await),
|
||||||
LambdaHead(arg => Box::new(Self::from_api(arg, hctx, xctx, src, i).boxed_local().await)),
|
LambdaHead(arg => Box::new(Self::from_api(arg, hctx, xctx, src, i).boxed_local().await)),
|
||||||
Name(n => i.es(*n).await),
|
Name(n => Tok::from_api(*n, i).await),
|
||||||
S(*par, b => ttv_from_api(b, hctx, xctx, src, i).await),
|
S(*par, b => ttv_from_api(b, hctx, xctx, src, i).await),
|
||||||
Comment(c.clone()),
|
Comment(c.clone()),
|
||||||
NewExpr(expr => X::from_api(expr, xctx, pos.clone(), i).await),
|
NewExpr(expr => X::from_api(expr, xctx, pos.clone(), i).await),
|
||||||
@@ -145,8 +145,8 @@ impl<H: ExprRepr, X: ExtraTok> TokTree<H, X> {
|
|||||||
api::TokenTree { range: self.sr.range.clone(), token }
|
api::TokenTree { range: self.sr.range.clone(), token }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_kw(&self, tk: IStr) -> bool { self.tok.is_kw(tk) }
|
pub fn is_kw(&self, tk: Tok<String>) -> bool { self.tok.is_kw(tk) }
|
||||||
pub fn as_name(&self) -> Option<IStr> {
|
pub fn as_name(&self) -> Option<Tok<String>> {
|
||||||
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
|
if let Token::Name(n) = &self.tok { Some(n.clone()) } else { None }
|
||||||
}
|
}
|
||||||
pub fn as_multiname(&self) -> Result<VName, &TokTree<H, X>> {
|
pub fn as_multiname(&self) -> Result<VName, &TokTree<H, X>> {
|
||||||
@@ -245,9 +245,9 @@ pub enum Token<H: ExprRepr, X: ExtraTok> {
|
|||||||
/// stretches to the end of the enclosing parens or the end of the const line
|
/// stretches to the end of the enclosing parens or the end of the const line
|
||||||
LambdaHead(Box<TokTree<H, X>>),
|
LambdaHead(Box<TokTree<H, X>>),
|
||||||
/// A binding, operator, or a segment of a namespaced::name
|
/// A binding, operator, or a segment of a namespaced::name
|
||||||
Name(IStr),
|
Name(Tok<String>),
|
||||||
/// A namespace prefix, like `my_ns::` followed by a token
|
/// A namespace prefix, like `my_ns::` followed by a token
|
||||||
NS(IStr, Box<TokTree<H, X>>),
|
NS(Tok<String>, Box<TokTree<H, X>>),
|
||||||
/// A line break
|
/// A line break
|
||||||
BR,
|
BR,
|
||||||
/// `()`, `[]`, or `{}`
|
/// `()`, `[]`, or `{}`
|
||||||
@@ -259,11 +259,11 @@ pub enum Token<H: ExprRepr, X: ExtraTok> {
|
|||||||
/// A grammar error emitted by a lexer plugin if it was possible to continue
|
/// A grammar error emitted by a lexer plugin if it was possible to continue
|
||||||
/// reading. Parsers should treat it as an atom unless it prevents parsing,
|
/// reading. Parsers should treat it as an atom unless it prevents parsing,
|
||||||
/// in which case both this and a relevant error should be returned.
|
/// in which case both this and a relevant error should be returned.
|
||||||
Bottom(OwnedOrcErr),
|
Bottom(OrcErrv),
|
||||||
}
|
}
|
||||||
impl<H: ExprRepr, X: ExtraTok> Token<H, X> {
|
impl<H: ExprRepr, X: ExtraTok> Token<H, X> {
|
||||||
pub fn at(self, sr: SrcRange) -> TokTree<H, X> { TokTree { sr, tok: self } }
|
pub fn at(self, sr: SrcRange) -> TokTree<H, X> { TokTree { sr, tok: self } }
|
||||||
pub fn is_kw(&self, tk: IStr) -> bool { matches!(self, Token::Name(n) if *n == tk) }
|
pub fn is_kw(&self, tk: Tok<String>) -> bool { matches!(self, Token::Name(n) if *n == tk) }
|
||||||
pub fn as_s(&self, par: Paren) -> Option<&[TokTree<H, X>]> {
|
pub fn as_s(&self, par: Paren) -> Option<&[TokTree<H, X>]> {
|
||||||
match self {
|
match self {
|
||||||
Self::S(p, b) if *p == par => Some(b),
|
Self::S(p, b) if *p == par => Some(b),
|
||||||
@@ -275,7 +275,8 @@ impl<H: ExprRepr, X: ExtraTok> Format for Token<H, X> {
|
|||||||
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
async fn print<'a>(&'a self, c: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
match self {
|
match self {
|
||||||
Self::BR => "\n".to_string().into(),
|
Self::BR => "\n".to_string().into(),
|
||||||
Self::Bottom(err) => format!("Botttom({}) ", indent(&err.to_string())).into(),
|
Self::Bottom(err) if err.len() == 1 => format!("Bottom({}) ", err.one().unwrap()).into(),
|
||||||
|
Self::Bottom(err) => format!("Botttom(\n{}) ", indent(&err.to_string())).into(),
|
||||||
Self::Comment(c) => format!("--[{c}]--").into(),
|
Self::Comment(c) => format!("--[{c}]--").into(),
|
||||||
Self::LambdaHead(arg) =>
|
Self::LambdaHead(arg) =>
|
||||||
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("\\{0b}.")))
|
tl_cache!(Rc<Variants>: Rc::new(Variants::default().bounded("\\{0b}.")))
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ pub enum Loaded {
|
|||||||
Code(Arc<String>),
|
Code(Arc<String>),
|
||||||
/// Conceptually equivalent to the list of *.orc files in a folder, without
|
/// Conceptually equivalent to the list of *.orc files in a folder, without
|
||||||
/// the extension
|
/// the extension
|
||||||
Collection(Arc<Vec<IStr>>),
|
Collection(Arc<Vec<Tok<String>>>),
|
||||||
}
|
}
|
||||||
impl Loaded {
|
impl Loaded {
|
||||||
/// Is the loaded item source code (not a collection)?
|
/// Is the loaded item source code (not a collection)?
|
||||||
pub fn is_code(&self) -> bool { matches!(self, Loaded::Code(_)) }
|
pub fn is_code(&self) -> bool { matches!(self, Loaded::Code(_)) }
|
||||||
/// Collect the elements in a collection rreport
|
/// Collect the elements in a collection rreport
|
||||||
pub fn collection(items: impl IntoIterator<Item = IStr>) -> Self {
|
pub fn collection(items: impl IntoIterator<Item = Tok<String>>) -> Self {
|
||||||
Self::Collection(Arc::new(items.into_iter().collect()))
|
Self::Collection(Arc::new(items.into_iter().collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ impl ErrorSansOrigin for CodeNotFound {
|
|||||||
/// formats and other sources for libraries and dependencies.
|
/// formats and other sources for libraries and dependencies.
|
||||||
pub trait VirtFS {
|
pub trait VirtFS {
|
||||||
/// Implementation of [VirtFS::read]
|
/// Implementation of [VirtFS::read]
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult;
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult;
|
||||||
/// Discover information about a path without reading it.
|
/// Discover information about a path without reading it.
|
||||||
///
|
///
|
||||||
/// Implement this if your vfs backend can do expensive operations
|
/// Implement this if your vfs backend can do expensive operations
|
||||||
@@ -68,7 +68,7 @@ pub trait VirtFS {
|
|||||||
}
|
}
|
||||||
/// Convert a path into a human-readable string that is meaningful in the
|
/// Convert a path into a human-readable string that is meaningful in the
|
||||||
/// target context.
|
/// target context.
|
||||||
fn display(&self, path: &[IStr]) -> Option<String>;
|
fn display(&self, path: &[Tok<String>]) -> Option<String>;
|
||||||
/// Convert the FS handler into a type-erased version of itself for packing in
|
/// Convert the FS handler into a type-erased version of itself for packing in
|
||||||
/// a tree.
|
/// a tree.
|
||||||
fn rc(self) -> Rc<dyn VirtFS>
|
fn rc(self) -> Rc<dyn VirtFS>
|
||||||
@@ -81,15 +81,15 @@ pub trait VirtFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtFS for &dyn VirtFS {
|
impl VirtFS for &dyn VirtFS {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
(*self).get(path, full_path)
|
(*self).get(path, full_path)
|
||||||
}
|
}
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> { (*self).display(path) }
|
fn display(&self, path: &[Tok<String>]) -> Option<String> { (*self).display(path) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: VirtFS + ?Sized> VirtFS for Rc<T> {
|
impl<T: VirtFS + ?Sized> VirtFS for Rc<T> {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
(**self).get(path, full_path)
|
(**self).get(path, full_path)
|
||||||
}
|
}
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> { (**self).display(path) }
|
fn display(&self, path: &[Tok<String>]) -> Option<String> { (**self).display(path) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ impl<'a> Combine for &'a dyn VirtFS {
|
|||||||
pub type DeclTree = ModEntry<Rc<dyn VirtFS>, (), ()>;
|
pub type DeclTree = ModEntry<Rc<dyn VirtFS>, (), ()>;
|
||||||
|
|
||||||
impl VirtFS for DeclTree {
|
impl VirtFS for DeclTree {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
match &self.member {
|
match &self.member {
|
||||||
ModMember::Item(it) => it.get(path, full_path),
|
ModMember::Item(it) => it.get(path, full_path),
|
||||||
ModMember::Sub(module) => match path.split_first() {
|
ModMember::Sub(module) => match path.split_first() {
|
||||||
@@ -44,7 +44,7 @@ impl VirtFS for DeclTree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> {
|
fn display(&self, path: &[Tok<String>]) -> Option<String> {
|
||||||
let (head, tail) = path.split_first()?;
|
let (head, tail) = path.split_first()?;
|
||||||
match &self.member {
|
match &self.member {
|
||||||
ModMember::Item(it) => it.display(path),
|
ModMember::Item(it) => it.display(path),
|
||||||
@@ -54,16 +54,16 @@ impl VirtFS for DeclTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtFS for String {
|
impl VirtFS for String {
|
||||||
fn display(&self, _: &[IStr]) -> Option<String> { None }
|
fn display(&self, _: &[Tok<String>]) -> Option<String> { None }
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
(path.is_empty().then(|| Loaded::Code(Arc::new(self.as_str().to_string()))))
|
(path.is_empty().then(|| Loaded::Code(Arc::new(self.as_str().to_string()))))
|
||||||
.ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())
|
.ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VirtFS for &'a str {
|
impl<'a> VirtFS for &'a str {
|
||||||
fn display(&self, _: &[IStr]) -> Option<String> { None }
|
fn display(&self, _: &[Tok<String>]) -> Option<String> { None }
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
(path.is_empty().then(|| Loaded::Code(Arc::new(self.to_string()))))
|
(path.is_empty().then(|| Loaded::Code(Arc::new(self.to_string()))))
|
||||||
.ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())
|
.ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,14 +99,14 @@ impl DirNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_pathbuf(&self, path: &[IStr]) -> PathBuf {
|
fn mk_pathbuf(&self, path: &[Tok<String>]) -> PathBuf {
|
||||||
let mut fpath = self.root.clone();
|
let mut fpath = self.root.clone();
|
||||||
path.iter().for_each(|seg| fpath.push(seg.as_str()));
|
path.iter().for_each(|seg| fpath.push(seg.as_str()));
|
||||||
fpath
|
fpath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl VirtFS for DirNode {
|
impl VirtFS for DirNode {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
let fpath = self.mk_pathbuf(path);
|
let fpath = self.mk_pathbuf(path);
|
||||||
let mut binding = self.cached.borrow_mut();
|
let mut binding = self.cached.borrow_mut();
|
||||||
let (_, res) = (binding.raw_entry_mut().from_key(&fpath))
|
let (_, res) = (binding.raw_entry_mut().from_key(&fpath))
|
||||||
@@ -114,7 +114,7 @@ impl VirtFS for DirNode {
|
|||||||
res.clone()
|
res.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> {
|
fn display(&self, path: &[Tok<String>]) -> Option<String> {
|
||||||
let pathbuf = self.mk_pathbuf(path).with_extension(self.ext());
|
let pathbuf = self.mk_pathbuf(path).with_extension(self.ext());
|
||||||
Some(pathbuf.to_string_lossy().to_string())
|
Some(pathbuf.to_string_lossy().to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ impl EmbeddedFS {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtFS for EmbeddedFS {
|
impl VirtFS for EmbeddedFS {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> FSResult {
|
||||||
if path.is_empty() {
|
if path.is_empty() {
|
||||||
return Ok(Loaded::collection(self.tree.keys(|_| true)));
|
return Ok(Loaded::collection(self.tree.keys(|_| true)));
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ impl VirtFS for EmbeddedFS {
|
|||||||
ModMember::Sub(sub) => Loaded::collection(sub.keys(|_| true)),
|
ModMember::Sub(sub) => Loaded::collection(sub.keys(|_| true)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> {
|
fn display(&self, path: &[Tok<String>]) -> Option<String> {
|
||||||
let Self { gen, suffix, .. } = self;
|
let Self { gen, suffix, .. } = self;
|
||||||
Some(format!("{}{suffix} in {gen}", path.iter().join("/")))
|
Some(format!("{}{suffix} in {gen}", path.iter().join("/")))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,18 +21,18 @@ impl<'a> PrefixFS<'a> {
|
|||||||
add: VPath::parse(add.as_ref()),
|
add: VPath::parse(add.as_ref()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn proc_path(&self, path: &[IStr]) -> Option<Vec<IStr>> {
|
fn proc_path(&self, path: &[Tok<String>]) -> Option<Vec<Tok<String>>> {
|
||||||
let path = path.strip_prefix(self.remove.as_slice())?;
|
let path = path.strip_prefix(self.remove.as_slice())?;
|
||||||
Some(self.add.0.iter().chain(path).cloned().collect_vec())
|
Some(self.add.0.iter().chain(path).cloned().collect_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'a> VirtFS for PrefixFS<'a> {
|
impl<'a> VirtFS for PrefixFS<'a> {
|
||||||
fn get(&self, path: &[IStr], full_path: &PathSlice) -> super::FSResult {
|
fn get(&self, path: &[Tok<String>], full_path: &PathSlice) -> super::FSResult {
|
||||||
let path =
|
let path =
|
||||||
self.proc_path(path).ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())?;
|
self.proc_path(path).ok_or_else(|| CodeNotFound::new(full_path.to_vpath()).pack())?;
|
||||||
self.wrapped.get(&path, full_path)
|
self.wrapped.get(&path, full_path)
|
||||||
}
|
}
|
||||||
fn display(&self, path: &[IStr]) -> Option<String> {
|
fn display(&self, path: &[Tok<String>]) -> Option<String> {
|
||||||
self.wrapped.display(&self.proc_path(path)?)
|
self.wrapped.display(&self.proc_path(path)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ use futures::{AsyncRead, AsyncWrite, FutureExt, StreamExt, stream};
|
|||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
|
use orchid_api_traits::{Coding, Decode, Encode, Request, enc_vec};
|
||||||
use orchid_base::clone;
|
use orchid_base::clone;
|
||||||
use orchid_base::ctx::Ctx;
|
use orchid_base::error::{OrcErrv, OrcRes, mk_errv, mk_errv_floating};
|
||||||
use orchid_base::error::{OrcErr, OrcRes};
|
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -136,10 +135,12 @@ pub struct NotTypAtom {
|
|||||||
pub ctx: SysCtx,
|
pub ctx: SysCtx,
|
||||||
}
|
}
|
||||||
impl NotTypAtom {
|
impl NotTypAtom {
|
||||||
pub fn mk_err(&self, ctx: &Ctx) -> OrcErr {
|
pub async fn mk_err(&self) -> OrcErrv {
|
||||||
ctx.mk_err("Not the expected type", format!("This expression is not a {}", self.typ.name()), [
|
mk_errv(
|
||||||
self.pos.clone(),
|
self.ctx.i().i("Not the expected type").await,
|
||||||
])
|
format!("This expression is not a {}", self.typ.name()),
|
||||||
|
[self.pos.clone()],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,10 +329,10 @@ impl Format for AtomFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err_not_callable(cx: &Ctx) -> OrcErr {
|
pub async fn err_not_callable(i: &Interner) -> OrcErrv {
|
||||||
cx.mk_err_floating("This atom is not callable", "Attempted to apply value as function")
|
mk_errv_floating(i.i("This atom is not callable").await, "Attempted to apply value as function")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err_not_command(cx: &Ctx) -> OrcErr {
|
pub async fn err_not_command(i: &Interner) -> OrcErrv {
|
||||||
cx.mk_err_floating("This atom is not a command", "Settled on an inactionable value")
|
mk_errv_floating(i.i("This atom is not a command").await, "Settled on an inactionable value")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use std::sync::atomic::AtomicU64;
|
|||||||
|
|
||||||
use async_lock::{RwLock, RwLockReadGuard};
|
use async_lock::{RwLock, RwLockReadGuard};
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
|
use dyn_clone::{DynClone, clone_box};
|
||||||
use futures::future::{LocalBoxFuture, ready};
|
use futures::future::{LocalBoxFuture, ready};
|
||||||
use futures::{AsyncRead, AsyncWrite, FutureExt};
|
use futures::{AsyncRead, AsyncWrite, FutureExt};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -15,7 +16,7 @@ use memo_map::MemoMap;
|
|||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_api_traits::{Decode, Encode, enc_vec};
|
use orchid_api_traits::{Decode, Encode, enc_vec};
|
||||||
use orchid_base::error::OrcRes;
|
use orchid_base::error::OrcRes;
|
||||||
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit};
|
use orchid_base::format::{FmtCtx, FmtCtxImpl, FmtUnit, take_first};
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
@@ -39,8 +40,10 @@ impl<A: OwnedAtom + Atomic<Variant = OwnedVariant>> AtomicFeaturesImpl<OwnedVari
|
|||||||
let (typ_id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
let (typ_id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
||||||
let mut data = enc_vec(&typ_id).await;
|
let mut data = enc_vec(&typ_id).await;
|
||||||
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
self.encode(Pin::<&mut Vec<u8>>::new(&mut data)).await;
|
||||||
ctx.get_or_default::<ObjStore>().objects.read().await.insert(atom_id, Box::new(self));
|
let g = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
api::Atom { drop: Some(atom_id), data, owner: ctx.sys_id() }
|
g.insert(atom_id, Box::new(self));
|
||||||
|
std::mem::drop(g);
|
||||||
|
api::Atom { drop: Some(atom_id), data: api::AtomData(data), owner: ctx.sys_id() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
|
fn _info() -> Self::_Info { OwnedAtomDynfo { msbuild: A::reg_reqs(), ms: OnceCell::new() } }
|
||||||
@@ -55,8 +58,10 @@ pub(crate) struct AtomReadGuard<'a> {
|
|||||||
impl<'a> AtomReadGuard<'a> {
|
impl<'a> AtomReadGuard<'a> {
|
||||||
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
async fn new(id: api::AtomId, ctx: &'a SysCtx) -> Self {
|
||||||
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
let guard = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
let valid = guard.iter().map(|i| i.0).collect_vec();
|
if guard.get(&id).is_none() {
|
||||||
assert!(guard.get(&id).is_some(), "Received invalid atom ID: {id:?} not in {valid:?}");
|
let valid = guard.iter().map(|i| i.0).collect_vec();
|
||||||
|
panic!("Received invalid atom ID: {id:?} not in {valid:?}");
|
||||||
|
}
|
||||||
Self { id, guard }
|
Self { id, guard }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -257,7 +262,7 @@ fn assert_serializable<T: OwnedAtom>() {
|
|||||||
assert_ne!(TypeId::of::<T::Refs>(), TypeId::of::<Never>(), "{MSG}");
|
assert_ne!(TypeId::of::<T::Refs>(), TypeId::of::<Never>(), "{MSG}");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DynOwnedAtom: 'static {
|
pub trait DynOwnedAtom: DynClone + 'static {
|
||||||
fn atom_tid(&self) -> TypeId;
|
fn atom_tid(&self) -> TypeId;
|
||||||
fn as_any_ref(&self) -> &dyn Any;
|
fn as_any_ref(&self) -> &dyn Any;
|
||||||
fn encode<'a>(&'a self, buffer: Pin<&'a mut dyn AsyncWrite>) -> LocalBoxFuture<'a, ()>;
|
fn encode<'a>(&'a self, buffer: Pin<&'a mut dyn AsyncWrite>) -> LocalBoxFuture<'a, ()>;
|
||||||
@@ -306,16 +311,38 @@ impl<T: OwnedAtom> DynOwnedAtom for T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ObjStore {
|
pub(crate) struct ObjStore {
|
||||||
next_id: AtomicU64,
|
pub(crate) next_id: AtomicU64,
|
||||||
objects: RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
pub(crate) objects: RwLock<MemoMap<api::AtomId, Box<dyn DynOwnedAtom>>>,
|
||||||
}
|
}
|
||||||
impl SysCtxEntry for ObjStore {}
|
impl SysCtxEntry for ObjStore {}
|
||||||
|
|
||||||
pub async fn own<A: OwnedAtom>(typ: TypAtom<A>) -> A {
|
pub async fn own<A: OwnedAtom>(typ: TypAtom<A>) -> A {
|
||||||
let ctx = typ.untyped.ctx();
|
let ctx = typ.untyped.ctx();
|
||||||
let g = ctx.get_or_default::<ObjStore>().objects.read().await;
|
let g = ctx.get_or_default::<ObjStore>().objects.read().await;
|
||||||
let dyn_atom = (g.get(&typ.untyped.atom.drop.expect("Owned atoms always have a drop ID")))
|
let atom_id = typ.untyped.atom.drop.expect("Owned atoms always have a drop ID");
|
||||||
.expect("Atom ID invalid; atom type probably not owned by this crate");
|
let dyn_atom =
|
||||||
|
g.get(&atom_id).expect("Atom ID invalid; atom type probably not owned by this crate");
|
||||||
dyn_atom.as_any_ref().downcast_ref().cloned().expect("The ID should imply a type as well")
|
dyn_atom.as_any_ref().downcast_ref().cloned().expect("The ID should imply a type as well")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn debug_print_obj_store(ctx: &SysCtx, show_atoms: bool) {
|
||||||
|
let store = ctx.get_or_default::<ObjStore>();
|
||||||
|
let keys = store.objects.read().await.keys().cloned().collect_vec();
|
||||||
|
let mut message = "Atoms in store:".to_string();
|
||||||
|
if !show_atoms {
|
||||||
|
message += &keys.iter().map(|k| format!(" {:?}", k)).join("");
|
||||||
|
} else {
|
||||||
|
for k in keys {
|
||||||
|
let g = store.objects.read().await;
|
||||||
|
let Some(atom) = g.get(&k) else {
|
||||||
|
message += &format!("\n{k:?} has since been deleted");
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let atom = clone_box(&**atom);
|
||||||
|
std::mem::drop(g);
|
||||||
|
message += &format!("\n{k:?} -> {}", take_first(&atom.dyn_print(ctx.clone()).await, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eprintln!("{message}")
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ impl<A: ThinAtom + Atomic<Variant = ThinVariant>> AtomicFeaturesImpl<ThinVariant
|
|||||||
let (id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
let (id, _) = get_info::<A>(ctx.get::<CtedObj>().inst().card());
|
||||||
let mut buf = enc_vec(&id).await;
|
let mut buf = enc_vec(&id).await;
|
||||||
self.encode(Pin::new(&mut buf)).await;
|
self.encode(Pin::new(&mut buf)).await;
|
||||||
api::Atom { drop: None, data: buf, owner: ctx.sys_id() }
|
api::Atom { drop: None, data: api::AtomData(buf), owner: ctx.sys_id() }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } }
|
fn _info() -> Self::_Info { ThinAtomDynfo { msbuild: Self::reg_reqs(), ms: OnceCell::new() } }
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, mk_err};
|
use orchid_base::error::{OrcErrv, OrcRes, mk_errv};
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
|
|
||||||
@@ -25,11 +25,11 @@ impl<T: TryFromExpr, U: TryFromExpr> TryFromExpr for (T, U) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn err_not_atom(pos: Pos, i: &Interner) -> OrcErrv {
|
async fn err_not_atom(pos: Pos, i: &Interner) -> OrcErrv {
|
||||||
mk_err(i.i("Expected an atom").await, "This expression is not an atom", [pos])
|
mk_errv(i.i("Expected an atom").await, "This expression is not an atom", [pos])
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn err_type(pos: Pos, i: &Interner) -> OrcErrv {
|
async fn err_type(pos: Pos, i: &Interner) -> OrcErrv {
|
||||||
mk_err(i.i("Type error").await, "The atom is a different type than expected", [pos])
|
mk_errv(i.i("Type error").await, "The atom is a different type than expected", [pos])
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFromExpr for ForeignAtom {
|
impl TryFromExpr for ForeignAtom {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use std::num::NonZero;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use async_lock::RwLock;
|
||||||
use futures::channel::mpsc::{Receiver, Sender, channel};
|
use futures::channel::mpsc::{Receiver, Sender, channel};
|
||||||
use futures::future::{LocalBoxFuture, join_all};
|
use futures::future::{LocalBoxFuture, join_all};
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
@@ -49,12 +50,12 @@ impl ExtensionData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum MemberRecord {
|
pub enum MemberRecord {
|
||||||
Gen(Vec<IStr>, LazyMemberFactory),
|
Gen(Vec<Tok<String>>, LazyMemberFactory),
|
||||||
Res,
|
Res,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SystemRecord {
|
pub struct SystemRecord {
|
||||||
lazy_members: HashMap<api::TreeId, MemberRecord>,
|
lazy_members: Mutex<HashMap<api::TreeId, MemberRecord>>,
|
||||||
ctx: SysCtx,
|
ctx: SysCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +73,7 @@ pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
|||||||
atom: &'a api::Atom,
|
atom: &'a api::Atom,
|
||||||
cb: impl WithAtomRecordCallback<'a, T>,
|
cb: impl WithAtomRecordCallback<'a, T>,
|
||||||
) -> T {
|
) -> T {
|
||||||
let mut data = &atom.data[..];
|
let mut data = &atom.data.0[..];
|
||||||
let ctx = get_sys_ctx(atom.owner).await;
|
let ctx = get_sys_ctx(atom.owner).await;
|
||||||
let inst = ctx.get::<CtedObj>().inst();
|
let inst = ctx.get::<CtedObj>().inst();
|
||||||
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
let id = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||||
@@ -82,7 +83,7 @@ pub async fn with_atom_record<'a, F: Future<Output = SysCtx>, T>(
|
|||||||
|
|
||||||
pub struct ExtensionOwner {
|
pub struct ExtensionOwner {
|
||||||
_interner_cell: Rc<RefCell<Option<Interner>>>,
|
_interner_cell: Rc<RefCell<Option<Interner>>>,
|
||||||
_systems_lock: Rc<Mutex<HashMap<api::SysId, SystemRecord>>>,
|
_systems_lock: Rc<RwLock<HashMap<api::SysId, SystemRecord>>>,
|
||||||
out_recv: Mutex<Receiver<Vec<u8>>>,
|
out_recv: Mutex<Receiver<Vec<u8>>>,
|
||||||
out_send: Sender<Vec<u8>>,
|
out_send: Sender<Vec<u8>>,
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ pub fn extension_init(
|
|||||||
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
|
.map(|(id, sys)| (u16::try_from(id).expect("more than u16max system ctors"), sys))
|
||||||
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
.map(|(id, sys)| sys.decl(api::SysDeclId(NonZero::new(id + 1).unwrap())))
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
let systems_lock = Rc::new(Mutex::new(HashMap::<api::SysId, SystemRecord>::new()));
|
let systems_lock = Rc::new(RwLock::new(HashMap::<api::SysId, SystemRecord>::new()));
|
||||||
let ext_header = api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() };
|
let ext_header = api::ExtensionHeader { name: data.name.to_string(), systems: decls.clone() };
|
||||||
let (out_send, in_recv) = channel::<Vec<u8>>(1);
|
let (out_send, in_recv) = channel::<Vec<u8>>(1);
|
||||||
let (in_send, out_recv) = channel::<Vec<u8>>(1);
|
let (in_send, out_recv) = channel::<Vec<u8>>(1);
|
||||||
@@ -119,7 +120,7 @@ pub fn extension_init(
|
|||||||
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
|
let get_ctx = clone!(systems_weak; move |id: api::SysId| clone!(systems_weak; async move {
|
||||||
let systems =
|
let systems =
|
||||||
systems_weak.upgrade().expect("System table dropped before request processing done");
|
systems_weak.upgrade().expect("System table dropped before request processing done");
|
||||||
systems.lock().await.get(&id).expect("System not found").ctx.clone()
|
systems.read().await.get(&id).expect("System not found").ctx.clone()
|
||||||
}));
|
}));
|
||||||
let init_ctx = {
|
let init_ctx = {
|
||||||
clone!(interner_weak, spawner, logger);
|
clone!(interner_weak, spawner, logger);
|
||||||
@@ -139,19 +140,14 @@ pub fn extension_init(
|
|||||||
Box::pin(async move { in_send.send(a.to_vec()).await.unwrap() })
|
Box::pin(async move { in_send.send(a.to_vec()).await.unwrap() })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
clone!(systems_weak, exit_send, get_ctx);
|
clone!(exit_send);
|
||||||
move |n, _| {
|
move |n, _| {
|
||||||
clone!(systems_weak, exit_send mut, get_ctx);
|
clone!(exit_send mut);
|
||||||
async move {
|
async move {
|
||||||
match n {
|
match n {
|
||||||
api::HostExtNotif::Exit => exit_send.send(()).await.unwrap(),
|
api::HostExtNotif::Exit => {
|
||||||
api::HostExtNotif::SystemDrop(api::SystemDrop(sys_id)) =>
|
eprintln!("Exit received");
|
||||||
if let Some(rc) = systems_weak.upgrade() {
|
exit_send.send(()).await.unwrap()
|
||||||
mem::drop(rc.lock().await.remove(&sys_id))
|
|
||||||
},
|
|
||||||
api::HostExtNotif::AtomDrop(api::AtomDrop(sys_id, atom)) => {
|
|
||||||
let ctx = get_ctx(sys_id).await;
|
|
||||||
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,8 +161,22 @@ pub fn extension_init(
|
|||||||
async move {
|
async move {
|
||||||
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
let interner_cell = interner_weak.upgrade().expect("Interner dropped before request");
|
||||||
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
let i = interner_cell.borrow().clone().expect("Request arrived before interner set");
|
||||||
writeln!(msg_logger, "{} extension received request {req:?}", data.name);
|
if !matches!(req, api::HostExtReq::AtomReq(api::AtomReq::AtomPrint(_))) {
|
||||||
|
writeln!(msg_logger, "{} extension received request {req:?}", data.name);
|
||||||
|
}
|
||||||
|
|
||||||
match req {
|
match req {
|
||||||
|
api::HostExtReq::SystemDrop(sys_drop) => {
|
||||||
|
if let Some(rc) = systems_weak.upgrade() {
|
||||||
|
mem::drop(rc.write().await.remove(&sys_drop.0))
|
||||||
|
}
|
||||||
|
hand.handle(&sys_drop, &()).await
|
||||||
|
},
|
||||||
|
api::HostExtReq::AtomDrop(atom_drop @ api::AtomDrop(sys_id, atom)) => {
|
||||||
|
let ctx = get_ctx(sys_id).await;
|
||||||
|
take_atom(atom, &ctx).await.dyn_free(ctx.clone()).await;
|
||||||
|
hand.handle(&atom_drop, &()).await
|
||||||
|
},
|
||||||
api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await,
|
api::HostExtReq::Ping(ping @ api::Ping) => hand.handle(&ping, &()).await,
|
||||||
api::HostExtReq::Sweep(sweep @ api::Sweep) =>
|
api::HostExtReq::Sweep(sweep @ api::Sweep) =>
|
||||||
hand.handle(&sweep, &i.sweep_replica().await).await,
|
hand.handle(&sweep, &i.sweep_replica().await).await,
|
||||||
@@ -178,18 +188,17 @@ pub fn extension_init(
|
|||||||
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
cted.inst().dyn_lexers().iter().fold(api::CharFilter(vec![]), |cf, lx| {
|
||||||
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
char_filter_union(&cf, &mk_char_filter(lx.char_filter().iter().cloned()))
|
||||||
});
|
});
|
||||||
let lazy_mems = Mutex::new(HashMap::new());
|
let lazy_members = Mutex::new(HashMap::new());
|
||||||
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
|
let ctx = init_ctx(new_sys.id, cted.clone(), hand.reqnot()).await;
|
||||||
let const_root = stream::iter(cted.inst().dyn_env())
|
let const_root = stream::iter(cted.inst().dyn_env())
|
||||||
.then(|mem| {
|
.then(|mem| {
|
||||||
let (req, lazy_mems) = (&hand, &lazy_mems);
|
let lazy_mems = &lazy_members;
|
||||||
clone!(i, ctx; async move {
|
clone!(i, ctx; async move {
|
||||||
let mut tia_ctx = TreeIntoApiCtxImpl {
|
let mut tia_ctx = TreeIntoApiCtxImpl {
|
||||||
lazy_members: &mut *lazy_mems.lock().await,
|
lazy_members: &mut *lazy_mems.lock().await,
|
||||||
sys: ctx,
|
sys: ctx,
|
||||||
basepath: &[],
|
basepath: &[],
|
||||||
path: Substack::Bottom,
|
path: Substack::Bottom,
|
||||||
req
|
|
||||||
};
|
};
|
||||||
(i.i(&mem.name).await.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
(i.i(&mem.name).await.to_api(), mem.kind.into_api(&mut tia_ctx).await)
|
||||||
})
|
})
|
||||||
@@ -198,9 +207,9 @@ pub fn extension_init(
|
|||||||
.await;
|
.await;
|
||||||
let prelude =
|
let prelude =
|
||||||
cted.inst().dyn_prelude(&i).await.iter().map(|sym| sym.to_api()).collect();
|
cted.inst().dyn_prelude(&i).await.iter().map(|sym| sym.to_api()).collect();
|
||||||
let record = SystemRecord { ctx, lazy_members: lazy_mems.into_inner() };
|
let record = SystemRecord { ctx, lazy_members };
|
||||||
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
let systems = systems_weak.upgrade().expect("System constructed during shutdown");
|
||||||
systems.lock().await.insert(new_sys.id, record);
|
systems.write().await.insert(new_sys.id, record);
|
||||||
let line_types = join_all(
|
let line_types = join_all(
|
||||||
(cted.inst().dyn_parsers().iter())
|
(cted.inst().dyn_parsers().iter())
|
||||||
.map(|p| async { i.i(p.line_head()).await.to_api() }),
|
.map(|p| async { i.i(p.line_head()).await.to_api() }),
|
||||||
@@ -212,9 +221,9 @@ pub fn extension_init(
|
|||||||
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
api::HostExtReq::GetMember(get_tree @ api::GetMember(sys_id, tree_id)) => {
|
||||||
let sys_ctx = get_ctx(sys_id).await;
|
let sys_ctx = get_ctx(sys_id).await;
|
||||||
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
|
let systems = systems_weak.upgrade().expect("Member queried during shutdown");
|
||||||
let mut systems_g = systems.lock().await;
|
let systems_g = systems.read().await;
|
||||||
let SystemRecord { lazy_members, .. } =
|
let mut lazy_members =
|
||||||
systems_g.get_mut(&sys_id).expect("System not found");
|
systems_g.get(&sys_id).expect("System not found").lazy_members.lock().await;
|
||||||
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
let (path, cb) = match lazy_members.insert(tree_id, MemberRecord::Res) {
|
||||||
None => panic!("Tree for ID not found"),
|
None => panic!("Tree for ID not found"),
|
||||||
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
Some(MemberRecord::Res) => panic!("This tree has already been transmitted"),
|
||||||
@@ -225,8 +234,7 @@ pub fn extension_init(
|
|||||||
sys: sys_ctx,
|
sys: sys_ctx,
|
||||||
path: Substack::Bottom,
|
path: Substack::Bottom,
|
||||||
basepath: &path,
|
basepath: &path,
|
||||||
lazy_members,
|
lazy_members: &mut lazy_members,
|
||||||
req: &hand,
|
|
||||||
};
|
};
|
||||||
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
hand.handle(&get_tree, &tree.into_api(&mut tia_ctx).await).await
|
||||||
},
|
},
|
||||||
@@ -237,7 +245,7 @@ pub fn extension_init(
|
|||||||
sys.dyn_request(hand, payload).await
|
sys.dyn_request(hand, payload).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) => {
|
api::HostExtReq::LexExpr(lex @ api::LexExpr { sys, src, text, pos, id }) => {
|
||||||
let sys_ctx = get_ctx(sys).await;
|
let mut sys_ctx = get_ctx(sys).await;
|
||||||
let text = Tok::from_api(text, &i).await;
|
let text = Tok::from_api(text, &i).await;
|
||||||
let src = Sym::from_api(src, sys_ctx.i()).await;
|
let src = Sym::from_api(src, sys_ctx.i()).await;
|
||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
@@ -264,7 +272,7 @@ pub fn extension_init(
|
|||||||
return hand.handle(&lex, &eopt).await;
|
return hand.handle(&lex, &eopt).await;
|
||||||
},
|
},
|
||||||
Ok((s, expr)) => {
|
Ok((s, expr)) => {
|
||||||
let expr = expr.into_api(&mut (), &mut (sys_ctx, &hand)).await;
|
let expr = expr.into_api(&mut (), &mut sys_ctx).await;
|
||||||
let pos = (text.len() - s.len()) as u32;
|
let pos = (text.len() - s.len()) as u32;
|
||||||
expr_store.dispose().await;
|
expr_store.dispose().await;
|
||||||
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
return hand.handle(&lex, &Some(Ok(api::LexedExpr { pos, expr }))).await;
|
||||||
@@ -294,22 +302,22 @@ pub fn extension_init(
|
|||||||
let parse_res = parser.parse(pctx, *exported, comments, snip).await;
|
let parse_res = parser.parse(pctx, *exported, comments, snip).await;
|
||||||
let o_line = match reporter.merge(parse_res) {
|
let o_line = match reporter.merge(parse_res) {
|
||||||
Err(e) => Err(e.to_api()),
|
Err(e) => Err(e.to_api()),
|
||||||
Ok(t) => Ok(linev_into_api(t, ctx.clone(), &hand).await),
|
Ok(t) => Ok(linev_into_api(t, ctx.clone()).await),
|
||||||
};
|
};
|
||||||
|
mem::drop(line);
|
||||||
expr_store.dispose().await;
|
expr_store.dispose().await;
|
||||||
hand.handle(&pline, &o_line).await
|
hand.handle(&pline, &o_line).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst { id, sys }) => {
|
api::HostExtReq::FetchParsedConst(ref fpc @ api::FetchParsedConst(sys, id)) => {
|
||||||
let ctx = get_ctx(sys).await;
|
let ctx = get_ctx(sys).await;
|
||||||
let cnst = get_const(id, ctx.clone()).await;
|
let cnst = get_const(id, ctx.clone()).await;
|
||||||
hand.handle(fpc, &cnst.api_return(ctx, &hand).await).await
|
hand.handle(fpc, &cnst.api_return(ctx).await).await
|
||||||
},
|
},
|
||||||
api::HostExtReq::AtomReq(atom_req) => {
|
api::HostExtReq::AtomReq(atom_req) => {
|
||||||
let atom = atom_req.get_atom();
|
let atom = atom_req.get_atom();
|
||||||
let atom_req = atom_req.clone();
|
let atom_req = atom_req.clone();
|
||||||
with_atom_record(&get_ctx, atom, async move |nfo, ctx, id, buf| {
|
with_atom_record(&get_ctx, atom, async move |nfo, ctx, id, buf| {
|
||||||
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
let actx = AtomCtx(buf, atom.drop, ctx.clone());
|
||||||
|
|
||||||
match &atom_req {
|
match &atom_req {
|
||||||
api::AtomReq::SerializeAtom(ser) => {
|
api::AtomReq::SerializeAtom(ser) => {
|
||||||
let mut buf = enc_vec(&id).await;
|
let mut buf = enc_vec(&id).await;
|
||||||
@@ -340,21 +348,20 @@ pub fn extension_init(
|
|||||||
hand.handle(fwded, &some.then_some(reply)).await
|
hand.handle(fwded, &some.then_some(reply)).await
|
||||||
},
|
},
|
||||||
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
api::AtomReq::CallRef(call @ api::CallRef(_, arg)) => {
|
||||||
// SAFETY: function calls borrow their argument implicitly
|
|
||||||
let expr_store = BorrowedExprStore::new();
|
let expr_store = BorrowedExprStore::new();
|
||||||
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||||
let ret = nfo.call_ref(actx, Expr::from_handle(expr_handle.clone())).await;
|
let ret = nfo.call_ref(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||||
expr_handle.drop_one().await;
|
let api_expr = ret.api_return(ctx.clone()).await;
|
||||||
let api_expr = ret.api_return(ctx.clone(), &hand).await;
|
mem::drop(expr_handle);
|
||||||
expr_store.dispose().await;
|
expr_store.dispose().await;
|
||||||
hand.handle(call, &api_expr).await
|
hand.handle(call, &api_expr).await
|
||||||
},
|
},
|
||||||
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
api::AtomReq::FinalCall(call @ api::FinalCall(_, arg)) => {
|
||||||
// SAFETY: function calls borrow their argument implicitly
|
|
||||||
let expr_store = BorrowedExprStore::new();
|
let expr_store = BorrowedExprStore::new();
|
||||||
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
let expr_handle = ExprHandle::borrowed(ctx.clone(), *arg, &expr_store);
|
||||||
let ret = nfo.call(actx, Expr::from_handle(expr_handle.clone())).await;
|
let ret = nfo.call(actx, Expr::from_handle(expr_handle.clone())).await;
|
||||||
let api_expr = ret.api_return(ctx.clone(), &hand).await;
|
let api_expr = ret.api_return(ctx.clone()).await;
|
||||||
|
mem::drop(expr_handle);
|
||||||
expr_store.dispose().await;
|
expr_store.dispose().await;
|
||||||
hand.handle(call, &api_expr).await
|
hand.handle(call, &api_expr).await
|
||||||
},
|
},
|
||||||
@@ -363,7 +370,7 @@ pub fn extension_init(
|
|||||||
Ok(opt) => match opt {
|
Ok(opt) => match opt {
|
||||||
None => hand.handle(cmd, &Ok(api::NextStep::Halt)).await,
|
None => hand.handle(cmd, &Ok(api::NextStep::Halt)).await,
|
||||||
Some(cont) => {
|
Some(cont) => {
|
||||||
let cont = cont.api_return(ctx.clone(), &hand).await;
|
let cont = cont.api_return(ctx.clone()).await;
|
||||||
hand.handle(cmd, &Ok(api::NextStep::Continue(cont))).await
|
hand.handle(cmd, &Ok(api::NextStep::Continue(cont))).await
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -51,14 +51,24 @@ impl ExprHandle {
|
|||||||
/// Drop one instance of the handle silently; if it's the last one, do
|
/// Drop one instance of the handle silently; if it's the last one, do
|
||||||
/// nothing, otherwise send an Acquire
|
/// nothing, otherwise send an Acquire
|
||||||
pub async fn drop_one(self: Rc<Self>) {
|
pub async fn drop_one(self: Rc<Self>) {
|
||||||
if let Err(rc) = Rc::try_unwrap(self) {
|
match Rc::try_unwrap(self) {
|
||||||
rc.ctx.reqnot().notify(api::Acquire(rc.ctx.sys_id(), rc.tk)).await
|
Err(rc) => {
|
||||||
|
eprintln!("Extending lifetime for {:?}", rc.tk);
|
||||||
|
rc.ctx.reqnot().notify(api::Acquire(rc.ctx.sys_id(), rc.tk)).await
|
||||||
|
},
|
||||||
|
Ok(hand) => {
|
||||||
|
// avoid calling destructor
|
||||||
|
hand.destructure();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Drop the handle and get the ticket without a release notification.
|
/// Drop the handle and get the ticket without a release notification.
|
||||||
/// Use this with messages that imply ownership transfer. This function is
|
/// Use this with messages that imply ownership transfer. This function is
|
||||||
/// safe because abusing it is a memory leak.
|
/// safe because abusing it is a memory leak.
|
||||||
pub fn serialize(self) -> api::ExprTicket { self.destructure().0 }
|
pub fn serialize(self) -> api::ExprTicket {
|
||||||
|
eprintln!("Skipping destructor for {:?}", self.tk);
|
||||||
|
self.destructure().0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Eq for ExprHandle {}
|
impl Eq for ExprHandle {}
|
||||||
impl PartialEq for ExprHandle {
|
impl PartialEq for ExprHandle {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
@@ -5,7 +6,6 @@ use orchid_base::error::{OrcErr, OrcErrv};
|
|||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::reqnot::ReqHandlish;
|
|
||||||
use orchid_base::{match_mapping, tl_cache};
|
use orchid_base::{match_mapping, tl_cache};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
@@ -19,17 +19,21 @@ pub struct GExpr {
|
|||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
}
|
}
|
||||||
impl GExpr {
|
impl GExpr {
|
||||||
pub async fn api_return(self, ctx: SysCtx, hand: &impl ReqHandlish) -> api::Expression {
|
pub async fn api_return(self, ctx: SysCtx) -> api::Expression {
|
||||||
if let GExprKind::Slot(ex) = self.kind {
|
if let GExprKind::Slot(ex) = self.kind {
|
||||||
hand.defer_drop(ex.handle());
|
let hand = ex.handle();
|
||||||
|
mem::drop(ex);
|
||||||
api::Expression {
|
api::Expression {
|
||||||
location: api::Location::SlotTarget,
|
location: api::Location::SlotTarget,
|
||||||
kind: api::ExpressionKind::Slot(ex.handle().tk),
|
kind: match Rc::try_unwrap(hand) {
|
||||||
|
Ok(h) => api::ExpressionKind::Slot { tk: h.serialize(), by_value: true },
|
||||||
|
Err(rc) => api::ExpressionKind::Slot { tk: rc.tk, by_value: false },
|
||||||
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
api::Expression {
|
api::Expression {
|
||||||
location: api::Location::Inherit,
|
location: api::Location::Inherit,
|
||||||
kind: self.kind.api_return(ctx, hand).boxed_local().await,
|
kind: self.kind.api_return(ctx).boxed_local().await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,17 +57,17 @@ pub enum GExprKind {
|
|||||||
Bottom(OrcErrv),
|
Bottom(OrcErrv),
|
||||||
}
|
}
|
||||||
impl GExprKind {
|
impl GExprKind {
|
||||||
pub async fn api_return(self, ctx: SysCtx, hand: &impl ReqHandlish) -> api::ExpressionKind {
|
pub async fn api_return(self, ctx: SysCtx) -> api::ExpressionKind {
|
||||||
match_mapping!(self, Self => api::ExpressionKind {
|
match_mapping!(self, Self => api::ExpressionKind {
|
||||||
Call(
|
Call(
|
||||||
f => Box::new(f.api_return(ctx.clone(), hand).await),
|
f => Box::new(f.api_return(ctx.clone()).await),
|
||||||
x => Box::new(x.api_return(ctx, hand).await)
|
x => Box::new(x.api_return(ctx).await)
|
||||||
),
|
),
|
||||||
Seq(
|
Seq(
|
||||||
a => Box::new(a.api_return(ctx.clone(), hand).await),
|
a => Box::new(a.api_return(ctx.clone()).await),
|
||||||
b => Box::new(b.api_return(ctx, hand).await)
|
b => Box::new(b.api_return(ctx).await)
|
||||||
),
|
),
|
||||||
Lambda(arg, body => Box::new(body.api_return(ctx, hand).await)),
|
Lambda(arg, body => Box::new(body.api_return(ctx).await)),
|
||||||
Arg(arg),
|
Arg(arg),
|
||||||
Const(name.to_api()),
|
Const(name.to_api()),
|
||||||
Bottom(err.to_api()),
|
Bottom(err.to_api()),
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
use orchid_base::interner::{ApiStrTok, ApiStrvTok, IStr};
|
|
||||||
|
|
||||||
pub struct ExtIStr(ApiStrTok, Rc<String>);
|
|
||||||
impl Deref for ExtIStr {}
|
|
||||||
pub struct ExtIStrv(ApiStrvTok, Rc<Vec<IStr>>);
|
|
||||||
|
|
||||||
pub struct ExtInterner {}
|
|
||||||
@@ -4,7 +4,7 @@ use std::ops::RangeInclusive;
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::future::LocalBoxFuture;
|
use futures::future::LocalBoxFuture;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_err};
|
use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::location::{Pos, SrcRange};
|
use orchid_base::location::{Pos, SrcRange};
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
@@ -17,27 +17,27 @@ use crate::parser::PTokTree;
|
|||||||
use crate::system::SysCtx;
|
use crate::system::SysCtx;
|
||||||
use crate::tree::GenTokTree;
|
use crate::tree::GenTokTree;
|
||||||
|
|
||||||
pub async fn ekey_cascade(i: &Interner) -> IStr {
|
pub async fn ekey_cascade(i: &Interner) -> Tok<String> {
|
||||||
i.i("An error cascading from a recursive call").await
|
i.i("An error cascading from a recursive call").await
|
||||||
}
|
}
|
||||||
pub async fn ekey_not_applicable(i: &Interner) -> IStr {
|
pub async fn ekey_not_applicable(i: &Interner) -> Tok<String> {
|
||||||
i.i("Pseudo-error to communicate that the current branch in a dispatch doesn't apply").await
|
i.i("Pseudo-error to communicate that the current branch in a dispatch doesn't apply").await
|
||||||
}
|
}
|
||||||
const MSG_INTERNAL_ERROR: &str = "This error is a sentinel for the extension library.\
|
const MSG_INTERNAL_ERROR: &str = "This error is a sentinel for the extension library.\
|
||||||
it should not be emitted by the extension.";
|
it should not be emitted by the extension.";
|
||||||
|
|
||||||
pub async fn err_cascade(i: &Interner) -> OrcErrv {
|
pub async fn err_cascade(i: &Interner) -> OrcErrv {
|
||||||
mk_err(ekey_cascade(i).await, MSG_INTERNAL_ERROR, [Pos::None])
|
mk_errv(ekey_cascade(i).await, MSG_INTERNAL_ERROR, [Pos::None])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn err_not_applicable(i: &Interner) -> OrcErrv {
|
pub async fn err_not_applicable(i: &Interner) -> OrcErrv {
|
||||||
mk_err(ekey_not_applicable(i).await, MSG_INTERNAL_ERROR, [Pos::None])
|
mk_errv(ekey_not_applicable(i).await, MSG_INTERNAL_ERROR, [Pos::None])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LexContext<'a> {
|
pub struct LexContext<'a> {
|
||||||
pub(crate) exprs: &'a BorrowedExprStore,
|
pub(crate) exprs: &'a BorrowedExprStore,
|
||||||
pub ctx: SysCtx,
|
pub ctx: SysCtx,
|
||||||
pub text: &'a IStr,
|
pub text: &'a Tok<String>,
|
||||||
pub id: api::ParsId,
|
pub id: api::ParsId,
|
||||||
pub pos: u32,
|
pub pos: u32,
|
||||||
pub(crate) src: Sym,
|
pub(crate) src: Sym,
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ pub mod func_atom;
|
|||||||
pub mod gen_expr;
|
pub mod gen_expr;
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
// pub mod msg;
|
// pub mod msg;
|
||||||
mod interner;
|
|
||||||
pub mod other_system;
|
pub mod other_system;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod reflection;
|
pub mod reflection;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use orchid_base::location::SrcRange;
|
|||||||
use orchid_base::match_mapping;
|
use orchid_base::match_mapping;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::{Comment, ParseCtx, Snippet};
|
use orchid_base::parse::{Comment, ParseCtx, Snippet};
|
||||||
use orchid_base::reqnot::{ReqHandlish, Requester};
|
use orchid_base::reqnot::Requester;
|
||||||
use orchid_base::tree::{TokTree, Token, ttv_into_api};
|
use orchid_base::tree::{TokTree, Token, ttv_into_api};
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
@@ -100,8 +100,8 @@ impl ParseCtx for ParsCtx<'_> {
|
|||||||
type BoxConstCallback = Box<dyn FnOnce(ConstCtx) -> LocalBoxFuture<'static, GExpr>>;
|
type BoxConstCallback = Box<dyn FnOnce(ConstCtx) -> LocalBoxFuture<'static, GExpr>>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ParsedConstCtxEntry {
|
pub(crate) struct ParsedConstCtxEntry {
|
||||||
consts: IdStore<BoxConstCallback>,
|
pub(crate) consts: IdStore<BoxConstCallback>,
|
||||||
}
|
}
|
||||||
impl SysCtxEntry for ParsedConstCtxEntry {}
|
impl SysCtxEntry for ParsedConstCtxEntry {}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ impl ParsedLine {
|
|||||||
sr: &SrcRange,
|
sr: &SrcRange,
|
||||||
comments: impl IntoIterator<Item = &'a Comment>,
|
comments: impl IntoIterator<Item = &'a Comment>,
|
||||||
exported: bool,
|
exported: bool,
|
||||||
name: IStr,
|
name: Tok<String>,
|
||||||
f: F,
|
f: F,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let cb = Box::new(|ctx| async move { f(ctx).await.to_expr().await }.boxed_local());
|
let cb = Box::new(|ctx| async move { f(ctx).await.to_expr().await }.boxed_local());
|
||||||
@@ -127,7 +127,7 @@ impl ParsedLine {
|
|||||||
sr: &SrcRange,
|
sr: &SrcRange,
|
||||||
comments: impl IntoIterator<Item = &'a Comment>,
|
comments: impl IntoIterator<Item = &'a Comment>,
|
||||||
exported: bool,
|
exported: bool,
|
||||||
name: &IStr,
|
name: &Tok<String>,
|
||||||
use_prelude: bool,
|
use_prelude: bool,
|
||||||
lines: impl IntoIterator<Item = ParsedLine>,
|
lines: impl IntoIterator<Item = ParsedLine>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@@ -136,7 +136,7 @@ impl ParsedLine {
|
|||||||
let comments = comments.into_iter().cloned().collect();
|
let comments = comments.into_iter().cloned().collect();
|
||||||
ParsedLine { comments, sr: sr.clone(), kind: line_kind }
|
ParsedLine { comments, sr: sr.clone(), kind: line_kind }
|
||||||
}
|
}
|
||||||
pub async fn into_api(self, ctx: SysCtx, hand: &dyn ReqHandlish) -> api::ParsedLine {
|
pub async fn into_api(self, mut ctx: SysCtx) -> api::ParsedLine {
|
||||||
api::ParsedLine {
|
api::ParsedLine {
|
||||||
comments: self.comments.into_iter().map(|c| c.to_api()).collect(),
|
comments: self.comments.into_iter().map(|c| c.to_api()).collect(),
|
||||||
source_range: self.sr.to_api(),
|
source_range: self.sr.to_api(),
|
||||||
@@ -149,24 +149,20 @@ impl ParsedLine {
|
|||||||
ctx.get_or_default::<ParsedConstCtxEntry>().consts.add(cb).id(),
|
ctx.get_or_default::<ParsedConstCtxEntry>().consts.add(cb).id(),
|
||||||
)),
|
)),
|
||||||
ParsedMemKind::Mod { lines, use_prelude } => api::ParsedMemberKind::Module {
|
ParsedMemKind::Mod { lines, use_prelude } => api::ParsedMemberKind::Module {
|
||||||
lines: linev_into_api(lines, ctx, hand).boxed_local().await,
|
lines: linev_into_api(lines, ctx).boxed_local().await,
|
||||||
use_prelude,
|
use_prelude,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ParsedLineKind::Rec(tv) =>
|
ParsedLineKind::Rec(tv) =>
|
||||||
api::ParsedLineKind::Recursive(ttv_into_api(tv, &mut (), &mut (ctx, hand)).await),
|
api::ParsedLineKind::Recursive(ttv_into_api(tv, &mut (), &mut ctx).await),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn linev_into_api(
|
pub(crate) async fn linev_into_api(v: Vec<ParsedLine>, ctx: SysCtx) -> Vec<api::ParsedLine> {
|
||||||
v: Vec<ParsedLine>,
|
join_all(v.into_iter().map(|l| l.into_api(ctx.clone()))).await
|
||||||
ctx: SysCtx,
|
|
||||||
hand: &dyn ReqHandlish,
|
|
||||||
) -> Vec<api::ParsedLine> {
|
|
||||||
join_all(v.into_iter().map(|l| l.into_api(ctx.clone(), hand))).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ParsedLineKind {
|
pub enum ParsedLineKind {
|
||||||
@@ -175,7 +171,7 @@ pub enum ParsedLineKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParsedMem {
|
pub struct ParsedMem {
|
||||||
pub name: IStr,
|
pub name: Tok<String>,
|
||||||
pub exported: bool,
|
pub exported: bool,
|
||||||
pub kind: ParsedMemKind,
|
pub kind: ParsedMemKind,
|
||||||
}
|
}
|
||||||
@@ -218,7 +214,7 @@ impl ConstCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_const(id: api::ParsedConstId, ctx: SysCtx) -> GExpr {
|
pub(crate) async fn get_const(id: api::ParsedConstId, ctx: SysCtx) -> GExpr {
|
||||||
let ent = ctx.get::<ParsedConstCtxEntry>();
|
let ent = ctx.get_or_default::<ParsedConstCtxEntry>();
|
||||||
let rec = ent.consts.get(id.0).expect("Bad ID or double read of parsed const");
|
let rec = ent.consts.get(id.0).expect("Bad ID or double read of parsed const");
|
||||||
let ctx = ConstCtx { constid: id, ctx: ctx.clone() };
|
let ctx = ConstCtx { constid: id, ctx: ctx.clone() };
|
||||||
rec.remove()(ctx).await
|
rec.remove()(ctx).await
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub struct ReflModData {
|
|||||||
inferred: Mutex<bool>,
|
inferred: Mutex<bool>,
|
||||||
path: VPath,
|
path: VPath,
|
||||||
ctx: WeakSysCtx,
|
ctx: WeakSysCtx,
|
||||||
members: MemoMap<IStr, ReflMem>,
|
members: MemoMap<Tok<String>, ReflMem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -41,7 +41,7 @@ impl ReflMod {
|
|||||||
fn ctx(&self) -> SysCtx {
|
fn ctx(&self) -> SysCtx {
|
||||||
self.0.ctx.upgrade().expect("ReflectedModule accessed after context drop")
|
self.0.ctx.upgrade().expect("ReflectedModule accessed after context drop")
|
||||||
}
|
}
|
||||||
pub fn path(&self) -> &[IStr] { &self.0.path[..] }
|
pub fn path(&self) -> &[Tok<String>] { &self.0.path[..] }
|
||||||
pub fn is_root(&self) -> bool { self.0.path.is_empty() }
|
pub fn is_root(&self) -> bool { self.0.path.is_empty() }
|
||||||
async fn try_populate(&self) -> Result<(), api::LsModuleError> {
|
async fn try_populate(&self) -> Result<(), api::LsModuleError> {
|
||||||
let ctx = self.ctx();
|
let ctx = self.ctx();
|
||||||
@@ -70,7 +70,7 @@ impl ReflMod {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub async fn get_child(&self, key: &IStr) -> Option<ReflMem> {
|
pub async fn get_child(&self, key: &Tok<String>) -> Option<ReflMem> {
|
||||||
let inferred_g = self.0.inferred.lock().await;
|
let inferred_g = self.0.inferred.lock().await;
|
||||||
if let Some(mem) = self.0.members.get(key) {
|
if let Some(mem) = self.0.members.get(key) {
|
||||||
return Some(mem.clone());
|
return Some(mem.clone());
|
||||||
@@ -88,7 +88,7 @@ impl ReflMod {
|
|||||||
}
|
}
|
||||||
self.0.members.get(key).cloned()
|
self.0.members.get(key).cloned()
|
||||||
}
|
}
|
||||||
pub async fn get_by_path(&self, path: &[IStr]) -> Result<ReflMem, InvalidPathError> {
|
pub async fn get_by_path(&self, path: &[Tok<String>]) -> Result<ReflMem, InvalidPathError> {
|
||||||
let ctx = self.ctx();
|
let ctx = self.ctx();
|
||||||
let (next, tail) = path.split_first().expect("Attempted to walk by empty path");
|
let (next, tail) = path.split_first().expect("Attempted to walk by empty path");
|
||||||
let inferred_g = self.0.inferred.lock().await;
|
let inferred_g = self.0.inferred.lock().await;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ pub async fn resolv_atom(
|
|||||||
sys: &(impl DynSystemCard + ?Sized),
|
sys: &(impl DynSystemCard + ?Sized),
|
||||||
atom: &api::Atom,
|
atom: &api::Atom,
|
||||||
) -> Box<dyn AtomDynfo> {
|
) -> Box<dyn AtomDynfo> {
|
||||||
let tid = AtomTypeId::decode(Pin::new(&mut &atom.data[..])).await;
|
let tid = AtomTypeId::decode(Pin::new(&mut &atom.data.0[..])).await;
|
||||||
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
|
atom_by_idx(sys, tid).expect("Value of nonexistent type found")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ impl<T: System> DynSystem for T {
|
|||||||
|
|
||||||
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom>
|
pub async fn downcast_atom<A>(foreign: ForeignAtom) -> Result<TypAtom<A>, ForeignAtom>
|
||||||
where A: AtomicFeatures {
|
where A: AtomicFeatures {
|
||||||
let mut data = &foreign.atom.data[..];
|
let mut data = &foreign.atom.data.0[..];
|
||||||
let ctx = foreign.ctx().clone();
|
let ctx = foreign.ctx().clone();
|
||||||
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
let value = AtomTypeId::decode(Pin::new(&mut data)).await;
|
||||||
let own_inst = ctx.get::<CtedObj>().inst();
|
let own_inst = ctx.get::<CtedObj>().inst();
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ use itertools::Itertools;
|
|||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::reqnot::ReqHandlish;
|
|
||||||
use orchid_base::tree::{TokTree, Token, TokenVariant};
|
use orchid_base::tree::{TokTree, Token, TokenVariant};
|
||||||
use substack::Substack;
|
use substack::Substack;
|
||||||
use trait_set::trait_set;
|
use trait_set::trait_set;
|
||||||
@@ -27,7 +26,7 @@ pub type GenTok = Token<Expr, GExpr>;
|
|||||||
|
|
||||||
impl TokenVariant<api::Expression> for GExpr {
|
impl TokenVariant<api::Expression> for GExpr {
|
||||||
type FromApiCtx<'a> = ();
|
type FromApiCtx<'a> = ();
|
||||||
type ToApiCtx<'a> = (SysCtx, &'a dyn ReqHandlish);
|
type ToApiCtx<'a> = SysCtx;
|
||||||
async fn from_api(
|
async fn from_api(
|
||||||
_: &api::Expression,
|
_: &api::Expression,
|
||||||
_: &mut Self::FromApiCtx<'_>,
|
_: &mut Self::FromApiCtx<'_>,
|
||||||
@@ -36,8 +35,8 @@ impl TokenVariant<api::Expression> for GExpr {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
panic!("Received new expression from host")
|
panic!("Received new expression from host")
|
||||||
}
|
}
|
||||||
async fn into_api(self, (ctx, hand): &mut Self::ToApiCtx<'_>) -> api::Expression {
|
async fn into_api(self, ctx: &mut Self::ToApiCtx<'_>) -> api::Expression {
|
||||||
self.api_return(ctx.clone(), hand).await
|
self.api_return(ctx.clone()).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +187,7 @@ impl MemKind {
|
|||||||
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
pub async fn into_api(self, ctx: &mut impl TreeIntoApiCtx) -> api::MemberKind {
|
||||||
match self {
|
match self {
|
||||||
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
|
Self::Lazy(lazy) => api::MemberKind::Lazy(ctx.with_lazy(lazy)),
|
||||||
Self::Const(c) => api::MemberKind::Const(c.api_return(ctx.sys(), ctx.req()).await),
|
Self::Const(c) => api::MemberKind::Const(c.api_return(ctx.sys()).await),
|
||||||
Self::Mod { members } => api::MemberKind::Module(api::Module {
|
Self::Mod { members } => api::MemberKind::Module(api::Module {
|
||||||
members: stream(async |mut cx| {
|
members: stream(async |mut cx| {
|
||||||
for m in members {
|
for m in members {
|
||||||
@@ -206,23 +205,20 @@ impl MemKind {
|
|||||||
pub trait TreeIntoApiCtx {
|
pub trait TreeIntoApiCtx {
|
||||||
fn sys(&self) -> SysCtx;
|
fn sys(&self) -> SysCtx;
|
||||||
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
|
fn with_lazy(&mut self, fac: LazyMemberFactory) -> api::TreeId;
|
||||||
fn push_path(&mut self, seg: IStr) -> impl TreeIntoApiCtx;
|
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx;
|
||||||
fn req(&self) -> &impl ReqHandlish;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TreeIntoApiCtxImpl<'a, 'b, RH: ReqHandlish> {
|
pub struct TreeIntoApiCtxImpl<'a, 'b> {
|
||||||
pub sys: SysCtx,
|
pub sys: SysCtx,
|
||||||
pub basepath: &'a [IStr],
|
pub basepath: &'a [Tok<String>],
|
||||||
pub path: Substack<'a, IStr>,
|
pub path: Substack<'a, Tok<String>>,
|
||||||
pub lazy_members: &'b mut HashMap<api::TreeId, MemberRecord>,
|
pub lazy_members: &'b mut HashMap<api::TreeId, MemberRecord>,
|
||||||
pub req: &'a RH,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
|
impl TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_> {
|
||||||
fn sys(&self) -> SysCtx { self.sys.clone() }
|
fn sys(&self) -> SysCtx { self.sys.clone() }
|
||||||
fn push_path(&mut self, seg: IStr) -> impl TreeIntoApiCtx {
|
fn push_path(&mut self, seg: Tok<String>) -> impl TreeIntoApiCtx {
|
||||||
TreeIntoApiCtxImpl {
|
TreeIntoApiCtxImpl {
|
||||||
req: self.req,
|
|
||||||
lazy_members: self.lazy_members,
|
lazy_members: self.lazy_members,
|
||||||
sys: self.sys.clone(),
|
sys: self.sys.clone(),
|
||||||
basepath: self.basepath,
|
basepath: self.basepath,
|
||||||
@@ -235,5 +231,4 @@ impl<RH: ReqHandlish> TreeIntoApiCtx for TreeIntoApiCtxImpl<'_, '_, RH> {
|
|||||||
self.lazy_members.insert(id, MemberRecord::Gen(path, fac));
|
self.lazy_members.insert(id, MemberRecord::Gen(path, fac));
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
fn req(&self) -> &impl ReqHandlish { self.req }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,11 +25,11 @@ impl AtomData {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
fn api(self) -> api::Atom {
|
fn api(self) -> api::Atom {
|
||||||
let (owner, drop, data, _display) = self.destructure();
|
let (owner, drop, data, _display) = self.destructure();
|
||||||
api::Atom { data, drop, owner: owner.id() }
|
api::Atom { data: api::AtomData(data), drop, owner: owner.id() }
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn api_ref(&self) -> api::Atom {
|
fn api_ref(&self) -> api::Atom {
|
||||||
api::Atom { data: self.data.clone(), drop: self.drop, owner: self.owner.id() }
|
api::Atom { data: api::AtomData(self.data.clone()), drop: self.drop, owner: self.owner.id() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Drop for AtomData {
|
impl Drop for AtomData {
|
||||||
@@ -73,7 +73,7 @@ impl AtomHand {
|
|||||||
pub fn sys(&self) -> &System { &self.0.owner }
|
pub fn sys(&self) -> &System { &self.0.owner }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn ext(&self) -> &Extension { self.sys().ext() }
|
pub fn ext(&self) -> &Extension { self.sys().ext() }
|
||||||
pub async fn req(&self, key: api::TVec, req: Vec<u8>) -> Option<Vec<u8>> {
|
pub async fn req(&self, key: api::TStrv, req: Vec<u8>) -> Option<Vec<u8>> {
|
||||||
self.0.owner.reqnot().request(api::Fwded(self.0.api_ref(), key, req)).await
|
self.0.owner.reqnot().request(api::Fwded(self.0.api_ref(), key, req)).await
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -97,7 +97,11 @@ impl AtomRepr for AtomHand {
|
|||||||
async fn from_api(atom: &api::Atom, _: Pos, ctx: &mut Self::Ctx) -> Self {
|
async fn from_api(atom: &api::Atom, _: Pos, ctx: &mut Self::Ctx) -> Self {
|
||||||
let api::Atom { data, drop, owner } = atom.clone();
|
let api::Atom { data, drop, owner } = atom.clone();
|
||||||
let sys = ctx.system_inst(owner).await.expect("Dropped system created atom");
|
let sys = ctx.system_inst(owner).await.expect("Dropped system created atom");
|
||||||
if let Some(id) = drop { sys.new_atom(data, id).await } else { AtomHand::new(data, sys, drop) }
|
if let Some(id) = drop {
|
||||||
|
sys.new_atom(data.0, id).await
|
||||||
|
} else {
|
||||||
|
AtomHand::new(data.0, sys, drop)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
async fn to_api(&self) -> orchid_api::Atom { self.api_ref() }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_err};
|
use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::VName;
|
use orchid_base::name::VName;
|
||||||
@@ -30,7 +30,7 @@ impl AbsPathError {
|
|||||||
format!("{path} is leading outside the root."),
|
format!("{path} is leading outside the root."),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
mk_err(descr, msg, [pos])
|
mk_errv(descr, msg, [pos])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ impl AbsPathError {
|
|||||||
/// if the relative path contains as many or more `super` segments than the
|
/// if the relative path contains as many or more `super` segments than the
|
||||||
/// length of the absolute path.
|
/// length of the absolute path.
|
||||||
pub async fn absolute_path(
|
pub async fn absolute_path(
|
||||||
mut cwd: &[IStr],
|
mut cwd: &[Tok<String>],
|
||||||
mut rel: &[IStr],
|
mut rel: &[Tok<String>],
|
||||||
i: &Interner,
|
i: &Interner,
|
||||||
) -> Result<VName, AbsPathError> {
|
) -> Result<VName, AbsPathError> {
|
||||||
let i_self = i.i("self").await;
|
let i_self = i.i("self").await;
|
||||||
@@ -67,13 +67,13 @@ pub struct DealiasCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn resolv_glob<Mod: Tree>(
|
pub async fn resolv_glob<Mod: Tree>(
|
||||||
cwd: &[IStr],
|
cwd: &[Tok<String>],
|
||||||
root: &Mod,
|
root: &Mod,
|
||||||
abs_path: &[IStr],
|
abs_path: &[Tok<String>],
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
i: &Interner,
|
i: &Interner,
|
||||||
ctx: &mut Mod::Ctx<'_>,
|
ctx: &mut Mod::Ctx<'_>,
|
||||||
) -> OrcRes<HashSet<IStr>> {
|
) -> OrcRes<HashSet<Tok<String>>> {
|
||||||
let coprefix_len = cwd.iter().zip(abs_path).take_while(|(a, b)| a == b).count();
|
let coprefix_len = cwd.iter().zip(abs_path).take_while(|(a, b)| a == b).count();
|
||||||
let (co_prefix, diff_path) = abs_path.split_at(abs_path.len().min(coprefix_len + 1));
|
let (co_prefix, diff_path) = abs_path.split_at(abs_path.len().min(coprefix_len + 1));
|
||||||
let fst_diff =
|
let fst_diff =
|
||||||
@@ -87,7 +87,7 @@ pub async fn resolv_glob<Mod: Tree>(
|
|||||||
ChildErrorKind::Missing => ("Invalid import path", format!("{path} not found")),
|
ChildErrorKind::Missing => ("Invalid import path", format!("{path} not found")),
|
||||||
ChildErrorKind::Private => ("Import inaccessible", format!("{path} is private")),
|
ChildErrorKind::Private => ("Import inaccessible", format!("{path} is private")),
|
||||||
};
|
};
|
||||||
return Err(mk_err(i.i(tk).await, msg, [pos]));
|
return Err(mk_errv(i.i(tk).await, msg, [pos]));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Ok(target_module.children(coprefix_len < abs_path.len()))
|
Ok(target_module.children(coprefix_len < abs_path.len()))
|
||||||
@@ -98,11 +98,11 @@ pub type ChildResult<'a, T> = Result<&'a T, ChildErrorKind>;
|
|||||||
pub trait Tree {
|
pub trait Tree {
|
||||||
type Ctx<'a>;
|
type Ctx<'a>;
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn children(&self, public_only: bool) -> HashSet<IStr>;
|
fn children(&self, public_only: bool) -> HashSet<Tok<String>>;
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn child(
|
fn child(
|
||||||
&self,
|
&self,
|
||||||
key: IStr,
|
key: Tok<String>,
|
||||||
public_only: bool,
|
public_only: bool,
|
||||||
ctx: &mut Self::Ctx<'_>,
|
ctx: &mut Self::Ctx<'_>,
|
||||||
) -> impl Future<Output = ChildResult<'_, Self>>;
|
) -> impl Future<Output = ChildResult<'_, Self>>;
|
||||||
@@ -133,7 +133,7 @@ pub struct ChildError {
|
|||||||
pub async fn walk<'a, T: Tree>(
|
pub async fn walk<'a, T: Tree>(
|
||||||
root: &'a T,
|
root: &'a T,
|
||||||
public_only: bool,
|
public_only: bool,
|
||||||
path: impl IntoIterator<Item = IStr>,
|
path: impl IntoIterator<Item = Tok<String>>,
|
||||||
ctx: &mut T::Ctx<'_>,
|
ctx: &mut T::Ctx<'_>,
|
||||||
) -> Result<&'a T, ChildError> {
|
) -> Result<&'a T, ChildError> {
|
||||||
let mut cur = root;
|
let mut cur = root;
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ impl Expr {
|
|||||||
},
|
},
|
||||||
api::ExpressionKind::NewAtom(a) =>
|
api::ExpressionKind::NewAtom(a) =>
|
||||||
ExprKind::Atom(AtomHand::from_api(a, pos.clone(), &mut ctx.ctx.clone()).await),
|
ExprKind::Atom(AtomHand::from_api(a, pos.clone(), &mut ctx.ctx.clone()).await),
|
||||||
api::ExpressionKind::Slot(tk) => return ctx.exprs.get_expr(*tk).expect("Invalid slot"),
|
api::ExpressionKind::Slot { tk, by_value: false } =>
|
||||||
|
return ctx.exprs.get_expr(*tk).expect("Invalid slot"),
|
||||||
|
api::ExpressionKind::Slot { tk, by_value: true } =>
|
||||||
|
return ctx.exprs.take_expr(*tk).expect("Invalid slot"),
|
||||||
api::ExpressionKind::Seq(a, b) => {
|
api::ExpressionKind::Seq(a, b) => {
|
||||||
let (apsb, bpsb) = psb.split();
|
let (apsb, bpsb) = psb.split();
|
||||||
ExprKind::Seq(
|
ExprKind::Seq(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::cell::RefCell;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use bound::Bound;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::hash_map::Entry;
|
use hashbrown::hash_map::Entry;
|
||||||
|
|
||||||
@@ -12,15 +13,29 @@ use crate::expr::Expr;
|
|||||||
pub struct ExprStoreData {
|
pub struct ExprStoreData {
|
||||||
exprs: RefCell<HashMap<api::ExprTicket, (u32, Expr)>>,
|
exprs: RefCell<HashMap<api::ExprTicket, (u32, Expr)>>,
|
||||||
parent: Option<ExprStore>,
|
parent: Option<ExprStore>,
|
||||||
|
tracking_parent: bool,
|
||||||
}
|
}
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct ExprStore(Rc<ExprStoreData>);
|
pub struct ExprStore(Rc<ExprStoreData>);
|
||||||
impl ExprStore {
|
impl ExprStore {
|
||||||
|
/// If tracking_parent is false, get_expr can fall back to the parent if none
|
||||||
|
/// is found here.
|
||||||
|
///
|
||||||
|
/// If tracking_parent is true, get_expr can still fall back to the parent,
|
||||||
|
/// but operations on the parent can access the child exprs too until this
|
||||||
|
/// store is dropped.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn derive(&self) -> Self {
|
pub fn derive(&self, tracking_parent: bool) -> Self {
|
||||||
Self(Rc::new(ExprStoreData { exprs: RefCell::default(), parent: Some(self.clone()) }))
|
Self(Rc::new(ExprStoreData {
|
||||||
|
exprs: RefCell::default(),
|
||||||
|
parent: Some(self.clone()),
|
||||||
|
tracking_parent,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
pub fn give_expr(&self, expr: Expr) {
|
pub fn give_expr(&self, expr: Expr) {
|
||||||
|
if self.0.tracking_parent {
|
||||||
|
self.0.parent.as_ref().unwrap().give_expr(expr.clone());
|
||||||
|
}
|
||||||
match self.0.exprs.borrow_mut().entry(expr.id()) {
|
match self.0.exprs.borrow_mut().entry(expr.id()) {
|
||||||
Entry::Occupied(mut oe) => oe.get_mut().0 += 1,
|
Entry::Occupied(mut oe) => oe.get_mut().0 += 1,
|
||||||
Entry::Vacant(v) => {
|
Entry::Vacant(v) => {
|
||||||
@@ -29,8 +44,11 @@ impl ExprStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn take_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
|
pub fn take_expr(&self, ticket: api::ExprTicket) -> Option<Expr> {
|
||||||
|
if self.0.tracking_parent {
|
||||||
|
self.0.parent.as_ref().unwrap().take_expr(ticket);
|
||||||
|
}
|
||||||
match self.0.exprs.borrow_mut().entry(ticket) {
|
match self.0.exprs.borrow_mut().entry(ticket) {
|
||||||
Entry::Vacant(_) => None,
|
Entry::Vacant(_) => panic!("Attempted to double-take expression"),
|
||||||
Entry::Occupied(oe) if oe.get().0 == 1 => Some(oe.remove().1),
|
Entry::Occupied(oe) if oe.get().0 == 1 => Some(oe.remove().1),
|
||||||
Entry::Occupied(mut oe) => {
|
Entry::Occupied(mut oe) => {
|
||||||
oe.get_mut().0 -= 1;
|
oe.get_mut().0 -= 1;
|
||||||
@@ -43,6 +61,11 @@ impl ExprStore {
|
|||||||
(self.0.exprs.borrow().get(&ticket).map(|(_, expr)| expr.clone()))
|
(self.0.exprs.borrow().get(&ticket).map(|(_, expr)| expr.clone()))
|
||||||
.or_else(|| self.0.parent.as_ref()?.get_expr(ticket))
|
.or_else(|| self.0.parent.as_ref()?.get_expr(ticket))
|
||||||
}
|
}
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = (u32, Expr)> {
|
||||||
|
let r = Bound::new(self.clone(), |this| this.0.exprs.borrow());
|
||||||
|
let mut iter = Bound::new(r, |r| r.values());
|
||||||
|
std::iter::from_fn(move || iter.wrapped_mut().next().cloned())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl fmt::Display for ExprStore {
|
impl fmt::Display for ExprStore {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@@ -51,3 +74,19 @@ impl fmt::Display for ExprStore {
|
|||||||
write!(f, "Store holding {rc} refs to {} exprs", r.len())
|
write!(f, "Store holding {rc} refs to {} exprs", r.len())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for ExprStore {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if 1 < Rc::strong_count(&self.0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !self.0.tracking_parent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let parent = self.0.parent.as_ref().unwrap();
|
||||||
|
for (id, (count, _)) in self.0.exprs.borrow().iter() {
|
||||||
|
for _ in 0..*count {
|
||||||
|
parent.take_expr(*id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ pub struct ReqPair<R: Request>(R, Sender<R::Response>);
|
|||||||
/// upgrading fails.
|
/// upgrading fails.
|
||||||
#[derive(destructure)]
|
#[derive(destructure)]
|
||||||
pub struct ExtensionData {
|
pub struct ExtensionData {
|
||||||
|
name: String,
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
reqnot: ReqNot<api::HostMsgSet>,
|
reqnot: ReqNot<api::HostMsgSet>,
|
||||||
systems: Vec<SystemCtor>,
|
systems: Vec<SystemCtor>,
|
||||||
@@ -67,21 +68,29 @@ impl Extension {
|
|||||||
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
Ok(Self(Rc::new_cyclic(|weak: &Weak<ExtensionData>| {
|
||||||
let init = Rc::new(init);
|
let init = Rc::new(init);
|
||||||
let (exiting_snd, exiting_rcv) = channel::<()>(0);
|
let (exiting_snd, exiting_rcv) = channel::<()>(0);
|
||||||
(ctx.spawn)(clone!(init, weak, ctx; Box::pin(async move {
|
(ctx.spawn)({
|
||||||
let rcv_stream = stream(async |mut cx| loop { cx.emit( init.recv().await).await });
|
clone!(init, weak, ctx);
|
||||||
let mut event_stream = pin!(stream::select(exiting_rcv.map(|()| None), rcv_stream));
|
Box::pin(async move {
|
||||||
while let Some(Some(msg)) = event_stream.next().await {
|
let rcv_stream = stream(async |mut cx| {
|
||||||
if let Some(reqnot) = weak.upgrade().map(|rc| rc.reqnot.clone()) {
|
loop {
|
||||||
let reqnot = reqnot.clone();
|
cx.emit(init.recv().await).await
|
||||||
(ctx.spawn)(Box::pin(async move {
|
}
|
||||||
reqnot.receive(&msg).await;
|
});
|
||||||
}))
|
let mut event_stream = pin!(stream::select(exiting_rcv.map(|()| None), rcv_stream));
|
||||||
|
while let Some(Some(msg)) = event_stream.next().await {
|
||||||
|
if let Some(reqnot) = weak.upgrade().map(|rc| rc.reqnot.clone()) {
|
||||||
|
let reqnot = reqnot.clone();
|
||||||
|
(ctx.spawn)(Box::pin(async move {
|
||||||
|
reqnot.receive(&msg).await;
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})));
|
});
|
||||||
ExtensionData {
|
ExtensionData {
|
||||||
|
name: init.name.clone(),
|
||||||
exiting_snd,
|
exiting_snd,
|
||||||
exprs: ctx.common_exprs.derive(),
|
exprs: ctx.common_exprs.derive(false),
|
||||||
ctx: ctx.clone(),
|
ctx: ctx.clone(),
|
||||||
systems: (init.systems.iter().cloned())
|
systems: (init.systems.iter().cloned())
|
||||||
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
.map(|decl| SystemCtor { decl, ext: WeakExtension(weak.clone()) })
|
||||||
@@ -95,17 +104,26 @@ impl Extension {
|
|||||||
clone!(weak; move |notif, _| {
|
clone!(weak; move |notif, _| {
|
||||||
clone!(weak; Box::pin(async move {
|
clone!(weak; Box::pin(async move {
|
||||||
let this = Extension(weak.upgrade().unwrap());
|
let this = Extension(weak.upgrade().unwrap());
|
||||||
|
if !matches!(notif, api::ExtHostNotif::Log(_)) {
|
||||||
|
writeln!(this.reqnot().logger(), "Host received notif {notif:?}");
|
||||||
|
}
|
||||||
match notif {
|
match notif {
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Acquire(acq)) => {
|
||||||
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
let target = this.0.exprs.get_expr(acq.1).expect("Invalid ticket");
|
||||||
this.0.exprs.give_expr(target)
|
this.0.exprs.give_expr(target)
|
||||||
}
|
}
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Release(rel)) => {
|
||||||
this.assert_own_sys(rel.0).await;
|
if this.is_own_sys(rel.0).await {
|
||||||
this.0.exprs.take_expr(rel.1);
|
this.0.exprs.take_expr(rel.1);
|
||||||
|
} else {
|
||||||
|
writeln!(this.reqnot().logger(), "Not our system {:?}", rel.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
api::ExtHostNotif::ExprNotif(api::ExprNotif::Move(mov)) => {
|
||||||
this.assert_own_sys(mov.dec).await;
|
if !this.is_own_sys(mov.dec).await {
|
||||||
|
writeln!(this.reqnot().logger(), "Not our system {:?}", mov.dec);
|
||||||
|
return;
|
||||||
|
}
|
||||||
let recp = this.ctx().system_inst(mov.inc).await.expect("invallid recipient sys id");
|
let recp = this.ctx().system_inst(mov.inc).await.expect("invallid recipient sys id");
|
||||||
let expr = this.0.exprs.get_expr(mov.expr).expect("invalid ticket");
|
let expr = this.0.exprs.get_expr(mov.expr).expect("invalid ticket");
|
||||||
recp.ext().0.exprs.give_expr(expr);
|
recp.ext().0.exprs.give_expr(expr);
|
||||||
@@ -120,7 +138,9 @@ impl Extension {
|
|||||||
clone!(weak, ctx);
|
clone!(weak, ctx);
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let this = Self(weak.upgrade().unwrap());
|
let this = Self(weak.upgrade().unwrap());
|
||||||
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
if !matches!(req, api::ExtHostReq::ExtAtomPrint(_)) {
|
||||||
|
writeln!(this.reqnot().logger(), "Host received request {req:?}");
|
||||||
|
}
|
||||||
let i = this.ctx().i.clone();
|
let i = this.ctx().i.clone();
|
||||||
match req {
|
match req {
|
||||||
api::ExtHostReq::Ping(ping) => hand.handle(&ping, &()).await,
|
api::ExtHostReq::Ping(ping) => hand.handle(&ping, &()).await,
|
||||||
@@ -235,8 +255,9 @@ impl Extension {
|
|||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
pub fn name(&self) -> &String { &self.0.name }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { &self.0.reqnot }
|
pub fn reqnot(&self) -> &ReqNot<api::HostMsgSet> { &self.0.reqnot }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn ctx(&self) -> &Ctx { &self.0.ctx }
|
pub fn ctx(&self) -> &Ctx { &self.0.ctx }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -246,12 +267,12 @@ impl Extension {
|
|||||||
pub fn exprs(&self) -> &ExprStore { &self.0.exprs }
|
pub fn exprs(&self) -> &ExprStore { &self.0.exprs }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn is_own_sys(&self, id: api::SysId) -> bool {
|
pub async fn is_own_sys(&self, id: api::SysId) -> bool {
|
||||||
let sys = self.ctx().system_inst(id).await.expect("invalid sender sys id");
|
let Some(sys) = self.ctx().system_inst(id).await else {
|
||||||
|
writeln!(self.logger(), "Invalid system ID {id:?}");
|
||||||
|
return false;
|
||||||
|
};
|
||||||
Rc::ptr_eq(&self.0, &sys.ext().0)
|
Rc::ptr_eq(&self.0, &sys.ext().0)
|
||||||
}
|
}
|
||||||
pub async fn assert_own_sys(&self, id: api::SysId) {
|
|
||||||
assert!(self.is_own_sys(id).await, "Incoming message impersonates separate system");
|
|
||||||
}
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn next_pars(&self) -> NonZeroU64 {
|
pub fn next_pars(&self) -> NonZeroU64 {
|
||||||
let mut next_pars = self.0.next_pars.borrow_mut();
|
let mut next_pars = self.0.next_pars.borrow_mut();
|
||||||
@@ -260,7 +281,7 @@ impl Extension {
|
|||||||
}
|
}
|
||||||
pub(crate) async fn lex_req<F: Future<Output = Option<api::SubLexed>>>(
|
pub(crate) async fn lex_req<F: Future<Output = Option<api::SubLexed>>>(
|
||||||
&self,
|
&self,
|
||||||
source: IStr,
|
source: Tok<String>,
|
||||||
src: Sym,
|
src: Sym,
|
||||||
pos: u32,
|
pos: u32,
|
||||||
sys: api::SysId,
|
sys: api::SysId,
|
||||||
@@ -293,7 +314,7 @@ impl Extension {
|
|||||||
pub fn system_drop(&self, id: api::SysId) {
|
pub fn system_drop(&self, id: api::SysId) {
|
||||||
let rc = self.clone();
|
let rc = self.clone();
|
||||||
(self.ctx().spawn)(Box::pin(async move {
|
(self.ctx().spawn)(Box::pin(async move {
|
||||||
rc.reqnot().notify(api::SystemDrop(id)).await;
|
rc.reqnot().request(api::SystemDrop(id)).await;
|
||||||
rc.ctx().systems.write().await.remove(&id);
|
rc.ctx().systems.write().await.remove(&id);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,22 +2,25 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::lock::Mutex;
|
use futures::lock::Mutex;
|
||||||
use orchid_base::error::{OrcErrv, OrcRes, mk_err};
|
use orchid_base::clone;
|
||||||
|
use orchid_base::error::{OrcErrv, OrcRes, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
use orchid_base::parse::{name_char, name_start, op_char, unrep_space};
|
||||||
use orchid_base::tokens::PARENS;
|
use orchid_base::tokens::PARENS;
|
||||||
|
use orchid_base::tree::recur;
|
||||||
|
|
||||||
use crate::api;
|
use crate::api;
|
||||||
use crate::ctx::Ctx;
|
use crate::ctx::Ctx;
|
||||||
use crate::expr::{Expr, ExprParseCtx};
|
use crate::expr::{Expr, ExprParseCtx};
|
||||||
|
use crate::expr_store::ExprStore;
|
||||||
use crate::parsed::{ParsTok, ParsTokTree, tt_to_api};
|
use crate::parsed::{ParsTok, ParsTokTree, tt_to_api};
|
||||||
use crate::system::System;
|
use crate::system::System;
|
||||||
|
|
||||||
pub struct LexCtx<'a> {
|
pub struct LexCtx<'a> {
|
||||||
pub systems: &'a [System],
|
pub systems: &'a [System],
|
||||||
pub source: &'a IStr,
|
pub source: &'a Tok<String>,
|
||||||
pub path: &'a Sym,
|
pub path: &'a Sym,
|
||||||
pub tail: &'a str,
|
pub tail: &'a str,
|
||||||
pub sub_trees: &'a mut Vec<Expr>,
|
pub sub_trees: &'a mut Vec<Expr>,
|
||||||
@@ -52,14 +55,14 @@ impl<'a> LexCtx<'a> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn ser_subtree(&mut self, subtree: ParsTokTree) -> api::TokenTree {
|
pub async fn ser_subtree(&mut self, subtree: ParsTokTree, exprs: ExprStore) -> api::TokenTree {
|
||||||
tt_to_api(&mut self.ctx.common_exprs.clone(), subtree).await
|
tt_to_api(&mut { exprs }, subtree).await
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn des_subtree(&mut self, tree: &api::TokenTree) -> ParsTokTree {
|
pub async fn des_subtree(&mut self, tree: &api::TokenTree, exprs: ExprStore) -> ParsTokTree {
|
||||||
ParsTokTree::from_api(
|
ParsTokTree::from_api(
|
||||||
tree,
|
tree,
|
||||||
&mut self.ctx.common_exprs.clone(),
|
&mut { exprs },
|
||||||
&mut ExprParseCtx { ctx: self.ctx, exprs: &self.ctx.common_exprs },
|
&mut ExprParseCtx { ctx: self.ctx, exprs: &self.ctx.common_exprs },
|
||||||
self.path,
|
self.path,
|
||||||
&self.ctx.i,
|
&self.ctx.i,
|
||||||
@@ -105,7 +108,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
ParsTok::NS(ctx.ctx.i.i(name).await, Box::new(body))
|
ParsTok::NS(ctx.ctx.i.i(name).await, Box::new(body))
|
||||||
} else if ctx.strip_prefix("--[") {
|
} else if ctx.strip_prefix("--[") {
|
||||||
let Some((cmt, tail)) = ctx.tail.split_once("]--") else {
|
let Some((cmt, tail)) = ctx.tail.split_once("]--") else {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.ctx.i.i("Unterminated block comment").await,
|
ctx.ctx.i.i("Unterminated block comment").await,
|
||||||
"This block comment has no ending ]--",
|
"This block comment has no ending ]--",
|
||||||
[SrcRange::new(start..start + 3, ctx.path)],
|
[SrcRange::new(start..start + 3, ctx.path)],
|
||||||
@@ -128,7 +131,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
ctx.trim_ws();
|
ctx.trim_ws();
|
||||||
while !ctx.strip_char(*rp) {
|
while !ctx.strip_char(*rp) {
|
||||||
if ctx.tail.is_empty() {
|
if ctx.tail.is_empty() {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.ctx.i.i("unclosed paren").await,
|
ctx.ctx.i.i("unclosed paren").await,
|
||||||
format!("this {lp} has no matching {rp}"),
|
format!("this {lp} has no matching {rp}"),
|
||||||
[SrcRange::new(start..start + 1, ctx.path)],
|
[SrcRange::new(start..start + 1, ctx.path)],
|
||||||
@@ -145,15 +148,23 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
let (source, pos, path) = (ctx.source.clone(), ctx.get_pos(), ctx.path.clone());
|
let (source, pos, path) = (ctx.source.clone(), ctx.get_pos(), ctx.path.clone());
|
||||||
let ctx_lck = &Mutex::new(&mut *ctx);
|
let ctx_lck = &Mutex::new(&mut *ctx);
|
||||||
let errors_lck = &Mutex::new(&mut errors);
|
let errors_lck = &Mutex::new(&mut errors);
|
||||||
|
let temp_store = sys.ext().exprs().derive(true);
|
||||||
|
let temp_store_cb = temp_store.clone();
|
||||||
let lx = sys
|
let lx = sys
|
||||||
.lex(source, path, pos, |pos| async move {
|
.lex(source, path, pos, |pos| {
|
||||||
let mut ctx_g = ctx_lck.lock().await;
|
clone!(temp_store_cb);
|
||||||
match lex_once(&mut ctx_g.push(pos)).boxed_local().await {
|
async move {
|
||||||
Ok(t) => Some(api::SubLexed { pos: t.sr.end(), tree: ctx_g.ser_subtree(t).await }),
|
let mut ctx_g = ctx_lck.lock().await;
|
||||||
Err(e) => {
|
match lex_once(&mut ctx_g.push(pos)).boxed_local().await {
|
||||||
errors_lck.lock().await.push(e);
|
Ok(t) => Some(api::SubLexed {
|
||||||
None
|
pos: t.sr.end(),
|
||||||
},
|
tree: ctx_g.ser_subtree(t, temp_store_cb.clone()).await,
|
||||||
|
}),
|
||||||
|
Err(e) => {
|
||||||
|
errors_lck.lock().await.push(e);
|
||||||
|
None
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@@ -164,7 +175,14 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
),
|
),
|
||||||
Ok(Some(lexed)) => {
|
Ok(Some(lexed)) => {
|
||||||
ctx.set_pos(lexed.pos);
|
ctx.set_pos(lexed.pos);
|
||||||
return Ok(ctx.des_subtree(&lexed.expr).await);
|
let lexed_tree = ctx.des_subtree(&lexed.expr, temp_store).await;
|
||||||
|
let stable_tree = recur(lexed_tree, &|tt, r| {
|
||||||
|
if let ParsTok::NewExpr(expr) = tt.tok {
|
||||||
|
return ParsTok::Handle(expr).at(tt.sr);
|
||||||
|
}
|
||||||
|
r(tt)
|
||||||
|
});
|
||||||
|
return Ok(stable_tree);
|
||||||
},
|
},
|
||||||
Ok(None) => match errors.into_iter().reduce(|a, b| a + b) {
|
Ok(None) => match errors.into_iter().reduce(|a, b| a + b) {
|
||||||
Some(errors) => return Err(errors),
|
Some(errors) => return Err(errors),
|
||||||
@@ -178,7 +196,7 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
} else if ctx.tail.starts_with(op_char) {
|
} else if ctx.tail.starts_with(op_char) {
|
||||||
ParsTok::Name(ctx.ctx.i.i(ctx.get_start_matches(op_char)).await)
|
ParsTok::Name(ctx.ctx.i.i(ctx.get_start_matches(op_char)).await)
|
||||||
} else {
|
} else {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.ctx.i.i("Unrecognized character").await,
|
ctx.ctx.i.i("Unrecognized character").await,
|
||||||
"The following syntax is meaningless.",
|
"The following syntax is meaningless.",
|
||||||
[SrcRange::new(start..start + 1, ctx.path)],
|
[SrcRange::new(start..start + 1, ctx.path)],
|
||||||
@@ -188,7 +206,12 @@ pub async fn lex_once(ctx: &mut LexCtx<'_>) -> OrcRes<ParsTokTree> {
|
|||||||
Ok(ParsTokTree { tok, sr: SrcRange::new(start..ctx.get_pos(), ctx.path) })
|
Ok(ParsTokTree { tok, sr: SrcRange::new(start..ctx.get_pos(), ctx.path) })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn lex(text: IStr, path: Sym, systems: &[System], ctx: &Ctx) -> OrcRes<Vec<ParsTokTree>> {
|
pub async fn lex(
|
||||||
|
text: Tok<String>,
|
||||||
|
path: Sym,
|
||||||
|
systems: &[System],
|
||||||
|
ctx: &Ctx,
|
||||||
|
) -> OrcRes<Vec<ParsTokTree>> {
|
||||||
let mut sub_trees = Vec::new();
|
let mut sub_trees = Vec::new();
|
||||||
let mut ctx =
|
let mut ctx =
|
||||||
LexCtx { source: &text, sub_trees: &mut sub_trees, tail: &text[..], systems, path: &path, ctx };
|
LexCtx { source: &text, sub_trees: &mut sub_trees, tail: &text[..], systems, path: &path, ctx };
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_err};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::format::fmt;
|
use orchid_base::format::fmt;
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
@@ -47,7 +47,7 @@ pub trait HostParseCtx: ParseCtx {
|
|||||||
|
|
||||||
pub async fn parse_items(
|
pub async fn parse_items(
|
||||||
ctx: &impl HostParseCtx,
|
ctx: &impl HostParseCtx,
|
||||||
path: Substack<'_, IStr>,
|
path: Substack<'_, Tok<String>>,
|
||||||
items: ParsSnippet<'_>,
|
items: ParsSnippet<'_>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
let lines = line_items(ctx, items).await;
|
let lines = line_items(ctx, items).await;
|
||||||
@@ -58,7 +58,7 @@ pub async fn parse_items(
|
|||||||
|
|
||||||
pub async fn parse_item(
|
pub async fn parse_item(
|
||||||
ctx: &impl HostParseCtx,
|
ctx: &impl HostParseCtx,
|
||||||
path: Substack<'_, IStr>,
|
path: Substack<'_, Tok<String>>,
|
||||||
comments: Vec<Comment>,
|
comments: Vec<Comment>,
|
||||||
item: ParsSnippet<'_>,
|
item: ParsSnippet<'_>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
@@ -67,7 +67,7 @@ pub async fn parse_item(
|
|||||||
n if *n == ctx.i().i("export").await => match try_pop_no_fluff(ctx, postdisc).await? {
|
n if *n == ctx.i().i("export").await => match try_pop_no_fluff(ctx, postdisc).await? {
|
||||||
Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } =>
|
Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } =>
|
||||||
parse_exportable_item(ctx, path, comments, true, n.clone(), tail).await,
|
parse_exportable_item(ctx, path, comments, true, n.clone(), tail).await,
|
||||||
Parsed { output, tail: _ } => Err(mk_err(
|
Parsed { output, tail: _ } => Err(mk_errv(
|
||||||
ctx.i().i("Malformed export").await,
|
ctx.i().i("Malformed export").await,
|
||||||
"`export` can either prefix other lines or list names inside ( )",
|
"`export` can either prefix other lines or list names inside ( )",
|
||||||
[output.sr()],
|
[output.sr()],
|
||||||
@@ -83,10 +83,11 @@ pub async fn parse_item(
|
|||||||
},
|
},
|
||||||
n => parse_exportable_item(ctx, path, comments, false, n.clone(), postdisc).await,
|
n => parse_exportable_item(ctx, path, comments, false, n.clone(), postdisc).await,
|
||||||
},
|
},
|
||||||
Some(_) =>
|
Some(_) => Err(mk_errv(
|
||||||
Err(mk_err(ctx.i().i("Expected a line type").await, "All lines must begin with a keyword", [
|
ctx.i().i("Expected a line type").await,
|
||||||
item.sr(),
|
"All lines must begin with a keyword",
|
||||||
])),
|
[item.sr()],
|
||||||
|
)),
|
||||||
None => unreachable!("These lines are filtered and aggregated in earlier stages"),
|
None => unreachable!("These lines are filtered and aggregated in earlier stages"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,10 +103,10 @@ pub async fn parse_import<'a>(
|
|||||||
|
|
||||||
pub async fn parse_exportable_item<'a>(
|
pub async fn parse_exportable_item<'a>(
|
||||||
ctx: &impl HostParseCtx,
|
ctx: &impl HostParseCtx,
|
||||||
path: Substack<'_, IStr>,
|
path: Substack<'_, Tok<String>>,
|
||||||
comments: Vec<Comment>,
|
comments: Vec<Comment>,
|
||||||
exported: bool,
|
exported: bool,
|
||||||
discr: IStr,
|
discr: Tok<String>,
|
||||||
tail: ParsSnippet<'a>,
|
tail: ParsSnippet<'a>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
let kind = if discr == ctx.i().i("mod").await {
|
let kind = if discr == ctx.i().i("mod").await {
|
||||||
@@ -120,7 +121,7 @@ pub async fn parse_exportable_item<'a>(
|
|||||||
.await;
|
.await;
|
||||||
} else {
|
} else {
|
||||||
let ext_lines = ctx.systems().flat_map(System::line_types).join(", ");
|
let ext_lines = ctx.systems().flat_map(System::line_types).join(", ");
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("Unrecognized line type").await,
|
ctx.i().i("Unrecognized line type").await,
|
||||||
format!("Line types are: mod, {ext_lines}"),
|
format!("Line types are: mod, {ext_lines}"),
|
||||||
[tail.prev().sr()],
|
[tail.prev().sr()],
|
||||||
@@ -131,13 +132,13 @@ pub async fn parse_exportable_item<'a>(
|
|||||||
|
|
||||||
pub async fn parse_module<'a>(
|
pub async fn parse_module<'a>(
|
||||||
ctx: &impl HostParseCtx,
|
ctx: &impl HostParseCtx,
|
||||||
path: Substack<'_, IStr>,
|
path: Substack<'_, Tok<String>>,
|
||||||
tail: ParsSnippet<'a>,
|
tail: ParsSnippet<'a>,
|
||||||
) -> OrcRes<(IStr, ParsedModule)> {
|
) -> OrcRes<(Tok<String>, ParsedModule)> {
|
||||||
let (name, tail) = match try_pop_no_fluff(ctx, tail).await? {
|
let (name, tail) = match try_pop_no_fluff(ctx, tail).await? {
|
||||||
Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } => (n.clone(), tail),
|
Parsed { output: TokTree { tok: Token::Name(n), .. }, tail } => (n.clone(), tail),
|
||||||
Parsed { output, .. } => {
|
Parsed { output, .. } => {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("Missing module name").await,
|
ctx.i().i("Missing module name").await,
|
||||||
format!("A name was expected, {} was found", fmt(output, ctx.i()).await),
|
format!("A name was expected, {} was found", fmt(output, ctx.i()).await),
|
||||||
[output.sr()],
|
[output.sr()],
|
||||||
@@ -147,7 +148,7 @@ pub async fn parse_module<'a>(
|
|||||||
let Parsed { output, tail: surplus } = try_pop_no_fluff(ctx, tail).await?;
|
let Parsed { output, tail: surplus } = try_pop_no_fluff(ctx, tail).await?;
|
||||||
expect_end(ctx, surplus).await?;
|
expect_end(ctx, surplus).await?;
|
||||||
let Some(body) = output.as_s(Paren::Round) else {
|
let Some(body) = output.as_s(Paren::Round) else {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("Expected module body").await,
|
ctx.i().i("Expected module body").await,
|
||||||
format!("A ( block ) was expected, {} was found", fmt(output, ctx.i()).await),
|
format!("A ( block ) was expected, {} was found", fmt(output, ctx.i()).await),
|
||||||
[output.sr()],
|
[output.sr()],
|
||||||
|
|||||||
@@ -69,14 +69,14 @@ impl Format for Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParsedMember {
|
pub struct ParsedMember {
|
||||||
pub name: IStr,
|
pub name: Tok<String>,
|
||||||
pub exported: bool,
|
pub exported: bool,
|
||||||
pub kind: ParsedMemberKind,
|
pub kind: ParsedMemberKind,
|
||||||
}
|
}
|
||||||
impl ParsedMember {
|
impl ParsedMember {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn name(&self) -> IStr { self.name.clone() }
|
pub fn name(&self) -> Tok<String> { self.name.clone() }
|
||||||
pub fn new(exported: bool, name: IStr, kind: impl Into<ParsedMemberKind>) -> Self {
|
pub fn new(exported: bool, name: Tok<String>, kind: impl Into<ParsedMemberKind>) -> Self {
|
||||||
Self { exported, name, kind: kind.into() }
|
Self { exported, name, kind: kind.into() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,14 +90,14 @@ impl Debug for ParsedMember {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type ParsedExprCallback =
|
pub(crate) type ParsedExprCallback =
|
||||||
Rc<dyn for<'a> Fn(&'a [IStr]) -> LocalBoxFuture<'a, Expr>>;
|
Rc<dyn for<'a> Fn(&'a [Tok<String>]) -> LocalBoxFuture<'a, Expr>>;
|
||||||
|
|
||||||
pub struct ParsedExpr {
|
pub struct ParsedExpr {
|
||||||
pub(crate) debug: String,
|
pub(crate) debug: String,
|
||||||
pub(crate) callback: ParsedExprCallback,
|
pub(crate) callback: ParsedExprCallback,
|
||||||
}
|
}
|
||||||
impl ParsedExpr {
|
impl ParsedExpr {
|
||||||
pub async fn run(self, imported_names: &[IStr]) -> Expr {
|
pub async fn run(self, imported_names: &[Tok<String>]) -> Expr {
|
||||||
(self.callback)(imported_names).await
|
(self.callback)(imported_names).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,10 +113,9 @@ pub enum ParsedMemberKind {
|
|||||||
impl From<ParsedModule> for ParsedMemberKind {
|
impl From<ParsedModule> for ParsedMemberKind {
|
||||||
fn from(value: ParsedModule) -> Self { Self::Mod(value) }
|
fn from(value: ParsedModule) -> Self { Self::Mod(value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ParsedModule {
|
pub struct ParsedModule {
|
||||||
pub exports: Vec<IStr>,
|
pub exports: Vec<Tok<String>>,
|
||||||
pub items: Vec<Item>,
|
pub items: Vec<Item>,
|
||||||
pub use_prelude: bool,
|
pub use_prelude: bool,
|
||||||
}
|
}
|
||||||
@@ -142,7 +141,7 @@ impl ParsedModule {
|
|||||||
(self.items.iter())
|
(self.items.iter())
|
||||||
.filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None })
|
.filter_map(|it| if let ItemKind::Import(i) = &it.kind { Some(i) } else { None })
|
||||||
}
|
}
|
||||||
pub fn default_item(self, name: IStr, sr: SrcRange) -> Item {
|
pub fn default_item(self, name: Tok<String>, sr: SrcRange) -> Item {
|
||||||
let mem = ParsedMember { exported: true, name, kind: ParsedMemberKind::Mod(self) };
|
let mem = ParsedMember { exported: true, name, kind: ParsedMemberKind::Mod(self) };
|
||||||
Item { comments: vec![], sr, kind: ItemKind::Member(mem) }
|
Item { comments: vec![], sr, kind: ItemKind::Member(mem) }
|
||||||
}
|
}
|
||||||
@@ -151,7 +150,7 @@ impl Tree for ParsedModule {
|
|||||||
type Ctx<'a> = ();
|
type Ctx<'a> = ();
|
||||||
async fn child(
|
async fn child(
|
||||||
&self,
|
&self,
|
||||||
key: IStr,
|
key: Tok<String>,
|
||||||
public_only: bool,
|
public_only: bool,
|
||||||
(): &mut Self::Ctx<'_>,
|
(): &mut Self::Ctx<'_>,
|
||||||
) -> ChildResult<'_, Self> {
|
) -> ChildResult<'_, Self> {
|
||||||
@@ -169,7 +168,7 @@ impl Tree for ParsedModule {
|
|||||||
}
|
}
|
||||||
ChildResult::Err(ChildErrorKind::Missing)
|
ChildResult::Err(ChildErrorKind::Missing)
|
||||||
}
|
}
|
||||||
fn children(&self, public_only: bool) -> HashSet<IStr> {
|
fn children(&self, public_only: bool) -> HashSet<Tok<String>> {
|
||||||
let mut public: HashSet<_> = self.exports.iter().cloned().collect();
|
let mut public: HashSet<_> = self.exports.iter().cloned().collect();
|
||||||
if !public_only {
|
if !public_only {
|
||||||
public.extend(
|
public.extend(
|
||||||
@@ -198,11 +197,11 @@ impl Format for ParsedModule {
|
|||||||
/// point to a module and rule_loc selects a macro rule within that module
|
/// point to a module and rule_loc selects a macro rule within that module
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct ConstPath {
|
pub struct ConstPath {
|
||||||
steps: Tok<Vec<IStr>>,
|
steps: Tok<Vec<Tok<String>>>,
|
||||||
}
|
}
|
||||||
impl ConstPath {
|
impl ConstPath {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn to_const(steps: Tok<Vec<IStr>>) -> Self { Self { steps } }
|
pub fn to_const(steps: Tok<Vec<Tok<String>>>) -> Self { Self { steps } }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn tt_to_api(exprs: &mut ExprStore, subtree: ParsTokTree) -> api::TokenTree {
|
pub async fn tt_to_api(exprs: &mut ExprStore, subtree: ParsTokTree) -> api::TokenTree {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub struct Parser {
|
|||||||
pub(crate) system: System,
|
pub(crate) system: System,
|
||||||
pub(crate) idx: u16,
|
pub(crate) idx: u16,
|
||||||
}
|
}
|
||||||
type ModPath<'a> = Substack<'a, IStr>;
|
type ModPath<'a> = Substack<'a, Tok<String>>;
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
pub async fn parse(
|
pub async fn parse(
|
||||||
@@ -35,12 +35,11 @@ impl Parser {
|
|||||||
comments: Vec<Comment>,
|
comments: Vec<Comment>,
|
||||||
callback: &mut impl AsyncFnMut(ModPath<'_>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
callback: &mut impl AsyncFnMut(ModPath<'_>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
|
let mut temp_store = self.system.ext().exprs().derive(true);
|
||||||
let src_path = line.first().expect("cannot be empty").sr.path();
|
let src_path = line.first().expect("cannot be empty").sr.path();
|
||||||
let line = join_all(
|
let line =
|
||||||
(line.into_iter())
|
join_all((line.into_iter()).map(|t| async { tt_to_api(&mut temp_store.clone(), t).await }))
|
||||||
.map(|t| async { tt_to_api(&mut self.system.ext().exprs().clone(), t).await }),
|
.await;
|
||||||
)
|
|
||||||
.await;
|
|
||||||
let mod_path = ctx.src_path().suffix(path.unreverse(), self.system.i()).await;
|
let mod_path = ctx.src_path().suffix(path.unreverse(), self.system.i()).await;
|
||||||
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
let comments = comments.iter().map(Comment::to_api).collect_vec();
|
||||||
let req = api::ParseLine {
|
let req = api::ParseLine {
|
||||||
@@ -53,18 +52,16 @@ impl Parser {
|
|||||||
line,
|
line,
|
||||||
};
|
};
|
||||||
match self.system.reqnot().request(req).await {
|
match self.system.reqnot().request(req).await {
|
||||||
Ok(parsed_v) => {
|
Ok(parsed_v) =>
|
||||||
let mut ext_exprs = self.system.ext().exprs().clone();
|
|
||||||
conv(parsed_v, path, callback, &mut ConvCtx {
|
conv(parsed_v, path, callback, &mut ConvCtx {
|
||||||
i: self.system.i(),
|
i: self.system.i(),
|
||||||
mod_path: &mod_path,
|
mod_path: &mod_path,
|
||||||
ext_exprs: &mut ext_exprs,
|
ext_exprs: &mut temp_store,
|
||||||
pctx: &mut ExprParseCtx { ctx: self.system.ctx(), exprs: self.system.ext().exprs() },
|
pctx: &mut ExprParseCtx { ctx: self.system.ctx(), exprs: self.system.ext().exprs() },
|
||||||
src_path: &src_path,
|
src_path: &src_path,
|
||||||
sys: &self.system,
|
sys: &self.system,
|
||||||
})
|
})
|
||||||
.await
|
.await,
|
||||||
},
|
|
||||||
Err(e) => Err(OrcErrv::from_api(&e, &self.system.ctx().i).await),
|
Err(e) => Err(OrcErrv::from_api(&e, &self.system.ctx().i).await),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,8 +77,8 @@ struct ConvCtx<'a> {
|
|||||||
}
|
}
|
||||||
async fn conv(
|
async fn conv(
|
||||||
parsed_v: Vec<api::ParsedLine>,
|
parsed_v: Vec<api::ParsedLine>,
|
||||||
module: Substack<'_, IStr>,
|
module: Substack<'_, Tok<String>>,
|
||||||
callback: &'_ mut impl AsyncFnMut(Substack<'_, IStr>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
callback: &'_ mut impl AsyncFnMut(Substack<'_, Tok<String>>, Vec<ParsTokTree>) -> OrcRes<Vec<Item>>,
|
||||||
ctx: &mut ConvCtx<'_>,
|
ctx: &mut ConvCtx<'_>,
|
||||||
) -> OrcRes<Vec<Item>> {
|
) -> OrcRes<Vec<Item>> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use hashbrown::HashMap;
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use orchid_base::char_filter::char_filter_match;
|
use orchid_base::char_filter::char_filter_match;
|
||||||
use orchid_base::error::{OrcRes, mk_err_floating};
|
use orchid_base::error::{OrcRes, mk_errv_floating};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format};
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::iter_utils::IteratorPrint;
|
use orchid_base::iter_utils::IteratorPrint;
|
||||||
@@ -35,7 +35,7 @@ pub(crate) struct SystemInstData {
|
|||||||
decl_id: api::SysDeclId,
|
decl_id: api::SysDeclId,
|
||||||
lex_filter: api::CharFilter,
|
lex_filter: api::CharFilter,
|
||||||
id: api::SysId,
|
id: api::SysId,
|
||||||
line_types: Vec<IStr>,
|
line_types: Vec<Tok<String>>,
|
||||||
prelude: Vec<Sym>,
|
prelude: Vec<Sym>,
|
||||||
owned_atoms: RwLock<HashMap<api::AtomId, WeakAtomHand>>,
|
owned_atoms: RwLock<HashMap<api::AtomId, WeakAtomHand>>,
|
||||||
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
pub(crate) const_paths: MemoMap<api::ParsedConstId, Sym>,
|
||||||
@@ -57,6 +57,10 @@ impl fmt::Debug for SystemInstData {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct System(pub(crate) Rc<SystemInstData>);
|
pub struct System(pub(crate) Rc<SystemInstData>);
|
||||||
impl System {
|
impl System {
|
||||||
|
#[must_use]
|
||||||
|
pub async fn atoms(&self) -> impl std::ops::Deref<Target = HashMap<api::AtomId, WeakAtomHand>> {
|
||||||
|
self.0.owned_atoms.read().await
|
||||||
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn id(&self) -> api::SysId { self.0.id }
|
pub fn id(&self) -> api::SysId { self.0.id }
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -88,7 +92,7 @@ impl System {
|
|||||||
/// [Self::can_lex] was called and returned true.
|
/// [Self::can_lex] was called and returned true.
|
||||||
pub async fn lex<F: Future<Output = Option<api::SubLexed>>>(
|
pub async fn lex<F: Future<Output = Option<api::SubLexed>>>(
|
||||||
&self,
|
&self,
|
||||||
source: IStr,
|
source: Tok<String>,
|
||||||
src: Sym,
|
src: Sym,
|
||||||
pos: u32,
|
pos: u32,
|
||||||
r: impl FnMut(u32) -> F,
|
r: impl FnMut(u32) -> F,
|
||||||
@@ -96,12 +100,12 @@ impl System {
|
|||||||
self.0.ext.lex_req(source, src, pos, self.id(), r).await
|
self.0.ext.lex_req(source, src, pos, self.id(), r).await
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn get_parser(&self, ltyp: IStr) -> Option<Parser> {
|
pub fn get_parser(&self, ltyp: Tok<String>) -> Option<Parser> {
|
||||||
(self.0.line_types.iter().enumerate())
|
(self.0.line_types.iter().enumerate())
|
||||||
.find(|(_, txt)| *txt == <yp)
|
.find(|(_, txt)| *txt == <yp)
|
||||||
.map(|(idx, _)| Parser { idx: idx as u16, system: self.clone() })
|
.map(|(idx, _)| Parser { idx: idx as u16, system: self.clone() })
|
||||||
}
|
}
|
||||||
pub fn line_types(&self) -> impl Iterator<Item = &IStr> + '_ { self.0.line_types.iter() }
|
pub fn line_types(&self) -> impl Iterator<Item = &Tok<String>> + '_ { self.0.line_types.iter() }
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
|
pub async fn request(&self, req: Vec<u8>) -> Vec<u8> {
|
||||||
@@ -118,19 +122,22 @@ impl System {
|
|||||||
owned_g.insert(id, new.downgrade());
|
owned_g.insert(id, new.downgrade());
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
pub(crate) fn drop_atom(&self, drop: api::AtomId) {
|
pub(crate) fn drop_atom(&self, dropped_atom_id: api::AtomId) {
|
||||||
let this = self.0.clone();
|
let this = self.0.clone();
|
||||||
(self.0.ctx.spawn)(Box::pin(async move {
|
(self.0.ctx.spawn)(Box::pin(async move {
|
||||||
this.owned_atoms.write().await.remove(&drop);
|
this.ext.reqnot().request(api::AtomDrop(this.id, dropped_atom_id)).await;
|
||||||
|
this.owned_atoms.write().await.remove(&dropped_atom_id);
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn downgrade(&self) -> WeakSystem { WeakSystem(Rc::downgrade(&self.0)) }
|
pub fn downgrade(&self) -> WeakSystem {
|
||||||
|
WeakSystem(Rc::downgrade(&self.0), self.0.decl_id, self.ext().downgrade())
|
||||||
|
}
|
||||||
/// Implementation of [api::ResolveNames]
|
/// Implementation of [api::ResolveNames]
|
||||||
pub(crate) async fn name_resolver(
|
pub(crate) async fn name_resolver(
|
||||||
&self,
|
&self,
|
||||||
orig: api::ParsedConstId,
|
orig: api::ParsedConstId,
|
||||||
) -> impl AsyncFnMut(&[IStr]) -> OrcRes<VName> + use<> {
|
) -> impl AsyncFnMut(&[Tok<String>]) -> OrcRes<VName> + use<> {
|
||||||
let root = self.0.ctx.root.read().await.upgrade().expect("find_names when root not in context");
|
let root = self.0.ctx.root.read().await.upgrade().expect("find_names when root not in context");
|
||||||
let orig = self.0.const_paths.get(&orig).expect("origin for find_names invalid").clone();
|
let orig = self.0.const_paths.get(&orig).expect("origin for find_names invalid").clone();
|
||||||
let ctx = self.0.ctx.clone();
|
let ctx = self.0.ctx.clone();
|
||||||
@@ -147,7 +154,7 @@ impl System {
|
|||||||
match cmod.imports.get(selector) {
|
match cmod.imports.get(selector) {
|
||||||
Some(Ok(dest)) => return Ok(dest.target.to_vname().suffix(tail.iter().cloned())),
|
Some(Ok(dest)) => return Ok(dest.target.to_vname().suffix(tail.iter().cloned())),
|
||||||
Some(Err(dests)) =>
|
Some(Err(dests)) =>
|
||||||
return Err(mk_err_floating(
|
return Err(mk_errv_floating(
|
||||||
ctx.i.i("Ambiguous name").await,
|
ctx.i.i("Ambiguous name").await,
|
||||||
format!(
|
format!(
|
||||||
"{selector} could refer to {}",
|
"{selector} could refer to {}",
|
||||||
@@ -159,7 +166,7 @@ impl System {
|
|||||||
if tail.is_empty() {
|
if tail.is_empty() {
|
||||||
return Ok(VPath::new(cwd.iter().cloned()).name_with_suffix(selector.clone()));
|
return Ok(VPath::new(cwd.iter().cloned()).name_with_suffix(selector.clone()));
|
||||||
}
|
}
|
||||||
Err(mk_err_floating(
|
Err(mk_errv_floating(
|
||||||
ctx.i.i("Invalid name").await,
|
ctx.i.i("Invalid name").await,
|
||||||
format!("{selector} doesn't refer to a module"),
|
format!("{selector} doesn't refer to a module"),
|
||||||
))
|
))
|
||||||
@@ -174,10 +181,14 @@ impl Format for System {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WeakSystem(Weak<SystemInstData>);
|
pub struct WeakSystem(Weak<SystemInstData>, api::SysDeclId, WeakExtension);
|
||||||
impl WeakSystem {
|
impl WeakSystem {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn upgrade(&self) -> Option<System> { self.0.upgrade().map(System) }
|
pub fn upgrade(&self) -> Option<System> { self.0.upgrade().map(System) }
|
||||||
|
pub fn ext(&self) -> Option<Extension> { self.2.upgrade() }
|
||||||
|
pub fn ctor(&self) -> Option<SystemCtor> {
|
||||||
|
self.ext()?.system_ctors().find(|ctor| ctor.decl.id == self.1).cloned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ use std::slice;
|
|||||||
|
|
||||||
use async_lock::RwLock;
|
use async_lock::RwLock;
|
||||||
use async_once_cell::OnceCell;
|
use async_once_cell::OnceCell;
|
||||||
|
use derive_destructure::destructure;
|
||||||
use futures::{FutureExt, StreamExt, stream};
|
use futures::{FutureExt, StreamExt, stream};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use hashbrown::hash_map::Entry;
|
use hashbrown::hash_map::Entry;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use memo_map::MemoMap;
|
use memo_map::MemoMap;
|
||||||
use orchid_base::clone;
|
use orchid_base::clone;
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_err};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::{CodeGenInfo, Pos};
|
use orchid_base::location::{CodeGenInfo, Pos};
|
||||||
use orchid_base::name::{NameLike, Sym, VPath};
|
use orchid_base::name::{NameLike, Sym, VPath};
|
||||||
@@ -88,7 +89,7 @@ impl Root {
|
|||||||
*this.ctx.root.write().await = new.downgrade();
|
*this.ctx.root.write().await = new.downgrade();
|
||||||
for (path, (sys_id, pc_id)) in deferred_consts {
|
for (path, (sys_id, pc_id)) in deferred_consts {
|
||||||
let sys = this.ctx.system_inst(sys_id).await.expect("System dropped since parsing");
|
let sys = this.ctx.system_inst(sys_id).await.expect("System dropped since parsing");
|
||||||
let api_expr = sys.reqnot().request(api::FetchParsedConst { id: pc_id, sys: sys.id() }).await;
|
let api_expr = sys.reqnot().request(api::FetchParsedConst(sys.id(), pc_id)).await;
|
||||||
let mut xp_ctx = ExprParseCtx { ctx: &this.ctx, exprs: sys.ext().exprs() };
|
let mut xp_ctx = ExprParseCtx { ctx: &this.ctx, exprs: sys.ext().exprs() };
|
||||||
let expr = Expr::from_api(&api_expr, PathSetBuilder::new(), &mut xp_ctx).await;
|
let expr = Expr::from_api(&api_expr, PathSetBuilder::new(), &mut xp_ctx).await;
|
||||||
new.0.write().await.consts.insert(path, expr);
|
new.0.write().await.consts.insert(path, expr);
|
||||||
@@ -109,7 +110,7 @@ impl Root {
|
|||||||
return Ok(val.clone());
|
return Ok(val.clone());
|
||||||
}
|
}
|
||||||
match module {
|
match module {
|
||||||
Ok(_) => Err(mk_err(
|
Ok(_) => Err(mk_errv(
|
||||||
ctx.i.i("module used as constant").await,
|
ctx.i.i("module used as constant").await,
|
||||||
format!("{name} is a module, not a constant"),
|
format!("{name} is a module, not a constant"),
|
||||||
[pos],
|
[pos],
|
||||||
@@ -117,7 +118,7 @@ impl Root {
|
|||||||
Err(e) => match e.kind {
|
Err(e) => match e.kind {
|
||||||
ChildErrorKind::Private => panic!("public_only is false"),
|
ChildErrorKind::Private => panic!("public_only is false"),
|
||||||
ChildErrorKind::Constant => panic!("Tree refers to constant not in table"),
|
ChildErrorKind::Constant => panic!("Tree refers to constant not in table"),
|
||||||
ChildErrorKind::Missing => Err(mk_err(
|
ChildErrorKind::Missing => Err(mk_errv(
|
||||||
ctx.i.i("Constant does not exist").await,
|
ctx.i.i("Constant does not exist").await,
|
||||||
format!("{name} does not refer to a constant"),
|
format!("{name} does not refer to a constant"),
|
||||||
[pos],
|
[pos],
|
||||||
@@ -144,11 +145,11 @@ impl Default for WeakRoot {
|
|||||||
pub struct TreeFromApiCtx<'a> {
|
pub struct TreeFromApiCtx<'a> {
|
||||||
pub sys: &'a System,
|
pub sys: &'a System,
|
||||||
pub consts: &'a MemoMap<Sym, Expr>,
|
pub consts: &'a MemoMap<Sym, Expr>,
|
||||||
pub path: Tok<Vec<IStr>>,
|
pub path: Tok<Vec<Tok<String>>>,
|
||||||
}
|
}
|
||||||
impl<'a> TreeFromApiCtx<'a> {
|
impl<'a> TreeFromApiCtx<'a> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn push<'c>(&'c self, name: IStr) -> TreeFromApiCtx<'c> {
|
pub async fn push<'c>(&'c self, name: Tok<String>) -> TreeFromApiCtx<'c> {
|
||||||
let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await;
|
let path = self.sys.ctx().i.i(&self.path.iter().cloned().chain([name]).collect_vec()).await;
|
||||||
TreeFromApiCtx { path, consts: self.consts, sys: self.sys }
|
TreeFromApiCtx { path, consts: self.consts, sys: self.sys }
|
||||||
}
|
}
|
||||||
@@ -162,8 +163,8 @@ pub struct ResolvedImport {
|
|||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub imports: HashMap<IStr, Result<ResolvedImport, Vec<ResolvedImport>>>,
|
pub imports: HashMap<Tok<String>, Result<ResolvedImport, Vec<ResolvedImport>>>,
|
||||||
pub members: HashMap<IStr, Rc<Member>>,
|
pub members: HashMap<Tok<String>, Rc<Member>>,
|
||||||
}
|
}
|
||||||
impl Module {
|
impl Module {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@@ -268,7 +269,7 @@ impl Module {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for item in values {
|
for item in values {
|
||||||
ctx.rep.report(mk_err(
|
ctx.rep.report(mk_errv(
|
||||||
conflicting_imports_msg.clone(),
|
conflicting_imports_msg.clone(),
|
||||||
format!("{key} is imported multiple times from different modules"),
|
format!("{key} is imported multiple times from different modules"),
|
||||||
[item.sr.pos()],
|
[item.sr.pos()],
|
||||||
@@ -298,7 +299,7 @@ impl Module {
|
|||||||
let Ok(import) = value else { continue };
|
let Ok(import) = value else { continue };
|
||||||
if import.target.strip_prefix(&path[..]).is_some_and(|t| t.starts_with(slice::from_ref(key)))
|
if import.target.strip_prefix(&path[..]).is_some_and(|t| t.starts_with(slice::from_ref(key)))
|
||||||
{
|
{
|
||||||
ctx.rep.report(mk_err(
|
ctx.rep.report(mk_errv(
|
||||||
self_referential_msg.clone(),
|
self_referential_msg.clone(),
|
||||||
format!("import {} points to itself or a path within itself", &import.target),
|
format!("import {} points to itself or a path within itself", &import.target),
|
||||||
[import.pos.clone()],
|
[import.pos.clone()],
|
||||||
@@ -396,7 +397,7 @@ impl Tree for Module {
|
|||||||
type Ctx<'a> = (Ctx, &'a MemoMap<Sym, Expr>);
|
type Ctx<'a> = (Ctx, &'a MemoMap<Sym, Expr>);
|
||||||
async fn child(
|
async fn child(
|
||||||
&self,
|
&self,
|
||||||
key: IStr,
|
key: Tok<String>,
|
||||||
public_only: bool,
|
public_only: bool,
|
||||||
(ctx, consts): &mut Self::Ctx<'_>,
|
(ctx, consts): &mut Self::Ctx<'_>,
|
||||||
) -> crate::dealias::ChildResult<'_, Self> {
|
) -> crate::dealias::ChildResult<'_, Self> {
|
||||||
@@ -411,7 +412,7 @@ impl Tree for Module {
|
|||||||
MemberKind::Const => Err(ChildErrorKind::Constant),
|
MemberKind::Const => Err(ChildErrorKind::Constant),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn children(&self, public_only: bool) -> hashbrown::HashSet<IStr> {
|
fn children(&self, public_only: bool) -> hashbrown::HashSet<Tok<String>> {
|
||||||
self.members.iter().filter(|(_, v)| !public_only || v.public).map(|(k, _)| k.clone()).collect()
|
self.members.iter().filter(|(_, v)| !public_only || v.public).map(|(k, _)| k.clone()).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -450,6 +451,7 @@ impl MemberKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(destructure)]
|
||||||
pub struct LazyMemberHandle {
|
pub struct LazyMemberHandle {
|
||||||
id: api::TreeId,
|
id: api::TreeId,
|
||||||
sys: api::SysId,
|
sys: api::SysId,
|
||||||
@@ -457,19 +459,26 @@ pub struct LazyMemberHandle {
|
|||||||
}
|
}
|
||||||
impl LazyMemberHandle {
|
impl LazyMemberHandle {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub async fn run(self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
pub async fn run(mut self, ctx: Ctx, consts: &MemoMap<Sym, Expr>) -> MemberKind {
|
||||||
let sys = ctx.system_inst(self.sys).await.expect("Missing system for lazy member");
|
let sys = ctx.system_inst(self.sys).await.expect("Missing system for lazy member");
|
||||||
match sys.get_tree(self.id).await {
|
match sys.get_tree(self.id).await {
|
||||||
api::MemberKind::Const(c) => {
|
api::MemberKind::Const(c) => {
|
||||||
let mut pctx = ExprParseCtx { ctx: &ctx, exprs: sys.ext().exprs() };
|
let mut pctx = ExprParseCtx { ctx: &ctx, exprs: sys.ext().exprs() };
|
||||||
let expr = Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await;
|
let expr = Expr::from_api(&c, PathSetBuilder::new(), &mut pctx).await;
|
||||||
consts.insert(self.path, expr);
|
let (.., path) = self.destructure();
|
||||||
|
consts.insert(path, expr);
|
||||||
MemberKind::Const
|
MemberKind::Const
|
||||||
},
|
},
|
||||||
api::MemberKind::Module(m) => MemberKind::Module(
|
api::MemberKind::Module(m) => {
|
||||||
Module::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: self.path.tok() }).await,
|
let (.., path) = self.destructure();
|
||||||
),
|
MemberKind::Module(
|
||||||
api::MemberKind::Lazy(id) => Self { id, ..self }.run(ctx, consts).boxed_local().await,
|
Module::from_api(m, &mut TreeFromApiCtx { sys: &sys, consts, path: path.tok() }).await,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
api::MemberKind::Lazy(id) => {
|
||||||
|
self.id = id;
|
||||||
|
self.run(ctx, consts).boxed_local().await
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ impl Parser for LetLine {
|
|||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
let dealiased = dealias_mac_v(aliased, &ctx, &rep).await;
|
let dealiased = dealias_mac_v(aliased, &ctx, &rep).await;
|
||||||
let macro_input = MacTok::S(Paren::Round, dealiased).at(sr.pos());
|
let macro_input = MacTok::S(Paren::Round, dealiased).at(sr.pos());
|
||||||
if let Some(e) = rep.res() {
|
if let Some(e) = rep.errv() {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(call([
|
Ok(call([
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub fn gen_macro_lib() -> Vec<GenMember> {
|
|||||||
fun(true, "lower", |tpl: TypAtom<MacTree>| async move {
|
fun(true, "lower", |tpl: TypAtom<MacTree>| async move {
|
||||||
let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() };
|
let ctx = LowerCtx { sys: tpl.untyped.ctx().clone(), rep: &Reporter::new() };
|
||||||
let res = own(tpl).await.lower(ctx, Substack::Bottom).await;
|
let res = own(tpl).await.lower(ctx, Substack::Bottom).await;
|
||||||
if let Some(e) = Reporter::new().res() { Err(e) } else { Ok(res) }
|
if let Some(e) = Reporter::new().errv() { Err(e) } else { Ok(res) }
|
||||||
}),
|
}),
|
||||||
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
fun(true, "resolve_recur", |state: TypAtom<RecurState>, tpl: TypAtom<MacTree>| async move {
|
||||||
exec("macros::resolve_recur", async move |mut h| {
|
exec("macros::resolve_recur", async move |mut h| {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use futures::{StreamExt, stream};
|
|||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use never::Never;
|
use never::Never;
|
||||||
use orchid_base::error::{OrcRes, Reporter, mk_err};
|
use orchid_base::error::{OrcRes, Reporter, mk_errv};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
@@ -40,7 +40,7 @@ impl Parser for MacroLine {
|
|||||||
line: PSnippet<'a>,
|
line: PSnippet<'a>,
|
||||||
) -> OrcRes<Vec<ParsedLine>> {
|
) -> OrcRes<Vec<ParsedLine>> {
|
||||||
if exported {
|
if exported {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("macros are always exported").await,
|
ctx.i().i("macros are always exported").await,
|
||||||
"The export keyword is forbidden here to avoid confusion\n\
|
"The export keyword is forbidden here to avoid confusion\n\
|
||||||
because macros are exported by default",
|
because macros are exported by default",
|
||||||
@@ -94,7 +94,7 @@ impl Parser for MacroLine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let Some(macro_name) = keywords.keys().next().cloned() else {
|
let Some(macro_name) = keywords.keys().next().cloned() else {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("macro with no keywords").await,
|
ctx.i().i("macro with no keywords").await,
|
||||||
"Macros must define at least one macro of their own.",
|
"Macros must define at least one macro of their own.",
|
||||||
[kw_line.tail.sr()],
|
[kw_line.tail.sr()],
|
||||||
@@ -109,7 +109,7 @@ impl Parser for MacroLine {
|
|||||||
let Parsed { tail, .. } = expect_tok(&ctx, line.tail, ctx.i().i("rule").await).await?;
|
let Parsed { tail, .. } = expect_tok(&ctx, line.tail, ctx.i().i("rule").await).await?;
|
||||||
let arrow_token = ctx.i().i("=>").await;
|
let arrow_token = ctx.i().i("=>").await;
|
||||||
let Some((pattern, body)) = tail.split_once(|tok| tok.is_kw(arrow_token.clone())) else {
|
let Some((pattern, body)) = tail.split_once(|tok| tok.is_kw(arrow_token.clone())) else {
|
||||||
ctx.rep().report(mk_err(
|
ctx.rep().report(mk_errv(
|
||||||
ctx.i().i("Missing => in rule").await,
|
ctx.i().i("Missing => in rule").await,
|
||||||
"Rule lines are of the form `rule ...pattern => ...body`",
|
"Rule lines are of the form `rule ...pattern => ...body`",
|
||||||
[line.tail.sr()],
|
[line.tail.sr()],
|
||||||
@@ -137,7 +137,7 @@ impl Parser for MacroLine {
|
|||||||
let rep = Reporter::new();
|
let rep = Reporter::new();
|
||||||
let body = dealias_mac_v(body_mactree, &ctx, &rep).await;
|
let body = dealias_mac_v(body_mactree, &ctx, &rep).await;
|
||||||
let macro_input = MacTok::S(Paren::Round, body).at(body_sr.pos());
|
let macro_input = MacTok::S(Paren::Round, body).at(body_sr.pos());
|
||||||
if let Some(e) = rep.res() {
|
if let Some(e) = rep.errv() {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
Ok(call([
|
Ok(call([
|
||||||
@@ -199,7 +199,7 @@ pub struct MacroData {
|
|||||||
pub module: Sym,
|
pub module: Sym,
|
||||||
pub prio: Option<u64>,
|
pub prio: Option<u64>,
|
||||||
pub rules: Vec<Rule>,
|
pub rules: Vec<Rule>,
|
||||||
pub own_kws: Vec<IStr>,
|
pub own_kws: Vec<Tok<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -210,8 +210,8 @@ pub struct Rule {
|
|||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
pub pattern: Matcher,
|
pub pattern: Matcher,
|
||||||
pub glossary: HashSet<Sym>,
|
pub glossary: HashSet<Sym>,
|
||||||
pub placeholders: Vec<IStr>,
|
pub placeholders: Vec<Tok<String>>,
|
||||||
pub body_name: IStr,
|
pub body_name: Tok<String>,
|
||||||
}
|
}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Matcher {
|
pub enum Matcher {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use futures::FutureExt;
|
|||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashSet;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcErrv, Reporter, mk_err};
|
use orchid_base::error::{OrcErrv, Reporter, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
use orchid_base::format::{FmtCtx, FmtUnit, Format, Variants, fmt};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
@@ -42,7 +42,7 @@ impl MacTree {
|
|||||||
MacTok::Bottom(e) => bot(e.clone()),
|
MacTok::Bottom(e) => bot(e.clone()),
|
||||||
MacTok::Lambda(arg, body) => {
|
MacTok::Lambda(arg, body) => {
|
||||||
let MacTok::Name(name) = &*arg.tok else {
|
let MacTok::Name(name) = &*arg.tok else {
|
||||||
let err = mk_err(
|
let err = mk_errv(
|
||||||
ctx.sys.i().i("Syntax error after macros").await,
|
ctx.sys.i().i("Syntax error after macros").await,
|
||||||
"This token ends up as a binding, consider replacing it with a name",
|
"This token ends up as a binding, consider replacing it with a name",
|
||||||
[arg.pos()],
|
[arg.pos()],
|
||||||
@@ -57,7 +57,7 @@ impl MacTree {
|
|||||||
Some((i, _)) => arg((args.len() - i) as u64),
|
Some((i, _)) => arg((args.len() - i) as u64),
|
||||||
},
|
},
|
||||||
MacTok::Ph(ph) => {
|
MacTok::Ph(ph) => {
|
||||||
let err = mk_err(
|
let err = mk_errv(
|
||||||
ctx.sys.i().i("Placeholder in value").await,
|
ctx.sys.i().i("Placeholder in value").await,
|
||||||
format!("Placeholder {ph} is only supported in macro patterns"),
|
format!("Placeholder {ph} is only supported in macro patterns"),
|
||||||
[self.pos()],
|
[self.pos()],
|
||||||
@@ -67,7 +67,7 @@ impl MacTree {
|
|||||||
},
|
},
|
||||||
MacTok::S(Paren::Round, body) => call(lower_v(body, ctx, args).await),
|
MacTok::S(Paren::Round, body) => call(lower_v(body, ctx, args).await),
|
||||||
MacTok::S(..) => {
|
MacTok::S(..) => {
|
||||||
let err = mk_err(
|
let err = mk_errv(
|
||||||
ctx.sys.i().i("[] or {} after macros").await,
|
ctx.sys.i().i("[] or {} after macros").await,
|
||||||
format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await),
|
format!("{} didn't match any macro", fmt(self, ctx.sys.i()).await),
|
||||||
[self.pos()],
|
[self.pos()],
|
||||||
@@ -166,7 +166,7 @@ pub async fn mtreev_fmt<'b>(
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct Ph {
|
pub struct Ph {
|
||||||
pub name: IStr,
|
pub name: Tok<String>,
|
||||||
pub kind: PhKind,
|
pub kind: PhKind,
|
||||||
}
|
}
|
||||||
impl Display for Ph {
|
impl Display for Ph {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use orchid_base::error::{OrcRes, mk_err};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::parse::ParseCtx;
|
use orchid_base::parse::ParseCtx;
|
||||||
use orchid_base::sym;
|
use orchid_base::sym;
|
||||||
use orchid_base::tokens::PARENS;
|
use orchid_base::tokens::PARENS;
|
||||||
@@ -55,7 +55,7 @@ impl Lexer for MacTreeLexer {
|
|||||||
if let Some(tail3) = tail2.strip_prefix(*rp) {
|
if let Some(tail3) = tail2.strip_prefix(*rp) {
|
||||||
break Ok((tail3, MacTok::S(*paren, items).at(ctx.pos_tt(tail, tail3).pos())));
|
break Ok((tail3, MacTok::S(*paren, items).at(ctx.pos_tt(tail, tail3).pos())));
|
||||||
} else if tail2.is_empty() {
|
} else if tail2.is_empty() {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("Unclosed block").await,
|
ctx.i().i("Unclosed block").await,
|
||||||
format!("Expected closing {rp}"),
|
format!("Expected closing {rp}"),
|
||||||
[ctx.pos_lt(1, tail)],
|
[ctx.pos_lt(1, tail)],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use std::fmt;
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use never::Never;
|
use never::Never;
|
||||||
|
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_extension::atom::Atomic;
|
use orchid_extension::atom::Atomic;
|
||||||
@@ -11,7 +12,7 @@ use orchid_extension::atom_owned::{OwnedAtom, OwnedVariant};
|
|||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct RulePath {
|
pub struct RulePath {
|
||||||
pub module: Sym,
|
pub module: Sym,
|
||||||
pub main_kw: IStr,
|
pub main_kw: Tok<String>,
|
||||||
pub rule: u32,
|
pub rule: u32,
|
||||||
}
|
}
|
||||||
impl RulePath {
|
impl RulePath {
|
||||||
@@ -56,4 +57,15 @@ impl OwnedAtom for RecurState {
|
|||||||
Self::Recursive { .. } => Some(()),
|
Self::Recursive { .. } => Some(()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
async fn print_atom<'a>(&'a self, _: &'a (impl FmtCtx + ?Sized + 'a)) -> FmtUnit {
|
||||||
|
self.to_string().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl fmt::Display for RecurState {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Bottom => write!(f, "RecurState::Bottom"),
|
||||||
|
Self::Recursive { path, prev } => write!(f, "{path}\n{prev}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::mk_err;
|
use orchid_base::error::mk_errv;
|
||||||
use orchid_base::location::Pos;
|
use orchid_base::location::Pos;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::sym;
|
use orchid_base::sym;
|
||||||
@@ -91,7 +91,7 @@ async fn mk_body_call(
|
|||||||
let rule_path =
|
let rule_path =
|
||||||
RulePath { module: mac.0.module.clone(), main_kw: mac.0.own_kws[0].clone(), rule: rule.index };
|
RulePath { module: mac.0.module.clone(), main_kw: mac.0.own_kws[0].clone(), rule: rule.index };
|
||||||
let Some(new_recur) = recur.push(rule_path.clone()) else {
|
let Some(new_recur) = recur.push(rule_path.clone()) else {
|
||||||
return bot(mk_err(
|
return bot(mk_errv(
|
||||||
ctx.i().i("Circular macro dependency").await,
|
ctx.i().i("Circular macro dependency").await,
|
||||||
format!("The definition of {rule_path} is circular"),
|
format!("The definition of {rule_path} is circular"),
|
||||||
[rule.pos.clone()],
|
[rule.pos.clone()],
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use futures::future::join_all;
|
use futures::future::join_all;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, mk_err};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::interner::{Interner, Tok};
|
use orchid_base::interner::{Interner, Tok};
|
||||||
use orchid_base::join_ok;
|
use orchid_base::join_ok;
|
||||||
use orchid_base::side::Side;
|
use orchid_base::side::Side;
|
||||||
@@ -11,7 +11,7 @@ use super::vec_attrs::vec_attrs;
|
|||||||
use crate::macros::mactree::{Ph, PhKind};
|
use crate::macros::mactree::{Ph, PhKind};
|
||||||
use crate::macros::{MacTok, MacTree};
|
use crate::macros::{MacTok, MacTree};
|
||||||
|
|
||||||
pub type MaxVecSplit<'a> = (&'a [MacTree], (IStr, u8, bool), &'a [MacTree]);
|
pub type MaxVecSplit<'a> = (&'a [MacTree], (Tok<String>, u8, bool), &'a [MacTree]);
|
||||||
|
|
||||||
/// Derive the details of the central vectorial and the two sides from a
|
/// Derive the details of the central vectorial and the two sides from a
|
||||||
/// slice of Expr's
|
/// slice of Expr's
|
||||||
@@ -124,7 +124,7 @@ async fn mk_scalar(pattern: &MacTree, i: &Interner) -> OrcRes<ScalMatcher> {
|
|||||||
},
|
},
|
||||||
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body, i).boxed_local().await?)),
|
MacTok::S(c, body) => ScalMatcher::S(*c, Box::new(mk_any(body, i).boxed_local().await?)),
|
||||||
MacTok::Lambda(..) =>
|
MacTok::Lambda(..) =>
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
i.i("Lambda in matcher").await,
|
i.i("Lambda in matcher").await,
|
||||||
"Lambdas can't be matched for, only generated in templates",
|
"Lambdas can't be matched for, only generated in templates",
|
||||||
[pattern.pos()],
|
[pattern.pos()],
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use crate::macros::{MacTok, MacTree};
|
|||||||
pub struct NamedMatcher {
|
pub struct NamedMatcher {
|
||||||
inner: AnyMatcher,
|
inner: AnyMatcher,
|
||||||
head: Sym,
|
head: Sym,
|
||||||
after_tok: IStr,
|
after_tok: Tok<String>,
|
||||||
}
|
}
|
||||||
impl NamedMatcher {
|
impl NamedMatcher {
|
||||||
pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes<Self> {
|
pub async fn new(pattern: &[MacTree], i: &Interner) -> OrcRes<Self> {
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ use orchid_base::tokens::{PARENS, Paren};
|
|||||||
pub enum ScalMatcher {
|
pub enum ScalMatcher {
|
||||||
Name(Sym),
|
Name(Sym),
|
||||||
S(Paren, Box<AnyMatcher>),
|
S(Paren, Box<AnyMatcher>),
|
||||||
Placeh { key: IStr },
|
Placeh { key: Tok<String> },
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum VecMatcher {
|
pub enum VecMatcher {
|
||||||
Placeh {
|
Placeh {
|
||||||
key: IStr,
|
key: Tok<String>,
|
||||||
nonzero: bool,
|
nonzero: bool,
|
||||||
},
|
},
|
||||||
Scan {
|
Scan {
|
||||||
@@ -41,7 +41,7 @@ pub enum VecMatcher {
|
|||||||
/// the length of matches on either side.
|
/// the length of matches on either side.
|
||||||
///
|
///
|
||||||
/// Vectorial keys that appear on either side, in priority order
|
/// Vectorial keys that appear on either side, in priority order
|
||||||
key_order: Vec<IStr>,
|
key_order: Vec<Tok<String>>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,11 +30,11 @@ pub enum StateEntry<'a> {
|
|||||||
}
|
}
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct MatchState<'a> {
|
pub struct MatchState<'a> {
|
||||||
placeholders: HashMap<IStr, StateEntry<'a>>,
|
placeholders: HashMap<Tok<String>, StateEntry<'a>>,
|
||||||
name_posv: HashMap<Sym, Vec<Pos>>,
|
name_posv: HashMap<Sym, Vec<Pos>>,
|
||||||
}
|
}
|
||||||
impl<'a> MatchState<'a> {
|
impl<'a> MatchState<'a> {
|
||||||
pub fn from_ph(key: IStr, entry: StateEntry<'a>) -> Self {
|
pub fn from_ph(key: Tok<String>, entry: StateEntry<'a>) -> Self {
|
||||||
Self { placeholders: HashMap::from([(key, entry)]), name_posv: HashMap::new() }
|
Self { placeholders: HashMap::from([(key, entry)]), name_posv: HashMap::new() }
|
||||||
}
|
}
|
||||||
pub fn combine(self, s: Self) -> Self {
|
pub fn combine(self, s: Self) -> Self {
|
||||||
@@ -45,7 +45,7 @@ impl<'a> MatchState<'a> {
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn ph_len(&self, key: &IStr) -> Option<usize> {
|
pub fn ph_len(&self, key: &Tok<String>) -> Option<usize> {
|
||||||
match self.placeholders.get(key)? {
|
match self.placeholders.get(key)? {
|
||||||
StateEntry::Vec(slc) => Some(slc.len()),
|
StateEntry::Vec(slc) => Some(slc.len()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -54,8 +54,8 @@ impl<'a> MatchState<'a> {
|
|||||||
pub fn from_name(name: Sym, location: Pos) -> Self {
|
pub fn from_name(name: Sym, location: Pos) -> Self {
|
||||||
Self { name_posv: HashMap::from([(name, vec![location])]), placeholders: HashMap::new() }
|
Self { name_posv: HashMap::from([(name, vec![location])]), placeholders: HashMap::new() }
|
||||||
}
|
}
|
||||||
pub fn get(&self, key: &IStr) -> Option<&StateEntry<'a>> { self.placeholders.get(key) }
|
pub fn get(&self, key: &Tok<String>) -> Option<&StateEntry<'a>> { self.placeholders.get(key) }
|
||||||
pub fn remove(&mut self, name: IStr) -> Option<StateEntry<'a>> {
|
pub fn remove(&mut self, name: Tok<String>) -> Option<StateEntry<'a>> {
|
||||||
self.placeholders.remove(&name)
|
self.placeholders.remove(&name)
|
||||||
}
|
}
|
||||||
pub fn mk_owned(self) -> OwnedState {
|
pub fn mk_owned(self) -> OwnedState {
|
||||||
@@ -85,10 +85,10 @@ pub enum OwnedEntry {
|
|||||||
Scalar(MacTree),
|
Scalar(MacTree),
|
||||||
}
|
}
|
||||||
pub struct OwnedState {
|
pub struct OwnedState {
|
||||||
placeholders: HashMap<IStr, OwnedEntry>,
|
placeholders: HashMap<Tok<String>, OwnedEntry>,
|
||||||
name_posv: HashMap<Sym, Vec<Pos>>,
|
name_posv: HashMap<Sym, Vec<Pos>>,
|
||||||
}
|
}
|
||||||
impl OwnedState {
|
impl OwnedState {
|
||||||
pub fn get(&self, key: &IStr) -> Option<&OwnedEntry> { self.placeholders.get(key) }
|
pub fn get(&self, key: &Tok<String>) -> Option<&OwnedEntry> { self.placeholders.get(key) }
|
||||||
pub fn positions(&self, name: &Sym) -> &[Pos] { self.name_posv.get(name).map_or(&[], |v| &v[..]) }
|
pub fn positions(&self, name: &Sym) -> &[Pos] { self.name_posv.get(name).map_or(&[], |v| &v[..]) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::macros::{MacTok, MacTree};
|
|||||||
/// Returns the name, priority and at_least_one of the expression if it is
|
/// Returns the name, priority and at_least_one of the expression if it is
|
||||||
/// a vectorial placeholder
|
/// a vectorial placeholder
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn vec_attrs(expr: &MacTree) -> Option<(IStr, u8, bool)> {
|
pub fn vec_attrs(expr: &MacTree) -> Option<(Tok<String>, u8, bool)> {
|
||||||
match (*expr.tok).clone() {
|
match (*expr.tok).clone() {
|
||||||
MacTok::Ph(Ph { kind: PhKind::Vector { priority, at_least_one }, name }) =>
|
MacTok::Ph(Ph { kind: PhKind::Vector { priority, at_least_one }, name }) =>
|
||||||
Some((name, priority, at_least_one)),
|
Some((name, priority, at_least_one)),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use std::rc::Rc;
|
|||||||
use futures::AsyncWrite;
|
use futures::AsyncWrite;
|
||||||
use orchid_api_derive::Coding;
|
use orchid_api_derive::Coding;
|
||||||
use orchid_api_traits::{Encode, Request};
|
use orchid_api_traits::{Encode, Request};
|
||||||
use orchid_base::error::{OrcRes, mk_err};
|
use orchid_base::error::{OrcRes, mk_errv};
|
||||||
use orchid_base::format::{FmtCtx, FmtUnit};
|
use orchid_base::format::{FmtCtx, FmtUnit};
|
||||||
use orchid_base::interner::Tok;
|
use orchid_base::interner::Tok;
|
||||||
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom};
|
use orchid_extension::atom::{AtomMethod, Atomic, MethodSetBuilder, Supports, TypAtom};
|
||||||
@@ -58,13 +58,13 @@ impl OwnedAtom for StrAtom {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct IntStrAtom(IStr);
|
pub struct IntStrAtom(Tok<String>);
|
||||||
impl Atomic for IntStrAtom {
|
impl Atomic for IntStrAtom {
|
||||||
type Variant = OwnedVariant;
|
type Variant = OwnedVariant;
|
||||||
type Data = orchid_api::TStr;
|
type Data = orchid_api::TStr;
|
||||||
}
|
}
|
||||||
impl From<IStr> for IntStrAtom {
|
impl From<Tok<String>> for IntStrAtom {
|
||||||
fn from(value: IStr) -> Self { Self(value) }
|
fn from(value: Tok<String>) -> Self { Self(value) }
|
||||||
}
|
}
|
||||||
impl OwnedAtom for IntStrAtom {
|
impl OwnedAtom for IntStrAtom {
|
||||||
type Refs = ();
|
type Refs = ();
|
||||||
@@ -109,7 +109,7 @@ impl TryFromExpr for OrcString {
|
|||||||
let ctx = expr.ctx();
|
let ctx = expr.ctx();
|
||||||
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
match TypAtom::<IntStrAtom>::try_from_expr(expr).await {
|
||||||
Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }),
|
Ok(t) => Ok(OrcString { ctx: t.untyped.ctx().clone(), kind: OrcStringKind::Int(t) }),
|
||||||
Err(e) => Err(mk_err(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
Err(e) => Err(mk_errv(ctx.i().i("A string was expected").await, "", e.pos_iter())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcErr, OrcErrv, OrcRes, mk_err};
|
use orchid_base::error::{OrcErr, OrcErrv, OrcRes, mk_errv};
|
||||||
use orchid_base::interner::Interner;
|
use orchid_base::interner::Interner;
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
@@ -36,7 +36,7 @@ impl StringError {
|
|||||||
/// Convert into project error for reporting
|
/// Convert into project error for reporting
|
||||||
pub async fn into_proj(self, path: &Sym, pos: u32, i: &Interner) -> OrcErrv {
|
pub async fn into_proj(self, path: &Sym, pos: u32, i: &Interner) -> OrcErrv {
|
||||||
let start = pos + self.pos;
|
let start = pos + self.pos;
|
||||||
mk_err(
|
mk_errv(
|
||||||
i.i("Failed to parse string").await,
|
i.i("Failed to parse string").await,
|
||||||
match self.kind {
|
match self.kind {
|
||||||
StringErrorKind::NotHex => "Expected a hex digit",
|
StringErrorKind::NotHex => "Expected a hex digit",
|
||||||
@@ -144,7 +144,7 @@ impl Lexer for StringLexer {
|
|||||||
tail = ch.as_str();
|
tail = ch.as_str();
|
||||||
} else {
|
} else {
|
||||||
let range = ctx.pos(all)..ctx.pos("");
|
let range = ctx.pos(all)..ctx.pos("");
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i().i("No string end").await,
|
ctx.i().i("No string end").await,
|
||||||
"String never terminated with \"",
|
"String never terminated with \"",
|
||||||
[SrcRange::new(range.clone(), ctx.src())],
|
[SrcRange::new(range.clone(), ctx.src())],
|
||||||
|
|||||||
@@ -37,6 +37,12 @@
|
|||||||
// Important; for accessibility reasons, code cannot be wider than 100ch
|
// Important; for accessibility reasons, code cannot be wider than 100ch
|
||||||
"editor.rulers": [ 100 ],
|
"editor.rulers": [ 100 ],
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/.git/objects/**": true,
|
||||||
|
"**/.git/subtree-cache/**": true,
|
||||||
|
"**/.hg/store/**": true,
|
||||||
|
"target": true,
|
||||||
|
},
|
||||||
"git.confirmSync": false,
|
"git.confirmSync": false,
|
||||||
"git.enableSmartCommit": true,
|
"git.enableSmartCommit": true,
|
||||||
"git.autofetch": true,
|
"git.autofetch": true,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ clap = { version = "4.5.24", features = ["derive", "env"] }
|
|||||||
ctrlc = "3.4.5"
|
ctrlc = "3.4.5"
|
||||||
futures = "0.3.31"
|
futures = "0.3.31"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
|
orchid-api = { version = "0.1.0", path = "../orchid-api" }
|
||||||
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
orchid-base = { version = "0.1.0", path = "../orchid-base" }
|
||||||
orchid-host = { version = "0.1.0", path = "../orchid-host" }
|
orchid-host = { version = "0.1.0", path = "../orchid-host" }
|
||||||
substack = "1.1.1"
|
substack = "1.1.1"
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ async fn main() -> io::Result<ExitCode> {
|
|||||||
};
|
};
|
||||||
let snip = Snippet::new(first, &lexemes);
|
let snip = Snippet::new(first, &lexemes);
|
||||||
let ptree = parse_items(&pctx, Substack::Bottom, snip).await.unwrap();
|
let ptree = parse_items(&pctx, Substack::Bottom, snip).await.unwrap();
|
||||||
if let Some(errv) = reporter.res() {
|
if let Some(errv) = reporter.errv() {
|
||||||
eprintln!("{errv}");
|
eprintln!("{errv}");
|
||||||
*exit_code1.borrow_mut() = ExitCode::FAILURE;
|
*exit_code1.borrow_mut() = ExitCode::FAILURE;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_err, os_str_to_string};
|
use orchid_base::error::{OrcRes, Reporter, async_io_err, mk_errv, os_str_to_string};
|
||||||
use orchid_base::location::SrcRange;
|
use orchid_base::location::SrcRange;
|
||||||
use orchid_base::name::Sym;
|
use orchid_base::name::Sym;
|
||||||
use orchid_base::parse::Snippet;
|
use orchid_base::parse::Snippet;
|
||||||
@@ -30,7 +30,7 @@ pub async fn parse_folder(
|
|||||||
let sr = SrcRange::new(0..0, &ns);
|
let sr = SrcRange::new(0..0, &ns);
|
||||||
if path.is_dir() {
|
if path.is_dir() {
|
||||||
let Some(name_os) = path.file_name() else {
|
let Some(name_os) = path.file_name() else {
|
||||||
return Err(mk_err(
|
return Err(mk_errv(
|
||||||
ctx.i.i("Could not read directory name").await,
|
ctx.i.i("Could not read directory name").await,
|
||||||
format!("Path {} ends in ..", path.to_string_lossy()),
|
format!("Path {} ends in ..", path.to_string_lossy()),
|
||||||
[sr],
|
[sr],
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Upsending: [ff ff ff ff ff ff ff f7 00 00 00 00 00 00 00 08 22 75 73 65 72 21 22 69]
|
|
||||||
Reference in New Issue
Block a user