Skip to main content

probl_syntax/
ast.rs

1//! The abstract syntax tree produced by the parser.
2
3use crate::span::Span;
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct Ident {
7    pub name: String,
8    pub span: Span,
9}
10
11#[derive(Clone, Debug, PartialEq)]
12pub struct Program {
13    pub pragmas: Vec<Pragma>,
14    pub items: Vec<Item>,
15}
16
17/// `@mode exact`, `@mode sample(runs: 1000)`, `@epsilon 1e-9`.
18#[derive(Clone, Debug, PartialEq)]
19pub struct Pragma {
20    pub name: Ident,
21    pub arg: Option<Expr>,
22    pub span: Span,
23}
24
25#[derive(Clone, Debug, PartialEq)]
26pub enum Item {
27    Fn(FnDecl),
28    Type(TypeDecl),
29    Enum(EnumDecl),
30    Import(Import),
31    Stmt(Stmt),
32}
33
34#[derive(Clone, Debug, PartialEq)]
35pub struct FnDecl {
36    pub name: Ident,
37    pub params: Vec<Param>,
38    pub ret: Option<TypeExpr>,
39    pub body: Block,
40    pub span: Span,
41}
42
43#[derive(Clone, Debug, PartialEq)]
44pub struct Param {
45    pub name: Ident,
46    pub ty: Option<TypeExpr>,
47}
48
49#[derive(Clone, Debug, PartialEq)]
50pub struct TypeDecl {
51    pub name: Ident,
52    pub ty: TypeExpr,
53    pub span: Span,
54}
55
56#[derive(Clone, Debug, PartialEq)]
57pub struct EnumDecl {
58    pub name: Ident,
59    pub variants: Vec<Ident>,
60    pub span: Span,
61}
62
63#[derive(Clone, Debug, PartialEq)]
64pub struct Import {
65    pub path: String,
66    pub span: Span,
67}
68
69#[derive(Clone, Debug, PartialEq)]
70pub enum TypeExpr {
71    /// `int`, `list[int]`, `dist[int]`, `Fighter`.
72    Named { name: Ident, args: Vec<TypeExpr> },
73    /// `{ hp: int, ac: int }`.
74    Record { fields: Vec<(Ident, TypeExpr)>, span: Span },
75}
76
77#[derive(Clone, Debug, PartialEq)]
78pub struct Block {
79    pub stmts: Vec<Stmt>,
80    pub span: Span,
81}
82
83#[derive(Clone, Debug, PartialEq)]
84pub struct Stmt {
85    pub kind: StmtKind,
86    pub span: Span,
87}
88
89/// `=` or `~` in a binding or assignment.
90#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91pub enum BindOp {
92    Assign,
93    Draw,
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
97pub enum AssignOp {
98    Set,
99    Draw,
100    Add,
101    Sub,
102    Mul,
103    Div,
104}
105
106#[derive(Clone, Debug, PartialEq)]
107pub enum StmtKind {
108    /// `let` / `var` bindings.
109    Let {
110        mutable: bool,
111        pattern: Pattern,
112        ty: Option<TypeExpr>,
113        op: BindOp,
114        value: Expr,
115    },
116    Assign {
117        target: Expr,
118        op: AssignOp,
119        value: Expr,
120    },
121    For {
122        pattern: Pattern,
123        iter: Expr,
124        body: Block,
125    },
126    While {
127        cond: Expr,
128        body: Block,
129    },
130    Repeat {
131        count: Expr,
132        body: Block,
133    },
134    Loop {
135        body: Block,
136    },
137    Break,
138    Continue,
139    Return(Option<Expr>),
140    Observe {
141        value: Expr,
142        from: Option<Expr>,
143    },
144    /// Multiply the current world's weight by a probability.
145    Score(Expr),
146    Report {
147        value: Expr,
148        by: Option<Expr>,
149        label: Option<(String, Span)>,
150    },
151    Expr(Expr),
152}
153
154#[derive(Clone, Debug, PartialEq)]
155pub struct Expr {
156    pub kind: ExprKind,
157    pub span: Span,
158}
159
160#[derive(Clone, Debug, PartialEq)]
161pub enum ExprKind {
162    Int(probl_number::Integer),
163    Float(f64),
164    /// Already divided by 100.
165    Percent(f64),
166    Dice {
167        count: u32,
168        sides: u32,
169    },
170    Str(Vec<StrSegment>),
171    Bool(bool),
172    Name(String),
173    List(Vec<Expr>),
174    Map(Vec<(Expr, Expr)>),
175    /// `Fighter { hp: 12 }` (named) or `{ won: true }` (anonymous).
176    Record {
177        name: Option<Ident>,
178        fields: Vec<Field>,
179    },
180    Unary {
181        op: UnOp,
182        expr: Box<Expr>,
183    },
184    /// Prefix `~`: draw one value each time this expression is evaluated.
185    Draw(Box<Expr>),
186    Binary {
187        op: BinOp,
188        lhs: Box<Expr>,
189        rhs: Box<Expr>,
190    },
191    Call {
192        callee: Box<Expr>,
193        args: Vec<Arg>,
194    },
195    /// `receiver.name(args)`.
196    Method {
197        receiver: Box<Expr>,
198        name: Ident,
199        args: Vec<Arg>,
200    },
201    Field {
202        expr: Box<Expr>,
203        name: Ident,
204    },
205    Index {
206        expr: Box<Expr>,
207        index: Box<Expr>,
208    },
209    /// `expr with { field: value }`.
210    With {
211        expr: Box<Expr>,
212        fields: Vec<Field>,
213    },
214    Lambda {
215        params: Vec<Ident>,
216        body: Box<Expr>,
217    },
218    If {
219        cond: Box<Expr>,
220        then: Block,
221        otherwise: Option<Box<Expr>>,
222    },
223    Chance {
224        arms: Vec<ChanceArm>,
225    },
226    Match {
227        scrutinee: Box<Expr>,
228        arms: Vec<MatchArm>,
229    },
230    Simulate(Block),
231    Block(Block),
232    /// `try { … } catch Fault { … } catch { … }`.
233    Try {
234        body: Block,
235        catches: Vec<Catch>,
236    },
237}
238
239/// `catch Fault { … }`, or `catch { … }` for every fault.
240#[derive(Clone, Debug, PartialEq)]
241pub struct Catch {
242    pub fault: Option<Ident>,
243    pub body: Block,
244    pub span: Span,
245}
246
247#[derive(Clone, Debug, PartialEq)]
248pub enum StrSegment {
249    Lit(String),
250    Expr(Expr),
251}
252
253#[derive(Clone, Debug, PartialEq)]
254pub struct Field {
255    pub name: Ident,
256    pub value: Expr,
257}
258
259#[derive(Clone, Debug, PartialEq)]
260pub struct Arg {
261    pub name: Option<Ident>,
262    pub value: Expr,
263}
264
265/// `weight => body`; the weight is `None` for `else`.
266#[derive(Clone, Debug, PartialEq)]
267pub struct ChanceArm {
268    pub weight: Option<Expr>,
269    pub body: Stmt,
270    pub span: Span,
271}
272
273#[derive(Clone, Debug, PartialEq)]
274pub struct MatchArm {
275    pub pattern: Pattern,
276    pub guard: Option<Expr>,
277    pub body: Stmt,
278    pub span: Span,
279}
280
281#[derive(Clone, Copy, Debug, PartialEq, Eq)]
282pub enum UnOp {
283    Neg,
284    Not,
285    Typeof,
286}
287
288#[derive(Clone, Copy, Debug, PartialEq, Eq)]
289pub enum BinOp {
290    Or,
291    And,
292    Eq,
293    Ne,
294    Lt,
295    Le,
296    Gt,
297    Ge,
298    In,
299    NotIn,
300    /// `a..b`, both ends included.
301    Range,
302    /// `a..<b`.
303    RangeExcl,
304    /// `a to b`: an estimate with a 90% interval.
305    To,
306    Add,
307    Sub,
308    Mul,
309    Div,
310    IntDiv,
311    Mod,
312    Pow,
313}
314
315impl BinOp {
316    pub fn symbol(self) -> &'static str {
317        match self {
318            BinOp::Or => "or",
319            BinOp::And => "and",
320            BinOp::Eq => "==",
321            BinOp::Ne => "!=",
322            BinOp::Lt => "<",
323            BinOp::Le => "<=",
324            BinOp::Gt => ">",
325            BinOp::Ge => ">=",
326            BinOp::In => "in",
327            BinOp::NotIn => "not in",
328            BinOp::Range => "..",
329            BinOp::RangeExcl => "..<",
330            BinOp::To => "to",
331            BinOp::Add => "+",
332            BinOp::Sub => "-",
333            BinOp::Mul => "*",
334            BinOp::Div => "/",
335            BinOp::IntDiv => "div",
336            BinOp::Mod => "mod",
337            BinOp::Pow => "^",
338        }
339    }
340}
341
342#[derive(Clone, Debug, PartialEq)]
343pub struct Pattern {
344    pub kind: PatternKind,
345    pub span: Span,
346}
347
348#[derive(Clone, Debug, PartialEq)]
349pub enum PatternKind {
350    Wildcard,
351    /// A name: binds a new variable, or matches an enum variant of that name.
352    Name(String),
353    Literal(Expr),
354    List(Vec<Pattern>),
355    Or(Vec<Pattern>),
356}