cleanup
This commit is contained in:
+4
-4
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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 ""
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user