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}