use std::collections::HashMap; use std::fmt; use std::num::NonZeroU64; use std::ops::Range; use std::rc::Rc; use orchid_api_derive::{Coding, Hierarchy}; use orchid_api_traits::Request; use crate::{ExprTicket, Expression, ExtHostReq, HostExtReq, OrcError, 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. /// /// Similar to [crate::expr::ExprTicket] in that it represents a token tree the /// lifetime of which is managed by the interpreter, and as such should probably /// not be exposed to libraries directly but rather wrapped in a /// lifetime-controlled abstraction. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)] pub struct TreeTicket(pub NonZeroU64); #[derive(Clone, Debug, Coding)] pub struct TokenTree { pub token: Token, pub range: Range, } #[derive(Clone, Debug, Coding)] pub enum Token { /// Lambda function head, from the opening \ until the beginning of the body. LambdaHead(Box), /// A name segment or an operator. Name(TStr), /// A newly generated expression. The last place this is supposed to happen is /// in lexers, parsers and macros should have enumerable many outputs /// expressed as function calls. NewExpr(Expression), /// A pre-existing expression Handle(ExprTicket), /// :: NS(TStr, Box), /// Line break. BR, /// ( Round parens ), [ Square brackets ] or { Curly braces } S(Paren, Vec), /// A static compile-time error returned by failing lexers if /// the rest of the source is likely still meaningful. This is distinct from /// NewExpr(Bottom) because it fails in dead branches too. Bottom(Vec), /// A comment Comment(Rc), } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Coding)] pub enum Paren { Round, Square, Curly, } impl fmt::Display for Paren { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", match self { Self::Round => "()", Self::Curly => "{}", Self::Square => "[]", }) } } #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Coding)] pub struct TreeId(pub NonZeroU64); #[derive(Clone, Debug, Coding)] pub struct Member { pub name: TStr, pub exported: bool, pub kind: MemberKind, pub comments: Vec, } #[derive(Clone, Debug, Coding)] pub enum MemberKind { Const(Expression), Module(Module), Lazy(TreeId), } #[derive(Clone, Debug, Coding)] pub struct Module { pub members: Vec, } /// Evaluate a lazy member. This call will only be issued to each system once. #[derive(Clone, Copy, Debug, Coding, Hierarchy)] #[extends(HostExtReq)] pub struct GetMember(pub SysId, pub TreeId); impl Request for GetMember { type Response = MemberKind; } /// This request can only be issued while the interpreter is running, so during /// an atom call. #[derive(Clone, Copy, Debug, Coding, Hierarchy)] #[extends(ExtHostReq)] pub struct LsModule(pub SysId, pub TStrv); impl Request for LsModule { type Response = Result; } #[derive(Clone, Debug, Coding)] pub enum LsModuleError { InvalidPath, IsConstant, TreeUnavailable, } /// Information about a module sent from the host to an extension. By necessity, /// members and imports are non-overlapping. #[derive(Clone, Debug, Coding)] pub struct ModuleInfo { /// List the names defined in this module pub members: HashMap, } #[derive(Clone, Copy, Debug, Coding)] pub struct MemberInfo { /// true if the name is exported pub public: bool, /// Whether the tree item is a constant value or a module pub kind: MemberInfoKind, } /// Indicates what kind of node a name refers to #[derive(Clone, Copy, Debug, Coding)] pub enum MemberInfoKind { /// has children obtained with [crate::LsModule] Module, /// has a value retrievable in [crate::ExpressionKind::Const] Constant, }