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