
proc define_symbol(Lisp_Object* symbol, Lisp_Object* value, Environment* env) -> void {
    // 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 = (Lisp_Object**)realloc(env->values, env->capacity * sizeof(Lisp_Object*));
    }

    env->keys  [env->next_index] = Memory::get_c_str(symbol->value.symbol->identifier);
    env->values[env->next_index] = value;
    ++env->next_index;
}

proc lookup_symbol_in_this_envt(Symbol* sym, Environment* env) -> Lisp_Object* {
    for (int i = env->next_index - 1; i >= 0; --i)
        if (string_equal(env->keys[i], Memory::get_c_str(sym->identifier)))
            return env->values[i];
    return nullptr;
}

proc lookup_symbol(Lisp_Object* node, Environment* env) -> Lisp_Object* {
    // first check current environment
    Symbol* sym = node->value.symbol;
    Lisp_Object* result;
    result = lookup_symbol_in_this_envt(sym, env);
    if (result)
        return result;

    if (env->parent) {
        result = lookup_symbol(node, env->parent);

        if (result)
            return result;
    }

    if (string_equal(Memory::get_c_str(sym->identifier), "nil")) {
        return Memory::nil;
    }
    if (string_equal(Memory::get_c_str(sym->identifier), "t")) {
        return Memory::t;
    }

    create_error(Error_Type::Symbol_Not_Defined, node->sourceCodeLocation);
    printf("%s\n", Memory::get_c_str(sym->identifier));
    return nullptr;
}

proc print_indent(int indent) -> void {
    for (int i = 0; i < indent; ++i) {
        printf(" ");
    }
}

proc print_environment_indent(Environment* env, int indent) -> void {
    for (int i = 0; i < env->next_index; ++i) {
        print_indent(indent);
        print(env->values[i]);
        printf(" %s", env->keys[i]);
        printf("\n");
    }
    if (env->parent) {
        print_indent(indent);
        printf("parent");
        printf(":\n");
        print_environment_indent(env->parent, indent+4);
    }
}

proc print_environment(Environment* env) -> void {
    printf("\n=== Environment ===\n");
    print_environment_indent(env, 0);
}
