Skip to main content

dolang_compile/ast/
visit.rs

1use std::{
2    fmt::{self, Debug, Formatter},
3    ops::ControlFlow,
4};
5
6use crate::source::Span;
7
8use super::origin;
9
10pub trait Node {
11    const TRANSPARENT: bool = false;
12
13    fn accept<'a, V: Visit>(&'a self, visit: &'a mut V) -> ControlFlow<V::Break>;
14
15    fn trans<'a, V: Visit>(&'a self, visit: &'a mut V) -> ControlFlow<V::Break> {
16        if Self::TRANSPARENT {
17            self.accept(visit)
18        } else {
19            visit.node(self)
20        }
21    }
22
23    fn span(&self) -> Span {
24        let mut visit = SpanVisit(Span::INVALID);
25        let _ = self.accept(&mut visit);
26        visit.0
27    }
28
29    fn kind(&self) -> NodeKind;
30}
31
32struct SpanVisit(Span);
33
34impl Visit for SpanVisit {
35    type Break = ();
36
37    fn node<T: Node + ?Sized>(&mut self, node: &T) -> ControlFlow<Self::Break> {
38        self.0 = self.0 | node.span();
39        ControlFlow::Continue(())
40    }
41
42    fn token(
43        &mut self,
44        _leaf: Token,
45        span: Span,
46        _origin: Option<origin::Id>,
47    ) -> ControlFlow<Self::Break> {
48        self.0 = self.0 | span;
49        ControlFlow::Continue(())
50    }
51}
52
53/// Syntactic token
54#[derive(Copy, Clone, Debug)]
55pub enum Token {
56    /// Comment
57    Comment,
58    /// Non-numeric, non-string constant such as `nil` or `false`
59    Constant,
60    /// Delimiter such as `(`, `[`, etc
61    Delim,
62    /// Escape within a string
63    Escape,
64    /// Field, e.g. `bar` in `foo.bar`
65    Field,
66    /// Key such as `foo:`
67    Key,
68    /// Module name
69    ModuleName,
70    /// Module item
71    ModuleItem,
72    /// Keyword such as `while`, `for`, `do`, `import`
73    Keyword,
74    /// Literal string, including non-escape, non-interpolated portions of quoted strings
75    Literal,
76    /// Numeric constant
77    Number,
78    /// Unary or binary operator such as `+` or `-`
79    Operator,
80    /// A string delimeter (`"`)
81    StringDelim,
82    /// A variable
83    Variable,
84    /// A sigil like `$` or `...`
85    Sigil,
86}
87
88pub trait Visit {
89    type Break;
90
91    fn node<T: Node + ?Sized>(&mut self, node: &T) -> ControlFlow<Self::Break>;
92    fn token(
93        &mut self,
94        token: Token,
95        span: Span,
96        origin: Option<origin::Id>,
97    ) -> ControlFlow<Self::Break>;
98}
99
100/// Classification of AST nodes
101#[derive(Clone, Copy, PartialEq, Eq, Debug)]
102pub enum NodeKind {
103    Literal,
104    Ident,
105    I64,
106    VerbatimI64,
107    F64,
108    VerbatimF64,
109    Bool,
110    Nil,
111    Sym,
112    Concat,
113    Escape,
114    BinConcat,
115    EscapeByte,
116    Group,
117    Unary,
118    Binary,
119    Call,
120    Lambda,
121    Field,
122    Index,
123    Array,
124    Dict,
125    Error,
126    Assign,
127    Bind,
128    Break,
129    Class,
130    Continue,
131    Def,
132    For,
133    If,
134    Import,
135    Let,
136    Return,
137    Throw,
138    Try,
139    While,
140    NlGuard,
141    Param,
142    Block,
143    Function,
144    ImportItem,
145    Branch,
146    Catch,
147    Expand,
148    Pair,
149    Body,
150    Pattern,
151    Key,
152}
153
154impl fmt::Display for NodeKind {
155    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156        Debug::fmt(self, f)
157    }
158}