Began implementing fully isomorphic macros

Like Rust's Proc macros. Now we have preprocessor recursion to worry about. I also made a cool macro for enums
This commit is contained in:
2024-10-14 00:13:09 +02:00
parent 84cbcdd4fe
commit 3a3ae98aff
66 changed files with 2302 additions and 1164 deletions

View File

@@ -3,10 +3,7 @@ use std::num::NonZeroU64;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::error::OrcResult;
use crate::expr::{Expr, ExprTicket};
use crate::proto::{ExtHostReq, HostExtNotif, HostExtReq};
use crate::system::SysId;
use crate::{ExprTicket, Expression, ExtHostReq, HostExtNotif, HostExtReq, OrcResult, SysId, TStrv};
pub type AtomData = Vec<u8>;
@@ -53,7 +50,7 @@ pub struct Atom {
#[extends(AtomReq, HostExtReq)]
pub struct CallRef(pub Atom, pub ExprTicket);
impl Request for CallRef {
type Response = Expr;
type Response = Expression;
}
/// Attempt to apply an atom as a function, consuming the atom and enabling the
@@ -63,7 +60,7 @@ impl Request for CallRef {
#[extends(AtomReq, HostExtReq)]
pub struct FinalCall(pub Atom, pub ExprTicket);
impl Request for FinalCall {
type Response = Expr;
type Response = Expression;
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
@@ -80,34 +77,24 @@ impl Request for DeserAtom {
type Response = Atom;
}
/// Determine whether two atoms are identical for the purposes of macro
/// application. If a given atom is never generated by macros or this relation
/// is difficult to define, the module can return false
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
#[extends(AtomReq, HostExtReq)]
pub struct AtomSame(pub Atom, pub Atom);
impl Request for AtomSame {
type Response = bool;
}
/// A request blindly routed to the system that provides an atom.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
#[extends(AtomReq, HostExtReq)]
pub struct Fwded(pub Atom, pub Vec<u8>);
pub struct Fwded(pub Atom, pub TStrv, pub Vec<u8>);
impl Request for Fwded {
type Response = Vec<u8>;
type Response = Option<Vec<u8>>;
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct Fwd(pub Atom, pub Vec<u8>);
pub struct Fwd(pub Atom, pub TStrv, pub Vec<u8>);
impl Request for Fwd {
type Response = Vec<u8>;
type Response = Option<Vec<u8>>;
}
#[derive(Clone, Debug, Coding)]
pub enum NextStep {
Continue(Expr),
Continue(Expression),
Halt,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
@@ -138,7 +125,6 @@ impl Request for AtomPrint {
pub enum AtomReq {
CallRef(CallRef),
FinalCall(FinalCall),
AtomSame(AtomSame),
Fwded(Fwded),
Command(Command),
AtomPrint(AtomPrint),
@@ -149,8 +135,7 @@ impl AtomReq {
/// subclass have at least one atom argument.
pub fn get_atom(&self) -> &Atom {
match self {
Self::AtomSame(AtomSame(a, ..))
| Self::CallRef(CallRef(a, ..))
Self::CallRef(CallRef(a, ..))
| Self::Command(Command(a))
| Self::FinalCall(FinalCall(a, ..))
| Self::Fwded(Fwded(a, ..))

View File

@@ -3,8 +3,7 @@ use std::sync::Arc;
use orchid_api_derive::Coding;
use crate::interner::TStr;
use crate::location::Location;
use crate::{Location, TStr};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
pub struct ErrId(pub NonZeroU16);

View File

@@ -3,12 +3,7 @@ use std::num::NonZeroU64;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::atom::Atom;
use crate::error::OrcError;
use crate::interner::TStrv;
use crate::location::Location;
use crate::proto::{ExtHostNotif, ExtHostReq};
use crate::system::SysId;
use crate::{Atom, ExtHostNotif, ExtHostReq, Location, OrcError, SysId, TStrv};
/// An arbitrary ID associated with an expression on the host side. Incoming
/// tickets always come with some lifetime guarantee, which can be extended with
@@ -57,11 +52,11 @@ pub struct Move {
/// [crate::atom::Call] or [crate::atom::CallRef], or a constant in the
/// [crate::tree::Tree].
#[derive(Clone, Debug, Coding)]
pub enum Clause {
pub enum ExpressionKind {
/// Apply the lhs as a function to the rhs
Call(Box<Expr>, Box<Expr>),
Call(Box<Expression>, Box<Expression>),
/// Lambda function. The number operates as an argument name
Lambda(u64, Box<Expr>),
Lambda(u64, Box<Expression>),
/// Binds the argument passed to the lambda with the same ID in the same
/// template
Arg(u64),
@@ -70,16 +65,12 @@ pub enum Clause {
Slot(ExprTicket),
/// The lhs must be fully processed before the rhs can be processed.
/// Equivalent to Haskell's function of the same name
Seq(Box<Expr>, Box<Expr>),
Seq(Box<Expression>, Box<Expression>),
/// Insert a new atom in the tree. When the clause is used in the const tree,
/// the atom must be trivial. This is always a newly constructed atom, if you
/// want to reference an existing atom, use the corresponding [ExprTicket].
/// Because the atom is newly constructed, it also must belong to this system.
NewAtom(Atom),
/// An atom, specifically an atom that already exists. This form is only ever
/// returned from [Inspect], and it's borrowed from the expression being
/// inspected.
Atom(ExprTicket, Atom),
/// A reference to a constant
Const(TStrv),
/// A static runtime error.
@@ -87,22 +78,35 @@ pub enum Clause {
}
#[derive(Clone, Debug, Coding)]
pub struct Expr {
pub clause: Clause,
pub struct Expression {
pub kind: ExpressionKind,
pub location: Location,
}
#[derive(Clone, Debug, Coding)]
pub struct Details {
pub expr: Expr,
pub enum InspectedKind {
Atom(Atom),
Bottom(Vec<OrcError>),
Opaque,
}
#[derive(Clone, Debug, Coding)]
pub struct Inspected {
pub kind: InspectedKind,
pub location: Location,
pub refcount: u32,
}
/// Obtain information about an expression. Used to act upon arguments by
/// resolving shallowly and operating on the atom, but also usable for
/// reflection
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]
#[extends(ExprReq, ExtHostReq)]
pub struct Inspect(pub ExprTicket);
pub struct Inspect {
pub target: ExprTicket,
}
impl Request for Inspect {
type Response = Details;
type Response = Inspected;
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Coding, Hierarchy)]

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::proto::{ExtHostReq, HostExtReq};
use crate::{ExtHostReq, HostExtReq};
/// Intern requests sent by the replica to the master. These requests are
/// repeatable.

46
orchid-api/src/lexer.rs Normal file
View File

@@ -0,0 +1,46 @@
use std::ops::RangeInclusive;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::{ExtHostReq, HostExtReq, OrcResult, ParsId, SysId, TStr, TokenTree, TreeTicket};
/// - All ranges contain at least one character
/// - All ranges are in increasing characeter order
/// - There are excluded characters between each pair of neighboring ranges
#[derive(Clone, Debug, Coding)]
pub struct CharFilter(pub Vec<RangeInclusive<char>>);
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(HostExtReq)]
pub struct LexExpr {
pub sys: SysId,
pub id: ParsId,
pub text: TStr,
pub pos: u32,
}
impl Request for LexExpr {
type Response = Option<OrcResult<LexedExpr>>;
}
#[derive(Clone, Debug, Coding)]
pub struct LexedExpr {
pub pos: u32,
pub expr: TokenTree,
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct SubLex {
pub id: ParsId,
pub pos: u32,
}
impl Request for SubLex {
type Response = Option<SubLexed>;
}
#[derive(Clone, Debug, Coding)]
pub struct SubLexed {
pub pos: u32,
pub ticket: TreeTicket,
}

View File

@@ -1,35 +1,26 @@
mod lexer;
pub use lexer::*;
mod macros;
pub use macros::*;
mod atom;
pub use atom::{
Atom, AtomData, AtomDrop, AtomId, AtomPrint, AtomReq, AtomSame, CallRef, Command, DeserAtom,
FinalCall, Fwd, Fwded, LocalAtom, NextStep, SerializeAtom,
};
pub use atom::*;
mod error;
pub use error::{ErrId, ErrLocation, OrcError, OrcResult};
pub use error::*;
mod expr;
pub use expr::{
Acquire, Clause, Details, Expr, ExprNotif, ExprReq, ExprTicket, Inspect, Move, Release,
};
pub use expr::*;
mod interner;
pub use interner::{
ExternStr, ExternStrv, IntReq, InternStr, InternStrv, Retained, Sweep, TStr, TStrv,
};
pub use interner::*;
mod location;
pub use location::{CodeGenInfo, Location, SourceRange};
pub use location::*;
mod logging;
pub use logging::{Log, LogStrategy};
pub use logging::*;
mod parser;
pub use parser::{CharFilter, LexExpr, LexedExpr, ParsId, ParseLine, ParserReq, SubLex, SubLexed};
pub use parser::*;
mod proto;
pub use proto::{
ExtHostChannel, ExtHostNotif, ExtHostReq, ExtMsgSet, ExtensionHeader, HostExtChannel,
HostExtNotif, HostExtReq, HostHeader, HostMsgSet, Ping,
};
pub use proto::*;
mod system;
pub use system::{NewSystem, SysDeclId, SysId, SysReq, SystemDecl, SystemDrop, SystemInst};
pub use system::*;
mod tree;
pub use tree::{
CompName, GetMember, Item, ItemKind, Member, MemberKind, Module, Paren, Token, TokenTree, TreeId,
TreeTicket,
};
pub use tree::*;
mod vfs;
pub use vfs::{EagerVfs, GetVfs, Loaded, VfsId, VfsRead, VfsReq};
pub use vfs::*;

View File

@@ -2,13 +2,17 @@ use std::ops::Range;
use orchid_api_derive::Coding;
use crate::interner::TStrv;
use crate::{TStr, TStrv};
#[derive(Clone, Debug, Coding)]
pub enum Location {
/// Location inaccessible. Locations are always debugging aids and never
/// mandatory.
None,
/// Associated with a slot when wrapped in an expression.
SlotTarget,
/// Used in functions to denote the generated code that carries on the
/// location of the call. Not allowed in the const tree.
/// location of the call.
Inherit,
Gen(CodeGenInfo),
/// Range and file
@@ -26,5 +30,5 @@ pub struct SourceRange {
#[derive(Clone, Debug, Coding)]
pub struct CodeGenInfo {
pub generator: TStrv,
pub details: String,
pub details: TStr,
}

View File

@@ -1,6 +1,6 @@
use orchid_api_derive::{Coding, Hierarchy};
use crate::proto::ExtHostNotif;
use crate::ExtHostNotif;
#[derive(Clone, Debug, Coding)]
pub enum LogStrategy {

82
orchid-api/src/macros.rs Normal file
View File

@@ -0,0 +1,82 @@
use std::collections::HashMap;
use std::num::NonZeroU64;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use ordered_float::NotNan;
use crate::{Comment, ExtHostReq, HostExtReq, Location, OrcResult, Paren, ParsId, SysId, TStr, TStrv};
#[derive(Clone, Debug, Coding)]
pub struct MacroTreeId(NonZeroU64);
#[derive(Clone, Debug, Coding)]
pub struct MacroTree {
pub location: Location,
pub token: MacroToken,
}
#[derive(Clone, Debug, Coding)]
pub enum MacroToken {
S(Paren, Vec<MacroTree>),
Name(TStrv),
Slot(MacroTreeId),
Lambda(Vec<MacroTree>, Vec<MacroTree>),
Ph(Placeholder),
}
#[derive(Clone, Debug, Coding)]
pub struct MacroBlock {
pub priority: Option<NotNan<f64>>,
pub rules: Vec<MacroRule>,
}
#[derive(Clone, Debug, Coding)]
pub struct MacroRule {
pub location: Location,
pub comments: Vec<Comment>,
pub pattern: Vec<MacroTree>,
pub id: MacroId,
}
/// A specific macro rule with a specific pattern across invocations
#[derive(Clone, Copy, Debug, Coding, PartialEq, Eq, Hash)]
pub struct MacroId(pub NonZeroU64);
/// After a pattern matches, this call executes the body of the macro. This request returns None
/// if an inner nested request raised an exception
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(HostExtReq)]
pub struct ApplyMacro {
pub sys: SysId,
pub id: MacroId,
/// Recursion token
pub run_id: ParsId,
/// Must contain exactly the keys that were specified as placeholders in the pattern
pub params: HashMap<TStr, Vec<MacroTree>>,
}
impl Request for ApplyMacro {
type Response = Option<OrcResult<Vec<MacroTree>>>;
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct RunMacros {
pub run_id: ParsId,
pub query: Vec<MacroTree>,
}
impl Request for RunMacros {
type Response = Option<Vec<MacroTree>>;
}
#[derive(Clone, Debug, Coding)]
pub struct Placeholder {
pub name: TStr,
pub kind: PhKind,
}
#[derive(Clone, Copy, Debug, Coding)]
pub enum PhKind {
Scalar,
Vector { priority: u8, at_least_one: bool },
}

View File

@@ -1,70 +1,19 @@
use std::num::NonZeroU64;
use std::ops::RangeInclusive;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use crate::error::OrcResult;
use crate::interner::TStr;
use crate::proto::{ExtHostReq, HostExtReq};
use crate::system::SysId;
use crate::tree::{TokenTree, TreeTicket};
use crate::{Comment, HostExtReq, OrcResult, SysId, TokenTree};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
pub struct ParsId(pub NonZeroU64);
/// - All ranges contain at least one character
/// - All ranges are in increasing characeter order
/// - There are excluded characters between each pair of neighboring ranges
#[derive(Clone, Debug, Coding)]
pub struct CharFilter(pub Vec<RangeInclusive<char>>);
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(HostExtReq)]
#[extendable]
pub enum ParserReq {
LexExpr(LexExpr),
ParseLine(ParseLine),
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ParserReq, HostExtReq)]
pub struct LexExpr {
pub sys: SysId,
pub id: ParsId,
pub text: TStr,
pub pos: u32,
}
impl Request for LexExpr {
type Response = Option<OrcResult<LexedExpr>>;
}
#[derive(Clone, Debug, Coding)]
pub struct LexedExpr {
pub pos: u32,
pub expr: TokenTree,
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct SubLex {
pub id: ParsId,
pub pos: u32,
}
impl Request for SubLex {
type Response = Option<SubLexed>;
}
#[derive(Clone, Debug, Coding)]
pub struct SubLexed {
pub pos: u32,
pub ticket: TreeTicket,
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ParserReq, HostExtReq)]
pub struct ParseLine {
pub sys: SysId,
pub comments: Vec<Comment>,
pub exported: bool,
pub line: Vec<TokenTree>,
}
impl Request for ParseLine {

View File

@@ -27,17 +27,16 @@ use std::io::{Read, Write};
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::{read_exact, write_exact, Channel, Decode, Encode, MsgSet, Request};
use crate::logging::{self, LogStrategy};
use crate::{atom, expr, interner, parser, system, tree, vfs};
use crate::{atom, expr, interner, lexer, logging, macros, parser, system, tree, vfs};
static HOST_INTRO: &[u8] = b"Orchid host, binary API v0\n";
pub struct HostHeader {
pub log_strategy: LogStrategy,
pub log_strategy: logging::LogStrategy,
}
impl Decode for HostHeader {
fn decode<R: Read + ?Sized>(read: &mut R) -> Self {
read_exact(read, HOST_INTRO);
Self { log_strategy: LogStrategy::decode(read) }
Self { log_strategy: logging::LogStrategy::decode(read) }
}
}
impl Encode for HostHeader {
@@ -79,8 +78,10 @@ pub enum ExtHostReq {
Ping(Ping),
IntReq(interner::IntReq),
Fwd(atom::Fwd),
SysFwd(system::SysFwd),
ExprReq(expr::ExprReq),
SubLex(parser::SubLex),
SubLex(lexer::SubLex),
RunMacros(macros::RunMacros),
}
/// Notifications sent from the extension to the host
@@ -107,9 +108,11 @@ pub enum HostExtReq {
Sweep(interner::Sweep),
AtomReq(atom::AtomReq),
DeserAtom(atom::DeserAtom),
ParserReq(parser::ParserReq),
LexExpr(lexer::LexExpr),
ParseLine(parser::ParseLine),
GetMember(tree::GetMember),
VfsReq(vfs::VfsReq),
ApplyMacro(macros::ApplyMacro),
}
/// Notifications sent from the host to the extension
@@ -147,13 +150,12 @@ impl MsgSet for HostMsgSet {
mod tests {
use orchid_api_traits::enc_vec;
use ordered_float::NotNan;
use system::{SysDeclId, SystemDecl};
use super::*;
#[test]
fn host_header_enc() {
let hh = HostHeader { log_strategy: LogStrategy::File("SomeFile".to_string()) };
let hh = HostHeader { log_strategy: logging::LogStrategy::File("SomeFile".to_string()) };
let mut enc = &enc_vec(&hh)[..];
eprintln!("Encoded to {enc:?}");
HostHeader::decode(&mut enc);
@@ -164,8 +166,8 @@ mod tests {
fn ext_header_enc() {
let eh = ExtensionHeader {
name: "my_extension".to_string(),
systems: vec![SystemDecl {
id: SysDeclId(1.try_into().unwrap()),
systems: vec![system::SystemDecl {
id: system::SysDeclId(1.try_into().unwrap()),
name: "misc".to_string(),
depends: vec!["std".to_string()],
priority: NotNan::new(1f64).unwrap(),

View File

@@ -5,10 +5,7 @@ use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use ordered_float::NotNan;
use crate::interner::TStr;
use crate::parser::CharFilter;
use crate::proto::{HostExtNotif, HostExtReq};
use crate::tree::MemberKind;
use crate::{CharFilter, ExtHostReq, HostExtNotif, HostExtReq, MemberKind, TStr};
/// ID of a system type
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)]
@@ -72,9 +69,24 @@ pub struct SystemInst {
#[extends(HostExtNotif)]
pub struct SystemDrop(pub SysId);
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(SysReq, HostExtReq)]
pub struct SysFwded(pub SysId, pub Vec<u8>);
impl Request for SysFwded {
type Response = Vec<u8>;
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(ExtHostReq)]
pub struct SysFwd(pub SysId, pub Vec<u8>);
impl Request for SysFwd {
type Response = Vec<u8>;
}
#[derive(Clone, Debug, Coding, Hierarchy)]
#[extends(HostExtReq)]
#[extendable]
pub enum SysReq {
NewSystem(NewSystem),
SysFwded(SysFwded),
}

View File

@@ -4,13 +4,11 @@ use std::sync::Arc;
use orchid_api_derive::{Coding, Hierarchy};
use orchid_api_traits::Request;
use ordered_float::NotNan;
use crate::error::OrcError;
use crate::interner::{TStr, TStrv};
use crate::location::Location;
use crate::proto::HostExtReq;
use crate::system::SysId;
use crate::{Atom, Expr};
use crate::{
Atom, Expression, HostExtReq, Location, MacroBlock, OrcError, Placeholder, SysId, TStr, TStrv,
};
/// 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.
@@ -31,7 +29,7 @@ pub struct TokenTree {
#[derive(Clone, Debug, Coding)]
pub enum Token {
/// Lambda function head, from the opening \ until the beginning of the body.
Lambda(Vec<TokenTree>),
LambdaHead(Vec<TokenTree>),
/// A name segment or an operator.
Name(TStr),
/// ::
@@ -49,9 +47,13 @@ pub enum Token {
Bottom(Vec<OrcError>),
/// A comment
Comment(Arc<String>),
/// Placeholder
Ph(Placeholder),
/// Macro block head
Macro(Option<NotNan<f64>>),
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Coding)]
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Coding)]
pub enum Paren {
Round,
Square,
@@ -64,45 +66,42 @@ pub struct TreeId(pub NonZeroU64);
#[derive(Clone, Debug, Coding)]
pub struct Item {
pub location: Location,
pub comments: Vec<(Arc<String>, Location)>,
pub comments: Vec<Comment>,
pub kind: ItemKind,
}
#[derive(Clone, Debug, Coding)]
pub enum ItemKind {
Member(Member),
Raw(Vec<TokenTree>),
Macro(MacroBlock),
Export(TStr),
Import(CompName),
Import(TStrv),
}
#[derive(Clone, Debug, Coding)]
pub struct Comment {
pub text: TStr,
pub location: Location,
}
#[derive(Clone, Debug, Coding)]
pub struct Member {
pub name: TStr,
pub exported: bool,
pub kind: MemberKind,
}
#[derive(Clone, Debug, Coding)]
pub enum MemberKind {
Const(Expr),
Const(Expression),
Module(Module),
Lazy(TreeId),
}
#[derive(Clone, Debug, Coding)]
pub struct Module {
pub imports: Vec<TStrv>,
pub items: Vec<Item>,
}
#[derive(Clone, Debug, Coding)]
pub struct CompName {
pub path: Vec<TStr>,
pub name: Option<TStr>,
pub location: Location,
}
#[derive(Clone, Copy, Debug, Coding, Hierarchy)]
#[extends(HostExtReq)]
pub struct GetMember(pub SysId, pub TreeId);