swan_core/ast.rs
1//! The abstract syntax tree produced by the [`Parser`](crate::parser::Parser).
2//!
3//! A parsed expression is a tree of [`Node`]s. Every node records `pos`, the
4//! byte offset in the source of the token that produced it (for a binary
5//! operation, the operator; for function application, which has no operator,
6//! the start of the argument). Evaluation errors report this position.
7//!
8//! Syntax errors do not stop parsing. They become [`Node::Unclosed`] or
9//! [`Node::UnexpectedToken`] leaves, which evaluate to `Undefined` values.
10
11
12/// A leaf node: a literal value and its source position.
13#[derive(Debug, PartialEq, Clone)]
14pub struct Leaf<T> {
15 /// Byte offset of the token in the source.
16 pub pos: usize,
17 /// The literal value.
18 pub val: T,
19}
20
21
22/// A node with one operand: a prefix operator or a bracketed group.
23#[derive(Debug, PartialEq, Clone)]
24pub struct UnaryOp {
25 /// Byte offset of the operator or opening bracket in the source.
26 pub pos: usize,
27 /// The operand.
28 pub opd: Box<Node>,
29}
30
31
32/// A node with two operands: an infix operator or function application.
33#[derive(Debug, PartialEq, Clone)]
34pub struct BinaryOp {
35 /// Byte offset of the operator in the source. For function application,
36 /// which has no operator, it is the byte offset of the argument.
37 pub pos: usize,
38 /// The left-hand operand.
39 pub lho: Box<Node>,
40 /// The right-hand operand.
41 pub rho: Box<Node>,
42}
43
44
45
46
47/// A node of the Swan syntax tree.
48///
49/// The comment on each variant shows the syntax that produces it.
50#[derive(Debug, PartialEq, Clone)]
51pub enum Node {
52
53 // Literals / Leaves
54
55 /// A name, such as `x` or `my_var`.
56 Identifier(Leaf<String>),
57 /// A number literal, such as `42` or `1.5e-3`.
58 Numb(Leaf<f64>),
59 /// A text literal, such as `"hello"`. The value excludes the quotes.
60 Text(Leaf<String>),
61 /// `()`, or an empty expression.
62 Nothing(Leaf<()>),
63 /// Syntax error: a group that is not closed. The value is the missing
64 /// closing bracket (`)`, `]` or `}`).
65 Unclosed(Leaf<char>),
66 /// Syntax error: a token that cannot appear where it was found. The value
67 /// is a debug description of the token.
68 UnexpectedToken(Leaf<String>),
69
70
71 // Grouping
72
73 /// `[X]`: a list literal.
74 List(UnaryOp),
75 /// `{X}`: a namespace literal.
76 Namespace(UnaryOp),
77
78
79 // Unary Operations
80
81 /// `+X`
82 AffirmOp(UnaryOp),
83 /// `-X`
84 NegateOp(UnaryOp),
85 /// `!X`
86 LogicalNegationOp(UnaryOp),
87 /// `$X`
88 LiftingOp(UnaryOp),
89
90
91 // Binary Operations :: Core
92
93 /// `X -> Y`
94 FunctionDefinitionOp(BinaryOp),
95 /// `X Y`: function application, written by juxtaposition.
96 ApplicationOp(BinaryOp),
97 /// `X , Y`
98 PairingOp(BinaryOp),
99 /// `X => Y`
100 MappingOp(BinaryOp),
101 /// `X = Y`
102 AssignmentOp(BinaryOp),
103 /// `X : Y`
104 LabellingOp(BinaryOp),
105 /// `X . Y`
106 SubcontextingOp(BinaryOp),
107 /// `X ~> Y`
108 ThenOp(BinaryOp),
109
110
111 // Binary Operations :: Arithmetic
112
113 /// `X ^ Y`
114 PowerOp(BinaryOp),
115 /// `X * Y`
116 ProductOp(BinaryOp),
117 /// `X / Y`
118 DivisionOp(BinaryOp),
119 /// `X % Y`
120 ModuloOp(BinaryOp),
121 /// `X + Y`
122 SumOp(BinaryOp),
123 /// `X - Y`
124 SubtractionOp(BinaryOp),
125
126
127 // Binary Operations :: Comparison
128
129 /// `X == Y`
130 EqualToOp(BinaryOp),
131 /// `X != Y`
132 NotEqualToOp(BinaryOp),
133 /// `X < Y`
134 LessThanOp(BinaryOp),
135 /// `X <= Y`
136 LessThanOrEqualToOp(BinaryOp),
137 /// `X > Y`
138 GreaterThanOp(BinaryOp),
139 /// `X >= Y`
140 GreaterThanOrEqualToOp(BinaryOp),
141
142
143 // Binary Operations :: Logic
144
145 /// `X & Y`
146 AndOp(BinaryOp),
147 /// `X | Y`
148 OrOp(BinaryOp),
149
150
151 // Binary Operations :: Conditional
152
153 /// `X ? Y`
154 ConditionalOp(BinaryOp),
155 /// `X ; Y`
156 AlternativeOp(BinaryOp),
157
158
159 // Binary Operations :: Function Composition
160
161 /// `X << Y`
162 CompositionOp(BinaryOp),
163 /// `X >> Y`
164 ReverseCompositionOp(BinaryOp),
165}
166
167
168impl Node {
169
170 /// Returns the source byte offset recorded in this node.
171 pub fn position (&self) -> usize {
172 match self {
173
174 Self::Identifier(leaf) => leaf.pos,
175 Self::Numb(leaf) => leaf.pos,
176 Self::Text(leaf) => leaf.pos,
177 Self::Nothing(leaf) => leaf.pos,
178 Self::Unclosed(leaf) => leaf.pos,
179 Self::UnexpectedToken(leaf) => leaf.pos,
180
181 Self::List(unary) => unary.pos,
182 Self::Namespace(unary) => unary.pos,
183
184 Self::AffirmOp(unary) => unary.pos,
185 Self::NegateOp(unary) => unary.pos,
186 Self::LogicalNegationOp(unary) => unary.pos,
187 Self::LiftingOp(unary) => unary.pos,
188
189 Self::FunctionDefinitionOp(binary) => binary.pos,
190 Self::ApplicationOp(binary) => binary.pos,
191 Self::PairingOp(binary) => binary.pos,
192 Self::MappingOp(binary) => binary.pos,
193 Self::AssignmentOp(binary) => binary.pos,
194 Self::LabellingOp(binary) => binary.pos,
195 Self::SubcontextingOp(binary) => binary.pos,
196 Self::ThenOp(binary) => binary.pos,
197
198 Self::PowerOp(binary) => binary.pos,
199 Self::ProductOp(binary) => binary.pos,
200 Self::DivisionOp(binary) => binary.pos,
201 Self::ModuloOp(binary) => binary.pos,
202 Self::SumOp(binary) => binary.pos,
203 Self::SubtractionOp(binary) => binary.pos,
204
205 Self::EqualToOp(binary) => binary.pos,
206 Self::NotEqualToOp(binary) => binary.pos,
207 Self::LessThanOp(binary) => binary.pos,
208 Self::LessThanOrEqualToOp(binary) => binary.pos,
209 Self::GreaterThanOp(binary) => binary.pos,
210 Self::GreaterThanOrEqualToOp(binary) => binary.pos,
211
212 Self::AndOp(binary) => binary.pos,
213 Self::OrOp(binary) => binary.pos,
214
215 Self::ConditionalOp(binary) => binary.pos,
216 Self::AlternativeOp(binary) => binary.pos,
217
218 Self::CompositionOp(binary) => binary.pos,
219 Self::ReverseCompositionOp(binary) => binary.pos,
220 }
221 }
222
223}