1use crate::eval::{EvalError, Result};
9use oxur_lang::{CoreForm, Expander, Parser};
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct TypedValue {
28 value: i64,
29 type_name: String,
30}
31
32impl TypedValue {
33 pub fn new(value: i64, type_name: impl Into<String>) -> Self {
35 Self { value, type_name: type_name.into() }
36 }
37
38 pub fn value(&self) -> i64 {
40 self.value
41 }
42
43 pub fn type_name(&self) -> &str {
45 &self.type_name
46 }
47}
48
49#[derive(Debug, Clone)]
54pub struct LispEvaluator {
55 variables: HashMap<String, TypedValue>,
57}
58
59impl LispEvaluator {
60 pub fn new() -> Self {
62 Self { variables: HashMap::new() }
63 }
64
65 pub fn try_eval_calculator(&mut self, code: impl AsRef<str>) -> Option<String> {
76 self.try_eval_with_errors(code).ok().flatten()
77 }
78
79 pub fn try_eval_with_errors(&mut self, code: impl AsRef<str>) -> Result<Option<String>> {
86 let expr = match self.parse_simple(code.as_ref()) {
88 Ok(expr) => expr,
89 Err(_) => return Ok(None), };
91
92 if let Expr::List(ref elements) = expr {
94 if let Some(Expr::Symbol(op)) = elements.first() {
95 if op == "def" {
96 return self.eval_def(&elements[1..]).map(Some);
97 }
98 }
99 }
100
101 match self.eval_calculator_expr(&expr) {
103 Ok(result) => Ok(Some(result)),
104 Err(_) => Ok(None), }
106 }
107
108 pub fn get_variables(&self) -> Vec<(String, String)> {
126 self.variables
127 .iter()
128 .map(|(name, typed_value)| (name.clone(), typed_value.type_name().to_string()))
129 .collect()
130 }
131
132 pub fn get_variable_value(&self, name: &str) -> Option<String> {
136 self.variables.get(name).map(|v| v.value().to_string())
137 }
138
139 fn parse_simple(&mut self, code: &str) -> Result<Expr> {
146 let trimmed = code.trim();
147 if trimmed.is_empty() {
148 return Err(EvalError::SyntaxError {
149 msg: "Empty expression".to_string(),
150 pos: oxur_smap::SourcePos::repl(1, 1, 1),
151 });
152 }
153
154 if let Ok(num) = trimmed.parse::<i64>() {
156 return Ok(Expr::Number(num));
157 }
158
159 if trimmed.starts_with('(') && trimmed.ends_with(')') {
161 return self.parse_list(trimmed);
162 }
163
164 Ok(Expr::Symbol(trimmed.to_string()))
166 }
167
168 fn parse_list(&mut self, code: &str) -> Result<Expr> {
170 let inner = &code[1..code.len() - 1].trim();
172
173 if inner.is_empty() {
174 return Ok(Expr::List(vec![]));
175 }
176
177 let tokens = self.tokenize(inner)?;
179
180 let mut elements = Vec::new();
182 for token in tokens {
183 elements.push(self.parse_simple(&token)?);
184 }
185
186 Ok(Expr::List(elements))
187 }
188
189 fn tokenize(&self, input: &str) -> Result<Vec<String>> {
194 let mut tokens = Vec::new();
195 let mut current_start = 0;
196 let mut depth = 0;
197 let bytes = input.as_bytes();
198
199 for (i, &byte) in bytes.iter().enumerate() {
200 match byte {
201 b'(' => {
202 if depth == 0 && i > current_start {
203 let token = input[current_start..i].trim();
204 if !token.is_empty() {
205 tokens.push(token.to_string());
206 }
207 current_start = i;
208 }
209 depth += 1;
210 }
211 b')' => {
212 depth -= 1;
213 if depth == 0 {
214 let token = input[current_start..=i].trim();
215 if !token.is_empty() {
216 tokens.push(token.to_string());
217 }
218 current_start = i + 1;
219 }
220 }
221 b' ' | b'\t' | b'\n' => {
222 if depth == 0 && i > current_start {
223 let token = input[current_start..i].trim();
224 if !token.is_empty() {
225 tokens.push(token.to_string());
226 }
227 current_start = i + 1;
228 }
229 }
230 _ => {}
231 }
232 }
233
234 if current_start < input.len() {
236 let token = input[current_start..].trim();
237 if !token.is_empty() {
238 tokens.push(token.to_string());
239 }
240 }
241
242 if depth != 0 {
243 return Err(EvalError::SyntaxError {
244 msg: "Mismatched parentheses".to_string(),
245 pos: oxur_smap::SourcePos::repl(1, 1, 1),
246 });
247 }
248
249 Ok(tokens)
250 }
251
252 fn eval_calculator_expr(&self, expr: &Expr) -> Result<String> {
254 match expr {
255 Expr::Number(n) => Ok(n.to_string()),
256
257 Expr::Symbol(s) => {
258 if let Some(typed_value) = self.variables.get(s) {
260 Ok(typed_value.value().to_string())
261 } else {
262 Err(EvalError::RuntimeError {
263 msg: format!("Undefined variable: {}", s),
264 pos: oxur_smap::SourcePos::repl(1, 1, 1),
265 })
266 }
267 }
268
269 Expr::List(elements) => {
270 if elements.is_empty() {
271 return Err(EvalError::SyntaxError {
272 msg: "Empty list".to_string(),
273 pos: oxur_smap::SourcePos::repl(1, 1, 1),
274 });
275 }
276
277 let op = match &elements[0] {
279 Expr::Symbol(s) => s.as_str(),
280 _ => {
281 return Err(EvalError::SyntaxError {
282 msg: "First element must be an operator".to_string(),
283 pos: oxur_smap::SourcePos::repl(1, 1, 1),
284 })
285 }
286 };
287
288 let args: Result<Vec<i64>> = elements[1..]
290 .iter()
291 .map(|e| {
292 let result = self.eval_calculator_expr(e)?;
293 result.parse::<i64>().map_err(|_| EvalError::RuntimeError {
294 msg: format!("Not a number: {}", result),
295 pos: oxur_smap::SourcePos::repl(1, 1, 1),
296 })
297 })
298 .collect();
299
300 let args = args?;
301
302 self.apply_operator(op, &args)
304 }
305 }
306 }
307
308 fn apply_operator(&self, op: &str, args: &[i64]) -> Result<String> {
310 if args.is_empty() {
311 return Err(EvalError::SyntaxError {
312 msg: format!("Operator '{}' requires at least one argument", op),
313 pos: oxur_smap::SourcePos::repl(1, 1, 1),
314 });
315 }
316
317 match op {
318 "+" => {
319 let sum: i64 = args.iter().sum();
320 Ok(sum.to_string())
321 }
322 "-" => {
323 if args.len() == 1 {
324 Ok((-args[0]).to_string())
325 } else {
326 let result = args.iter().skip(1).fold(args[0], |acc, &x| acc - x);
327 Ok(result.to_string())
328 }
329 }
330 "*" => {
331 let product: i64 = args.iter().product();
332 Ok(product.to_string())
333 }
334 "/" => {
335 if args.len() == 1 {
336 return Err(EvalError::RuntimeError {
337 msg: "Division requires at least two arguments".to_string(),
338 pos: oxur_smap::SourcePos::repl(1, 1, 1),
339 });
340 }
341
342 let result = args.iter().skip(1).try_fold(args[0], |acc, &x| {
343 if x == 0 {
344 Err(EvalError::RuntimeError {
345 msg: "Division by zero".to_string(),
346 pos: oxur_smap::SourcePos::repl(1, 1, 1),
347 })
348 } else {
349 Ok(acc / x)
350 }
351 })?;
352
353 Ok(result.to_string())
354 }
355 _ => Err(EvalError::UnsupportedOperation {
356 msg: format!("Unknown operator in calculator mode: {}", op),
357 pos: oxur_smap::SourcePos::repl(1, 1, 1),
358 }),
359 }
360 }
361
362 fn eval_def(&mut self, args: &[Expr]) -> Result<String> {
383 if args.len() != 2 {
385 return Err(EvalError::SyntaxError {
386 msg: format!("def requires 2 arguments, got {}", args.len()),
387 pos: oxur_smap::SourcePos::repl(1, 1, 1),
388 });
389 }
390
391 let (var_name, type_name) = self.parse_typed_identifier(&args[0])?;
393
394 if type_name != "i32" && type_name != "i64" {
396 return Err(EvalError::TypeError {
397 msg: format!(
398 "Only i32 and i64 types are supported in calculator mode, got: {}",
399 type_name
400 ),
401 pos: oxur_smap::SourcePos::repl(1, 1, 1),
402 });
403 }
404
405 let value_str = self.eval_calculator_expr(&args[1])?;
407 let value = value_str.parse::<i64>().map_err(|_| EvalError::RuntimeError {
408 msg: format!("Value must be an integer, got: {}", value_str),
409 pos: oxur_smap::SourcePos::repl(1, 1, 1),
410 })?;
411
412 self.variables.insert(var_name.clone(), TypedValue::new(value, type_name));
414
415 Ok(value.to_string())
417 }
418
419 fn parse_typed_identifier(&self, expr: &Expr) -> Result<(String, String)> {
433 match expr {
434 Expr::Symbol(s) => {
435 if let Some(colon_pos) = s.find(':') {
437 let var_name = s[..colon_pos].to_string();
438 let type_name = s[colon_pos + 1..].to_string();
439
440 if var_name.is_empty() {
441 return Err(EvalError::SyntaxError {
442 msg: "Variable name cannot be empty".to_string(),
443 pos: oxur_smap::SourcePos::repl(1, 1, 1),
444 });
445 }
446
447 if type_name.is_empty() {
448 return Err(EvalError::SyntaxError {
449 msg: "Type name cannot be empty".to_string(),
450 pos: oxur_smap::SourcePos::repl(1, 1, 1),
451 });
452 }
453
454 Ok((var_name, type_name))
455 } else {
456 Err(EvalError::SyntaxError {
457 msg: format!("Expected type annotation 'varname:type', got: {}", s),
458 pos: oxur_smap::SourcePos::repl(1, 1, 1),
459 })
460 }
461 }
462 _ => Err(EvalError::SyntaxError {
463 msg: "Expected symbol with type annotation".to_string(),
464 pos: oxur_smap::SourcePos::repl(1, 1, 1),
465 }),
466 }
467 }
468
469 pub fn parse(&mut self, code: impl AsRef<str>) -> Result<Vec<CoreForm>> {
474 let mut parser = Parser::new(code.as_ref().to_string());
476 let surface_forms = parser.parse().map_err(|e| EvalError::SyntaxError {
477 msg: format!("Parse error: {}", e),
478 pos: oxur_smap::SourcePos::repl(1, 1, 1),
479 })?;
480
481 let mut expander = Expander::new();
483 expander.expand(surface_forms).map_err(|e| EvalError::SyntaxError {
484 msg: format!("Expansion error: {}", e),
485 pos: oxur_smap::SourcePos::repl(1, 1, 1),
486 })
487 }
488}
489
490impl Default for LispEvaluator {
491 fn default() -> Self {
492 Self::new()
493 }
494}
495
496#[derive(Debug, Clone, PartialEq)]
498enum Expr {
499 Number(i64),
500 Symbol(String),
501 List(Vec<Expr>),
502}
503
504#[cfg(test)]
505mod tests {
506 use super::*;
507
508 #[test]
509 fn test_calculator_simple_addition() {
510 let mut eval = LispEvaluator::new();
511 assert_eq!(eval.try_eval_calculator("(+ 1 2)"), Some("3".to_string()));
512 }
513
514 #[test]
515 fn test_calculator_simple_subtraction() {
516 let mut eval = LispEvaluator::new();
517 assert_eq!(eval.try_eval_calculator("(- 10 5)"), Some("5".to_string()));
518 }
519
520 #[test]
521 fn test_calculator_simple_multiplication() {
522 let mut eval = LispEvaluator::new();
523 assert_eq!(eval.try_eval_calculator("(* 3 4)"), Some("12".to_string()));
524 }
525
526 #[test]
527 fn test_calculator_simple_division() {
528 let mut eval = LispEvaluator::new();
529 assert_eq!(eval.try_eval_calculator("(/ 10 2)"), Some("5".to_string()));
530 }
531
532 #[test]
533 fn test_calculator_multiple_args() {
534 let mut eval = LispEvaluator::new();
535 assert_eq!(eval.try_eval_calculator("(+ 1 2 3 4)"), Some("10".to_string()));
536 assert_eq!(eval.try_eval_calculator("(* 2 3 4)"), Some("24".to_string()));
537 }
538
539 #[test]
540 fn test_calculator_nested_expressions() {
541 let mut eval = LispEvaluator::new();
542 assert_eq!(eval.try_eval_calculator("(+ (* 2 3) 4)"), Some("10".to_string()));
543 assert_eq!(eval.try_eval_calculator("(* (+ 1 2) (- 10 5))"), Some("15".to_string()));
544 }
545
546 #[test]
547 fn test_calculator_unary_minus() {
548 let mut eval = LispEvaluator::new();
549 assert_eq!(eval.try_eval_calculator("(- 5)"), Some("-5".to_string()));
550 }
551
552 #[test]
553 fn test_calculator_division_by_zero() {
554 let mut eval = LispEvaluator::new();
555 assert_eq!(eval.try_eval_calculator("(/ 10 0)"), None);
556 }
557
558 #[test]
559 fn test_calculator_invalid_operator() {
560 let mut eval = LispEvaluator::new();
561 assert_eq!(eval.try_eval_calculator("(foo 1 2)"), None);
562 }
563
564 #[test]
565 fn test_calculator_variables_not_supported() {
566 let mut eval = LispEvaluator::new();
567 assert_eq!(eval.try_eval_calculator("(+ x 2)"), None);
568 }
569
570 #[test]
571 fn test_calculator_empty_list() {
572 let mut eval = LispEvaluator::new();
573 assert_eq!(eval.try_eval_calculator("()"), None);
574 }
575
576 #[test]
577 fn test_parse_simple_number() {
578 let mut eval = LispEvaluator::new();
579 let expr = eval.parse_simple("42").unwrap();
580 assert_eq!(expr, Expr::Number(42));
581 }
582
583 #[test]
584 fn test_parse_simple_symbol() {
585 let mut eval = LispEvaluator::new();
586 let expr = eval.parse_simple("+").unwrap();
587 assert_eq!(expr, Expr::Symbol("+".to_string()));
588 }
589
590 #[test]
591 fn test_parse_simple_list() {
592 let mut eval = LispEvaluator::new();
593 let expr = eval.parse_simple("(+ 1 2)").unwrap();
594 assert_eq!(
595 expr,
596 Expr::List(vec![Expr::Symbol("+".to_string()), Expr::Number(1), Expr::Number(2),])
597 );
598 }
599
600 #[test]
601 fn test_parse_nested_list() {
602 let mut eval = LispEvaluator::new();
603 let expr = eval.parse_simple("(+ (* 2 3) 4)").unwrap();
604 assert_eq!(
605 expr,
606 Expr::List(vec![
607 Expr::Symbol("+".to_string()),
608 Expr::List(vec![Expr::Symbol("*".to_string()), Expr::Number(2), Expr::Number(3),]),
609 Expr::Number(4),
610 ])
611 );
612 }
613
614 #[test]
615 fn test_tokenize_simple() {
616 let eval = LispEvaluator::new();
617 let tokens = eval.tokenize("+ 1 2").unwrap();
618 assert_eq!(tokens, vec!["+".to_string(), "1".to_string(), "2".to_string()]);
619 }
620
621 #[test]
622 fn test_tokenize_nested() {
623 let eval = LispEvaluator::new();
624 let tokens = eval.tokenize("+ (* 2 3) 4").unwrap();
625 assert_eq!(tokens, vec!["+".to_string(), "(* 2 3)".to_string(), "4".to_string()]);
626 }
627
628 #[test]
629 fn test_tokenize_mismatched_parens() {
630 let eval = LispEvaluator::new();
631 let result = eval.tokenize("(+ 1 2");
632 assert!(result.is_err());
633 }
634
635 #[test]
636 fn test_apply_operator_addition() {
637 let eval = LispEvaluator::new();
638 assert_eq!(eval.apply_operator("+", &[1, 2, 3]).unwrap(), "6");
639 }
640
641 #[test]
642 fn test_apply_operator_subtraction() {
643 let eval = LispEvaluator::new();
644 assert_eq!(eval.apply_operator("-", &[10, 3, 2]).unwrap(), "5");
645 }
646
647 #[test]
648 fn test_apply_operator_multiplication() {
649 let eval = LispEvaluator::new();
650 assert_eq!(eval.apply_operator("*", &[2, 3, 4]).unwrap(), "24");
651 }
652
653 #[test]
654 fn test_apply_operator_division() {
655 let eval = LispEvaluator::new();
656 assert_eq!(eval.apply_operator("/", &[20, 2, 2]).unwrap(), "5");
657 }
658
659 #[test]
660 fn test_apply_operator_unknown() {
661 let eval = LispEvaluator::new();
662 assert!(eval.apply_operator("foo", &[1, 2]).is_err());
663 }
664
665 #[test]
666 fn test_parse_simple_expression() {
667 let mut eval = LispEvaluator::new();
668 let forms = eval.parse("42").unwrap();
669
670 assert_eq!(forms.len(), 1);
671 match &forms[0] {
672 CoreForm::Number { value, .. } => assert_eq!(value, &42),
673 _ => panic!("Expected Number"),
674 }
675 }
676
677 #[test]
678 fn test_parse_symbol() {
679 let mut eval = LispEvaluator::new();
680 let forms = eval.parse("test-symbol").unwrap();
681
682 assert_eq!(forms.len(), 1);
683 match &forms[0] {
684 CoreForm::Symbol { name, .. } => assert_eq!(name, "test-symbol"),
685 _ => panic!("Expected Symbol"),
686 }
687 }
688
689 #[test]
690 fn test_parse_string() {
691 let mut eval = LispEvaluator::new();
692 let forms = eval.parse(r#""hello world""#).unwrap();
693
694 assert_eq!(forms.len(), 1);
695 match &forms[0] {
696 CoreForm::String { value, .. } => assert_eq!(value, "hello world"),
697 _ => panic!("Expected String"),
698 }
699 }
700
701 #[test]
702 fn test_parse_list() {
703 let mut eval = LispEvaluator::new();
704 let forms = eval.parse("(+ 1 2)").unwrap();
705
706 assert_eq!(forms.len(), 1);
707 match &forms[0] {
708 CoreForm::List { elements, .. } => assert_eq!(elements.len(), 3),
709 _ => panic!("Expected List"),
710 }
711 }
712
713 #[test]
714 fn test_parse_deffn_expands_to_define_func() {
715 let mut eval = LispEvaluator::new();
716 let forms = eval.parse(r#"(deffn main () (println! "Hello"))"#).unwrap();
717
718 assert_eq!(forms.len(), 1);
719
720 match &forms[0] {
722 CoreForm::DefineFunc { name, params, body, .. } => {
723 assert_eq!(name, "main");
724 assert!(params.is_empty());
725
726 match &**body {
728 CoreForm::List { elements, .. } => {
729 assert_eq!(elements.len(), 2);
730 match &elements[0] {
731 CoreForm::Symbol { name, .. } => assert_eq!(name, "println!"),
732 _ => panic!("Expected println! symbol"),
733 }
734 }
735 _ => panic!("Expected List as body"),
736 }
737 }
738 other => panic!("Expected DefineFunc, got {:?}", other),
739 }
740 }
741
742 #[test]
743 fn test_parse_deffn_with_params() {
744 let mut eval = LispEvaluator::new();
745 let forms = eval.parse("(deffn add (a b) (+ a b))").unwrap();
746
747 assert_eq!(forms.len(), 1);
748
749 match &forms[0] {
750 CoreForm::DefineFunc { name, params, .. } => {
751 assert_eq!(name, "add");
752 assert_eq!(params.len(), 2);
753 assert_eq!(params[0], "a");
754 assert_eq!(params[1], "b");
755 }
756 other => panic!("Expected DefineFunc, got {:?}", other),
757 }
758 }
759
760 #[test]
763 fn test_def_simple_literal() {
764 let mut eval = LispEvaluator::new();
765 let result = eval.try_eval_calculator("(def x:i32 42)");
766 assert_eq!(result, Some("42".to_string()));
767 }
768
769 #[test]
770 fn test_def_with_i64() {
771 let mut eval = LispEvaluator::new();
772 let result = eval.try_eval_calculator("(def y:i64 1000)");
773 assert_eq!(result, Some("1000".to_string()));
774 }
775
776 #[test]
777 fn test_def_with_expression() {
778 let mut eval = LispEvaluator::new();
779 let result = eval.try_eval_calculator("(def z:i32 (+ 1 2))");
780 assert_eq!(result, Some("3".to_string()));
781 }
782
783 #[test]
784 fn test_def_with_nested_expression() {
785 let mut eval = LispEvaluator::new();
786 let result = eval.try_eval_calculator("(def result:i32 (* (+ 2 3) 4))");
787 assert_eq!(result, Some("20".to_string()));
788 }
789
790 #[test]
791 fn test_variable_lookup_after_def() {
792 let mut eval = LispEvaluator::new();
793
794 eval.try_eval_calculator("(def x:i32 42)");
796
797 let result = eval.try_eval_calculator("x");
799 assert_eq!(result, Some("42".to_string()));
800 }
801
802 #[test]
803 fn test_use_variable_in_expression() {
804 let mut eval = LispEvaluator::new();
805
806 eval.try_eval_calculator("(def x:i32 10)");
808
809 let result = eval.try_eval_calculator("(+ x 5)");
811 assert_eq!(result, Some("15".to_string()));
812 }
813
814 #[test]
815 fn test_multiple_variables() {
816 let mut eval = LispEvaluator::new();
817
818 eval.try_eval_calculator("(def x:i32 10)");
819 eval.try_eval_calculator("(def y:i32 20)");
820 eval.try_eval_calculator("(def z:i32 5)");
821
822 let result = eval.try_eval_calculator("(+ x y z)");
823 assert_eq!(result, Some("35".to_string()));
824 }
825
826 #[test]
827 fn test_def_using_existing_variable() {
828 let mut eval = LispEvaluator::new();
829
830 eval.try_eval_calculator("(def x:i32 10)");
831 eval.try_eval_calculator("(def y:i32 (+ x 5))");
832
833 let result = eval.try_eval_calculator("y");
834 assert_eq!(result, Some("15".to_string()));
835 }
836
837 #[test]
838 fn test_variable_shadowing() {
839 let mut eval = LispEvaluator::new();
840
841 eval.try_eval_calculator("(def x:i32 10)");
842 assert_eq!(eval.try_eval_calculator("x"), Some("10".to_string()));
843
844 eval.try_eval_calculator("(def x:i32 20)");
846 assert_eq!(eval.try_eval_calculator("x"), Some("20".to_string()));
847 }
848
849 #[test]
850 fn test_def_with_negative_value() {
851 let mut eval = LispEvaluator::new();
852 let result = eval.try_eval_calculator("(def neg:i32 (- 5))");
853 assert_eq!(result, Some("-5".to_string()));
854 }
855
856 #[test]
857 fn test_complex_expression_with_variables() {
858 let mut eval = LispEvaluator::new();
859
860 eval.try_eval_calculator("(def a:i32 10)");
861 eval.try_eval_calculator("(def b:i32 20)");
862 eval.try_eval_calculator("(def c:i32 (+ (* a 2) b))");
863
864 assert_eq!(eval.try_eval_calculator("c"), Some("40".to_string()));
866 }
867
868 #[test]
871 fn test_def_wrong_number_of_args_too_few() {
872 let mut eval = LispEvaluator::new();
873 let result = eval.try_eval_calculator("(def x:i32)");
874 assert_eq!(result, None); }
876
877 #[test]
878 fn test_def_wrong_number_of_args_too_many() {
879 let mut eval = LispEvaluator::new();
880 let result = eval.try_eval_calculator("(def x:i32 42 extra)");
881 assert_eq!(result, None); }
883
884 #[test]
885 fn test_def_missing_type_annotation() {
886 let mut eval = LispEvaluator::new();
887 let result = eval.try_eval_calculator("(def x 42)");
888 assert_eq!(result, None); }
890
891 #[test]
892 fn test_def_invalid_type() {
893 let mut eval = LispEvaluator::new();
894 let result = eval.try_eval_calculator("(def x:String 42)");
895 assert_eq!(result, None); }
897
898 #[test]
899 fn test_def_invalid_type_f64() {
900 let mut eval = LispEvaluator::new();
901 let result = eval.try_eval_calculator("(def x:f64 42)");
902 assert_eq!(result, None); }
904
905 #[test]
906 fn test_undefined_variable_lookup() {
907 let mut eval = LispEvaluator::new();
908 let result = eval.try_eval_calculator("undefined_var");
909 assert_eq!(result, None); }
911
912 #[test]
913 fn test_undefined_variable_in_expression() {
914 let mut eval = LispEvaluator::new();
915 let result = eval.try_eval_calculator("(+ undefined_var 5)");
916 assert_eq!(result, None); }
918
919 #[test]
920 fn test_def_empty_variable_name() {
921 let mut eval = LispEvaluator::new();
922 let result = eval.try_eval_calculator("(def :i32 42)");
923 assert_eq!(result, None); }
925
926 #[test]
927 fn test_def_empty_type_name() {
928 let mut eval = LispEvaluator::new();
929 let result = eval.try_eval_calculator("(def x: 42)");
930 assert_eq!(result, None); }
932
933 #[test]
934 fn test_def_no_colon_in_identifier() {
935 let mut eval = LispEvaluator::new();
936 let result = eval.try_eval_calculator("(def xi32 42)");
937 assert_eq!(result, None); }
939
940 #[test]
941 fn test_typed_value_creation() {
942 let val = TypedValue::new(42, "i32");
943 assert_eq!(val.value(), 42);
944 assert_eq!(val.type_name(), "i32");
945 }
946
947 #[test]
948 fn test_typed_value_equality() {
949 let val1 = TypedValue::new(42, "i32");
950 let val2 = TypedValue::new(42, "i32");
951 let val3 = TypedValue::new(43, "i32");
952 let val4 = TypedValue::new(42, "i64");
953
954 assert_eq!(val1, val2);
955 assert_ne!(val1, val3);
956 assert_ne!(val1, val4);
957 }
958
959 #[test]
960 fn test_typed_value_clone() {
961 let val1 = TypedValue::new(42, "i32");
962 let val2 = val1.clone();
963 assert_eq!(val1, val2);
964 }
965}