Skip to main content

knave_expand/core/
expr.rs

1use std::rc::Rc;
2
3use super::{BindingId, Keyword, ReferenceKind, TypeExpr};
4use crate::reader::{Form, Number};
5use crate::source::Span;
6
7#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
8pub struct Expr {
9    kind: ExprKind,
10    span: Span,
11}
12
13#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
14pub enum ExprKind {
15    Leaf(Leaf),
16    Fn(Rc<Lambda>),
17    Call(Box<Expr>, Vec<Expr>),
18    Recur(Vec<Expr>),
19    Try(Box<Expr>),
20    Infer(Box<Expr>),
21    Borrow(ReferenceKind, Box<Expr>),
22    Deref(Box<Expr>),
23    Control(Control),
24    Struct(StructExpr),
25    Variant(BindingId, Vec<Expr>),
26    LabeledVariant(BindingId, Vec<(FieldLabel, Expr)>),
27    Assoc(Box<Expr>, Vec<Expr>, Box<Expr>),
28    MapAt(MapOperation, Box<Expr>, Vec<Expr>),
29    SetAt(Box<Expr>, Vec<Expr>, Box<Expr>),
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
33pub enum MapOperation {
34    Get,
35    Keys,
36    Vals,
37    Iter,
38    Update,
39    Push,
40}
41
42impl MapOperation {
43    const KEYWORDS: [(Self, &'static str); 6] = [
44        (Self::Get, "get"),
45        (Self::Keys, "keys"),
46        (Self::Vals, "vals"),
47        (Self::Iter, "iter"),
48        (Self::Update, "update"),
49        (Self::Push, "push"),
50    ];
51
52    pub fn of(name: &str) -> Option<Self> {
53        Self::KEYWORDS
54            .iter()
55            .find(|(_, keyword)| *keyword == name)
56            .map(|(operation, _)| *operation)
57    }
58
59    pub fn keyword(self) -> &'static str {
60        Self::KEYWORDS
61            .iter()
62            .find(|(operation, _)| *operation == self)
63            .map(|(_, keyword)| *keyword)
64            .expect("every map operation has a keyword")
65    }
66}
67
68#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
69pub enum Leaf {
70    Literal(Literal),
71    Var(BindingId),
72    Quote(Form),
73    Rust(Rc<RustTemplate>),
74}
75
76#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
77pub enum Control {
78    Block(Block),
79    If(Box<Expr>, Box<Expr>, Box<Expr>),
80    Match(Box<Expr>, Vec<Arm>),
81}
82
83#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
84pub struct Arm {
85    pub pattern: Pattern,
86    pub body: Block,
87    pub span: Span,
88}
89
90#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
91pub struct Pattern {
92    pub kind: PatternKind,
93    pub span: Span,
94}
95
96#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
97pub enum PatternKind {
98    Wildcard,
99    Bind(BindingId),
100    BareName {
101        name: Rc<str>,
102        binding: BindingId,
103        candidates: Vec<BindingId>,
104        outer: Option<BindingId>,
105    },
106    Variant(BindingId, PatternArguments),
107    Struct(BindingId, PatternArguments),
108    ShortVariant {
109        name: Rc<str>,
110        candidates: Vec<BindingId>,
111        arguments: PatternArguments,
112    },
113    Literal(Literal),
114}
115
116#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
117pub struct PatternArguments {
118    pub parts: Vec<PatternPart>,
119}
120
121#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
122pub enum PatternPart {
123    Positional(Pattern),
124    Labeled(FieldLabel, Option<Pattern>),
125}
126
127impl PatternArguments {
128    pub fn patterns(&self) -> impl Iterator<Item = &Pattern> {
129        self.parts.iter().filter_map(|part| match part {
130            PatternPart::Positional(pattern) => Some(pattern),
131            PatternPart::Labeled(_, pattern) => pattern.as_ref(),
132        })
133    }
134
135    pub fn positional(&self) -> impl Iterator<Item = &Pattern> {
136        self.parts.iter().filter_map(|part| match part {
137            PatternPart::Positional(pattern) => Some(pattern),
138            PatternPart::Labeled(..) => None,
139        })
140    }
141
142    pub fn labeled(&self) -> impl Iterator<Item = (&FieldLabel, Option<&Pattern>)> {
143        self.parts.iter().filter_map(|part| match part {
144            PatternPart::Positional(_) => None,
145            PatternPart::Labeled(label, pattern) => Some((label, pattern.as_ref())),
146        })
147    }
148}
149
150impl Pattern {
151    pub fn new(kind: PatternKind, span: Span) -> Self {
152        Self { kind, span }
153    }
154
155    pub fn arm_outer(&self) -> Option<(BindingId, BindingId)> {
156        match &self.kind {
157            PatternKind::BareName {
158                binding,
159                outer: Some(outer),
160                ..
161            } => Some((*binding, *outer)),
162            _ => None,
163        }
164    }
165
166    pub fn nested(&self) -> impl Iterator<Item = &Pattern> {
167        self.arguments()
168            .into_iter()
169            .flat_map(PatternArguments::patterns)
170    }
171
172    fn arguments(&self) -> Option<&PatternArguments> {
173        match &self.kind {
174            PatternKind::Variant(_, arguments)
175            | PatternKind::Struct(_, arguments)
176            | PatternKind::ShortVariant { arguments, .. } => Some(arguments),
177            _ => None,
178        }
179    }
180}
181
182#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
183pub enum StructExpr {
184    New(BindingId, Vec<(FieldLabel, Expr)>),
185    Update(Box<Expr>, Vec<(FieldLabel, Expr)>),
186    Field(Box<Expr>, FieldLabel),
187}
188
189#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
190pub enum Literal {
191    Number(Number),
192    String(Rc<str>),
193    Bool(bool),
194}
195
196#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
197pub struct FieldLabel {
198    pub name: Rc<str>,
199    pub span: Span,
200    pub spelling: FieldSpelling,
201}
202
203impl FieldLabel {
204    pub fn spelled(&self, field_name: &str) -> String {
205        match self.spelling {
206            FieldSpelling::Bare => field_name.to_string(),
207            FieldSpelling::Keyword => format!("{}{field_name}", Keyword::MARKER),
208        }
209    }
210}
211
212#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
213pub enum FieldSpelling {
214    Bare,
215    Keyword,
216}
217
218#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
219pub struct Binder {
220    pub binding: BindingId,
221    pub annotation: Option<TypeExpr>,
222    pub span: Span,
223}
224
225#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
226pub struct Lambda {
227    pub params: Vec<Binder>,
228    pub body: Block,
229}
230
231#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
232pub struct Block {
233    pub items: Vec<BodyItem>,
234}
235
236#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
237pub enum BodyItem {
238    Let(Binder, Expr),
239    Expr(Expr),
240}
241
242#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
243pub struct RustTemplate {
244    pub template: Rc<str>,
245    pub type_expr: TypeExpr,
246    pub clauses: Vec<RustClause>,
247}
248
249#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
250pub struct RustClause {
251    pub target: TypeExpr,
252    pub template: Rc<str>,
253}
254
255impl Expr {
256    pub fn new(kind: ExprKind, span: Span) -> Self {
257        Self { kind, span }
258    }
259
260    pub fn kind(&self) -> &ExprKind {
261        &self.kind
262    }
263
264    pub fn span(&self) -> Span {
265        self.span
266    }
267
268    pub fn children(&self) -> Vec<&Expr> {
269        match &self.kind {
270            ExprKind::Leaf(_) => Vec::new(),
271            ExprKind::Fn(lambda) => lambda.body.expressions().collect(),
272            ExprKind::Call(callee, arguments) => {
273                std::iter::once(callee.as_ref()).chain(arguments).collect()
274            }
275            ExprKind::Control(control) => control.children(),
276            other => other.nested_children(),
277        }
278    }
279}
280
281impl ExprKind {
282    fn nested_children(&self) -> Vec<&Expr> {
283        match self {
284            ExprKind::Recur(arguments) => arguments.iter().collect(),
285            ExprKind::Try(value)
286            | ExprKind::Infer(value)
287            | ExprKind::Borrow(_, value)
288            | ExprKind::Deref(value) => {
289                vec![value]
290            }
291            ExprKind::Struct(structure) => structure.children(),
292            ExprKind::Variant(_, arguments) => arguments.iter().collect(),
293            ExprKind::LabeledVariant(_, fields) => fields.iter().map(|(_, value)| value).collect(),
294            other => other.collection_children(),
295        }
296    }
297
298    fn collection_children(&self) -> Vec<&Expr> {
299        match self {
300            ExprKind::Assoc(value, keys, item) | ExprKind::SetAt(value, keys, item) => {
301                std::iter::once(value.as_ref())
302                    .chain(keys)
303                    .chain(std::iter::once(item.as_ref()))
304                    .collect()
305            }
306            ExprKind::MapAt(_, value, arguments) => {
307                std::iter::once(value.as_ref()).chain(arguments).collect()
308            }
309            _ => Vec::new(),
310        }
311    }
312}
313
314impl Control {
315    fn children(&self) -> Vec<&Expr> {
316        match self {
317            Control::Block(block) => block.expressions().collect(),
318            Control::If(test, then, otherwise) => vec![test, then, otherwise],
319            Control::Match(value, arms) => std::iter::once(value.as_ref())
320                .chain(arms.iter().flat_map(|arm| arm.body.expressions()))
321                .collect(),
322        }
323    }
324}
325
326impl StructExpr {
327    fn children(&self) -> Vec<&Expr> {
328        match self {
329            StructExpr::New(_, fields) => fields.iter().map(|(_, value)| value).collect(),
330            StructExpr::Update(base, fields) => std::iter::once(base.as_ref())
331                .chain(fields.iter().map(|(_, value)| value))
332                .collect(),
333            StructExpr::Field(value, _) => vec![value],
334        }
335    }
336}
337
338impl Block {
339    pub fn expressions(&self) -> impl Iterator<Item = &Expr> {
340        self.items.iter().map(BodyItem::expr)
341    }
342}
343
344impl BodyItem {
345    pub fn expr(&self) -> &Expr {
346        match self {
347            BodyItem::Let(_, value) | BodyItem::Expr(value) => value,
348        }
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::{
355        FieldLabel, FieldSpelling, MapOperation, Pattern, PatternArguments, PatternKind,
356        PatternPart,
357    };
358    use crate::core::{BindingArena, BindingId, BindingInfo, BindingKind};
359    use crate::source::{SourceId, Span};
360
361    struct PatternFixture {
362        bindings: BindingArena,
363    }
364
365    impl PatternFixture {
366        fn new() -> Self {
367            Self {
368                bindings: BindingArena::default(),
369            }
370        }
371
372        fn binding(&mut self) -> BindingId {
373            self.bindings
374                .add(BindingInfo::new("name".into(), BindingKind::Local, None))
375        }
376
377        fn pattern(kind: PatternKind) -> Pattern {
378            Pattern::new(kind, Span::new(SourceId::new(0), 0..0))
379        }
380
381        fn bare_name(&mut self, outer: Option<BindingId>) -> Pattern {
382            let binding = self.binding();
383            Self::pattern(PatternKind::BareName {
384                name: "name".into(),
385                binding,
386                candidates: Vec::new(),
387                outer,
388            })
389        }
390
391        fn held(&mut self) -> PatternArguments {
392            PatternArguments {
393                parts: vec![PatternPart::Positional(self.bare_name(None))],
394            }
395        }
396
397        fn label() -> FieldLabel {
398            FieldLabel {
399                name: "name".into(),
400                spelling: FieldSpelling::Keyword,
401                span: Span::new(SourceId::new(0), 0..0),
402            }
403        }
404    }
405
406    #[test]
407    fn a_bare_name_pairs_its_binding_with_its_outer_binding() {
408        let mut fixture = PatternFixture::new();
409        let outer = fixture.binding();
410        let pattern = fixture.bare_name(Some(outer));
411        let (_, found) = pattern.arm_outer().expect("the name has an outer binding");
412        assert_eq!(found, outer);
413    }
414
415    #[test]
416    fn a_bare_name_without_an_outer_binding_has_no_arm_outer() {
417        assert_eq!(PatternFixture::new().bare_name(None).arm_outer(), None);
418    }
419
420    #[test]
421    fn a_wildcard_has_no_arm_outer() {
422        let pattern = PatternFixture::pattern(PatternKind::Wildcard);
423        assert_eq!(pattern.arm_outer(), None);
424    }
425
426    #[test]
427    fn a_variant_pattern_holds_its_nested_patterns() {
428        let mut fixture = PatternFixture::new();
429        let variant = fixture.binding();
430        let held = fixture.held();
431        let pattern = PatternFixture::pattern(PatternKind::Variant(variant, held));
432        assert_eq!(pattern.nested().count(), 1);
433    }
434
435    #[test]
436    fn a_struct_pattern_holds_its_nested_patterns() {
437        let mut fixture = PatternFixture::new();
438        let shape = fixture.binding();
439        let held = fixture.held();
440        let pattern = PatternFixture::pattern(PatternKind::Struct(shape, held));
441        assert_eq!(pattern.nested().count(), 1);
442    }
443
444    #[test]
445    fn a_short_variant_pattern_holds_its_nested_patterns() {
446        let mut fixture = PatternFixture::new();
447        let arguments = fixture.held();
448        let pattern = PatternFixture::pattern(PatternKind::ShortVariant {
449            name: "name".into(),
450            candidates: Vec::new(),
451            arguments,
452        });
453        assert_eq!(pattern.nested().count(), 1);
454    }
455
456    #[test]
457    fn a_labeled_part_holds_its_pattern() {
458        let mut fixture = PatternFixture::new();
459        let shape = fixture.binding();
460        let inner = fixture.bare_name(None);
461        let label = PatternFixture::label();
462        let parts = vec![PatternPart::Labeled(label, Some(inner))];
463        let pattern =
464            PatternFixture::pattern(PatternKind::Struct(shape, PatternArguments { parts }));
465        assert_eq!(pattern.nested().count(), 1);
466    }
467
468    #[test]
469    fn a_label_without_a_pattern_holds_nothing() {
470        let parts = vec![PatternPart::Labeled(PatternFixture::label(), None)];
471        assert_eq!(PatternArguments { parts }.patterns().count(), 0);
472    }
473
474    #[test]
475    fn a_wildcard_holds_no_nested_patterns() {
476        let wildcard = PatternFixture::pattern(PatternKind::Wildcard);
477        assert_eq!(wildcard.nested().count(), 0);
478    }
479
480    #[test]
481    fn every_operation_name_round_trips() {
482        assert_eq!(MapOperation::of("iter"), Some(MapOperation::Iter));
483        assert_eq!(MapOperation::Iter.keyword(), "iter");
484        assert_eq!(MapOperation::of("unknown"), None);
485    }
486}