some things
This commit is contained in:
+16
-5
@@ -1,18 +1,24 @@
|
|||||||
(define-syntax when (condition :rest body)
|
(define-syntax when (condition :rest body)
|
||||||
(list 'if condition (pair 'prog body) nil))
|
;; (break)
|
||||||
|
`(if ,condition ,(pair prog body) nil))
|
||||||
|
;; (list 'if condition (pair 'prog body) nil))
|
||||||
|
|
||||||
(define-syntax unless (condition :rest body)
|
(define-syntax unless (condition :rest body)
|
||||||
(list 'if condition nil (pair 'prog body)))
|
`(if ,condition nil ,(pair prog body)))
|
||||||
|
|
||||||
(define-syntax defun (name arguments :rest body)
|
(define-syntax defun (name arguments :rest body)
|
||||||
;; (type-assert arguments :pair)
|
;; (type-assert arguments :pair)
|
||||||
;; `(define ,name (lambda ,arguments ,body))
|
;; `(define ,name (lambda ,arguments ,body))
|
||||||
|
|
||||||
|
;; TODO(Felix: I think we do not need to wrap the body of the lamba
|
||||||
|
;; in a prog
|
||||||
|
|
||||||
;; see if we have a docstring
|
;; see if we have a docstring
|
||||||
(if (and (= (type (first body)) :string) (not (= (type (rest body)) :nil)))
|
(if (and (= (type (first body)) :string) (not (= (type (rest body)) :nil)))
|
||||||
(list 'define name (list 'lambda arguments (first body) (pair 'prog (rest body))))
|
(list 'define name (list 'lambda arguments (first body) (pair 'prog (rest body))))
|
||||||
(list 'define name (list 'lambda arguments (pair 'prog body)))))
|
(list 'define name (list 'lambda arguments (pair 'prog body)))))
|
||||||
|
|
||||||
|
|
||||||
(define-syntax defspecial (name arguments :rest body)
|
(define-syntax defspecial (name arguments :rest body)
|
||||||
;; (type-assert arguments :pair)
|
;; (type-assert arguments :pair)
|
||||||
;; `(define ,name (lambda ,arguments ,body))
|
;; `(define ,name (lambda ,arguments ,body))
|
||||||
@@ -52,7 +58,7 @@
|
|||||||
|
|
||||||
(defun pair? (x)
|
(defun pair? (x)
|
||||||
"Checks if the argument is a pair."
|
"Checks if the argument is a pair."
|
||||||
(or (= (type x) :pair) (= (type x) :nil)))
|
(= (type x) :pair))
|
||||||
|
|
||||||
(defun string? (x)
|
(defun string? (x)
|
||||||
"Checks if the argument is a string."
|
"Checks if the argument is a string."
|
||||||
@@ -191,6 +197,11 @@ added to a list, which in the end is returned."
|
|||||||
(filter fun (rest seq)))
|
(filter fun (rest seq)))
|
||||||
(filter fun (rest seq)))))
|
(filter fun (rest seq)))))
|
||||||
|
|
||||||
|
(defun zip (l1 l2)
|
||||||
|
(if (and (nil? l1) (nil? l2))
|
||||||
|
nil
|
||||||
|
(pair (list (first l1) (first l2)) (zip (rest l1) (rest l2)))))
|
||||||
|
|
||||||
(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
|
||||||
@@ -208,5 +219,5 @@ las argument."
|
|||||||
|
|
||||||
(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)
|
(defspecial pe (@expr)
|
||||||
;; (printf @expr "evaluates to" (eval @expr)))
|
(printf @expr "evaluates to" (eval @expr)))
|
||||||
|
|||||||
+61
-64
@@ -1,80 +1,77 @@
|
|||||||
;; (define-syntax defclass (name members :rest functions)
|
(define-syntax defclass (name members :rest body)
|
||||||
;; (list 'defun (string->symbol (concat-strings "make-" (symbol->string name)))
|
"Macro for creatating classes."
|
||||||
|
(defun underscore (sym)
|
||||||
|
(string->symbol (concat-strings "_" (symbol->string sym))))
|
||||||
|
|
||||||
|
(define underscored-members (map underscore members))
|
||||||
|
|
||||||
|
;; the wrapping let environment
|
||||||
|
(define let-body (list 'let (zip members underscored-members)))
|
||||||
|
|
||||||
|
;; the body
|
||||||
|
(map (lambda (fun) (append let-body fun)) body)
|
||||||
|
|
||||||
|
;; the dispatch function
|
||||||
|
(append let-body (list 'special-lambda '(message :rest args)
|
||||||
|
"This is the docs for the handle"
|
||||||
|
'(eval (extend (list message) args))))
|
||||||
|
|
||||||
|
|
||||||
;; ))
|
;; stuff it all in the constructor function
|
||||||
|
(eval (list 'defun (string->symbol (concat-strings "make-" (symbol->string name))) underscored-members
|
||||||
|
"This is the handle to an object of the class "
|
||||||
|
let-body)))
|
||||||
|
|
||||||
;; (defclass vector3 (x y z)
|
;; (v1 print)
|
||||||
;; ;; getters and setters will be auto generated
|
;; (v1 length)
|
||||||
|
;; (v1 get-x)
|
||||||
|
;; (v1 set-x 10)
|
||||||
|
|
||||||
;; (defun ->length ()
|
(defclass vector3 (x y z)
|
||||||
;; (** (+ (* x x) (* y y) (* z z)) 0.5))
|
(defun get-x () x)
|
||||||
|
(defun get-y () y)
|
||||||
|
(defun get-z () z)
|
||||||
|
|
||||||
;; (defun ->scale (fac)
|
(defun set-x (new-x) (mutate x new-x))
|
||||||
;; (mutate x (* fac x))
|
(defun set-y (new-y) (mutate y new-y))
|
||||||
;; (mutate y (* fac y))
|
(defun set-z (new-z) (mutate z new-z))
|
||||||
;; (mutate z (* fac z)))
|
|
||||||
|
|
||||||
;; )
|
(defun length ()
|
||||||
|
(** (+ (* x x) (* y y) (* z z)) 0.5))
|
||||||
|
|
||||||
(defun make-vector3 (x-coord y-coord z-coord)
|
(defun scale (fac)
|
||||||
(let ((x x-coord)
|
(mutate x (* fac x))
|
||||||
(y y-coord)
|
(mutate y (* fac y))
|
||||||
(z z-coord))
|
(mutate z (* fac z))
|
||||||
|
fac)
|
||||||
|
|
||||||
(defun ->get-x () x)
|
(defun add (other)
|
||||||
(defun ->get-y () y)
|
(make-vector3
|
||||||
(defun ->get-z () z)
|
(+ x (other get-x))
|
||||||
(defun ->set-x (new-x) (mutate x new-x))
|
(+ y (other get-y))
|
||||||
(defun ->set-y (new-y) (mutate y new-y))
|
(+ z (other get-z))))
|
||||||
(defun ->set-z (new-z) (mutate z new-z))
|
|
||||||
|
|
||||||
(defun ->length ()
|
(defun subtract (other)
|
||||||
(** (+ (* x x) (* y y) (* z z)) 0.5))
|
(make-vector3
|
||||||
|
(- x (other get-x))
|
||||||
|
(- y (other get-y))
|
||||||
|
(- z (other get-z))))
|
||||||
|
|
||||||
(defun ->scale (fac)
|
(defun scalar-product (other)
|
||||||
(mutate x (* fac x))
|
(+ (* x (other get-x))
|
||||||
(mutate y (* fac y))
|
(* y (other get-y))
|
||||||
(mutate z (* fac z)))
|
(* z (other get-z))))
|
||||||
|
|
||||||
(defun ->print ()
|
(defun cross-product (other)
|
||||||
(print "[vector3] (")
|
(make-vector3
|
||||||
(print x)
|
(- (* y (other get-z)) (* z (other get-y)))
|
||||||
(print " ")
|
(- (* z (other get-x)) (* x (other get-z)))
|
||||||
(print y)
|
(- (* x (other get-y)) (* y (other get-x)))))
|
||||||
(print " ")
|
|
||||||
(print z)
|
|
||||||
(print ")\n"))
|
|
||||||
|
|
||||||
(defun ->+ (other)
|
(defun printout ()
|
||||||
(make-vector
|
(printf "[vector3] (" x y z ")"))
|
||||||
(+ 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 v1 (make-vector3 1 2 3))
|
||||||
(define v2 (make-vector3 3 2 1))
|
(define v2 (make-vector3 3 2 1))
|
||||||
|
|
||||||
(print ((v1 ->length)))
|
|
||||||
(print ((v2 ->length)))
|
|
||||||
|
|
||||||
(read " ")
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pushd build
|
|||||||
taskkill /F /IM %exeName% > NUL 2> NUL
|
taskkill /F /IM %exeName% > NUL 2> NUL
|
||||||
|
|
||||||
echo ---------- Compiling ----------
|
echo ---------- Compiling ----------
|
||||||
call timecmd cl ../src/main.cpp /Fe%exeName% /D_DEBUG /W3 /Zi /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib
|
call timecmd cl ../src/main.cpp /std:c++latest /Fe%exeName% /D_DEBUG /W3 /Zi /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib
|
||||||
|
|
||||||
if %errorlevel% == 0 (
|
if %errorlevel% == 0 (
|
||||||
echo.
|
echo.
|
||||||
|
|||||||
Binary file not shown.
+11
-34
@@ -1,31 +1,5 @@
|
|||||||
struct Ast_Node;
|
struct 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);
|
define_array_list(Ast_Node*, Ast_Node);
|
||||||
|
|
||||||
enum struct Ast_Node_Type {
|
enum struct Ast_Node_Type {
|
||||||
@@ -73,8 +47,8 @@ struct String {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Pair {
|
struct Pair {
|
||||||
struct Ast_Node* first;
|
Ast_Node* first;
|
||||||
struct Ast_Node* rest;
|
Ast_Node* rest;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Positional_Arguments {
|
struct Positional_Arguments {
|
||||||
@@ -87,17 +61,14 @@ struct Positional_Arguments {
|
|||||||
|
|
||||||
struct Keyword_Arguments {
|
struct Keyword_Arguments {
|
||||||
char** identifiers;
|
char** identifiers;
|
||||||
// values[i] will be nullptr if no defalut value was declared for
|
// NOTE(Felix): values[i] will be nullptr if no defalut value was
|
||||||
// key identifiers[i]
|
// declared for key identifiers[i]
|
||||||
Ast_Node_Array_List* values;
|
Ast_Node_Array_List* values;
|
||||||
int next_index;
|
int next_index;
|
||||||
int length;
|
int length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Ast_Node_Array_List* create_Ast_Node_Array_List(int initial_length); */
|
|
||||||
/* void append_to_Ast_Node_Array_List(Ast_Node_Array_List* list, struct Ast_Node* node); */
|
|
||||||
|
|
||||||
Positional_Arguments* create_positional_argument_list(int initial_capacity) {
|
Positional_Arguments* create_positional_argument_list(int initial_capacity) {
|
||||||
Positional_Arguments* ret = new(Positional_Arguments);
|
Positional_Arguments* ret = new(Positional_Arguments);
|
||||||
ret->identifiers = (char**)malloc(initial_capacity * sizeof(char*));
|
ret->identifiers = (char**)malloc(initial_capacity * sizeof(char*));
|
||||||
@@ -138,8 +109,14 @@ void append_to_keyword_argument_list(Keyword_Arguments* args,
|
|||||||
|
|
||||||
struct Environment;
|
struct Environment;
|
||||||
|
|
||||||
|
enum struct Function_Type {
|
||||||
|
Lambda,
|
||||||
|
Special_Lambda,
|
||||||
|
Macro
|
||||||
|
};
|
||||||
|
|
||||||
struct Function {
|
struct Function {
|
||||||
bool is_special_form;
|
Function_Type type;
|
||||||
char* docstring;
|
char* docstring;
|
||||||
Positional_Arguments* positional_arguments;
|
Positional_Arguments* positional_arguments;
|
||||||
Keyword_Arguments* keyword_arguments;
|
Keyword_Arguments* keyword_arguments;
|
||||||
|
|||||||
+161
-19
@@ -450,6 +450,67 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
|
|
||||||
return arguments->value.pair->first;
|
return arguments->value.pair->first;
|
||||||
});
|
});
|
||||||
|
defun("quasiquote", cLambda {
|
||||||
|
try {
|
||||||
|
arguments_length = list_length(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments_length != 1) {
|
||||||
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
|
}
|
||||||
|
// print(arguments);
|
||||||
|
// printf("\n");
|
||||||
|
|
||||||
|
// recursive lambdas in lambdas yay!!
|
||||||
|
std::function<Ast_Node*(Ast_Node*)> unquoteSomeExpressions;
|
||||||
|
unquoteSomeExpressions = [&unquoteSomeExpressions, &env] (Ast_Node* expr) -> Ast_Node* {
|
||||||
|
// if it is an atom, return it
|
||||||
|
if (expr->type != Ast_Node_Type::Pair)
|
||||||
|
return copy_ast_node(expr);
|
||||||
|
|
||||||
|
// it is a pair!
|
||||||
|
Ast_Node* originalPair = expr->value.pair->first;
|
||||||
|
if (originalPair->type == Ast_Node_Type::Symbol &&
|
||||||
|
string_equal(originalPair->value.symbol->identifier, "unquote"))
|
||||||
|
{
|
||||||
|
// eval replace the stuff
|
||||||
|
return eval_expr(expr->value.pair->rest->value.pair->first, env);
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is a list but not starting with the symbol
|
||||||
|
// unquote, so search in there for stuff to unquote.
|
||||||
|
// While copying the list
|
||||||
|
|
||||||
|
//NOTE(Felix): Of fucking course we have to copy the
|
||||||
|
// list. The quasiquote will be part of the body of a
|
||||||
|
// funciton, we can't jsut modify it because otherwise
|
||||||
|
// we modify the body of the function and would bake
|
||||||
|
// in the result...
|
||||||
|
Ast_Node* newPair = create_ast_node_pair(nullptr, nullptr);
|
||||||
|
Ast_Node* newPairHead = newPair;
|
||||||
|
Ast_Node* head = expr;
|
||||||
|
while (head->type == Ast_Node_Type::Pair) {
|
||||||
|
newPairHead->value.pair->first = unquoteSomeExpressions(head->value.pair->first);
|
||||||
|
|
||||||
|
if (head->value.pair->rest->type != Ast_Node_Type::Pair)
|
||||||
|
break;
|
||||||
|
|
||||||
|
newPairHead->value.pair->rest = create_ast_node_pair(nullptr, nullptr);
|
||||||
|
|
||||||
|
newPairHead = newPairHead->value.pair->rest;
|
||||||
|
head = head->value.pair->rest;
|
||||||
|
}
|
||||||
|
newPairHead->value.pair->rest = create_ast_node_nil();
|
||||||
|
|
||||||
|
return newPair;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ast_Node* ret = arguments->value.pair->first;
|
||||||
|
Ast_Node* head = ret;
|
||||||
|
|
||||||
|
ret = unquoteSomeExpressions(ret);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
defun("and", cLambda {
|
defun("and", cLambda {
|
||||||
bool result = true;
|
bool result = true;
|
||||||
while (arguments->type != Ast_Node_Type::Nil) {
|
while (arguments->type != Ast_Node_Type::Nil) {
|
||||||
@@ -596,7 +657,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_special_form = false;
|
function->type = Function_Type::Lambda;
|
||||||
|
|
||||||
// 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) {
|
||||||
@@ -646,7 +707,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_special_form = true;
|
function->type = Function_Type::Special_Lambda;
|
||||||
|
|
||||||
// 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) {
|
||||||
@@ -726,11 +787,6 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (list_length(evaluated_arguments) != 2) {
|
|
||||||
if (arguments_length != 2) {
|
if (arguments_length != 2) {
|
||||||
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
}
|
}
|
||||||
@@ -776,9 +832,14 @@ 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_special_form)
|
Function* fun = evaluated_arguments->value.pair->first->value.function;
|
||||||
return create_ast_node_keyword("dynamic-macro");
|
if (fun->type == Function_Type::Lambda)
|
||||||
return create_ast_node_keyword("dynamic-function");
|
return create_ast_node_keyword("lambda");
|
||||||
|
else if (fun->type == Function_Type::Special_Lambda)
|
||||||
|
return create_ast_node_keyword("special-lambda");
|
||||||
|
else if (fun->type == Function_Type::Macro)
|
||||||
|
return create_ast_node_keyword("macro");
|
||||||
|
else return create_ast_node_keyword("unknown");
|
||||||
}
|
}
|
||||||
case Ast_Node_Type::Keyword: return create_ast_node_keyword("keyword");
|
case Ast_Node_Type::Keyword: return create_ast_node_keyword("keyword");
|
||||||
case Ast_Node_Type::Nil: return create_ast_node_keyword("nil");
|
case Ast_Node_Type::Nil: return create_ast_node_keyword("nil");
|
||||||
@@ -810,15 +871,16 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
if (type) {
|
if (type) {
|
||||||
printf(" is of type ");
|
printf(" is of type ");
|
||||||
print(type);
|
print(type);
|
||||||
printf("\n");
|
printf("\n\n");
|
||||||
// just make sure type was not redefined and
|
|
||||||
// returns something that is not a keyword
|
// TODO(Felix): Maybe don't compare strings here?? Wtf
|
||||||
if (type->type == Ast_Node_Type::Keyword &&
|
if (type->type == Ast_Node_Type::Keyword &&
|
||||||
(string_equal(type->value.keyword->identifier, "dynamic-function") ||
|
(string_equal(type->value.keyword->identifier, "lambda") ||
|
||||||
string_equal(type->value.keyword->identifier, "dynamic-macro")))
|
string_equal(type->value.keyword->identifier, "special-lambda") ||
|
||||||
|
string_equal(type->value.keyword->identifier, "macro")))
|
||||||
{
|
{
|
||||||
Ast_Node* fun = eval_expr(arguments->value.pair->first, env);
|
Ast_Node* fun = eval_expr(arguments->value.pair->first, env);
|
||||||
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
|
||||||
@@ -914,9 +976,9 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
});
|
});
|
||||||
defun("break", cLambda {
|
defun("break", cLambda {
|
||||||
print_environment(env);
|
print_environment(env);
|
||||||
#ifdef _DEBUG
|
if_debug {
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
#endif
|
}
|
||||||
return create_ast_node_nil();
|
return create_ast_node_nil();
|
||||||
});
|
});
|
||||||
defun("try", cLambda {
|
defun("try", cLambda {
|
||||||
@@ -961,6 +1023,9 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
|
|
||||||
});
|
});
|
||||||
defun("copy", cLambda {
|
defun("copy", cLambda {
|
||||||
|
|
||||||
|
// TODO(Felix): if we are copying string nodes, then
|
||||||
|
// shouldn't the string itself also get copied??
|
||||||
try {
|
try {
|
||||||
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
}
|
}
|
||||||
@@ -990,6 +1055,83 @@ void load_built_ins_into_environment(Environment* env) {
|
|||||||
report_error(Error_Type::Unknown_Error);
|
report_error(Error_Type::Unknown_Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defun("string->symbol", cLambda {
|
||||||
|
|
||||||
|
// TODO(Felix): do some sanity checks on the string. For
|
||||||
|
// example, numbers are not valid symbols.
|
||||||
|
|
||||||
|
try {
|
||||||
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments_length != 1) {
|
||||||
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast_Node* source = evaluated_arguments->value.pair->first;
|
||||||
|
|
||||||
|
if (source->type != Ast_Node_Type::String) {
|
||||||
|
report_error(Error_Type::Type_Missmatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return create_ast_node_symbol(_strdup(source->value.string->value));
|
||||||
|
});
|
||||||
|
defun("symbol->string", cLambda {
|
||||||
|
try {
|
||||||
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments_length != 1) {
|
||||||
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ast_Node* source = evaluated_arguments->value.pair->first;
|
||||||
|
|
||||||
|
if (source->type != Ast_Node_Type::Symbol) {
|
||||||
|
report_error(Error_Type::Type_Missmatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Felix): this is not really fast what we are doing here:
|
||||||
|
return create_ast_node_string(_strdup(source->value.symbol->identifier), (int)strlen(source->value.symbol->identifier));
|
||||||
|
});
|
||||||
|
defun("concat-strings", cLambda {
|
||||||
|
try {
|
||||||
|
evaluated_arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments_length < 1) {
|
||||||
|
report_error(Error_Type::Wrong_Number_Of_Arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
int resulting_string_len = 0;
|
||||||
|
|
||||||
|
Ast_Node* head = evaluated_arguments;
|
||||||
|
|
||||||
|
while (head->type == Ast_Node_Type::Pair) {
|
||||||
|
try {
|
||||||
|
assert_type(head->value.pair->first, Ast_Node_Type::String);
|
||||||
|
}
|
||||||
|
resulting_string_len += head->value.pair->first->value.string->length;
|
||||||
|
|
||||||
|
head = head->value.pair->rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
head = evaluated_arguments;
|
||||||
|
|
||||||
|
char* resulting_string = (char*)malloc(resulting_string_len * sizeof(char)) + 1;
|
||||||
|
int index_in_string = 0;
|
||||||
|
|
||||||
|
while (head->type == Ast_Node_Type::Pair) {
|
||||||
|
strcpy(resulting_string+index_in_string, head->value.pair->first->value.string->value);
|
||||||
|
index_in_string += head->value.pair->first->value.string->length;
|
||||||
|
head = head->value.pair->rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
resulting_string[index_in_string] = '\0';
|
||||||
|
|
||||||
|
return create_ast_node_string(resulting_string, resulting_string_len);
|
||||||
|
});
|
||||||
|
|
||||||
#undef report_error
|
#undef report_error
|
||||||
#undef cLambda
|
#undef cLambda
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ Ast_Node* lookup_symbol(Ast_Node* node, Environment* env) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
void print_indent(int indent) {
|
void print_indent(int indent) {
|
||||||
|
|||||||
+1
-1
@@ -52,6 +52,6 @@ char* Error_Type_to_string(Error_Type type) {
|
|||||||
case Error_Type::Unexpected_Eof: return "Parsing-error: Unexpected EOF";
|
case Error_Type::Unexpected_Eof: return "Parsing-error: Unexpected EOF";
|
||||||
case Error_Type::Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument";
|
case Error_Type::Unknown_Keyword_Argument: return "Evaluation-error: Unknown keyword argument";
|
||||||
case Error_Type::Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";
|
case Error_Type::Wrong_Number_Of_Arguments: return "Evaluation-error: Wrong number of arguments";
|
||||||
default: return "Unknown Error";
|
default: return "Unknown Error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-16
@@ -13,17 +13,17 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function) {
|
|||||||
create_ast_node_symbol(function->positional_arguments->identifiers[i]),
|
create_ast_node_symbol(function->positional_arguments->identifiers[i]),
|
||||||
arguments->value.pair->first, new_env);
|
arguments->value.pair->first, new_env);
|
||||||
} else {
|
} else {
|
||||||
// not enough arguments given
|
|
||||||
create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation);
|
create_error(Error_Type::Ill_Formed_Arguments, arguments->sourceCodeLocation);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
arguments = arguments->value.pair->rest;
|
arguments = arguments->value.pair->rest;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments->type == Ast_Node_Type::Nil)
|
|
||||||
goto eval_time;
|
|
||||||
|
|
||||||
String_Array_List* read_in_keywords = create_String_array_list(16);
|
String_Array_List* read_in_keywords = create_String_array_list(16);
|
||||||
|
|
||||||
|
if (arguments->type == Ast_Node_Type::Nil)
|
||||||
|
goto checks;
|
||||||
// keyword arguments: use all given ones and keep track of the
|
// keyword arguments: use all given ones and keep track of the
|
||||||
// added ones (array list), if end of parameters in encountered or
|
// added ones (array list), if end of parameters in encountered or
|
||||||
// something that is not a keyword is encountered or a keyword
|
// something that is not a keyword is encountered or a keyword
|
||||||
@@ -85,7 +85,7 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checks:
|
||||||
// check if all necessary keywords have been read in
|
// check if all necessary keywords have been read in
|
||||||
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
|
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
|
||||||
char* defined_keyword = function->keyword_arguments->identifiers[i];
|
char* defined_keyword = function->keyword_arguments->identifiers[i];
|
||||||
@@ -135,14 +135,14 @@ Ast_Node* apply_arguments_to_function(Ast_Node* arguments, Function* function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eval_time: {
|
|
||||||
Ast_Node* result;
|
|
||||||
try {
|
|
||||||
result = eval_expr(function->body, new_env);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
Ast_Node* result;
|
||||||
|
try {
|
||||||
|
result = eval_expr(function->body, new_env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -397,9 +397,11 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for list function
|
// check for lisp function
|
||||||
if (lispOperator->type == Ast_Node_Type::Function) {
|
if (lispOperator->type == Ast_Node_Type::Function) {
|
||||||
if (!lispOperator->value.function->is_special_form) {
|
// only for lambdas we evaluate the arguments before
|
||||||
|
// apllying
|
||||||
|
if (lispOperator->value.function->type == Function_Type::Lambda) {
|
||||||
try {
|
try {
|
||||||
arguments = eval_arguments(arguments, env, &arguments_length);
|
arguments = eval_arguments(arguments, env, &arguments_length);
|
||||||
}
|
}
|
||||||
@@ -413,9 +415,6 @@ Ast_Node* eval_expr(Ast_Node* node, Environment* env) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
#ifdef _DEBUG
|
|
||||||
__debugbreak();
|
|
||||||
#endif
|
|
||||||
report_error(Error_Type::Not_A_Function);
|
report_error(Error_Type::Not_A_Function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-6
@@ -1,14 +1,22 @@
|
|||||||
#define new(type) new type
|
#define new(type) new type
|
||||||
#define nullptr NULL
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define assert(cond) \
|
constexpr bool is_debug_build = true;
|
||||||
if (!cond) \
|
|
||||||
__debugbreak();
|
|
||||||
#else
|
#else
|
||||||
#define assert(cond)
|
constexpr bool is_debug_build = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define if_debug if constexpr (is_debug_build)
|
||||||
|
|
||||||
|
#define assert(cond) \
|
||||||
|
if_debug { \
|
||||||
|
if (!cond) { \
|
||||||
|
printf("Assertion failed: %s %d", __FILE__, __LINE__); \
|
||||||
|
__debugbreak(); \
|
||||||
|
} \
|
||||||
|
} else {} \
|
||||||
|
|
||||||
|
|
||||||
#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 \
|
||||||
@@ -62,7 +70,6 @@
|
|||||||
|
|
||||||
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);
|
||||||
// }
|
// }
|
||||||
|
|||||||
+69
-4
@@ -50,7 +50,7 @@ void print(Ast_Node* node) {
|
|||||||
printf("%f", node->value.number->value);
|
printf("%f", node->value.number->value);
|
||||||
} break;
|
} break;
|
||||||
case (Ast_Node_Type::String): {
|
case (Ast_Node_Type::String): {
|
||||||
printf("%s", node->value.string->value);
|
printf("\"%s\"", node->value.string->value);
|
||||||
} break;
|
} break;
|
||||||
case (Ast_Node_Type::Symbol): {
|
case (Ast_Node_Type::Symbol): {
|
||||||
printf("%s", node->value.symbol->identifier);
|
printf("%s", node->value.symbol->identifier);
|
||||||
@@ -59,10 +59,14 @@ 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_special_form)
|
if (node->value.function->type == Function_Type::Lambda)
|
||||||
printf("[special-lambda]");
|
|
||||||
else
|
|
||||||
printf("[lambda]");
|
printf("[lambda]");
|
||||||
|
else if (node->value.function->type == Function_Type::Special_Lambda)
|
||||||
|
printf("[special-lambda]");
|
||||||
|
else if (node->value.function->type == Function_Type::Macro)
|
||||||
|
printf("[macro]");
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
} break;
|
} break;
|
||||||
case (Ast_Node_Type::CFunction): {
|
case (Ast_Node_Type::CFunction): {
|
||||||
printf("[C-function]");
|
printf("[C-function]");
|
||||||
@@ -94,6 +98,67 @@ void print(Ast_Node* node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX(Felix): obv code dublicate
|
||||||
|
void fprint(FILE* f, Ast_Node* node) {
|
||||||
|
switch (node->type) {
|
||||||
|
case (Ast_Node_Type::Nil): {
|
||||||
|
fprintf(f, "nil");
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::T): {
|
||||||
|
fprintf(f, "t");
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::Number): {
|
||||||
|
fprintf(f, "%f", node->value.number->value);
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::String): {
|
||||||
|
fprintf(f, "\"%s\"", node->value.string->value);
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::Symbol): {
|
||||||
|
fprintf(f, "%s", node->value.symbol->identifier);
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::Keyword): {
|
||||||
|
fprintf(f, ":%s", node->value.keyword->identifier);
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::Function): {
|
||||||
|
if (node->value.function->type == Function_Type::Lambda)
|
||||||
|
fprintf(f, "[lambda]");
|
||||||
|
else if (node->value.function->type == Function_Type::Special_Lambda)
|
||||||
|
fprintf(f, "[special-lambda]");
|
||||||
|
else if (node->value.function->type == Function_Type::Macro)
|
||||||
|
fprintf(f, "[macro]");
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::CFunction): {
|
||||||
|
fprintf(f, "[C-function]");
|
||||||
|
} break;
|
||||||
|
case (Ast_Node_Type::Pair): {
|
||||||
|
Ast_Node* head = node;
|
||||||
|
fprintf(f, "(");
|
||||||
|
|
||||||
|
// NOTE(Felix): We cold do a while true here, however in case
|
||||||
|
// we want to print a broken list (for logging the error) we
|
||||||
|
// should do mo checks.
|
||||||
|
while (head) {
|
||||||
|
fprint(f, head->value.pair->first);
|
||||||
|
head = head->value.pair->rest;
|
||||||
|
if (!head)
|
||||||
|
return;
|
||||||
|
if (head->type != Ast_Node_Type::Pair)
|
||||||
|
break;
|
||||||
|
fprintf(f, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (head->type != Ast_Node_Type::Nil) {
|
||||||
|
fprintf(f, " . ");
|
||||||
|
print(head);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, ")");
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void print_error_location() {
|
void print_error_location() {
|
||||||
if (error->location) {
|
if (error->location) {
|
||||||
printf("%s (line %d, position %d)",
|
printf("%s (line %d, position %d)",
|
||||||
|
|||||||
+3
-2
@@ -52,12 +52,13 @@ 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* env = create_built_ins_environment();
|
||||||
load_built_ins_into_environment(env);
|
|
||||||
|
|
||||||
Parser::init(env);
|
Parser::init(env);
|
||||||
|
|
||||||
built_in_load("pre.slime", env);
|
built_in_load("pre.slime", env);
|
||||||
|
built_in_load("test.slime", env);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
log_error();
|
log_error();
|
||||||
delete_error();
|
delete_error();
|
||||||
|
|||||||
+82
-18
@@ -1,8 +1,8 @@
|
|||||||
// forward decls -- start
|
// forward decls -- start
|
||||||
void load_built_ins_into_environment(Environment*);
|
void load_built_ins_into_environment(Environment*);
|
||||||
int list_length(Ast_Node*);
|
|
||||||
void parse_argument_list(Ast_Node*, Function*);
|
|
||||||
Ast_Node* eval_expr(Ast_Node*, Environment*);
|
Ast_Node* eval_expr(Ast_Node*, Environment*);
|
||||||
|
void parse_argument_list(Ast_Node*, Function*);
|
||||||
|
int list_length(Ast_Node*);
|
||||||
// forward decls -- end
|
// forward decls -- end
|
||||||
|
|
||||||
|
|
||||||
@@ -18,16 +18,16 @@ namespace Parser {
|
|||||||
int parser_line;
|
int parser_line;
|
||||||
int parser_col;
|
int parser_col;
|
||||||
|
|
||||||
// NOTE(Felix): In this environment, the build in vunctions will
|
// NOTE(Felix): In this environment, the build in functions will
|
||||||
// be loaded, and the macros will be stroed in form of
|
// be loaded, and the macros will be stroed in form of
|
||||||
// special-lambdas, that get executed in this environment at
|
// special-lambdas, that get executed in this environment at
|
||||||
// read-time
|
// read-time. This should always be the global environment.
|
||||||
Environment* environment_for_macros;
|
Environment* environment_for_macros;
|
||||||
|
|
||||||
void init(Environment* env) {
|
void init(Environment* env) {
|
||||||
// if we already initialized it, then skip
|
// NOTE(Felix): it is important to keep the parser environment
|
||||||
if (environment_for_macros)
|
// up to date with the global environment. When donig tests,
|
||||||
return;
|
// or running a programm we have to reaload it.
|
||||||
|
|
||||||
// NOTE(Felix): For now we just allow executing built-ins at
|
// NOTE(Felix): For now we just allow executing built-ins at
|
||||||
// read-time (while creating macros). If later we want to
|
// read-time (while creating macros). If later we want to
|
||||||
@@ -148,6 +148,10 @@ namespace Parser {
|
|||||||
*str = '\0';
|
*str = '\0';
|
||||||
Ast_Node* ret = create_ast_node_string(str, 0);
|
Ast_Node* ret = create_ast_node_string(str, 0);
|
||||||
inject_scl(ret);
|
inject_scl(ret);
|
||||||
|
|
||||||
|
// plus one because we want to go after the quotes
|
||||||
|
*index_in_text += 1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,11 +223,19 @@ namespace Parser {
|
|||||||
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 it is quoted
|
||||||
if (text[*index_in_text] == '\'') {
|
if (text[*index_in_text] == '\'' ||
|
||||||
|
text[*index_in_text] == '`' ||
|
||||||
|
text[*index_in_text] == ',')
|
||||||
|
{
|
||||||
|
char quoteType = text[*index_in_text];
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
Ast_Node* result;
|
Ast_Node* result;
|
||||||
if (text[*index_in_text] == '(' || text[*index_in_text] == '\'' ) {
|
if (text[*index_in_text] == '(' ||
|
||||||
|
text[*index_in_text] == '\'' ||
|
||||||
|
text[*index_in_text] == '`' ||
|
||||||
|
text[*index_in_text] == ',')
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
result = parse_expression(text, index_in_text);
|
result = parse_expression(text, index_in_text);
|
||||||
}
|
}
|
||||||
@@ -232,11 +244,22 @@ namespace Parser {
|
|||||||
result = parse_atom(text, index_in_text);
|
result = parse_atom(text, index_in_text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quoteType == '\'')
|
||||||
|
return create_ast_node_pair(
|
||||||
|
create_ast_node_symbol("quote"),
|
||||||
|
create_ast_node_pair(result, create_ast_node_nil()));
|
||||||
|
else if (quoteType == '`')
|
||||||
|
return create_ast_node_pair(
|
||||||
|
create_ast_node_symbol("quasiquote"),
|
||||||
|
create_ast_node_pair(result, create_ast_node_nil()));
|
||||||
|
// it has to be an unquote
|
||||||
return create_ast_node_pair(
|
return create_ast_node_pair(
|
||||||
create_ast_node_symbol("quote"),
|
create_ast_node_symbol("unquote"),
|
||||||
create_ast_node_pair(result, create_ast_node_nil()));
|
create_ast_node_pair(result, create_ast_node_nil()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if it is not quoted
|
// if it is not quoted
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
++parser_col;
|
++parser_col;
|
||||||
@@ -258,7 +281,11 @@ namespace Parser {
|
|||||||
Ast_Node* expression = head;
|
Ast_Node* expression = head;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (text[(*index_in_text)] == '(' || text[(*index_in_text)] == '\'' ) {
|
if (text[*index_in_text] == '(' ||
|
||||||
|
text[*index_in_text] == '\''||
|
||||||
|
text[*index_in_text] == '`' ||
|
||||||
|
text[*index_in_text] == ',')
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
head->value.pair->first = parse_expression(text, index_in_text);
|
head->value.pair->first = parse_expression(text, index_in_text);
|
||||||
}
|
}
|
||||||
@@ -333,7 +360,7 @@ namespace Parser {
|
|||||||
|
|
||||||
Function* function = new(Function);
|
Function* function = new(Function);
|
||||||
function->parent_environment = environment_for_macros;
|
function->parent_environment = environment_for_macros;
|
||||||
function->is_special_form = true;
|
function->type = Function_Type::Macro;
|
||||||
|
|
||||||
// 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) {
|
||||||
@@ -393,14 +420,20 @@ namespace Parser {
|
|||||||
|
|
||||||
for (int i = 0; i < environment_for_macros->next_index; ++i) {
|
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]) &&
|
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)
|
environment_for_macros->values[i]->type == Ast_Node_Type::Function &&
|
||||||
|
environment_for_macros->values[i]->value.function->type == Function_Type::Macro)
|
||||||
{
|
{
|
||||||
// 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 {
|
try {
|
||||||
|
// if (string_equal(environment_for_macros->keys[i], "when")) {
|
||||||
|
// printf("invoking macro for %s in %s:%d to:\n\t", environment_for_macros->keys[i], parser_file, parser_line);
|
||||||
|
// print(environment_for_macros->values[i]->value.function->body);
|
||||||
|
// }
|
||||||
expression = eval_expr(expression, environment_for_macros);
|
expression = eval_expr(expression, environment_for_macros);
|
||||||
|
// if (string_equal(environment_for_macros->keys[i], "when")) {
|
||||||
|
// printf("\nresult: \n\t");
|
||||||
|
// print(expression);
|
||||||
|
// printf("\n\n");
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,10 +454,15 @@ namespace Parser {
|
|||||||
eat_until_code(text, &index_in_text);
|
eat_until_code(text, &index_in_text);
|
||||||
if (text[(index_in_text)] == '\0')
|
if (text[(index_in_text)] == '\0')
|
||||||
return create_ast_node_nil();
|
return create_ast_node_nil();
|
||||||
if (text[(index_in_text)] == '(' || text[(index_in_text)] == '\'' )
|
if (text[index_in_text] == '(' ||
|
||||||
|
text[index_in_text] == '\'' ||
|
||||||
|
text[index_in_text] == '`' ||
|
||||||
|
text[index_in_text] == ',')
|
||||||
|
{
|
||||||
try {
|
try {
|
||||||
result = parse_expression(text, &index_in_text);
|
result = parse_expression(text, &index_in_text);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
try {
|
try {
|
||||||
result = parse_atom(text, &index_in_text);
|
result = parse_atom(text, &index_in_text);
|
||||||
@@ -436,6 +474,29 @@ namespace Parser {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void write_expanded_file(char* file_name, Ast_Node_Array_List* program) {
|
||||||
|
char* ext = ".expanded";
|
||||||
|
char* newName = (char*)calloc(4 + strlen(file_name), sizeof(char));
|
||||||
|
strcpy(newName, file_name);
|
||||||
|
strcat(newName, ext);
|
||||||
|
|
||||||
|
FILE *f = fopen(newName, "w");
|
||||||
|
if (f == NULL) {
|
||||||
|
printf("Error opening file!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < program->next_index; ++i) {
|
||||||
|
// a macro will parse as nil for now, so we skip those
|
||||||
|
if (program->data[i]->type == Ast_Node_Type::Nil)
|
||||||
|
continue;
|
||||||
|
fprint(f, program->data[i]);
|
||||||
|
fprintf(f, "\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -468,6 +529,9 @@ namespace Parser {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write_expanded_file(file_name, program);
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-4
@@ -122,7 +122,8 @@
|
|||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>Default</CompileAs>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<Profile>true</Profile>
|
<Profile>true</Profile>
|
||||||
@@ -134,6 +135,7 @@
|
|||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<Profile>true</Profile>
|
<Profile>true</Profile>
|
||||||
@@ -159,12 +161,13 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<SDLCheck>true</SDLCheck>
|
<SDLCheck>true</SDLCheck>
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>Default</CompileAs>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>NotSet</SubSystem>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -173,4 +176,4 @@
|
|||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
</Project>
|
</Project>
|
||||||
Reference in New Issue
Block a user