Skip to main content

lambda_ref_cat/
syntax.rs

1//! Abstract syntax and source-position newtypes.
2//!
3//! Extends the spike-1 grammar (variable, lambda, application, `let`, `fix`)
4//! with four stateful forms: cell allocation (`ref e`), dereference (`!e`),
5//! assignment (`r := v`), and sequencing (`e1 ; e2`).
6
7/// A byte offset into the source string.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Position(usize);
10
11impl Position {
12    /// The underlying byte offset.
13    #[must_use]
14    pub fn value(&self) -> usize {
15        self.0
16    }
17}
18
19impl From<usize> for Position {
20    fn from(value: usize) -> Self {
21        Self(value)
22    }
23}
24
25impl std::fmt::Display for Position {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        write!(f, "{}", self.0)
28    }
29}
30
31/// A variable identifier.
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct VarName(String);
34
35impl VarName {
36    /// View the name as a string slice.
37    #[must_use]
38    pub fn as_str(&self) -> &str {
39        &self.0
40    }
41}
42
43impl From<String> for VarName {
44    fn from(value: String) -> Self {
45        Self(value)
46    }
47}
48
49impl From<&str> for VarName {
50    fn from(value: &str) -> Self {
51        Self(value.to_owned())
52    }
53}
54
55impl std::fmt::Display for VarName {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        f.write_str(&self.0)
58    }
59}
60
61/// The abstract syntax tree.
62#[derive(Debug, Clone, PartialEq, Eq)]
63pub enum Expr {
64    /// Variable reference.
65    Var(VarName),
66    /// Lambda abstraction.
67    Lam {
68        /// Bound parameter name.
69        param: VarName,
70        /// Function body.
71        body: Box<Expr>,
72    },
73    /// Function application (left-associative at the surface).
74    App {
75        /// The function being applied.
76        func: Box<Expr>,
77        /// The argument.
78        arg: Box<Expr>,
79    },
80    /// Let-binding.
81    Let {
82        /// The bound name.
83        name: VarName,
84        /// The value being bound.
85        value: Box<Expr>,
86        /// The body in which the binding is in scope.
87        body: Box<Expr>,
88    },
89    /// Fixed-point binding: `fix name. body`.
90    Fix {
91        /// The name bound to the fixed point inside `body`.
92        name: VarName,
93        /// The expression being closed over its own name.
94        body: Box<Expr>,
95    },
96    /// Allocate a fresh cell initialised with the value of `inner`.
97    Ref {
98        /// The expression whose value will populate the new cell.
99        inner: Box<Expr>,
100    },
101    /// Dereference the cell pointed to by `inner`.
102    Deref {
103        /// The expression that must evaluate to a [`Value::Ref`].
104        ///
105        /// [`Value::Ref`]: crate::value::Value::Ref
106        inner: Box<Expr>,
107    },
108    /// Assign `value` into the cell pointed to by `target`.
109    Assign {
110        /// The expression that must evaluate to a [`Value::Ref`].
111        ///
112        /// [`Value::Ref`]: crate::value::Value::Ref
113        target: Box<Expr>,
114        /// The value to store.
115        value: Box<Expr>,
116    },
117    /// Sequence: evaluate `first` (discarding its value), then evaluate
118    /// `second` and return its value.
119    Seq {
120        /// The expression evaluated for effect only.
121        first: Box<Expr>,
122        /// The expression whose value is the result of the sequence.
123        second: Box<Expr>,
124    },
125}
126
127impl Expr {
128    /// Build a variable reference.
129    #[must_use]
130    pub fn var(name: impl Into<VarName>) -> Self {
131        Self::Var(name.into())
132    }
133
134    /// Build a lambda abstraction.
135    #[must_use]
136    pub fn lam(param: impl Into<VarName>, body: Self) -> Self {
137        Self::Lam {
138            param: param.into(),
139            body: Box::new(body),
140        }
141    }
142
143    /// Build an application node.
144    #[must_use]
145    pub fn app(func: Self, arg: Self) -> Self {
146        Self::App {
147            func: Box::new(func),
148            arg: Box::new(arg),
149        }
150    }
151
152    /// Build a let-binding.  Named `bind` because `let` is a keyword.
153    #[must_use]
154    pub fn bind(name: impl Into<VarName>, value: Self, body: Self) -> Self {
155        Self::Let {
156            name: name.into(),
157            value: Box::new(value),
158            body: Box::new(body),
159        }
160    }
161
162    /// Build a fixed-point binding.
163    #[must_use]
164    pub fn fix(name: impl Into<VarName>, body: Self) -> Self {
165        Self::Fix {
166            name: name.into(),
167            body: Box::new(body),
168        }
169    }
170
171    /// Build a `ref` allocation node.  Named `alloc` to avoid the `ref`
172    /// keyword.
173    #[must_use]
174    pub fn alloc(inner: Self) -> Self {
175        Self::Ref {
176            inner: Box::new(inner),
177        }
178    }
179
180    /// Build a dereference node.
181    #[must_use]
182    pub fn deref(inner: Self) -> Self {
183        Self::Deref {
184            inner: Box::new(inner),
185        }
186    }
187
188    /// Build an assignment node.
189    #[must_use]
190    pub fn assign(target: Self, value: Self) -> Self {
191        Self::Assign {
192            target: Box::new(target),
193            value: Box::new(value),
194        }
195    }
196
197    /// Build a sequence node.
198    #[must_use]
199    pub fn seq(first: Self, second: Self) -> Self {
200        Self::Seq {
201            first: Box::new(first),
202            second: Box::new(second),
203        }
204    }
205}
206
207impl std::fmt::Display for Expr {
208    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
209        match self {
210            Self::Var(name) => write!(f, "{name}"),
211            Self::Lam { param, body } => write!(f, "(\\{param}. {body})"),
212            Self::App { func, arg } => write!(f, "({func} {arg})"),
213            Self::Let { name, value, body } => {
214                write!(f, "(let {name} = {value} in {body})")
215            }
216            Self::Fix { name, body } => write!(f, "(fix {name}. {body})"),
217            Self::Ref { inner } => write!(f, "(ref {inner})"),
218            Self::Deref { inner } => write!(f, "(!{inner})"),
219            Self::Assign { target, value } => write!(f, "({target} := {value})"),
220            Self::Seq { first, second } => write!(f, "({first} ; {second})"),
221        }
222    }
223}