1use std::collections::HashMap;
12use std::rc::Rc;
13
14use crate::ast::*;
15use crate::diagnostic::{LuxError, Span};
16
17#[derive(Debug, Clone, PartialEq)]
18pub enum Value {
19 Int(i64),
20 Float(f64),
21 Str(String),
22 Bool(bool),
23 Array(Vec<Value>),
24 Range(i64, i64),
26 Struct {
28 name: String,
29 fields: Vec<(String, Value)>,
30 },
31 Enum {
33 enum_name: String,
34 variant: String,
35 fields: Vec<(String, Value)>,
36 },
37 Unit,
39}
40
41impl Value {
42 pub fn type_name(&self) -> &'static str {
43 match self {
44 Value::Int(_) => "int",
45 Value::Float(_) => "float",
46 Value::Str(_) => "string",
47 Value::Bool(_) => "bool",
48 Value::Array(_) => "array",
49 Value::Range(..) => "range",
50 Value::Struct { .. } => "struct",
51 Value::Enum { .. } => "enum",
52 Value::Unit => "nothing",
53 }
54 }
55}
56
57struct Binding {
58 value: Value,
59 mutable: bool,
60}
61
62struct FuncData {
66 params: Vec<Param>,
67 ret: Option<TypeAnn>,
68 body: Vec<Stmt>,
69}
70
71struct StructData {
73 fields: Vec<FieldDef>,
74}
75
76struct EnumData {
78 variants: Vec<VariantDef>,
79}
80
81enum Flow {
83 Normal,
84 Return(Value),
85}
86
87struct Interp {
88 scopes: Vec<HashMap<String, Binding>>,
89 funcs: HashMap<String, Rc<FuncData>>,
90 structs: HashMap<String, Rc<StructData>>,
91 enums: HashMap<String, Rc<EnumData>>,
92 program_args: Vec<String>,
96}
97
98pub fn run(program: &[Stmt], program_args: &[String]) -> Result<(), LuxError> {
101 let mut interp = Interp {
102 scopes: vec![HashMap::new()],
103 funcs: HashMap::new(),
104 structs: HashMap::new(),
105 enums: HashMap::new(),
106 program_args: program_args.to_vec(),
107 };
108 interp.register_builtin_types();
111 interp.register_types(program)?;
115 interp.validate_type_decls(program)?;
116 interp.register_funcs(program)?;
117 interp.exec_block(program)?;
118 Ok(())
119}
120
121impl Interp {
122 fn register_builtin_types(&mut self) {
128 let variant = |name: &str| VariantDef {
129 name: name.to_string(),
130 fields: Vec::new(),
131 span: Span::new(0, 0),
132 };
133 self.enums.insert(
134 "Option".to_string(),
135 Rc::new(EnumData {
136 variants: vec![variant("some"), variant("none")],
137 }),
138 );
139 self.enums.insert(
140 "Result".to_string(),
141 Rc::new(EnumData {
142 variants: vec![variant("ok"), variant("err")],
143 }),
144 );
145 let field = |name: &str, ty: &str| FieldDef {
149 name: name.to_string(),
150 ty: TypeAnn {
151 kind: TypeKind::Named(ty.to_string()),
152 span: Span::new(0, 0),
153 },
154 span: Span::new(0, 0),
155 };
156 self.structs.insert(
157 "Output".to_string(),
158 Rc::new(StructData {
159 fields: vec![
160 field("status", "int"),
161 field("stdout", "string"),
162 field("stderr", "string"),
163 ],
164 }),
165 );
166 }
167
168 fn register_types(&mut self, program: &[Stmt]) -> Result<(), LuxError> {
170 for s in program {
171 match s {
172 Stmt::Struct { name, fields, span } => {
173 if self.type_exists(name) {
174 return Err(already_defined(name, *span));
175 }
176 self.structs.insert(
177 name.clone(),
178 Rc::new(StructData {
179 fields: fields.clone(),
180 }),
181 );
182 }
183 Stmt::Enum {
184 name,
185 variants,
186 span,
187 } => {
188 if self.type_exists(name) {
189 return Err(already_defined(name, *span));
190 }
191 self.enums.insert(
192 name.clone(),
193 Rc::new(EnumData {
194 variants: variants.clone(),
195 }),
196 );
197 }
198 _ => {}
199 }
200 }
201 Ok(())
202 }
203
204 fn type_exists(&self, name: &str) -> bool {
205 self.structs.contains_key(name) || self.enums.contains_key(name)
206 }
207
208 fn validate_type_decls(&self, program: &[Stmt]) -> Result<(), LuxError> {
211 for s in program {
212 match s {
213 Stmt::Struct { fields, .. } => {
214 for f in fields {
215 self.validate_type(&f.ty)?;
216 }
217 }
218 Stmt::Enum { variants, .. } => {
219 for v in variants {
220 for f in &v.fields {
221 self.validate_type(&f.ty)?;
222 }
223 }
224 }
225 _ => {}
226 }
227 }
228 Ok(())
229 }
230
231 fn register_funcs(&mut self, program: &[Stmt]) -> Result<(), LuxError> {
234 for s in program {
235 if let Stmt::Func {
236 name,
237 params,
238 ret,
239 body,
240 span,
241 } = s
242 {
243 if self.funcs.contains_key(name) {
244 return Err(LuxError::new(
245 format!("function `{}` is already defined", name),
246 *span,
247 ));
248 }
249 self.funcs.insert(
250 name.clone(),
251 Rc::new(FuncData {
252 params: params.clone(),
253 ret: ret.clone(),
254 body: body.clone(),
255 }),
256 );
257 }
258 }
259 Ok(())
260 }
261
262 fn push(&mut self) {
263 self.scopes.push(HashMap::new());
264 }
265
266 fn pop(&mut self) {
267 self.scopes.pop();
268 }
269
270 fn current_has(&self, name: &str) -> bool {
271 self.scopes.last().unwrap().contains_key(name)
272 }
273
274 fn lookup(&self, name: &str) -> Option<&Binding> {
275 self.scopes.iter().rev().find_map(|s| s.get(name))
276 }
277
278 fn lookup_mut(&mut self, name: &str) -> Option<&mut Binding> {
279 self.scopes.iter_mut().rev().find_map(|s| s.get_mut(name))
280 }
281
282 fn declare(&mut self, name: String, value: Value, mutable: bool) {
283 self.scopes
284 .last_mut()
285 .unwrap()
286 .insert(name, Binding { value, mutable });
287 }
288
289 fn exec_block(&mut self, stmts: &[Stmt]) -> Result<Flow, LuxError> {
292 for s in stmts {
293 match self.exec_stmt(s)? {
294 Flow::Normal => {}
295 ret @ Flow::Return(_) => return Ok(ret),
296 }
297 }
298 Ok(Flow::Normal)
299 }
300
301 fn exec_stmt(&mut self, stmt: &Stmt) -> Result<Flow, LuxError> {
302 match stmt {
303 Stmt::Let {
304 name,
305 ty,
306 value,
307 span,
308 } => {
309 let v = self.eval(value)?;
310 match ty {
311 Some(ann) => self.check_type(ann, &v)?,
312 None => ensure_determined(&v, value.span())?,
313 }
314 if self.current_has(name) {
315 return Err(LuxError::new(
316 format!("`{}` is already declared in this scope", name),
317 *span,
318 ));
319 }
320 self.declare(name.clone(), v, false);
321 Ok(Flow::Normal)
322 }
323
324 Stmt::Var {
325 name,
326 ty,
327 value,
328 span,
329 } => {
330 let v = match value {
331 Some(e) => {
332 let v = self.eval(e)?;
333 match ty {
334 Some(ann) => self.check_type(ann, &v)?,
335 None => ensure_determined(&v, e.span())?,
336 }
337 v
338 }
339 None => {
340 let ann = ty.as_ref().ok_or_else(|| {
341 LuxError::new(format!("`{}` needs a type or a value", name), *span)
342 .with_note("write `var x: int` or `var x = 0`")
343 .with_learn("variables", "a let holds still, a var can change")
344 })?;
345 self.zero_value(ann)?
346 }
347 };
348 if self.current_has(name) {
349 return Err(LuxError::new(
350 format!("`{}` is already declared in this scope", name),
351 *span,
352 ));
353 }
354 self.declare(name.clone(), v, true);
355 Ok(Flow::Normal)
356 }
357
358 Stmt::Assign {
359 name,
360 name_span,
361 op,
362 value,
363 span,
364 } => {
365 let new = self.eval(value)?;
366 let binding = self.lookup(name).ok_or_else(|| {
367 LuxError::new(format!("`{}` is not defined", name), *name_span)
368 .with_note("declare it first with let or var")
369 .with_learn("variables", "a name has to be made before it's used")
370 })?;
371 if !binding.mutable {
372 return Err(LuxError::new(
373 format!("cannot reassign `{}` — it was declared with let", name),
374 *span,
375 )
376 .with_note("use `var` instead of `let` if it needs to change")
377 .with_learn(
378 "variables",
379 "a let holds still on purpose — that's what keeps it safe",
380 ));
381 }
382 let current = binding.value.clone();
383 let result = match op {
384 AssignOp::Set => {
385 if !same_type(¤t, &new) {
386 return Err(LuxError::new(
387 format!(
388 "`{}` is {} but you assigned {}",
389 name,
390 value_type(¤t),
391 value_type(&new)
392 ),
393 *span,
394 )
395 .with_learn("variables", "a name keeps the type it started with"));
396 }
397 new
398 }
399 AssignOp::Add => append_or_add(current, new, *span)?,
400 AssignOp::Sub => sub(¤t, &new, *span)?,
401 };
402 self.lookup_mut(name).unwrap().value = result;
403 Ok(Flow::Normal)
404 }
405
406 Stmt::Func { .. } | Stmt::Struct { .. } | Stmt::Enum { .. } => Ok(Flow::Normal),
409
410 Stmt::Return { value, .. } => {
411 let v = match value {
412 Some(e) => self.eval(e)?,
413 None => Value::Unit,
414 };
415 Ok(Flow::Return(v))
416 }
417
418 Stmt::If {
419 cond,
420 then_body,
421 else_body,
422 ..
423 } => {
424 if self.eval_bool(cond)? {
425 self.run_scoped(then_body)
426 } else if let Some(eb) = else_body {
427 self.run_scoped(eb)
428 } else {
429 Ok(Flow::Normal)
430 }
431 }
432
433 Stmt::While { cond, body, .. } => {
434 while self.eval_bool(cond)? {
435 match self.run_scoped(body)? {
436 Flow::Normal => {}
437 ret @ Flow::Return(_) => return Ok(ret),
438 }
439 }
440 Ok(Flow::Normal)
441 }
442
443 Stmt::For {
444 var, iter, body, ..
445 } => {
446 let iterable = self.eval(iter)?;
447 match iterable {
448 Value::Array(items) => {
449 for item in items {
450 match self.run_loop_body(var, item, body)? {
451 Flow::Normal => {}
452 ret @ Flow::Return(_) => return Ok(ret),
453 }
454 }
455 }
456 Value::Range(lo, hi) => {
457 let mut i = lo;
458 while i < hi {
459 match self.run_loop_body(var, Value::Int(i), body)? {
460 Flow::Normal => {}
461 ret @ Flow::Return(_) => return Ok(ret),
462 }
463 i += 1;
464 }
465 }
466 other => {
467 return Err(LuxError::new(
468 format!("cannot loop over {}", value_type(&other)),
469 iter.span(),
470 )
471 .with_note("for ... in needs an array or a range like 0..10")
472 .with_learn("for", "for walks an array or counts a range like 0..10"));
473 }
474 }
475 Ok(Flow::Normal)
476 }
477
478 Stmt::Expr(e) => {
479 self.eval(e)?;
480 Ok(Flow::Normal)
481 }
482 }
483 }
484
485 fn run_scoped(&mut self, body: &[Stmt]) -> Result<Flow, LuxError> {
487 self.push();
488 let r = self.exec_block(body);
489 self.pop();
490 r
491 }
492
493 fn run_loop_body(&mut self, var: &str, item: Value, body: &[Stmt]) -> Result<Flow, LuxError> {
496 self.push();
497 self.declare(var.to_string(), item, false);
498 let r = self.exec_block(body);
499 self.pop();
500 r
501 }
502
503 fn eval(&mut self, e: &Expr) -> Result<Value, LuxError> {
506 match e {
507 Expr::Int(v, _) => Ok(Value::Int(*v)),
508 Expr::Float(v, _) => Ok(Value::Float(*v)),
509 Expr::Str(s, _) => Ok(Value::Str(s.clone())),
510 Expr::Bool(b, _) => Ok(Value::Bool(*b)),
511 Expr::Ident(name, span) => match self.lookup(name) {
512 Some(b) => Ok(b.value.clone()),
513 None if name == "none" => Ok(option_none()),
514 None => Err(LuxError::new(format!("`{}` is not defined", name), *span)
515 .with_note("declare it with let or var before using it")
516 .with_learn("scope", "a name lives only inside the { } where it's made")),
517 },
518 Expr::Array(elems, _) => {
519 let mut items = Vec::with_capacity(elems.len());
520 for e in elems {
521 items.push(self.eval(e)?);
522 }
523 if let Some(first) = items.first() {
525 for (v, e) in items.iter().zip(elems).skip(1) {
526 if !same_type(first, v) {
527 return Err(LuxError::new(
528 format!(
529 "an array's elements must all be the same type, but found {} and {}",
530 value_type(first),
531 value_type(v)
532 ),
533 e.span(),
534 )
535 .with_learn("arrays", "an array holds many values of one type"));
536 }
537 }
538 }
539 Ok(Value::Array(items))
540 }
541 Expr::Unary { op, rhs, span } => {
542 let v = self.eval(rhs)?;
543 unary(*op, v, *span)
544 }
545 Expr::Binary { op, lhs, rhs, span } => {
546 match op {
548 BinOp::And => {
549 if !self.eval_bool(lhs)? {
550 return Ok(Value::Bool(false));
551 }
552 Ok(Value::Bool(self.eval_bool(rhs)?))
553 }
554 BinOp::Or => {
555 if self.eval_bool(lhs)? {
556 return Ok(Value::Bool(true));
557 }
558 Ok(Value::Bool(self.eval_bool(rhs)?))
559 }
560 _ => {
561 let a = self.eval(lhs)?;
562 let b = self.eval(rhs)?;
563 binary_op(*op, &a, &b, *span)
564 }
565 }
566 }
567 Expr::Index { base, index, span } => {
568 let collection = self.eval(base)?;
569 let idx = self.eval(index)?;
570 let items = match collection {
571 Value::Array(items) => items,
572 other => {
573 return Err(LuxError::new(
574 format!(
575 "cannot index into {}; only arrays can be indexed",
576 value_type(&other)
577 ),
578 base.span(),
579 )
580 .with_learn("arrays", "a numbered row of values, all one type, from 0"));
581 }
582 };
583 let i = match idx {
584 Value::Int(i) => i,
585 other => {
586 return Err(LuxError::new(
587 format!(
588 "an array index must be an int, but this is {}",
589 value_type(&other)
590 ),
591 index.span(),
592 )
593 .with_learn(
594 "arrays",
595 "you reach an element by its position, counting from 0",
596 ));
597 }
598 };
599 if i < 0 || i as usize >= items.len() {
600 let note = if items.is_empty() {
601 "this array is empty".to_string()
602 } else {
603 format!("valid indices are 0 to {}", items.len() - 1)
604 };
605 return Err(LuxError::new(
606 format!(
607 "index {} is out of bounds for an array of length {}",
608 i,
609 items.len()
610 ),
611 *span,
612 )
613 .with_note(note)
614 .with_learn(
615 "arrays",
616 "the first element is 0, so the last is length minus 1",
617 ));
618 }
619 Ok(items[i as usize].clone())
620 }
621 Expr::Range { start, end, span } => {
622 let lo = self.eval(start)?;
623 let hi = self.eval(end)?;
624 match (lo, hi) {
625 (Value::Int(a), Value::Int(b)) => Ok(Value::Range(a, b)),
626 (a, b) => Err(LuxError::new(
627 format!(
628 "a range needs two ints, but got {} and {}",
629 value_type(&a),
630 value_type(&b)
631 ),
632 *span,
633 )
634 .with_note("write something like 0..10")
635 .with_learn("for", "a range like 0..10 counts, end not included")),
636 }
637 }
638 Expr::Call { name, args, span } => self.call(name, args, *span),
639 Expr::StructLit { name, fields, span } => self.eval_struct_lit(name, fields, *span),
640 Expr::EnumLit {
641 enum_name,
642 variant,
643 fields,
644 span,
645 } => self.construct_enum(enum_name, variant, fields, *span),
646 Expr::Field { base, field, span } => self.eval_field(base, field, *span),
647 Expr::Match {
648 scrutinee,
649 arms,
650 span,
651 } => self.eval_match(scrutinee, arms, *span),
652 }
653 }
654
655 fn eval_struct_lit(
658 &mut self,
659 name: &str,
660 provided: &[(String, Expr)],
661 span: Span,
662 ) -> Result<Value, LuxError> {
663 let data = match self.structs.get(name) {
664 Some(d) => Rc::clone(d),
665 None => {
666 return Err(LuxError::new(format!("unknown struct `{}`", name), span)
667 .with_note("define it with `struct`, or check the spelling")
668 .with_learn("structs", "a struct gathers a few values under one name"));
669 }
670 };
671 for (k, e) in provided {
673 if !data.fields.iter().any(|f| &f.name == k) {
674 return Err(LuxError::new(
675 format!("struct `{}` has no field `{}`", name, k),
676 e.span(),
677 )
678 .with_learn("structs", "a struct's fields are fixed when you define it"));
679 }
680 }
681 let mut built = Vec::with_capacity(data.fields.len());
682 for f in &data.fields {
683 let value_expr = match provided.iter().find(|(k, _)| k == &f.name) {
684 Some((_, e)) => e,
685 None => {
686 return Err(LuxError::new(
687 format!("missing field `{}` for struct `{}`", f.name, name),
688 span,
689 )
690 .with_note(format!(
691 "`{}` has a field `{}: {}`",
692 name,
693 f.name,
694 describe_type(&f.ty)
695 ))
696 .with_learn(
697 "structs",
698 "every field gets a value when you build a struct",
699 ));
700 }
701 };
702 let v = self.eval(value_expr)?;
703 if !self.type_matches(&f.ty, &v) {
704 return Err(LuxError::new(
705 format!(
706 "field `{}` of `{}` should be {}, but got {}",
707 f.name,
708 name,
709 describe_type(&f.ty),
710 value_type(&v)
711 ),
712 value_expr.span(),
713 )
714 .with_learn(
715 "structs",
716 "each field has a type, set when you define the struct",
717 ));
718 }
719 built.push((f.name.clone(), v));
720 }
721 Ok(Value::Struct {
722 name: name.to_string(),
723 fields: built,
724 })
725 }
726
727 fn construct_enum(
730 &mut self,
731 enum_name: &str,
732 variant: &str,
733 provided: &[(String, Expr)],
734 span: Span,
735 ) -> Result<Value, LuxError> {
736 let data = match self.enums.get(enum_name) {
737 Some(d) => Rc::clone(d),
738 None => {
739 return Err(LuxError::new(format!("unknown enum `{}`", enum_name), span)
740 .with_note("define it with `enum`, or check the spelling")
741 .with_learn("enums", "an enum is one of a fixed set of shapes"));
742 }
743 };
744 let vdef = match data.variants.iter().find(|v| v.name == variant) {
745 Some(v) => v,
746 None => {
747 return Err(LuxError::new(
748 format!("enum `{}` has no case `{}`", enum_name, variant),
749 span,
750 )
751 .with_note(format!("cases are: {}", variant_names(&data)))
752 .with_learn(
753 "enums",
754 "an enum's cases are the fixed set of shapes it allows",
755 ));
756 }
757 };
758 if provided.len() != vdef.fields.len() {
759 return Err(LuxError::new(
760 format!(
761 "`{}.{}` carries {}, but you gave {}",
762 enum_name,
763 variant,
764 count(vdef.fields.len(), "value"),
765 provided.len()
766 ),
767 span,
768 )
769 .with_learn("enums", "each case can carry its own values"));
770 }
771 let mut built = Vec::with_capacity(vdef.fields.len());
772 for f in &vdef.fields {
773 let value_expr = match provided.iter().find(|(k, _)| k == &f.name) {
774 Some((_, e)) => e,
775 None => {
776 return Err(LuxError::new(
777 format!("missing value `{}` for `{}.{}`", f.name, enum_name, variant),
778 span,
779 )
780 .with_learn(
781 "enums",
782 "a case carries its values, named like a struct's fields",
783 ));
784 }
785 };
786 let v = self.eval(value_expr)?;
787 if !self.type_matches(&f.ty, &v) {
788 return Err(LuxError::new(
789 format!(
790 "`{}` in `{}.{}` should be {}, but got {}",
791 f.name,
792 enum_name,
793 variant,
794 describe_type(&f.ty),
795 value_type(&v)
796 ),
797 value_expr.span(),
798 )
799 .with_learn("enums", "each value a case carries has a type"));
800 }
801 built.push((f.name.clone(), v));
802 }
803 Ok(Value::Enum {
804 enum_name: enum_name.to_string(),
805 variant: variant.to_string(),
806 fields: built,
807 })
808 }
809
810 fn eval_field(&mut self, base: &Expr, field: &str, span: Span) -> Result<Value, LuxError> {
814 if let Expr::Ident(n, nspan) = base {
815 if self.lookup(n).is_none() {
816 if self.enums.contains_key(n) {
817 return self.construct_enum(n, field, &[], span);
818 }
819 return Err(LuxError::new(format!("`{}` is not defined", n), *nspan)
822 .with_note("if it's an enum, declare it with `enum`; otherwise declare the value with let or var")
823 .with_learn("variables", "a name has to be made before it's used"));
824 }
825 }
826 let v = self.eval(base)?;
827 match v {
828 Value::Struct { name, fields } => match fields.iter().find(|(k, _)| k == field) {
829 Some((_, val)) => Ok(val.clone()),
830 None => Err(LuxError::new(
831 format!("struct `{}` has no field `{}`", name, field),
832 span,
833 )
834 .with_learn("structs", "a struct only has the fields you gave it")),
835 },
836 other => Err(LuxError::new(
837 format!(
838 "cannot read field `{}` of {}; only structs have fields",
839 field,
840 value_type(&other)
841 ),
842 base.span(),
843 )
844 .with_learn(
845 "structs",
846 "only a struct has named fields to read with a dot",
847 )),
848 }
849 }
850
851 fn eval_match(
854 &mut self,
855 scrutinee: &Expr,
856 arms: &[MatchArm],
857 span: Span,
858 ) -> Result<Value, LuxError> {
859 let v = self.eval(scrutinee)?;
860 match &v {
861 Value::Enum {
862 enum_name,
863 variant,
864 fields,
865 } => {
866 let data = Rc::clone(
867 self.enums
868 .get(enum_name)
869 .expect("an enum value implies a registered enum"),
870 );
871 let has_wildcard = arms
872 .iter()
873 .any(|a| matches!(a.pattern, Pattern::Wildcard(_)));
874
875 for a in arms {
877 match &a.pattern {
878 Pattern::Variant {
879 name, span: psp, ..
880 } => {
881 if !data.variants.iter().any(|vd| &vd.name == name) {
882 return Err(LuxError::new(
883 format!("enum `{}` has no case `{}`", enum_name, name),
884 *psp,
885 )
886 .with_note(format!("cases are: {}", variant_names(&data)))
887 .with_learn(
888 "match",
889 "every arm names one of the enum's real cases",
890 ));
891 }
892 }
893 Pattern::Wildcard(_) => {}
894 other => {
895 return Err(LuxError::new(
896 format!(
897 "this matches on enum `{}`, so each arm must be a case name or `_`",
898 enum_name
899 ),
900 other.span(),
901 )
902 .with_learn("match", "each arm is one case you handle"));
903 }
904 }
905 }
906
907 if !has_wildcard {
909 let missing: Vec<String> = data
910 .variants
911 .iter()
912 .filter(|vd| {
913 !arms.iter().any(|a| {
914 matches!(&a.pattern, Pattern::Variant { name, .. } if name == &vd.name)
915 })
916 })
917 .map(|vd| vd.name.clone())
918 .collect();
919 if !missing.is_empty() {
920 return Err(LuxError::new(
921 format!("this match on `{}` doesn't handle every case", enum_name),
922 span,
923 )
924 .with_learn("match", "covering every case is what makes match safe")
925 .with_note(format!(
926 "add an arm for: {} (or a `_` catch-all)",
927 missing.join(", ")
928 )));
929 }
930 }
931
932 for a in arms {
934 match &a.pattern {
935 Pattern::Variant {
936 name,
937 bindings,
938 span: psp,
939 } if name == variant => {
940 if bindings.len() != fields.len() {
941 return Err(LuxError::new(
942 format!(
943 "case `{}` carries {}, but the pattern captures {}",
944 name,
945 count(fields.len(), "value"),
946 bindings.len()
947 ),
948 *psp,
949 )
950 .with_learn(
951 "match",
952 "a pattern binds the values its case carries",
953 ));
954 }
955 self.push();
956 for (b, (_, val)) in bindings.iter().zip(fields.iter()) {
957 self.declare(b.clone(), val.clone(), false);
958 }
959 let r = self.eval(&a.body);
960 self.pop();
961 return r;
962 }
963 Pattern::Wildcard(_) => return self.eval(&a.body),
964 _ => continue,
965 }
966 }
967 unreachable!("exhaustiveness guarantees a matching arm")
968 }
969 other => self.match_value(other, arms, scrutinee.span(), span),
970 }
971 }
972
973 fn match_value(
976 &mut self,
977 v: &Value,
978 arms: &[MatchArm],
979 scrutinee_span: Span,
980 span: Span,
981 ) -> Result<Value, LuxError> {
982 if !matches!(v, Value::Int(_) | Value::Str(_) | Value::Bool(_)) {
983 return Err(LuxError::new(
984 format!(
985 "cannot match on {}; match works on enums, int, string, and bool",
986 value_type(v)
987 ),
988 scrutinee_span,
989 )
990 .with_learn(
991 "match",
992 "match takes apart an enum or a plain int, string, or bool",
993 ));
994 }
995 let has_wildcard = arms
998 .iter()
999 .any(|a| matches!(a.pattern, Pattern::Wildcard(_)));
1000 let bool_exhaustive = matches!(v, Value::Bool(_))
1001 && arms
1002 .iter()
1003 .any(|a| matches!(a.pattern, Pattern::Bool(true, _)))
1004 && arms
1005 .iter()
1006 .any(|a| matches!(a.pattern, Pattern::Bool(false, _)));
1007 if !has_wildcard && !bool_exhaustive {
1008 return Err(LuxError::new(
1009 format!("this match on {} needs a `_` case", value_type(v)),
1010 span,
1011 )
1012 .with_note("matching a value (not an enum) can't be exhaustive, so add `_ => ...`")
1013 .with_learn(
1014 "match",
1015 "`_` is the catch-all that covers every other value",
1016 ));
1017 }
1018 for a in arms {
1019 let fits = match (&a.pattern, v) {
1020 (Pattern::Wildcard(_), _) => true,
1021 (Pattern::Int(n, _), Value::Int(m)) => n == m,
1022 (Pattern::Str(s, _), Value::Str(t)) => s == t,
1023 (Pattern::Bool(b, _), Value::Bool(c)) => b == c,
1024 (Pattern::Variant { span: psp, .. }, _) => {
1025 return Err(LuxError::new(
1026 format!("this is {}, not an enum, so it has no cases", value_type(v)),
1027 *psp,
1028 )
1029 .with_learn("enums", "only an enum has named cases to match"));
1030 }
1031 _ => false,
1032 };
1033 if fits {
1034 return self.eval(&a.body);
1035 }
1036 }
1037 unreachable!("the required `_` arm guarantees a match")
1038 }
1039
1040 fn eval_bool(&mut self, e: &Expr) -> Result<bool, LuxError> {
1041 match self.eval(e)? {
1042 Value::Bool(b) => Ok(b),
1043 other => Err(LuxError::new(
1044 format!(
1045 "expected a true/false value, but this is {}",
1046 named(other.type_name())
1047 ),
1048 e.span(),
1049 )
1050 .with_note("conditions and &&/|| operands must be bool")
1051 .with_learn("booleans", "if, while, and and/or all run on true or false")),
1052 }
1053 }
1054
1055 fn call(&mut self, name: &str, args: &[Expr], span: Span) -> Result<Value, LuxError> {
1056 match name {
1057 "print" => {
1058 let mut parts = Vec::with_capacity(args.len());
1059 for a in args {
1060 parts.push(display(&self.eval(a)?));
1061 }
1062 println!("{}", parts.join(" "));
1063 Ok(Value::Unit)
1064 }
1065 "string" => {
1066 let v = self.one_arg(name, args, span)?;
1067 Ok(Value::Str(display(&v)))
1068 }
1069 "int" => {
1070 let v = self.one_arg(name, args, span)?;
1071 match v {
1072 Value::Int(_) => Ok(v),
1073 Value::Float(f) => Ok(Value::Int(f as i64)),
1074 Value::Str(_) => Err(LuxError::new(
1075 "int converts between numbers, not from text".to_string(),
1076 span,
1077 )
1078 .with_note("to read a number from text use parseInt, which hands back an Option you match on")
1079 .with_learn("conversions", "parseInt reads a number from text and gives back an Option")),
1080 other => Err(LuxError::new(
1081 format!("cannot convert {} to an int", named(other.type_name())),
1082 span,
1083 )),
1084 }
1085 }
1086 "float" => {
1087 let v = self.one_arg(name, args, span)?;
1088 match v {
1089 Value::Float(_) => Ok(v),
1090 Value::Int(n) => Ok(Value::Float(n as f64)),
1091 Value::Str(_) => Err(LuxError::new(
1092 "float converts between numbers, not from text".to_string(),
1093 span,
1094 )
1095 .with_note("to read a number from text use parseFloat, which hands back an Option you match on")
1096 .with_learn("conversions", "parseFloat reads a number from text and gives back an Option")),
1097 other => Err(LuxError::new(
1098 format!("cannot convert {} to a float", named(other.type_name())),
1099 span,
1100 )),
1101 }
1102 }
1103 "length" => {
1104 let v = self.one_arg(name, args, span)?;
1105 match v {
1106 Value::Array(items) => Ok(Value::Int(items.len() as i64)),
1107 Value::Str(s) => Ok(Value::Int(s.chars().count() as i64)),
1109 other => Err(LuxError::new(
1110 format!(
1111 "length expects an array or a string, but got {}",
1112 value_type(&other)
1113 ),
1114 span,
1115 )
1116 .with_learn(
1117 "arrays",
1118 "length counts an array's items or a string's characters",
1119 )),
1120 }
1121 }
1122 "readFile" => {
1127 let path = self.one_str(name, args, span)?;
1128 match std::fs::read_to_string(&path) {
1129 Ok(contents) => Ok(result_ok(Value::Str(contents))),
1130 Err(e) => Ok(result_err(Value::Str(format!(
1131 "could not read {}: {}",
1132 path, e
1133 )))),
1134 }
1135 }
1136 "writeFile" => {
1140 let (path, contents) = self.two_str(name, args, span)?;
1141 match std::fs::write(&path, &contents) {
1142 Ok(()) => Ok(result_ok(Value::Unit)),
1143 Err(e) => Ok(result_err(Value::Str(format!(
1144 "could not write {}: {}",
1145 path, e
1146 )))),
1147 }
1148 }
1149 "args" => {
1152 self.no_args(name, args, span)?;
1153 let items = self.program_args.iter().cloned().map(Value::Str).collect();
1154 Ok(Value::Array(items))
1155 }
1156 "readLine" => {
1160 self.no_args(name, args, span)?;
1161 let mut line = String::new();
1162 match std::io::stdin().read_line(&mut line) {
1163 Ok(0) | Err(_) => Ok(option_none()),
1164 Ok(_) => {
1165 let text = line.strip_suffix('\n').unwrap_or(&line);
1166 let text = text.strip_suffix('\r').unwrap_or(text);
1167 Ok(option_some(Value::Str(text.to_string())))
1168 }
1169 }
1170 }
1171 "eprint" => {
1175 let mut parts = Vec::with_capacity(args.len());
1176 for a in args {
1177 parts.push(display(&self.eval(a)?));
1178 }
1179 eprintln!("{}", parts.join(" "));
1180 Ok(Value::Unit)
1181 }
1182 "run" => {
1189 let (program, arg_list) = self.program_and_args(name, args, span)?;
1190 match std::process::Command::new(&program)
1191 .args(&arg_list)
1192 .stdin(std::process::Stdio::null())
1193 .output()
1194 {
1195 Ok(out) => {
1196 let status = out.status.code().unwrap_or(-1) as i64;
1197 let stdout = String::from_utf8_lossy(&out.stdout).into_owned();
1198 let stderr = String::from_utf8_lossy(&out.stderr).into_owned();
1199 Ok(result_ok(output_value(status, stdout, stderr)))
1200 }
1201 Err(e) => Ok(result_err(Value::Str(format!(
1202 "could not run {}: {}",
1203 program, e
1204 )))),
1205 }
1206 }
1207 "parseInt" => match self.one_arg(name, args, span)? {
1211 Value::Str(s) => Ok(match s.trim().parse::<i64>() {
1212 Ok(n) => option_some(Value::Int(n)),
1213 Err(_) => option_none(),
1214 }),
1215 other => Err(LuxError::new(
1216 format!("parseInt reads text, but got {}", named(other.type_name())),
1217 span,
1218 )),
1219 },
1220 "parseFloat" => match self.one_arg(name, args, span)? {
1221 Value::Str(s) => Ok(match s.trim().parse::<f64>() {
1222 Ok(f) => option_some(Value::Float(f)),
1223 Err(_) => option_none(),
1224 }),
1225 other => Err(LuxError::new(
1226 format!("parseFloat reads text, but got {}", named(other.type_name())),
1227 span,
1228 )),
1229 },
1230 "some" => Ok(option_some(self.one_arg(name, args, span)?)),
1233 "ok" => Ok(result_ok(self.one_arg(name, args, span)?)),
1234 "err" => Ok(result_err(self.one_arg(name, args, span)?)),
1235 _ => self.call_user(name, args, span),
1236 }
1237 }
1238
1239 fn one_arg(&mut self, name: &str, args: &[Expr], span: Span) -> Result<Value, LuxError> {
1240 if args.len() != 1 {
1241 return Err(LuxError::new(
1242 format!("{} takes exactly one value, but got {}", name, args.len()),
1243 span,
1244 ));
1245 }
1246 self.eval(&args[0])
1247 }
1248
1249 fn one_str(&mut self, name: &str, args: &[Expr], span: Span) -> Result<String, LuxError> {
1251 match self.one_arg(name, args, span)? {
1252 Value::Str(s) => Ok(s),
1253 other => Err(LuxError::new(
1254 format!("{} expects a string, but got {}", name, value_type(&other)),
1255 span,
1256 )),
1257 }
1258 }
1259
1260 fn two_str(
1262 &mut self,
1263 name: &str,
1264 args: &[Expr],
1265 span: Span,
1266 ) -> Result<(String, String), LuxError> {
1267 if args.len() != 2 {
1268 return Err(LuxError::new(
1269 format!("{} takes exactly two values, but got {}", name, args.len()),
1270 span,
1271 ));
1272 }
1273 let first = self.eval(&args[0])?;
1274 let second = self.eval(&args[1])?;
1275 let path = match first {
1276 Value::Str(s) => s,
1277 other => {
1278 return Err(LuxError::new(
1279 format!(
1280 "{} expects the path as a string, but got {}",
1281 name,
1282 value_type(&other)
1283 ),
1284 span,
1285 ));
1286 }
1287 };
1288 let contents = match second {
1289 Value::Str(s) => s,
1290 other => {
1291 return Err(LuxError::new(
1292 format!(
1293 "{} expects the contents as a string, but got {}",
1294 name,
1295 value_type(&other)
1296 ),
1297 span,
1298 ));
1299 }
1300 };
1301 Ok((path, contents))
1302 }
1303
1304 fn no_args(&self, name: &str, args: &[Expr], span: Span) -> Result<(), LuxError> {
1306 if !args.is_empty() {
1307 return Err(LuxError::new(
1308 format!("{} takes no values, but got {}", name, args.len()),
1309 span,
1310 ));
1311 }
1312 Ok(())
1313 }
1314
1315 fn program_and_args(
1318 &mut self,
1319 name: &str,
1320 args: &[Expr],
1321 span: Span,
1322 ) -> Result<(String, Vec<String>), LuxError> {
1323 if args.len() != 2 {
1324 return Err(LuxError::new(
1325 format!(
1326 "{} takes a program name and a list of arguments, but got {}",
1327 name,
1328 args.len()
1329 ),
1330 span,
1331 ));
1332 }
1333 let program = match self.eval(&args[0])? {
1334 Value::Str(s) => s,
1335 other => {
1336 return Err(LuxError::new(
1337 format!(
1338 "{} expects the program name as a string, but got {}",
1339 name,
1340 value_type(&other)
1341 ),
1342 span,
1343 ));
1344 }
1345 };
1346 let arg_list = match self.eval(&args[1])? {
1347 Value::Array(items) => {
1348 let mut out = Vec::with_capacity(items.len());
1349 for it in items {
1350 match it {
1351 Value::Str(s) => out.push(s),
1352 other => {
1353 return Err(LuxError::new(
1354 format!(
1355 "{} expects the arguments as a list of strings, but one was {}",
1356 name,
1357 value_type(&other)
1358 ),
1359 span,
1360 ));
1361 }
1362 }
1363 }
1364 out
1365 }
1366 other => {
1367 return Err(LuxError::new(
1368 format!(
1369 "{} expects the arguments as a list of strings, but got {}",
1370 name,
1371 value_type(&other)
1372 ),
1373 span,
1374 ));
1375 }
1376 };
1377 Ok((program, arg_list))
1378 }
1379
1380 fn call_user(&mut self, name: &str, args: &[Expr], span: Span) -> Result<Value, LuxError> {
1386 let func = match self.funcs.get(name) {
1387 Some(f) => Rc::clone(f),
1388 None => {
1389 return Err(LuxError::new(format!("unknown function `{}`", name), span).with_note(
1390 "define it with `func`, or use a built-in: print, eprint, string, int, float, length, readFile, writeFile, readLine, args, run",
1391 )
1392 .with_learn("functions", "a function takes values in and hands one result back"));
1393 }
1394 };
1395
1396 if args.len() != func.params.len() {
1397 return Err(LuxError::new(
1398 format!(
1399 "function `{}` expects {} but got {}",
1400 name,
1401 count(func.params.len(), "value"),
1402 args.len()
1403 ),
1404 span,
1405 )
1406 .with_learn(
1407 "functions",
1408 "a function takes exactly the parameters it declares",
1409 ));
1410 }
1411
1412 let mut frame = HashMap::new();
1414 for (param, arg) in func.params.iter().zip(args) {
1415 let v = self.eval(arg)?;
1416 self.validate_type(¶m.ty)?;
1417 if !self.type_matches(¶m.ty, &v) {
1418 return Err(LuxError::new(
1419 format!(
1420 "`{}` expects `{}` to be {}, but got {}",
1421 name,
1422 param.name,
1423 describe_type(¶m.ty),
1424 value_type(&v)
1425 ),
1426 arg.span(),
1427 )
1428 .with_learn("functions", "each parameter has a type the call must match"));
1429 }
1430 frame.insert(
1431 param.name.clone(),
1432 Binding {
1433 value: v,
1434 mutable: false,
1435 },
1436 );
1437 }
1438
1439 let saved = std::mem::replace(&mut self.scopes, vec![frame]);
1442 let outcome = self.exec_block(&func.body);
1443 self.scopes = saved;
1444 let returned = match outcome? {
1445 Flow::Return(v) => v,
1446 Flow::Normal => Value::Unit,
1447 };
1448
1449 match &func.ret {
1450 Some(ann) => {
1451 self.validate_type(ann)?;
1452 if matches!(returned, Value::Unit) {
1453 return Err(LuxError::new(
1454 format!(
1455 "`{}` must return {}, but it ended without returning a value",
1456 name,
1457 describe_type(ann)
1458 ),
1459 span,
1460 )
1461 .with_learn("functions", "a `-> type` is a promise to hand that back"));
1462 }
1463 if !self.type_matches(ann, &returned) {
1464 return Err(LuxError::new(
1465 format!(
1466 "`{}` should return {}, but returned {}",
1467 name,
1468 describe_type(ann),
1469 value_type(&returned)
1470 ),
1471 span,
1472 )
1473 .with_learn("functions", "what comes back must match the `-> type`"));
1474 }
1475 Ok(returned)
1476 }
1477 None => {
1478 if !matches!(returned, Value::Unit) {
1479 return Err(LuxError::new(
1480 format!("`{}` has no return type, so it can't return a value", name),
1481 span,
1482 )
1483 .with_note("add `-> type` to the signature if it should return something")
1484 .with_learn(
1485 "functions",
1486 "no `-> type` means the function returns nothing",
1487 ));
1488 }
1489 Ok(Value::Unit)
1490 }
1491 }
1492 }
1493
1494 fn validate_type(&self, ann: &TypeAnn) -> Result<(), LuxError> {
1499 match &ann.kind {
1500 TypeKind::Named(n) => {
1501 if matches!(n.as_str(), "Option" | "Result") {
1504 let hint = if n == "Option" {
1505 "write `Option<int>`"
1506 } else {
1507 "write `Result<int, string>`"
1508 };
1509 return Err(LuxError::new(
1510 format!("`{}` needs a type in angle brackets", n),
1511 ann.span,
1512 )
1513 .with_note(hint)
1514 .with_learn(
1515 "option",
1516 "Option and Result say what they hold, like Option<int>",
1517 ));
1518 }
1519 if matches!(n.as_str(), "int" | "float" | "string" | "bool" | "Unit")
1522 || self.type_exists(n)
1523 {
1524 Ok(())
1525 } else {
1526 Err(LuxError::new(format!("unknown type `{}`", n), ann.span).with_note(
1527 "known types: int, float, string, bool, Unit, arrays like [int], and any struct or enum you define",
1528 ))
1529 }
1530 }
1531 TypeKind::Array(elem) => self.validate_type(elem),
1532 TypeKind::Generic(name, args) => match name.as_str() {
1533 "Option" => {
1534 if args.len() != 1 {
1535 return Err(LuxError::new(
1536 format!("`Option` takes one type, but got {}", args.len()),
1537 ann.span,
1538 )
1539 .with_note("write `Option<int>`")
1540 .with_learn(
1541 "option",
1542 "an Option holds one type — what's there when it's not none",
1543 ));
1544 }
1545 self.validate_type(&args[0])
1546 }
1547 "Result" => {
1548 if args.len() != 2 {
1549 return Err(LuxError::new(
1550 format!("`Result` takes two types, but got {}", args.len()),
1551 ann.span,
1552 )
1553 .with_note(
1554 "write `Result<int, string>` — the value type and the error type",
1555 )
1556 .with_learn(
1557 "result",
1558 "a Result holds two types: the value and the error",
1559 ));
1560 }
1561 self.validate_type(&args[0])?;
1562 self.validate_type(&args[1])
1563 }
1564 _ => Err(LuxError::new(
1565 format!("`{}` is not a parameterized type", name),
1566 ann.span,
1567 )
1568 .with_note("only Option and Result take a type in angle brackets, like Option<int>")
1569 .with_learn("option", "some(x) or none — a missing value with no null")),
1570 },
1571 }
1572 }
1573
1574 fn type_matches(&self, ann: &TypeAnn, v: &Value) -> bool {
1578 match (&ann.kind, v) {
1579 (TypeKind::Named(n), Value::Struct { name, .. }) => n == name,
1580 (TypeKind::Named(n), Value::Enum { enum_name, .. }) => n == enum_name,
1581 (TypeKind::Named(n), Value::Unit) => n == "Unit",
1583 (TypeKind::Named(n), _) => n == v.type_name(),
1584 (TypeKind::Array(elem), Value::Array(items)) => {
1585 items.iter().all(|it| self.type_matches(elem, it))
1586 }
1587 (
1592 TypeKind::Generic(name, args),
1593 Value::Enum {
1594 enum_name,
1595 variant,
1596 fields,
1597 },
1598 ) if name == enum_name => match (name.as_str(), variant.as_str()) {
1599 ("Option", "none") => true,
1600 ("Option", "some") => self.payload_matches(&args[0], fields),
1601 ("Result", "ok") => self.payload_matches(&args[0], fields),
1602 ("Result", "err") => self.payload_matches(&args[1], fields),
1603 _ => false,
1604 },
1605 _ => false,
1606 }
1607 }
1608
1609 fn payload_matches(&self, ann: &TypeAnn, fields: &[(String, Value)]) -> bool {
1611 match fields.first() {
1612 Some((_, v)) => self.type_matches(ann, v),
1613 None => false,
1614 }
1615 }
1616
1617 fn check_type(&self, ann: &TypeAnn, v: &Value) -> Result<(), LuxError> {
1620 self.validate_type(ann)?;
1621 if !self.type_matches(ann, v) {
1622 return Err(LuxError::new(
1623 format!(
1624 "type mismatch: annotated `{}` but the value is {}",
1625 describe_type(ann),
1626 value_type(v)
1627 ),
1628 ann.span,
1629 ));
1630 }
1631 Ok(())
1632 }
1633
1634 fn zero_value(&self, ann: &TypeAnn) -> Result<Value, LuxError> {
1637 match &ann.kind {
1638 TypeKind::Named(n) => match n.as_str() {
1639 "int" => Ok(Value::Int(0)),
1640 "float" => Ok(Value::Float(0.0)),
1641 "string" => Ok(Value::Str(String::new())),
1642 "bool" => Ok(Value::Bool(false)),
1643 _ if self.type_exists(n) => Err(LuxError::new(
1644 format!("a `var` of type `{}` needs a starting value", n),
1645 ann.span,
1646 )
1647 .with_note(format!("write `var x = {}(...)`", n))),
1648 _ => Err(LuxError::new(format!("unknown type `{}`", n), ann.span)
1649 .with_note("lux has int, float, string, bool, and arrays like [int]")),
1650 },
1651 TypeKind::Array(elem) => {
1652 self.validate_type(elem)?;
1653 Ok(Value::Array(Vec::new()))
1654 }
1655 TypeKind::Generic(name, _) => {
1656 self.validate_type(ann)?;
1657 if name == "Option" {
1658 Ok(option_none())
1660 } else {
1661 Err(LuxError::new(
1662 format!(
1663 "a `var` of type `{}` needs a starting value",
1664 describe_type(ann)
1665 ),
1666 ann.span,
1667 )
1668 .with_note("a Result is either ok(...) or err(...) — there's no empty one")
1669 .with_learn("result", "ok(x) or err(why) — failure as plain data"))
1670 }
1671 }
1672 }
1673 }
1674}
1675
1676fn unary(op: UnOp, v: Value, span: Span) -> Result<Value, LuxError> {
1679 match (op, v) {
1680 (UnOp::Neg, Value::Int(n)) => Ok(Value::Int(-n)),
1681 (UnOp::Neg, Value::Float(f)) => Ok(Value::Float(-f)),
1682 (UnOp::Neg, other) => Err(LuxError::new(
1683 format!("cannot negate {}", named(other.type_name())),
1684 span,
1685 )),
1686 (UnOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)),
1687 (UnOp::Not, other) => Err(LuxError::new(
1688 format!("cannot apply ! to {}", named(other.type_name())),
1689 span,
1690 )
1691 .with_note("! works on bool values")
1692 .with_learn("booleans", "! flips true to false and back")),
1693 }
1694}
1695
1696fn binary_op(op: BinOp, a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1697 match op {
1698 BinOp::Add => add(a, b, span),
1699 BinOp::Sub => sub(a, b, span),
1700 BinOp::Mul => mul(a, b, span),
1701 BinOp::Div => div(a, b, span),
1702 BinOp::Mod => modulo(a, b, span),
1703 BinOp::Eq => equality(a, b, span, false),
1704 BinOp::Ne => equality(a, b, span, true),
1705 BinOp::Lt | BinOp::Gt | BinOp::Le | BinOp::Ge => ordering(op, a, b, span),
1706 BinOp::And | BinOp::Or => unreachable!("&& and || are handled in eval"),
1707 }
1708}
1709
1710fn named(type_name: &str) -> String {
1713 let article = match type_name.chars().next() {
1714 Some('a' | 'e' | 'i' | 'o' | 'u') => "an",
1715 _ => "a",
1716 };
1717 format!("{} {}", article, type_name)
1718}
1719
1720fn value_type(v: &Value) -> String {
1724 match v {
1725 Value::Array(items) => match items.first() {
1726 Some(first) => format!("[{}]", value_type(first)),
1727 None => "[]".to_string(),
1728 },
1729 Value::Struct { name, .. } => name.clone(),
1730 Value::Enum {
1734 enum_name,
1735 variant,
1736 fields,
1737 } if enum_name == "Option" => match (variant.as_str(), fields.first()) {
1738 ("some", Some((_, v))) => format!("Option<{}>", value_type(v)),
1739 _ => "Option<?>".to_string(),
1740 },
1741 Value::Enum {
1742 enum_name,
1743 variant,
1744 fields,
1745 } if enum_name == "Result" => match (variant.as_str(), fields.first()) {
1746 ("ok", Some((_, v))) => format!("Result<{}, ?>", value_type(v)),
1747 ("err", Some((_, v))) => format!("Result<?, {}>", value_type(v)),
1748 _ => "Result".to_string(),
1749 },
1750 Value::Enum { enum_name, .. } => enum_name.clone(),
1751 other => other.type_name().to_string(),
1752 }
1753}
1754
1755fn append_or_add(current: Value, new: Value, span: Span) -> Result<Value, LuxError> {
1757 match current {
1758 Value::Array(mut items) => {
1759 if let Some(first) = items.first() {
1760 if !same_type(first, &new) {
1761 return Err(LuxError::new(
1762 format!(
1763 "cannot add {} to an array of {}",
1764 value_type(&new),
1765 value_type(first)
1766 ),
1767 span,
1768 )
1769 .with_learn("arrays", "an array holds one type, so += has to match it"));
1770 }
1771 }
1772 items.push(new);
1773 Ok(Value::Array(items))
1774 }
1775 scalar => add(&scalar, &new, span),
1776 }
1777}
1778
1779fn add(a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1780 match (a, b) {
1781 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x + y)),
1782 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x + y)),
1783 (Value::Str(x), Value::Str(y)) => Ok(Value::Str(format!("{}{}", x, y))),
1784 _ => Err(mix_or_type_error("add", a, b, span)),
1785 }
1786}
1787
1788fn sub(a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1789 match (a, b) {
1790 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x - y)),
1791 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x - y)),
1792 _ => Err(mix_or_type_error("subtract", a, b, span)),
1793 }
1794}
1795
1796fn mul(a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1797 match (a, b) {
1798 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
1799 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
1800 _ => Err(mix_or_type_error("multiply", a, b, span)),
1801 }
1802}
1803
1804fn div(a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1805 match (a, b) {
1806 (Value::Int(_), Value::Int(0)) => Err(LuxError::new("division by zero", span)),
1807 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x / y)),
1808 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x / y)),
1809 _ => Err(mix_or_type_error("divide", a, b, span)),
1810 }
1811}
1812
1813fn modulo(a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1814 match (a, b) {
1815 (Value::Int(_), Value::Int(0)) => Err(LuxError::new("remainder by zero", span)),
1816 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x % y)),
1817 _ => Err(LuxError::new(
1818 format!(
1819 "% needs two ints, but got {} and {}",
1820 named(a.type_name()),
1821 named(b.type_name())
1822 ),
1823 span,
1824 )),
1825 }
1826}
1827
1828fn equality(a: &Value, b: &Value, span: Span, negate: bool) -> Result<Value, LuxError> {
1829 if !same_type(a, b) {
1830 return Err(LuxError::new(
1831 format!("cannot compare {} with {}", value_type(a), value_type(b)),
1832 span,
1833 )
1834 .with_note("both sides of == and != must be the same type"));
1835 }
1836 let eq = a == b;
1837 Ok(Value::Bool(if negate { !eq } else { eq }))
1838}
1839
1840fn ordering(op: BinOp, a: &Value, b: &Value, span: Span) -> Result<Value, LuxError> {
1841 use std::cmp::Ordering;
1842 let ord: Ordering = match (a, b) {
1843 (Value::Int(x), Value::Int(y)) => x.cmp(y),
1844 (Value::Float(x), Value::Float(y)) => x
1845 .partial_cmp(y)
1846 .ok_or_else(|| LuxError::new("cannot compare with NaN", span))?,
1847 (Value::Str(x), Value::Str(y)) => x.cmp(y),
1848 (Value::Bool(_), Value::Bool(_)) => {
1849 return Err(LuxError::new("cannot order bool values with < or >", span)
1850 .with_note("use == or != to compare bools")
1851 .with_learn(
1852 "booleans",
1853 "true and false aren't ordered, only equal or not",
1854 ));
1855 }
1856 _ => {
1857 return Err(LuxError::new(
1858 format!(
1859 "cannot compare {} with {}",
1860 named(a.type_name()),
1861 named(b.type_name())
1862 ),
1863 span,
1864 )
1865 .with_note("both sides must be the same type"));
1866 }
1867 };
1868 let result = match op {
1869 BinOp::Lt => ord == Ordering::Less,
1870 BinOp::Gt => ord == Ordering::Greater,
1871 BinOp::Le => ord != Ordering::Greater,
1872 BinOp::Ge => ord != Ordering::Less,
1873 _ => unreachable!(),
1874 };
1875 Ok(Value::Bool(result))
1876}
1877
1878fn mix_or_type_error(verb: &str, a: &Value, b: &Value, span: Span) -> LuxError {
1881 let mixed = matches!(
1882 (a, b),
1883 (Value::Int(_), Value::Float(_)) | (Value::Float(_), Value::Int(_))
1884 );
1885 if mixed {
1886 LuxError::new("cannot mix int and float — convert one first", span)
1887 .with_note("wrap a value in float(...) or int(...)")
1888 .with_learn(
1889 "numbers",
1890 "there's a reason lux makes you say when a whole number becomes a fraction",
1891 )
1892 } else {
1893 let (topic, lure) = if matches!(a, Value::Str(_)) || matches!(b, Value::Str(_)) {
1897 (
1898 "strings",
1899 "lux never turns a number into text for you — you ask",
1900 )
1901 } else {
1902 (
1903 "numbers",
1904 "arithmetic needs both sides to be the same number type",
1905 )
1906 };
1907 LuxError::new(
1908 format!(
1909 "cannot {} {} and {}",
1910 verb,
1911 named(a.type_name()),
1912 named(b.type_name())
1913 ),
1914 span,
1915 )
1916 .with_learn(topic, lure)
1917 }
1918}
1919
1920fn describe_type(ann: &TypeAnn) -> String {
1924 match &ann.kind {
1925 TypeKind::Named(n) => n.clone(),
1926 TypeKind::Array(elem) => format!("[{}]", describe_type(elem)),
1927 TypeKind::Generic(name, args) => {
1928 let inner: Vec<String> = args.iter().map(describe_type).collect();
1929 format!("{}<{}>", name, inner.join(", "))
1930 }
1931 }
1932}
1933
1934fn same_type(a: &Value, b: &Value) -> bool {
1938 match (a, b) {
1939 (Value::Struct { name: x, .. }, Value::Struct { name: y, .. }) => x == y,
1940 (
1941 Value::Enum {
1942 enum_name: x,
1943 variant: vx,
1944 fields: fx,
1945 },
1946 Value::Enum {
1947 enum_name: y,
1948 variant: vy,
1949 fields: fy,
1950 },
1951 ) => {
1952 if x != y {
1953 return false;
1954 }
1955 match x.as_str() {
1960 "Option" => payloads_compatible(fx, fy),
1961 "Result" if vx == vy => payloads_compatible(fx, fy),
1962 "Result" => true,
1963 _ => true,
1964 }
1965 }
1966 (Value::Array(x), Value::Array(y)) => match (x.first(), y.first()) {
1967 (Some(a), Some(b)) => same_type(a, b),
1968 _ => true,
1969 },
1970 _ => a.type_name() == b.type_name(),
1971 }
1972}
1973
1974fn payloads_compatible(fx: &[(String, Value)], fy: &[(String, Value)]) -> bool {
1977 match (fx.first(), fy.first()) {
1978 (Some((_, a)), Some((_, b))) => same_type(a, b),
1979 _ => true,
1980 }
1981}
1982
1983const PAYLOAD: &str = "value";
1989
1990fn option_none() -> Value {
1991 Value::Enum {
1992 enum_name: "Option".to_string(),
1993 variant: "none".to_string(),
1994 fields: Vec::new(),
1995 }
1996}
1997
1998fn option_some(v: Value) -> Value {
1999 Value::Enum {
2000 enum_name: "Option".to_string(),
2001 variant: "some".to_string(),
2002 fields: vec![(PAYLOAD.to_string(), v)],
2003 }
2004}
2005
2006fn result_ok(v: Value) -> Value {
2007 Value::Enum {
2008 enum_name: "Result".to_string(),
2009 variant: "ok".to_string(),
2010 fields: vec![(PAYLOAD.to_string(), v)],
2011 }
2012}
2013
2014fn result_err(v: Value) -> Value {
2015 Value::Enum {
2016 enum_name: "Result".to_string(),
2017 variant: "err".to_string(),
2018 fields: vec![(PAYLOAD.to_string(), v)],
2019 }
2020}
2021
2022fn output_value(status: i64, stdout: String, stderr: String) -> Value {
2025 Value::Struct {
2026 name: "Output".to_string(),
2027 fields: vec![
2028 ("status".to_string(), Value::Int(status)),
2029 ("stdout".to_string(), Value::Str(stdout)),
2030 ("stderr".to_string(), Value::Str(stderr)),
2031 ],
2032 }
2033}
2034
2035fn ensure_determined(v: &Value, span: Span) -> Result<(), LuxError> {
2040 if fully_determined(v) {
2041 Ok(())
2042 } else {
2043 Err(LuxError::new(
2044 format!(
2045 "can't tell what type this is — {} leaves it open",
2046 value_type(v)
2047 ),
2048 span,
2049 )
2050 .with_note("name the type, like `let x: Option<int> = none`")
2051 .with_learn(
2052 "option",
2053 "lux usually guesses the type, but an empty none needs you to say",
2054 ))
2055 }
2056}
2057
2058fn fully_determined(v: &Value) -> bool {
2061 match v {
2062 Value::Enum {
2063 enum_name,
2064 variant,
2065 fields,
2066 } if enum_name == "Option" => {
2067 variant == "some" && fields.first().is_some_and(|(_, x)| fully_determined(x))
2068 }
2069 Value::Enum { enum_name, .. } if enum_name == "Result" => false,
2072 Value::Array(items) => items.is_empty() || items.iter().any(fully_determined),
2075 _ => true,
2076 }
2077}
2078
2079fn variant_names(data: &EnumData) -> String {
2081 data.variants
2082 .iter()
2083 .map(|v| v.name.clone())
2084 .collect::<Vec<_>>()
2085 .join(", ")
2086}
2087
2088fn already_defined(name: &str, span: Span) -> LuxError {
2090 LuxError::new(format!("type `{}` is already defined", name), span)
2091}
2092
2093fn count(n: usize, noun: &str) -> String {
2095 if n == 1 {
2096 format!("{} {}", n, noun)
2097 } else {
2098 format!("{} {}s", n, noun)
2099 }
2100}
2101
2102fn display(v: &Value) -> String {
2107 match v {
2108 Value::Int(n) => n.to_string(),
2109 Value::Float(f) => format_float(*f),
2110 Value::Str(s) => s.clone(),
2111 Value::Bool(b) => b.to_string(),
2112 Value::Array(items) => {
2113 let parts: Vec<String> = items.iter().map(display).collect();
2114 format!("[{}]", parts.join(", "))
2115 }
2116 Value::Range(lo, hi) => format!("{}..{}", lo, hi),
2117 Value::Struct { name, fields } => {
2118 format!("{}({})", name, display_fields(fields))
2119 }
2120 Value::Enum {
2123 enum_name,
2124 variant,
2125 fields,
2126 } if enum_name == "Option" || enum_name == "Result" => match fields.first() {
2127 Some((_, payload)) => format!("{}({})", variant, display(payload)),
2128 None => variant.clone(),
2129 },
2130 Value::Enum {
2131 enum_name,
2132 variant,
2133 fields,
2134 } => {
2135 if fields.is_empty() {
2136 format!("{}.{}", enum_name, variant)
2137 } else {
2138 format!("{}.{}({})", enum_name, variant, display_fields(fields))
2139 }
2140 }
2141 Value::Unit => String::new(),
2142 }
2143}
2144
2145fn format_float(f: f64) -> String {
2146 if f.is_finite() && f == f.trunc() {
2147 format!("{:.1}", f)
2148 } else {
2149 format!("{}", f)
2150 }
2151}
2152
2153fn display_fields(fields: &[(String, Value)]) -> String {
2156 fields
2157 .iter()
2158 .map(|(k, v)| format!("{}: {}", k, display(v)))
2159 .collect::<Vec<_>>()
2160 .join(", ")
2161}