now use global symbol tables so symbols and keywords are finally unique
This commit is contained in:
@@ -32,4 +32,5 @@
|
|||||||
(c++-mode . ((eval . (company-clang-set-prefix "slime.h"))
|
(c++-mode . ((eval . (company-clang-set-prefix "slime.h"))
|
||||||
(eval . (flycheck-mode 0))
|
(eval . (flycheck-mode 0))
|
||||||
(eval . (rainbow-mode 0))
|
(eval . (rainbow-mode 0))
|
||||||
|
(eval . (setq c-backslash-max-column 99))
|
||||||
)))
|
)))
|
||||||
|
|||||||
+1
-1
@@ -107,7 +107,7 @@ proc load_built_ins_into_environment() -> void {
|
|||||||
|
|
||||||
|
|
||||||
#define fetch1(var) \
|
#define fetch1(var) \
|
||||||
Lisp_Object* var##_symbol = Memory::get_or_create_lisp_object_symbol(#var); \
|
static Lisp_Object* var##_symbol = Memory::get_or_create_lisp_object_symbol(#var); \
|
||||||
Lisp_Object* var = lookup_symbol(var##_symbol, get_current_environment()); \
|
Lisp_Object* var = lookup_symbol(var##_symbol, get_current_environment()); \
|
||||||
if (Globals::error) printf("in %s:%d\n", __FILE__, __LINE__)
|
if (Globals::error) printf("in %s:%d\n", __FILE__, __LINE__)
|
||||||
|
|
||||||
|
|||||||
+7
-11
@@ -36,6 +36,7 @@
|
|||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
else label(body,__LINE__):
|
else label(body,__LINE__):
|
||||||
|
;
|
||||||
|
|
||||||
#define try_struct try_or_else_return({})
|
#define try_struct try_or_else_return({})
|
||||||
#define try_void try_or_else_return()
|
#define try_void try_or_else_return()
|
||||||
@@ -44,8 +45,8 @@
|
|||||||
#define dont_break_on_errors fluid_let(Globals::breaking_on_errors, false)
|
#define dont_break_on_errors fluid_let(Globals::breaking_on_errors, false)
|
||||||
#define ignore_logging fluid_let(Globals::log_level, Log_Level::None)
|
#define ignore_logging fluid_let(Globals::log_level, Log_Level::None)
|
||||||
|
|
||||||
|
|
||||||
#define define_array_list(type, name) \
|
#define define_array_list(type, name) \
|
||||||
|
\
|
||||||
struct name##_Array_List { \
|
struct name##_Array_List { \
|
||||||
type* data; \
|
type* data; \
|
||||||
int length; \
|
int length; \
|
||||||
@@ -147,8 +148,7 @@
|
|||||||
* iterate over array lists
|
* iterate over array lists
|
||||||
*/
|
*/
|
||||||
#define for_array_list(l) \
|
#define for_array_list(l) \
|
||||||
if (int it_index = 0); \
|
if (int it_index = 0); else \
|
||||||
else \
|
|
||||||
for (auto it = (l).data[0]; \
|
for (auto it = (l).data[0]; \
|
||||||
it_index < (l).next_index; \
|
it_index < (l).next_index; \
|
||||||
it=(l).data[++it_index])
|
it=(l).data[++it_index])
|
||||||
@@ -157,10 +157,8 @@
|
|||||||
* iterate over lisp vectors
|
* iterate over lisp vectors
|
||||||
*/
|
*/
|
||||||
#define for_lisp_vector(v) \
|
#define for_lisp_vector(v) \
|
||||||
if (!v); \
|
if (!v); else \
|
||||||
else \
|
if (int it_index = 0); else \
|
||||||
if (int it_index = 0); \
|
|
||||||
else \
|
|
||||||
for (auto it = v->value.vector.data; \
|
for (auto it = v->value.vector.data; \
|
||||||
it_index < v->value.vector.length; \
|
it_index < v->value.vector.length; \
|
||||||
it=v->value.vector.data+(++it_index))
|
it=v->value.vector.data+(++it_index))
|
||||||
@@ -169,10 +167,8 @@
|
|||||||
* iterate over lisp lists
|
* iterate over lisp lists
|
||||||
*/
|
*/
|
||||||
#define for_lisp_list(l) \
|
#define for_lisp_list(l) \
|
||||||
if (!l); \
|
if (!l); else \
|
||||||
else \
|
if (int it_index = 0); else \
|
||||||
if (int it_index = 0); \
|
|
||||||
else \
|
|
||||||
for (Lisp_Object* head = l, *it; \
|
for (Lisp_Object* head = l, *it; \
|
||||||
Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \
|
Memory::get_type(head) == Lisp_Object_Type::Pair && (it = head->value.pair.first); \
|
||||||
head = head->value.pair.rest, ++it_index)
|
head = head->value.pair.rest, ++it_index)
|
||||||
|
|||||||
+46
-21
@@ -1,5 +1,11 @@
|
|||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
|
// ------------------
|
||||||
|
// global symbol / keyword table
|
||||||
|
// ------------------
|
||||||
|
String_Hash_Map* global_symbol_table;
|
||||||
|
String_Hash_Map* global_keyword_table;
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
// lisp_objects
|
// lisp_objects
|
||||||
// ------------------
|
// ------------------
|
||||||
@@ -159,7 +165,18 @@ namespace Memory {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc free_everything() {
|
||||||
|
free(global_symbol_table);
|
||||||
|
free(global_keyword_table);
|
||||||
|
free(object_memory);
|
||||||
|
free(environment_memory);
|
||||||
|
free(string_memory);
|
||||||
|
}
|
||||||
|
|
||||||
proc init(int oms, int ems, int sms) {
|
proc init(int oms, int ems, int sms) {
|
||||||
|
global_symbol_table = create_String_hashmap();
|
||||||
|
global_keyword_table = create_String_hashmap();
|
||||||
|
|
||||||
object_memory_size = oms;
|
object_memory_size = oms;
|
||||||
environment_memory_size = ems;
|
environment_memory_size = ems;
|
||||||
string_memory_size = sms;
|
string_memory_size = sms;
|
||||||
@@ -274,44 +291,52 @@ namespace Memory {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* {
|
proc create_new_lisp_object_symbol(String* identifier) -> Lisp_Object* {
|
||||||
// TODO(Felix): if we already have it stored somewhere then
|
|
||||||
// reuse it and dont create new one
|
|
||||||
Lisp_Object* node;
|
Lisp_Object* node;
|
||||||
try node = create_lisp_object();
|
try node = create_lisp_object();
|
||||||
set_type(node, Lisp_Object_Type::Symbol);
|
set_type(node, Lisp_Object_Type::Symbol);
|
||||||
// node->value.symbol = new(Symbol);
|
|
||||||
node->value.symbol.identifier = identifier;
|
node->value.symbol.identifier = identifier;
|
||||||
node->value.symbol.hash = hash(identifier);
|
node->value.symbol.hash = hash(identifier);
|
||||||
|
hm_set(global_symbol_table, get_c_str(identifier), node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
proc get_or_create_lisp_object_symbol(const char* identifier) -> Lisp_Object* {
|
proc create_new_lisp_object_keyword(String* keyword) -> Lisp_Object* {
|
||||||
// TODO(Felix): This is really bad: we create a new string
|
|
||||||
// even if the symbol/keyword is already existing, just to
|
|
||||||
// check IF it exists and then never deleting it.
|
|
||||||
return get_or_create_lisp_object_symbol(
|
|
||||||
Memory::create_string(identifier));
|
|
||||||
}
|
|
||||||
|
|
||||||
proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* {
|
|
||||||
// TODO(Felix): if we already have it stored somewhere then
|
|
||||||
// reuse it and dont create new one
|
|
||||||
Lisp_Object* node;
|
Lisp_Object* node;
|
||||||
try node = create_lisp_object();
|
try node = create_lisp_object();
|
||||||
set_type(node, Lisp_Object_Type::Keyword);
|
set_type(node, Lisp_Object_Type::Keyword);
|
||||||
// node->value.keyword = new(Keyword);
|
|
||||||
node->value.symbol.identifier = keyword;
|
node->value.symbol.identifier = keyword;
|
||||||
node->value.symbol.hash = hash(keyword);
|
node->value.symbol.hash = hash(keyword);
|
||||||
|
hm_set(global_keyword_table, get_c_str(keyword), node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc get_or_create_lisp_object_symbol(String* identifier) -> Lisp_Object* {
|
||||||
|
if (auto ret = hm_get_object(global_symbol_table, 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 = hm_get_object(global_symbol_table, (char*)identifier))
|
||||||
|
return (Lisp_Object*)ret;
|
||||||
|
else
|
||||||
|
return create_new_lisp_object_symbol(Memory::create_string(identifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
proc get_or_create_lisp_object_keyword(String* keyword) -> Lisp_Object* {
|
||||||
|
if (auto ret = hm_get_object(global_keyword_table, 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_or_create_lisp_object_keyword(const char* keyword) -> Lisp_Object* {
|
||||||
// TODO(Felix): This is really bad: we create a new string
|
if (auto ret = hm_get_object(global_keyword_table, (char*)keyword))
|
||||||
// even if the symbol/keyword is already existing, just to
|
return (Lisp_Object*)ret;
|
||||||
// check IF it exists and then never deleting it.
|
else
|
||||||
return get_or_create_lisp_object_keyword(
|
return create_new_lisp_object_keyword(Memory::create_string(keyword));
|
||||||
Memory::create_string(keyword));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proc create_lisp_object_cfunction(bool is_special) -> Lisp_Object* {
|
proc create_lisp_object_cfunction(bool is_special) -> Lisp_Object* {
|
||||||
|
|||||||
+3
-116
@@ -340,7 +340,9 @@ namespace Parser {
|
|||||||
++parser_col;
|
++parser_col;
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
break;
|
break;
|
||||||
} else if (text[(*index_in_text)] == '.') {
|
} else if (text[(*index_in_text) ] == '.' &&
|
||||||
|
text[(*index_in_text)+1] == ' ')
|
||||||
|
{
|
||||||
++parser_col;
|
++parser_col;
|
||||||
++(*index_in_text);
|
++(*index_in_text);
|
||||||
eat_until_code(text, index_in_text);
|
eat_until_code(text, index_in_text);
|
||||||
@@ -364,121 +366,6 @@ namespace Parser {
|
|||||||
head = head->value.pair.rest;
|
head = head->value.pair.rest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// // 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// // 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 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;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 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);
|
|
||||||
|
|
||||||
// // 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.
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-3
@@ -540,9 +540,6 @@ proc test_built_in_type() -> testresult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proc test_singular_t_and_nil() -> testresult {
|
proc test_singular_t_and_nil() -> testresult {
|
||||||
Environment* env;
|
|
||||||
try env = get_root_environment();
|
|
||||||
|
|
||||||
// nil testing
|
// nil testing
|
||||||
char exp_string1[] = "()";
|
char exp_string1[] = "()";
|
||||||
char exp_string2[] = "nil";
|
char exp_string2[] = "nil";
|
||||||
@@ -574,6 +571,19 @@ proc test_singular_t_and_nil() -> testresult {
|
|||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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"));
|
||||||
|
|
||||||
|
assert_equal_int(cc_s_aa, s_s_aa);
|
||||||
|
assert_equal_int(cc_s_aa2, s_s_aa2);
|
||||||
|
assert_not_equal_int(cc_s_aa, cc_s_aa2);
|
||||||
|
|
||||||
|
return pass;
|
||||||
|
}
|
||||||
|
|
||||||
proc test_file(const char* file) -> testresult {
|
proc test_file(const char* file) -> testresult {
|
||||||
// Memory::reset();
|
// Memory::reset();
|
||||||
// assert_no_error();
|
// assert_no_error();
|
||||||
@@ -630,6 +640,7 @@ proc run_all_tests() -> bool {
|
|||||||
|
|
||||||
printf("\n-- Memory management --\n");
|
printf("\n-- Memory management --\n");
|
||||||
invoke_test(test_singular_t_and_nil);
|
invoke_test(test_singular_t_and_nil);
|
||||||
|
invoke_test(test_singular_symbols);
|
||||||
|
|
||||||
printf("\n-- Test Files --\n");
|
printf("\n-- Test Files --\n");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user