This commit is contained in:
FelixBrendel
2019-12-04 11:55:40 +01:00
parent 28ab850bee
commit 667989e373
39 changed files with 2010 additions and 1273 deletions
+4 -4
View File
@@ -1,10 +1,10 @@
/**
Usage of the create_error_macros:
*/
#define __create_error(keyword, ...) \
create_error( \
__FUNCTION__, __FILE__, __LINE__, \
Memory::get_or_create_lisp_object_keyword(keyword), \
#define __create_error(keyword, ...) \
create_error( \
__FUNCTION__, __FILE__, __LINE__, \
Memory::get_keyword(keyword), \
__VA_ARGS__)
#define create_out_of_memory_error(...) \
+732 -732
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -49,7 +49,7 @@
#define ignore_logging fluid_let(Globals::log_level, Log_Level::None)
#define fetch1(var) \
Lisp_Object* var##_symbol = Memory::get_or_create_lisp_object_symbol(#var); \
Lisp_Object* var##_symbol = Memory::get_symbol(#var); \
Lisp_Object* var = lookup_symbol(var##_symbol, get_current_environment()); \
if_error_log_location_and_return(nullptr)
+1 -4
View File
@@ -20,7 +20,4 @@
#define console_red "\x1B[31m"
#define console_green "\x1B[32m"
#define console_cyan "\x1B[36m"
// #define console_normal ""
// #define console_red ""
// #define console_green ""
// #define console_cyan ""
+1 -3
View File
@@ -54,9 +54,7 @@ proc generate_docs(String* path) -> void {
*/
Lisp_Object_Type type = Memory::get_type(value);
Lisp_Object* LOtype;
Lisp_Object* type_expr = Memory::create_list(
Memory::get_or_create_lisp_object_symbol("type"),
value);
Lisp_Object* type_expr = Memory::create_list(Memory::get_symbol("type"), value);
try_void LOtype = eval_expr(type_expr);
fprintf(f, "\n - type :: =");
+58 -51
View File
@@ -1,119 +1,126 @@
proc define_symbol(Lisp_Object* symbol, Lisp_Object* value) -> void {
namespace Slime {
proc define_symbol(Lisp_Object* symbol, Lisp_Object* value) -> void {
profile_with_comment(&symbol->value.symbol->data);
Environment* env = get_current_environment();
env->hm.set_object((void*)symbol, value);
}
}
inline proc lookup_symbol_in_this_envt(Lisp_Object* sym, Environment* env) -> Lisp_Object* {
inline proc lookup_symbol_in_this_envt(Lisp_Object* sym, Environment* env) -> Lisp_Object* {
return (Lisp_Object*)env->hm.get_object((void*)sym);
}
}
proc environment_binds_symbol(Lisp_Object* sym, Environment* env) -> bool {
proc environment_binds_symbol(Lisp_Object* sym, Environment* env) -> bool {
return lookup_symbol_in_this_envt(sym, env) != nullptr;
}
}
proc find_binding_environment(Lisp_Object* sym, Environment* env) -> Environment* {
proc find_binding_environment(Lisp_Object* sym, Environment* env) -> Environment* {
if (environment_binds_symbol(sym, env))
return env;
return env;
for (auto it : env->parents) {
if (Environment* ret = find_binding_environment(sym, it))
return ret;
if (Environment* ret = find_binding_environment(sym, it))
return ret;
}
return nullptr;
}
}
proc try_lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
proc try_lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
// first check current environment
Lisp_Object* result;
result = lookup_symbol_in_this_envt(node, env);
if (result)
return result;
return result;
for (int i = 0; i < env->parents.next_index; ++i) {
result = try_lookup_symbol(node, env->parents.data[i]);
result = try_lookup_symbol(node, env->parents.data[i]);
if (result)
return result;
if (result)
return result;
}
auto nil_sym = Memory::get_or_create_lisp_object_symbol("nil");
auto t_sym = Memory::get_or_create_lisp_object_symbol("t");
auto nil_sym = Memory::get_symbol("nil");
auto t_sym = Memory::get_symbol("t");
if (node == nil_sym) {
return Memory::nil;
return Memory::nil;
}
if (node == t_sym) {
return Memory::t;
return Memory::t;
}
return nullptr;
}
}
inline proc push_environment(Environment* env) -> void {
inline proc push_environment(Environment* env) -> void {
using namespace Globals::Current_Execution;
envi_stack.append(env);
}
}
inline proc pop_environment() -> void {
inline proc pop_environment() -> void {
using namespace Globals::Current_Execution;
--envi_stack.next_index;
}
}
inline proc get_root_environment() -> Environment* {
inline proc get_root_environment() -> Environment* {
using namespace Globals::Current_Execution;
return envi_stack.data[0];
}
}
inline proc get_current_environment() -> Environment* {
inline proc get_current_environment() -> Environment* {
using namespace Globals::Current_Execution;
return envi_stack.data[envi_stack.next_index-1];
}
}
proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
profile_with_comment(&node->value.symbol->data);
// print(node);
assert_type(node, Lisp_Object_Type::Symbol);
Lisp_Object* result = try_lookup_symbol(node, env);
if (result)
return result;
return result;
String* identifier = node->value.symbol;
print_environment(env);
printf("\n");
create_symbol_undefined_error("The symbol '%s' is not defined.", &identifier->data);
return nullptr;
}
}
proc print_environment_indent(Environment* env, int indent) -> void {
proc print_environment_indent(Environment* env, int indent) -> void {
proc print_indent = [](int indent) {
for (int i = 0; i < indent; ++i) {
printf(" ");
}
};
for (int i = 0; i < indent; ++i) {
printf(" ");
}
};
// if(env == get_root_environment()) {
// print_indent(indent);
// printf("[built-ins]-Environment (%lld)\n", (long long)env);
// return;
// print_indent(indent);
// printf("[built-ins]-Environment (%lld)\n", (long long)env);
// return;
// }
for_hash_map (env->hm) {
print_indent(indent);
printf("-> %s :: ", &(((Lisp_Object*)key)->value.symbol->data));
print((Lisp_Object*)value);
printf(" (0x%016llx)", (unsigned long long)value);
puts("");
print_indent(indent);
printf("-> %s :: ", &(((Lisp_Object*)key)->value.symbol->data));
print((Lisp_Object*)value);
printf(" (0x%016llx)", (unsigned long long)value);
puts("");
}
for (int i = 0; i < env->parents.next_index; ++i) {
print_indent(indent);
printf("parent (0x%016llx)", (long long)env->parents.data[i]);
puts(":");
print_environment_indent(env->parents.data[i], indent+4);
print_indent(indent);
printf("parent (0x%016llx)", (long long)env->parents.data[i]);
puts(":");
print_environment_indent(env->parents.data[i], indent+4);
}
}
}
proc print_environment(Environment* env) -> void {
proc print_environment(Environment* env) -> void {
printf("\n=== Environment === (0x%016llx)\n", (long long)env);
print_environment_indent(env, 0);
}
}
+3 -5
View File
@@ -135,7 +135,7 @@ proc create_extended_environment_for_function_application(
}
// 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);
try_void sym = Memory::get_symbol(arguments->value.pair.first->value.symbol);
// NOTE(Felix): It seems we do not need to evaluate the argument here...
if (is_c_function) {
try_void define_symbol(sym, arguments->value.pair.rest->value.pair.first);
@@ -163,9 +163,7 @@ proc create_extended_environment_for_function_application(
auto defined_keyword = arg_spec->keyword.keywords.data[i];
bool was_set = false;
for (int j = 0; j < read_in_keywords.next_index; ++j) {
// TODO(Felix): Later compare the keywords, not their strings!!
if (read_in_keywords.data[j] == defined_keyword)
{
if (read_in_keywords.data[j] == defined_keyword) {
was_set = true;
break;
}
@@ -183,7 +181,7 @@ proc create_extended_environment_for_function_application(
// this one does have a default value, lets see if we have
// 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->value.symbol);
try_void sym = Memory::get_symbol(defined_keyword->value.symbol);
if (is_c_function) {
try_void val = arg_spec->keyword.values.data[i];
} else {
+6 -7
View File
@@ -34,18 +34,17 @@ void log_error();
namespace Memory {
Environment* create_built_ins_environment();
Lisp_Object* create_lisp_object_cfunction(bool is_special);
Lisp_Object* get_or_create_lisp_object_keyword(const char* identifier);
inline Lisp_Object_Type get_type(Lisp_Object* node);
void init(int);
char* get_c_str(String*);
void free_everything();
String* create_string(const char*);
Lisp_Object* create_lisp_object_number(double);
Lisp_Object* get_or_create_lisp_object_symbol(String* identifier);
Lisp_Object* get_or_create_lisp_object_symbol(const char*);
Lisp_Object* get_or_create_lisp_object_keyword(String* identifier);
Lisp_Object* get_or_create_lisp_object_keyword(const char*);
Lisp_Object* create_lisp_object_string(const char*);
Lisp_Object* get_symbol(String* identifier);
Lisp_Object* get_symbol(const char*);
Lisp_Object* get_keyword(String* identifier);
Lisp_Object* get_keyword(const char*);
Lisp_Object* create_lisp_object(double);
Lisp_Object* create_lisp_object(const char*);
Lisp_Object* create_lisp_object_vector(Lisp_Object*);
Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*);
Lisp_Object* create_lisp_object_vector(Lisp_Object*, Lisp_Object*, Lisp_Object*);
+5 -5
View File
@@ -120,7 +120,7 @@ proc unescape_string(char* in) -> int {
}
proc read_entire_file(char* filename) -> char* {
profile_this();
profile_with_comment(filename);
char *fileContent = nullptr;
FILE *fp = fopen(filename, "r");
if (fp) {
@@ -370,10 +370,10 @@ proc print(Lisp_Object* node, bool print_repr, FILE* file) -> void {
auto symbol = head->value.pair.first;
auto quote_sym = Memory::get_or_create_lisp_object_symbol("quote");
auto unquote_sym = Memory::get_or_create_lisp_object_symbol("unquote");
auto quasiquote_sym = Memory::get_or_create_lisp_object_symbol("quasiquote");
auto unquote_splicing_sym = Memory::get_or_create_lisp_object_symbol("unquote-splicing");
auto quote_sym = Memory::get_symbol("quote");
auto unquote_sym = Memory::get_symbol("unquote");
auto quasiquote_sym = Memory::get_symbol("quasiquote");
auto unquote_splicing_sym = Memory::get_symbol("unquote-splicing");
if (symbol == quote_sym || symbol == unquote_sym || symbol == unquote_splicing_sym)
{
if (symbol == quote_sym)
+1 -1
View File
@@ -115,7 +115,7 @@ namespace Slime {
# include "error.cpp"
# include "io.cpp"
# include "env.cpp"
# include "parse2.cpp"
# include "parse.cpp"
# include "eval.cpp"
# include "visualization.cpp"
# include "docgeneration.cpp"
+10
View File
@@ -1,6 +1,16 @@
#include "libslime.cpp"
int main(int argc, char* argv[]) {
if_windows {
// enable colored terminal output for windows
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hOut, dwMode);
}
if (argc > 1) {
if (Slime::string_equal(argv[1], "--run-tests")) {
int res = Slime::run_all_tests();
+28 -33
View File
@@ -241,7 +241,7 @@ namespace Memory {
push_environment(user_env);
}
proc create_lisp_object_pointer(void* ptr) -> Lisp_Object* {
proc create_lisp_object(void* ptr) -> Lisp_Object* {
Lisp_Object* node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::Pointer);
@@ -257,7 +257,7 @@ namespace Memory {
return node;
}
proc create_lisp_object_number(double number) -> Lisp_Object* {
proc create_lisp_object(double number) -> Lisp_Object* {
Lisp_Object* node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::Number);
@@ -265,7 +265,7 @@ namespace Memory {
return node;
}
proc create_lisp_object_string(String* str) -> Lisp_Object* {
proc create_lisp_object(String* str) -> Lisp_Object* {
Lisp_Object* node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::String);
@@ -273,7 +273,7 @@ namespace Memory {
return node;
}
proc create_lisp_object_string(const char* str) -> Lisp_Object* {
proc create_lisp_object(const char* str) -> Lisp_Object* {
Lisp_Object* node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::String);
@@ -355,8 +355,12 @@ namespace Memory {
}
proc create_new_lisp_object_symbol(String* identifier) -> Lisp_Object* {
Lisp_Object* node;
proc get_symbol(String* identifier) -> Lisp_Object* {
Lisp_Object* node = global_symbol_table.get_object(get_c_str(identifier));
if (node)
return (Lisp_Object*)node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::Symbol);
node->value.symbol = identifier;
@@ -364,8 +368,21 @@ namespace Memory {
return node;
}
proc create_new_lisp_object_keyword(String* keyword) -> Lisp_Object* {
Lisp_Object* node;
proc get_symbol(const char* identifier) -> Lisp_Object* {
if (auto ret = global_symbol_table.get_object((char*)identifier))
return (Lisp_Object*)ret;
else {
String* str;
try str = Memory::create_string(identifier);
return get_symbol(str);
}
}
proc get_keyword(String* keyword) -> Lisp_Object* {
Lisp_Object* node = global_keyword_table.get_object(get_c_str(keyword));
if (node)
return (Lisp_Object*)node;
try node = create_lisp_object();
set_type(node, Lisp_Object_Type::Keyword);
node->value.symbol = keyword;
@@ -373,37 +390,14 @@ namespace Memory {
return node;
}
proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* {
if (auto ret = global_symbol_table.get_object(get_c_str(identifier)))
return (Lisp_Object*)ret;
else
return create_new_lisp_object_symbol(identifier);
}
proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* {
if (auto ret = global_symbol_table.get_object((char*)identifier))
return (Lisp_Object*)ret;
else {
String* str;
try str = Memory::create_string(identifier);
return create_new_lisp_object_symbol(str);
}
}
proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* {
if (auto ret = global_keyword_table.get_object(get_c_str(keyword)))
return (Lisp_Object*)ret;
else
return create_new_lisp_object_keyword(keyword);
}
proc get_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* {
proc get_keyword(const char* keyword) -> Lisp_Object* {
if (auto ret = global_keyword_table.get_object((char*)keyword))
return (Lisp_Object*)ret;
else {
String* str;
try str = Memory::create_string(keyword);
return create_new_lisp_object_keyword(str);
return get_keyword(str);
}
}
@@ -474,6 +468,7 @@ namespace Memory {
return ret;
}
inline proc create_list(Lisp_Object* o1) -> Lisp_Object* {
Lisp_Object* ret;
try ret = create_lisp_object_pair(o1, nil);
+225 -343
View File
@@ -4,39 +4,6 @@ namespace Parser {
int parser_line;
int parser_col;
proc maybe_expand_reader_macro() -> Lisp_Object* {
// static Lisp_Object* quote_sym = Memory::get_or_create_lisp_object_symbol("quote");
// static Lisp_Object* qquote_sym = Memory::get_or_create_lisp_object_symbol("quasiquote");
// static Lisp_Object* unquote_sym = Memory::get_or_create_lisp_object_symbol("unquote");
// static Lisp_Object* us_sym = Memory::get_or_create_lisp_object_symbol("unquote-splicing");
// if (text[*index_in_text] == '\'') {
// *index_in_text++;
// return quote_sym;
// }
// if (text[*index_in_text] == '`') {
// *index_in_text++;
// return qquote_sym;
// }
// if (text[*index_in_text] == ',') {
// *index_in_text++;
// return unquote_sym;
// }
// if (text[*index_in_text] == ',' && text[*index_in_text] == '@') {
// *index_in_text += 2;
// return us_sym;
// }
return nullptr;
}
proc inject_scl(Lisp_Object* lo) -> void {
lo->sourceCodeLocation = (Source_Code_Location*)malloc(sizeof(Source_Code_Location));
lo->sourceCodeLocation->file = parser_file;
lo->sourceCodeLocation->line = parser_line;
lo->sourceCodeLocation->column = parser_col;
}
proc eat_comment_line(char* text, int* index_in_text) -> void {
// safety check if we are actually starting a comment here
if (text[*index_in_text] != ';')
@@ -51,13 +18,8 @@ namespace Parser {
text[(*index_in_text)] != '\0');
}
proc eat_whitespace(char* text, int* index_in_text) -> void {
// skip whitespaces
while (text[(*index_in_text)] == ' ' ||
text[(*index_in_text)] == '\t' ||
text[(*index_in_text)] == '\n' ||
text[(*index_in_text)] == '\r')
{
proc step_char(char* text, int* index_in_text, int steps = 1) {
for (int i = 0; i < steps; ++i) {
if (text[(*index_in_text)] == '\n') {
++parser_line;
parser_col = 0;
@@ -67,7 +29,19 @@ namespace Parser {
}
}
proc eat_whitespace(char* text, int* index_in_text) -> void {
// skip whitespaces
while (text[(*index_in_text)] == ' ' ||
text[(*index_in_text)] == '\t' ||
text[(*index_in_text)] == '\n' ||
text[(*index_in_text)] == '\r')
{
step_char(text, index_in_text);
}
}
proc eat_until_code(char* text, int* index_in_text) -> void {
profile_this();
int position_before;
do {
position_before = *index_in_text;
@@ -76,11 +50,48 @@ namespace Parser {
} while (position_before != *index_in_text);
}
proc read_atom(char* text, int* index_in_text) -> String* {
proc step_char_and_eat_until_code(char* text, int* index_in_text) {
step_char(text, index_in_text);
eat_until_code(text, index_in_text);
}
proc parse_fancy_delimiter(char* text, int* index_in_text, char l_delimiter, char r_delimiter, Lisp_Object* first_elem) -> Lisp_Object* {
profile_this();
if (text[*index_in_text] != l_delimiter) {
create_parsing_error("a fancy cannot be parsed here");
return nullptr;
}
Lisp_Object* ret;
Lisp_Object* head;
try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil);
head = ret;
step_char(text, index_in_text);
eat_until_code(text, index_in_text);
while (text[*index_in_text] != r_delimiter) {
Lisp_Object* element;
try element = parse_expression(text, index_in_text);
try head->value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil);
head = head->value.pair.rest;
eat_until_code(text, index_in_text);
}
step_char(text, index_in_text);
return ret;
}
proc get_atom_text_length(char* text, int* index_in_text) -> int {
int atom_length = 0;
while (text[*index_in_text+atom_length] != ' ' &&
text[*index_in_text+atom_length] != ')' &&
text[*index_in_text+atom_length] != '(' &&
text[*index_in_text+atom_length] != '[' &&
text[*index_in_text+atom_length] != ']' &&
text[*index_in_text+atom_length] != '{' &&
text[*index_in_text+atom_length] != '}' &&
text[*index_in_text+atom_length] != '\0' &&
text[*index_in_text+atom_length] != '\n' &&
text[*index_in_text+atom_length] != '\r' &&
@@ -88,79 +99,64 @@ namespace Parser {
{
++atom_length;
}
// let's mark the end of the atom there quickly, so the string can
// be copied from there easily and then put the char that was
// before there back
char before = text[*index_in_text+atom_length];
text[*index_in_text+atom_length] = '\0';
// get the atom
String* ret = Memory::create_string("", atom_length);
strcpy(&ret->data, text+(*index_in_text));
// restore the original string
text[*index_in_text+atom_length] = before;
// update the index to point to the character after the atom
// ended
*index_in_text += atom_length;
parser_col += atom_length;
return ret;
return atom_length;
}
proc parse_number(char* text, int* index_in_text) -> Lisp_Object* {
double number;
// TODO(Felix): parse the number direcrly from the string and
// dont create a String first
String* str_number = read_atom(text, index_in_text);
sscanf(Memory::get_c_str(str_number), "%lf", &number);
Lisp_Object* ret;
try ret = Memory::create_lisp_object_number(number);
try ret = Memory::create_lisp_object(0.0);
sscanf(text+*index_in_text, "%lf", &ret->value.number);
int atom_length = get_atom_text_length(text, index_in_text);
step_char(text, index_in_text, atom_length);
// inject_scl(ret);
return ret;
}
proc parse_keyword(char* text, int* index_in_text) -> Lisp_Object* {
// we are now on the colon
++(*index_in_text);
++parser_col;
String* str_keyword = read_atom(text, index_in_text);
Lisp_Object* ret;
try ret = Memory::get_or_create_lisp_object_keyword(str_keyword);
proc parse_symbol_or_keyword(char* text, int* index_in_text) -> Lisp_Object* {
bool keyword = false;
if (text[*index_in_text] == ':') {
keyword = true;
step_char(text, index_in_text);
}
int atom_length = get_atom_text_length(text, index_in_text);
char orig = text[*index_in_text+atom_length];
text[*index_in_text+atom_length] = '\0';
String* str_keyword;
Lisp_Object* ret;
try str_keyword = Memory::create_string("", atom_length);
strcpy(&str_keyword->data, text+*index_in_text);
if (keyword) {
try ret = Memory::get_keyword(str_keyword);
} else {
try ret = Memory::get_symbol(str_keyword);
}
text[*index_in_text+atom_length] = orig;
step_char(text, index_in_text, atom_length);
// inject_scl(ret);
return ret;
}
proc parse_symbol(char* text, int* index_in_text) -> Lisp_Object* {
// we are now at the first char of the symbol
String* str_symbol = read_atom(text, index_in_text);
Lisp_Object* ret;
try ret = Memory::get_or_create_lisp_object_symbol(str_symbol);
// inject_scl(ret);
return ret;
}
proc parse_string(char* text, int* index_in_text) -> Lisp_Object*{
proc parse_string(char* text, int* index_in_text) -> Lisp_Object* {
// the first character is the '"'
++(*index_in_text);
++parser_col;
step_char(text, index_in_text);
// now we are at the first letter, if this is the closing '"' then
// it's easy
if (text[*index_in_text] == '"') {
Lisp_Object* ret;
try ret = Memory::create_lisp_object_string(
Memory::create_string("", 0));
try ret = Memory::create_lisp_object(Memory::create_string("", 0));
// inject_scl(ret);
// plus one because we want to go after the quotes
*index_in_text += 1;
++parser_col;
step_char(text, index_in_text);
return ret;
}
@@ -190,40 +186,24 @@ namespace Parser {
String* string = Memory::create_string("", new_len);
// TODO(Felix): manually copy to parse control sequences
// correctly without the need to unescape the string, also
// better for keeping track of the encountered new lines and
// characters since last new line so we can update the parser
// location more easily
strcpy(&string->data, text+(*index_in_text));
// printf("------ %s\n", &string->data);
text[*index_in_text+string_length] = '"';
// plus one because we want to go after the quotes
*index_in_text += string_length +1;
// NOTE(Felix): this only has to be done until we manually
// copy the string and we can do some bookeeping:
/* recalculate the parser cursors position: */
/* new col = (count chars since last \n) + 1 */
for (int i = 0; i < string->length; ++i) {
if (*((&string->data)+i) == '\n') {
++parser_line;
parser_col = 0;
} else {
++parser_col;
}
}
step_char(text, index_in_text, string_length+1);
Lisp_Object* ret;
try ret = Memory::create_lisp_object_string(string);
try ret = Memory::create_lisp_object(string);
// inject_scl(ret);
return ret;
}
proc parse_atom(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
Lisp_Object* ret;
// numbers
if ((text[*index_in_text] <= 57 && // if number
text[*index_in_text] >= 48)
@@ -238,137 +218,143 @@ namespace Parser {
&&
(text[*index_in_text +1] <= 57 &&
text[*index_in_text +1] >= 48)))
return parse_number(text, index_in_text);
// keywords
if (text[*index_in_text] == ':')
return parse_keyword(text, index_in_text);
// strings
if (text[*index_in_text] == '"')
return parse_string(text, index_in_text);
return parse_symbol(text, index_in_text);
}
proc parse_expression(char* text, int* index_in_text) -> Lisp_Object* {
// if it is quoted
// TODO(Felix): This looks totally broken..
if (text[*index_in_text] == '\'' ||
text[*index_in_text] == '`' ||
text[*index_in_text] == '@' ||
text[*index_in_text] == ',')
{
char quoteType = text[*index_in_text];
++(*index_in_text);
++parser_col;
Lisp_Object* result;
if (text[*index_in_text] == '(' ||
text[*index_in_text] == '\'' ||
text[*index_in_text] == '`' ||
text[*index_in_text] == '@' ||
text[*index_in_text] == ',')
{
try result = parse_expression(text, index_in_text);
} else {
try result = parse_atom(text, index_in_text);
}
Lisp_Object* ret = nullptr;
if (quoteType == '\'')
try ret = Memory::create_list(Memory::get_or_create_lisp_object_symbol("quote"), result);
else if (quoteType == '`')
try ret = Memory::create_list(Memory::get_or_create_lisp_object_symbol("quasiquote"), result);
else if (quoteType == ',')
try ret = Memory::create_list(Memory::get_or_create_lisp_object_symbol("unquote"), result);
else if (quoteType == '@') {
try ret = Memory::create_list(Memory::get_or_create_lisp_object_symbol("unquote-splicing"), result);
}
// if (ret && ret != Memory::nil && ret != Memory::t)
// inject_scl(ret);
return ret;
try ret = parse_number(text, index_in_text);
}
else if (text[*index_in_text] == '"')
try ret = parse_string(text, index_in_text);
else
try ret = parse_symbol_or_keyword(text, index_in_text);
// if it is not quoted
++(*index_in_text);
++parser_col;
return ret;
}
eat_whitespace(text, index_in_text);
// if there was actually nothing in the list, we define here,
// that that means nil
if (text[(*index_in_text)] == ')') {
++(*index_in_text);
++parser_col;
proc parse_list(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
if (text[*index_in_text] != '(') {
create_parsing_error("a list cannot be parsed here");
return nullptr;
}
step_char_and_eat_until_code(text, index_in_text);
if (text[*index_in_text] == ')') {
step_char(text, index_in_text);
return Memory::nil;
}
// okay there is something
Lisp_Object* first_elem;
Lisp_Object* ret;
Lisp_Object* head;
try head = Memory::create_lisp_object();
Memory::set_type(head, Lisp_Object_Type::Pair);
// head->value.pair = new(Pair);
Lisp_Object* expression = head;
while (true) {
// inject_scl(head);
if (text[*index_in_text] == '(' ||
text[*index_in_text] == '\''||
text[*index_in_text] == '`' ||
text[*index_in_text] == '@' ||
text[*index_in_text] == ',')
try first_elem = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil);
head = ret;
eat_until_code(text, index_in_text);
while (text[*index_in_text] != ')') {
Lisp_Object* element;
if (text[*index_in_text+0] == '.' &&
text[*index_in_text+1] == ' ')
{
try head->value.pair.first = parse_expression(text, index_in_text);
} else {
try head->value.pair.first = parse_atom(text, index_in_text);
step_char(text, index_in_text, 2);
try element = parse_expression(text, index_in_text);
head->value.pair.rest = element;
eat_until_code(text, index_in_text);
if (text[*index_in_text] != ')') {
create_parsing_error("expected the list to end after the dotted end.");
return nullptr;
}
step_char(text, index_in_text);
return ret;
}
try element = parse_expression(text, index_in_text);
try head->value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil);
head = head->value.pair.rest;
eat_until_code(text, index_in_text);
if (text[(*index_in_text)] == '\0') {
create_parsing_error(
"Unexpected EOF in %s:%d:%d",
parser_file, parser_line, parser_col);
return nullptr;
}
if (text[(*index_in_text)] == ')') {
head->value.pair.rest = Memory::nil;
++parser_col;
++(*index_in_text);
break;
} else if (text[(*index_in_text) ] == '.' &&
text[(*index_in_text)+1] == ' ')
{
++parser_col;
++(*index_in_text);
eat_until_code(text, index_in_text);
if (text[(*index_in_text)] == '(')
head->value.pair.rest = parse_expression(text, index_in_text);
else
head->value.pair.rest = parse_atom(text, index_in_text);
eat_until_code(text, index_in_text);
if (text[(*index_in_text)] != ')')
create_parsing_error(
"Expected ')' after the element after the '.' in %s:%d:%d",
create_source_code_location(parser_file, parser_line, parser_col));
++parser_col;
++(*index_in_text);
break;
} else {
try head->value.pair.rest = Memory::create_lisp_object_pair(Memory::nil, Memory::nil);
head = head->value.pair.rest;
// inject_scl(head);
}
}
return expression;
step_char(text, index_in_text);
return ret;
}
proc maybe_expand_short_form(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
Lisp_Object* vector_sym = Memory::get_symbol("vector");
Lisp_Object* hash_map_sym = Memory::get_symbol("hash-map");
Lisp_Object* quote_sym = Memory::get_symbol("quote");
Lisp_Object* quasiquote_sym = Memory::get_symbol("quasiquote");
Lisp_Object* unquote_sym = Memory::get_symbol("unquote");
Lisp_Object* unquote_splicing_sym = Memory::get_symbol("unquote-splicing");
Lisp_Object* ret = nullptr;
Lisp_Object* expr;
switch (text[*index_in_text]) {
case '\'': {
// quote
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(quote_sym, ret);
} break;
case '`': {
// quasiquote
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(quasiquote_sym, ret);
} break;
case ',': {
step_char_and_eat_until_code(text, index_in_text);
if (text[*index_in_text] == '@') {
// unquote-splicing
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(unquote_splicing_sym, ret);
} else {
// unquote
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(unquote_sym, ret);
}
} break;
case '[': {
// vector
try ret = parse_fancy_delimiter(text, index_in_text, '[', ']', vector_sym);
} break;
case '{': {
// hashmap
try ret = parse_fancy_delimiter(text, index_in_text, '{', '}', hash_map_sym);
} break;
default: break;
}
return ret;
}
proc parse_expression(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
Lisp_Object* ret;
eat_until_code(text, index_in_text);
try ret = maybe_expand_short_form(text, index_in_text);
if (ret)
return ret;
if (text[*index_in_text] == '(') {
try ret = parse_list(text, index_in_text);
} else {
try ret = parse_atom(text, index_in_text);
}
return ret;
}
proc parse_single_expression(wchar_t* text) -> Lisp_Object* {
@@ -376,107 +362,21 @@ namespace Parser {
defer {free(res);};
return parse_single_expression(res);
}
proc parse_single_expression(char* text) -> Lisp_Object* {
parser_file = standard_in;
parser_line = 1;
parser_col = 1;
int index_in_text = 0;
Lisp_Object* result;
eat_until_code(text, &index_in_text);
if (text[(index_in_text)] == '\0')
return Memory::nil;
if (text[index_in_text] == '(' ||
text[index_in_text] == '\'' ||
text[index_in_text] == '@' ||
text[index_in_text] == '`' ||
text[index_in_text] == ',')
{
try {
result = parse_expression(text, &index_in_text);
}
}
else
try {
result = parse_atom(text, &index_in_text);
}
eat_until_code(text, &index_in_text);
if (text[(index_in_text)] == '\0')
return result;
create_parsing_error("Trainling garbage after expression at %s:%d:%d",
parser_file, parser_line, parser_col);
return nullptr;
Lisp_Object* ret;
try ret = parse_expression(text, &index_in_text);
return ret;
}
proc parse_single_expression_or_bare_words(char* text, char* bare) -> Lisp_Object* {
parser_file = standard_in;
parser_line = 1;
parser_col = 1;
int index_in_text = 0;
Lisp_Object* result;
eat_until_code(text, &index_in_text);
if (text[(index_in_text)] == '\0')
return Memory::nil;
if (text[index_in_text] == '(' ||
text[index_in_text] == '\'' ||
text[index_in_text] == '@' ||
text[index_in_text] == '`' ||
text[index_in_text] == ',')
{
try {
result = parse_expression(text, &index_in_text);
}
return result;
}
else {
// TODO(Felix): What is going on, why do we not have to
// increase the index_in_text
int end_pos = index_in_text;
while (text[end_pos] != '\n')
++end_pos;
text[end_pos] = '\0';
Lisp_Object* str;
try str = Memory::create_lisp_object_string(
Memory::create_string(text+index_in_text));
text[end_pos] = '\n';
return Memory::create_list(Memory::get_or_create_lisp_object_symbol(bare), str);
}
}
proc write_expanded_file(String* file_name, Array_List<Lisp_Object*>* program) -> void {
const char* ext = ".expanded";
char* newName = (char*)calloc(10 + file_name->length, sizeof(char));
strcpy(newName, Memory::get_c_str(file_name));
strcat(newName, ext);
FILE *f = fopen(newName, "w");
defer {
fclose(f);
free(newName);
};
if (f == NULL) {
printf("Error opening .expanded file for writing!\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] == Memory::nil)
continue;
print(program->data[i], true, f);
fprintf(f, "\n\n");
}
}
proc parse_program(String* file_name, char* text) -> Array_List<Lisp_Object*>* {
profile_this();
parser_file = file_name;
parser_line = 1;
parser_col = 0;
@@ -484,33 +384,15 @@ namespace Parser {
Array_List<Lisp_Object*>* program = new Array_List<Lisp_Object*>;
int index_in_text = 0;
Lisp_Object* parsed;
eat_until_code(text, &index_in_text);
while (text[index_in_text] != '\0') {
switch (text[index_in_text]) {
case '(': {
Lisp_Object* parsed;
try_struct {
parsed = parse_expression(text, &index_in_text);
}
program->append(parsed);
} break;
case ';':
case ' ':
case '\t':
case '\n':
case '\r': {
eat_until_code(text, &index_in_text);
} break;
default:
/* syntax error */
create_parsing_error("Garbage in file scope at %s:%d:%d",
parser_file, parser_line, parser_col);
return {};
}
try parsed = parse_expression(text, &index_in_text);
program->append(parsed);
eat_until_code(text, &index_in_text);
}
write_expanded_file(file_name, program);
return program;
}
}
-396
View File
@@ -1,396 +0,0 @@
namespace Parser {
String* standard_in;
String* parser_file;
int parser_line;
int parser_col;
proc eat_comment_line(char* text, int* index_in_text) -> void {
// safety check if we are actually starting a comment here
if (text[*index_in_text] != ';')
return;
// eat the comment line
do {
++(*index_in_text);
++parser_col;
} while (text[(*index_in_text)] != '\n' &&
text[(*index_in_text)] != '\r' &&
text[(*index_in_text)] != '\0');
}
proc step_char(char* text, int* index_in_text, int steps = 1) {
for (int i = 0; i < steps; ++i) {
if (text[(*index_in_text)] == '\n') {
++parser_line;
parser_col = 0;
}
++parser_col;
++(*index_in_text);
}
}
proc eat_whitespace(char* text, int* index_in_text) -> void {
// skip whitespaces
while (text[(*index_in_text)] == ' ' ||
text[(*index_in_text)] == '\t' ||
text[(*index_in_text)] == '\n' ||
text[(*index_in_text)] == '\r')
{
step_char(text, index_in_text);
}
}
proc eat_until_code(char* text, int* index_in_text) -> void {
int position_before;
do {
position_before = *index_in_text;
eat_comment_line(text, index_in_text);
eat_whitespace(text, index_in_text);
} while (position_before != *index_in_text);
}
proc step_char_and_eat_until_code(char* text, int* index_in_text) {
step_char(text, index_in_text);
eat_until_code(text, index_in_text);
}
proc parse_fancy_delimiter(char* text, int* index_in_text, char l_delimiter, char r_delimiter, Lisp_Object* first_elem) -> Lisp_Object* {
if (text[*index_in_text] != l_delimiter) {
create_parsing_error("a fancy cannot be parsed here");
return nullptr;
}
Lisp_Object* ret;
Lisp_Object* head;
try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil);
head = ret;
step_char(text, index_in_text);
eat_until_code(text, index_in_text);
while (text[*index_in_text] != r_delimiter) {
Lisp_Object* element;
try element = parse_expression(text, index_in_text);
try head->value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil);
head = head->value.pair.rest;
eat_until_code(text, index_in_text);
}
step_char(text, index_in_text);
return ret;
}
proc get_atom_text_length(char* text, int* index_in_text) -> int {
int atom_length = 0;
while (text[*index_in_text+atom_length] != ' ' &&
text[*index_in_text+atom_length] != ')' &&
text[*index_in_text+atom_length] != '(' &&
text[*index_in_text+atom_length] != '[' &&
text[*index_in_text+atom_length] != ']' &&
text[*index_in_text+atom_length] != '{' &&
text[*index_in_text+atom_length] != '}' &&
text[*index_in_text+atom_length] != '\0' &&
text[*index_in_text+atom_length] != '\n' &&
text[*index_in_text+atom_length] != '\r' &&
text[*index_in_text+atom_length] != '\t')
{
++atom_length;
}
return atom_length;
}
proc parse_number(char* text, int* index_in_text) -> Lisp_Object* {
Lisp_Object* ret;
try ret = Memory::create_lisp_object_number(0);
sscanf(text+*index_in_text, "%lf", &ret->value.number);
int atom_length = get_atom_text_length(text, index_in_text);
step_char(text, index_in_text, atom_length);
return ret;
}
proc parse_symbol_or_keyword(char* text, int* index_in_text) -> Lisp_Object* {
bool keyword = false;
if (text[*index_in_text] == ':') {
keyword = true;
step_char(text, index_in_text);
}
int atom_length = get_atom_text_length(text, index_in_text);
char orig = text[*index_in_text+atom_length];
text[*index_in_text+atom_length] = '\0';
String* str_keyword;
Lisp_Object* ret;
try str_keyword = Memory::create_string("", atom_length);
strcpy(&str_keyword->data, text+*index_in_text);
if (keyword) {
try ret = Memory::get_or_create_lisp_object_keyword(str_keyword);
} else {
try ret = Memory::get_or_create_lisp_object_symbol(str_keyword);
}
text[*index_in_text+atom_length] = orig;
step_char(text, index_in_text, atom_length);
return ret;
}
proc parse_string(char* text, int* index_in_text) -> Lisp_Object* {
// the first character is the '"'
step_char(text, index_in_text);
// now we are at the first letter, if this is the closing '"' then
// it's easy
if (text[*index_in_text] == '"') {
Lisp_Object* ret;
try ret = Memory::create_lisp_object_string(
Memory::create_string("", 0));
// inject_scl(ret);
// plus one because we want to go after the quotes
step_char(text, index_in_text);
return ret;
}
// okay so the first letter was not actually closing the string...
int string_length = 0;
bool escaping = false;
while (escaping || text[*index_in_text+string_length] != '"') {
if (escaping) {
escaping = false;
}
else
if (text[*index_in_text+string_length] == '\\')
escaping = true;
++string_length;
}
// we found the end of the string
text[*index_in_text+string_length] = '\0';
// NOTE(Felix): Tactic: Through unescaping the string will
// only get shorter, so we replace it inplace and later jump
// to the original end of the string.
int new_len;
try new_len = unescape_string(text+(*index_in_text));
String* string = Memory::create_string("", new_len);
strcpy(&string->data, text+(*index_in_text));
// printf("------ %s\n", &string->data);
text[*index_in_text+string_length] = '"';
// plus one because we want to go after the quotes
step_char(text, index_in_text, string_length+1);
Lisp_Object* ret;
try ret = Memory::create_lisp_object_string(string);
// inject_scl(ret);
return ret;
}
proc parse_atom(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
Lisp_Object* ret;
// numbers
if ((text[*index_in_text] <= 57 && // if number
text[*index_in_text] >= 48)
||
((text[*index_in_text] == '+' || // or if sign and then number
text[*index_in_text] == '-')
&&
(text[*index_in_text +1] <= 57 &&
text[*index_in_text +1] >= 48))
||
((text[*index_in_text] == '.') // or if . and then number
&&
(text[*index_in_text +1] <= 57 &&
text[*index_in_text +1] >= 48)))
{
try ret = parse_number(text, index_in_text);
}
else if (text[*index_in_text] == '"')
try ret = parse_string(text, index_in_text);
else
try ret = parse_symbol_or_keyword(text, index_in_text);
return ret;
}
proc parse_list(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
if (text[*index_in_text] != '(') {
create_parsing_error("a list cannot be parsed here");
return nullptr;
}
step_char_and_eat_until_code(text, index_in_text);
if (text[*index_in_text] == ')') {
step_char(text, index_in_text);
return Memory::nil;
}
Lisp_Object* first_elem;
Lisp_Object* ret;
Lisp_Object* head;
try first_elem = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(first_elem, Memory::nil);
head = ret;
eat_until_code(text, index_in_text);
while (text[*index_in_text] != ')') {
Lisp_Object* element;
if (text[*index_in_text+0] == '.' &&
text[*index_in_text+1] == ' ')
{
step_char(text, index_in_text, 2);
try element = parse_expression(text, index_in_text);
head->value.pair.rest = element;
eat_until_code(text, index_in_text);
if (text[*index_in_text] != ')') {
create_parsing_error("expected the list to end after the dotted end.");
return nullptr;
}
step_char(text, index_in_text);
return ret;
}
try element = parse_expression(text, index_in_text);
try head->value.pair.rest = Memory::create_lisp_object_pair(element, Memory::nil);
head = head->value.pair.rest;
eat_until_code(text, index_in_text);
}
step_char(text, index_in_text);
return ret;
}
proc maybe_expand_short_form(char* text, int* index_in_text) -> Lisp_Object* {
Lisp_Object* vector_sym = Memory::get_or_create_lisp_object_symbol("vector");
Lisp_Object* hash_map_sym = Memory::get_or_create_lisp_object_symbol("hash-map");
Lisp_Object* quote_sym = Memory::get_or_create_lisp_object_symbol("quote");
Lisp_Object* quasiquote_sym = Memory::get_or_create_lisp_object_symbol("quasiquote");
Lisp_Object* unquote_sym = Memory::get_or_create_lisp_object_symbol("unquote");
Lisp_Object* unquote_splicing_sym = Memory::get_or_create_lisp_object_symbol("unquote-splicing");
Lisp_Object* ret = nullptr;
Lisp_Object* expr;
switch (text[*index_in_text]) {
case '\'': {
// quote
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(quote_sym, ret);
} break;
case '`': {
// quasiquote
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(quasiquote_sym, ret);
} break;
case ',': {
step_char_and_eat_until_code(text, index_in_text);
if (text[*index_in_text] == '@') {
// unquote-splicing
step_char_and_eat_until_code(text, index_in_text);
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(unquote_splicing_sym, ret);
} else {
// unquote
try expr = parse_expression(text, index_in_text);
try ret = Memory::create_lisp_object_pair(expr, Memory::nil);
try ret = Memory::create_lisp_object_pair(unquote_sym, ret);
}
} break;
case '[': {
// vector
try ret = parse_fancy_delimiter(text, index_in_text, '[', ']', vector_sym);
} break;
case '{': {
// hashmap
try ret = parse_fancy_delimiter(text, index_in_text, '{', '}', hash_map_sym);
} break;
default: break;
}
return ret;
}
proc parse_expression(char* text, int* index_in_text) -> Lisp_Object* {
profile_this();
Lisp_Object* ret;
eat_until_code(text, index_in_text);
try ret = maybe_expand_short_form(text, index_in_text);
if (ret)
return ret;
if (text[*index_in_text] == '(') {
try ret = parse_list(text, index_in_text);
} else {
try ret = parse_atom(text, index_in_text);
}
return ret;
}
proc parse_single_expression(wchar_t* text) -> Lisp_Object* {
char* res = wchar_to_char(text);
defer {free(res);};
return parse_single_expression(res);
}
proc parse_single_expression(char* text) -> Lisp_Object* {
parser_file = standard_in;
parser_line = 1;
parser_col = 1;
int index_in_text = 0;
Lisp_Object* ret;
try ret = parse_expression(text, &index_in_text);
return ret;
}
proc parse_program(String* file_name, char* text) -> Array_List<Lisp_Object*>* {
profile_this();
parser_file = file_name;
parser_line = 1;
parser_col = 0;
Array_List<Lisp_Object*>* program = new Array_List<Lisp_Object*>;
int index_in_text = 0;
Lisp_Object* parsed;
eat_until_code(text, &index_in_text);
while (text[index_in_text] != '\0') {
try parsed = parse_expression(text, &index_in_text);
program->append(parsed);
eat_until_code(text, &index_in_text);
}
return program;
}
}
+11 -17
View File
@@ -570,10 +570,10 @@ proc test_singular_t_and_nil() -> testresult {
}
proc test_singular_symbols() -> testresult {
auto cc_s_aa = Memory::get_or_create_lisp_object_symbol("aa");
auto cc_s_aa2 = Memory::get_or_create_lisp_object_symbol("aa2");
auto s_s_aa = Memory::get_or_create_lisp_object_symbol(Memory::create_string("aa"));
auto s_s_aa2 = Memory::get_or_create_lisp_object_symbol(Memory::create_string("aa2"));
auto cc_s_aa = Memory::get_symbol("aa");
auto cc_s_aa2 = Memory::get_symbol("aa2");
auto s_s_aa = Memory::get_symbol(Memory::create_string("aa"));
auto s_s_aa2 = Memory::get_symbol(Memory::create_string("aa2"));
assert_equal_int(cc_s_aa, s_s_aa);
assert_equal_int(cc_s_aa2, s_s_aa2);
@@ -583,26 +583,20 @@ proc test_singular_symbols() -> testresult {
}
proc test_file(const char* file) -> testresult {
profile_with_name(file);
// Memory::reset();
// assert_no_error();
Memory::reset();
assert_no_error();
Environment* root_env = get_root_environment();
Environment* user_env = Memory::create_child_environment(root_env);
assert_no_error();
push_environment(user_env);
defer {
pop_environment();
};
try built_in_load(Memory::create_string(file));
push_environment(Memory::create_child_environment(get_current_environment()));
built_in_load(Memory::create_string(file));
assert_no_error();
pop_environment();
return pass;
}
proc run_all_tests() -> bool {
profile_this();
bool result = true;