| @@ -1,5 +1,37 @@ | |||
| (define nil ()) | |||
| (define pe | |||
| (macro (expr) | |||
| (print expr) | |||
| (print " evaluates to -> ") | |||
| (print (eval expr)) | |||
| (print " | |||
| ") | |||
| nil)) | |||
| (define apply | |||
| (lambda (fun seq) | |||
| (eval (pair fun seq)))) | |||
| (define defun | |||
| (macro (name params :rest body) | |||
| (printf "name" params "params" params "body" body) | |||
| (define name | |||
| (lambda (params) body)))) | |||
| (define when | |||
| (macro (test :rest body) | |||
| (if (eval test) | |||
| (apply prog body) | |||
| nil))) | |||
| (define unless | |||
| (macro (test :rest body) | |||
| (if (eval test) | |||
| nil | |||
| (apply prog body)))) | |||
| (define nil? | |||
| (lambda (x) | |||
| "Checks if the argument is nil." | |||
| @@ -41,14 +73,14 @@ defined by the key 'from' and ends with the number defined in | |||
| nil))) | |||
| (define map | |||
| (lambda (function sequence) | |||
| (lambda (fun seq) | |||
| "Takes a sequence and a function as arguments and returns a | |||
| new sequence which contains the results of using the first | |||
| sequences elemens as argument to that function." | |||
| (if (nil? sequence) | |||
| sequence | |||
| (pair (function (first sequence)) | |||
| (map (rest sequence) function))))) | |||
| (if (nil? seq) | |||
| seq | |||
| (pair (fun (first seq)) | |||
| (map fun (rest seq)))))) | |||
| (define reduce | |||
| (lambda (function sequence) | |||
| @@ -56,7 +88,7 @@ sequences elemens as argument to that function." | |||
| function to the argument sequence. This only works correctly if the | |||
| given function accepts a variable amount of parameters. If your | |||
| funciton is limited to two arguments, use `reduce-binary' instead." | |||
| (eval (pair function sequence)))) | |||
| (apply function sequence))) | |||
| (define reduce-binary | |||
| (lambda (function sequence) | |||
| @@ -78,15 +110,19 @@ as compared to `reduce'." | |||
| (filter (rest sequence) function)) | |||
| (filter (rest sequence) function))))) | |||
| (define printf | |||
| (lambda (:keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||
| (if (and (nil? (first args)) (nil? (rest args))) | |||
| (print end) | |||
| (define printf-quoted | |||
| (macro (:keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||
| (if (nil? args) | |||
| (prog (print (eval end)) nil) | |||
| (prog | |||
| (print (first args)) | |||
| (if (not (nil? (rest args))) | |||
| (print sep)) | |||
| ;; TODO(Felix): later we should use `extend' here: | |||
| ;; (eval (extend (quote (printf :sep sep :end end)) (rest args))) | |||
| (eval (extend '(printf :sep sep :end end) (rest args))) | |||
| nil)))) | |||
| (when (not (nil? (rest args))) (print (eval sep))) | |||
| (define command-args (list :sep (eval sep) :end (eval end))) | |||
| (append command-args (rest args)) | |||
| (apply printf-quoted command-args))))) | |||
| (define printf | |||
| (lambda (:keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||
| (define command-args (list :sep (eval sep) :end (eval end))) | |||
| (append command-args args) | |||
| (apply printf-quoted command-args))) | |||
| @@ -97,6 +97,7 @@ void append_to_keyword_argument_list(Keyword_Arguments* args, | |||
| typedef struct { | |||
| bool is_macro; | |||
| char* docstring; | |||
| Positional_Arguments* positional_arguments; | |||
| Keyword_Arguments* keyword_arguments; | |||
| @@ -126,6 +127,7 @@ typedef enum { | |||
| Built_In_Define, | |||
| Built_In_Mutate, | |||
| Built_In_Lambda, | |||
| Built_In_Macro, | |||
| Built_In_Eval, | |||
| Built_In_Quote, | |||
| Built_In_Prog, | |||
| @@ -159,6 +161,7 @@ char* Built_In_Name_to_string(Built_In_Name name) { | |||
| case Built_In_Less_Equal: return "<="; | |||
| case Built_In_List: return "list"; | |||
| case Built_In_Load: return "load"; | |||
| case Built_In_Macro: return "macro"; | |||
| case Built_In_Multiplication: return "*"; | |||
| case Built_In_Mutate: return "mutate"; | |||
| case Built_In_Not: return "not"; | |||
| @@ -265,6 +268,7 @@ Ast_Node* create_ast_node_built_in_function(char* name) { | |||
| else if (string_equal(name, "define")) type = Built_In_Define; | |||
| else if (string_equal(name, "mutate")) type = Built_In_Mutate; | |||
| else if (string_equal(name, "lambda")) type = Built_In_Lambda; | |||
| else if (string_equal(name, "macro")) type = Built_In_Macro; | |||
| else if (string_equal(name, "eval")) type = Built_In_Eval; | |||
| else if (string_equal(name, "quote")) type = Built_In_Quote; | |||
| else if (string_equal(name, "prog")) type = Built_In_Prog; | |||
| @@ -308,37 +308,6 @@ int list_length(Ast_Node* node) { | |||
| return 0; | |||
| } | |||
| /** | |||
| Copies a list, in that it creates a new list, however the items are | |||
| the same as in the original (same pointers). This is needed to copy | |||
| a list when evaluating a parameters list, but not wanting to change | |||
| the parameters list. This happens if you have someting like: | |||
| (define a 10) | |||
| (define condition (quote (= a 10))) | |||
| (eval condition) | |||
| > 1.00000 | |||
| If we wouldn't copy the parameters list, after calling eval would | |||
| be baked into the quoted list. So even after changing a, the result | |||
| of (eval condition) would be 1.00000. | |||
| **/ | |||
| /* Ast_Node* copy_list(Ast_Node* node) { */ | |||
| /* // we don't copy immutables in here */ | |||
| /* if (node->type != Ast_Node_Type_Pair) { */ | |||
| /* return node; */ | |||
| /* } */ | |||
| /* Ast_Node* result = new(Ast_Node); */ | |||
| /* result->type = Ast_Node_Type_Pair; */ | |||
| /* result->value.pair = new(Pair); */ | |||
| /* result->value.pair->first = copy_list(node->value.pair->first); */ | |||
| /* result->value.pair->rest = copy_list(node->value.pair->rest); */ | |||
| /* return result; */ | |||
| /* } */ | |||
| bool is_truthy (Ast_Node* expression, Environment* env); | |||
| Ast_Node* extract_keyword_value(char* keyword, Parsed_Arguments* args) { | |||
| @@ -385,6 +354,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| create_error(_type, node); \ | |||
| return nullptr; \ | |||
| } | |||
| if (error) | |||
| return nullptr; | |||
| @@ -422,6 +392,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| // check for special form | |||
| if (operator->type == Ast_Node_Type_Built_In_Function) { | |||
| switch (operator->value.built_in_function->type) { | |||
| case Built_In_Macro: | |||
| case Built_In_Lambda: { | |||
| /* | |||
| * (lambda ()) | |||
| @@ -435,6 +406,12 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| Function* function = new(Function); | |||
| if (operator->value.built_in_function->type == Built_In_Macro) { | |||
| function->is_macro = true; | |||
| } else { | |||
| function->is_macro = false; | |||
| } | |||
| // if parameters were specified | |||
| if (arguments->value.pair->first->type != Ast_Node_Type_Nil) { | |||
| try { | |||
| @@ -739,10 +716,14 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| } | |||
| // assume it's lambda function and evaluate the arguments | |||
| try { | |||
| arguments = eval_arguments(arguments, env, &arguments_length); | |||
| } | |||
| if (operator->type == Ast_Node_Type_Function) { | |||
| if (!operator->value.function->is_macro) { | |||
| try { | |||
| arguments = eval_arguments(arguments, env, &arguments_length); | |||
| } | |||
| } | |||
| Ast_Node* result; | |||
| try { | |||
| result = apply_arguments_to_function(arguments, operator->value.function, env); | |||
| @@ -750,9 +731,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) { | |||
| return result; | |||
| } | |||
| } | |||
| default: { | |||
| printf("wtf???????????"); | |||
| report_error(Error_Type_Not_A_Function); | |||
| } | |||
| } | |||