diff --git a/bin/pre.slime b/bin/pre.slime index 3b8f203..c815b44 100644 --- a/bin/pre.slime +++ b/bin/pre.slime @@ -124,6 +124,17 @@ by the key 'from' and ends with the number defined in 'to'." (when (< from to) (pair from (range :from (+ 1 from) :to to)))) +(defun range-while (:keys from :defaults-to 0 to) + "Returns a sequence of numbers starting with the number defined +by the key 'from' and ends with the number defined in 'to'." + (define result (list from)) + (mutate from (incr from)) + (while (< from to) + (prog + (append result (copy from)) + (mutate from (incr from)))) + result) + (defun map (fun seq) "Takes a function and a sequence as arguments and returns a new sequence which contains the results of using the first sequences diff --git a/src/ast.c b/src/ast.c index 8fd7c14..90085c1 100644 --- a/src/ast.c +++ b/src/ast.c @@ -156,6 +156,7 @@ typedef enum { Built_In_Read, Built_In_Rest, Built_In_Subtraction, + Built_In_Try, Built_In_Type, Built_In_While, } Built_In_Name; @@ -198,6 +199,7 @@ char* Built_In_Name_to_string(Built_In_Name name) { case Built_In_Read: return "read"; case Built_In_Rest: return "rest"; case Built_In_Subtraction: return "-"; + case Built_In_Try: return "try"; case Built_In_Type: return "type"; case Built_In_While: return "while"; } @@ -315,6 +317,7 @@ Ast_Node* create_ast_node_built_in_function(char* name) { else if (string_equal(name, "quote")) type = Built_In_Quote; else if (string_equal(name, "read")) type = Built_In_Read; else if (string_equal(name, "rest")) type = Built_In_Rest; + else if (string_equal(name, "try")) type = Built_In_Try; else if (string_equal(name, "type")) type = Built_In_Type; else if (string_equal(name, "while")) type = Built_In_While; else return nullptr; diff --git a/src/eval.c b/src/eval.c index 53802f4..bb3d80a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -640,11 +640,21 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { if (arguments_length < 2) { report_error(Error_Type_Wrong_Number_Of_Arguments); } - Ast_Node* condition = arguments->value.pair->first; + Ast_Node* condition_part = arguments->value.pair->first; + Ast_Node* condition; Ast_Node* then_part = arguments->value.pair->rest; Ast_Node* result = create_ast_node_nil(); - while (eval_expr(condition, env)->type != Ast_Node_Type_Nil) { - result = eval_expr(then_part->value.pair->first, env); + + while (true) { + try { + condition = eval_expr(condition_part, env); + } + if (condition->type == Ast_Node_Type_Nil) { + break; + } + try { + result = eval_expr(then_part->value.pair->first, env); + } } return result; @@ -684,6 +694,27 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { } return arguments->value.pair->first; } + case Built_In_Try: { + try { + arguments_length = list_length(arguments); + } + if (arguments_length != 2) { + report_error(Error_Type_Wrong_Number_Of_Arguments); + } + + Ast_Node* try_part = arguments->value.pair->first; + Ast_Node* catch_part = arguments->value.pair->rest->value.pair->first; + Ast_Node* result; + + result = eval_expr(try_part, env); + if (error) { + delete_error(); + try { + result = eval_expr(catch_part, env); + } + } + return result; + } case Built_In_Macro_Define: case Built_In_Define: { try {