Skip to main content

ruprizzle_parser/
ast.rs

1//! The loose syntax tree, one step away from the grammar.
2//!
3//! This mirrors what was *written*, not what it *means*: no types are resolved,
4//! no names are mapped, no relation has two sides yet. Lowering turns it into the
5//! strict IR.
6//!
7//! The separation is not ceremony. Relation resolution needs the complete set of
8//! models, which does not exist part-way through a parse, so an IR built directly
9//! in the parse walk would be wrong for any schema that references a model before
10//! declaring it — which is most of them.
11
12use ruprizzle_core::span::Span;
13
14/// A parsed schema file.
15#[derive(Debug, Clone, Default, PartialEq)]
16pub struct Ast {
17    /// Declarations in source order.
18    pub decls: Vec<Decl>,
19}
20
21impl Ast {
22    /// The `datasource` blocks, in source order.
23    pub fn datasources(&self) -> impl Iterator<Item = &Block> {
24        self.decls.iter().filter_map(|d| match d {
25            Decl::Datasource(b) => Some(b),
26            _ => None,
27        })
28    }
29
30    /// The `generator` blocks, in source order.
31    pub fn generators(&self) -> impl Iterator<Item = &Block> {
32        self.decls.iter().filter_map(|d| match d {
33            Decl::Generator(b) => Some(b),
34            _ => None,
35        })
36    }
37
38    /// The `enum` declarations, in source order.
39    pub fn enums(&self) -> impl Iterator<Item = &EnumDecl> {
40        self.decls.iter().filter_map(|d| match d {
41            Decl::Enum(e) => Some(e),
42            _ => None,
43        })
44    }
45
46    /// The `model` declarations, in source order.
47    pub fn models(&self) -> impl Iterator<Item = &ModelDecl> {
48        self.decls.iter().filter_map(|d| match d {
49            Decl::Model(m) => Some(m),
50            _ => None,
51        })
52    }
53}
54
55/// One top-level declaration.
56#[derive(Debug, Clone, PartialEq)]
57pub enum Decl {
58    /// `datasource db { ... }`
59    Datasource(Block),
60    /// `generator client { ... }`
61    Generator(Block),
62    /// `enum Role { ... }`
63    Enum(EnumDecl),
64    /// `model User { ... }`
65    Model(ModelDecl),
66}
67
68/// A `datasource` or `generator` block.
69#[derive(Debug, Clone, PartialEq)]
70pub struct Block {
71    /// Block name as written, e.g. `db`.
72    pub name: String,
73    /// `key = value` entries, in source order.
74    pub entries: Vec<ConfigEntry>,
75    /// Source location of the whole block.
76    pub span: Span,
77}
78
79impl Block {
80    /// The entry with the given key, if present.
81    #[must_use]
82    pub fn get(&self, key: &str) -> Option<&ConfigEntry> {
83        self.entries.iter().find(|e| e.key == key)
84    }
85}
86
87/// One `key = value` line inside a block.
88#[derive(Debug, Clone, PartialEq)]
89pub struct ConfigEntry {
90    /// Left-hand side.
91    pub key: String,
92    /// Right-hand side.
93    pub value: Value,
94    /// Source location of the entry.
95    pub span: Span,
96}
97
98/// An `enum` declaration.
99#[derive(Debug, Clone, PartialEq)]
100pub struct EnumDecl {
101    /// Name as written.
102    pub name: String,
103    /// Source location of the name alone, for diagnostics that point at it.
104    pub name_span: Span,
105    /// Variants in source order.
106    pub variants: Vec<VariantDecl>,
107    /// Joined `///` lines.
108    pub docs: Option<String>,
109    /// Source location of the whole declaration.
110    pub span: Span,
111}
112
113/// One variant of an [`EnumDecl`].
114#[derive(Debug, Clone, PartialEq)]
115pub struct VariantDecl {
116    /// Name as written.
117    pub name: String,
118    /// `@map("...")`, if given.
119    pub map: Option<String>,
120    /// Joined `///` lines.
121    pub docs: Option<String>,
122    /// Source location of the variant.
123    pub span: Span,
124}
125
126/// A `model` declaration.
127#[derive(Debug, Clone, PartialEq)]
128pub struct ModelDecl {
129    /// Name as written.
130    pub name: String,
131    /// Source location of the name alone.
132    pub name_span: Span,
133    /// Fields in source order.
134    pub fields: Vec<FieldDecl>,
135    /// `@@`-attributes in source order.
136    pub block_attrs: Vec<Attr>,
137    /// Joined `///` lines.
138    pub docs: Option<String>,
139    /// Source location of the whole declaration.
140    pub span: Span,
141}
142
143/// A field within a [`ModelDecl`].
144#[derive(Debug, Clone, PartialEq)]
145pub struct FieldDecl {
146    /// Name as written.
147    pub name: String,
148    /// Source location of the name alone.
149    pub name_span: Span,
150    /// Type name as written, before resolution.
151    pub type_name: String,
152    /// Source location of the type.
153    pub type_span: Span,
154    /// Whether the type carried `[]` or `?`.
155    pub arity: Arity,
156    /// `@`-attributes in source order.
157    pub attrs: Vec<Attr>,
158    /// Joined `///` lines.
159    pub docs: Option<String>,
160    /// Source location of the whole field.
161    pub span: Span,
162}
163
164impl FieldDecl {
165    /// The first attribute whose path matches, if any.
166    #[must_use]
167    pub fn attr(&self, path: &str) -> Option<&Attr> {
168        self.attrs.iter().find(|a| a.path == path)
169    }
170
171    /// Whether an attribute with the given path is present.
172    #[must_use]
173    pub fn has_attr(&self, path: &str) -> bool {
174        self.attr(path).is_some()
175    }
176}
177
178/// How many values a field holds.
179#[derive(Debug, Clone, Copy, PartialEq, Eq)]
180pub enum Arity {
181    /// `T` — exactly one.
182    Required,
183    /// `T?` — zero or one.
184    Optional,
185    /// `T[]` — many.
186    List,
187}
188
189/// An `@attr` or `@@attr`, with its arguments.
190#[derive(Debug, Clone, PartialEq)]
191pub struct Attr {
192    /// Dotted path as written, e.g. `id`, `db.VarChar`, `relation`.
193    pub path: String,
194    /// Arguments, in source order.
195    pub args: Vec<Arg>,
196    /// Source location of the attribute.
197    pub span: Span,
198}
199
200impl Attr {
201    /// The named argument with this name, if given.
202    #[must_use]
203    pub fn named(&self, name: &str) -> Option<&Value> {
204        self.args.iter().find_map(|a| match a {
205            Arg::Named { name: n, value, .. } if n == name => Some(value),
206            _ => None,
207        })
208    }
209
210    /// Positional arguments, in source order.
211    pub fn positional(&self) -> impl Iterator<Item = &Value> {
212        self.args.iter().filter_map(|a| match a {
213            Arg::Positional(v) => Some(v),
214            Arg::Named { .. } => None,
215        })
216    }
217
218    /// The first positional argument, if any.
219    #[must_use]
220    pub fn first_positional(&self) -> Option<&Value> {
221        self.positional().next()
222    }
223}
224
225/// One argument of an [`Attr`].
226#[derive(Debug, Clone, PartialEq)]
227pub enum Arg {
228    /// `name: value`
229    Named {
230        /// Argument name.
231        name: String,
232        /// Argument value.
233        value: Value,
234        /// Source location of the whole argument.
235        span: Span,
236    },
237    /// A bare value.
238    Positional(Value),
239}
240
241/// A value written in an attribute argument or a config entry.
242#[derive(Debug, Clone, PartialEq)]
243pub enum Value {
244    /// `"text"`
245    Str(String, Span),
246    /// A number, kept as written so integer and float stay distinguishable.
247    Num(String, Span),
248    /// `true` / `false`
249    Bool(bool, Span),
250    /// A bare identifier, e.g. `USER` or `Cascade`.
251    Ident(String, Span),
252    /// `env("DATABASE_URL")`
253    Env(String, Span),
254    /// `uuid7()`, `dbgenerated("...")`
255    Func {
256        /// Function name.
257        name: String,
258        /// Arguments, in source order.
259        args: Vec<Value>,
260        /// Source location of the call.
261        span: Span,
262    },
263    /// `[a, b]`
264    Array(Vec<Value>, Span),
265}
266
267impl Value {
268    /// Source location of the value.
269    #[must_use]
270    pub fn span(&self) -> Span {
271        match self {
272            Value::Str(_, s)
273            | Value::Num(_, s)
274            | Value::Bool(_, s)
275            | Value::Ident(_, s)
276            | Value::Env(_, s)
277            | Value::Func { span: s, .. }
278            | Value::Array(_, s) => *s,
279        }
280    }
281
282    /// The string, if this is a string literal.
283    #[must_use]
284    pub fn as_str(&self) -> Option<&str> {
285        match self {
286            Value::Str(s, _) => Some(s),
287            _ => None,
288        }
289    }
290
291    /// The identifier, if this is a bare identifier.
292    #[must_use]
293    pub fn as_ident(&self) -> Option<&str> {
294        match self {
295            Value::Ident(s, _) => Some(s),
296            _ => None,
297        }
298    }
299
300    /// The elements, if this is an array.
301    #[must_use]
302    pub fn as_array(&self) -> Option<&[Value]> {
303        match self {
304            Value::Array(v, _) => Some(v),
305            _ => None,
306        }
307    }
308
309    /// How this value reads in a diagnostic.
310    #[must_use]
311    pub fn describe(&self) -> String {
312        match self {
313            Value::Str(s, _) => format!("\"{s}\""),
314            Value::Num(n, _) => n.clone(),
315            Value::Bool(b, _) => b.to_string(),
316            Value::Ident(i, _) => i.clone(),
317            Value::Env(v, _) => format!("env(\"{v}\")"),
318            Value::Func { name, .. } => format!("{name}(…)"),
319            Value::Array(..) => "[…]".to_owned(),
320        }
321    }
322}