work transfer to laptop
This commit is contained in:
+914
-1034
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -84,6 +84,8 @@ inline proc get_current_environment() -> Environment* {
|
||||
}
|
||||
|
||||
proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
|
||||
assert_type(node, Lisp_Object_Type::Symbol);
|
||||
|
||||
Lisp_Object* result = try_lookup_symbol(node, env);
|
||||
|
||||
if (result)
|
||||
@@ -110,8 +112,8 @@ proc print_environment_indent(Environment* env, int indent) -> void {
|
||||
}
|
||||
for (int i = 0; i < env->next_index; ++i) {
|
||||
print_indent(indent);
|
||||
printf("-> %s :: ", env->keys[i]);
|
||||
print(env->values[i]);
|
||||
printf(" %s", env->keys[i]);
|
||||
printf(" (%lld)", (long long)env->values[i]);
|
||||
puts("");
|
||||
}
|
||||
|
||||
+4
-4
@@ -9,10 +9,10 @@ proc delete_error() -> void {
|
||||
|
||||
proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void {
|
||||
|
||||
if (Globals::log_level > Log_Level::None) {
|
||||
printf("Error created in:\n %s:%d\n", c_file_name, c_file_line);
|
||||
printf(" -> %s\n", Memory::get_c_str(message));
|
||||
}
|
||||
if (Globals::log_level > Log_Level::None) {
|
||||
printf("Error created in:\n %s:%d\n", c_file_name, c_file_line);
|
||||
printf(" -> %s\n", Memory::get_c_str(message));
|
||||
}
|
||||
|
||||
delete_error();
|
||||
if (Globals::breaking_on_errors) {
|
||||
|
||||
+150
-152
@@ -1,30 +1,68 @@
|
||||
proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) -> Lisp_Object* {
|
||||
proc create_extended_environment_for_function_application(
|
||||
Lisp_Object* unevaluated_arguments,
|
||||
Lisp_Object* function) -> Environment*
|
||||
{
|
||||
profile_this;
|
||||
|
||||
bool is_c_function = Memory::get_type(function) == Lisp_Object_Type::CFunction;
|
||||
Environment* new_env;
|
||||
try new_env = Memory::create_child_environment(function->parent_environment);
|
||||
Lisp_Object* arguments = unevaluated_arguments;
|
||||
Arguments* arg_spec;
|
||||
|
||||
// NOTE(Felix): Step 1.
|
||||
// - setting the parent environment
|
||||
// - setting the arg_spec
|
||||
// - potentially evaluating the arguments
|
||||
if (is_c_function) {
|
||||
new_env = Memory::create_child_environment(get_root_environment());
|
||||
arg_spec = &function->value.cFunction->args;
|
||||
// if it is not a special form, evaluate the arguments
|
||||
if (!function->value.cFunction->is_special_form) {
|
||||
try arguments = eval_arguments(arguments);
|
||||
}
|
||||
} else {
|
||||
new_env = Memory::create_child_environment(function->value.function.parent_environment);
|
||||
arg_spec = &function->value.function.args;
|
||||
// if it is a lambda
|
||||
if (function->value.function.type == Function_Type::Lambda) {
|
||||
try arguments = eval_arguments(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(Felix): Even though we will return the environment at the
|
||||
// end, for defining symbols here for the parameters, it has to be
|
||||
// on the envi stack.
|
||||
push_environment(new_env);
|
||||
defer {
|
||||
pop_environment();
|
||||
};
|
||||
|
||||
|
||||
// NOTE(Felix): Step 2.
|
||||
// Reading the argument spec and fill in the environment
|
||||
// for the function call
|
||||
|
||||
Lisp_Object* sym, *val; // used as temp storage to use `try`
|
||||
String_Array_List read_in_keywords;
|
||||
int obligatory_keywords_count = 0;
|
||||
int read_obligatory_keywords_count = 0;
|
||||
|
||||
proc read_positional_args = [&]() -> void {
|
||||
for (int i = 0; i < function->args.positional.symbols.next_index; ++i) {
|
||||
for (int i = 0; i < arg_spec->positional.symbols.next_index; ++i) {
|
||||
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
|
||||
create_wrong_number_of_arguments_error(function->args.positional.symbols.next_index, i);
|
||||
create_wrong_number_of_arguments_error(arg_spec->positional.symbols.next_index, i);
|
||||
return;
|
||||
}
|
||||
// NOTE(Felix): We have to copy all the arguments, otherwise
|
||||
// we change the program code.
|
||||
try_void sym = function->args.positional.symbols.data[i];
|
||||
define_symbol(
|
||||
sym,
|
||||
Memory::copy_lisp_object_except_pairs(arguments->value.pair.first));
|
||||
// NOTE(Felix): We have to copy all the arguments,
|
||||
// otherwise we change the program code. XXX(Felix): T C
|
||||
// functions we pass by reference...
|
||||
try_void sym = arg_spec->positional.symbols.data[i];
|
||||
if (is_c_function) {
|
||||
define_symbol(sym, arguments->value.pair.first);
|
||||
} else {
|
||||
define_symbol(
|
||||
sym,
|
||||
Memory::copy_lisp_object_except_pairs(arguments->value.pair.first));
|
||||
}
|
||||
|
||||
arguments = arguments->value.pair.rest;
|
||||
}
|
||||
@@ -41,8 +79,8 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
return;
|
||||
|
||||
// find out how many keyword args we /have/ to read
|
||||
for (int i = 0; i < function->args.keyword.values.next_index; ++i) {
|
||||
if (function->args.keyword.values.data[i] == nullptr)
|
||||
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||
if (arg_spec->keyword.values.data[i] == nullptr)
|
||||
++obligatory_keywords_count;
|
||||
else
|
||||
break;
|
||||
@@ -52,10 +90,10 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
|
||||
// check if this one is even an accepted keyword
|
||||
bool accepted = false;
|
||||
for (int i = 0; i < function->args.keyword.values.next_index; ++i) {
|
||||
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||
if (string_equal(
|
||||
arguments->value.pair.first->value.symbol.identifier,
|
||||
function->args.keyword.keywords.data[i]->value.symbol.identifier))
|
||||
arg_spec->keyword.keywords.data[i]->value.symbol.identifier))
|
||||
{
|
||||
accepted = true;
|
||||
break;
|
||||
@@ -108,9 +146,13 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
// if not set it and then add it to the array list
|
||||
try_void sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier);
|
||||
// NOTE(Felix): It seems we do not need to evaluate the argument here...
|
||||
try_void define_symbol(
|
||||
sym,
|
||||
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first));
|
||||
if (is_c_function) {
|
||||
try_void define_symbol(sym, arguments->value.pair.rest->value.pair.first);
|
||||
} else {
|
||||
try_void define_symbol(
|
||||
sym,
|
||||
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first));
|
||||
}
|
||||
|
||||
append_to_array_list(&read_in_keywords, arguments->value.pair.first->value.symbol.identifier);
|
||||
++read_obligatory_keywords_count;
|
||||
@@ -126,8 +168,8 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
|
||||
proc check_keyword_args = [&]() -> void {
|
||||
// check if all necessary keywords have been read in
|
||||
for (int i = 0; i < function->args.keyword.values.next_index; ++i) {
|
||||
String* defined_keyword = function->args.keyword.keywords.data[i]->value.symbol.identifier;
|
||||
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||
String* defined_keyword = arg_spec->keyword.keywords.data[i]->value.symbol.identifier;
|
||||
bool was_set = false;
|
||||
for (int j = 0; j < read_in_keywords.next_index; ++j) {
|
||||
// TODO(Felix): Later compare the keywords, not their strings!!
|
||||
@@ -139,7 +181,7 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (function->args.keyword.values.data[i] == nullptr) {
|
||||
if (arg_spec->keyword.values.data[i] == nullptr) {
|
||||
// if this one does not have a default value
|
||||
if (!was_set) {
|
||||
create_generic_error(
|
||||
@@ -153,7 +195,11 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
// to use it or if the user supplied his own
|
||||
if (!was_set) {
|
||||
try_void sym = Memory::get_or_create_lisp_object_symbol(defined_keyword);
|
||||
try_void val = Memory::copy_lisp_object_except_pairs(function->args.keyword.values.data[i]);
|
||||
if (is_c_function) {
|
||||
try_void val = arg_spec->keyword.values.data[i];
|
||||
} else {
|
||||
try_void val = Memory::copy_lisp_object_except_pairs(arg_spec->keyword.values.data[i]);
|
||||
}
|
||||
define_symbol(sym, val);
|
||||
}
|
||||
}
|
||||
@@ -162,13 +208,13 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
|
||||
proc read_rest_arg = [&]() -> void {
|
||||
if (arguments == Memory::nil) {
|
||||
if (function->args.rest) {
|
||||
define_symbol(function->args.rest, Memory::nil);
|
||||
if (arg_spec->rest) {
|
||||
define_symbol(arg_spec->rest, Memory::nil);
|
||||
}
|
||||
} else {
|
||||
if (function->args.rest) {
|
||||
if (arg_spec->rest) {
|
||||
define_symbol(
|
||||
function->args.rest,
|
||||
arg_spec->rest,
|
||||
// NOTE(Felix): arguments will be a list, and I THINK
|
||||
// we do not need to copy it...
|
||||
arguments);
|
||||
@@ -187,11 +233,27 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
try check_keyword_args();
|
||||
try read_rest_arg();
|
||||
|
||||
Lisp_Object* result;
|
||||
try result = eval_expr(function->body);
|
||||
return result;
|
||||
return new_env;
|
||||
}
|
||||
|
||||
proc apply_arguments_to_function(Lisp_Object* arguments, Lisp_Object* function) -> Lisp_Object* {
|
||||
profile_this;
|
||||
Environment* new_env;
|
||||
try new_env = create_extended_environment_for_function_application(arguments, function);
|
||||
push_environment(new_env);
|
||||
defer {
|
||||
pop_environment();
|
||||
};
|
||||
|
||||
Lisp_Object* result;
|
||||
// if c function:
|
||||
if (Memory::get_type(function) == Lisp_Object_Type::CFunction)
|
||||
try result = function->value.cFunction->body();
|
||||
else // if lisp function
|
||||
try result = eval_expr(function->value.function.body);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
This parses the argument specification of funcitons into their
|
||||
@@ -199,145 +261,84 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
positional_arguments, keyword_arguments and rest_argument and
|
||||
filling it in
|
||||
*/
|
||||
proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void {
|
||||
proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_Object* function) -> void {
|
||||
Arguments* result;
|
||||
if (Memory::get_type(function) == Lisp_Object_Type::CFunction) {
|
||||
result = &function->value.cFunction->args;
|
||||
} else {
|
||||
result = &function->value.function.args;
|
||||
}
|
||||
|
||||
// first init the fields
|
||||
function->args.positional = create_positional_argument_list(16);
|
||||
function->args.keyword = create_keyword_argument_list(16);
|
||||
function->args.rest = nullptr;
|
||||
result->positional = create_positional_argument_list(16);
|
||||
result->keyword = create_keyword_argument_list(16);
|
||||
result->rest = nullptr;
|
||||
|
||||
// okay let's try to read some positional arguments
|
||||
while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) {
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
|
||||
if (string_equal(arguments->value.pair.first->value.symbol.identifier, "keys") ||
|
||||
string_equal(arguments->value.pair.first->value.symbol.identifier, "rest"))
|
||||
// if we encounter a keyword or a list (for keywords with
|
||||
// defualt args), the positionals are done
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword ||
|
||||
Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Pair) {
|
||||
break;
|
||||
else {
|
||||
create_parsing_error("A non recognized marker was found "
|
||||
"in the lambda list: ':%s'",
|
||||
&arguments->value.pair.first->value.symbol.identifier->data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we encounter something that is neither a symbol nor a
|
||||
// keyword arg, it's an error
|
||||
if (Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) {
|
||||
create_parsing_error("Only symbols and keywords can be "
|
||||
"parsed here, but found '%s'",
|
||||
create_parsing_error("Only symbols and keywords "
|
||||
"(with or without default args) "
|
||||
"can be parsed here, but found '%s'",
|
||||
Lisp_Object_Type_to_string(Memory::get_type(arguments->value.pair.first)));
|
||||
return;
|
||||
}
|
||||
|
||||
// okay wow we found an actual symbol
|
||||
// okay we found an actual symbol
|
||||
append_to_positional_argument_list(
|
||||
&function->args.positional,
|
||||
&result->positional,
|
||||
arguments->value.pair.first);
|
||||
|
||||
arguments = arguments->value.pair.rest;
|
||||
}
|
||||
|
||||
// okay we are done with positional arguments, lets check for
|
||||
// keywords,
|
||||
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
|
||||
if (arguments != Memory::nil)
|
||||
create_parsing_error("The lambda list must be nil terminated.");
|
||||
return;
|
||||
}
|
||||
// if we reach here, we are on a keyword or a pair wher a keyword
|
||||
// should be in first
|
||||
while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) {
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
|
||||
// if we are on a actual keyword (with no default arg)
|
||||
auto keyword = arguments->value.pair.first;
|
||||
append_to_keyword_argument_list(&result->keyword, keyword, nullptr);
|
||||
} else if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Pair) {
|
||||
// if we are on a keyword with a default value
|
||||
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword &&
|
||||
string_equal(arguments->value.pair.first->value.symbol.identifier, "keys"))
|
||||
{
|
||||
arguments = arguments->value.pair.rest;
|
||||
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
|
||||
create_parsing_error("Actual keys have to follow the :keys indicator.");
|
||||
}
|
||||
// if (arguments->value.pair.first->type != Lisp_Object_Type::Symbol) {
|
||||
// create_parsing_error(
|
||||
// "Only symbols can be parsed here, but found '%s'.",
|
||||
// Lisp_Object_Type_to_string(arguments->value.pair.first->type));
|
||||
// return;
|
||||
// }
|
||||
|
||||
while (Memory::get_type(arguments) == Lisp_Object_Type::Pair) {
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
|
||||
if (string_equal(arguments->value.pair.first->value.symbol.identifier, "rest"))
|
||||
break;
|
||||
else {
|
||||
create_parsing_error(
|
||||
"Only the :rest keyword can be parsed here, but got ':%s'.",
|
||||
&arguments->value.pair.first->value.symbol.identifier->data);
|
||||
return;
|
||||
}
|
||||
auto keyword = arguments->value.pair.first->value.pair.first;
|
||||
if (Memory::get_type(keyword) != Lisp_Object_Type::Keyword) {
|
||||
create_parsing_error("Default args must be keywords");
|
||||
}
|
||||
|
||||
if (Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol) {
|
||||
create_parsing_error(
|
||||
"Only symbols can be parsed here, but found '%s'.",
|
||||
Lisp_Object_Type_to_string(Memory::get_type(arguments->value.pair.first)));
|
||||
return;
|
||||
}
|
||||
|
||||
// we found a symbol (arguments->value.pair->first) for
|
||||
// the keyword args! Let's check if the next arguement is
|
||||
// :defaults-to
|
||||
Lisp_Object* next = arguments->value.pair.rest;
|
||||
if (Memory::get_type(next) == Lisp_Object_Type::Pair &&
|
||||
Memory::get_type(next->value.pair.first) == Lisp_Object_Type::Keyword &&
|
||||
string_equal(next->value.pair.first->value.symbol.identifier,
|
||||
"defaults-to"))
|
||||
if (Memory::get_type(arguments->value.pair.first->value.pair.rest)
|
||||
!= Lisp_Object_Type::Pair)
|
||||
{
|
||||
// check if there is a next argument too, otherwise it
|
||||
// would be an error
|
||||
next = next->value.pair.rest;
|
||||
if (Memory::get_type(next) == Lisp_Object_Type::Pair) {
|
||||
Lisp_Object* ret;
|
||||
push_environment(function->parent_environment);
|
||||
defer {
|
||||
pop_environment();
|
||||
};
|
||||
try_void ret = eval_expr(next->value.pair.first);
|
||||
append_to_keyword_argument_list(&function->args.keyword,
|
||||
arguments->value.pair.first,
|
||||
ret);
|
||||
arguments = next->value.pair.rest;
|
||||
} else {
|
||||
create_parsing_error("Expecting a value after 'defaults-to'");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// No :defaults-to, so just add it to the list
|
||||
append_to_keyword_argument_list(&function->args.keyword,
|
||||
arguments->value.pair.first,
|
||||
nullptr);
|
||||
arguments = next;
|
||||
create_parsing_error("Default args must be a list of 2.");
|
||||
}
|
||||
auto value = arguments->value.pair.first->value.pair.rest->value.pair.first;
|
||||
if (arguments->value.pair.first->value.pair.rest->value.pair.rest != Memory::nil) {
|
||||
create_parsing_error("Default args must be a list of 2.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
append_to_keyword_argument_list(&result->keyword, keyword, value);
|
||||
}
|
||||
arguments = arguments->value.pair.rest;
|
||||
}
|
||||
|
||||
// Now we are also done with keyword arguments, lets check for
|
||||
// if there is a rest argument
|
||||
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
|
||||
if (arguments != Memory::nil)
|
||||
create_parsing_error("The lambda list must be nil terminated.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword &&
|
||||
string_equal(arguments->value.pair.first->value.symbol.identifier, "rest"))
|
||||
{
|
||||
arguments = arguments->value.pair.rest;
|
||||
if (// arguments->type != Lisp_Object_Type::Pair ||
|
||||
Memory::get_type(arguments->value.pair.first) != Lisp_Object_Type::Symbol)
|
||||
{
|
||||
create_parsing_error("After the 'rest' marker there must follow a symbol.");
|
||||
if (arguments == Memory::nil)
|
||||
return;
|
||||
}
|
||||
function->args.rest = arguments->value.pair.first;
|
||||
if (arguments->value.pair.rest != Memory::nil) {
|
||||
create_parsing_error("The lambda list must end after the rest symbol");
|
||||
}
|
||||
} else {
|
||||
printf("this should not happen?");
|
||||
create_generic_error("What is happening?");
|
||||
if (Memory::get_type(arguments) == Lisp_Object_Type::Symbol)
|
||||
result->rest = arguments;
|
||||
else
|
||||
create_parsing_error("The rest argument must be a symbol.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,11 +362,11 @@ proc list_length(Lisp_Object* node) -> int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc eval_arguments(Lisp_Object* arguments, int *out_arguments_length) -> Lisp_Object* {
|
||||
proc eval_arguments(Lisp_Object* arguments) -> Lisp_Object* {
|
||||
profile_this;
|
||||
int my_out_arguments_length = 0;
|
||||
// int my_out_arguments_length = 0;
|
||||
if (arguments == Memory::nil) {
|
||||
*(out_arguments_length) = 0;
|
||||
// *(out_arguments_length) = 0;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
@@ -390,9 +391,9 @@ proc eval_arguments(Lisp_Object* arguments, int *out_arguments_length) -> Lisp_O
|
||||
create_parsing_error("Attempting to evaluate ill formed argument list.");
|
||||
return nullptr;
|
||||
}
|
||||
++my_out_arguments_length;
|
||||
// ++my_out_arguments_length;
|
||||
}
|
||||
*(out_arguments_length) = my_out_arguments_length;
|
||||
// *(out_arguments_length) = my_out_arguments_length;
|
||||
return evaluated_arguments;
|
||||
}
|
||||
|
||||
@@ -435,12 +436,10 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* {
|
||||
}
|
||||
|
||||
Lisp_Object* arguments = node->value.pair.rest;
|
||||
int arguments_length;
|
||||
|
||||
// check for c function
|
||||
if (Memory::get_type(lispOperator) == Lisp_Object_Type::CFunction) {
|
||||
Lisp_Object* result;
|
||||
try result = lispOperator->value.cFunction->function(arguments);
|
||||
try result = apply_arguments_to_function(arguments, lispOperator);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -449,12 +448,9 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* {
|
||||
// only for lambdas we evaluate the arguments before
|
||||
// apllying, for the other types, special-lambda and macro
|
||||
// we do not need.
|
||||
if (lispOperator->value.function.type == Function_Type::Lambda) {
|
||||
try arguments = eval_arguments(arguments, &arguments_length);
|
||||
}
|
||||
|
||||
Lisp_Object* result;
|
||||
try result = apply_arguments_to_function(arguments, &lispOperator->value.function);
|
||||
try result = apply_arguments_to_function(arguments, lispOperator);
|
||||
|
||||
// NOTE(Felix): The parser does not understnad (import ..)
|
||||
// so it cannot expand imported macros at read time
|
||||
@@ -464,7 +460,9 @@ proc eval_expr(Lisp_Object* node) -> Lisp_Object* {
|
||||
// and bake them in, so they do not have to be expanded
|
||||
// later again. We will call this "lazy macro expansion"
|
||||
if (lispOperator->value.function.type == Function_Type::Macro) {
|
||||
// bake in the macro expansion:
|
||||
*node = *result;
|
||||
// eval again because macro
|
||||
try result = eval_expr(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ proc built_in_import(String*) -> Lisp_Object*;
|
||||
proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, String* message) -> void;
|
||||
proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...) -> void;
|
||||
proc create_error(Lisp_Object* type, const char* message, const char* c_file_name, int c_file_line) -> void;
|
||||
proc eval_arguments(Lisp_Object*, int*) -> Lisp_Object*;
|
||||
proc eval_arguments(Lisp_Object*) -> Lisp_Object*;
|
||||
proc eval_expr(Lisp_Object*) -> Lisp_Object*;
|
||||
proc is_truthy (Lisp_Object*) -> bool;
|
||||
proc list_length(Lisp_Object*) -> int;
|
||||
proc load_built_ins_into_environment() -> void;
|
||||
proc parse_argument_list(Lisp_Object*, Function*) -> void;
|
||||
proc create_arguments_from_lambda_list_and_inject(Lisp_Object* formal_arguments, Lisp_Object* function) -> void;
|
||||
|
||||
|
||||
proc print_environment(Environment*) -> void;
|
||||
@@ -36,6 +36,8 @@ namespace Parser {
|
||||
extern String* parser_file;
|
||||
extern int parser_line;
|
||||
extern int parser_col;
|
||||
|
||||
proc parse_single_expression(char* text) -> Lisp_Object*;
|
||||
}
|
||||
|
||||
namespace Globals {
|
||||
|
||||
+94
-93
@@ -1,93 +1,94 @@
|
||||
namespace GC {
|
||||
proc maybe_mark(Environment* env) -> void;
|
||||
|
||||
int current_mark;
|
||||
|
||||
Lisp_Object_Array_List marked_objects;
|
||||
String_Array_List marked_strings;
|
||||
Environment_Array_List marked_environments;
|
||||
Environment_Array_List protected_environments;
|
||||
|
||||
proc marked(Lisp_Object* node) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
proc marked(Environment* env) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
proc maybe_mark(Lisp_Object* node) -> void {
|
||||
if (marked(node))
|
||||
return;
|
||||
|
||||
// mark object itself
|
||||
append_to_array_list(&marked_objects, node);
|
||||
|
||||
// mark docstring
|
||||
if (node->docstring)
|
||||
append_to_array_list(&marked_strings, node->docstring);
|
||||
|
||||
// mark type specific data
|
||||
switch (Memory::get_type(node)) {
|
||||
case Lisp_Object_Type::Pair: {
|
||||
for_lisp_list (node) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
case Lisp_Object_Type::Vector: {
|
||||
for_lisp_vector (node) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
case Lisp_Object_Type::String: {
|
||||
append_to_array_list(&marked_strings, node->value.string);
|
||||
} break;
|
||||
case Lisp_Object_Type::Function: {
|
||||
// NOTE(Felix): We dont have to mark the symbols, keywords
|
||||
// for parameter names, as symbols and keywords are never
|
||||
// garbage collected
|
||||
maybe_mark(node->value.function.parent_environment);
|
||||
maybe_mark(node->value.function.body);
|
||||
// mark the default arguemnt values:
|
||||
for_array_list (node->value.function.args.keyword.values) {
|
||||
if (it) maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proc maybe_mark(Environment* env) -> void {
|
||||
if (marked(env))
|
||||
return;
|
||||
|
||||
append_to_array_list(&marked_environments, env);
|
||||
|
||||
for_array_list (env->parents) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
|
||||
Lisp_Object* it = env->values[0];
|
||||
for (int i = 0; i < env->next_index; it = env->values[++i]) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
}
|
||||
|
||||
proc garbage_collect() -> void {
|
||||
profile_this;
|
||||
++current_mark;
|
||||
|
||||
for_array_list (protected_environments) maybe_mark(it);
|
||||
for_array_list (Globals::Current_Execution::envi_stack) maybe_mark(it);
|
||||
}
|
||||
|
||||
proc gc_init_and_go() -> void {
|
||||
current_mark = 0;
|
||||
marked_objects = create_Lisp_Object_array_list(1024);
|
||||
marked_environments = create_Environment_array_list(1024);
|
||||
|
||||
while (1) {
|
||||
garbage_collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace GC {
|
||||
proc maybe_mark(Environment* env) -> void;
|
||||
|
||||
int current_mark;
|
||||
|
||||
Lisp_Object_Array_List marked_objects;
|
||||
String_Array_List marked_strings;
|
||||
Environment_Array_List marked_environments;
|
||||
Environment_Array_List protected_environments;
|
||||
|
||||
proc marked(Lisp_Object* node) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
proc marked(Environment* env) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
proc maybe_mark(Lisp_Object* node) -> void {
|
||||
if (marked(node))
|
||||
return;
|
||||
|
||||
// mark object itself
|
||||
append_to_array_list(&marked_objects, node);
|
||||
|
||||
// mark docstring
|
||||
if (node->docstring)
|
||||
append_to_array_list(&marked_strings, node->docstring);
|
||||
|
||||
// mark type specific data
|
||||
switch (Memory::get_type(node)) {
|
||||
case Lisp_Object_Type::Pair: {
|
||||
for_lisp_list (node) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
case Lisp_Object_Type::Vector: {
|
||||
for_lisp_vector (node) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
case Lisp_Object_Type::String: {
|
||||
append_to_array_list(&marked_strings, node->value.string);
|
||||
} break;
|
||||
case Lisp_Object_Type::Function: {
|
||||
// NOTE(Felix): We dont have to mark the symbols, keywords
|
||||
// for parameter names, as symbols and keywords are never
|
||||
// garbage collected
|
||||
maybe_mark(node->value.function.parent_environment);
|
||||
maybe_mark(node->value.function.body);
|
||||
// mark the default arguemnt values:
|
||||
for_array_list (node->value.function.args.keyword.values) {
|
||||
if (it) maybe_mark(it);
|
||||
}
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proc maybe_mark(Environment* env) -> void {
|
||||
if (marked(env))
|
||||
return;
|
||||
|
||||
append_to_array_list(&marked_environments, env);
|
||||
|
||||
for_array_list (env->parents) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
|
||||
Lisp_Object* it = env->values[0];
|
||||
for (int i = 0; i < env->next_index; it = env->values[++i]) {
|
||||
maybe_mark(it);
|
||||
}
|
||||
}
|
||||
|
||||
proc garbage_collect() -> void {
|
||||
profile_this;
|
||||
++current_mark;
|
||||
|
||||
for_array_list (protected_environments) maybe_mark(it);
|
||||
for_array_list (Globals::Current_Execution::envi_stack) maybe_mark(it);
|
||||
}
|
||||
|
||||
proc gc_init_and_go() -> void {
|
||||
current_mark = 0;
|
||||
marked_objects = create_Lisp_Object_array_list(1024);
|
||||
marked_environments = create_Environment_array_list(1024);
|
||||
|
||||
while (1) {
|
||||
garbage_collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -366,7 +366,7 @@ proc print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout) -> v
|
||||
|
||||
if (Memory::get_type(head) != Lisp_Object_Type::Nil) {
|
||||
fputs(" . ", file);
|
||||
print(head);
|
||||
print(head, print_repr, file);
|
||||
}
|
||||
|
||||
putc(')', file);
|
||||
@@ -376,7 +376,7 @@ proc print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout) -> v
|
||||
|
||||
proc print_single_call(Lisp_Object* obj) -> void {
|
||||
printf(console_cyan);
|
||||
print(obj);
|
||||
print(obj, true);
|
||||
printf(console_normal);
|
||||
printf("\n at ");
|
||||
if (obj->sourceCodeLocation) {
|
||||
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
#include "slime.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
if (argc > 1) {
|
||||
if (Slime::string_equal(argv[1], "--run-tests")) {
|
||||
int res = Slime::run_all_tests();
|
||||
Slime::interprete_file("generate-docs.slime");
|
||||
Slime::interprete_file((char*)"generate-docs.slime");
|
||||
return res ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
+17
-16
@@ -184,8 +184,8 @@ namespace Memory {
|
||||
|
||||
try_void Parser::standard_in = create_string("stdin");
|
||||
|
||||
try_void Globals::Current_Execution::envi_stack.data[0] = create_built_ins_environment();
|
||||
try_void Globals::Current_Execution::envi_stack.next_index = 1;
|
||||
Globals::Current_Execution::envi_stack.next_index = 0;
|
||||
push_environment(create_built_ins_environment());
|
||||
}
|
||||
|
||||
proc reset() -> void {
|
||||
@@ -198,8 +198,8 @@ namespace Memory {
|
||||
next_index_in_environment_memory = 0;
|
||||
next_free_spot_in_string_memory = string_memory;
|
||||
|
||||
try_void Globals::Current_Execution::envi_stack.data[0] = create_built_ins_environment();
|
||||
try_void Globals::Current_Execution::envi_stack.next_index = 1;
|
||||
Globals::Current_Execution::envi_stack.next_index = 0;
|
||||
push_environment(create_built_ins_environment());
|
||||
}
|
||||
|
||||
proc create_lisp_object_number(double number) -> Lisp_Object* {
|
||||
@@ -306,13 +306,14 @@ namespace Memory {
|
||||
Memory::create_string(keyword));
|
||||
}
|
||||
|
||||
proc create_lisp_object_cfunction(std::function<Lisp_Object* (Lisp_Object*)> function) -> Lisp_Object* {
|
||||
proc create_lisp_object_cfunction(bool is_special) -> Lisp_Object* {
|
||||
Lisp_Object* node;
|
||||
try node = create_lisp_object();
|
||||
set_type(node, Lisp_Object_Type::CFunction);
|
||||
// node->value.lambdaWrapper = new Lambda_Wrapper(function);
|
||||
node->value.cFunction = new(cFunction);
|
||||
node->value.cFunction->function = function;
|
||||
node->value.cFunction->args = {};
|
||||
node->value.cFunction->is_special_form = is_special;
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -402,17 +403,17 @@ namespace Memory {
|
||||
|
||||
load_built_ins_into_environment();
|
||||
|
||||
// // save the current working directory
|
||||
// char* cwd = get_cwd();
|
||||
// defer {
|
||||
// change_cwd(cwd);
|
||||
// free(cwd);
|
||||
// };
|
||||
// save the current working directory
|
||||
//char* cwd = get_cwd();
|
||||
//defer {
|
||||
// change_cwd(cwd);
|
||||
// free(cwd);
|
||||
//};
|
||||
|
||||
// // get the direction of the exe
|
||||
// char* exe_path = get_exe_dir();
|
||||
// change_cwd(exe_path);
|
||||
// free(exe_path);
|
||||
//// get the direction of the exe
|
||||
//char* exe_path = get_exe_dir();
|
||||
//change_cwd(exe_path);
|
||||
//free(exe_path);
|
||||
|
||||
built_in_load(Memory::create_string("pre.slime"));
|
||||
|
||||
|
||||
+99
-99
@@ -366,118 +366,118 @@ namespace Parser {
|
||||
}
|
||||
|
||||
// check if we have to create or delete or run macros
|
||||
while (Memory::get_type(expression->value.pair.first) == Lisp_Object_Type::Symbol) {
|
||||
Lisp_Object* parsed_symbol = expression->value.pair.first;
|
||||
if (string_equal("define-syntax", parsed_symbol->value.symbol.identifier)) {
|
||||
// create a new macro
|
||||
Lisp_Object* arguments = expression->value.pair.rest;
|
||||
Lisp_Object* body;
|
||||
int arguments_length;
|
||||
// while (Memory::get_type(expression->value.pair.first) == Lisp_Object_Type::Symbol) {
|
||||
// Lisp_Object* parsed_symbol = expression->value.pair.first;
|
||||
// if (string_equal("define-syntax", parsed_symbol->value.symbol.identifier)) {
|
||||
// // create a new macro
|
||||
// Lisp_Object* arguments = expression->value.pair.rest;
|
||||
// Lisp_Object* body;
|
||||
// int arguments_length;
|
||||
|
||||
// HACK(Felix): almost code duplicate from
|
||||
// `built_ins.cpp`: special-lambda
|
||||
try arguments_length = list_length(arguments);
|
||||
// // 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_wrong_number_of_arguments_error(3, arguments_length);
|
||||
return nullptr;
|
||||
}
|
||||
// // (define-syntax (defun name args :rest body) (...))
|
||||
// if (arguments_length < 2) {
|
||||
// create_wrong_number_of_arguments_error(3, arguments_length);
|
||||
// return nullptr;
|
||||
// }
|
||||
|
||||
assert_type(arguments->value.pair.first, Lisp_Object_Type::Pair);
|
||||
// assert_type(arguments->value.pair.first, Lisp_Object_Type::Pair);
|
||||
|
||||
// extract the name
|
||||
Lisp_Object* symbol_for_macro = arguments->value.pair.first->value.pair.first;
|
||||
body = arguments->value.pair.rest;
|
||||
arguments = arguments->value.pair.first->value.pair.rest;
|
||||
// // extract the name
|
||||
// Lisp_Object* symbol_for_macro = arguments->value.pair.first->value.pair.first;
|
||||
// body = arguments->value.pair.rest;
|
||||
// arguments = arguments->value.pair.first->value.pair.rest;
|
||||
|
||||
// Function* function = new(Function);
|
||||
Lisp_Object* macro;
|
||||
try macro = Memory::create_lisp_object();
|
||||
Memory::set_type(macro, Lisp_Object_Type::Function);
|
||||
macro->value.function.parent_environment = get_current_environment();
|
||||
macro->value.function.type = Function_Type::Macro;
|
||||
// // Function* function = new(Function);
|
||||
// Lisp_Object* macro;
|
||||
// try macro = Memory::create_lisp_object();
|
||||
// Memory::set_type(macro, Lisp_Object_Type::Function);
|
||||
// macro->value.function.parent_environment = get_current_environment();
|
||||
// macro->value.function.type = Function_Type::Macro;
|
||||
|
||||
// if parameters were specified
|
||||
if (arguments != Memory::nil) {
|
||||
try assert_type(arguments, Lisp_Object_Type::Pair);
|
||||
try parse_argument_list(arguments, ¯o->value.function);
|
||||
} else {
|
||||
macro->value.function.args.positional = create_positional_argument_list(1);
|
||||
macro->value.function.args.keyword = create_keyword_argument_list(1);
|
||||
macro->value.function.args.rest = nullptr;
|
||||
}
|
||||
// // if parameters were specified
|
||||
// if (arguments != Memory::nil) {
|
||||
// try assert_type(arguments, Lisp_Object_Type::Pair);
|
||||
// try create_arguments_from_lambda_list_and_inject(arguments, macro);
|
||||
// } else {
|
||||
// macro->value.function.args.positional = create_positional_argument_list(1);
|
||||
// macro->value.function.args.keyword = create_keyword_argument_list(1);
|
||||
// macro->value.function.args.rest = nullptr;
|
||||
// }
|
||||
|
||||
// arguments = arguments->value.pair.rest;
|
||||
// if there is a docstring, use it
|
||||
if (Memory::get_type(body->value.pair.first) == Lisp_Object_Type::String) {
|
||||
macro->docstring = body->value.pair.first->value.string;
|
||||
body = body->value.pair.rest;
|
||||
} else {
|
||||
macro->docstring = nullptr;
|
||||
}
|
||||
// // arguments = arguments->value.pair.rest;
|
||||
// // if there is a docstring, use it
|
||||
// if (Memory::get_type(body->value.pair.first) == Lisp_Object_Type::String) {
|
||||
// macro->docstring = body->value.pair.first->value.string;
|
||||
// body = body->value.pair.rest;
|
||||
// } else {
|
||||
// macro->docstring = nullptr;
|
||||
// }
|
||||
|
||||
// we are now in the function body, just wrap it in an
|
||||
// implicit begin
|
||||
try macro->value.function.body = Memory::create_lisp_object_pair(
|
||||
Memory::get_or_create_lisp_object_symbol("begin"),
|
||||
body);
|
||||
// // we are now in the function body, just wrap it in an
|
||||
// // implicit begin
|
||||
// try macro->value.function.body = Memory::create_lisp_object_pair(
|
||||
// Memory::get_or_create_lisp_object_symbol("begin"),
|
||||
// body);
|
||||
|
||||
inject_scl(macro);
|
||||
// macro->value.function = function;
|
||||
define_symbol(symbol_for_macro, macro);
|
||||
// inject_scl(macro);
|
||||
// // macro->value.function = function;
|
||||
// define_symbol(symbol_for_macro, macro);
|
||||
|
||||
// print_environment(environment_for_macros);
|
||||
return Memory::nil;
|
||||
// // print_environment(environment_for_macros);
|
||||
// return Memory::nil;
|
||||
|
||||
} else if (string_equal("delete-syntax", parsed_symbol->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.
|
||||
// } else if (string_equal("delete-syntax", parsed_symbol->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_generic_error("deleting macros has not yet be implemented,"
|
||||
"and I don't know if it is a good idea to do so.");
|
||||
return nullptr;
|
||||
} else {
|
||||
// if threre is a macro named like this, then macroexpand
|
||||
// if not it is regular code, dont touch.
|
||||
break;
|
||||
// create_generic_error("deleting macros has not yet be implemented,"
|
||||
// "and I don't know if it is a good idea to do so.");
|
||||
// return nullptr;
|
||||
// } else {
|
||||
// // if threre is a macro named like this, then macroexpand
|
||||
// // if not it is regular code, dont touch.
|
||||
// break;
|
||||
|
||||
Lisp_Object* macro = try_lookup_symbol(parsed_symbol, get_current_environment());
|
||||
if (macro &&
|
||||
Memory::get_type(macro) == Lisp_Object_Type::Function &&
|
||||
macro->value.function.type == Function_Type::Macro)
|
||||
{
|
||||
// printf("pretending to expand macro at %s %d %d: ",
|
||||
// Memory::get_c_str(parser_file),
|
||||
// parser_line, parser_col);
|
||||
// print(parsed_symbol);
|
||||
// printf("\n");
|
||||
// NOTE(Felix): Execute it as a special lambda,
|
||||
// because if we keep it as a macro, the evaluator
|
||||
// will think it is a stray macro that was not yet
|
||||
// expanded, and attempt to evaluate it twice (1.
|
||||
// for expanding, and 2. for evaluating)
|
||||
macro->value.function.type = Function_Type::Special_Lambda;
|
||||
// NOTE(Felix): deferred so even if eval expr
|
||||
// fails, and returns, the type will be be
|
||||
// resetted to macro.
|
||||
defer {
|
||||
macro->value.function.type = Function_Type::Macro;
|
||||
};
|
||||
try expression = eval_expr(expression);
|
||||
break;
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
// Lisp_Object* macro = try_lookup_symbol(parsed_symbol, get_current_environment());
|
||||
// if (macro &&
|
||||
// Memory::get_type(macro) == Lisp_Object_Type::Function &&
|
||||
// macro->value.function.type == Function_Type::Macro)
|
||||
// {
|
||||
// // printf("pretending to expand macro at %s %d %d: ",
|
||||
// // Memory::get_c_str(parser_file),
|
||||
// // parser_line, parser_col);
|
||||
// // print(parsed_symbol);
|
||||
// // printf("\n");
|
||||
// // NOTE(Felix): Execute it as a special lambda,
|
||||
// // because if we keep it as a macro, the evaluator
|
||||
// // will think it is a stray macro that was not yet
|
||||
// // expanded, and attempt to evaluate it twice (1.
|
||||
// // for expanding, and 2. for evaluating)
|
||||
// macro->value.function.type = Function_Type::Special_Lambda;
|
||||
// // NOTE(Felix): deferred so even if eval expr
|
||||
// // fails, and returns, the type will be be
|
||||
// // resetted to macro.
|
||||
// defer {
|
||||
// macro->value.function.type = Function_Type::Macro;
|
||||
// };
|
||||
// try expression = eval_expr(expression);
|
||||
// break;
|
||||
// } else break;
|
||||
// }
|
||||
// }
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
+5
-3
@@ -121,13 +121,15 @@ struct Environment {
|
||||
|
||||
struct Function {
|
||||
Function_Type type;
|
||||
Arguments args;
|
||||
Lisp_Object* body; // implicit begin
|
||||
Arguments args;
|
||||
Lisp_Object* body; // maybe implicit begin
|
||||
Environment* parent_environment; // we are doing closures now!!
|
||||
};
|
||||
|
||||
struct cFunction {
|
||||
std::function<Lisp_Object* (Lisp_Object*)> function;
|
||||
std::function<Lisp_Object* ()> body;
|
||||
Arguments args;
|
||||
bool is_special_form;
|
||||
};
|
||||
|
||||
struct Lisp_Object {
|
||||
|
||||
+12
-7
@@ -196,8 +196,7 @@ proc test_array_lists_searching() -> testresult {
|
||||
proc test_eval_operands() -> testresult {
|
||||
char operands_string[] = "((eval 1) (+ 1 2) \"okay\" (eval :haha))";
|
||||
Lisp_Object* operands = Parser::parse_single_expression(operands_string);
|
||||
int operands_length;
|
||||
try operands = eval_arguments(operands, &operands_length);
|
||||
try operands = eval_arguments(operands);
|
||||
|
||||
assert_no_error();
|
||||
assert_equal_int(list_length(operands), 4);
|
||||
@@ -504,7 +503,7 @@ proc test_built_in_type() -> testresult {
|
||||
assert_equal_string(result->value.symbol.identifier, "number");
|
||||
|
||||
// setting user type
|
||||
char exp_string2[] = "(begin (set-type a :my-type)(type a))";
|
||||
char exp_string2[] = "(begin (set-type! a :my-type)(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string2);
|
||||
result = eval_expr(expression);
|
||||
|
||||
@@ -514,7 +513,7 @@ proc test_built_in_type() -> testresult {
|
||||
assert_equal_string(result->value.symbol.identifier, "my-type");
|
||||
|
||||
// trying to set invalid user type
|
||||
char exp_string3[] = "(begin (set-type a \"wrong tpye\")(type a))";
|
||||
char exp_string3[] = "(begin (set-type! a \"wrong tpye\")(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string3);
|
||||
assert_no_error();
|
||||
|
||||
@@ -528,7 +527,7 @@ proc test_built_in_type() -> testresult {
|
||||
delete_error();
|
||||
|
||||
// deleting user type
|
||||
char exp_string4[] = "(begin (delete-type a)(type a))";
|
||||
char exp_string4[] = "(begin (delete-type! a)(type a))";
|
||||
expression = Parser::parse_single_expression(exp_string4);
|
||||
result = eval_expr(expression);
|
||||
|
||||
@@ -598,13 +597,19 @@ proc run_all_tests() -> bool {
|
||||
|
||||
bool result = true;
|
||||
|
||||
Memory::init(4096 * 2000, 1024 * 32, 4096 * 16 * 10);
|
||||
Environment* root_env = get_root_environment();
|
||||
Environment* user_env = Memory::create_child_environment(root_env);
|
||||
push_environment(user_env);
|
||||
defer{
|
||||
pop_environment();
|
||||
};
|
||||
|
||||
printf("-- Util --\n");
|
||||
invoke_test(test_array_lists_adding_and_removing);
|
||||
invoke_test(test_array_lists_sorting);
|
||||
invoke_test(test_array_lists_searching);
|
||||
|
||||
Memory::init(4096 * 2000, 1024 * 32, 4096 * 16 * 10);
|
||||
|
||||
printf("\n -- Parsing --\n");
|
||||
invoke_test(test_parse_atom);
|
||||
invoke_test(test_parse_expression);
|
||||
|
||||
Reference in New Issue
Block a user