Files
orchid/orchid-api/src/tree.rs

141 lines
3.8 KiB
Rust

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<u32>,
}
#[derive(Clone, Debug, Coding)]
pub enum Token {
/// Lambda function head, from the opening \ until the beginning of the body.
LambdaHead(Box<TokenTree>),
/// 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<TokenTree>),
/// Line break.
BR,
/// ( Round parens ), [ Square brackets ] or { Curly braces }
S(Paren, Vec<TokenTree>),
/// 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<OrcError>),
/// A comment
Comment(Rc<String>),
}
#[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<TStr>,
}
#[derive(Clone, Debug, Coding)]
pub enum MemberKind {
Const(Expression),
Module(Module),
Lazy(TreeId),
}
#[derive(Clone, Debug, Coding)]
pub struct Module {
pub members: Vec<Member>,
}
/// 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<ModuleInfo, LsModuleError>;
}
#[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<TStr, MemberInfo>,
}
#[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,
}