Skip to main content

brooks_lib/mel/interpreter/
values.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18//! MEL values used by the interpreter
19
20use std::{
21    collections::HashMap,
22    fmt::{Debug, Display},
23    io,
24    net::IpAddr,
25    sync::Arc,
26};
27
28use regex::Regex;
29
30use crate::{
31    environment::scope::Scope,
32    mel::{
33        interpreter::{error::InterpError, interpret::BuiltinFunction},
34        types::{
35            mel_empty_var_type, mel_header_type_from_processable_rr, mel_header_type_from_req,
36            mel_req_type, mel_uri_type,
37        },
38    },
39    prr,
40};
41
42use crate::mel::{
43    analysis::CompiledConstant,
44    types::{Struct, Type},
45};
46
47#[derive(Debug, Clone)]
48pub struct StructValue {
49    pub fields: HashMap<String, TypedValue>,
50    pub tpe: Struct,
51}
52
53impl StructValue {
54    pub fn new(tpe: Struct) -> StructValue {
55        StructValue {
56            fields: HashMap::new(),
57            tpe,
58        }
59    }
60
61    pub fn insert_field(&mut self, name: &str, value: TypedValue) -> Result<(), Box<InterpError>> {
62        let ft = self
63            .tpe
64            .get_field(name)
65            .ok_or(InterpError::UnknownField(name.to_string()))?;
66
67        if ft != value.tpe {
68            return Err(InterpError::MistypedField(name.to_string(), ft.clone(), value.tpe).into());
69        }
70
71        self.fields.insert(name.to_string(), value);
72        Ok(())
73    }
74}
75
76impl Display for StructValue {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        let mut field_values = self
79            .fields
80            .iter()
81            .map(|(k, v)| format!("{k}: {v}"))
82            .collect::<Vec<_>>();
83        field_values.sort();
84        let field_values = field_values.join(", ");
85        write!(
86            f,
87            "Type: {}, Field Values: {}",
88            self.tpe.name,
89            if !field_values.is_empty() {
90                field_values
91            } else {
92                "None".to_string()
93            }
94        )
95    }
96}
97
98#[derive(Default, Debug, Clone)]
99pub enum Value {
100    Integer(i64),
101    Unsigned(u64),
102    Real(f64),
103    String(String),
104    Boolean(bool),
105    Regex(Regex),
106    IPAddress(IpAddr),
107    Function(Arc<dyn BuiltinFunction>),
108    Struct(StructValue),
109    ArgumentList(Vec<TypedValue>),
110    Nil,
111    #[default]
112    Uninitialized,
113}
114
115#[derive(Default, Debug, Clone)]
116pub struct TypedValue {
117    pub value: Value,
118    pub tpe: Type,
119}
120
121impl Display for TypedValue {
122    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123        match &self.value {
124            Value::Nil => write!(f, "nil"),
125            Value::Integer(i) => write!(f, "{i}"),
126            Value::Unsigned(u) => write!(f, "{u}"),
127            Value::Real(i) => write!(f, "{i}"),
128            Value::String(s) => write!(f, "{s}"),
129            Value::Boolean(b) => write!(f, "{b}"),
130            Value::Regex(regex) => write!(f, "{regex}"),
131            Value::IPAddress(ip_addr) => write!(f, "{ip_addr}"),
132            Value::Function(bft) => write!(f, "Function: {}", bft.name()),
133            Value::Struct(struct_value) => write!(f, "{}", struct_value),
134            Value::ArgumentList(typed_values) => write!(
135                f,
136                "Argument List: {}",
137                typed_values
138                    .iter()
139                    .map(|tv| { tv.to_string() })
140                    .collect::<Vec<_>>()
141                    .join(",")
142            ),
143            Value::Uninitialized => write!(f, "Uninitialized"),
144        }
145    }
146}
147
148impl From<&CompiledConstant> for TypedValue {
149    fn from(value: &CompiledConstant) -> Self {
150        match value {
151            CompiledConstant::Integer(i) => TypedValue {
152                value: Value::Integer(*i),
153                tpe: Type::Integer,
154            },
155            CompiledConstant::String(s) => TypedValue {
156                value: Value::String(s.clone()),
157                tpe: Type::String,
158            },
159            CompiledConstant::Boolean(b) => TypedValue {
160                value: Value::Boolean(*b),
161                tpe: Type::Boolean,
162            },
163            CompiledConstant::IPAddress(ip) => TypedValue {
164                value: Value::IPAddress(*ip),
165                tpe: Type::IPAddress,
166            },
167        }
168    }
169}
170
171impl TryFrom<http::Request<Vec<u8>>> for Scope<TypedValue> {
172    type Error = io::Error;
173    fn try_from(value: http::Request<Vec<u8>>) -> Result<Self, Self::Error> {
174        let ht = mel_header_type_from_req(&value);
175        let urit = mel_uri_type();
176        let reqt = mel_req_type(ht.clone(), urit.clone());
177
178        // Set up the built-in variables for interpreting.
179        let mut value_scope = Scope::<TypedValue>::default();
180
181        let mut reqv = StructValue::new(reqt.clone());
182
183        let mut hv = StructValue::new(ht.clone());
184
185        value.headers().iter().for_each(|header| {
186            if let Ok(x) = header.1.to_str() {
187                hv.insert_field(
188                    &header.0.to_string().replace("-", "_").to_lowercase(),
189                    TypedValue {
190                        value: Value::String(x.to_string()),
191                        tpe: Type::String,
192                    },
193                )
194                .expect("header field value is mistyped");
195            }
196        });
197
198        let mut uriv = StructValue::new(urit.clone());
199
200        uriv.insert_field(
201            "path",
202            TypedValue {
203                value: Value::String(value.uri().path().to_string()),
204                tpe: Type::String,
205            },
206        )
207        .expect("path field value is mistyped.");
208
209        uriv.insert_field(
210            "query",
211            TypedValue {
212                value: Value::String(value.uri().query().unwrap_or_default().to_string()),
213                tpe: Type::String,
214            },
215        )
216        .expect("query field value is mistyped.");
217
218        reqv.insert_field(
219            "h",
220            TypedValue {
221                value: Value::Struct(hv),
222                tpe: Type::Struct(ht.clone()),
223            },
224        )
225        .expect("h field value is mistyped.");
226
227        reqv.insert_field(
228            "uri",
229            TypedValue {
230                value: Value::Struct(uriv),
231                tpe: Type::Struct(urit.clone()),
232            },
233        )
234        .expect("uri field value is mistyped.");
235
236        reqv.insert_field(
237            "method",
238            TypedValue {
239                value: Value::String(value.method().to_string()),
240                tpe: Type::String,
241            },
242        )
243        .expect("method field value is mistyped.");
244
245        reqv.insert_field(
246            "scheme",
247            TypedValue {
248                value: Value::String(value.uri().scheme().expect("Missing scheme").to_string()),
249                tpe: Type::String,
250            },
251        )
252        .expect("Header field value is mistyped.");
253
254        value_scope = value_scope.insert(
255            "req",
256            TypedValue {
257                value: Value::Struct(reqv),
258                tpe: Type::Struct(reqt),
259            },
260        );
261
262        Ok(value_scope)
263    }
264}
265
266/// Create a scope that contains the values of the MEL core variables present in an HTTP request.
267impl<A> From<&dyn prr::Prr<A>> for Scope<TypedValue> {
268    fn from(value: &dyn prr::Prr<A>) -> Self {
269        let ht = mel_header_type_from_processable_rr(value);
270        let urit = mel_uri_type();
271        let reqt = mel_req_type(ht.clone(), urit.clone());
272
273        // Set up the built-in variables for interpreting.
274        let mut value_scope = Scope::<TypedValue>::default();
275
276        let mut reqv = StructValue::new(reqt.clone());
277
278        let mut hv = StructValue::new(ht.clone());
279
280        value.headers().iter().for_each(|header| {
281            if let Ok(x) = header.1.to_str() {
282                hv.insert_field(
283                    &header.0.to_string().replace("-", "_").to_lowercase(),
284                    TypedValue {
285                        value: Value::String(x.to_string()),
286                        tpe: Type::String,
287                    },
288                )
289                .expect("header field value is mistyped");
290            }
291        });
292
293        let mut uriv = StructValue::new(urit.clone());
294
295        uriv.insert_field(
296            "path",
297            TypedValue {
298                value: Value::String(value.url().expect("Missing URI").path().to_string()),
299                tpe: Type::String,
300            },
301        )
302        .expect("path field value is mistyped.");
303
304        uriv.insert_field(
305            "query",
306            TypedValue {
307                value: Value::String(
308                    value
309                        .url()
310                        .expect("Missing URI")
311                        .query()
312                        .unwrap_or_default()
313                        .to_string(),
314                ),
315                tpe: Type::String,
316            },
317        )
318        .expect("query field value is mistyped.");
319
320        reqv.insert_field(
321            "h",
322            TypedValue {
323                value: Value::Struct(hv),
324                tpe: Type::Struct(ht.clone()),
325            },
326        )
327        .expect("h field value is mistyped.");
328
329        reqv.insert_field(
330            "uri",
331            TypedValue {
332                value: Value::Struct(uriv),
333                tpe: Type::Struct(urit.clone()),
334            },
335        )
336        .expect("uri field value is mistyped.");
337
338        reqv.insert_field(
339            "method",
340            TypedValue {
341                //value: Value::String(value.method().to_string()),
342                value: Value::String(http::method::Method::GET.to_string()),
343                tpe: Type::String,
344            },
345        )
346        .expect("method field value is mistyped.");
347
348        reqv.insert_field(
349            "scheme",
350            TypedValue {
351                value: Value::String(value.url().expect("Missing URI").scheme().to_string()),
352                tpe: Type::String,
353            },
354        )
355        .expect("Header field value is mistyped.");
356
357        value_scope = value_scope.insert(
358            "req",
359            TypedValue {
360                value: Value::Struct(reqv),
361                tpe: Type::Struct(reqt),
362            },
363        );
364
365        value_scope
366    }
367}
368
369pub fn mel_empty_var_value() -> TypedValue {
370    let vart = mel_empty_var_type();
371
372    TypedValue {
373        value: Value::Struct(StructValue {
374            fields: Default::default(),
375            tpe: vart.clone(),
376        }),
377        tpe: Type::Struct(vart),
378    }
379}
380
381pub fn mel_var_value_from_type(tpe: Struct) -> TypedValue {
382    TypedValue {
383        value: Value::Struct(StructValue {
384            fields: Default::default(),
385            tpe: tpe.clone(),
386        }),
387        tpe: Type::Struct(tpe),
388    }
389}