Need macros nextmaster
| @@ -1,196 +1,197 @@ | |||||
| (define defmacro | (define defmacro | ||||
| (macro (@name @params :rest @body) | (macro (@name @params :rest @body) | ||||
| "Macro for creating macros with a more concise syntax." | "Macro for creating macros with a more concise syntax." | ||||
| (eval (pair 'define (pair @name (pair (pair 'macro (pair @params @body)) nil)))))) | |||||
| (eval (pair 'define-upwards (pair @name (pair (pair 'macro (pair @params @body)) nil)))))) | |||||
| (defmacro defun (@name @params :rest @body) | |||||
| (define defun | |||||
| (macro (@name @params :rest @body) | |||||
| "Macro for creating functions with a more concise syntax." | "Macro for creating functions with a more concise syntax." | ||||
| (eval (pair 'define (pair @name (pair (pair 'lambda (pair @params @body)) nil))))) | |||||
| (defun nil? (x) | |||||
| "Checks if the argument is nil." | |||||
| (= x nil)) | |||||
| (defun number? (x) | |||||
| "Checks if the argument is a number." | |||||
| (= (type x) :number)) | |||||
| (defun symbol? (x) | |||||
| "Checks if the argument is a symbol." | |||||
| (= (type x) :symbol)) | |||||
| (defun keyword? (x) | |||||
| "Checks if the argument is a keyword." | |||||
| (= (type x) :keyword)) | |||||
| (defun pair? (x) | |||||
| "Checks if the argument is a pair." | |||||
| (= (type x) :pair)) | |||||
| (defun string? (x) | |||||
| "Checks if the argument is a string." | |||||
| (= (type x) :string)) | |||||
| (defun dynamic-function? (x) | |||||
| "Checks if the argument is a function." | |||||
| (= (type x) :dynamic-function)) | |||||
| (defun dynamic-macro? (x) | |||||
| "Checks if the argument is a macro." | |||||
| (= (type x) :dynamic-macro)) | |||||
| (defun built-in-function? (x) | |||||
| "Checks if the argument is a built-in function." | |||||
| (= (type x) :built-in-function)) | |||||
| (defun apply (fun seq) | |||||
| "Applies the funciton to the sequence, as in calls the funciton with | |||||
| ithe sequence as arguemens." | |||||
| (eval (pair fun seq))) | |||||
| (defmacro when (@test :rest @body) | |||||
| "Executes the code in :rest if test is true." | |||||
| (if (eval @test) | |||||
| (eval (pair prog @body)) | |||||
| nil)) | |||||
| (defmacro unless (@test :rest @body) | |||||
| "Executes the code in :rest if test is false." | |||||
| (if (eval @test) | |||||
| nil | |||||
| (eval (pair prog @body)))) | |||||
| (defun end (seq) | |||||
| "Returns the last pair in the sqeuence." | |||||
| (if (or (nil? seq) (not (pair? (rest seq)))) | |||||
| seq | |||||
| (end (rest seq)))) | |||||
| (defun last (seq) | |||||
| "Returns the (first) of the last (pair) of the given sequence." | |||||
| (first (end seq))) | |||||
| (defun extend (seq elem) | |||||
| "Extends a list with the given element, by putting it in | |||||
| the (rest) of the last element of the sequence." | |||||
| (when (pair? seq) | |||||
| (define e (end seq)) | |||||
| (mutate e (pair (first e) elem))) | |||||
| seq) | |||||
| (defun incr (val) | |||||
| "Adds one to the argument." | |||||
| (+ val 1)) | |||||
| (defun decr (val) | |||||
| "Subtracts one from the argument." | |||||
| (- val 1)) | |||||
| (defun append (seq elem) | |||||
| "Appends an element to a sequence, by extendeing the list | |||||
| with (pair elem nil)." | |||||
| (extend seq (pair elem nil))) | |||||
| (defun length (seq) | |||||
| "Returns the length of the given sequence." | |||||
| (if (nil? seq) | |||||
| 0 | |||||
| (incr (length (rest seq))))) | |||||
| (defmacro n-times (@times @action) | |||||
| "Executes @action @times times." | |||||
| (unless (<= (eval @times) 0) | |||||
| (eval @action) | |||||
| (apply n-times (list (list - @times 1) @action)))) | |||||
| (defmacro for (@symbol @from @to :rest @for-body) | |||||
| "Designed to resemble a C style for loop. It takes a symbol as | |||||
| well as its starting number and end number and executes the | |||||
| @for-body with the defined symbol for all numbers between @from | |||||
| to @to, where @to is exclusive." | |||||
| (if (< (eval @from) (eval @to)) | |||||
| (macro-define @op incr) | |||||
| (if (> (eval @from) (eval @to)) | |||||
| (macro-define @op decr) | |||||
| (macro-define @op nil))) | |||||
| (when @op | |||||
| (macro-define (eval @symbol) (eval @from)) | |||||
| (eval (pair prog @for-body)) | |||||
| (eval (extend (list for @symbol (@op @from) @to) @for-body)))) | |||||
| (defun range (: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'." | |||||
| (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 (copy from))) | |||||
| (define head result) | |||||
| (mutate from (incr from)) | |||||
| (while (< from to) | |||||
| (prog | |||||
| (mutate head (pair (first head) (pair (copy from) nil))) | |||||
| (define head (rest head)) | |||||
| (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 | |||||
| elemens as argument to that function." | |||||
| (if (nil? seq) | |||||
| seq | |||||
| (pair (fun (first seq)) | |||||
| (map fun (rest seq))))) | |||||
| (defun reduce (fun seq) | |||||
| "Takes a function and a sequence as arguments and applies the | |||||
| 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." | |||||
| (apply fun seq)) | |||||
| (defun reduce-binary (fun seq) | |||||
| "Takes a function and a sequence as arguments and applies the | |||||
| function to the argument sequence. reduce-binary applies the | |||||
| arguments `pair-wise' which means it works with binary functions | |||||
| as compared to `reduce'." | |||||
| (if (nil? (rest seq)) | |||||
| (first seq) | |||||
| (fun (first seq) | |||||
| (reduce-binary fun (rest seq))))) | |||||
| (defun filter (fun seq) | |||||
| "Takes a function and a sequence as arguments and applies the | |||||
| function to every value in the sequence. If the result of that | |||||
| funciton application returns a truthy value, the original value is | |||||
| added to a list, which in the end is returned." | |||||
| (when seq | |||||
| (if (fun (first seq)) | |||||
| (pair (first seq) | |||||
| (filter fun (rest seq))) | |||||
| (filter fun (rest seq))))) | |||||
| (defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||||
| "A wrapper for the built-in (print) that accepts a variable number | |||||
| of arguments and also provides keywords for specifying the printed | |||||
| separators between the arguments and what should be printed after the | |||||
| las argument." | |||||
| (defmacro printf-quoted (:keys @sep @end :rest @args) | |||||
| (if (nil? @args) | |||||
| (prog (print (eval @end)) nil) | |||||
| (prog | |||||
| (print (first @args)) | |||||
| (unless (nil? (rest @args)) | |||||
| (print (eval @sep))) | |||||
| (eval (pair printf-quoted | |||||
| (extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args))))))) | |||||
| (eval (pair printf-quoted (extend (list :@sep (eval sep) :@end (eval end)) args)))) | |||||
| (defmacro pe (@expr) | |||||
| (printf @expr "evaluates to" (eval @expr))) | |||||
| (eval (pair 'define-upwards (pair @name (pair (pair 'lambda (pair @params @body)) nil)))))) | |||||
| ;; (defun nil? (x) | |||||
| ;; "Checks if the argument is nil." | |||||
| ;; (= x nil)) | |||||
| ;; (defun number? (x) | |||||
| ;; "Checks if the argument is a number." | |||||
| ;; (= (type x) :number)) | |||||
| ;; (defun symbol? (x) | |||||
| ;; "Checks if the argument is a symbol." | |||||
| ;; (= (type x) :symbol)) | |||||
| ;; (defun keyword? (x) | |||||
| ;; "Checks if the argument is a keyword." | |||||
| ;; (= (type x) :keyword)) | |||||
| ;; (defun pair? (x) | |||||
| ;; "Checks if the argument is a pair." | |||||
| ;; (= (type x) :pair)) | |||||
| ;; (defun string? (x) | |||||
| ;; "Checks if the argument is a string." | |||||
| ;; (= (type x) :string)) | |||||
| ;; (defun dynamic-function? (x) | |||||
| ;; "Checks if the argument is a function." | |||||
| ;; (= (type x) :dynamic-function)) | |||||
| ;; (defun dynamic-macro? (x) | |||||
| ;; "Checks if the argument is a macro." | |||||
| ;; (= (type x) :dynamic-macro)) | |||||
| ;; (defun built-in-function? (x) | |||||
| ;; "Checks if the argument is a built-in function." | |||||
| ;; (= (type x) :built-in-function)) | |||||
| ;; (defun apply (fun seq) | |||||
| ;; "Applies the funciton to the sequence, as in calls the function | |||||
| ;; with ithe sequence as arguemens." | |||||
| ;; (eval (pair fun seq))) | |||||
| ;; (defmacro when (@test :rest @body) | |||||
| ;; "Executes the code in :rest if test is true." | |||||
| ;; (if (eval @test) | |||||
| ;; (eval (pair prog @body)) | |||||
| ;; nil)) | |||||
| ;; (defmacro unless (@test :rest @body) | |||||
| ;; "Executes the code in :rest if test is false." | |||||
| ;; (if (eval @test) | |||||
| ;; nil | |||||
| ;; (eval (pair prog @body)))) | |||||
| ;; (defun end (seq) | |||||
| ;; "Returns the last pair in the sqeuence." | |||||
| ;; (if (or (nil? seq) (not (pair? (rest seq)))) | |||||
| ;; seq | |||||
| ;; (end (rest seq)))) | |||||
| ;; (defun last (seq) | |||||
| ;; "Returns the (first) of the last (pair) of the given sequence." | |||||
| ;; (first (end seq))) | |||||
| ;; (defun extend (seq elem) | |||||
| ;; "Extends a list with the given element, by putting it in | |||||
| ;; the (rest) of the last element of the sequence." | |||||
| ;; (when (pair? seq) | |||||
| ;; (define e (end seq)) | |||||
| ;; (mutate e (pair (first e) elem))) | |||||
| ;; seq) | |||||
| ;; (defun incr (val) | |||||
| ;; "Adds one to the argument." | |||||
| ;; (+ val 1)) | |||||
| ;; (defun decr (val) | |||||
| ;; "Subtracts one from the argument." | |||||
| ;; (- val 1)) | |||||
| ;; (defun append (seq elem) | |||||
| ;; "Appends an element to a sequence, by extendeing the list | |||||
| ;; with (pair elem nil)." | |||||
| ;; (extend seq (pair elem nil))) | |||||
| ;; (defun length (seq) | |||||
| ;; "Returns the length of the given sequence." | |||||
| ;; (if (nil? seq) | |||||
| ;; 0 | |||||
| ;; (incr (length (rest seq))))) | |||||
| ;; (defmacro n-times (@times @action) | |||||
| ;; "Executes @action @times times." | |||||
| ;; (unless (<= (eval @times) 0) | |||||
| ;; (eval @action) | |||||
| ;; (apply n-times (list (list - @times 1) @action)))) | |||||
| ;; (defmacro for (@symbol @from @to :rest @for-body) | |||||
| ;; "Designed to resemble a C style for loop. It takes a symbol as | |||||
| ;; well as its starting number and end number and executes the | |||||
| ;; @for-body with the defined symbol for all numbers between @from | |||||
| ;; to @to, where @to is exclusive." | |||||
| ;; (if (< (eval @from) (eval @to)) | |||||
| ;; (macro-define @op incr) | |||||
| ;; (if (> (eval @from) (eval @to)) | |||||
| ;; (macro-define @op decr) | |||||
| ;; (macro-define @op nil))) | |||||
| ;; (when @op | |||||
| ;; (macro-define (eval @symbol) (eval @from)) | |||||
| ;; (eval (pair prog @for-body)) | |||||
| ;; (eval (extend (list for @symbol (@op @from) @to) @for-body)))) | |||||
| ;; (defun range (: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'." | |||||
| ;; (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 (copy from))) | |||||
| ;; (define head result) | |||||
| ;; (mutate from (incr from)) | |||||
| ;; (while (< from to) | |||||
| ;; (prog | |||||
| ;; (mutate head (pair (first head) (pair (copy from) nil))) | |||||
| ;; (define head (rest head)) | |||||
| ;; (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 | |||||
| ;; elemens as argument to that function." | |||||
| ;; (if (nil? seq) | |||||
| ;; seq | |||||
| ;; (pair (fun (first seq)) | |||||
| ;; (map fun (rest seq))))) | |||||
| ;; (defun reduce (fun seq) | |||||
| ;; "Takes a function and a sequence as arguments and applies the | |||||
| ;; 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." | |||||
| ;; (apply fun seq)) | |||||
| ;; (defun reduce-binary (fun seq) | |||||
| ;; "Takes a function and a sequence as arguments and applies the | |||||
| ;; function to the argument sequence. reduce-binary applies the | |||||
| ;; arguments `pair-wise' which means it works with binary functions | |||||
| ;; as compared to `reduce'." | |||||
| ;; (if (nil? (rest seq)) | |||||
| ;; (first seq) | |||||
| ;; (fun (first seq) | |||||
| ;; (reduce-binary fun (rest seq))))) | |||||
| ;; (defun filter (fun seq) | |||||
| ;; "Takes a function and a sequence as arguments and applies the | |||||
| ;; function to every value in the sequence. If the result of that | |||||
| ;; funciton application returns a truthy value, the original value is | |||||
| ;; added to a list, which in the end is returned." | |||||
| ;; (when seq | |||||
| ;; (if (fun (first seq)) | |||||
| ;; (pair (first seq) | |||||
| ;; (filter fun (rest seq))) | |||||
| ;; (filter fun (rest seq))))) | |||||
| ;; (defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args) | |||||
| ;; "A wrapper for the built-in (print) that accepts a variable number | |||||
| ;; of arguments and also provides keywords for specifying the printed | |||||
| ;; separators between the arguments and what should be printed after the | |||||
| ;; las argument." | |||||
| ;; (defmacro printf-quoted (:keys @sep @end :rest @args) | |||||
| ;; (if (nil? @args) | |||||
| ;; (prog (print (eval @end)) nil) | |||||
| ;; (prog | |||||
| ;; (print (first @args)) | |||||
| ;; (unless (nil? (rest @args)) | |||||
| ;; (print (eval @sep))) | |||||
| ;; (eval (pair printf-quoted | |||||
| ;; (extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args))))))) | |||||
| ;; (eval (pair printf-quoted (extend (list :@sep (eval sep) :@end (eval end)) args)))) | |||||
| ;; (defmacro pe (@expr) | |||||
| ;; (printf @expr "evaluates to" (eval @expr))) | |||||
| @@ -1,12 +1,29 @@ | |||||
| (defun make-vector (x y z) | (defun make-vector (x y z) | ||||
| (let ((local-x x) | |||||
| (local-y y) | |||||
| (local-z z)) | |||||
| (lambda () | |||||
| local-x))) | |||||
| (let ((local-x x) | |||||
| (local-y y) | |||||
| (local-z z) | |||||
| (defun (macro (@name @params :rest @body) | |||||
| (eval (pair 'define-upwards (pair @name (pair (pair 'lambda (pair @params @body)) nil))))))) | |||||
| (defun set-x (new-x) (mutate local-x new-x)) | |||||
| (defun set-y (new-y) (mutate local-y new-y)) | |||||
| (defun set-z (new-z) (mutate local-z new-z)) | |||||
| (defun dispatch (message) | |||||
| (if (= message ::get-x) | |||||
| local-x | |||||
| (if (= message ::set-x) | |||||
| set-x | |||||
| nil))) | |||||
| (break) | |||||
| dispatch)) | |||||
| (define v (make-vector 1 2 3)) | (define v (make-vector 1 2 3)) | ||||
| (print (v)) | |||||
| (print (v ::get-x)) | |||||
| ((v ::set-x) 19) | |||||
| (print (v ::get-x)) | |||||
| (read " ") | (read " ") | ||||
| @@ -109,6 +109,7 @@ void append_to_keyword_argument_list(Keyword_Arguments* args, | |||||
| append_to_Ast_Node_array_list(args->values, default_value); | append_to_Ast_Node_array_list(args->values, default_value); | ||||
| } | } | ||||
| struct Environment; | |||||
| struct Function { | struct Function { | ||||
| bool is_macro; | bool is_macro; | ||||
| @@ -117,10 +118,10 @@ struct Function { | |||||
| Keyword_Arguments* keyword_arguments; | Keyword_Arguments* keyword_arguments; | ||||
| // rest_argument will be nullptr if no rest argument is declared | // rest_argument will be nullptr if no rest argument is declared | ||||
| char* rest_argument; | char* rest_argument; | ||||
| struct Ast_Node* body; // implicit prog | |||||
| Ast_Node* body; // implicit prog | |||||
| Environment* parent_environment; // we are doing closures now!! | |||||
| }; | }; | ||||
| struct Environment; | |||||
| struct CFunction { | struct CFunction { | ||||
| std::function<Ast_Node*(Ast_Node*, Environment*)> function; | std::function<Ast_Node*(Ast_Node*, Environment*)> function; | ||||
| @@ -324,7 +324,7 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| return value; | return value; | ||||
| }); | }); | ||||
| defun("macro-define", cLambda { | |||||
| defun("define-upwards", cLambda { | |||||
| try { | try { | ||||
| arguments_length = list_length(arguments); | arguments_length = list_length(arguments); | ||||
| } | } | ||||
| @@ -345,15 +345,50 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| report_error(Error_Type::Type_Missmatch); | report_error(Error_Type::Type_Missmatch); | ||||
| } | } | ||||
| if (!env->parent) { | |||||
| report_error(Error_Type::Unknown_Error); | |||||
| } | |||||
| Ast_Node* value = arguments->value.pair->rest->value.pair->first; | Ast_Node* value = arguments->value.pair->rest->value.pair->first; | ||||
| try { | try { | ||||
| value = eval_expr(value, env); | value = eval_expr(value, env); | ||||
| } | } | ||||
| define_macro_symbol(symbol, value, env); | |||||
| define_symbol(symbol, value, env->parent); | |||||
| return value; | return value; | ||||
| }); | }); | ||||
| // defun("macro-define", cLambda { | |||||
| // try { | |||||
| // arguments_length = list_length(arguments); | |||||
| // } | |||||
| // if (arguments_length != 2) { | |||||
| // report_error(Error_Type::Wrong_Number_Of_Arguments); | |||||
| // } | |||||
| // Ast_Node* symbol = arguments->value.pair->first; | |||||
| // if (symbol->type == Ast_Node_Type::Pair) { | |||||
| // try { | |||||
| // symbol = eval_expr(symbol, env); | |||||
| // } | |||||
| // } | |||||
| // if (symbol->type != Ast_Node_Type::Symbol) { | |||||
| // report_error(Error_Type::Type_Missmatch); | |||||
| // } | |||||
| // Ast_Node* value = arguments->value.pair->rest->value.pair->first; | |||||
| // try { | |||||
| // value = eval_expr(value, env); | |||||
| // } | |||||
| // define_macro_symbol(symbol, value, env); | |||||
| // return value; | |||||
| // }); | |||||
| defun("mutate", cLambda { | defun("mutate", cLambda { | ||||
| try { | try { | ||||
| evaluated_arguments = eval_arguments(arguments, env, &arguments_length); | evaluated_arguments = eval_arguments(arguments, env, &arguments_length); | ||||
| @@ -500,7 +535,7 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| if (arguments_length < 1) | if (arguments_length < 1) | ||||
| report_error(Error_Type::Wrong_Number_Of_Arguments); | report_error(Error_Type::Wrong_Number_Of_Arguments); | ||||
| Environment* let_env = create_child_environment(env, Environment_Type::Let); | |||||
| Environment* let_env = create_child_environment(env); | |||||
| Ast_Node* bindings = arguments->value.pair->first; | Ast_Node* bindings = arguments->value.pair->first; | ||||
| while (true) { | while (true) { | ||||
| if (bindings->type == Ast_Node_Type::Nil) { | if (bindings->type == Ast_Node_Type::Nil) { | ||||
| @@ -564,6 +599,7 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| /* if (lispOperator->value.built_in_function->type == Built_In_Macro) { */ | /* if (lispOperator->value.built_in_function->type == Built_In_Macro) { */ | ||||
| /* function->is_macro = true; */ | /* function->is_macro = true; */ | ||||
| /* } else { */ | /* } else { */ | ||||
| function->parent_environment = env; | |||||
| function->is_macro = false; | function->is_macro = false; | ||||
| /* } */ | /* } */ | ||||
| @@ -614,6 +650,7 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| report_error(Error_Type::Wrong_Number_Of_Arguments); | report_error(Error_Type::Wrong_Number_Of_Arguments); | ||||
| Function* function = new(Function); | Function* function = new(Function); | ||||
| function->parent_environment = env; | |||||
| function->is_macro = true; | function->is_macro = true; | ||||
| // if parameters were specified | // if parameters were specified | ||||
| @@ -962,7 +999,7 @@ void load_built_ins_into_environment(Environment* env) { | |||||
| } | } | ||||
| Environment* create_built_ins_environment() { | Environment* create_built_ins_environment() { | ||||
| Environment* ret = create_child_environment(nullptr, Environment_Type::Let); | |||||
| Environment* ret = create_child_environment(nullptr); | |||||
| load_built_ins_into_environment(ret); | load_built_ins_into_environment(ret); | ||||
| return ret; | return ret; | ||||
| } | } | ||||
| @@ -1,12 +1,5 @@ | |||||
| enum struct Environment_Type { | |||||
| Let, | |||||
| Lambda, | |||||
| Macro, | |||||
| }; | |||||
| struct Environment { | struct Environment { | ||||
| struct Environment* parent; | struct Environment* parent; | ||||
| Environment_Type type; | |||||
| int capacity; | int capacity; | ||||
| int next_index; | int next_index; | ||||
| @@ -15,12 +8,11 @@ struct Environment { | |||||
| Ast_Node** values; | Ast_Node** values; | ||||
| }; | }; | ||||
| Environment* create_child_environment(Environment* parent, Environment_Type type) { | |||||
| Environment* create_child_environment(Environment* parent) { | |||||
| Environment* env = new(Environment); | Environment* env = new(Environment); | ||||
| int start_capacity = 16; | int start_capacity = 16; | ||||
| env->type = type; | |||||
| env->parent = parent; | env->parent = parent; | ||||
| env->capacity = start_capacity; | env->capacity = start_capacity; | ||||
| env->next_index = 0; | env->next_index = 0; | ||||
| @@ -30,19 +22,19 @@ Environment* create_child_environment(Environment* parent, Environment_Type type | |||||
| return env; | return env; | ||||
| } | } | ||||
| Environment* create_empty_environment(Environment_Type type) { | |||||
| return create_child_environment(nullptr, type); | |||||
| Environment* create_empty_environment() { | |||||
| return create_child_environment(nullptr); | |||||
| } | } | ||||
| void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | ||||
| if (env->type == Environment_Type::Macro) { | |||||
| // NOTE(Felix): we know we have a parent because every | |||||
| // environment has a parent except the top level environment. | |||||
| // However the top level environment is not a let-environment, | |||||
| // so we would not land here | |||||
| define_symbol(symbol, value, env->parent); | |||||
| return; | |||||
| } | |||||
| // if (env->type == Environment_Type::Macro) { | |||||
| // // NOTE(Felix): we know we have a parent because every | |||||
| // // environment has a parent except the top level environment. | |||||
| // // However the top level environment is not a let-environment, | |||||
| // // so we would not land here | |||||
| // define_symbol(symbol, value, env->parent); | |||||
| // return; | |||||
| // } | |||||
| // NOTE(Felix): right now we are simply adding the symol at the | // NOTE(Felix): right now we are simply adding the symol at the | ||||
| // back of the list without checking if it already exists but are | // back of the list without checking if it already exists but are | ||||
| @@ -60,16 +52,16 @@ void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | |||||
| ++env->next_index; | ++env->next_index; | ||||
| } | } | ||||
| void define_macro_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | |||||
| if (env->type != Environment_Type::Macro) { | |||||
| create_error(Error_Type::Unknown_Error, symbol->sourceCodeLocation); | |||||
| return; | |||||
| } | |||||
| // void define_macro_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { | |||||
| // if (env->type != Environment_Type::Macro) { | |||||
| // create_error(Error_Type::Unknown_Error, symbol->sourceCodeLocation); | |||||
| // return; | |||||
| // } | |||||
| env->type = Environment_Type::Lambda; | |||||
| define_symbol(symbol, value, env); | |||||
| env->type = Environment_Type::Macro; | |||||
| } | |||||
| // env->type = Environment_Type::Lambda; | |||||
| // define_symbol(symbol, value, env); | |||||
| // env->type = Environment_Type::Macro; | |||||
| // } | |||||
| void print_environment(Environment* env); | void print_environment(Environment* env); | ||||
| @@ -80,41 +72,41 @@ Ast_Node* lookup_symbol_in_this_envt(Symbol* sym, Environment* env) { | |||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| Ast_Node* lookup_symbol_from_lambda_env(Symbol* sym, Environment* env) { | |||||
| Ast_Node* result; | |||||
| do { | |||||
| if (env->type != Environment_Type::Lambda) { | |||||
| result = lookup_symbol_in_this_envt(sym, env); | |||||
| if (result) return result; | |||||
| } | |||||
| env = env->parent; | |||||
| } while (env); | |||||
| return nullptr; | |||||
| } | |||||
| Ast_Node* lookup_symbol_from_let_or_macro_env(Symbol* sym, Environment* env) { | |||||
| Ast_Node* result; | |||||
| do { | |||||
| result = lookup_symbol_in_this_envt(sym, env); | |||||
| if (result) return result; | |||||
| if (env->type == Environment_Type::Lambda) | |||||
| break; | |||||
| env = env->parent; | |||||
| } while (env); | |||||
| if (env) { | |||||
| do { | |||||
| if (env->type != Environment_Type::Lambda) { | |||||
| result = lookup_symbol_in_this_envt(sym, env); | |||||
| if (result) return result; | |||||
| } | |||||
| env = env->parent; | |||||
| } while (env); | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| // Ast_Node* lookup_symbol_from_lambda_env(Symbol* sym, Environment* env) { | |||||
| // Ast_Node* result; | |||||
| // do { | |||||
| // if (env->type != Environment_Type::Lambda) { | |||||
| // result = lookup_symbol_in_this_envt(sym, env); | |||||
| // if (result) return result; | |||||
| // } | |||||
| // env = env->parent; | |||||
| // } while (env); | |||||
| // return nullptr; | |||||
| // } | |||||
| // Ast_Node* lookup_symbol_from_let_or_macro_env(Symbol* sym, Environment* env) { | |||||
| // Ast_Node* result; | |||||
| // do { | |||||
| // result = lookup_symbol_in_this_envt(sym, env); | |||||
| // if (result) return result; | |||||
| // if (env->type == Environment_Type::Lambda) | |||||
| // break; | |||||
| // env = env->parent; | |||||
| // } while (env); | |||||
| // if (env) { | |||||
| // do { | |||||
| // if (env->type != Environment_Type::Lambda) { | |||||
| // result = lookup_symbol_in_this_envt(sym, env); | |||||
| // if (result) return result; | |||||
| // } | |||||
| // env = env->parent; | |||||
| // } while (env); | |||||
| // } | |||||
| // return nullptr; | |||||
| // } | |||||
| Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) { | Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) { | ||||
| // first check current environment | // first check current environment | ||||
| @@ -125,11 +117,7 @@ Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) { | |||||
| return result; | return result; | ||||
| if (env->parent) { | if (env->parent) { | ||||
| if (env->type == Environment_Type::Lambda) { | |||||
| result = lookup_symbol_from_lambda_env(sym, env->parent); | |||||
| } else { | |||||
| result = lookup_symbol_from_let_or_macro_env(sym, env->parent); | |||||
| } | |||||
| result = lookup_symbol(node, env->parent); | |||||
| if (result) | if (result) | ||||
| return result; | return result; | ||||
| @@ -142,14 +130,6 @@ Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) { | |||||
| return create_ast_node_t(); | return create_ast_node_t(); | ||||
| } | } | ||||
| // we should not need this anymore when we have c lambdas as built | |||||
| // in functions | |||||
| /* result = create_ast_node_built_in_function(sym->identifier); */ | |||||
| /* result->sourceCodeLocation = node->sourceCodeLocation; */ | |||||
| /* if (result) */ | |||||
| /* return result; */ | |||||
| create_error(Error_Type::Symbol_Not_Defined, node->sourceCodeLocation); | create_error(Error_Type::Symbol_Not_Defined, node->sourceCodeLocation); | ||||
| /* printf("%s\n", sym->identifier); */ | /* printf("%s\n", sym->identifier); */ | ||||
| return nullptr; | return nullptr; | ||||
| @@ -170,12 +150,12 @@ void print_environment_indent(Environment* env, int indent) { | |||||
| if (env->parent) { | if (env->parent) { | ||||
| print_indent(indent); | print_indent(indent); | ||||
| printf("parent"); | printf("parent"); | ||||
| if (env->parent->type == Environment_Type::Lambda) | |||||
| printf(" (lambda)"); | |||||
| else if (env->parent->type == Environment_Type::Macro) | |||||
| printf(" (macro)"); | |||||
| else if (env->parent->type == Environment_Type::Let) | |||||
| printf(" (let)"); | |||||
| // if (env->parent->type == Environment_Type::Lambda) | |||||
| // printf(" (lambda)"); | |||||
| // else if (env->parent->type == Environment_Type::Macro) | |||||
| // printf(" (macro)"); | |||||
| // else if (env->parent->type == Environment_Type::Let) | |||||
| // printf(" (let)"); | |||||
| printf(":\n"); | printf(":\n"); | ||||
| print_environment_indent(env->parent, indent+4); | print_environment_indent(env->parent, indent+4); | ||||
| } | } | ||||
| @@ -6,7 +6,8 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E | |||||
| // switching between "define_symbol" and "define_macro_symbol" all | // switching between "define_symbol" and "define_macro_symbol" all | ||||
| // the time | // the time | ||||
| Environment* new_env = create_child_environment(parent, Environment_Type::Lambda); | |||||
| // Environment* new_env = create_child_environment(parent, Environment_Type::Lambda); | |||||
| Environment* new_env = create_child_environment(function->parent_environment); | |||||
| // positional arguments | // positional arguments | ||||
| for (int i = 0; i < function->positional_arguments->next_index; ++i) { | for (int i = 0; i < function->positional_arguments->next_index; ++i) { | ||||
| @@ -145,8 +146,6 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E | |||||
| // don't have to check every time if it is macro environment or | // don't have to check every time if it is macro environment or | ||||
| // not | // not | ||||
| if (function->is_macro) | |||||
| new_env->type = Environment_Type::Macro; | |||||
| try { | try { | ||||
| result = eval_expr(function->body, new_env); | result = eval_expr(function->body, new_env); | ||||
| @@ -30,7 +30,7 @@ Ast_Node* interprete_file (char* file_name) { | |||||
| program = parse_program(file_name, file_content); | program = parse_program(file_name, file_content); | ||||
| } | } | ||||
| Environment* env = create_empty_environment(Environment_Type::Let); | |||||
| Environment* env = create_empty_environment(); | |||||
| load_built_ins_into_environment(env); | load_built_ins_into_environment(env); | ||||
| try { | try { | ||||
| @@ -50,7 +50,7 @@ Ast_Node* interprete_file (char* file_name) { | |||||
| int interprete_stdin () { | int interprete_stdin () { | ||||
| printf("Welcome to the lispy interpreter.\n"); | printf("Welcome to the lispy interpreter.\n"); | ||||
| char* line; | char* line; | ||||
| Environment* env = create_empty_environment(Environment_Type::Let); | |||||
| Environment* env = create_empty_environment(); | |||||
| load_built_ins_into_environment(env); | load_built_ins_into_environment(env); | ||||
| built_in_load("pre.slime", env); | built_in_load("pre.slime", env); | ||||