Skip to main content

lex_syntax/
syntax.rs

1//! Syntax tree (the parser's direct output, before canonicalization in §5).
2//!
3//! These nodes hew closely to source syntax; canonicalization (§5.3) folds
4//! `if` into `Match`, `?` into its match expansion, etc.
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub struct Program {
10    pub items: Vec<Item>,
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub enum Item {
15    Import(Import),
16    TypeDecl(TypeDecl),
17    FnDecl(FnDecl),
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
21pub struct Import {
22    pub reference: String,
23    pub alias: String,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
27pub struct TypeDecl {
28    pub name: String,
29    pub params: Vec<String>,
30    pub definition: TypeExpr,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
34pub struct FnDecl {
35    pub name: String,
36    pub type_params: Vec<String>,
37    pub params: Vec<Param>,
38    pub effects: Vec<Effect>,
39    pub return_type: TypeExpr,
40    pub body: Block,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct Param {
45    pub name: String,
46    pub ty: TypeExpr,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50pub struct Effect {
51    pub name: String,
52    pub arg: Option<EffectArg>,
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
56pub enum EffectArg {
57    Str(String),
58    Int(i64),
59    Ident(String),
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
63pub enum TypeExpr {
64    /// Named primitive or constructor application (`Int`, `Result[Int, Str]`, `T`).
65    /// We resolve which it is during type-checking, not parsing.
66    Named { name: String, args: Vec<TypeExpr> },
67    Record(Vec<TypeField>),
68    Tuple(Vec<TypeExpr>),
69    Function {
70        params: Vec<TypeExpr>,
71        effects: Vec<Effect>,
72        ret: Box<TypeExpr>,
73    },
74    Union(Vec<UnionVariant>),
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78pub struct TypeField {
79    pub name: String,
80    pub ty: TypeExpr,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
84pub struct UnionVariant {
85    pub name: String,
86    /// `None` = tag-only (`Empty`); `Some(payload)` = constructor with payload.
87    pub payload: Option<TypeExpr>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
91pub struct Block {
92    pub statements: Vec<Statement>,
93    pub result: Box<Expr>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
97pub enum Statement {
98    Let { name: String, ty: Option<TypeExpr>, value: Expr },
99    Expr(Expr),
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
103pub enum Expr {
104    Lit(Literal),
105    Var(String),
106    Block(Block),
107    Call { callee: Box<Expr>, args: Vec<Expr> },
108    Pipe { left: Box<Expr>, right: Box<Expr> },
109    /// `expr?` postfix.
110    Try(Box<Expr>),
111    /// `expr.field`
112    Field { value: Box<Expr>, field: String },
113    BinOp { op: BinOp, lhs: Box<Expr>, rhs: Box<Expr> },
114    UnaryOp { op: UnaryOp, expr: Box<Expr> },
115    If { cond: Box<Expr>, then_block: Block, else_block: Block },
116    Match { scrutinee: Box<Expr>, arms: Vec<Arm> },
117    RecordLit(Vec<RecordLitField>),
118    TupleLit(Vec<Expr>),
119    ListLit(Vec<Expr>),
120    /// A bare constructor name (`None`, `Empty`) or constructor call (`Ok(x)`).
121    /// Since we cannot distinguish a constructor from a variable at parse
122    /// time, the parser emits `Var`/`Call` and the type checker resolves it.
123    /// This variant is kept for the canonicalizer to lift detected
124    /// constructors into.
125    Constructor { name: String, args: Vec<Expr> },
126    Lambda(Box<Lambda>),
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
130pub struct Lambda {
131    pub params: Vec<Param>,
132    pub return_type: TypeExpr,
133    pub effects: Vec<Effect>,
134    pub body: Block,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
138pub struct RecordLitField {
139    pub name: String,
140    pub value: Expr,
141}
142
143#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
144pub enum BinOp {
145    Add, Sub, Mul, Div, Mod,
146    Eq, Neq, Lt, Lte, Gt, Gte,
147    And, Or,
148}
149
150impl BinOp {
151    pub fn precedence(self) -> u8 {
152        use BinOp::*;
153        match self {
154            Or => 1,
155            And => 2,
156            Eq | Neq | Lt | Lte | Gt | Gte => 3,
157            Add | Sub => 4,
158            Mul | Div | Mod => 5,
159        }
160    }
161
162    pub fn as_str(self) -> &'static str {
163        use BinOp::*;
164        match self {
165            Add => "+", Sub => "-", Mul => "*", Div => "/", Mod => "%",
166            Eq => "==", Neq => "!=", Lt => "<", Lte => "<=", Gt => ">", Gte => ">=",
167            And => "and", Or => "or",
168        }
169    }
170}
171
172#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
173pub enum UnaryOp { Neg, Not }
174
175#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
176pub struct Arm {
177    pub pattern: Pattern,
178    pub body: Expr,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
182pub enum Pattern {
183    Lit(Literal),
184    /// Bare ident — either a binder or (during canonicalization) a tag-only constructor.
185    Var(String),
186    Wild,
187    Constructor { name: String, args: Vec<Pattern> },
188    Record { fields: Vec<RecordPatField>, rest: bool },
189    Tuple(Vec<Pattern>),
190}
191
192#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
193pub struct RecordPatField {
194    pub name: String,
195    /// `None` means shorthand `{ name }` => `{ name: name }`.
196    pub pattern: Option<Pattern>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
200pub enum Literal {
201    Int(i64),
202    Float(f64),
203    Str(String),
204    Bytes(Vec<u8>),
205    Bool(bool),
206    Unit,
207}