Skip to main content

nifty_syntax/
ast.rs

1//! The syntax tree. It records what was written; names and types are checked later.
2
3use crate::span::Span;
4use crate::token::TokenKind;
5
6#[derive(Clone, Debug, Default, PartialEq)]
7pub struct File {
8    pub items: Vec<Item>,
9}
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum Item {
13    State(StateDecl),
14    Struct(StructDecl),
15    Fn(FnDecl),
16    View(ViewDecl),
17    /// A top-level element with a name, such as `window settings(...)`.
18    Named(NamedElement),
19    /// A top-level statement, such as a `window(...)` element.
20    Stmt(Stmt),
21}
22
23/// A top-level element given a name, such as `window settings("Settings") { … }`, which
24/// code uses to refer to it. `call` is the element's call as it reads without the name.
25#[derive(Clone, Debug, PartialEq)]
26pub struct NamedElement {
27    pub name: Ident,
28    pub call: Stmt,
29}
30
31#[derive(Clone, Debug, PartialEq)]
32pub struct Ident {
33    pub name: String,
34    pub span: Span,
35}
36
37/// `name: Type`, as used by parameters and struct fields.
38#[derive(Clone, Debug, PartialEq)]
39pub struct TypedName {
40    pub name: Ident,
41    pub ty: TypeExpr,
42}
43
44#[derive(Clone, Debug, PartialEq)]
45pub struct StateDecl {
46    pub name: Ident,
47    pub ty: Option<TypeExpr>,
48    pub value: Expr,
49    pub span: Span,
50}
51
52#[derive(Clone, Debug, PartialEq)]
53pub struct StructDecl {
54    pub name: Ident,
55    pub fields: Vec<TypedName>,
56    pub span: Span,
57}
58
59#[derive(Clone, Debug, PartialEq)]
60pub struct FnDecl {
61    pub name: Ident,
62    pub params: Vec<TypedName>,
63    pub return_type: Option<TypeExpr>,
64    pub body: Block,
65    pub span: Span,
66}
67
68#[derive(Clone, Debug, PartialEq)]
69pub struct ViewDecl {
70    pub name: Ident,
71    pub params: Vec<TypedName>,
72    pub body: Block,
73    pub span: Span,
74}
75
76#[derive(Clone, Debug, PartialEq)]
77pub struct TypeExpr {
78    pub kind: TypeExprKind,
79    pub span: Span,
80}
81
82#[derive(Clone, Debug, PartialEq)]
83pub enum TypeExprKind {
84    Named(String),
85    List(Box<TypeExpr>),
86}
87
88#[derive(Clone, Debug, PartialEq)]
89pub struct Block {
90    pub stmts: Vec<Stmt>,
91    pub span: Span,
92}
93
94#[derive(Clone, Debug, PartialEq)]
95pub struct Stmt {
96    pub kind: StmtKind,
97    pub span: Span,
98}
99
100#[derive(Clone, Debug, PartialEq)]
101pub enum StmtKind {
102    Let {
103        name: Ident,
104        ty: Option<TypeExpr>,
105        value: Expr,
106    },
107    Assign {
108        target: Expr,
109        op: AssignOp,
110        value: Expr,
111    },
112    If(IfStmt),
113    /// `for item in list`, `for index, item in list` or `for i in start..end`.
114    For {
115        index: Option<Ident>,
116        item: Ident,
117        iterable: Iterable,
118        body: Block,
119    },
120    Return(Option<Expr>),
121    Expr(Expr),
122}
123
124/// What a `for` loops over.
125#[derive(Clone, Debug, PartialEq)]
126pub enum Iterable {
127    List(Expr),
128    /// `start..end`: each `int` from `start` up to, but not including, `end`.
129    Range {
130        start: Expr,
131        end: Expr,
132    },
133}
134
135#[derive(Clone, Debug, PartialEq)]
136pub struct IfStmt {
137    pub condition: Expr,
138    pub then_block: Block,
139    pub else_branch: Option<ElseBranch>,
140}
141
142#[derive(Clone, Debug, PartialEq)]
143pub enum ElseBranch {
144    If(Box<IfStmt>),
145    Block(Block),
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
149pub enum AssignOp {
150    Set,
151    Add,
152    Sub,
153    Mul,
154    Div,
155}
156
157#[derive(Clone, Debug, PartialEq)]
158pub struct Expr {
159    pub kind: ExprKind,
160    pub span: Span,
161}
162
163#[derive(Clone, Debug, PartialEq)]
164pub enum ExprKind {
165    Int(i64),
166    Float(f64),
167    Bool(bool),
168    String(Vec<StringPart>),
169    Name(String),
170    /// `.center`: a member of whatever type the context expects.
171    ImplicitMember(Ident),
172    List(Vec<Expr>),
173    Unary {
174        op: UnaryOp,
175        operand: Box<Expr>,
176    },
177    Binary {
178        op: BinaryOp,
179        lhs: Box<Expr>,
180        rhs: Box<Expr>,
181    },
182    Call {
183        callee: Box<Expr>,
184        args: Vec<Arg>,
185        trailing_block: Option<Block>,
186    },
187    Field {
188        base: Box<Expr>,
189        name: Ident,
190    },
191    Index {
192        base: Box<Expr>,
193        index: Box<Expr>,
194    },
195    /// Stands in for an expression that failed to parse, so parsing can continue.
196    Error,
197}
198
199#[derive(Clone, Debug, PartialEq)]
200pub enum StringPart {
201    Text(String),
202    Expr(Expr),
203}
204
205#[derive(Clone, Debug, PartialEq)]
206pub struct Arg {
207    pub label: Option<Ident>,
208    pub value: Expr,
209}
210
211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
212pub enum UnaryOp {
213    Not,
214    Neg,
215    /// `$place`: a two-way binding.
216    Bind,
217}
218
219#[derive(Clone, Copy, Debug, PartialEq, Eq)]
220pub enum BinaryOp {
221    Or,
222    And,
223    Eq,
224    NotEq,
225    Lt,
226    LtEq,
227    Gt,
228    GtEq,
229    Add,
230    Sub,
231    Mul,
232    Div,
233    Rem,
234}
235
236impl BinaryOp {
237    #[must_use]
238    pub fn is_comparison(self) -> bool {
239        matches!(
240            self,
241            Self::Eq | Self::NotEq | Self::Lt | Self::LtEq | Self::Gt | Self::GtEq
242        )
243    }
244
245    /// The operator token, which also gives its spelling.
246    #[must_use]
247    pub const fn token(self) -> TokenKind {
248        match self {
249            Self::Or => TokenKind::OrOr,
250            Self::And => TokenKind::AndAnd,
251            Self::Eq => TokenKind::EqEq,
252            Self::NotEq => TokenKind::BangEq,
253            Self::Lt => TokenKind::Lt,
254            Self::LtEq => TokenKind::LtEq,
255            Self::Gt => TokenKind::Gt,
256            Self::GtEq => TokenKind::GtEq,
257            Self::Add => TokenKind::Plus,
258            Self::Sub => TokenKind::Minus,
259            Self::Mul => TokenKind::Star,
260            Self::Div => TokenKind::Slash,
261            Self::Rem => TokenKind::Percent,
262        }
263    }
264}