varyk_syntax/ast.rs
1//! The AST produced by the parser (spec section 6.3). Every node carries a
2//! [`Span`], except [`Program`] and [`Item`], whose span is whichever
3//! variant/item they hold.
4
5use crate::span::Span;
6
7/// A name plus the span it was written at.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Ident {
10 pub name: String,
11 pub span: Span,
12}
13
14/// Where a path starts (spec 3.1, 3.3): one of the three keyword prefixes,
15/// or nothing (a plain module name declared in this file, or no module
16/// segment at all). The parser records whichever prefix is written;
17/// resolving `Crate` and `Super` to an actual module, and rejecting
18/// `Super` in the crate root (V0111), is the compiler's resolver's job.
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum PathStart {
21 Crate,
22 SelfMod,
23 Super,
24 None,
25}
26
27/// A `::`-separated path (spec 3.1, 3.3): an optional keyword prefix
28/// (`crate`, `self`, `super`) followed by name segments. What the segments
29/// (and any name that follows them, for a type or expression path) resolve
30/// to -- a chain of modules, a type, a function, a variant -- is decided by
31/// where the path appears and, ultimately, the compiler's resolver, never
32/// the parser.
33#[derive(Debug, Clone, PartialEq, Eq)]
34pub struct Path {
35 pub leading: PathStart,
36 pub segments: Vec<Ident>,
37 pub span: Span,
38}
39
40/// A named type: `string`, `i32`, `User`, and so on are all just names,
41/// resolved later by the compiler's resolver. A type may carry a module
42/// path (`m::User`, `shop::cart::Cart`, spec 2.10, 3.1) and generic
43/// arguments (`Vec<i32>`, `Result<User, string>`, nested freely, spec 2.6);
44/// the parser only records them, and the resolver checks that the path,
45/// the name, and the argument count exist.
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct TypeExpr {
48 pub path: Option<Path>,
49 pub name: Ident,
50 pub args: Vec<TypeExpr>,
51 pub span: Span,
52}
53
54impl TypeExpr {
55 /// Renders the whole type back to source text: the path (if any), the
56 /// name, and any generic arguments, recursively. Used wherever a
57 /// diagnostic or fix-it needs to show the type as written, rather than
58 /// just its base name.
59 pub fn display_name(&self) -> String {
60 let mut out = String::new();
61 if let Some(path) = &self.path {
62 match path.leading {
63 PathStart::Crate => out.push_str("crate::"),
64 PathStart::SelfMod => out.push_str("self::"),
65 PathStart::Super => out.push_str("super::"),
66 PathStart::None => {}
67 }
68 for segment in &path.segments {
69 out.push_str(&segment.name);
70 out.push_str("::");
71 }
72 }
73 out.push_str(&self.name.name);
74 if !self.args.is_empty() {
75 out.push('<');
76 for (i, arg) in self.args.iter().enumerate() {
77 if i > 0 {
78 out.push_str(", ");
79 }
80 out.push_str(&arg.display_name());
81 }
82 out.push('>');
83 }
84 out
85 }
86}
87
88/// An attribute, `#[name]` or `#[name(literal)]` (M5a spec 2.2), written
89/// before an item, a struct field, an enum variant, a field of a variant,
90/// or a method. The parser keeps every one it reads; which names exist and
91/// where each may go is the compiler's resolver's to check.
92#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct Attribute {
94 pub name: Ident,
95 /// What is between the parentheses; `None` when there are none.
96 pub arg: Option<AttrArg>,
97 /// From `#` through `]`.
98 pub span: Span,
99}
100
101/// The argument of an attribute: one literal, a number optionally after
102/// `-`, with a number's raw text as lexed and a string's text between the
103/// quotes, unmodified.
104#[derive(Debug, Clone, PartialEq, Eq)]
105pub enum AttrArg {
106 Str(String),
107 Int {
108 text: String,
109 negative: bool,
110 },
111 Float {
112 text: String,
113 negative: bool,
114 },
115 Bool(bool),
116 /// Anything else between the parentheses (`#[derive(Clone)]`): kept
117 /// so the resolver can name the attribute, never a valid argument.
118 Other,
119}
120
121/// A whole parsed source file: the top-level items it declares, in order.
122#[derive(Debug, Clone, PartialEq)]
123pub struct Program {
124 pub items: Vec<Item>,
125}
126
127/// A top-level declaration (spec 4.1, 2.2, 2.5): a function, a struct, an
128/// enum, an `impl` block, or a module declaration. `mod name;` only
129/// declares a submodule; resolving it to the submodule's own file and items
130/// is the compiler's `resolve` module's job.
131#[derive(Debug, Clone, PartialEq)]
132pub enum Item {
133 Function(Function),
134 Struct(StructDecl),
135 Enum(EnumDecl),
136 Impl(ImplBlock),
137 Mod(ModDecl),
138 Use(UseDecl),
139}
140
141/// Whether a function is a plain function, or a method with a `self`
142/// receiver (spec 2.5): `self` is a shared borrow, `mut self` a mutable
143/// borrow. There is no owned `self` in milestone 2.
144#[derive(Debug, Clone, Copy, PartialEq, Eq)]
145pub enum SelfMode {
146 None,
147 Shared,
148 Mutable,
149}
150
151/// `fn name(params) -> ReturnType { body }`, optionally `pub`. Inside an
152/// `impl` block the parameter list may start with a `self` receiver
153/// (`self_mode`), which is never a [`Param`] (spec 2.5).
154#[derive(Debug, Clone, PartialEq)]
155pub struct Function {
156 pub attrs: Vec<Attribute>,
157 pub name: Ident,
158 pub is_pub: bool,
159 pub self_mode: SelfMode,
160 /// The `self` keyword of the receiver, where a `mut ` fix-it inserts;
161 /// `None` exactly when `self_mode` is [`SelfMode::None`].
162 pub self_span: Option<Span>,
163 pub params: Vec<Param>,
164 pub return_type: Option<TypeExpr>,
165 pub body: Block,
166 pub span: Span,
167}
168
169/// One parameter: `name: T` is a shared borrow, `mut name: T` is a mutable
170/// borrow (spec 4.2).
171#[derive(Debug, Clone, PartialEq)]
172pub struct Param {
173 pub name: Ident,
174 pub mutable: bool,
175 pub ty: TypeExpr,
176 pub span: Span,
177}
178
179/// `struct Name { fields... }`, optionally `pub` (spec 4.1). Whether a
180/// field is visible follows the same rule as everything else (spec 3.2):
181/// see [`FieldDecl::is_pub`].
182#[derive(Debug, Clone, PartialEq)]
183pub struct StructDecl {
184 pub attrs: Vec<Attribute>,
185 pub name: Ident,
186 pub is_pub: bool,
187 pub fields: Vec<FieldDecl>,
188 pub span: Span,
189}
190
191/// A struct field: `name: T`, optionally `pub` (spec 3.4). Visibility
192/// follows the same rule as everything else (section 3.2): a private
193/// field is visible in the declaring module and its descendants, which
194/// includes the struct's own methods.
195#[derive(Debug, Clone, PartialEq)]
196pub struct FieldDecl {
197 pub attrs: Vec<Attribute>,
198 pub name: Ident,
199 pub ty: TypeExpr,
200 pub is_pub: bool,
201 pub span: Span,
202}
203
204/// `enum Name { variants... }` (spec 2.2), optionally `pub`. An enum has one
205/// or more variants; an empty `{ }` is `V0002`, since the parser found a
206/// complete-looking declaration missing the one thing it must have.
207#[derive(Debug, Clone, PartialEq)]
208pub struct EnumDecl {
209 pub attrs: Vec<Attribute>,
210 pub name: Ident,
211 pub is_pub: bool,
212 pub variants: Vec<EnumVariant>,
213 pub span: Span,
214}
215
216/// A variant of an enum: a unit variant (`Point`), a tuple variant
217/// (`Circle(f64)`), or a variant with named fields (`Click { x: i32 }`, M4
218/// spec 2.5).
219#[derive(Debug, Clone, PartialEq)]
220pub struct EnumVariant {
221 pub attrs: Vec<Attribute>,
222 pub name: Ident,
223 pub fields: VariantFields,
224 pub span: Span,
225}
226
227/// What a variant holds: nothing, values by position (`Circle(f64)`; an
228/// empty `Circle()` is a `Tuple` of no types), or named fields.
229#[derive(Debug, Clone, PartialEq)]
230pub enum VariantFields {
231 Unit,
232 Tuple(Vec<TypeExpr>),
233 Named(Vec<VariantField>),
234}
235
236/// A named field of a variant: `name: T`. It has no visibility of its own:
237/// a variant's fields are as visible as the enum, and Rust rejects `pub`
238/// on them.
239#[derive(Debug, Clone, PartialEq)]
240pub struct VariantField {
241 pub attrs: Vec<Attribute>,
242 pub name: Ident,
243 pub ty: TypeExpr,
244 pub span: Span,
245}
246
247/// `impl Name { fns... }` (spec 2.5): a block of functions and methods for
248/// a struct or enum declared in the same file. Whether `name` actually
249/// names a struct or enum is the compiler's `resolve` module's job.
250#[derive(Debug, Clone, PartialEq)]
251pub struct ImplBlock {
252 pub attrs: Vec<Attribute>,
253 pub type_name: Ident,
254 pub functions: Vec<Function>,
255 pub span: Span,
256}
257
258/// `mod name;` (spec 4.5): declares a submodule resolved to `name.vr` or
259/// `name.rs` in the same directory. Resolving and merging the submodule's
260/// items is the compiler's `resolve` module's job; this node only records
261/// the declaration.
262#[derive(Debug, Clone, PartialEq)]
263pub struct ModDecl {
264 pub attrs: Vec<Attribute>,
265 pub name: Ident,
266 pub is_pub: bool,
267 pub span: Span,
268}
269
270/// `use path;` or `use path as name;` (spec 3.3): introduces a local alias
271/// for whatever `path` names -- a module, a struct, an enum, or a function
272/// -- resolved and checked by the compiler's resolver, never the parser.
273#[derive(Debug, Clone, PartialEq)]
274pub struct UseDecl {
275 pub attrs: Vec<Attribute>,
276 pub path: Path,
277 pub alias: Option<Ident>,
278 pub span: Span,
279}
280
281/// A statement: `let`, assignment, `return`, `while`, `break`, `continue`,
282/// or an expression used for its side effects (or as a block's tail,
283/// distinguished by `has_semi` on [`Stmt::Expr`] so the type checker can tell a
284/// mid-block statement from a block's value).
285#[derive(Debug, Clone, PartialEq)]
286pub enum Stmt {
287 Let {
288 name: Ident,
289 mutable: bool,
290 ty: Option<TypeExpr>,
291 value: Expr,
292 span: Span,
293 },
294 /// Assignment to a place expression: a path (a variable) or a field
295 /// access. Anything else as the target is rejected (`V0002`) before
296 /// this node is ever built.
297 Assign {
298 target: Expr,
299 value: Expr,
300 span: Span,
301 },
302 /// An expression statement. `has_semi` is false only for a block-like
303 /// expression (`if`, a bare block) written without a trailing `;` in
304 /// the middle of a block, not at its end.
305 Expr {
306 expr: Expr,
307 span: Span,
308 has_semi: bool,
309 },
310 Return {
311 value: Option<Expr>,
312 span: Span,
313 },
314 While {
315 cond: Expr,
316 body: Block,
317 span: Span,
318 },
319 /// `while let pattern = value { body }` (M4 spec 2.4): `value` is
320 /// parsed in condition position, as `while`'s condition is.
321 WhileLet {
322 pattern: Pattern,
323 value: Expr,
324 body: Block,
325 span: Span,
326 },
327 /// `for var in head { body }` (spec 2.4). `head` is either a half-open
328 /// range or a `Vec` iterated element by element; the loop variable's
329 /// type and whether the `Vec` case borrows or owns each element is the
330 /// type checker's job (task 8).
331 For {
332 var: Ident,
333 head: ForHead,
334 body: Block,
335 span: Span,
336 },
337 Break {
338 span: Span,
339 },
340 Continue {
341 span: Span,
342 },
343}
344
345/// The head of a `for` loop (spec 2.4): an integer range, half-open
346/// (`a..b`) or `inclusive` (`a..=b`, M4 spec 2.11), parsed only here since
347/// an expression range exists nowhere else in Varyk, or an expression
348/// iterated element by element as a `Vec`.
349#[derive(Debug, Clone, PartialEq)]
350pub enum ForHead {
351 Range {
352 start: Box<Expr>,
353 end: Box<Expr>,
354 inclusive: bool,
355 },
356 Expr(Box<Expr>),
357}
358
359/// `{ stmts...; tail }`. The tail expression, if present, is the block's
360/// value.
361#[derive(Debug, Clone, PartialEq)]
362pub struct Block {
363 pub stmts: Vec<Stmt>,
364 pub tail: Option<Box<Expr>>,
365 pub span: Span,
366}
367
368/// Unary operators (spec 4.1). Unary binds tighter than any binary
369/// operator.
370#[derive(Debug, Clone, Copy, PartialEq, Eq)]
371pub enum UnaryOp {
372 Neg,
373 Not,
374}
375
376/// Binary operators (spec 4.1), in Rust's precedence order from loosest to
377/// tightest: `||`, `&&`, the comparisons (non-associative), `+ -`, then
378/// `* / %`.
379#[derive(Debug, Clone, Copy, PartialEq, Eq)]
380pub enum BinaryOp {
381 Or,
382 And,
383 Eq,
384 Ne,
385 Lt,
386 Le,
387 Gt,
388 Ge,
389 Add,
390 Sub,
391 Mul,
392 Div,
393 Rem,
394}
395
396impl BinaryOp {
397 /// The operator as written, the same in Varyk and Rust.
398 pub fn as_str(self) -> &'static str {
399 match self {
400 BinaryOp::Or => "||",
401 BinaryOp::And => "&&",
402 BinaryOp::Eq => "==",
403 BinaryOp::Ne => "!=",
404 BinaryOp::Lt => "<",
405 BinaryOp::Le => "<=",
406 BinaryOp::Gt => ">",
407 BinaryOp::Ge => ">=",
408 BinaryOp::Add => "+",
409 BinaryOp::Sub => "-",
410 BinaryOp::Mul => "*",
411 BinaryOp::Div => "/",
412 BinaryOp::Rem => "%",
413 }
414 }
415}
416
417/// An expression node: its kind plus the span it spans in the source.
418#[derive(Debug, Clone, PartialEq)]
419pub struct Expr {
420 pub kind: ExprKind,
421 pub span: Span,
422}
423
424#[derive(Debug, Clone, PartialEq)]
425pub enum ExprKind {
426 /// Raw digits, as lexed: the type checker decides the type from context.
427 Integer(String),
428 /// Raw `digits.digits`, as lexed.
429 Float(String),
430 Bool(bool),
431 /// Raw text between the quotes, as written: escapes are copied unchanged
432 /// into the generated Rust, which resolves them.
433 String(String),
434
435 /// `name`, `module::name`, or `module::Type::name` (spec 2.5, 2.10,
436 /// 3.1): a plain name, a module-qualified one, or a
437 /// module-and-type-qualified one (an associated function or enum
438 /// variant reached through a module), with paths now growing to any
439 /// depth as nested modules do. `path` covers every segment before the
440 /// final one (the module chain, and the type name when the path names
441 /// an associated function or a variant); `name` is that final segment,
442 /// the thing actually read or called. Whether `path`'s segments name a
443 /// deeper module chain than milestone 3 resolves, a single module, or a
444 /// type in this file (the two-way ambiguity a bare one-segment `path`
445 /// carries, spec 2.10) is the compiler's resolver's job, not the
446 /// parser's.
447 Path {
448 path: Option<Path>,
449 name: Ident,
450 },
451
452 Unary {
453 op: UnaryOp,
454 operand: Box<Expr>,
455 },
456
457 Binary {
458 op: BinaryOp,
459 lhs: Box<Expr>,
460 rhs: Box<Expr>,
461 },
462
463 /// `callee(args...)`. `callee` must be a `Path`, naming a plain
464 /// function or an associated function (spec 2.5); `x.f(args)` is
465 /// method-call syntax and parses as [`ExprKind::MethodCall`] instead,
466 /// never as a `Call` with a `Field` callee. Any other callee shape
467 /// (calling the result of a grouped expression, an index, and so on)
468 /// is rejected: `V0002` from the parser, and defensively `V0001` from
469 /// the type checker if such a node ever reaches it.
470 Call {
471 callee: Box<Expr>,
472 args: Vec<Expr>,
473 },
474
475 Field {
476 base: Box<Expr>,
477 name: Ident,
478 },
479
480 /// `receiver.method(args...)` (spec 2.5): a method call, `value.name(args)`.
481 MethodCall {
482 receiver: Box<Expr>,
483 method: Ident,
484 args: Vec<Expr>,
485 },
486
487 /// `base[index]` (spec 2.6): indexing, `v[i]`. Whether `base` is
488 /// actually a `Vec`, and whether `index` is a `usize`, is the type
489 /// checker's job.
490 Index {
491 base: Box<Expr>,
492 index: Box<Expr>,
493 },
494
495 /// `operand?` (spec 2.8): propagates an `Err` out of the enclosing
496 /// function. Whether `operand` is actually a `Result` compatible with
497 /// the function's return type is the type checker's job.
498 Try {
499 operand: Box<Expr>,
500 },
501
502 /// `match scrutinee { arms... }` (spec 2.3), an expression like `if`.
503 /// It may also stand as a statement without a trailing `;`, the same
504 /// as `if` and a bare block, distinguished the same way by
505 /// `Stmt::Expr`'s `has_semi`.
506 Match {
507 scrutinee: Box<Expr>,
508 arms: Vec<MatchArm>,
509 },
510
511 /// `vec![a, b, c]` (spec 2.9), a compiler intrinsic like `println!`,
512 /// not a macro system: its elements, each an owned slot.
513 VecLit(Vec<Expr>),
514
515 /// `Name { field: expr, ... }`, or `path::Name { field: expr, ... }`
516 /// with a module path of any depth and an optional `crate::`,
517 /// `self::`, or `super::` prefix (spec 2.10, 3.1). Never parsed in
518 /// condition position.
519 StructLit {
520 path: Option<Path>,
521 name: Ident,
522 fields: Vec<(Ident, Expr)>,
523 },
524
525 Block(Block),
526
527 /// `if cond { ... }` or `if cond { ... } else { ... }`. `cond` is
528 /// parsed in condition position, so no struct literal is parsed
529 /// directly in it. An `else if` is represented as `else_` holding a
530 /// synthetic block whose only content is the nested `If` as its tail
531 /// expression.
532 If {
533 cond: Box<Expr>,
534 then: Block,
535 else_: Option<Block>,
536 },
537
538 /// `if let pattern = value { ... }`, with an optional `else` (M4 spec
539 /// 2.4). `value` is parsed in condition position, as `if`'s condition
540 /// is, and `else if` and `else if let` are a synthetic block holding
541 /// the nested expression as its tail, as for [`ExprKind::If`].
542 IfLet {
543 pattern: Pattern,
544 value: Box<Expr>,
545 then: Block,
546 else_: Option<Block>,
547 span: Span,
548 },
549
550 /// `|params| body` (M4 spec 2.2). The parameters carry no type; how
551 /// many there may be, and where a closure may appear, is the
552 /// checker's to decide.
553 Closure {
554 params: Vec<Ident>,
555 body: Box<Expr>,
556 span: Span,
557 },
558
559 /// `expr as T` (M4 spec 2.9), binding tighter than `*`. `ty` is a
560 /// plain name with no path and no generic arguments.
561 Cast {
562 expr: Box<Expr>,
563 ty: TypeExpr,
564 span: Span,
565 },
566
567 /// `println!(format, args...)` or `format!(format, args...)` (spec
568 /// 2.9): compiler intrinsics sharing one shape, told apart by `name`.
569 /// `format` keeps the format string's raw text and span; placeholder
570 /// checking is the type checker's job.
571 Intrinsic {
572 name: Ident,
573 format: (String, Span),
574 args: Vec<Expr>,
575 },
576}
577
578/// One arm of a `match` (spec 2.3): `pattern => body`, with an optional
579/// trailing comma the parser consumes but does not record.
580#[derive(Debug, Clone, PartialEq)]
581pub struct MatchArm {
582 pub pattern: Pattern,
583 pub body: Expr,
584 pub span: Span,
585}
586
587/// A pattern (spec 2.3, M4 spec 2.5), in a `match` arm, an `if let`, or a
588/// `while let`, nested to any depth. Not in Varyk, each `V0001` from the
589/// parser: guards (`pattern if cond`), alternatives (`a | b`), rest
590/// patterns (`..`), and `@` bindings.
591#[derive(Debug, Clone, PartialEq)]
592pub enum Pattern {
593 /// `_`: matches anything, binds nothing.
594 Wildcard(Span),
595 /// A bare name: matches anything and binds it. The parser cannot tell
596 /// this apart from a zero-argument variant written without its type
597 /// (`None`): the type checker decides against the matched value's
598 /// type.
599 Name(Ident),
600 /// A variant, optionally reached through a type and a module, with its
601 /// values by position: `Point`, `Some(p)`, `Shape::Circle(p, q)`,
602 /// `geo::Shape::Point`. `path`'s last segment is always the type
603 /// (unlike an expression path, a pattern never calls anything, so
604 /// there is no bare-module case to weigh it against); any segments
605 /// before that are the module chain. `span` ends at the closing `)`
606 /// when there are parentheses, so `Point()` is told apart from
607 /// `Point`.
608 Variant {
609 path: Option<Path>,
610 name: Ident,
611 fields: Vec<Pattern>,
612 span: Span,
613 },
614 /// A variant or struct with named fields: `Event::Click { x: 0, y }`.
615 /// A shorthand field `y` is `(y, Pattern::Name(y))`.
616 Struct {
617 path: Option<Path>,
618 name: Ident,
619 fields: Vec<(Ident, Pattern)>,
620 span: Span,
621 },
622 /// A literal: an integer with an optional `-`, a string, `true`, or
623 /// `false` (and a float, which the checker rejects).
624 Literal(Literal, Span),
625 /// `start..=end`, both ends included.
626 Range {
627 start: Literal,
628 end: Literal,
629 span: Span,
630 },
631}
632
633impl Pattern {
634 pub fn span(&self) -> Span {
635 match self {
636 Pattern::Wildcard(span) | Pattern::Literal(_, span) => *span,
637 Pattern::Name(ident) => ident.span,
638 Pattern::Variant { span, .. }
639 | Pattern::Struct { span, .. }
640 | Pattern::Range { span, .. } => *span,
641 }
642 }
643}
644
645/// The value of a literal pattern or of a range pattern's end, with the
646/// raw text of a number as lexed.
647#[derive(Debug, Clone, PartialEq, Eq)]
648pub enum Literal {
649 Int { text: String, negative: bool },
650 Float { text: String, negative: bool },
651 Str(String),
652 Bool(bool),
653}