1#![expect(unused, reason = "Work in progress")]
8
9use super::*;
10use crate::{
11 function::Function,
12 place::Place,
13 typeinfo::{Model, TypeInfo},
14};
15use cl_ast::{
16 types::{Literal, Path},
17 *,
18};
19use cl_structures::intern::interned::Interned;
20use std::{collections::HashMap, iter, rc::Rc, slice};
21
22macro trace($($t:tt)*) {{
23 #[cfg(debug_assertions)]
24 if std::env::var("CONLANG_TRACE").is_ok() {
25 eprintln!($($t)*)
26 }
27}}
28
29pub macro cl_todo {
31 () => {
32 Err(Error::Panic(format!("Not yet implemented (at {}:{}:{})", file!(), line!(), column!())))
33 },
34 ($($t:tt)*) => {
35 Err(Error::Panic(format!("Not yet implemented: {} (at {}:{}:{})", format_args!($($t)*), file!(), line!(), column!())))
36 }
37}
38
39pub macro cl_unimplemented {
41 () => {
42 Err(Error::Panic(format!("Not implemented (at {}:{}:{})", file!(), line!(), column!())))
43 },
44 ($($t:tt)*) => {
45 Err(Error::Panic(format!("Not implemented: {} (at {}:{}:{})", format_args!($($t)*), file!(), line!(), column!())))
46 }
47}
48
49pub use self::{cl_todo as todo, cl_unimplemented as unimplemented};
50
51pub trait Interpret {
53 fn interpret(&self, env: &mut Environment) -> IResult<ConValue>;
57}
58
59impl<T: Annotation + Interpret> Interpret for At<T> {
60 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
61 self.0.interpret(env).map_err(|e| e.with_span(self.1))
62 }
63}
64
65impl Interpret for Expr<DefaultTypes> {
66 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
67 match self {
68 Self::Omitted => Ok(ConValue::Empty),
69 Self::Id(path) => match path.parts.as_slice() {
70 &[name] => env.get(name),
71 [first, names @ ..] => {
72 let mut value = env.get(*first)?;
73 for name in names {
74 value = match value {
75 ConValue::Module(values) => {
76 values.get(name).cloned().ok_or(Error::NotDefined(*name))?
77 }
78 ConValue::TypeInfo(ty) => ty.getattr(*name)?,
79 _ => todo!("{self}")?,
80 };
81 }
82 Ok(value)
83 }
84 [] => unimplemented!("Empty paths"),
85 _ => todo!("Extract value at {path}"),
86 },
87 Self::MetId(_) => cl_todo!("Meta-identifiers are not allowed here"),
88 Self::Lit(Literal::Bool(v)) => Ok(ConValue::Bool(*v)),
89 Self::Lit(Literal::Char(v)) => Ok(ConValue::Char(*v)),
90 Self::Lit(Literal::Int(v, _)) => Ok(ConValue::Int(*v as _)),
91 Self::Lit(Literal::Str(v)) => Ok(ConValue::Str(v.as_str().into())),
92 Self::Use(_) => cl_todo!("Use `{self}`"),
93 Self::Bind(bind) => bind.interpret(env),
94 Self::Make(make) => make.interpret(env),
95 Self::Match(mtch) => mtch.interpret(env),
96 Self::Op(op, exprs) => {
97 if self.is_place()
98 && let Ok(place) = Place::new(self, env)
99 {
100 place.get_mut(env).cloned()
101 } else {
102 (*op, exprs.as_slice()).interpret(env)
103 }
104 }
105 }
106 }
107}
108
109impl Interpret for (Op, &[At<Expr>]) {
110 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
111 match self {
112 (Op::Do, []) => Ok(ConValue::Empty),
113 (Op::Do, [ats @ .., ret]) => {
114 for at in ats {
115 at.0.interpret(env)?;
116 }
117 ret.0.interpret(env)
118 }
119 (Op::As, [value, ty]) => match ty.interpret(env)? {
120 ConValue::TypeInfo(ty) => value.interpret(env).map(|v| v.cast(&ty)),
121 other => Err(Error::TypeError("type", other.typename())),
122 },
123 (Op::As, [value, ty]) => cl_todo!("{value} as {ty} operator"),
124 (Op::Block, []) => Ok(ConValue::Empty),
125 (Op::Block, [expr]) => expr.interpret(&mut env.frame("block", None)),
126 (Op::Array, []) => Ok(ConValue::Array(Box::new([]))),
127 (Op::Array, exprs) => Ok(ConValue::Array(
128 exprs
129 .iter()
130 .map(|e| e.interpret(env))
131 .collect::<Result<Box<_>, _>>()?,
132 )),
133 (Op::ArRep, [v, rep]) => {
134 let v = v.interpret(env)?;
135 match rep.interpret(env)? {
136 ConValue::Int(rep) => {
137 Ok(ConValue::Array(vec![v; rep as usize].into_boxed_slice()))
138 }
139 rep => Err(Error::TypeError("int", rep.typename())),
140 }
141 }
142 (Op::Group, [expr]) => expr.interpret(env),
143 (Op::Tuple, []) => Ok(ConValue::Empty),
144 (Op::Tuple, exprs) => Ok(ConValue::Tuple(
145 exprs
146 .iter()
147 .map(|e| e.interpret(env))
148 .collect::<Result<Box<_>, _>>()?,
149 )),
150 (Op::MetaInner, [_, expr]) => expr.interpret(env),
151 (Op::MetaOuter, [_, expr]) => expr.interpret(env),
152 (Op::Try, [expr]) => expr.interpret(env),
153 (Op::Index, [expr, idx]) => expr.interpret(env)?.index(&idx.interpret(env)?, env),
154 (Op::Call, [expr, arg]) => {
155 let callee = expr.interpret(env)?;
156 match arg.interpret(env)? {
157 ConValue::Empty => callee.call(env, &[]),
158 ConValue::Tuple(args) => callee.call(env, &args),
159 arg => callee.call(env, slice::from_ref(&arg)),
160 }
161 }
162
163 (Op::Pub, [expr]) => expr.interpret(env),
165 (Op::Const, [expr]) => expr.interpret(env), (Op::Static, [expr]) => expr.interpret(env), (Op::Macro, _) => cl_todo!("Macros are not supported in the interpreter"),
170 (Op::Loop, [expr]) => loop {
171 match expr.interpret(env) {
172 Ok(_) => {}
173 Err(Error { kind: ErrorKind::Break(v), .. }) => break Ok(v),
174 Err(Error { kind: ErrorKind::Continue, .. }) => continue,
175 Err(e) => Err(e)?,
176 }
177 },
178 (Op::If, [cond, pass, fail]) => {
179 let mut scope = env.frame("if", None);
180 if cond.interpret(&mut scope)?.truthy()? {
181 return pass.interpret(&mut scope);
182 }
183 drop(scope);
184 fail.interpret(env)
185 }
186 (Op::While, [cond, pass, fail]) => {
187 loop {
188 let mut scope = env.frame("while", None);
189 if cond.interpret(&mut scope)?.truthy()? {
190 match pass.interpret(&mut scope) {
191 Ok(_) => {}
192 Err(Error { kind: ErrorKind::Break(value), .. }) => return Ok(value),
193 Err(Error { kind: ErrorKind::Continue, .. }) => continue,
194 Err(e) => Err(e)?,
195 }
196 } else {
197 break;
198 }
199 }
200 fail.interpret(env)
201 }
202 (Op::Break, [expr]) => Err(Error::Break(expr.interpret(env)?)),
203 (Op::Return, [expr]) => Err(Error::Return(expr.interpret(env)?)),
204 (Op::Continue, []) => Err(Error::Continue()),
205
206 (Op::Dot, [scrutinee, At(Expr::Op(Op::Call, args), _)]) => {
208 let [callee, args] = args.as_slice() else {
209 cl_todo!("Interpret non-call {args:?}")?
210 };
211 let scrutinee = Place::new_or_temporary(scrutinee.value(), env)?;
212 let function = callee.interpret(env)?;
213 let args = args.interpret(env)?;
214 match args {
215 ConValue::Empty => function.call(env, &[ConValue::Ref(scrutinee)]),
216 ConValue::Tuple(args) => function.call(
217 env,
218 &iter::once(ConValue::Ref(scrutinee))
219 .chain(args) .collect::<Box<_>>(),
221 ),
222 other => function.call(env, &[ConValue::Ref(scrutinee), other]),
223 }
224 }
225 (
226 Op::Dot,
227 [
228 At(Expr::Lit(Literal::Int(whole, _)), _),
229 At(Expr::Lit(Literal::Int(frac, _)), _),
230 ],
231 ) => Ok(ConValue::Float(format!("{whole}.{frac}").parse().unwrap())),
232 (Op::Dot, [scrutinee, At(Expr::Lit(Literal::Int(idx, _)), _)]) => {
233 let place = Place::new_or_temporary(scrutinee.value(), env)?;
234 Ok(ConValue::Ref(place.dot_idx(*idx as _)))
235 }
236 (Op::Dot, [scrutinee, proj]) => cl_todo!("dot: {scrutinee}.{proj}"),
237
238 (Op::RangeEx, [lhs, rhs]) => Ok(ConValue::TupleStruct(
240 env.get_type("RangeExc".into())
241 .ok_or_else(|| Error::NotDefined("RangeExc".into()))?,
242 Box::new([lhs.interpret(env)?, rhs.interpret(env)?]),
243 )),
244 (Op::RangeIn, [lhs, rhs]) => Ok(ConValue::TupleStruct(
245 env.get_type("RangeInc".into())
246 .ok_or_else(|| Error::NotDefined("RangeInc".into()))?,
247 Box::new([lhs.interpret(env)?, rhs.interpret(env)?]),
248 )),
249 (Op::RangeEx, [rhs]) => Ok(ConValue::TupleStruct(
250 env.get_type("RangeTo".into())
251 .ok_or_else(|| Error::NotDefined("RangeTo".into()))?,
252 Box::new([rhs.interpret(env)?]),
253 )),
254 (Op::RangeIn, [rhs]) => Ok(ConValue::TupleStruct(
255 env.get_type("RangeToInc".into())
256 .ok_or_else(|| Error::NotDefined("RangeToInc".into()))?,
257 Box::new([rhs.interpret(env)?]),
258 )),
259
260 (Op::Neg, [expr]) => {
262 let value = expr.interpret(env)?;
263 env.get("neg".into())?.call(env, &[value])
264 }
265 (Op::Not, [expr]) => {
266 let value = expr.interpret(env)?;
267 env.get("not".into())?.call(env, &[value]) }
269 (Op::Identity, [expr]) => expr.interpret(env),
270
271 (Op::Refer, [expr]) => Ok(ConValue::Ref(
273 Place::new(expr.value(), env).map_err(|e| Error::Panic("asfd".into()))?,
274 )),
275 (Op::Deref, [expr]) => match expr.interpret(env)? {
276 ConValue::Ref(place) => place.get(env).cloned(),
277 other => Ok(other),
278 },
279 (Op::Deref, [expr]) => cl_todo!("References: *{expr}"),
280
281 (Op::Mul, [lhs, rhs]) => lhs.interpret(env)? * rhs.interpret(env)?,
283 (Op::Div, [lhs, rhs]) => lhs.interpret(env)? / rhs.interpret(env)?,
284 (Op::Rem, [lhs, rhs]) => lhs.interpret(env)? % rhs.interpret(env)?,
285 (Op::Add, [lhs, rhs]) => lhs.interpret(env)? + rhs.interpret(env)?,
286 (Op::Sub, [lhs, rhs]) => lhs.interpret(env)? - rhs.interpret(env)?,
287 (Op::Shl, [lhs, rhs]) => lhs.interpret(env)? << rhs.interpret(env)?,
288 (Op::Shr, [lhs, rhs]) => lhs.interpret(env)? >> rhs.interpret(env)?,
289 (Op::And, [lhs, rhs]) => lhs.interpret(env)? & rhs.interpret(env)?,
290 (Op::Xor, [lhs, rhs]) => lhs.interpret(env)? ^ rhs.interpret(env)?,
291 (Op::Or, [lhs, rhs]) => lhs.interpret(env)? | rhs.interpret(env)?,
292
293 (Op::Lt, [lhs, rhs]) => lhs.interpret(env)?.lt(&rhs.interpret(env)?),
295 (Op::Leq, [lhs, rhs]) => lhs.interpret(env)?.lt_eq(&rhs.interpret(env)?),
296 (Op::Eq, [lhs, rhs]) => lhs.interpret(env)?.eq(&rhs.interpret(env)?),
297 (Op::Neq, [lhs, rhs]) => lhs.interpret(env)?.neq(&rhs.interpret(env)?),
298 (Op::Geq, [lhs, rhs]) => lhs.interpret(env)?.gt_eq(&rhs.interpret(env)?),
299 (Op::Gt, [lhs, rhs]) => lhs.interpret(env)?.gt(&rhs.interpret(env)?),
300
301 (Op::LogAnd, [lhs, rhs]) => {
303 let lhs = lhs.interpret(env)?;
304 if lhs.truthy()? {
305 rhs.interpret(env)
306 } else {
307 Ok(lhs)
308 }
309 }
310 (Op::LogXor, [lhs, rhs]) => todo!(),
311 (Op::LogOr, [lhs, rhs]) => {
312 let lhs = lhs.interpret(env)?;
313 if lhs.truthy()? {
314 Ok(lhs)
315 } else {
316 rhs.interpret(env)
317 }
318 }
319
320 (Op::Set, [target, value]) => {
322 let place = Place::new(target.value(), env)?;
323 let value = value.interpret(env)?;
324 *(place.get_mut(env)?) = value;
325 Ok(ConValue::Empty)
326 }
327 (Op::MulSet, [target, value]) => {
328 let place = Place::new(target.value(), env)?;
329 let value = value.interpret(env)?;
330 place.get_mut(env)?.mul_assign(value)?;
331 Ok(ConValue::Empty)
332 }
333 (Op::DivSet, [target, value]) => {
334 let place = Place::new(target.value(), env)?;
335 let value = value.interpret(env)?;
336 place.get_mut(env)?.div_assign(value)?;
337 Ok(ConValue::Empty)
338 }
339 (Op::RemSet, [target, value]) => {
340 let place = Place::new(target.value(), env)?;
341 let value = value.interpret(env)?;
342 place.get_mut(env)?.rem_assign(value)?;
343 Ok(ConValue::Empty)
344 }
345 (Op::AddSet, [target, value]) => {
346 let place = Place::new(target.value(), env)?;
347 let value = value.interpret(env)?;
348 place.get_mut(env)?.add_assign(value)?;
349 Ok(ConValue::Empty)
350 }
351 (Op::SubSet, [target, value]) => {
352 let place = Place::new(target.value(), env)?;
353 let value = value.interpret(env)?;
354 place.get_mut(env)?.sub_assign(value)?;
355 Ok(ConValue::Empty)
356 }
357 (Op::ShlSet, [target, value]) => {
358 let place = Place::new(target.value(), env)?;
359 let value = value.interpret(env)?;
360 place.get_mut(env)?.shl_assign(value)?;
361 Ok(ConValue::Empty)
362 }
363 (Op::ShrSet, [target, value]) => {
364 let place = Place::new(target.value(), env)?;
365 let value = value.interpret(env)?;
366 place.get_mut(env)?.shr_assign(value)?;
367 Ok(ConValue::Empty)
368 }
369 (Op::AndSet, [target, value]) => {
370 let place = Place::new(target.value(), env)?;
371 let value = value.interpret(env)?;
372 place.get_mut(env)?.bitand_assign(value)?;
373 Ok(ConValue::Empty)
374 }
375 (Op::XorSet, [target, value]) => {
376 let place = Place::new(target.value(), env)?;
377 let value = value.interpret(env)?;
378 place.get_mut(env)?.bitxor_assign(value)?;
379 Ok(ConValue::Empty)
380 }
381 (Op::OrSet, [target, value]) => {
382 let place = Place::new(target.value(), env)?;
383 let mut value = value.interpret(env)?;
384 place.get_mut(env)?.bitor_assign(value)?;
385 Ok(ConValue::Empty)
386 }
387 (op, exprs) => cl_unimplemented!("Evaluate {op:?} {exprs:#?}"),
388 }
389 }
390}
391
392impl Interpret for Bind<DefaultTypes> {
393 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
394 let Bind(op, _generics, pat, exprs) = self;
395 match (op, pat, exprs.as_slice()) {
396 (BindOp::Let, _, []) => cl_todo!("let {pat}"),
397 (BindOp::Let, _, [scrutinee]) => {
398 let mut bind = HashMap::new();
399 let out = pat.matches(
400 scrutinee.interpret(env)?,
401 &mut MatchEnv::new(env, &mut bind),
402 );
403
404 Ok(ConValue::Bool(match out {
405 Ok(_) => {
406 for (name, value) in bind {
407 env.bind(name, value);
408 }
409 true
410 }
411 Err(e) => false,
412 }))
413 }
414 (BindOp::Let, _, [scrutinee, default]) => {
415 let mut bind = HashMap::new();
416 let out = pat.matches(
417 scrutinee.interpret(env)?,
418 &mut MatchEnv::new(env, &mut bind),
419 );
420
421 if out.is_ok() {
422 for (name, value) in bind {
423 env.bind(name, value);
424 }
425 return Ok(ConValue::Empty);
426 }
427
428 bind.clear();
429 pat.matches(default.interpret(env)?, &mut MatchEnv::new(env, &mut bind))?;
430 for (name, value) in bind {
431 env.bind(name, value);
432 }
433
434 Ok(ConValue::Empty)
435 }
436 (BindOp::Type, _, []) => cl_todo!("type {pat}"),
437 (BindOp::Type, _, [body]) => cl_todo!("type {pat} = {body}"),
438 (BindOp::Fn, _, [body]) => {
439 let func = Rc::new(Function::new(self));
440 if let Some(name) = func.name() {
441 env.bind(name, ConValue::Function(func.clone()))
442 }
443 Ok(ConValue::Function(func))
444 }
445 (BindOp::Mod, _, [At(Expr::Op(Op::Block, exprs), ..)]) => {
446 let [body] = exprs.as_slice() else {
447 todo!("{exprs:?}")?
448 };
449 body.interpret(env)
450 }
451 (BindOp::Mod, _, [body]) => body.interpret(env),
452 (BindOp::Impl, _, [body]) => cl_todo!("impl {pat} {body}"),
453 (BindOp::Struct, pat, []) => {
454 let (name, model) = bind_struct(pat, env)?;
455 if let Some(name) = name {
456 let typeid = env.def_type(name, model);
457 env.bind(name, ConValue::TypeInfo(typeid));
458 Ok(ConValue::TypeInfo(typeid))
459 } else {
460 Err(Error::MatchNonexhaustive()) }
462 }
463 (BindOp::Struct, Pat::Name(name), []) => {
464 let typeid = env.def_type(*name, typeinfo::Model::Unit(0));
465 env.bind(*name, ConValue::TypeInfo(typeid));
466 Ok(ConValue::TypeInfo(typeid))
467 }
468 (BindOp::Struct, pat, []) => cl_todo!("struct {pat}"),
469 (BindOp::Enum, Pat::Name(name), []) => {
470 let typeid = env.def_type(*name, typeinfo::Model::Never);
471 env.bind(*name, ConValue::TypeInfo(typeid));
472 Ok(ConValue::TypeInfo(typeid))
473 }
474 (BindOp::Enum, pat, []) => bind_enum(pat, env),
475 (BindOp::Enum, _, []) => cl_todo!("enum {pat}"),
476 (BindOp::For, _, [iter, pass, fail]) => {
477 let iter: Box<dyn Iterator<Item = ConValue>> = match iter.interpret(env)? {
478 ConValue::Array(values) | ConValue::Tuple(values) => {
479 Box::new(values.into_iter())
480 }
481 ConValue::String(str) => Box::new(str.into_chars().map(ConValue::Char)),
482 ConValue::Str(str) => Box::new(str.to_ref().chars().map(ConValue::Char)),
483 ConValue::TupleStruct(
484 Interned(TypeInfo { ident: Interned("RangeExc", ..), .. }, ..),
485 bounds,
486 ) => match *bounds {
487 [ConValue::Int(start), ConValue::Int(end)] => {
488 Box::new((start..end).map(ConValue::Int))
489 }
490 _ => Err(Error::NotIterable())?,
491 },
492 ConValue::TupleStruct(
493 Interned(TypeInfo { ident: Interned("RangeInc", ..), .. }, ..),
494 bounds,
495 ) => match *bounds {
496 [ConValue::Int(start), ConValue::Int(end)] => {
497 Box::new((start..=end).map(ConValue::Int))
498 }
499 _ => Err(Error::NotIterable())?,
500 },
501 _ => Err(Error::NotIterable())?,
502 };
503 for item in iter {
504 let mut bind = HashMap::new();
505 pat.matches(item, &mut MatchEnv::new(env, &mut bind))?;
506
507 let mut scope = env.with_frame("for-loop", bind);
508 match pass.interpret(&mut scope) {
509 Ok(_) => {}
510 Err(Error { kind: ErrorKind::Break(value), .. }) => return Ok(value),
511 Err(Error { kind: ErrorKind::Continue, .. }) => continue,
512 Err(e) => Err(e)?,
513 }
514 }
515 fail.interpret(env)
516 }
517 _ => cl_unimplemented!("{self}"),
518 }
519 }
520}
521
522fn bind_struct(pat: &Pat, env: &mut Environment) -> IResult<(Option<Sym>, Model)> {
523 fn bind_struct_op(
524 op: PatOp,
525 pats: &[Pat],
526 env: &mut Environment,
527 ) -> IResult<(Option<Sym>, Model)> {
528 match (op, pats) {
529 (PatOp::Pub | PatOp::Mut, [expr]) => bind_struct(expr, env),
530 (PatOp::Ref, []) => todo!("Ref in bind_struct_op?"),
531 (PatOp::Ptr, []) => todo!("Ptr in bind_struct_op?"),
532 (PatOp::Rest, []) => todo!("Rest in bind_struct_op?"),
533 (PatOp::RangeEx, []) => todo!("RangeEx in bind_struct_op?"),
534 (PatOp::RangeIn, []) => todo!("RangeIn in bind_struct_op?"),
535 (PatOp::Record, elements) => {
536 let mut members = Vec::new();
537 let mut exhaustive = true;
538 for (idx, member) in elements.iter().enumerate() {
539 if let Pat::Op(PatOp::Rest, _) = member {
540 exhaustive = false;
541 continue;
542 }
543 if let (Some(name), model) = bind_struct(member, env)? {
544 members.push((name, env.get_type("_".into()).unwrap()));
545 }
546 }
547 Ok((None, Model::Struct(members.into_boxed_slice(), exhaustive)))
548 }
549 (PatOp::Tuple, elements) => {
550 let members = vec![env.get_type("_".into()).unwrap(); elements.len()];
551 Ok((None, Model::Tuple(members.into_boxed_slice())))
552 }
553 (PatOp::Typed, [name, _ty]) => bind_struct(name, env),
554 (PatOp::TypePrefixed, [name, ty]) => match bind_struct(ty, env)? {
555 (None, model) => Ok((name.name(), model)),
556 (Some(name), model) => todo!("Typeprefixed {name} :: {model:?}"),
557 },
558 (PatOp::Generic, [first, ..]) => bind_struct(first, env),
559 _ => todo!("{op} ({pats:?})"),
560 }
561 }
562 Ok(match pat {
563 Pat::Ignore => todo!("Pat::Ignore in struct binding")?,
564 Pat::Never => todo!("Pat::Never in struct binding")?,
565 Pat::MetId(_) => todo!("Pat::MetId in struct binding")?,
566 Pat::Name(name) => (Some(*name), typeinfo::Model::Unit(0)),
567 Pat::Value(at) => todo!("Pat::Value in struct binding")?,
568 Pat::Op(pat_op, pats) => bind_struct_op(*pat_op, pats, env)?,
569 })
570}
571
572fn bind_enum(pat: &Pat, env: &mut Environment) -> IResult<ConValue> {
573 let name = pat
574 .name()
575 .ok_or_else(|| Error::PatFailed(Box::new(pat.clone())))?;
576 let mut variants = vec![];
577 if let Pat::Op(PatOp::TypePrefixed, pats) = pat
578 && let [_prefix, pats] = pats.as_slice()
579 && let Pat::Op(PatOp::Record, pats) = pats
580 {
581 for (idx, pat) in pats.iter().enumerate() {
582 if let (Some(name), model) = bind_struct(pat, env)? {
583 let model = match model {
584 Model::Unit(_) => Model::Unit(idx),
585 _ => model,
586 };
587 let typeid = env.def_type(name, model);
588 variants.push((name, typeid));
589 }
590 }
591 } else {
592 todo!("Bind other enum: {pat}")?
593 };
594
595 let typeid = env.def_type(name, Model::Enum(variants.into_boxed_slice()));
596 env.bind(name, ConValue::TypeInfo(typeid));
597 Ok(ConValue::TypeInfo(typeid))
598}
599
600impl Interpret for Make<DefaultTypes> {
601 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
602 let Self(ty, entries) = self;
603
604 let tyinfo = match ty.interpret(env)? {
605 ConValue::TypeInfo(info) => info,
606 other => Err(Error::TypeError("type", other.typename()))?,
607 };
608
609 let mut members = HashMap::new();
610
611 for MakeArm(name, value) in entries {
612 members.insert(
614 *name,
615 match value {
616 Some(value) => value.interpret(env),
617 None => env.get(*name),
618 }?,
619 );
620 }
621
622 tyinfo.make_struct(members)
623 }
624}
625
626impl Interpret for cl_ast::ast::Match<DefaultTypes> {
627 fn interpret(&self, env: &mut Environment) -> IResult<ConValue> {
628 let Self(scrutinee, arms) = self;
629 let scrutinee = scrutinee.interpret(env)?;
630 for MatchArm(pat, expr) in arms {
631 let mut bind = HashMap::new();
632 if pat
633 .matches(scrutinee.clone(), &mut MatchEnv::new(env, &mut bind))
634 .is_ok()
635 {
636 return expr.interpret(&mut env.with_frame("match-arm", bind));
637 }
638 }
639 Err(Error::MatchNonexhaustive())
640 }
641}
642
643pub enum BindingMode {
644 Value,
645 Ref,
646 Ptr,
647}
648
649#[derive(Debug)]
650pub struct MatchEnv<'env> {
651 env: &'env mut Environment,
652 bind: &'env mut HashMap<Sym, ConValue>,
653 public: bool,
654 mutable: bool,
655}
656
657impl MatchEnv<'_> {
658 pub fn new<'e>(env: &'e mut Environment, bind: &'e mut HashMap<Sym, ConValue>) -> MatchEnv<'e> {
659 MatchEnv { env, bind, public: false, mutable: false } }
661 pub fn public(&mut self) -> MatchEnv<'_> {
662 let Self { ref mut env, ref mut bind, public: _, mutable } = *self;
663 MatchEnv { env, bind, public: true, mutable }
664 }
665
666 pub fn mutable(&mut self) -> MatchEnv<'_> {
667 let Self { ref mut env, ref mut bind, public, mutable: _ } = *self;
668 MatchEnv { env, bind, public, mutable: true }
669 }
670}
671
672pub trait Match<Value = ConValue> {
673 fn matches<'env>(&self, value: Value, in_env: &mut MatchEnv<'env>) -> IResult<()>;
674}
675
676impl Match for Pat {
677 fn matches<'env>(&self, value: ConValue, in_env: &mut MatchEnv<'env>) -> IResult<()> {
678 match (self) {
679 Self::Ignore => Ok(()),
680 Self::Never => todo!("Never"),
681 Self::MetId(_) => todo!("Meta-identifiers are not allowed here"),
682 &Self::Name(name) => {
683 in_env.bind.insert(name, value);
684 Ok(())
685 }
686 Self::Value(at) => {
687 let truth = at.interpret(in_env.env)?;
688 if truth.neq(&value)?.truthy()? {
689 Err(Error::PatFailed(self.clone().into()))
690 } else {
691 Ok(())
692 }
693 }
694 Self::Op(pat_op, pats) => (*pat_op, pats.as_slice()).matches(value, in_env),
695 }
696 }
697}
698
699impl Match for (PatOp, &[Pat]) {
700 fn matches<'env>(&self, value: ConValue, in_env: &mut MatchEnv<'env>) -> IResult<()> {
701 match self {
702 (PatOp::Pub, [pat]) => pat.matches(value, &mut in_env.public()),
703 (PatOp::Pub, _) => unimplemented!(),
704 (PatOp::Mut, [pat]) => pat.matches(value, &mut in_env.mutable()),
705 (PatOp::Mut, _) => unimplemented!(),
706 (PatOp::Ref, [pat]) => match value {
707 ConValue::Ref(place) => {
708 let value = place
709 .get(in_env.env)
710 .cloned()
711 .map_err(|_| Error::PatFailed(pat.clone().into()))?;
712 pat.matches(value, in_env)
713 }
714 other => pat.matches(other, in_env),
716 },
717 (PatOp::Ref, _) => unimplemented!("Ref patterns!"),
718 (PatOp::Ptr, _) => todo!("Raw pointer/deref patterns?"),
719 (PatOp::Rest, []) => Ok(()),
720 (PatOp::Rest, [Pat::Value(end)]) => {
722 if end.interpret(in_env.env)?.lt_eq(&value)?.truthy()? {
723 return Err(Error::MatchNonexhaustive());
724 }
725 Ok(())
726 }
727 (PatOp::Rest, [rest]) => rest.matches(value, in_env),
728 (PatOp::Rest, _) => unimplemented!("rest pattern with more than one arg"),
729 (PatOp::RangeEx, [Pat::Value(start)]) => {
730 if start.interpret(in_env.env)?.gt(&value)?.truthy()? {
732 return Err(Error::MatchNonexhaustive());
733 }
734 Ok(())
735 }
736 (PatOp::RangeEx, [Pat::Value(start), Pat::Value(end)]) => {
737 if start.interpret(in_env.env)?.gt(&value)?.truthy()? {
738 return Err(Error::MatchNonexhaustive());
739 }
740 if end.interpret(in_env.env)?.lt_eq(&value)?.truthy()? {
741 return Err(Error::MatchNonexhaustive());
742 }
743 Ok(())
744 }
745 (PatOp::RangeEx, pats) => todo!("RangeEx patterns: {pats:?}"),
746 (PatOp::RangeIn, [Pat::Value(start), Pat::Value(end)]) => {
747 if start.interpret(in_env.env)?.gt(&value)?.truthy()? {
748 return Err(Error::MatchNonexhaustive());
749 }
750 if end.interpret(in_env.env)?.lt(&value)?.truthy()? {
751 return Err(Error::MatchNonexhaustive());
752 }
753 Ok(())
754 }
755 (PatOp::RangeIn, pats) => todo!("Range patterns: {pats:?}"),
756 (PatOp::Record, pats) => match_pat_for_struct(pats, value, in_env),
757 (PatOp::Tuple, pats) => match value {
758 ConValue::Empty if pats.is_empty() => Ok(()),
759 ConValue::Tuple(values) if pats.len() <= values.len() => {
760 (SliceMode::Tuple, *pats).matches(values, in_env)
761 }
762 _ => todo!("Match {pats:?} against {value}"),
763 },
764 (PatOp::Slice, pats) => match value {
765 ConValue::Array(values) if pats.len() <= values.len() => {
766 (SliceMode::Slice, *pats).matches(values, in_env)
767 }
768 _ => todo!("Match {pats:?} against {value}"),
769 },
770 (PatOp::ArRep, _) => todo!(),
771 (PatOp::Typed, [pat, _ty @ ..]) => pat.matches(value, in_env),
772 (PatOp::Typed, _) => todo!(),
773 (PatOp::TypePrefixed, [Pat::Value(e), pat]) => {
774 let ty = match e.interpret(in_env.env)? {
775 ConValue::TypeInfo(ty) => ty,
776 other => Err(Error::TypeError("type", other.typename()))?,
777 };
778 match value {
779 ConValue::Struct(value_ty, _) | ConValue::TupleStruct(value_ty, _)
780 if ty != value_ty =>
781 {
782 Err(Error::TypeError(ty.ident.to_ref(), value_ty.ident.to_ref()))?
783 }
784 ConValue::TupleStruct(value_ty, values) => {
785 pat.matches(ConValue::Tuple(values), in_env)
786 }
787 _ => pat.matches(value, in_env),
788 }
789 }
790 (PatOp::TypePrefixed, [pat_name, pat]) => match value {
791 ConValue::TupleStruct(value_type, values) => {
792 let Some(pat_name) = pat_name.name() else {
793 todo!("{pat_name}({pat})")?
794 };
795 if in_env.env.get_type(pat_name) != Some(value_type) {
796 Err(Error::TypeError(
797 pat_name.to_ref(),
798 value_type.ident.to_ref(),
799 ))?
800 }
801 pat.matches(ConValue::Tuple(values), in_env)
802 }
803 ConValue::Struct(ty, _) => {
804 let Some(pat_name) = pat_name.name() else {
805 todo!("{pat_name}({pat})")?
806 };
807 if in_env.env.get_type(pat_name) != Some(ty) {
808 Err(Error::TypeError(pat_name.to_ref(), ty.ident.to_ref()))?
809 }
810 pat.matches(value, in_env)
811 }
812 _ => pat.matches(value, in_env),
813 },
814 (PatOp::TypePrefixed, _) => todo!("TypePrefixed {self:?}"),
815 (PatOp::Generic, [pat, _subs @ ..]) => pat.matches(value, in_env),
816 (PatOp::Generic, _) => todo!(),
817 (PatOp::Fn, [args, _]) => args.matches(value, in_env),
818 (PatOp::Fn, _) => todo!(),
819 &(PatOp::Alt, alts) if value.is_cheap_to_copy() => {
820 let mut bind = HashMap::new();
821 for alt in alts {
822 alt.matches(value.clone(), &mut MatchEnv::new(in_env.env, &mut bind))?;
823 }
824 Ok(())
825 }
826 (PatOp::Alt, alts) => todo!(
827 "Alternate patterns require trying the same value multiple times, which is expensive."
828 ),
829 }
830 }
831}
832
833fn match_pat_for_struct<'env>(
834 pats: &[Pat],
835 value: ConValue,
836 in_env: &mut MatchEnv<'env>,
837) -> IResult<()> {
838 fn match_typed<'env>(
839 pats: &[Pat],
840 values: &mut HashMap<Sym, ConValue>,
841 in_env: &mut MatchEnv<'env>,
842 ) -> IResult<()> {
843 let [Pat::Name(name), dest] = pats else {
844 todo!("match_typed could not find name in typed pattern")?
845 };
846 let Some(value) = values.remove(name) else {
847 todo!("Struct {values:?} has no value at {name}")?
848 };
849 in_env.bind.insert(*name, value);
850 Ok(())
851 }
852
853 let ConValue::Struct(_, mut values) = value else {
854 todo!("match_pat_for_struct called on {}", value)?
855 };
856
857 for pat in pats {
858 match pat {
859 Pat::Name(name) => {
860 let Some(value) = values.remove(name) else {
861 todo!("Struct {values:?} has no value at {name}")?
862 };
863 in_env.bind.insert(*name, value);
864 }
865 Pat::Op(PatOp::Typed, pats) => match_typed(pats, &mut values, in_env)?,
866 Pat::Op(PatOp::Rest, pats) if pats.is_empty() => break,
867 pat => todo!("{pat}")?,
868 }
869 }
870 Ok(())
871}
872
873enum SliceMode {
874 Slice,
875 Tuple,
876}
877
878impl Match<Box<[ConValue]>> for (SliceMode, &[Pat]) {
879 fn matches<'env>(&self, values: Box<[ConValue]>, in_env: &mut MatchEnv<'env>) -> IResult<()> {
880 let (mode, pats) = self;
881
882 let mut values = values.into_iter();
883 let mut pats = pats.iter().peekable();
884 while !matches!(pats.peek(), None | Some(Pat::Op(PatOp::Rest, _))) {
885 let (Some(pat), Some(value)) = (pats.next(), values.next()) else {
886 break;
887 };
888 pat.matches(value, in_env)?;
889 }
890
891 let mut values = values.rev();
892 let mut pats = pats.rev().peekable();
893 while !matches!(pats.peek(), None | Some(Pat::Op(PatOp::Rest, _))) {
894 let (Some(pat), Some(value)) = (pats.next(), values.next()) else {
895 break;
896 };
897 pat.matches(value, in_env)?;
898 }
899
900 if let Some(Pat::Op(PatOp::Rest, pats)) = pats.next() {
901 if let [pat] = pats.as_slice() {
902 let values = values.into_inner().collect();
903 match mode {
904 SliceMode::Slice => pat.matches(ConValue::Array(values), in_env)?,
905 SliceMode::Tuple => pat.matches(ConValue::Tuple(values), in_env)?,
906 };
907 }
908 } else if values.next().is_some() {
909 Err(Error::MatchNonexhaustive())?
910 }
911
912 match pats.next() {
913 Some(_) => unimplemented!("Match against multiple rest-patterns"),
914 None => Ok(()),
915 }
916 }
917}