Skip to main content

lib_maniascript/parser/
typed_node.rs

1use std::fmt;
2
3use rowan::{NodeOrToken, WalkEvent};
4
5use crate::parser::{language::{SyntaxElement, SyntaxNode, SyntaxToken}, SyntaxKind::{self, *}};
6
7macro_rules! typed {
8    ($($kind:expr => $name:ident$(: $trait:ident)*$(: { $($block:tt)* })*),*) => {
9        $(
10            #[derive(Clone)]
11            pub struct $name(SyntaxNode);
12
13            impl TypedNode for $name {
14                fn cast(from: SyntaxNode) -> Option<Self> {
15                    if from.kind() == $kind {
16                        Some(Self(from))
17                    } else {
18                        None
19                    }
20                }
21                fn node(&self) -> &SyntaxNode {
22                    &self.0
23                }
24            }
25            $(impl $trait for $name {})*
26            $(impl $name { $($block)* })*
27        )*
28    }
29}
30macro_rules! nth {
31    ($self:expr; $index:expr) => {
32        $self.node().children()
33            .nth($index)
34    };
35    ($self:expr; ($kind:ident) $index:expr) => {
36        nth!($self; $index).and_then($kind::cast)
37    };
38}
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
41pub enum BinOpKind {
42    Concat,
43    And,
44    Or,
45    Equal,
46    NotEqual,
47    Less,
48    LessOrEq,
49    More,
50    MoreOrEq,
51    Add,
52    Sub,
53    Mult,
54    Div,
55    Mod,
56
57    Member,
58    As,
59    Is,
60    In,
61    KeyValue,
62    Namespace,
63}
64
65impl BinOpKind {
66    pub fn from_token(token: SyntaxKind) -> Option<Self> {
67        match token {
68            TOKEN_CONCAT => Some(BinOpKind::Concat),
69            TOKEN_AND => Some(BinOpKind::And),
70            TOKEN_OR => Some(BinOpKind::Or),
71            TOKEN_EQ_EQ => Some(BinOpKind::Equal),
72            TOKEN_NOT_EQ => Some(BinOpKind::NotEqual),
73            TOKEN_LESS => Some(BinOpKind::Less),
74            TOKEN_LESS_OR_EQ => Some(BinOpKind::LessOrEq),
75            TOKEN_MORE => Some(BinOpKind::More),
76            TOKEN_MORE_OR_EQ => Some(BinOpKind::MoreOrEq),
77            TOKEN_PLUS => Some(BinOpKind::Add),
78            TOKEN_MINUS => Some(BinOpKind::Sub),
79            TOKEN_MULT => Some(BinOpKind::Mult),
80            TOKEN_DIV => Some(BinOpKind::Div),
81            TOKEN_MOD => Some(BinOpKind::Mod),
82
83            TOKEN_DOT => Some(BinOpKind::Member),
84            TOKEN_AS => Some(BinOpKind::As),
85            TOKEN_IS => Some(BinOpKind::Is),
86            TOKEN_IN => Some(BinOpKind::In),
87            TOKEN_ARROW => Some(BinOpKind::KeyValue),
88            TOKEN_COLON_COLON => Some(BinOpKind::Namespace),
89
90            _ => None,
91        }
92    }
93}
94
95#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
96pub enum UnaryOpKind {
97    Not,
98    Negate,
99}
100
101impl UnaryOpKind {
102    /// Get the operation kind from a token in the AST
103    pub fn from_token(token: SyntaxKind) -> Option<Self> {
104        match token {
105            TOKEN_NOT => Some(UnaryOpKind::Not),
106            TOKEN_MINUS => Some(UnaryOpKind::Negate),
107            _ => None,
108        }
109    }
110}
111
112/// A struct that prints out the textual representation of a node in a
113/// stable format. See TypedNode::dump.
114pub struct TextDump(SyntaxNode);
115
116impl fmt::Display for TextDump {
117    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118        let mut indent = 0;
119        let mut skip_newline = true;
120        for event in self.0.preorder_with_tokens() {
121            if skip_newline {
122                skip_newline = false;
123            } else {
124                writeln!(f)?;
125            }
126            match &event {
127                WalkEvent::Enter(enter) => {
128                    write!(f, "{:i$}{:?}", "", enter.kind(), i = indent)?;
129                    if let NodeOrToken::Token(token) = enter {
130                        write!(f, "(\"{}\")", token.text().escape_default())?
131                    }
132                    write!(
133                        f,
134                        " {}..{}",
135                        enter.text_range().start(),
136                        enter.text_range().end()
137                    )?;
138                    if let NodeOrToken::Node(_) = enter {
139                        write!(f, " {{")?;
140                    }
141                    indent += 2;
142                }
143                WalkEvent::Leave(leave) => {
144                    indent -= 2;
145                    if let NodeOrToken::Node(_) = leave {
146                        write!(f, "{:i$}}}", "", i = indent)?;
147                    } else {
148                        skip_newline = true;
149                    }
150                }
151            }
152        }
153        Ok(())
154    }
155}
156
157/// Internal function to get an iterator over non-trivia tokens
158pub(crate) fn tokens(node: &SyntaxNode) -> impl Iterator<Item = SyntaxToken> {
159    node.children_with_tokens()
160        .filter_map(|element| element.into_token())
161        .filter(|token| !token.kind().is_trivia())
162}
163
164/// A TypedNode is simply a wrapper around an untyped node to provide a type
165/// system in some sense.
166pub trait TypedNode: Clone {
167    /// Cast an untyped node into this strongly-typed node. This will return
168    /// None if the type was not correct.
169    fn cast(from: SyntaxNode) -> Option<Self>;
170    /// Return a reference to the inner untyped node
171    fn node(&self) -> &SyntaxNode;
172    /// Return all errors of all children, recursively
173    fn errors(&self) -> Vec<SyntaxElement> {
174        self.node()
175            .descendants_with_tokens()
176            // Empty errors can happen if it encounteres EOF while
177            // creating them, which in case a root error is added.
178            .filter(|node| !node.text_range().is_empty())
179            .filter(|node| node.kind() == NODE_ERROR || node.kind() == TOKEN_ERROR)
180            .collect()
181    }
182    /// Return the first non-trivia token
183    fn first_token(&self) -> Option<SyntaxToken> {
184        tokens(self.node()).next()
185    }
186    /// Return a dump of the AST. One of the goals is to be a stable
187    /// format that can be used in tests.
188    fn dump(&self) -> TextDump {
189        TextDump(self.node().clone())
190    }
191}
192
193pub trait TokenWrapper: TypedNode {
194    fn as_str(&self) -> &str {
195        self.node().green().children().next().unwrap().as_token().unwrap().text().as_str()
196    }
197}
198
199
200/*
201// TODO: maybe for arrays, vectors?
202/// Provides the function `.entries()`
203pub trait EntryHolder: TypedNode {
204    /// Return an iterator over all key=value entries
205    fn entries(&self) -> Box<dyn Iterator<Item = KeyValue>> {
206        Box::new(self.node().children().filter_map(KeyValue::cast))
207    }
208    /// Return an iterator over all inherit entries
209    fn inherits(&self) -> Box<dyn Iterator<Item = Inherit>> {
210        Box::new(self.node().children().filter_map(Inherit::cast))
211    }
212}
213 */
214
215/// Provides the function `.inner()` for wrapping types like parenthensis
216pub trait Wrapper: TypedNode {
217    /// Return the inner value
218    fn inner(&self) -> Option<SyntaxNode> {
219        nth!(self; 0)
220    }
221}
222
223pub struct ParsedTypeError(pub SyntaxKind);
224
225pub enum ParsedType {
226    Root(Root),
227
228    Include(Include),
229    Const(Const),
230    Setting(Setting),
231    RequireContext(RequireContext),
232    Extends(Extends),
233    Struct(Struct),
234
235    StructField(StructField), // TODO: not needed?
236    VarDecl(VarDecl),
237    FuncDecl(FuncDecl),
238    FormalArg(FormalArg), // TODO: not needed?
239    LabelDecl(LabelDecl),
240
241    IfElse(IfElse),
242    Switch(Switch),
243    Case(Case), // TODO: not needed?
244    Default(Default), // TODO: not needed?
245    For(For),
246    Foreach(Foreach),
247    While(While),
248
249    Continue(Continue), // TODO: not needed?
250    Break(Break), // TODO: not needed?
251    Return(Return), // TODO: not needed?
252    Yield(Yield), // TODO: not needed?
253    LabelCall(LabelCall),
254    Assignment(Assignment),
255
256    Block(Block),
257    Parenthesised(Parenthesised),
258
259    Identifier(Identifier),
260    String(String),
261    Literal(Literal),
262    Vector(Vector),
263    Array(Array),
264    UnaryOp(UnaryOp),
265    BinaryOp(BinaryOp),
266    ArrayAccess(ArrayAccess),
267    FunctionCall(FunctionCall),
268    StructInit(StructInit),
269
270    Type(Type)
271}
272
273impl core::convert::TryFrom<SyntaxNode> for ParsedType {
274    type Error = ParsedTypeError;
275
276    fn try_from(node: SyntaxNode) -> Result<Self, ParsedTypeError> {
277        match node.kind() {
278            NODE_ROOT => Ok(ParsedType::Root(Root::cast(node).unwrap())),
279
280            NODE_INCLUDE => Ok(ParsedType::Include(Include::cast(node).unwrap())),
281            NODE_CONST => Ok(ParsedType::Const(Const::cast(node).unwrap())),
282            NODE_SETTING => Ok(ParsedType::Setting(Setting::cast(node).unwrap())),
283            NODE_REQUIRE_CONTEXT => Ok(ParsedType::RequireContext(RequireContext::cast(node).unwrap())),
284            NODE_EXTENDS => Ok(ParsedType::Extends(Extends::cast(node).unwrap())),
285            NODE_STRUCT => Ok(ParsedType::Struct(Struct::cast(node).unwrap())),
286
287            NODE_STRUCT_FIELD => Ok(ParsedType::StructField(StructField::cast(node).unwrap())),
288            NODE_VAR_DECL => Ok(ParsedType::VarDecl(VarDecl::cast(node).unwrap())),
289            NODE_FUNC_DECL => Ok(ParsedType::FuncDecl(FuncDecl::cast(node).unwrap())),
290            NODE_FORMAL_ARG => Ok(ParsedType::FormalArg(FormalArg::cast(node).unwrap())),
291            NODE_LABEL_DECL => Ok(ParsedType::LabelDecl(LabelDecl::cast(node).unwrap())),
292
293            NODE_IF_ELSE => Ok(ParsedType::IfElse(IfElse::cast(node).unwrap())),
294            NODE_SWITCH => Ok(ParsedType::Switch(Switch::cast(node).unwrap())),
295            NODE_CASE => Ok(ParsedType::Case(Case::cast(node).unwrap())),
296            NODE_DEFAULT => Ok(ParsedType::Default(Default::cast(node).unwrap())),
297            NODE_FOR => Ok(ParsedType::For(For::cast(node).unwrap())),
298            NODE_FOREACH => Ok(ParsedType::Foreach(Foreach::cast(node).unwrap())),
299            NODE_WHILE => Ok(ParsedType::While(While::cast(node).unwrap())),
300
301            NODE_CONTINUE => Ok(ParsedType::Continue(Continue::cast(node).unwrap())),
302            NODE_BREAK => Ok(ParsedType::Break(Break::cast(node).unwrap())),
303            NODE_RETURN => Ok(ParsedType::Return(Return::cast(node).unwrap())),
304            NODE_YIELD => Ok(ParsedType::Yield(Yield::cast(node).unwrap())),
305            NODE_LABEL_CALL => Ok(ParsedType::LabelCall(LabelCall::cast(node).unwrap())),
306            NODE_ASSIGNMENT => Ok(ParsedType::Assignment(Assignment::cast(node).unwrap())),
307
308            NODE_BLOCK => Ok(ParsedType::Block(Block::cast(node).unwrap())),
309            NODE_PARENTHESISED => Ok(ParsedType::Parenthesised(Parenthesised::cast(node).unwrap())),
310
311            NODE_IDENTIFIER => Ok(ParsedType::Identifier(Identifier::cast(node).unwrap())),
312            NODE_STRING => Ok(ParsedType::String(String::cast(node).unwrap())),
313            NODE_LITERAL => Ok(ParsedType::Literal(Literal::cast(node).unwrap())),
314            NODE_VECTOR => Ok(ParsedType::Vector(Vector::cast(node).unwrap())),
315            NODE_ARRAY => Ok(ParsedType::Array(Array::cast(node).unwrap())),
316            NODE_UNARY_OP => Ok(ParsedType::UnaryOp(UnaryOp::cast(node).unwrap())),
317            NODE_BINARY_OP => Ok(ParsedType::BinaryOp(BinaryOp::cast(node).unwrap())),
318            NODE_ARRAY_ACCESS => Ok(ParsedType::ArrayAccess(ArrayAccess::cast(node).unwrap())),
319            NODE_FUNCTION_CALL => Ok(ParsedType::FunctionCall(FunctionCall::cast(node).unwrap())),
320            NODE_STRUCT_INIT => Ok(ParsedType::StructInit(StructInit::cast(node).unwrap())),
321
322            NODE_TYPE => Ok(ParsedType::Type(Type::cast(node).unwrap())),
323            other => Err(ParsedTypeError(other)),
324        }
325    }
326}
327
328// TODO: implems
329typed![
330    NODE_ROOT => Root,
331
332    NODE_INCLUDE => Include,
333    NODE_CONST => Const,
334    NODE_SETTING => Setting,
335    NODE_REQUIRE_CONTEXT => RequireContext,
336    NODE_EXTENDS => Extends,
337    NODE_STRUCT => Struct,
338
339    NODE_STRUCT_FIELD => StructField,
340    NODE_VAR_DECL => VarDecl,
341    NODE_FUNC_DECL => FuncDecl,
342    NODE_FORMAL_ARG => FormalArg,
343    NODE_LABEL_DECL => LabelDecl,
344
345    NODE_IF_ELSE => IfElse,
346    NODE_SWITCH => Switch,
347    NODE_CASE => Case,
348    NODE_DEFAULT => Default,
349    NODE_FOR => For,
350    NODE_FOREACH => Foreach,
351    NODE_WHILE => While,
352
353    NODE_CONTINUE => Continue,
354    NODE_BREAK => Break,
355    NODE_RETURN => Return,
356    NODE_YIELD => Yield,
357    NODE_LABEL_CALL => LabelCall,
358    NODE_ASSIGNMENT => Assignment,
359
360    NODE_BLOCK => Block,
361    NODE_PARENTHESISED => Parenthesised,
362
363    NODE_IDENTIFIER => Identifier,
364    NODE_STRING => String,
365    NODE_LITERAL => Literal,
366    NODE_VECTOR => Vector,
367    NODE_ARRAY => Array,
368    NODE_UNARY_OP => UnaryOp,
369    NODE_BINARY_OP => BinaryOp,
370    NODE_ARRAY_ACCESS => ArrayAccess,
371    NODE_FUNCTION_CALL => FunctionCall,
372    NODE_STRUCT_INIT => StructInit,
373
374    NODE_TYPE => Type
375];