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