typedef enum { Environment_Type_Let, Environment_Type_Lambda, Environment_Type_Macro, } Environment_Type; struct Environment { struct Environment* parent; Environment_Type type; int capacity; int next_index; // TODO(Felix): Use a hashmap here. char** keys; Ast_Node** values; }; typedef struct Environment Environment; Environment* create_child_environment(Environment* parent, Environment_Type type) { Environment* env = new(Environment); int start_capacity = 16; env->type = type; env->parent = parent; env->capacity = start_capacity; env->next_index = 0; env->keys = (char**)malloc(start_capacity * sizeof(char*)); env->values = (Ast_Node**)malloc(start_capacity * sizeof(Ast_Node*)); return env; } Environment* create_empty_environment(Environment_Type type) { return create_child_environment(nullptr, type); } void define_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { if (env->type == Environment_Type_Macro) { // NOTE(Felix): we know we have a parent because every // environment has a parent except the top level environment. // However the top level environment is not a let-environment, // so we would not land here define_symbol(symbol, value, env->parent); return; } // NOTE(Felix): right now we are simply adding the symol at the // back of the list without checking if it already exists but are // also searching for thesymbol from the back, so we will find the // latest defined one first, but a bit messy. Later we should use // a hashmap here. @refactor if (env->next_index == env->capacity) { env->capacity *= 2; env->keys = (char**)realloc(env->keys, env->capacity * sizeof(char*)); env->values = (Ast_Node**)realloc(env->values, env->capacity * sizeof(Ast_Node*)); } env->keys [env->next_index] = symbol->value.symbol->identifier; env->values[env->next_index] = value; ++env->next_index; } void define_macro_symbol(Ast_Node* symbol, Ast_Node* value, Environment* env) { if (env->type != Environment_Type_Macro) { create_error(Error_Type_Unknown_Error, symbol); return; } env->type = Environment_Type_Lambda; define_symbol(symbol, value, env); env->type = Environment_Type_Macro; } void print_environment(Environment* env); Ast_Node* lookup_symbol_in_this_envt(Symbol* sym, Environment* env) { for (int i = env->next_index - 1; i >= 0; --i) if (string_equal(env->keys[i], sym->identifier)) return env->values[i]; return nullptr; } Ast_Node* lookup_symbol_from_lambda_env(Symbol* sym, Environment* env) { Ast_Node* result; do { if (env->type != Environment_Type_Lambda) { result = lookup_symbol_in_this_envt(sym, env); if (result) return result; } env = env->parent; } while (env); return nullptr; } Ast_Node* lookup_symbol_from_let_or_macro_env(Symbol* sym, Environment* env) { Ast_Node* result; do { result = lookup_symbol_in_this_envt(sym, env); if (result) return result; if (env->type == Environment_Type_Lambda) break; env = env->parent; } while (env); if (env) { do { if (env->type != Environment_Type_Lambda) { result = lookup_symbol_in_this_envt(sym, env); if (result) return result; } env = env->parent; } while (env); } return nullptr; } Ast_Node* lookup_symbol(Symbol* sym, Environment* env) { // first check current environment Ast_Node* result; result = lookup_symbol_in_this_envt(sym, env); if (result) return result; if (env->parent) { if (env->type == Environment_Type_Lambda) { result = lookup_symbol_from_lambda_env(sym, env->parent); } else { result = lookup_symbol_from_let_or_macro_env(sym, env->parent); } if (result) return result; } if (string_equal(sym->identifier, "nil")) { return create_ast_node_nil(); } if (string_equal(sym->identifier, "t")) { return create_ast_node_t(); } result = create_ast_node_built_in_function(sym->identifier); if (result) return result; create_error(Error_Type_Symbol_Not_Defined, create_ast_node_nil()); /* printf("%s\n", sym->identifier); */ return nullptr; } void print_indent(int indent) { for (int i = 0; i < indent; ++i) { printf(" "); } } void print_environment_indent(Environment* env, int indent) { for (int i = 0; i < env->next_index; ++i) { print_indent(indent); printf("%s -> ", env->keys[i]); print(env->values[i]); printf("\n"); } if (env->parent) { print_indent(indent); printf("parent"); if (env->parent->type == Environment_Type_Lambda) printf(" (lambda)"); else if (env->parent->type == Environment_Type_Macro) printf(" (macro)"); else if (env->parent->type == Environment_Type_Let) printf(" (let)"); printf(":\n"); print_environment_indent(env->parent, indent+4); } } void print_environment(Environment* env) { printf("\n=== Environment ===\n"); print_environment_indent(env, 0); }