#pragma once // #include #include "ftb/arraylist.hpp" #include "ftb/hashmap.hpp" namespace Slime { struct Lisp_Object; struct String; struct Environment; enum struct Thread_Type { Main, GarbageCollection }; enum struct Lisp_Object_Type { Nil, T, Symbol, Keyword, Number, String, Pair, Vector, Continuation, Pointer, HashMap, // OwningPointer, Function, CFunction, }; enum class Lisp_Object_Flags { // bits 1 to 5 (including) will be reserved for the type Already_Garbage_Collected = 1 << 5, Under_Construction = 1 << 6, }; enum struct Function_Type { Lambda, Macro }; enum struct Log_Level { None, Critical, Warning, Info, Debug, }; struct Continuation { Array_List call_stack; Array_List envi_stack; }; struct String { int length; char data; }; struct Source_Code_Location { String* file; int line; int column; }; struct Pair { Lisp_Object* first; Lisp_Object* rest; }; struct Vector { int length; Lisp_Object* data; }; struct Positional_Arguments { Array_List symbols; }; struct Keyword_Arguments { // Array of Pointers to Lisp_Object Array_List keywords; // NOTE(Felix): values[i] will be nullptr if no defalut value was // declared for key identifiers[i] Array_List values; }; struct Arguments { Positional_Arguments positional; Keyword_Arguments keyword; // NOTE(Felix): rest_argument will be nullptr if no rest argument // is declared otherwise its a symbol Lisp_Object* rest; }; struct Environment { Array_List parents; Hash_Map hm; ~Environment() { parents.~Array_List(); hm.~Hash_Map(); } }; struct Function { Function_Type type; Arguments args; Lisp_Object* body; // maybe implicit begin Environment* parent_environment; // we are doing closures now!! }; struct cFunction { Lisp_Object* (*body)(); Arguments args; bool is_special_form; }; struct Lisp_Object { Source_Code_Location* sourceCodeLocation; u64 flags; Lisp_Object* userType; // keyword String* docstring; union value { String* symbol; // used for symbols and keywords double number; String* string; Pair pair; Vector vector; Function* function; cFunction* cFunction; void* pointer; Continuation* continuation; Hash_Map* hashMap; ~value() {} } value; ~Lisp_Object(); }; struct Error { Lisp_Object* position; // type has to be a keyword Lisp_Object* type; String* message; }; const wchar_t* char_to_wchar(const char* c); char* read_entire_file(char* filename); void add_to_load_path(const char*); bool lisp_object_equal(Lisp_Object*,Lisp_Object*); Lisp_Object* built_in_load(String*); Lisp_Object* built_in_import(String*); void delete_error(); void create_error(const char* c_func_name, const char* c_file_name, int c_file_line, Lisp_Object* type, const char* format, ...); void create_error(const char* c_func_name, const char* c_file_name, int c_file_line, Lisp_Object* type, String* message); void create_error(Lisp_Object* type, const char* message, const char* c_file_name, int c_file_line); Lisp_Object* eval_arguments(Lisp_Object*); Lisp_Object* eval_expr(Lisp_Object*); bool is_truthy (Lisp_Object*); int list_length(Lisp_Object*); void* load_built_ins_into_environment(); void create_arguments_from_lambda_list_and_inject(Lisp_Object* formal_arguments, Lisp_Object* function); Lisp_Object* lookup_symbol(Lisp_Object* symbol, Environment*); void define_symbol(Lisp_Object* symbol, Lisp_Object* value); void print(Lisp_Object* node, bool print_repr = false, FILE* file = stdout); void print_environment(Environment*); bool run_all_tests(); inline Environment* get_root_environment(); inline Environment* get_current_environment(); inline void push_environment(Environment*); inline void pop_environment(); const char* Lisp_Object_Type_to_string(Lisp_Object_Type type); void visualize_lisp_machine(); void generate_docs(String* path); void log_error(); namespace Memory { Environment* create_built_ins_environment(); Lisp_Object* create_lisp_object_cfunction(bool is_special); 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* 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*); Lisp_Object* create_lisp_object_vector(int, Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*,Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*,Lisp_Object*,Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*); inline Lisp_Object* create_list(Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*,Lisp_Object*); } namespace Parser { // extern Environment* environment_for_macros; extern String* standard_in; extern String* parser_file; extern int parser_line; extern int parser_col; Lisp_Object* parse_single_expression(char* text); Lisp_Object* parse_single_expression(wchar_t* text); } namespace Globals { extern char* bin_path; extern Log_Level log_level; extern Array_List load_path; namespace Current_Execution { extern Array_List call_stack; extern Array_List envi_stack; } extern Error* error; extern bool breaking_on_errors; } }