From 65b97fe535bd20b2c2b7c0c2714ac7d95648225a Mon Sep 17 00:00:00 2001 From: FelixBrendel Date: Tue, 23 Oct 2018 08:27:42 +0200 Subject: [PATCH] macros --- bin/pre.slime | 68 +++++++++++++++++++++++++++++++++++++++------------ src/ast.c | 4 +++ src/eval.c | 51 ++++++++++++-------------------------- 3 files changed, 71 insertions(+), 52 deletions(-) diff --git a/bin/pre.slime b/bin/pre.slime index e822ea8..2c56339 100644 --- a/bin/pre.slime +++ b/bin/pre.slime @@ -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))) diff --git a/src/ast.c b/src/ast.c index 5b9ef08..b6651c8 100644 --- a/src/ast.c +++ b/src/ast.c @@ -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; diff --git a/src/eval.c b/src/eval.c index 76aae2b..4eb6a81 100644 --- a/src/eval.c +++ b/src/eval.c @@ -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); } }