we have macros. OOOOOOFFF
This commit is contained in:
+160
-145
@@ -1,102 +1,117 @@
|
|||||||
(define defmacro
|
(define-syntax when (condition :rest body)
|
||||||
(macro (@name @params :rest @body)
|
(list 'if condition (pair 'prog body) nil))
|
||||||
"Macro for creating macros with a more concise syntax."
|
|
||||||
(eval (pair 'define-upwards (pair @name (pair (pair 'macro (pair @params @body)) nil))))))
|
|
||||||
|
|
||||||
(define defun
|
(define-syntax unless (condition :rest body)
|
||||||
(macro (@name @params :rest @body)
|
(list 'if condition nil (pair 'prog body)))
|
||||||
"Macro for creating functions with a more concise syntax."
|
|
||||||
(eval (pair 'define-upwards (pair @name (pair (pair 'lambda (pair @params @body)) nil))))))
|
|
||||||
|
|
||||||
;; (defun nil? (x)
|
(define-syntax defun (name arguments :rest body)
|
||||||
;; "Checks if the argument is nil."
|
;; (type-assert arguments :pair)
|
||||||
;; (= x nil))
|
;; `(define ,name (lambda ,arguments ,body))
|
||||||
|
|
||||||
;; (defun number? (x)
|
;; see if we have a docstring
|
||||||
;; "Checks if the argument is a number."
|
(if (and (= (type (first body)) :string) (not (= (type (rest body)) :nil)))
|
||||||
;; (= (type x) :number))
|
(list 'define name (list 'lambda arguments (first body) (pair 'prog (rest body))))
|
||||||
|
(list 'define name (list 'lambda arguments (pair 'prog body)))))
|
||||||
|
|
||||||
;; (defun symbol? (x)
|
(define-syntax defspecial (name arguments :rest body)
|
||||||
;; "Checks if the argument is a symbol."
|
;; (type-assert arguments :pair)
|
||||||
;; (= (type x) :symbol))
|
;; `(define ,name (lambda ,arguments ,body))
|
||||||
|
|
||||||
;; (defun keyword? (x)
|
;; see if we have a docstring
|
||||||
;; "Checks if the argument is a keyword."
|
(if (and (= (type (first body)) :string) (not (= (type (rest body)) :nil)))
|
||||||
;; (= (type x) :keyword))
|
(list 'define name (list 'special-lambda arguments (first body) (pair 'prog (rest body))))
|
||||||
|
(list 'define name (list 'special-lambda arguments (pair 'prog body)))))
|
||||||
|
|
||||||
;; (defun pair? (x)
|
;; (cond
|
||||||
;; "Checks if the argument is a pair."
|
;; (p1 v1)
|
||||||
;; (= (type x) :pair))
|
;; (p2 v2))
|
||||||
|
(define-syntax cond (:rest clauses)
|
||||||
|
(defun rec (clauses)
|
||||||
|
(if (= nil clauses)
|
||||||
|
nil
|
||||||
|
(list 'if (first (first clauses))
|
||||||
|
(pair 'prog (rest (first clauses)))
|
||||||
|
(rec (rest clauses)))))
|
||||||
|
(rec clauses))
|
||||||
|
|
||||||
;; (defun string? (x)
|
(defun nil? (x)
|
||||||
;; "Checks if the argument is a string."
|
"Checks if the argument is nil."
|
||||||
;; (= (type x) :string))
|
(= x nil))
|
||||||
|
|
||||||
;; (defun dynamic-function? (x)
|
(defun number? (x)
|
||||||
;; "Checks if the argument is a function."
|
"Checks if the argument is a number."
|
||||||
;; (= (type x) :dynamic-function))
|
(= (type x) :number))
|
||||||
|
|
||||||
;; (defun dynamic-macro? (x)
|
(defun symbol? (x)
|
||||||
;; "Checks if the argument is a macro."
|
"Checks if the argument is a symbol."
|
||||||
;; (= (type x) :dynamic-macro))
|
(= (type x) :symbol))
|
||||||
|
|
||||||
;; (defun built-in-function? (x)
|
(defun keyword? (x)
|
||||||
;; "Checks if the argument is a built-in function."
|
"Checks if the argument is a keyword."
|
||||||
;; (= (type x) :built-in-function))
|
(= (type x) :keyword))
|
||||||
|
|
||||||
;; (defun apply (fun seq)
|
(defun pair? (x)
|
||||||
;; "Applies the funciton to the sequence, as in calls the function
|
"Checks if the argument is a pair."
|
||||||
;; with ithe sequence as arguemens."
|
(or (= (type x) :pair) (= (type x) :nil)))
|
||||||
;; (eval (pair fun seq)))
|
|
||||||
|
|
||||||
;; (defmacro when (@test :rest @body)
|
(defun string? (x)
|
||||||
;; "Executes the code in :rest if test is true."
|
"Checks if the argument is a string."
|
||||||
;; (if (eval @test)
|
(= (type x) :string))
|
||||||
;; (eval (pair prog @body))
|
|
||||||
;; nil))
|
|
||||||
|
|
||||||
;; (defmacro unless (@test :rest @body)
|
(defun lambda? (x)
|
||||||
;; "Executes the code in :rest if test is false."
|
"Checks if the argument is a function."
|
||||||
;; (if (eval @test)
|
(= (type x) :dynamic-function))
|
||||||
;; nil
|
|
||||||
;; (eval (pair prog @body))))
|
|
||||||
|
|
||||||
;; (defun end (seq)
|
(defun special-lambda? (x)
|
||||||
;; "Returns the last pair in the sqeuence."
|
"Checks if the argument is a macro."
|
||||||
;; (if (or (nil? seq) (not (pair? (rest seq))))
|
(= (type x) :dynamic-macro))
|
||||||
;; seq
|
|
||||||
;; (end (rest seq))))
|
|
||||||
|
|
||||||
;; (defun last (seq)
|
(defun built-in-function? (x)
|
||||||
;; "Returns the (first) of the last (pair) of the given sequence."
|
"Checks if the argument is a built-in function."
|
||||||
;; (first (end seq)))
|
(= (type x) :built-in-function))
|
||||||
|
|
||||||
;; (defun extend (seq elem)
|
(defun apply (fun seq)
|
||||||
;; "Extends a list with the given element, by putting it in
|
"Applies the funciton to the sequence, as in calls the function
|
||||||
;; the (rest) of the last element of the sequence."
|
with ithe sequence as arguemens."
|
||||||
;; (when (pair? seq)
|
(eval (pair fun seq)))
|
||||||
;; (define e (end seq))
|
|
||||||
;; (mutate e (pair (first e) elem)))
|
|
||||||
;; seq)
|
|
||||||
|
|
||||||
;; (defun incr (val)
|
(defun end (seq)
|
||||||
;; "Adds one to the argument."
|
"Returns the last pair in the sqeuence."
|
||||||
;; (+ val 1))
|
(if (or (nil? seq) (not (pair? (rest seq))))
|
||||||
|
seq
|
||||||
|
(end (rest seq))))
|
||||||
|
|
||||||
;; (defun decr (val)
|
(defun last (seq)
|
||||||
;; "Subtracts one from the argument."
|
"Returns the (first) of the last (pair) of the given sequence."
|
||||||
;; (- val 1))
|
(first (end seq)))
|
||||||
|
|
||||||
;; (defun append (seq elem)
|
(defun extend (seq elem)
|
||||||
;; "Appends an element to a sequence, by extendeing the list
|
"Extends a list with the given element, by putting it in
|
||||||
;; with (pair elem nil)."
|
the (rest) of the last element of the sequence."
|
||||||
;; (extend seq (pair elem nil)))
|
(when (pair? seq)
|
||||||
|
(define e (end seq))
|
||||||
|
(mutate e (pair (first e) elem)))
|
||||||
|
seq)
|
||||||
|
|
||||||
|
(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)))))
|
||||||
|
|
||||||
|
(defun increment (val)
|
||||||
|
"Adds one to the argument."
|
||||||
|
(+ val 1))
|
||||||
|
|
||||||
|
(defun decrement (val)
|
||||||
|
"Subtracts one from the argument."
|
||||||
|
(- val 1))
|
||||||
|
|
||||||
;; (defun length (seq)
|
|
||||||
;; "Returns the length of the given sequence."
|
|
||||||
;; (if (nil? seq)
|
|
||||||
;; 0
|
|
||||||
;; (incr (length (rest seq)))))
|
|
||||||
|
|
||||||
;; (defmacro n-times (@times @action)
|
;; (defmacro n-times (@times @action)
|
||||||
;; "Executes @action @times times."
|
;; "Executes @action @times times."
|
||||||
@@ -119,79 +134,79 @@
|
|||||||
;; (eval (pair prog @for-body))
|
;; (eval (pair prog @for-body))
|
||||||
;; (eval (extend (list for @symbol (@op @from) @to) @for-body))))
|
;; (eval (extend (list for @symbol (@op @from) @to) @for-body))))
|
||||||
|
|
||||||
;; (defun range (:keys from :defaults-to 0 to)
|
(defun range (:keys from :defaults-to 0 to)
|
||||||
;; "Returns a sequence of numbers starting with the number defined
|
"Returns a sequence of numbers starting with the number defined
|
||||||
;; by the key 'from' and ends with the number defined in 'to'."
|
by the key 'from' and ends with the number defined in 'to'."
|
||||||
;; (when (< from to)
|
(when (< from to)
|
||||||
;; (pair from (range :from (+ 1 from) :to to))))
|
(pair from (range :from (+ 1 from) :to to))))
|
||||||
|
|
||||||
;; (defun range-while (:keys from :defaults-to 0 to)
|
(defun range-while (:keys from :defaults-to 0 to)
|
||||||
;; "Returns a sequence of numbers starting with the number defined
|
"Returns a sequence of numbers starting with the number defined
|
||||||
;; by the key 'from' and ends with the number defined in 'to'."
|
by the key 'from' and ends with the number defined in 'to'."
|
||||||
;; (define result (list (copy from)))
|
(define result (list (copy from)))
|
||||||
;; (define head result)
|
(define head result)
|
||||||
;; (mutate from (incr from))
|
(mutate from (increment from))
|
||||||
;; (while (< from to)
|
(while (< from to)
|
||||||
;; (prog
|
(prog
|
||||||
;; (mutate head (pair (first head) (pair (copy from) nil)))
|
(mutate head (pair (first head) (pair (copy from) nil)))
|
||||||
;; (define head (rest head))
|
(define head (rest head))
|
||||||
;; (mutate from (incr from))))
|
(mutate from (increment from))))
|
||||||
;; result)
|
result)
|
||||||
|
|
||||||
;; (defun map (fun seq)
|
(defun map (fun seq)
|
||||||
;; "Takes a function and a sequence as arguments and returns a new
|
"Takes a function and a sequence as arguments and returns a new
|
||||||
;; sequence which contains the results of using the first sequences
|
sequence which contains the results of using the first sequences
|
||||||
;; elemens as argument to that function."
|
elemens as argument to that function."
|
||||||
;; (if (nil? seq)
|
(if (nil? seq)
|
||||||
;; seq
|
seq
|
||||||
;; (pair (fun (first seq))
|
(pair (fun (first seq))
|
||||||
;; (map fun (rest seq)))))
|
(map fun (rest seq)))))
|
||||||
|
|
||||||
;; (defun reduce (fun seq)
|
(defun reduce (fun seq)
|
||||||
;; "Takes a function and a sequence as arguments and applies the
|
"Takes a function and a sequence as arguments and applies the
|
||||||
;; function to the argument sequence. This only works correctly if
|
function to the argument sequence. This only works correctly if
|
||||||
;; the given function accepts a variable amount of parameters. If
|
the given function accepts a variable amount of parameters. If
|
||||||
;; your funciton is limited to two arguments, use `reduce-binary'
|
your funciton is limited to two arguments, use `reduce-binary'
|
||||||
;; instead."
|
instead."
|
||||||
;; (apply fun seq))
|
(apply fun seq))
|
||||||
|
|
||||||
;; (defun reduce-binary (fun seq)
|
(defun reduce-binary (fun seq)
|
||||||
;; "Takes a function and a sequence as arguments and applies the
|
"Takes a function and a sequence as arguments and applies the
|
||||||
;; function to the argument sequence. reduce-binary applies the
|
function to the argument sequence. reduce-binary applies the
|
||||||
;; arguments `pair-wise' which means it works with binary functions
|
arguments `pair-wise' which means it works with binary functions
|
||||||
;; as compared to `reduce'."
|
as compared to `reduce'."
|
||||||
;; (if (nil? (rest seq))
|
(if (nil? (rest seq))
|
||||||
;; (first seq)
|
(first seq)
|
||||||
;; (fun (first seq)
|
(fun (first seq)
|
||||||
;; (reduce-binary fun (rest seq)))))
|
(reduce-binary fun (rest seq)))))
|
||||||
|
|
||||||
;; (defun filter (fun seq)
|
(defun filter (fun seq)
|
||||||
;; "Takes a function and a sequence as arguments and applies the
|
"Takes a function and a sequence as arguments and applies the
|
||||||
;; function to every value in the sequence. If the result of that
|
function to every value in the sequence. If the result of that
|
||||||
;; funciton application returns a truthy value, the original value is
|
funciton application returns a truthy value, the original value is
|
||||||
;; added to a list, which in the end is returned."
|
added to a list, which in the end is returned."
|
||||||
;; (when seq
|
(when seq
|
||||||
;; (if (fun (first seq))
|
(if (fun (first seq))
|
||||||
;; (pair (first seq)
|
(pair (first seq)
|
||||||
;; (filter fun (rest seq)))
|
(filter fun (rest seq)))
|
||||||
;; (filter fun (rest seq)))))
|
(filter fun (rest seq)))))
|
||||||
|
|
||||||
;; (defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
|
(defun printf (:keys sep :defaults-to " " end :defaults-to "\n" :rest args)
|
||||||
;; "A wrapper for the built-in (print) that accepts a variable number
|
"A wrapper for the built-in (print) that accepts a variable number
|
||||||
;; of arguments and also provides keywords for specifying the printed
|
of arguments and also provides keywords for specifying the printed
|
||||||
;; separators between the arguments and what should be printed after the
|
separators between the arguments and what should be printed after the
|
||||||
;; las argument."
|
las argument."
|
||||||
;; (defmacro printf-quoted (:keys @sep @end :rest @args)
|
(defspecial printf-quoted (:keys @sep @end :rest @args)
|
||||||
;; (if (nil? @args)
|
(if (nil? @args)
|
||||||
;; (prog (print (eval @end)) nil)
|
(prog (print (eval @end)) nil)
|
||||||
;; (prog
|
(prog
|
||||||
;; (print (first @args))
|
(print (first @args))
|
||||||
;; (unless (nil? (rest @args))
|
(unless (nil? (rest @args))
|
||||||
;; (print (eval @sep)))
|
(print (eval @sep)))
|
||||||
;; (eval (pair printf-quoted
|
(eval (pair printf-quoted
|
||||||
;; (extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args)))))))
|
(extend (list :@sep (eval @sep) :@end (eval @end)) (rest @args)))))))
|
||||||
|
|
||||||
;; (eval (pair printf-quoted (extend (list :@sep (eval sep) :@end (eval end)) args))))
|
(eval (pair printf-quoted (extend (list :@sep (eval sep) :@end (eval end)) args))))
|
||||||
|
|
||||||
;; (defmacro pe (@expr)
|
;; (defmacro pe (@expr)
|
||||||
;; (printf @expr "evaluates to" (eval @expr)))
|
;; (printf @expr "evaluates to" (eval @expr)))
|
||||||
|
|||||||
+72
-21
@@ -1,29 +1,80 @@
|
|||||||
|
;; (define-syntax defclass (name members :rest functions)
|
||||||
|
;; (list 'defun (string->symbol (concat-strings "make-" (symbol->string name)))
|
||||||
|
|
||||||
(defun make-vector (x y z)
|
|
||||||
(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)
|
;; (defclass vector3 (x y z)
|
||||||
(if (= message ::get-x)
|
;; ;; getters and setters will be auto generated
|
||||||
local-x
|
|
||||||
(if (= message ::set-x)
|
|
||||||
set-x
|
|
||||||
nil)))
|
|
||||||
|
|
||||||
(break)
|
;; (defun ->length ()
|
||||||
dispatch))
|
;; (** (+ (* x x) (* y y) (* z z)) 0.5))
|
||||||
|
|
||||||
(define v (make-vector 1 2 3))
|
;; (defun ->scale (fac)
|
||||||
|
;; (mutate x (* fac x))
|
||||||
|
;; (mutate y (* fac y))
|
||||||
|
;; (mutate z (* fac z)))
|
||||||
|
|
||||||
(print (v ::get-x))
|
;; )
|
||||||
((v ::set-x) 19)
|
|
||||||
(print (v ::get-x))
|
(defun make-vector3 (x-coord y-coord z-coord)
|
||||||
|
(let ((x x-coord)
|
||||||
|
(y y-coord)
|
||||||
|
(z z-coord))
|
||||||
|
|
||||||
|
(defun ->get-x () x)
|
||||||
|
(defun ->get-y () y)
|
||||||
|
(defun ->get-z () z)
|
||||||
|
(defun ->set-x (new-x) (mutate x new-x))
|
||||||
|
(defun ->set-y (new-y) (mutate y new-y))
|
||||||
|
(defun ->set-z (new-z) (mutate z new-z))
|
||||||
|
|
||||||
|
(defun ->length ()
|
||||||
|
(** (+ (* x x) (* y y) (* z z)) 0.5))
|
||||||
|
|
||||||
|
(defun ->scale (fac)
|
||||||
|
(mutate x (* fac x))
|
||||||
|
(mutate y (* fac y))
|
||||||
|
(mutate z (* fac z)))
|
||||||
|
|
||||||
|
(defun ->print ()
|
||||||
|
(print "[vector3] (")
|
||||||
|
(print x)
|
||||||
|
(print " ")
|
||||||
|
(print y)
|
||||||
|
(print " ")
|
||||||
|
(print z)
|
||||||
|
(print ")\n"))
|
||||||
|
|
||||||
|
(defun ->+ (other)
|
||||||
|
(make-vector
|
||||||
|
(+ x ((other ->get-x)))
|
||||||
|
(+ y ((other ->get-y)))
|
||||||
|
(+ z ((other ->get-z)))))
|
||||||
|
|
||||||
|
(defun ->- (other)
|
||||||
|
(make-vector
|
||||||
|
(- x ((other ->get-x)))
|
||||||
|
(- y ((other ->get-y)))
|
||||||
|
(- z ((other ->get-z)))))
|
||||||
|
|
||||||
|
(defun ->scalar-product (other)
|
||||||
|
(+ (* x ((other ->get-x)))
|
||||||
|
(* y ((other ->get-y)))
|
||||||
|
(* z ((other ->get-z)))))
|
||||||
|
|
||||||
|
(defun ->cross-product (other)
|
||||||
|
(make-vector
|
||||||
|
(- (* y ((other ->get-z))) (* z ((other ->get-y))))
|
||||||
|
(- (* z ((other ->get-x))) (* x ((other ->get-z))))
|
||||||
|
(- (* x ((other ->get-y))) (* y ((other ->get-x))))))
|
||||||
|
|
||||||
|
(special-lambda (message) (eval message))))
|
||||||
|
|
||||||
|
(define v1 (make-vector3 1 2 3))
|
||||||
|
(define v2 (make-vector3 3 2 1))
|
||||||
|
|
||||||
|
(print ((v1 ->length)))
|
||||||
|
(print ((v2 ->length)))
|
||||||
|
|
||||||
(read " ")
|
(read " ")
|
||||||
|
|||||||
Binary file not shown.
+29
-2
@@ -1,5 +1,32 @@
|
|||||||
struct Ast_Node;
|
struct Ast_Node;
|
||||||
define_array_list(struct Ast_Node*, Ast_Node);
|
|
||||||
|
// #define define_array_list(type, name) \
|
||||||
|
// struct name##_Array_List { \
|
||||||
|
// type* data; \
|
||||||
|
// int length; \
|
||||||
|
// int next_index; \
|
||||||
|
// }; \
|
||||||
|
// \
|
||||||
|
// \
|
||||||
|
// void append_to_##name##_array_list(name##_Array_List* arraylist, type element) { \
|
||||||
|
// if (arraylist->next_index == arraylist->length) { \
|
||||||
|
// arraylist->length *= 2; \
|
||||||
|
// arraylist->data = \
|
||||||
|
// (type*)realloc(arraylist->data, arraylist->length * sizeof(type)); \
|
||||||
|
// } \
|
||||||
|
// arraylist->data[arraylist->next_index++] = element; \
|
||||||
|
// } \
|
||||||
|
// \
|
||||||
|
// \
|
||||||
|
// name##_Array_List* create_##name##_array_list(int initial_capacity) { \
|
||||||
|
// name##_Array_List* ret = new(name##_Array_List); \
|
||||||
|
// ret->data = (type*)malloc(initial_capacity * sizeof(type)); \
|
||||||
|
// ret->next_index = 0; \
|
||||||
|
// ret->length = initial_capacity; \
|
||||||
|
// return ret; \
|
||||||
|
// }
|
||||||
|
|
||||||
|
define_array_list(Ast_Node*, Ast_Node);
|
||||||
|
|
||||||
enum struct Ast_Node_Type {
|
enum struct Ast_Node_Type {
|
||||||
Nil,
|
Nil,
|
||||||
@@ -112,7 +139,7 @@ void append_to_keyword_argument_list(Keyword_Arguments* args,
|
|||||||
struct Environment;
|
struct Environment;
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
bool is_macro;
|
bool is_special_form;
|
||||||
char* docstring;
|
char* docstring;
|
||||||
Positional_Arguments* positional_arguments;
|
Positional_Arguments* positional_arguments;
|
||||||
Keyword_Arguments* keyword_arguments;
|
Keyword_Arguments* keyword_arguments;
|
||||||
|
|||||||
+41
-45
@@ -247,6 +247,34 @@ Ast_Node* built_in_divide(Ast_Node* arguments, Environment* env) {
|
|||||||
return create_ast_node_number(quotient);
|
return create_ast_node_number(quotient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast_Node* built_in_exponentiate(Ast_Node* arguments, Environment* env) {
|
||||||
|
int arguments_length;
|
||||||
|
try {
|
||||||
|
arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments_length != 2) {
|
||||||
|
create_error(Error_Type::Wrong_Number_Of_Arguments, arguments->sourceCodeLocation);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert_type(arguments->value.pair->first, Ast_Node_Type::Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
double base = arguments->value.pair->first->value.number->value;
|
||||||
|
|
||||||
|
arguments = arguments->value.pair->rest;
|
||||||
|
|
||||||
|
try {
|
||||||
|
assert_type(arguments->value.pair->first, Ast_Node_Type::Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
double exponent = arguments->value.pair->first->value.number->value;
|
||||||
|
|
||||||
|
return create_ast_node_number(pow(base, exponent));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Ast_Node* built_in_load(char* file_name, Environment* env) {
|
Ast_Node* built_in_load(char* file_name, Environment* env) {
|
||||||
char* file_content = read_entire_file(file_name);
|
char* file_content = read_entire_file(file_name);
|
||||||
@@ -254,7 +282,7 @@ Ast_Node* built_in_load(char* file_name, Environment* env) {
|
|||||||
Ast_Node* result = create_ast_node_nil();
|
Ast_Node* result = create_ast_node_nil();
|
||||||
Ast_Node_Array_List* program;
|
Ast_Node_Array_List* program;
|
||||||
try {
|
try {
|
||||||
program = parse_program(file_name, file_content);
|
program = Parser::parse_program(file_name, file_content);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < program->next_index; ++i) {
|
for (int i = 0; i < program->next_index; ++i) {
|
||||||
try {
|
try {
|
||||||
@@ -294,6 +322,7 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
defun("-", built_in_substract);
|
defun("-", built_in_substract);
|
||||||
defun("*", built_in_multiply);
|
defun("*", built_in_multiply);
|
||||||
defun("/", built_in_divide);
|
defun("/", built_in_divide);
|
||||||
|
defun("**", built_in_exponentiate);
|
||||||
defun("define", cLambda {
|
defun("define", cLambda {
|
||||||
try {
|
try {
|
||||||
arguments_length = list_length(arguments);
|
arguments_length = list_length(arguments);
|
||||||
@@ -359,36 +388,6 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
|
|
||||||
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);
|
||||||
@@ -596,12 +595,8 @@ 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);
|
||||||
/* if (lispOperator->value.built_in_function->type == Built_In_Macro) { */
|
|
||||||
/* function->is_macro = true; */
|
|
||||||
/* } else { */
|
|
||||||
function->parent_environment = env;
|
function->parent_environment = env;
|
||||||
function->is_macro = false;
|
function->is_special_form = false;
|
||||||
/* } */
|
|
||||||
|
|
||||||
// if parameters were specified
|
// if parameters were specified
|
||||||
if (arguments->value.pair->first->type != Ast_Node_Type::Nil) {
|
if (arguments->value.pair->first->type != Ast_Node_Type::Nil) {
|
||||||
@@ -637,10 +632,10 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
ret->value.function = function;
|
ret->value.function = function;
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
defun("macro", cLambda {
|
defun("special-lambda", cLambda {
|
||||||
/*
|
/*
|
||||||
* (macro ())
|
* (special-lambda ())
|
||||||
* (macro (x d) (+ 1 2) (- 1 2) (* 1 2))
|
* (special-lambda (x d) (+ 1 2) (- 1 2) (* 1 2))
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
arguments_length = list_length(arguments);
|
arguments_length = list_length(arguments);
|
||||||
@@ -651,7 +646,7 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
|
|
||||||
Function* function = new(Function);
|
Function* function = new(Function);
|
||||||
function->parent_environment = env;
|
function->parent_environment = env;
|
||||||
function->is_macro = true;
|
function->is_special_form = true;
|
||||||
|
|
||||||
// if parameters were specified
|
// if parameters were specified
|
||||||
if (arguments->value.pair->first->type != Ast_Node_Type::Nil) {
|
if (arguments->value.pair->first->type != Ast_Node_Type::Nil) {
|
||||||
@@ -734,8 +729,9 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
||||||
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
||||||
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
// BUG(Felix): Why is arguments_length for '(1 (2)) == 3 and not 2??
|
||||||
/* if (arguments_length != 2) { */
|
|
||||||
if (list_length(evaluated_arguments) != 2) {
|
// if (list_length(evaluated_arguments) != 2) {
|
||||||
|
if (arguments_length != 2) {
|
||||||
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
return create_ast_node_pair(evaluated_arguments->value.pair->first, evaluated_arguments->value.pair->rest->value.pair->first);
|
return create_ast_node_pair(evaluated_arguments->value.pair->first, evaluated_arguments->value.pair->rest->value.pair->first);
|
||||||
@@ -780,7 +776,7 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Ast_Node_Type::CFunction: return create_ast_node_keyword("cfunction");
|
case Ast_Node_Type::CFunction: return create_ast_node_keyword("cfunction");
|
||||||
case Ast_Node_Type::Function: {
|
case Ast_Node_Type::Function: {
|
||||||
if (evaluated_arguments->value.pair->first->value.function->is_macro)
|
if (evaluated_arguments->value.pair->first->value.function->is_special_form)
|
||||||
return create_ast_node_keyword("dynamic-macro");
|
return create_ast_node_keyword("dynamic-macro");
|
||||||
return create_ast_node_keyword("dynamic-function");
|
return create_ast_node_keyword("dynamic-function");
|
||||||
}
|
}
|
||||||
@@ -822,7 +818,7 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
string_equal(type->value.keyword->identifier, "dynamic-macro")))
|
string_equal(type->value.keyword->identifier, "dynamic-macro")))
|
||||||
{
|
{
|
||||||
Ast_Node* fun = eval_expr(arguments->value.pair->first, env);
|
Ast_Node* fun = eval_expr(arguments->value.pair->first, env);
|
||||||
printf("\nMacro? %s\n", (fun->value.function->is_macro) ? "yes" : "no");
|
printf("\nspecial-lambda? %s\n", (fun->value.function->is_special_form) ? "yes" : "no");
|
||||||
if (fun->value.function->docstring)
|
if (fun->value.function->docstring)
|
||||||
printf("Docstring:\n==========\n%s\n\n", fun->value.function->docstring);
|
printf("Docstring:\n==========\n%s\n\n", fun->value.function->docstring);
|
||||||
else
|
else
|
||||||
@@ -876,7 +872,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);
|
||||||
}
|
}
|
||||||
print(evaluated_arguments->value.pair->first);
|
print(evaluated_arguments->value.pair->first);
|
||||||
printf("\n");
|
// printf("\n");
|
||||||
return create_ast_node_nil();
|
return create_ast_node_nil();
|
||||||
});
|
});
|
||||||
defun("read", cLambda {
|
defun("read", cLambda {
|
||||||
|
|||||||
-62
@@ -27,15 +27,6 @@ Environment* create_empty_environment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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
|
||||||
// also searching for thesymbol from the back, so we will find the
|
// also searching for thesymbol from the back, so we will find the
|
||||||
@@ -52,17 +43,6 @@ 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
||||||
Ast_Node* lookup_symbol_in_this_envt(Symbol* sym, Environment* env) {
|
Ast_Node* lookup_symbol_in_this_envt(Symbol* sym, Environment* env) {
|
||||||
@@ -72,42 +52,6 @@ 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(Ast_Node* node, Environment* env) {
|
Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) {
|
||||||
// first check current environment
|
// first check current environment
|
||||||
Symbol* sym = node->value.symbol;
|
Symbol* sym = node->value.symbol;
|
||||||
@@ -150,12 +94,6 @@ 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)");
|
|
||||||
printf(":\n");
|
printf(":\n");
|
||||||
print_environment_indent(env->parent, indent+4);
|
print_environment_indent(env->parent, indent+4);
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-16
@@ -1,12 +1,6 @@
|
|||||||
Ast_Node* eval_expr(Ast_Node* node, Environment* env);
|
Ast_Node* eval_expr(Ast_Node*, Environment*);
|
||||||
|
|
||||||
Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, Environment* parent) {
|
Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function) {
|
||||||
// NOTE(Felix): if it is a macro, we will set it later, so we can
|
|
||||||
// use the default "define_symbol" method here instead of
|
|
||||||
// switching between "define_symbol" and "define_macro_symbol" all
|
|
||||||
// the time
|
|
||||||
|
|
||||||
// Environment* new_env = create_child_environment(parent, Environment_Type::Lambda);
|
|
||||||
Environment* new_env = create_child_environment(function->parent_environment);
|
Environment* new_env = create_child_environment(function->parent_environment);
|
||||||
|
|
||||||
// positional arguments
|
// positional arguments
|
||||||
@@ -143,10 +137,6 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function, E
|
|||||||
|
|
||||||
eval_time: {
|
eval_time: {
|
||||||
Ast_Node* result;
|
Ast_Node* result;
|
||||||
|
|
||||||
// don't have to check every time if it is macro environment or
|
|
||||||
// not
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = eval_expr(function->body, new_env);
|
result = eval_expr(function->body, new_env);
|
||||||
}
|
}
|
||||||
@@ -331,7 +321,7 @@ Ast_Node* extract_keyword_value(char* keyword, Parsed_Arguments* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) {
|
Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_arguments_length) {
|
||||||
*out_arguments_length = 0;
|
int my_out_arguments_length = 0;
|
||||||
if (arguments->type == Ast_Node_Type::Nil) {
|
if (arguments->type == Ast_Node_Type::Nil) {
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
@@ -355,8 +345,9 @@ Ast_Node* eval_arguments(Ast_Node* arguments, Environment* env, int *out_argumen
|
|||||||
create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation);
|
create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
++(*out_arguments_length);
|
++my_out_arguments_length;
|
||||||
}
|
}
|
||||||
|
*(out_arguments_length) = my_out_arguments_length;
|
||||||
return evaluated_arguments;
|
return evaluated_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +399,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
|
|
||||||
// check for list function
|
// check for list function
|
||||||
if (lispOperator->type == Ast_Node_Type::Function) {
|
if (lispOperator->type == Ast_Node_Type::Function) {
|
||||||
if (!lispOperator->value.function->is_macro) {
|
if (!lispOperator->value.function->is_special_form) {
|
||||||
try {
|
try {
|
||||||
arguments = eval_arguments(arguments, env, &arguments_length);
|
arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
}
|
}
|
||||||
@@ -416,7 +407,7 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
|
|
||||||
Ast_Node* result;
|
Ast_Node* result;
|
||||||
try {
|
try {
|
||||||
result = apply_arguments_to_function(arguments, lispOperator->value.function, env);
|
result = apply_arguments_to_function(arguments, lispOperator->value.function);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-2
@@ -1,6 +1,14 @@
|
|||||||
#define new(type) new type
|
#define new(type) new type
|
||||||
#define nullptr NULL
|
#define nullptr NULL
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define assert(cond) \
|
||||||
|
if (!cond) \
|
||||||
|
__debugbreak();
|
||||||
|
#else
|
||||||
|
#define assert(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define concat_( a, b) a##b
|
#define concat_( a, b) a##b
|
||||||
#define label(prefix, lnum) concat_(prefix,lnum)
|
#define label(prefix, lnum) concat_(prefix,lnum)
|
||||||
#define try \
|
#define try \
|
||||||
@@ -55,10 +63,23 @@
|
|||||||
define_array_list(char*, String);
|
define_array_list(char*, String);
|
||||||
|
|
||||||
|
|
||||||
int string_equal(char* a, char* b) {
|
// int string_equal(char* a, char* b) {
|
||||||
return !strcmp(a, b);
|
// return !strcmp(a, b);
|
||||||
|
// }
|
||||||
|
|
||||||
|
int string_equal(char input[],char check[])
|
||||||
|
{
|
||||||
|
int i,result=1;
|
||||||
|
for(i=0; input[i]!='\0' || check[i]!='\0'; i++) {
|
||||||
|
if(input[i] != check[i]) {
|
||||||
|
result=0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// asprintf implementation
|
// asprintf implementation
|
||||||
int _vscprintf_so(const char * format, va_list pargs) {
|
int _vscprintf_so(const char * format, va_list pargs) {
|
||||||
int retval;
|
int retval;
|
||||||
|
|||||||
+2
-2
@@ -59,8 +59,8 @@ void print(Ast_Node* node) {
|
|||||||
printf(":%s", node->value.keyword->identifier);
|
printf(":%s", node->value.keyword->identifier);
|
||||||
} break;
|
} break;
|
||||||
case (Ast_Node_Type::Function): {
|
case (Ast_Node_Type::Function): {
|
||||||
if (node->value.function->is_macro)
|
if (node->value.function->is_special_form)
|
||||||
printf("[macro]");
|
printf("[special-lambda]");
|
||||||
else
|
else
|
||||||
printf("[lambda]");
|
printf("[lambda]");
|
||||||
} break;
|
} break;
|
||||||
|
|||||||
+11
-7
@@ -13,8 +13,8 @@
|
|||||||
#include "./error.cpp"
|
#include "./error.cpp"
|
||||||
#include "./io.cpp"
|
#include "./io.cpp"
|
||||||
#include "./assert.cpp"
|
#include "./assert.cpp"
|
||||||
#include "./parse.cpp"
|
|
||||||
#include "./env.cpp"
|
#include "./env.cpp"
|
||||||
|
#include "./parse.cpp"
|
||||||
#include "./built_ins.cpp"
|
#include "./built_ins.cpp"
|
||||||
#include "./eval.cpp"
|
#include "./eval.cpp"
|
||||||
#include "./testing.cpp"
|
#include "./testing.cpp"
|
||||||
@@ -25,18 +25,20 @@ Ast_Node* interprete_file (char* file_name) {
|
|||||||
create_error(Error_Type::Unknown_Error, nullptr);
|
create_error(Error_Type::Unknown_Error, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node_Array_List* program;
|
|
||||||
try {
|
|
||||||
program = parse_program(file_name, file_content);
|
|
||||||
}
|
|
||||||
|
|
||||||
Environment* env = create_empty_environment();
|
Environment* env = create_empty_environment();
|
||||||
load_built_ins_into_environment(env);
|
load_built_ins_into_environment(env);
|
||||||
|
|
||||||
|
Parser::init(env);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
built_in_load("pre.slime", env);
|
built_in_load("pre.slime", env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast_Node_Array_List* program;
|
||||||
|
try {
|
||||||
|
program = Parser::parse_program(file_name, file_content);
|
||||||
|
}
|
||||||
|
|
||||||
Ast_Node* result = create_ast_node_nil();
|
Ast_Node* result = create_ast_node_nil();
|
||||||
for (int i = 0; i < program->next_index; ++i) {
|
for (int i = 0; i < program->next_index; ++i) {
|
||||||
try {
|
try {
|
||||||
@@ -53,6 +55,8 @@ int interprete_stdin () {
|
|||||||
Environment* env = create_empty_environment();
|
Environment* env = create_empty_environment();
|
||||||
load_built_ins_into_environment(env);
|
load_built_ins_into_environment(env);
|
||||||
|
|
||||||
|
Parser::init(env);
|
||||||
|
|
||||||
built_in_load("pre.slime", env);
|
built_in_load("pre.slime", env);
|
||||||
if (error) {
|
if (error) {
|
||||||
log_error();
|
log_error();
|
||||||
@@ -63,7 +67,7 @@ int interprete_stdin () {
|
|||||||
while (true) {
|
while (true) {
|
||||||
printf(">");
|
printf(">");
|
||||||
line = read_expression();
|
line = read_expression();
|
||||||
parsed = parse_single_expression(line);
|
parsed = Parser::parse_single_expression(line);
|
||||||
if (error) {
|
if (error) {
|
||||||
log_error();
|
log_error();
|
||||||
delete_error();
|
delete_error();
|
||||||
|
|||||||
+167
-49
@@ -1,6 +1,12 @@
|
|||||||
char* parser_file;
|
// forward decls -- start
|
||||||
int parser_line;
|
void load_built_ins_into_environment(Environment*);
|
||||||
int parser_col;
|
int list_length(Ast_Node*);
|
||||||
|
void parse_argument_list(Ast_Node*, Function*);
|
||||||
|
Ast_Node* eval_expr(Ast_Node*, Environment*);
|
||||||
|
// forward decls -- end
|
||||||
|
|
||||||
|
|
||||||
|
namespace Parser {
|
||||||
|
|
||||||
#define inject_scl(_ret) \
|
#define inject_scl(_ret) \
|
||||||
ret->sourceCodeLocation = new(Source_Code_Location); \
|
ret->sourceCodeLocation = new(Source_Code_Location); \
|
||||||
@@ -8,29 +14,29 @@ int parser_col;
|
|||||||
ret->sourceCodeLocation->line = parser_line; \
|
ret->sourceCodeLocation->line = parser_line; \
|
||||||
ret->sourceCodeLocation->column = parser_col
|
ret->sourceCodeLocation->column = parser_col
|
||||||
|
|
||||||
|
char* parser_file;
|
||||||
|
int parser_line;
|
||||||
|
int parser_col;
|
||||||
|
|
||||||
// TODO(Felix): use the array list macro here?
|
// NOTE(Felix): In this environment, the build in vunctions will
|
||||||
Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length) {
|
// be loaded, and the macros will be stroed in form of
|
||||||
Ast_Node_Array_List* ret = new (Ast_Node_Array_List);
|
// special-lambdas, that get executed in this environment at
|
||||||
|
// read-time
|
||||||
|
Environment* environment_for_macros;
|
||||||
|
|
||||||
// create one with 16 entries first
|
void init(Environment* env) {
|
||||||
ret->length = initial_length;
|
// if we already initialized it, then skip
|
||||||
ret->data = (struct Ast_Node**)malloc(initial_length * sizeof(struct Ast_Node));
|
if (environment_for_macros)
|
||||||
ret->next_index = 0;
|
return;
|
||||||
|
|
||||||
return ret;
|
// NOTE(Felix): For now we just allow executing built-ins at
|
||||||
}
|
// read-time (while creating macros). If later we want to
|
||||||
|
// change that, we have to define some funcions in this
|
||||||
void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, struct Ast_Node* node) {
|
// environment.
|
||||||
if (list->next_index == list->length) {
|
environment_for_macros = env;
|
||||||
list->length *= 2;
|
|
||||||
list->data = (struct Ast_Node**)realloc(list->data, list->length * sizeof(struct Ast_Node));
|
|
||||||
}
|
}
|
||||||
list->data[list->next_index++] = node;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void eat_comment_line(char* text, int* index_in_text) {
|
||||||
void eat_comment_line(char* text, int* index_in_text) {
|
|
||||||
// safety check if we are actually starting a comment here
|
// safety check if we are actually starting a comment here
|
||||||
if (text[*index_in_text] != ';')
|
if (text[*index_in_text] != ';')
|
||||||
return;
|
return;
|
||||||
@@ -42,9 +48,9 @@ void eat_comment_line(char* text, int* index_in_text) {
|
|||||||
} while (text[(*index_in_text)] != '\n' &&
|
} while (text[(*index_in_text)] != '\n' &&
|
||||||
text[(*index_in_text)] != '\r' &&
|
text[(*index_in_text)] != '\r' &&
|
||||||
text[(*index_in_text)] != '\0');
|
text[(*index_in_text)] != '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
void eat_whitespace(char* text, int* index_in_text) {
|
void eat_whitespace(char* text, int* index_in_text) {
|
||||||
// skip whitespaces
|
// skip whitespaces
|
||||||
while (text[(*index_in_text)] == ' ' ||
|
while (text[(*index_in_text)] == ' ' ||
|
||||||
text[(*index_in_text)] == '\t' ||
|
text[(*index_in_text)] == '\t' ||
|
||||||
@@ -59,18 +65,18 @@ void eat_whitespace(char* text, int* index_in_text) {
|
|||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void eat_until_code(char* text, int* index_in_text) {
|
void eat_until_code(char* text, int* index_in_text) {
|
||||||
int position_before;
|
int position_before;
|
||||||
do {
|
do {
|
||||||
position_before = *index_in_text;
|
position_before = *index_in_text;
|
||||||
eat_comment_line(text, index_in_text);
|
eat_comment_line(text, index_in_text);
|
||||||
eat_whitespace(text, index_in_text);
|
eat_whitespace(text, index_in_text);
|
||||||
} while (position_before != *index_in_text);
|
} while (position_before != *index_in_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* read_atom(char* text, int* index_in_text) {
|
char* read_atom(char* text, int* index_in_text) {
|
||||||
int atom_length = 0;
|
int atom_length = 0;
|
||||||
while (text[*index_in_text+atom_length] != ' ' &&
|
while (text[*index_in_text+atom_length] != ' ' &&
|
||||||
text[*index_in_text+atom_length] != ')' &&
|
text[*index_in_text+atom_length] != ')' &&
|
||||||
@@ -101,19 +107,18 @@ char* read_atom(char* text, int* index_in_text) {
|
|||||||
*index_in_text += atom_length;
|
*index_in_text += atom_length;
|
||||||
|
|
||||||
return atom;
|
return atom;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* parse_number(char* text, int* index_in_text) {
|
Ast_Node* parse_number(char* text, int* index_in_text) {
|
||||||
double number;
|
double number;
|
||||||
char* str_number = read_atom(text, index_in_text);
|
char* str_number = read_atom(text, index_in_text);
|
||||||
sscanf(str_number, "%lf", &number);
|
sscanf(str_number, "%lf", &number);
|
||||||
Ast_Node* ret = create_ast_node_number(number);
|
Ast_Node* ret = create_ast_node_number(number);
|
||||||
inject_scl(ret);
|
inject_scl(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ast_Node* parse_keyword(char* text, int* index_in_text) {
|
||||||
Ast_Node* parse_keyword(char* text, int* index_in_text) {
|
|
||||||
// we are now on the colon
|
// we are now on the colon
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
@@ -121,17 +126,17 @@ Ast_Node* parse_keyword(char* text, int* index_in_text) {
|
|||||||
Ast_Node* ret = create_ast_node_keyword(str_keyword);
|
Ast_Node* ret = create_ast_node_keyword(str_keyword);
|
||||||
inject_scl(ret);
|
inject_scl(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* parse_symbol(char* text, int* index_in_text) {
|
Ast_Node* parse_symbol(char* text, int* index_in_text) {
|
||||||
// we are now at the first char of the symbol
|
// we are now at the first char of the symbol
|
||||||
char* str_symbol = read_atom(text, index_in_text);
|
char* str_symbol = read_atom(text, index_in_text);
|
||||||
Ast_Node* ret = create_ast_node_symbol(str_symbol);
|
Ast_Node* ret = create_ast_node_symbol(str_symbol);
|
||||||
inject_scl(ret);
|
inject_scl(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* parse_string(char* text, int* index_in_text) {
|
Ast_Node* parse_string(char* text, int* index_in_text) {
|
||||||
// the first character is the '"'
|
// the first character is the '"'
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
@@ -181,9 +186,9 @@ Ast_Node* parse_string(char* text, int* index_in_text) {
|
|||||||
Ast_Node* ret = create_ast_node_string(string, string_length);
|
Ast_Node* ret = create_ast_node_string(string, string_length);
|
||||||
inject_scl(ret);
|
inject_scl(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* parse_atom(char* text, int* index_in_text) {
|
Ast_Node* parse_atom(char* text, int* index_in_text) {
|
||||||
// numbers
|
// numbers
|
||||||
if ((text[*index_in_text] <= 57 && // if number
|
if ((text[*index_in_text] <= 57 && // if number
|
||||||
text[*index_in_text] >= 48)
|
text[*index_in_text] >= 48)
|
||||||
@@ -209,9 +214,11 @@ Ast_Node* parse_atom(char* text, int* index_in_text) {
|
|||||||
return parse_string(text, index_in_text);
|
return parse_string(text, index_in_text);
|
||||||
|
|
||||||
return parse_symbol(text, index_in_text);
|
return parse_symbol(text, index_in_text);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node* parse_expression(char* text, int* index_in_text) {
|
Ast_Node* parse_expression(char* text, int* index_in_text) {
|
||||||
|
|
||||||
|
// if it is quoted
|
||||||
if (text[*index_in_text] == '\'') {
|
if (text[*index_in_text] == '\'') {
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
@@ -229,12 +236,15 @@ Ast_Node* parse_expression(char* text, int* index_in_text) {
|
|||||||
create_ast_node_symbol("quote"),
|
create_ast_node_symbol("quote"),
|
||||||
create_ast_node_pair(result, create_ast_node_nil()));
|
create_ast_node_pair(result, create_ast_node_nil()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if it is not quoted
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
|
|
||||||
eat_whitespace(text, index_in_text);
|
eat_whitespace(text, index_in_text);
|
||||||
|
|
||||||
// if there was actually nothing in the list, return nil
|
// if there was actually nothing in the list, we define here,
|
||||||
|
// that that means nil
|
||||||
if (text[(*index_in_text)] == ')') {
|
if (text[(*index_in_text)] == ')') {
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
@@ -292,10 +302,116 @@ Ast_Node* parse_expression(char* text, int* index_in_text) {
|
|||||||
head = head->value.pair->rest;
|
head = head->value.pair->rest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ast_Node* parse_single_expression(char* text) {
|
// check if we have to create or delete or run macros
|
||||||
|
if (expression->value.pair->first->type == Ast_Node_Type::Symbol) {
|
||||||
|
if (string_equal("define-syntax", expression->value.pair->first->value.symbol->identifier)) {
|
||||||
|
// create a new macro
|
||||||
|
Ast_Node* arguments = expression->value.pair->rest;
|
||||||
|
int arguments_length;
|
||||||
|
|
||||||
|
// HACK(Felix): almost code duplicate from
|
||||||
|
// `built_ins.cpp`: special-lambda
|
||||||
|
try {
|
||||||
|
arguments_length = list_length(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// (define-syntax defun (name args :rest body) (...))
|
||||||
|
if (arguments_length < 2) {
|
||||||
|
create_error(Error_Type::Wrong_Number_Of_Arguments, expression->sourceCodeLocation);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments->value.pair->first->type != Ast_Node_Type::Symbol) {
|
||||||
|
create_error(Error_Type::Type_Missmatch, expression->sourceCodeLocation);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract the name
|
||||||
|
Ast_Node* symbol_for_macro = arguments->value.pair->first;
|
||||||
|
arguments = arguments->value.pair->rest;
|
||||||
|
|
||||||
|
Function* function = new(Function);
|
||||||
|
function->parent_environment = environment_for_macros;
|
||||||
|
function->is_special_form = true;
|
||||||
|
|
||||||
|
// if parameters were specified
|
||||||
|
if (arguments->value.pair->first->type != Ast_Node_Type::Nil) {
|
||||||
|
try {
|
||||||
|
assert_type(arguments->value.pair->first, Ast_Node_Type::Pair);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
parse_argument_list(arguments->value.pair->first, function);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
function->positional_arguments = create_positional_argument_list(1);
|
||||||
|
function->keyword_arguments = create_keyword_argument_list(1);
|
||||||
|
function->rest_argument = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments = arguments->value.pair->rest;
|
||||||
|
// if there is a docstring, use it
|
||||||
|
if (arguments->value.pair->first->type == Ast_Node_Type::String) {
|
||||||
|
function->docstring = arguments->value.pair->first->value.string->value;
|
||||||
|
arguments = arguments->value.pair->rest;
|
||||||
|
} else {
|
||||||
|
function->docstring = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are now in the function body, just wrap it in an
|
||||||
|
// implicit prog
|
||||||
|
function->body = create_ast_node_pair(
|
||||||
|
create_ast_node_symbol("prog"),
|
||||||
|
arguments);
|
||||||
|
|
||||||
|
Ast_Node* macro = new(Ast_Node);
|
||||||
|
macro->type = Ast_Node_Type::Function;
|
||||||
|
macro->value.function = function;
|
||||||
|
define_symbol(symbol_for_macro, macro, environment_for_macros);
|
||||||
|
|
||||||
|
// print_environment(environment_for_macros);
|
||||||
|
return create_ast_node_nil();
|
||||||
|
|
||||||
|
} else if (string_equal("delete-syntax", expression->value.pair->first->value.symbol->identifier)) {
|
||||||
|
/* --- deleting an existing macro --- */
|
||||||
|
// TODO(Felix): this is a hard one because when
|
||||||
|
// environments will be made from hashmaps, how can we
|
||||||
|
// delete stuff from hashmaps? If we do probing on
|
||||||
|
// collision and then delte the first colliding entry,
|
||||||
|
// how can we find the second one? How many probes do
|
||||||
|
// we have to do to know for sure that an elemenet is
|
||||||
|
// not in the hashmap? It would be much easier if we
|
||||||
|
// never deleted any elements from the hashmap, so
|
||||||
|
// that, when an entry is not found immidiately, we
|
||||||
|
// know for sure that it does not exist in the table.
|
||||||
|
|
||||||
|
create_error(Error_Type::Not_Yet_Implemented, expression->sourceCodeLocation);
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
// if threre is a macro named like this, then macroexpand
|
||||||
|
// if not it is regular code, dont touch.
|
||||||
|
|
||||||
|
for (int i = 0; i < environment_for_macros->next_index; ++i) {
|
||||||
|
if (string_equal(expression->value.pair->first->value.symbol->identifier, environment_for_macros->keys[i]) &&
|
||||||
|
environment_for_macros->values[i]->type == Ast_Node_Type::Function)
|
||||||
|
{
|
||||||
|
// every `Function` that is defined in this
|
||||||
|
// environment _has_ to be a macro because
|
||||||
|
// only built_ins are in there otherwise,
|
||||||
|
// which are `CFunction`s.
|
||||||
|
try {
|
||||||
|
expression = eval_expr(expression, environment_for_macros);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast_Node* parse_single_expression(char* text) {
|
||||||
parser_file = "stdin";
|
parser_file = "stdin";
|
||||||
parser_line = 1;
|
parser_line = 1;
|
||||||
parser_col = 1;
|
parser_col = 1;
|
||||||
@@ -318,15 +434,15 @@ Ast_Node* parse_single_expression(char* text) {
|
|||||||
return result;
|
return result;
|
||||||
create_error(Error_Type::Trailing_Garbage, create_source_code_location(parser_file, parser_line, parser_col));
|
create_error(Error_Type::Trailing_Garbage, create_source_code_location(parser_file, parser_line, parser_col));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast_Node_Array_List* parse_program(char* file_name, char* text) {
|
Ast_Node_Array_List* parse_program(char* file_name, char* text) {
|
||||||
parser_file = (char*)malloc(strlen(file_name) * sizeof(char) + 1);
|
parser_file = (char*)malloc(strlen(file_name) * sizeof(char) + 1);
|
||||||
strcpy(parser_file, file_name);
|
strcpy(parser_file, file_name);
|
||||||
parser_line = 1;
|
parser_line = 1;
|
||||||
parser_col = 0;
|
parser_col = 0;
|
||||||
|
|
||||||
Ast_Node_Array_List* program = create_Ast_Node_Array_List(16);
|
Ast_Node_Array_List* program = create_Ast_Node_array_list(16);
|
||||||
|
|
||||||
int index_in_text = 0;
|
int index_in_text = 0;
|
||||||
|
|
||||||
@@ -337,7 +453,7 @@ Ast_Node_Array_List* parse_program(char* file_name, char* text) {
|
|||||||
try {
|
try {
|
||||||
parsed = parse_expression(text, &index_in_text);
|
parsed = parse_expression(text, &index_in_text);
|
||||||
}
|
}
|
||||||
append_to_Ast_Node_Array_List(program, parsed);
|
append_to_Ast_Node_array_list(program, parsed);
|
||||||
} break;
|
} break;
|
||||||
case ';':
|
case ';':
|
||||||
case ' ':
|
case ' ':
|
||||||
@@ -353,6 +469,8 @@ Ast_Node_Array_List* parse_program(char* file_name, char* text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef inject_scl
|
#undef inject_scl
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
+23
-22
@@ -87,7 +87,7 @@
|
|||||||
|
|
||||||
testresult test_eval_operands() {
|
testresult test_eval_operands() {
|
||||||
char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))";
|
char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))";
|
||||||
Ast_Node* operands = parse_single_expression(operands_string);
|
Ast_Node* operands = Parser::parse_single_expression(operands_string);
|
||||||
int operands_length;
|
int operands_length;
|
||||||
operands = eval_arguments(operands, create_built_ins_environment(), &operands_length);
|
operands = eval_arguments(operands, create_built_ins_environment(), &operands_length);
|
||||||
|
|
||||||
@@ -128,47 +128,47 @@ testresult test_parse_atom() {
|
|||||||
"sym +"; // symbols
|
"sym +"; // symbols
|
||||||
|
|
||||||
// test numbers
|
// test numbers
|
||||||
Ast_Node* result = parse_atom(string, &index_in_text);
|
Ast_Node* result = Parser::parse_atom(string, &index_in_text);
|
||||||
|
|
||||||
assert_equal_type(result, Ast_Node_Type::Number);
|
assert_equal_type(result, Ast_Node_Type::Number);
|
||||||
assert_equal_double(result->value.number->value, 123);
|
assert_equal_double(result->value.number->value, 123);
|
||||||
|
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::Number);
|
assert_equal_type(result, Ast_Node_Type::Number);
|
||||||
assert_equal_double(result->value.number->value, -1.23e-2);
|
assert_equal_double(result->value.number->value, -1.23e-2);
|
||||||
|
|
||||||
// test strings
|
// test strings
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::String);
|
assert_equal_type(result, Ast_Node_Type::String);
|
||||||
assert_equal_string(result->value.string->value, "asd");
|
assert_equal_string(result->value.string->value, "asd");
|
||||||
|
|
||||||
// test keywords
|
// test keywords
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::Keyword);
|
assert_equal_type(result, Ast_Node_Type::Keyword);
|
||||||
assert_equal_string(result->value.keyword->identifier, "key1");
|
assert_equal_string(result->value.keyword->identifier, "key1");
|
||||||
|
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::Keyword);
|
assert_equal_type(result, Ast_Node_Type::Keyword);
|
||||||
assert_equal_string(result->value.keyword->identifier, "key:2");
|
assert_equal_string(result->value.keyword->identifier, "key:2");
|
||||||
|
|
||||||
// test symbols
|
// test symbols
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::Symbol);
|
assert_equal_type(result, Ast_Node_Type::Symbol);
|
||||||
assert_equal_string(result->value.symbol->identifier, "sym");
|
assert_equal_string(result->value.symbol->identifier, "sym");
|
||||||
|
|
||||||
++index_in_text;
|
++index_in_text;
|
||||||
|
|
||||||
result = parse_atom(string, &index_in_text);
|
result = Parser::parse_atom(string, &index_in_text);
|
||||||
assert_equal_type(result, Ast_Node_Type::Symbol);
|
assert_equal_type(result, Ast_Node_Type::Symbol);
|
||||||
assert_equal_string(result->value.symbol->identifier, "+");
|
assert_equal_string(result->value.symbol->identifier, "+");
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ testresult test_parse_expression() {
|
|||||||
int index_in_text = 0;
|
int index_in_text = 0;
|
||||||
char string[] = "(fun + 12)";
|
char string[] = "(fun + 12)";
|
||||||
|
|
||||||
Ast_Node* result = parse_expression(string, &index_in_text);
|
Ast_Node* result = Parser::parse_expression(string, &index_in_text);
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
|
|
||||||
assert_equal_type(result, Ast_Node_Type::Pair);
|
assert_equal_type(result, Ast_Node_Type::Pair);
|
||||||
@@ -205,7 +205,7 @@ testresult test_parse_expression() {
|
|||||||
char string2[] = "(define fun (lambda (x) (+ 5 (* x x ))))";
|
char string2[] = "(define fun (lambda (x) (+ 5 (* x x ))))";
|
||||||
index_in_text = 0;
|
index_in_text = 0;
|
||||||
|
|
||||||
result = parse_expression(string2, &index_in_text);
|
result = Parser::parse_expression(string2, &index_in_text);
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
|
|
||||||
assert_equal_type(result, Ast_Node_Type::Pair);
|
assert_equal_type(result, Ast_Node_Type::Pair);
|
||||||
@@ -232,7 +232,7 @@ testresult test_parse_expression() {
|
|||||||
|
|
||||||
testresult test_built_in_add() {
|
testresult test_built_in_add() {
|
||||||
char exp_string[] = "(+ 10 4)";
|
char exp_string[] = "(+ 10 4)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -245,7 +245,7 @@ testresult test_built_in_add() {
|
|||||||
|
|
||||||
testresult test_built_in_substract() {
|
testresult test_built_in_substract() {
|
||||||
char exp_string[] = "(- 10 4)";
|
char exp_string[] = "(- 10 4)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -259,7 +259,7 @@ testresult test_built_in_substract() {
|
|||||||
|
|
||||||
testresult test_built_in_multiply() {
|
testresult test_built_in_multiply() {
|
||||||
char exp_string[] = "(* 10 4)";
|
char exp_string[] = "(* 10 4)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -273,7 +273,7 @@ testresult test_built_in_multiply() {
|
|||||||
|
|
||||||
testresult test_built_in_divide() {
|
testresult test_built_in_divide() {
|
||||||
char exp_string[] = "(/ 20 4)";
|
char exp_string[] = "(/ 20 4)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_null(error);
|
assert_null(error);
|
||||||
@@ -287,7 +287,7 @@ testresult test_built_in_divide() {
|
|||||||
|
|
||||||
testresult test_built_in_if() {
|
testresult test_built_in_if() {
|
||||||
char exp_string1[] = "(if 1 4 5)";
|
char exp_string1[] = "(if 1 4 5)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string1);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -296,7 +296,7 @@ testresult test_built_in_if() {
|
|||||||
assert_equal_double(result->value.number->value, 4);
|
assert_equal_double(result->value.number->value, 4);
|
||||||
|
|
||||||
char exp_string2[] = "(if () 4 5)";
|
char exp_string2[] = "(if () 4 5)";
|
||||||
expression = parse_single_expression(exp_string2);
|
expression = Parser::parse_single_expression(exp_string2);
|
||||||
result = eval_expr(expression, create_built_ins_environment());
|
result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -309,7 +309,7 @@ testresult test_built_in_if() {
|
|||||||
|
|
||||||
testresult test_built_in_and() {
|
testresult test_built_in_and() {
|
||||||
char exp_string1[] = "(and 1 \"asd\" 4)";
|
char exp_string1[] = "(and 1 \"asd\" 4)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string1);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -318,7 +318,7 @@ testresult test_built_in_and() {
|
|||||||
|
|
||||||
// a false case
|
// a false case
|
||||||
char exp_string2[] = "(and () \"asd\" 4)";
|
char exp_string2[] = "(and () \"asd\" 4)";
|
||||||
expression = parse_single_expression(exp_string2);
|
expression = Parser::parse_single_expression(exp_string2);
|
||||||
result = eval_expr(expression, create_built_ins_environment());
|
result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -330,7 +330,7 @@ testresult test_built_in_and() {
|
|||||||
|
|
||||||
testresult test_built_in_or() {
|
testresult test_built_in_or() {
|
||||||
char exp_string1[] = "(or \"asd\" nil)";
|
char exp_string1[] = "(or \"asd\" nil)";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string1);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -339,7 +339,7 @@ testresult test_built_in_or() {
|
|||||||
|
|
||||||
// a false case
|
// a false case
|
||||||
char exp_string2[] = "(or () ())";
|
char exp_string2[] = "(or () ())";
|
||||||
expression = parse_single_expression(exp_string2);
|
expression = Parser::parse_single_expression(exp_string2);
|
||||||
result = eval_expr(expression, create_built_ins_environment());
|
result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -352,7 +352,7 @@ testresult test_built_in_or() {
|
|||||||
|
|
||||||
testresult test_built_in_not() {
|
testresult test_built_in_not() {
|
||||||
char exp_string1[] = "(not ())";
|
char exp_string1[] = "(not ())";
|
||||||
Ast_Node* expression = parse_single_expression(exp_string1);
|
Ast_Node* expression = Parser::parse_single_expression(exp_string1);
|
||||||
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
Ast_Node* result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
// a true case
|
// a true case
|
||||||
@@ -362,7 +362,7 @@ testresult test_built_in_not() {
|
|||||||
|
|
||||||
// a false case
|
// a false case
|
||||||
char exp_string2[] = "(not \"asd xD\")";
|
char exp_string2[] = "(not \"asd xD\")";
|
||||||
expression = parse_single_expression(exp_string2);
|
expression = Parser::parse_single_expression(exp_string2);
|
||||||
result = eval_expr(expression, create_built_ins_environment());
|
result = eval_expr(expression, create_built_ins_environment());
|
||||||
|
|
||||||
assert_no_error(error);
|
assert_no_error(error);
|
||||||
@@ -374,6 +374,7 @@ testresult test_built_in_not() {
|
|||||||
|
|
||||||
void run_all_tests() {
|
void run_all_tests() {
|
||||||
log_level = Log_Level::None;
|
log_level = Log_Level::None;
|
||||||
|
Parser::init(create_built_ins_environment());
|
||||||
|
|
||||||
printf("-- Parsing --\n");
|
printf("-- Parsing --\n");
|
||||||
invoke_test(test_parse_atom);
|
invoke_test(test_parse_atom);
|
||||||
|
|||||||
Reference in New Issue
Block a user