macros
This commit is contained in:
+52
-16
@@ -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;
|
||||
|
||||
+15
-36
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user