@@ -294,10 +294,8 @@ impl Interpreter {
294294 for arm in & decide. arms {
295295 if self . pattern_matches ( & arm. pattern , & scrutinee) {
296296 self . env . push_scope ( ) ;
297- // Bind pattern variables
298- if let Pattern :: Identifier ( name) = & arm. pattern {
299- self . env . define ( name. clone ( ) , scrutinee. clone ( ) ) ;
300- }
297+ // Bind pattern variables (handles Identifier, Constructor, etc.)
298+ self . bind_pattern ( & arm. pattern , & scrutinee) ;
301299 for stmt in & arm. body {
302300 if let ControlFlow :: Return ( v) = self . execute_statement ( stmt) ? {
303301 self . env . pop_scope ( ) ;
@@ -353,6 +351,45 @@ impl Interpreter {
353351 let lit_value = self . literal_to_value ( lit) ;
354352 value == & lit_value
355353 }
354+ Pattern :: Constructor ( name, inner_pattern) => match ( name. as_str ( ) , value) {
355+ ( "Okay" , Value :: Okay ( inner_val) ) => {
356+ if let Some ( pat) = inner_pattern {
357+ self . pattern_matches ( pat, inner_val)
358+ } else {
359+ true
360+ }
361+ }
362+ ( "Oops" , Value :: Oops ( _) ) => {
363+ // Oops pattern matches any Oops value
364+ // The inner pattern (if any) can bind the error message
365+ true
366+ }
367+ _ => false ,
368+ } ,
369+ }
370+ }
371+
372+ fn bind_pattern ( & mut self , pattern : & Pattern , value : & Value ) {
373+ match pattern {
374+ Pattern :: Identifier ( name) => {
375+ self . env . define ( name. clone ( ) , value. clone ( ) ) ;
376+ }
377+ Pattern :: Constructor ( name, inner_pattern) => {
378+ if let Some ( pat) = inner_pattern {
379+ match ( name. as_str ( ) , value) {
380+ ( "Okay" , Value :: Okay ( inner_val) ) => {
381+ self . bind_pattern ( pat, inner_val) ;
382+ }
383+ ( "Oops" , Value :: Oops ( err_msg) ) => {
384+ self . bind_pattern ( pat, & Value :: String ( err_msg. clone ( ) ) ) ;
385+ }
386+ _ => { }
387+ }
388+ }
389+ }
390+ Pattern :: Wildcard | Pattern :: Literal ( _) => {
391+ // No bindings for wildcards or literals
392+ }
356393 }
357394 }
358395
@@ -413,6 +450,57 @@ impl Interpreter {
413450 . collect :: < Result < _ > > ( ) ?;
414451 Ok ( Value :: Array ( values) )
415452 }
453+ Expr :: Index ( target, index) => {
454+ let target_val = self . evaluate ( target) ?;
455+ let index_val = self . evaluate ( index) ?;
456+ self . apply_index ( target_val, index_val)
457+ }
458+ Expr :: Okay ( inner) => {
459+ let val = self . evaluate ( inner) ?;
460+ Ok ( Value :: Okay ( Box :: new ( val) ) )
461+ }
462+ Expr :: Oops ( inner) => {
463+ let val = self . evaluate ( inner) ?;
464+ match val {
465+ Value :: String ( s) => Ok ( Value :: Oops ( s) ) ,
466+ other => Ok ( Value :: Oops ( other. to_string ( ) ) ) ,
467+ }
468+ }
469+ Expr :: Unwrap ( inner) => {
470+ let val = self . evaluate ( inner) ?;
471+ match val {
472+ Value :: Okay ( v) => Ok ( * v) ,
473+ Value :: Oops ( e) => Err ( RuntimeError :: Complaint ( e) ) ,
474+ other => Ok ( other) , // Non-result values pass through
475+ }
476+ }
477+ }
478+ }
479+
480+ fn apply_index ( & self , target : Value , index : Value ) -> Result < Value > {
481+ let idx = match index {
482+ Value :: Int ( n) => {
483+ if n < 0 {
484+ return Err ( RuntimeError :: IndexOutOfBounds ( n as usize ) ) ;
485+ }
486+ n as usize
487+ }
488+ _ => return Err ( RuntimeError :: TypeError ( "Index must be an integer" . into ( ) ) ) ,
489+ } ;
490+
491+ match target {
492+ Value :: Array ( arr) => arr
493+ . get ( idx)
494+ . cloned ( )
495+ . ok_or ( RuntimeError :: IndexOutOfBounds ( idx) ) ,
496+ Value :: String ( s) => s
497+ . chars ( )
498+ . nth ( idx)
499+ . map ( |c| Value :: String ( c. to_string ( ) ) )
500+ . ok_or ( RuntimeError :: IndexOutOfBounds ( idx) ) ,
501+ _ => Err ( RuntimeError :: TypeError (
502+ "Cannot index this type" . into ( ) ,
503+ ) ) ,
416504 }
417505 }
418506
@@ -469,6 +557,49 @@ impl Interpreter {
469557 _ => Err ( RuntimeError :: TypeError ( "Cannot convert to Int" . into ( ) ) ) ,
470558 }
471559 }
560+ "isOkay" => {
561+ if args. len ( ) != 1 {
562+ return Err ( RuntimeError :: ArityMismatch {
563+ expected : 1 ,
564+ got : args. len ( ) ,
565+ } ) ;
566+ }
567+ Ok ( Some ( Value :: Bool ( args[ 0 ] . is_okay ( ) ) ) )
568+ }
569+ "isOops" => {
570+ if args. len ( ) != 1 {
571+ return Err ( RuntimeError :: ArityMismatch {
572+ expected : 1 ,
573+ got : args. len ( ) ,
574+ } ) ;
575+ }
576+ Ok ( Some ( Value :: Bool ( args[ 0 ] . is_oops ( ) ) ) )
577+ }
578+ "unwrapOr" => {
579+ if args. len ( ) != 2 {
580+ return Err ( RuntimeError :: ArityMismatch {
581+ expected : 2 ,
582+ got : args. len ( ) ,
583+ } ) ;
584+ }
585+ match & args[ 0 ] {
586+ Value :: Okay ( v) => Ok ( Some ( ( * * v) . clone ( ) ) ) ,
587+ Value :: Oops ( _) => Ok ( Some ( args[ 1 ] . clone ( ) ) ) ,
588+ other => Ok ( Some ( other. clone ( ) ) ) ,
589+ }
590+ }
591+ "getError" => {
592+ if args. len ( ) != 1 {
593+ return Err ( RuntimeError :: ArityMismatch {
594+ expected : 1 ,
595+ got : args. len ( ) ,
596+ } ) ;
597+ }
598+ match & args[ 0 ] {
599+ Value :: Oops ( e) => Ok ( Some ( Value :: String ( e. clone ( ) ) ) ) ,
600+ _ => Ok ( Some ( Value :: Unit ) ) ,
601+ }
602+ }
472603 _ => Ok ( None ) , // Not a builtin
473604 }
474605 }
@@ -678,4 +809,99 @@ mod tests {
678809 "# ;
679810 assert ! ( run_program( source) . is_ok( ) ) ;
680811 }
812+
813+ #[ test]
814+ fn test_result_okay ( ) {
815+ let source = r#"
816+ to main() {
817+ remember result = Okay(42);
818+ remember is_ok = isOkay(result);
819+ }
820+ "# ;
821+ assert ! ( run_program( source) . is_ok( ) ) ;
822+ }
823+
824+ #[ test]
825+ fn test_result_oops ( ) {
826+ let source = r#"
827+ to main() {
828+ remember result = Oops("Something went wrong");
829+ remember is_err = isOops(result);
830+ }
831+ "# ;
832+ assert ! ( run_program( source) . is_ok( ) ) ;
833+ }
834+
835+ #[ test]
836+ fn test_unwrap_or ( ) {
837+ let source = r#"
838+ to main() {
839+ remember ok_result = Okay(10);
840+ remember err_result = Oops("error");
841+ remember val1 = unwrapOr(ok_result, 0);
842+ remember val2 = unwrapOr(err_result, 0);
843+ }
844+ "# ;
845+ assert ! ( run_program( source) . is_ok( ) ) ;
846+ }
847+
848+ #[ test]
849+ fn test_array_indexing ( ) {
850+ let source = r#"
851+ to main() {
852+ remember arr = [1, 2, 3, 4, 5];
853+ remember first = arr[0];
854+ remember third = arr[2];
855+ }
856+ "# ;
857+ assert ! ( run_program( source) . is_ok( ) ) ;
858+ }
859+
860+ #[ test]
861+ fn test_string_indexing ( ) {
862+ let source = r#"
863+ to main() {
864+ remember str = "hello";
865+ remember first_char = str[0];
866+ }
867+ "# ;
868+ assert ! ( run_program( source) . is_ok( ) ) ;
869+ }
870+
871+ #[ test]
872+ fn test_decide_with_result ( ) {
873+ let source = r#"
874+ to process(val: Int) -> Result {
875+ when val > 0 {
876+ give back Okay(val * 2);
877+ } otherwise {
878+ give back Oops("Value must be positive");
879+ }
880+ }
881+
882+ to main() {
883+ remember result = process(5);
884+ decide based on result {
885+ Okay(x) -> {
886+ print(x);
887+ }
888+ Oops(e) -> {
889+ print(e);
890+ }
891+ }
892+ }
893+ "# ;
894+ assert ! ( run_program( source) . is_ok( ) ) ;
895+ }
896+
897+ #[ test]
898+ fn test_chained_indexing ( ) {
899+ let source = r#"
900+ to main() {
901+ remember matrix = [[1, 2], [3, 4]];
902+ remember val = matrix[0][1];
903+ }
904+ "# ;
905+ assert ! ( run_program( source) . is_ok( ) ) ;
906+ }
681907}
0 commit comments