Skip to main content

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