From ee2a34a3b1eb8e1a5e07a6717b3653d62acb08d6 Mon Sep 17 00:00:00 2001 From: Arthur Barraux Date: Thu, 18 Sep 2025 13:52:46 +0200 Subject: [PATCH] test functions --- include/config.h | 24 ++ include/config_tools.h | 28 -- include/data.h | 246 ++++++++-------- include/define.h | 9 - include/function.h | 33 ++- include/init.h | 13 + include/lexer.h | 8 +- include/node.h | 20 -- include/parser.h | 6 +- include/utils.h | 14 + init.bl | 17 -- main.c | 34 --- src/config.c | 218 ++++++++++++++ src/config_tools.c | 333 --------------------- src/data.c | 154 +++++----- src/function.c | 651 ++++++++++++++++++++++++++++++----------- src/init.c | 85 ++++++ src/lexer.c | 226 +++++--------- src/node.c | 223 -------------- src/parser.c | 262 ++--------------- src/utils.c | 82 ++++++ 21 files changed, 1252 insertions(+), 1434 deletions(-) create mode 100644 include/config.h delete mode 100644 include/config_tools.h delete mode 100644 include/define.h create mode 100644 include/init.h delete mode 100644 include/node.h create mode 100644 include/utils.h delete mode 100644 init.bl delete mode 100644 main.c create mode 100644 src/config.c delete mode 100644 src/config_tools.c create mode 100644 src/init.c delete mode 100644 src/node.c create mode 100644 src/utils.c diff --git a/include/config.h b/include/config.h new file mode 100644 index 0000000..930c57b --- /dev/null +++ b/include/config.h @@ -0,0 +1,24 @@ +#ifndef BLISP_CONFIG_H_ +#define BLISP_CONFIG_H_ + +#include "data.h" + +ConfigValue *get_config_var(const char *name); + +int get_config_int(const char *name, int default_val); +double get_config_float(const char *name, double default_val); +char *get_config_string(const char *name, const char *default_val); +bool get_config_bool(const char *name, bool default_val); +char **get_config_list(const char *name, int *count); + +void free_config_value(ConfigValue *val); + +bool config_var_exists(const char *name); + +void set_config_int(const char *name, int value); +void set_config_float(const char *name, double value); +void set_config_string(const char *name, const char *value); +void set_config_bool(const char *name, bool value); + +void print_all_config_vars(void); +#endif diff --git a/include/config_tools.h b/include/config_tools.h deleted file mode 100644 index be22c8a..0000000 --- a/include/config_tools.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef CONFIG_TOOLS_H_ -#define CONFIG_TOOLS_H_ - -#include "data.h" -#include "parser.h" -#include - -void config_create(void); -void init_builtin_functions(void); - -int handle_map_key(node_t **args, int arg_count); -int handle_define(node_t **args, int arg_count); -int handle_function(node_t **args, int arg_count); - -int execute_function_call(node_t *call); -int config_parse_string(const char *input); -int config_parse_file(const char *filename); - -const char *config_get_key_mapping(const char *key_combo); -node_t *find_variable(const char *name); - -const char *config_get_string(const char *path, const char *default_value); -int config_get_int(const char *path, int default_value); -double config_get_double(const char *path, double default_value); -bool config_get_bool(const char *path, bool default_value); -void config_print_all(void); - -#endif diff --git a/include/data.h b/include/data.h index 8c8270e..ec4bf2b 100644 --- a/include/data.h +++ b/include/data.h @@ -1,151 +1,145 @@ #ifndef DATA_H_PARSER #define DATA_H_PARSER +#include #include +#include +#include +#include -// Token types for lexical analysis +// Forward declarations +typedef struct Value Value; +typedef struct Env Env; + +// Value types +typedef enum { + VAL_NIL, + VAL_NUMBER, + VAL_STRING, + VAL_SYMBOL, + VAL_LIST, + VAL_FUNCTION, + VAL_KEYMAP +} ValueType; typedef enum { - TOKEN_COMMA, // , - TOKEN_PERCENT, // % - TOKEN_LPAREN, // ( - TOKEN_RPAREN, // ) - TOKEN_SYMBOL, // identifiers/function names - TOKEN_STRING, // "quoted strings" - TOKEN_NUMBER, // integers and floats - TOKEN_BOOLEAN, // true false - TOKEN_NEWLINE, // \n (statement separator) - TOKEN_EOF, - TOKEN_ERROR -} token_type_t; + CONFIG_INT, + CONFIG_FLOAT, + CONFIG_STRING, + CONFIG_BOOL, + CONFIG_LIST, + CONFIG_UNKNOWN +} ConfigType; typedef struct { - token_type_t type; - char *value; - int line; - int column; -} token_t; - -// AST node types -typedef enum { - NODE_SYMBOL, - NODE_STRING, - NODE_NUMBER, - NODE_BOOLEAN, - NODE_FUNCTION_REF, // %function-name - NODE_FUNCTION_CALL, // ,function-name() - NODE_LIST -} node_type_t; - -typedef struct node { - node_type_t type; + ConfigType type; union { - char *symbol; - char *string; - double number; - bool boolean; - char *function_ref; + int int_val; + double float_val; + char *string_val; + bool bool_val; struct { - char *function_name; - struct node **args; - int arg_count; - } call; - struct { - struct node **children; - int child_count; - } list; - } data; -} node_t; + char **items; + int count; + } list_val; + } value; +} ConfigValue; + +/** + * @typedef Functions + * + */ + +typedef Value *(*Function)(char **params, int param_count, Value *body, + Env *closure); + +// Value structure +struct Value { + ValueType type; + union { + double number; + char *string; + char *symbol; + struct { + Value *car; + Value *cdr; + } list; + Function *function; + struct { + char **keys; + Value **values; + int count; + int capacity; + } keymap; + } data; +}; + +// Environment for variable bindings +struct Env { + char **names; + Value **values; + int count; + int capacity; + Env *parent; +}; + +typedef enum { + TOK_LPAREN, + TOK_RPAREN, + TOK_QUOTE, + TOK_SYMBOL, + TOK_NUMBER, + TOK_STRING, + TOK_EOF +} TokenType; + +typedef struct { + TokenType type; + char *value; +} Token; -// Lexer state typedef struct { const char *input; int pos; - int line; - int column; - char current_char; -} lexer_t; + int length; +} Lexer; -// Configuration storage -typedef struct key_mapping { - char *key_combo; - char *function_name; - struct key_mapping *next; -} key_mapping_t; +/** + * @struct KeyBinding + * @brief Make the link between a Key Sequence and a command to execute + */ -typedef struct config_var { - char *name; - node_t *value; - struct config_var *next; -} config_var_t; +typedef struct { + char *key_sequence; + char *command; +} KeyBinding; +//@} +typedef struct { + KeyBinding *bindings; + int count; + int capacity; +} KeyBindingTable; -typedef struct config { - key_mapping_t *key_mappings; - config_var_t *variables; -} config_t; +Value *make_value(ValueType type); +Value *make_nil(void); +Value *make_number(double n); +Value *make_string(const char *s); +Value *make_symbol(const char *s); +Value *make_list(Value *car, Value *cdr); +Value *make_builtin(BuiltinFunc func); +Env *make_env(Env *parent); +void env_set(Env *env, const char *name, Value *value); +Value *env_get(Env *env, const char *name); -// Execution context for function calls -typedef struct exec_context { - struct { - char **names; - node_t **values; - int count; - } local_vars; -} exec_context_t; +#ifdef GLOBAL_ENV_ -typedef void (*command_func_t)(void); +Env *global_env = NULL; +KeyBindingTable *active_keybindings = NULL; -typedef enum { FUNC_BUILTIN, FUNC_USER_DEFINED, FUNC_REGISTRY } function_type_t; - -typedef struct unified_function { - char *name; - function_type_t type; - union { - // For built-in functions - struct { - int (*handler)(node_t **args, int arg_count); - bool eval_args; // Whether to evaluate arguments before calling - } builtin; - - // For user-defined functions - struct { - char **parameters; - int param_count; - node_t *body; - } user_defined; - - // For registry functions - struct { - command_func_t func; - } registry; - } data; - - struct unified_function *next; -} unified_function_t; - -void advance_char(lexer_t *lexer); -void skip_whitespace(lexer_t *lexer); -void skip_comment(lexer_t *lexer); - -void add_arg_to_call(node_t *call, node_t *args); -void add_to_list(node_t *node, node_t *element); - -#endif - -#ifdef GLOBAL_CONFIG - -unified_function_t *unified_functions = NULL; -int registry_count; -config_var_t variable_registry[256]; -int var_registry_count; - -config_t config; #else -extern unified_function_t *unified_functions; -extern int registry_count; -extern config_var_t variable_registry[256]; -extern int var_registry_count; +extern Env *global_env; +extern KeyBindingTable *active_keybindings; -extern config_t config; +#endif #endif diff --git a/include/define.h b/include/define.h deleted file mode 100644 index 1aa64fa..0000000 --- a/include/define.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef BLISP_DEFINE_H_ -#define BLISP_DEFINE_H_ - -#define MAX_TOKEN_LENGTH 256 -#define MAX_SYMBOL_LENGTH 128 -#define MAX_STRING_LENGTH 512 -#define MAX_ARGS 16 - -#endif diff --git a/include/function.h b/include/function.h index 739f2f1..3195832 100644 --- a/include/function.h +++ b/include/function.h @@ -3,22 +3,31 @@ #include "data.h" -int register_builtin_function(const char *name, int (*handler)(node_t **, int), - bool eval_args); -int register_user_function(const char *name, char **parameters, int param_count, - node_t *body); -int register_registry_function(const char *name, command_func_t func); +// Builtins -int register_function(const char *name, command_func_t func); +Value *builtin_add(Value *args); +Value *builtin_sub(Value *args); +Value *builtin_mul(Value *args); +Value *builtin_div(Value *args); +Value *builtin_eq(Value *args); +Value *builtin_list(Value *args); +Value *builtin_car(Value *args); +Value *builtin_cdr(Value *args); -unified_function_t *find_unified_function(const char *name); +// Evaluator -node_t *execute_unified_function(exec_context_t *ctx, const char *name, - node_t **args, int arg_count); +Value *eval_list(Value *list, Env *env); +Value *apply_function(Value *func, Value *args, Env *env); +Value *eval_expr(Value *expr, Env *env); -command_func_t find_function(const char *name); -int execute_command(const char *name); +// Key-mapping -node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call); +KeyBindingTable *extract_keybindings(Value *keymap); +char *normalize_key_sequence(const char *raw_input); +bool execute_keybinding(const char *key_sequence); +void set_active_keymap(const char *keymap_name); +void combine_keymaps(const char *global_keymap, const char *mode_keymap); + +bool execute_editor_command(const char *command); #endif diff --git a/include/init.h b/include/init.h new file mode 100644 index 0000000..c092f0c --- /dev/null +++ b/include/init.h @@ -0,0 +1,13 @@ +#ifndef BLISP_INIT_H_ +#define BLISP_INIT_H_ + +#include "data.h" + +void init_builtins(Env *env); + +Value *lisp_eval(const char *input); +void lisp_init(void); +void repl(void); +void load_file(const char *filename); + +#endif diff --git a/include/lexer.h b/include/lexer.h index ba7a3ef..f10992c 100644 --- a/include/lexer.h +++ b/include/lexer.h @@ -2,9 +2,11 @@ #define LEXER_H_ #include "data.h" -#include -#include -token_t next_token(lexer_t *lexer); +void skip_whitespace(Lexer *lex); + +Token peek_token(Lexer *lex); + +Token next_token(Lexer *lex); #endif diff --git a/include/node.h b/include/node.h deleted file mode 100644 index 68027fd..0000000 --- a/include/node.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NODE_T_ -#define NODE_T_ - -#include "data.h" - -node_t *create_node(node_type_t type); -node_t *create_symbol_node(const char *symbol); -node_t *create_string_node(const char *string); -node_t *create_number_node(double number); -node_t *create_boolean_node(bool value); -node_t *create_list_node(void); -node_t *create_function_ref_node(const char *function_name); -node_t *create_function_call_node(const char *function_name); - -void free_node(node_t *node); -node_t *copy_node(node_t *src); - -node_t *evaluate_node(exec_context_t *ctx, node_t *node); - -#endif diff --git a/include/parser.h b/include/parser.h index d6dce27..929c251 100644 --- a/include/parser.h +++ b/include/parser.h @@ -3,9 +3,7 @@ #include "data.h" -node_t *parse_atom(lexer_t *lexer, token_t *token); -node_t *parse_function_call(lexer_t *lexer, const char *function_name); -node_t *parse_statement(lexer_t *lexer); -node_t *parse_expression(lexer_t *lexer, token_t *token); +Value *parse_list(Lexer *lex); +Value *parse_expr(Lexer *lex); #endif diff --git a/include/utils.h b/include/utils.h new file mode 100644 index 0000000..02b2a6d --- /dev/null +++ b/include/utils.h @@ -0,0 +1,14 @@ +#ifndef BLISP_UTILS_H_ +#define BLISP_UTILS_H_ + +#include "data.h" + +bool is_nil(Value *v); +bool is_symbol(Value *v, const char *sym); +Value *car(Value *v); +Value *cdr(Value *v); +int list_length(Value *v); + +void print_value(Value *v); + +#endif diff --git a/init.bl b/init.bl deleted file mode 100644 index 6f20209..0000000 --- a/init.bl +++ /dev/null @@ -1,17 +0,0 @@ -// Configuration file - -,map-key("CTRL-s" %editorSave) -// ,map-key("CTRL-q" %editorQuit) -,map-key("CTRL-a" %move-cursor-beg-line) -,map-key("CTRL-z" %move-cursor-end-line) -,map-key("CTRL-f o" %open-file) -,map-key("CTRL-w s h" %window-split-horizontal) -,map-key("CTRL-w s v" %window-split-vertical) - -,fun(saveQuit () ( - ,editorSave - ,editorQuit -)) - -,define(theme "dark") -,define(auto-save true) diff --git a/main.c b/main.c deleted file mode 100644 index 365f9bf..0000000 --- a/main.c +++ /dev/null @@ -1,34 +0,0 @@ - -#define GLOBAL_EDITOR - -#include "include/config_tools.h" -#include "include/data.h" - -int main(void) { - // Parse the configuration - config_create(); - char *config_file = "init.bl"; - - if (config_parse_file(config_file) != 0) { - fprintf(stderr, "Error: Failed to parse config file\n"); - return 1; - } - - printf("Successfully parsed Lisp config file: %s\n\n", config_file); - - // Print all entries - config_print_all(); - printf("\n"); - - // Demonstrate usage - printf("Example usage:\n"); - printf("CTRL-s maps to: %s\n", config_get_key_mapping("CTRL-s")); - printf("CTRL-f o maps to: %s\n", config_get_key_mapping("CTRL-f o")); - printf("Window width: %d\n", config_get_int("window-width", 1024)); - printf("Theme: %s\n", config_get_string("theme", "light")); - printf("Auto-save: %s\n", - config_get_bool("auto-save", false) ? "enabled" : "disabled"); - printf("Font size: %d\n", config_get_int("font-size", 12)); - - return 0; -} diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..443d7bc --- /dev/null +++ b/src/config.c @@ -0,0 +1,218 @@ +#include "../include/config.h" +#include "../include/utils.h" + +ConfigValue *get_config_var(const char *name) { + Value *val = env_get(global_env, name); + if (!val) + return NULL; + + ConfigValue *config = malloc(sizeof(ConfigValue)); + + switch (val->type) { + case VAL_NUMBER: + if (val->data.number == (int)val->data.number) { + config->type = CONFIG_INT; + config->value.int_val = (int)val->data.number; + } else { + config->type = CONFIG_FLOAT; + config->value.float_val = val->data.number; + } + break; + + case VAL_STRING: + config->type = CONFIG_STRING; + config->value.string_val = strdup(val->data.string); + break; + + case VAL_SYMBOL: + if (strcmp(val->data.symbol, "true") == 0) { + config->type = CONFIG_BOOL; + config->value.bool_val = true; + } else if (strcmp(val->data.symbol, "false") == 0) { + config->type = CONFIG_BOOL; + config->value.bool_val = false; + } else { + config->type = CONFIG_STRING; + config->value.string_val = strdup(val->data.symbol); + } + break; + + case VAL_LIST: { + config->type = CONFIG_LIST; + config->value.list_val.count = list_length(val); + config->value.list_val.items = + malloc(sizeof(char *) * config->value.list_val.count); + + Value *curr = val; + int i = 0; + while (curr->type == VAL_LIST && i < config->value.list_val.count) { + Value *item = car(curr); + if (item->type == VAL_STRING) { + config->value.list_val.items[i] = strdup(item->data.string); + } else if (item->type == VAL_SYMBOL) { + config->value.list_val.items[i] = strdup(item->data.symbol); + } else if (item->type == VAL_NUMBER) { + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%.2f", item->data.number); + config->value.list_val.items[i] = strdup(buffer); + } else { + config->value.list_val.items[i] = strdup("unknown"); + } + curr = cdr(curr); + i++; + } + break; + } + + default: + config->type = CONFIG_UNKNOWN; + break; + } + + return config; +} + +// Convenience functions for common types +int get_config_int(const char *name, int default_val) { + ConfigValue *val = get_config_var(name); + if (!val) + return default_val; + + int result = default_val; + if (val->type == CONFIG_INT) { + result = val->value.int_val; + } else if (val->type == CONFIG_FLOAT) { + result = (int)val->value.float_val; + } + + free_config_value(val); + return result; +} + +double get_config_float(const char *name, double default_val) { + ConfigValue *val = get_config_var(name); + if (!val) + return default_val; + + double result = default_val; + if (val->type == CONFIG_FLOAT) { + result = val->value.float_val; + } else if (val->type == CONFIG_INT) { + result = (double)val->value.int_val; + } + + free_config_value(val); + return result; +} + +char *get_config_string(const char *name, const char *default_val) { + ConfigValue *val = get_config_var(name); + if (!val) + return default_val ? strdup(default_val) : NULL; + + char *result = NULL; + if (val->type == CONFIG_STRING) { + result = strdup(val->value.string_val); + } else if (default_val) { + result = strdup(default_val); + } + + free_config_value(val); + return result; +} + +bool get_config_bool(const char *name, bool default_val) { + ConfigValue *val = get_config_var(name); + if (!val) + return default_val; + + bool result = default_val; + if (val->type == CONFIG_BOOL) { + result = val->value.bool_val; + } else if (val->type == CONFIG_INT) { + result = val->value.int_val != 0; + } + + free_config_value(val); + return result; +} + +char **get_config_list(const char *name, int *count) { + ConfigValue *val = get_config_var(name); + if (!val || val->type != CONFIG_LIST) { + if (count) + *count = 0; + return NULL; + } + + char **result = malloc(sizeof(char *) * val->value.list_val.count); + for (int i = 0; i < val->value.list_val.count; i++) { + result[i] = strdup(val->value.list_val.items[i]); + } + + if (count) + *count = val->value.list_val.count; + + free_config_value(val); + return result; +} + +// Free ConfigValue +void free_config_value(ConfigValue *val) { + if (!val) + return; + + switch (val->type) { + case CONFIG_STRING: + free(val->value.string_val); + break; + case CONFIG_LIST: + for (int i = 0; i < val->value.list_val.count; i++) { + free(val->value.list_val.items[i]); + } + free(val->value.list_val.items); + break; + default: + break; + } + + free(val); +} + +// Check if variable exists +bool config_var_exists(const char *name) { + return env_get(global_env, name) != NULL; +} + +// Set variables from C code +void set_config_int(const char *name, int value) { + env_set(global_env, name, make_number(value)); +} + +void set_config_float(const char *name, double value) { + env_set(global_env, name, make_number(value)); +} + +void set_config_string(const char *name, const char *value) { + env_set(global_env, name, make_string(value)); +} + +void set_config_bool(const char *name, bool value) { + env_set(global_env, name, make_symbol(value ? "true" : "false")); +} + +// Print all variables (for debugging) +void print_all_config_vars(void) { + printf("\n=== Configuration Variables ===\n"); + Env *env = global_env; + + while (env) { + for (int i = 0; i < env->count; i++) { + printf("%-20s = ", env->names[i]); + print_value(env->values[i]); + printf("\n"); + } + env = env->parent; + } + printf("==============================\n\n"); +} diff --git a/src/config_tools.c b/src/config_tools.c deleted file mode 100644 index baedad0..0000000 --- a/src/config_tools.c +++ /dev/null @@ -1,333 +0,0 @@ - -#include "../include/config_tools.h" -#include "../include/function.h" -#include "../include/node.h" -#define GLOBAL_CONFIG -#include "../include/data.h" -#include -#include -#include - -void config_create(void) { - /* - * @brief Initialize config structure - */ - config.key_mappings = NULL; - config.variables = NULL; -} - -void init_builtin_functions(void) { - register_builtin_function("map-key", handle_map_key, true); - register_builtin_function("define", handle_define, false); // Don't eval args - register_builtin_function("func", handle_function, false); // Don't eval args -} - -// Built-in function handlers -int handle_map_key(node_t **args, int arg_count) { - if (arg_count != 2 || args[0]->type != NODE_STRING || - args[1]->type != NODE_FUNCTION_REF) { - fprintf(stderr, "Error: map-key requires (key_combo, function_ref)\n"); - return -1; - } - - key_mapping_t *mapping = malloc(sizeof(key_mapping_t)); - if (!mapping) - return -1; - - mapping->key_combo = strdup(args[0]->data.string); - mapping->function_name = strdup(args[1]->data.function_ref); - mapping->next = config.key_mappings; - config.key_mappings = mapping; - - return 0; -} - -int handle_define(node_t **args, int arg_count) { - - if (arg_count != 2) { - fprintf(stderr, "Error: define requires exactly 2 arguments, got %d\n", - arg_count); - return -1; - } - - if (args[0]->type != NODE_SYMBOL) { - fprintf( - stderr, - "Error: define requires first argument to be a symbol, got type %d\n", - args[0]->type); - return -1; - } - - config_var_t *var = malloc(sizeof(config_var_t)); - if (!var) { - fprintf(stderr, "Error: Failed to allocate memory for variable\n"); - return -1; - } - - var->name = strdup(args[0]->data.symbol); - if (!var->name) { - free(var); - fprintf(stderr, "Error: Failed to allocate memory for variable name\n"); - return -1; - } - - var->value = copy_node(args[1]); - if (!var->value) { - free(var->name); - free(var); - fprintf(stderr, "Error: Failed to copy variable value\n"); - return -1; - } - - var->next = config.variables; - config.variables = var; - - // Verify it was stored - config_var_t *check = config.variables; - while (check) { - check = check->next; - } - - return 0; -} - -int handle_function(node_t **args, int arg_count) { - if (arg_count != 3) { - fprintf(stderr, "Error: func requires exactly 3 arguments, got %d\n", - arg_count); - return -1; - } - - if (args[0]->type != NODE_SYMBOL) { - fprintf( - stderr, - "Error: func requires first argument to be a symbol (function name)\n"); - return -1; - } - - if (args[1]->type != NODE_LIST) { - fprintf(stderr, - "Error: func requires second argument to be a list (parameters)\n"); - return -1; - } - - // Prepare parameters - node_t *param_list = args[1]; - int param_count = param_list->data.list.child_count; - char **parameters = NULL; - - if (param_count > 0) { - parameters = malloc(sizeof(char *) * param_count); - if (!parameters) - return -1; - - for (int i = 0; i < param_count; i++) { - if (param_list->data.list.children[i]->type != NODE_SYMBOL) { - fprintf(stderr, "Error: Function parameters must be symbols\n"); - for (int j = 0; j < i; j++) { - free(parameters[j]); - } - free(parameters); - return -1; - } - parameters[i] = strdup(param_list->data.list.children[i]->data.symbol); - } - } - - // Prepare body - node_t *body = args[2]; - if (body->type != NODE_LIST) { - node_t *wrapper = create_list_node(); - add_to_list(wrapper, copy_node(body)); - body = wrapper; - } else { - body = copy_node(body); - } - - // Register the function - return register_user_function(args[0]->data.symbol, parameters, param_count, - body); -} - -int execute_function_call(node_t *call) { - exec_context_t ctx = {0}; - ctx.local_vars.names = NULL; - ctx.local_vars.values = NULL; - ctx.local_vars.count = 0; - - node_t *result = execute_function_call_in_context(&ctx, call); - if (result) { - free_node(result); - return 0; - } - return -1; -} - -int config_parse_string(const char *input) { - lexer_t lexer = {0}; - lexer.input = input; - lexer.pos = 0; - lexer.line = 1; - lexer.column = 1; - lexer.current_char = input[0]; - - while (lexer.current_char != '\0') { - skip_whitespace(&lexer); - skip_comment(&lexer); - skip_whitespace(&lexer); - - if (lexer.current_char == '\0') - break; - if (lexer.current_char == '\n') { - advance_char(&lexer); - continue; - } - - node_t *stmt = parse_statement(&lexer); - if (stmt) { - if (execute_function_call(stmt) != 0) { - fprintf(stderr, "Error executing statement at line %d\n", lexer.line); - } - if (stmt->type != NODE_FUNCTION_CALL || - (strcmp(stmt->data.call.function_name, "define") != 0 && - strcmp(stmt->data.call.function_name, "func") != 0)) { - free_node(stmt); // Don't free if ownership was transferred - } - } - - // Skip to next line - while (lexer.current_char != '\n' && lexer.current_char != '\0') { - advance_char(&lexer); - } - } - - return 0; -} - -int config_parse_file(const char *filename) { - FILE *file = fopen(filename, "r"); - long file_size = 0; - char *content = NULL; - int result = 0; - if (!file) { - perror("Error opening config file"); - return -1; - } - - fseek(file, 0, SEEK_END); - file_size = ftell(file); - fseek(file, 0, SEEK_SET); - - content = (char *)malloc(file_size + 1); - if (!content) { - fclose(file); - return -1; - } - - fread(content, 1, file_size, file); - content[file_size] = '\0'; - fclose(file); - - result = config_parse_string(content); - free(content); - - return result; -} - -// Getter functions - -const char *config_get_key_mapping(const char *key_combo) { - key_mapping_t *mapping = config.key_mappings; - while (mapping) { - if (strcmp(mapping->key_combo, key_combo) == 0) { - return mapping->function_name; - } - mapping = mapping->next; - } - return NULL; -} - -node_t *find_variable(const char *name) { - config_var_t *var = config.variables; - while (var) { - if (strcmp(var->name, name) == 0) { - return var->value; - } - var = var->next; - } - return NULL; -} - -const char *config_get_string(const char *path, const char *default_value) { - node_t *node = find_variable(path); - if (node && node->type == NODE_STRING) { - return node->data.string; - } - return default_value; -} - -int config_get_int(const char *path, int default_value) { - node_t *node = find_variable(path); - if (node && node->type == NODE_NUMBER) { - return (int)node->data.number; - } - return default_value; -} - -double config_get_double(const char *path, double default_value) { - node_t *node = find_variable(path); - if (node && node->type == NODE_NUMBER) { - return node->data.number; - } - return default_value; -} - -bool config_get_bool(const char *path, bool default_value) { - node_t *node = find_variable(path); - if (node && node->type == NODE_BOOLEAN) { - return node->data.boolean; - } - return default_value; -} - -void config_print_all(void) { - printf("Key Mappings:\n"); - printf("%-20s -> %s\n", "Key Combination", "Function\n"); - printf("%-20s %s\n", "---------------", "--------\n"); - - key_mapping_t *mapping = config.key_mappings; - while (mapping) { - printf("%-20s -> %s\n", mapping->key_combo, mapping->function_name); - mapping = mapping->next; - } - - printf("\nVariables:\n"); - printf("%-20s = %s\n", "Name", "Value\n"); - printf("%-20s %s\n", "----", "-----\n"); - - config_var_t *var = config.variables; - while (var) { - printf("%-20s = \n", var->name); - - switch (var->value->type) { - case NODE_STRING: - printf("\"%s\"", var->value->data.string); - break; - case NODE_NUMBER: - printf("%g", var->value->data.number); - break; - case NODE_BOOLEAN: - printf("%s", var->value->data.boolean ? "true" : "false"); - break; - case NODE_SYMBOL: - printf("%s", var->value->data.symbol); - break; - default: - printf("[unknown type]"); - break; - } - printf("\n"); - - var = var->next; - } -} diff --git a/src/data.c b/src/data.c index 5814076..5747f91 100644 --- a/src/data.c +++ b/src/data.c @@ -1,92 +1,102 @@ -#include "../include/data.h" -#include "../include/define.h" -#include #include -#include -#include +#define GLOBAL_ENV_ -void advance_char(lexer_t *lexer) { - if (lexer->current_char == '\n') { - lexer->line++; - lexer->column = 1; - } else { - lexer->column++; - } - lexer->pos++; - lexer->current_char = lexer->input[lexer->pos]; -} +#include "../include/data.h" -void skip_whitespace(lexer_t *lexer) { - while (isspace(lexer->current_char) && lexer->current_char != '\n') { - advance_char(lexer); - } -} - -void skip_comment(lexer_t *lexer) { - if (lexer->current_char == '/' && lexer->input[lexer->pos + 1] == '/') { - while (lexer->current_char != '\n' && lexer->current_char != '\0') { - advance_char(lexer); - } - } -} - -node_t *create_list_node(void) { - node_t *node = malloc(sizeof(node_t)); - if (!node) { +// Memory management +Value *make_value(ValueType type) { + /* + ** Create a Value struct of type -type- + */ + Value *v = (Value *)malloc(sizeof(Value)); + if (!v) { return NULL; } - - node->type = NODE_LIST; - node->data.list.child_count = 0; - node->data.list.children = NULL; - - return node; + v->type = type; + return v; } -void add_arg_to_call(node_t *call, node_t *arg) { - if (call->type == NODE_FUNCTION_CALL && - call->data.call.arg_count < MAX_ARGS) { - call->data.call.args = - (node_t **)realloc(call->data.call.args, - (call->data.call.arg_count + 1) * sizeof(node_t *)); - call->data.call.args[call->data.call.arg_count++] = arg; +Value *make_nil(void) { return make_value(VAL_NIL); } + +Value *make_number(double n) { + Value *v = make_value(VAL_NUMBER); + if (!v) { + fprintf(stderr, "ERROR : not assigned\n"); } + v->data.number = n; + fprintf(stderr, "DEBUG : value %lf\n", n); + return v; } -void add_to_list(node_t *list, node_t *element) { - node_t **new_children = NULL; - if (!list || !element) { - return; +Value *make_string(const char *s) { + Value *v = make_value(VAL_STRING); + v->data.string = strdup(s); + return v; +} + +Value *make_symbol(const char *s) { + Value *v = make_value(VAL_SYMBOL); + v->data.symbol = strdup(s); + return v; +} + +Value *make_list(Value *car, Value *cdr) { + fprintf(stderr, "DEBUG : list done\n"); + Value *v = make_value(VAL_LIST); + if (!v) { + fprintf(stderr, "ERROR : value\n"); } + v->data.list.cdr = car; + v->data.list.cdr = cdr; + return v; +} - // Ensure this is actually a list node - if (list->type != NODE_LIST) { - return; - } +Value *make_builtin(BuiltinFunc func) { + Value *v = make_value(VAL_BUILTIN); + v->data.builtin = func; + return v; +} - // If this is the first element - if (list->data.list.children == NULL) { +// Environment functions +Env *make_env(Env *parent) { + Env *env = malloc(sizeof(Env)); + env->names = malloc(sizeof(char *) * 16); + env->values = malloc(sizeof(Value *) * 16); + env->count = 0; + env->capacity = 16; + env->parent = parent; + return env; +} - fprintf(stderr, "DEBUG : child number 0 added\n"); - list->data.list.children = malloc(sizeof(node_t *)); - if (!list->data.list.children) { - return; // Memory allocation failed +void env_set(Env *env, const char *name, Value *value) { + // Check if variable already exists + for (int i = 0; i < env->count; i++) { + if (strcmp(env->names[i], name) == 0) { + env->values[i] = value; + return; } - list->data.list.children[0] = element; - list->data.list.child_count = 1; - return; } - // Reallocate to add new element - new_children = realloc(list->data.list.children, - sizeof(node_t *) * (list->data.list.child_count + 1)); - if (!new_children) { - return; // Memory allocation failed + // Add new variable + if (env->count >= env->capacity) { + env->capacity *= 2; + env->names = realloc(env->names, sizeof(char *) * env->capacity); + env->values = realloc(env->values, sizeof(Value *) * env->capacity); } - list->data.list.children = new_children; - list->data.list.children[list->data.list.child_count] = element; - list->data.list.child_count++; - fprintf(stderr, "DEBUG : child number %d added\n", - list->data.list.child_count); + env->names[env->count] = strdup(name); + env->values[env->count] = value; + env->count++; +} + +Value *env_get(Env *env, const char *name) { + while (env) { + for (int i = 0; i < env->count; i++) { + if (strcmp(env->names[i], name) == 0) { + return env->values[i]; + } + } + env = env->parent; + } + return NULL; } diff --git a/src/function.c b/src/function.c index e57eac7..0650f48 100644 --- a/src/function.c +++ b/src/function.c @@ -1,215 +1,518 @@ #include "../include/function.h" -#include "../include/data.h" -#include "../include/node.h" +#include "../include/utils.h" #include -#include -#include -int register_builtin_function(const char *name, - int (*handler)(node_t **args, int arg_count), - bool eval_args) { - unified_function_t *func = malloc(sizeof(unified_function_t)); - if (!func) - return -1; +// Builtins - func->name = strdup(name); - func->type = FUNC_BUILTIN; - func->data.builtin.handler = handler; - func->data.builtin.eval_args = eval_args; - func->next = unified_functions; - unified_functions = func; - fprintf(stderr, "%s succefully added\n", name); - - return 0; -} - -int register_user_function(const char *name, char **parameters, int param_count, - node_t *body) { - unified_function_t *func = malloc(sizeof(unified_function_t)); - if (!func) - return -1; - - func->name = strdup(name); - func->type = FUNC_USER_DEFINED; - func->data.user_defined.parameters = parameters; - func->data.user_defined.param_count = param_count; - func->data.user_defined.body = body; - func->next = unified_functions; - unified_functions = func; - - return 0; -} - -int register_registry_function(const char *name, command_func_t c_func) { - unified_function_t *func = malloc(sizeof(unified_function_t)); - if (!func) - return -1; - - func->name = strdup(name); - func->type = FUNC_REGISTRY; - func->data.registry.func = c_func; - func->next = unified_functions; - unified_functions = func; - fprintf(stderr, "DEBIG : %s added\n", name); - - return 0; -} - -int register_function(const char *name, command_func_t func) { - return register_registry_function(name, func); -} - -unified_function_t *find_unified_function(const char *name) { - unified_function_t *func = unified_functions; - while (func) { - // fprintf(stderr, "%s\n", func->name); - if (strcmp(func->name, name) == 0) { - return func; +Value *builtin_add(Value *args) { + double sum = 0; + while (args->type == VAL_LIST) { + Value *arg = car(args); + if (arg->type == VAL_NUMBER) { + sum += arg->data.number; } - func = func->next; + args = cdr(args); } - return NULL; + return make_number(sum); } -node_t *execute_unified_function(exec_context_t *ctx, const char *name, - node_t **args, int arg_count) { - unified_function_t *func = find_unified_function(name); - if (!func) { - fprintf(stderr, "Error: Unknown function '%s'\n", name); - return NULL; +Value *builtin_sub(Value *args) { + if (args->type != VAL_LIST) + return make_number(0); + + Value *first = car(args); + if (first->type != VAL_NUMBER) + return make_number(0); + + double result = first->data.number; + args = cdr(args); + + if (args->type == VAL_NIL) { + return make_number(-result); } - switch (func->type) { - case FUNC_BUILTIN: { - node_t **eval_args = args; + while (args->type == VAL_LIST) { + Value *arg = car(args); + if (arg->type == VAL_NUMBER) { + result -= arg->data.number; + } + args = cdr(args); + } + return make_number(result); +} - // Evaluate arguments if needed - if (func->data.builtin.eval_args) { - eval_args = malloc(sizeof(node_t *) * arg_count); - if (!eval_args) - return NULL; +Value *builtin_mul(Value *args) { + double product = 1; + while (args->type == VAL_LIST) { + Value *arg = car(args); + if (arg->type == VAL_NUMBER) { + product *= arg->data.number; + } + args = cdr(args); + } + return make_number(product); +} - for (int i = 0; i < arg_count; i++) { - eval_args[i] = evaluate_node(ctx, args[i]); - if (!eval_args[i]) { - // Clean up on failure - for (int j = 0; j < i; j++) { - free_node(eval_args[j]); +Value *builtin_div(Value *args) { + if (args->type != VAL_LIST) + return make_number(0); + + Value *first = car(args); + if (first->type != VAL_NUMBER) + return make_number(0); + + double result = first->data.number; + args = cdr(args); + + while (args->type == VAL_LIST) { + Value *arg = car(args); + if (arg->type == VAL_NUMBER && arg->data.number != 0) { + result /= arg->data.number; + } + args = cdr(args); + } + return make_number(result); +} + +Value *builtin_eq(Value *args) { + if (list_length(args) < 2) + return make_nil(); + + Value *first = car(args); + args = cdr(args); + + while (args->type == VAL_LIST) { + Value *arg = car(args); + + if (first->type != arg->type) + return make_nil(); + + switch (first->type) { + case VAL_NUMBER: + if (first->data.number != arg->data.number) + return make_nil(); + break; + case VAL_STRING: + if (strcmp(first->data.string, arg->data.string) != 0) + return make_nil(); + break; + case VAL_SYMBOL: + if (strcmp(first->data.symbol, arg->data.symbol) != 0) + return make_nil(); + break; + case VAL_NIL: + break; + default: + return make_nil(); + } + + args = cdr(args); + } + + return make_symbol("true"); +} + +Value *builtin_list(Value *args) { return args; } + +Value *builtin_car(Value *args) { + if (args->type != VAL_LIST) + return make_nil(); + Value *arg = car(args); + return car(arg); +} + +Value *builtin_cdr(Value *args) { + if (args->type != VAL_LIST) + return make_nil(); + Value *arg = car(args); + return cdr(arg); +} + +// Evaluator + +Value *eval_list(Value *list) { + if (list->type == VAL_NIL) + return make_nil(); + Value *head = eval_expr(car(list)); + Value *tail = eval_list(cdr(list)); + return make_list(head, tail); +} + +Value *apply_function(Value *func, Value *args) { + if (func->type == VAL_FUNCTION) { + + // Bind parameters + Value *arg_list = args; + for (int i = 0; i < func->data.function.param_count; i++) { + if (arg_list->type == VAL_LIST) { + env_set(local_env, func->data.function.params[i], car(arg_list)); + arg_list = cdr(arg_list); + } else { + env_set(local_env, func->data.function.params[i], make_nil()); + } + } + + return eval_expr(func->data.function.body, local_env); + } + + return make_nil(); +} + +Value *eval_expr(Value *expr) { + fprintf(stderr, "DEBUG : Starting evaluation %d\n", expr->type); + switch (expr->type) { + case VAL_NUMBER: + case VAL_STRING: + case VAL_NIL: + return expr; + + case VAL_SYMBOL: + fprintf(stderr, "DEBUG : symbol %s\n", expr->data.symbol); + if (strcmp(expr->data.symbol, "true") == 0) + return expr; + if (strcmp(expr->data.symbol, "false") == 0) + return expr; + return env_get(env, expr->data.symbol) ?: make_nil(); + + case VAL_LIST: { + fprintf(stderr, "DEBUG : eval list\n"); + if (is_nil(expr)) + return expr; + + Value *head = car(expr); + fprintf(stderr, "%s\n", head->data.symbol); + Value *args = cdr(expr); + + // Special forms + if (is_symbol(head, "quote")) { + return car(args); + } + + if (is_symbol(head, "def")) { + fprintf(stderr, "DEBUG : def new var -> %s\n", car(args)->data.symbol); + Value *name = car(args); + Value *value = eval_expr(car(cdr(args)), env); + if (name->type == VAL_SYMBOL) { + env_set(env, name->data.symbol, value); + } + return value; + } + + if (is_symbol(head, "defun")) { + Value *name = car(args); + Value *params = car(cdr(args)); + Value *body = car(cdr(cdr(args))); + + if (name->type == VAL_SYMBOL) { + Value *func = make_value(VAL_FUNCTION); + func->data.function.param_count = list_length(params); + func->data.function.params = + malloc(sizeof(char *) * func->data.function.param_count); + + Value *param_list = params; + for (int i = 0; i < func->data.function.param_count; i++) { + Value *param = car(param_list); + if (param->type == VAL_SYMBOL) { + func->data.function.params[i] = strdup(param->data.symbol); } - free(eval_args); - return NULL; + param_list = cdr(param_list); } + + func->data.function.body = body; + func->data.function.closure = env; + + env_set(env, name->data.symbol, func); + return func; + } + return make_nil(); + } + + if (is_symbol(head, "if")) { + Value *condition = eval_expr(car(args), env); + Value *then_expr = car(cdr(args)); + Value *else_expr = car(cdr(cdr(args))); + + bool is_true = !(condition->type == VAL_NIL || + (condition->type == VAL_SYMBOL && + strcmp(condition->data.symbol, "false") == 0)); + + if (is_true) { + return eval_expr(then_expr, env); + } else { + return eval_expr(else_expr, env); } } - int result = func->data.builtin.handler(eval_args, arg_count); + if (is_symbol(head, "defkeymap")) { + Value *name = car(args); + if (name->type != VAL_SYMBOL) + return make_nil(); - // Clean up evaluated arguments if we allocated them - if (func->data.builtin.eval_args) { - for (int i = 0; i < arg_count; i++) { - free_node(eval_args[i]); - } - free(eval_args); - } + Value *keymap = make_value(VAL_KEYMAP); + keymap->data.keymap.capacity = 16; + keymap->data.keymap.count = 0; + keymap->data.keymap.keys = + malloc(sizeof(char *) * keymap->data.keymap.capacity); + keymap->data.keymap.values = + malloc(sizeof(Value *) * keymap->data.keymap.capacity); - return create_boolean_node(result == 0); - } + Value *bindings = cdr(args); + while (bindings->type == VAL_LIST && cdr(bindings)->type == VAL_LIST) { + Value *key = car(bindings); + Value *value = car(cdr(bindings)); - case FUNC_USER_DEFINED: { - fprintf(stderr, "DEBUG : BODY length %d\n", - func->data.user_defined.body->data.list.child_count); - if (func->data.user_defined.param_count != arg_count) { - fprintf(stderr, "Error: Function '%s' expects %d arguments, got %d\n", - name, func->data.user_defined.param_count, arg_count); - return NULL; - } - - // Create new execution context - exec_context_t new_ctx = *ctx; - - if (func->data.user_defined.param_count > 0) { - new_ctx.local_vars.count = func->data.user_defined.param_count; - new_ctx.local_vars.names = - malloc(sizeof(char *) * func->data.user_defined.param_count); - new_ctx.local_vars.values = - malloc(sizeof(node_t *) * func->data.user_defined.param_count); - - for (int i = 0; i < func->data.user_defined.param_count; i++) { - new_ctx.local_vars.names[i] = func->data.user_defined.parameters[i]; - new_ctx.local_vars.values[i] = evaluate_node(ctx, args[i]); - if (!new_ctx.local_vars.values[i]) { - // Clean up on failure - for (int j = 0; j < i; j++) { - free_node(new_ctx.local_vars.values[j]); + if (key->type == VAL_STRING && value->type == VAL_SYMBOL) { + if (keymap->data.keymap.count >= keymap->data.keymap.capacity) { + keymap->data.keymap.capacity *= 2; + keymap->data.keymap.keys = + realloc(keymap->data.keymap.keys, + sizeof(char *) * keymap->data.keymap.capacity); + keymap->data.keymap.values = + realloc(keymap->data.keymap.values, + sizeof(Value *) * keymap->data.keymap.capacity); } - free(new_ctx.local_vars.names); - free(new_ctx.local_vars.values); - return NULL; + + keymap->data.keymap.keys[keymap->data.keymap.count] = + strdup(key->data.string); + keymap->data.keymap.values[keymap->data.keymap.count] = value; + keymap->data.keymap.count++; } + + bindings = cdr(cdr(bindings)); } + + env_set(env, name->data.symbol, keymap); + return keymap; } - fprintf(stderr, "DEBUG : body %s\n", - func->data.user_defined.body->data.symbol); - node_t *result = evaluate_node(&new_ctx, func->data.user_defined.body); - - // Clean up context - if (func->data.user_defined.param_count > 0) { - for (int i = 0; i < func->data.user_defined.param_count; i++) { - free_node(new_ctx.local_vars.values[i]); - } - free(new_ctx.local_vars.names); - free(new_ctx.local_vars.values); - } - - return result; - } - - case FUNC_REGISTRY: { - // Registry functions don't take arguments and don't return values - func->data.registry.func(); - return create_boolean_node(true); + // Function application + Value *func = eval_expr(head, env); + Value *eval_args = eval_list(args, env); + return apply_function(func, eval_args, env); } default: - fprintf(stderr, "Error: Unknown function type for '%s'\n", name); - return NULL; + fprintf(stderr, "DEBUG : default\n"); + return make_nil(); } } -int execute_command(const char *name) { - fprintf(stderr, "Looking for command %s\n", name); - unified_function_t *func = find_unified_function(name); - if (!func) { - return -1; - } +// Key-mapping - if (func->type == FUNC_REGISTRY) { - func->data.registry.func(); - return 0; - } else if (func->type == FUNC_USER_DEFINED) { - fprintf(stderr, "DEBUG ; user definned %s \n", name); - exec_context_t ctx = {0}; - node_t *result = evaluate_node(&ctx, func->data.user_defined.body); - if (result) { - free_node(result); - return 0; +KeyBindingTable *extract_keybindings(Value *keymap) { + if (keymap->type != VAL_KEYMAP) + return NULL; + + KeyBindingTable *table = malloc(sizeof(KeyBindingTable)); + table->capacity = keymap->data.keymap.count; + table->count = keymap->data.keymap.count; + table->bindings = malloc(sizeof(KeyBinding) * table->capacity); + + for (int i = 0; i < keymap->data.keymap.count; i++) { + table->bindings[i].key_sequence = strdup(keymap->data.keymap.keys[i]); + if (keymap->data.keymap.values[i]->type == VAL_SYMBOL) { + table->bindings[i].command = + strdup(keymap->data.keymap.values[i]->data.symbol); + } else { + table->bindings[i].command = strdup("unknown"); } } - return -1; + return table; } -// Execute function call with context support -node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call) { +// Key sequence normalization +char *normalize_key_sequence(const char *raw_input) { + // Convert raw key input to standard format + // Example: Ctrl+S -> "Ctrl+s", Alt+F4 -> "Alt+F4" + char *normalized = malloc(strlen(raw_input) + 1); + strcpy(normalized, raw_input); - if (call->type != NODE_FUNCTION_CALL) { - return NULL; + // Simple normalization - make letters lowercase except function keys + for (int i = 0; normalized[i]; i++) { + if (normalized[i] >= 'A' && normalized[i] <= 'Z' && + (i == 0 || normalized[i - 1] == '+')) { + // Only lowercase single letters after modifiers + if (strlen(normalized + i) == 1 || normalized[i + 1] == '\0' || + normalized[i + 1] == ' ') { + normalized[i] = tolower(normalized[i]); + } + } } - fprintf(stderr, "DEBUG : Call in context %s\n", - call->data.call.function_name); - return execute_unified_function(ctx, call->data.call.function_name, - call->data.call.args, - call->data.call.arg_count); + return normalized; +} + +// Execute key binding +bool execute_keybinding(const char *key_sequence) { + if (!active_keybindings) + return false; + + char *normalized = normalize_key_sequence(key_sequence); + + for (int i = 0; i < active_keybindings->count; i++) { + if (strcmp(active_keybindings->bindings[i].key_sequence, normalized) == 0) { + // Found matching key binding - execute the command + char *command = active_keybindings->bindings[i].command; + + // Try to find function in environment + Value *func = env_get(global_env, command); + if (func) { + if (func->type == VAL_FUNCTION || func->type == VAL_BUILTIN) { + // Execute function with no arguments + Value *result = apply_function(func, make_nil(), global_env); + free(normalized); + return true; + } else { + // It's a variable or other value - could be a command string + printf("Key bound to value: "); + print_value(func); + printf("\n"); + free(normalized); + return true; + } + } else { + // Command not found in Lisp environment + // This is where you'd call your C editor functions + printf("Executing C command: %s\n", command); + + // Example: dispatch to your editor's command system + if (execute_editor_command(command)) { + free(normalized); + return true; + } + } + } + } + + free(normalized); + return false; +} + +// Set active keymap +void set_active_keymap(const char *keymap_name) { + Value *keymap = env_get(global_env, keymap_name); + if (keymap && keymap->type == VAL_KEYMAP) { + if (active_keybindings) { + // Free old bindings + for (int i = 0; i < active_keybindings->count; i++) { + free(active_keybindings->bindings[i].key_sequence); + free(active_keybindings->bindings[i].command); + } + free(active_keybindings->bindings); + free(active_keybindings); + } + + active_keybindings = extract_keybindings(keymap); + printf("Activated keymap: %s (%d bindings)\n", keymap_name, + active_keybindings->count); + } +} + +// Combine multiple keymaps (for mode-specific + global bindings) +void combine_keymaps(const char *global_keymap, const char *mode_keymap) { + Value *global = env_get(global_env, global_keymap); + Value *mode = env_get(global_env, mode_keymap); + + int total_bindings = 0; + if (global && global->type == VAL_KEYMAP) + total_bindings += global->data.keymap.count; + if (mode && mode->type == VAL_KEYMAP) + total_bindings += mode->data.keymap.count; + + if (active_keybindings) { + for (int i = 0; i < active_keybindings->count; i++) { + free(active_keybindings->bindings[i].key_sequence); + free(active_keybindings->bindings[i].command); + } + free(active_keybindings->bindings); + free(active_keybindings); + } + + active_keybindings = malloc(sizeof(KeyBindingTable)); + active_keybindings->capacity = total_bindings; + active_keybindings->count = 0; + active_keybindings->bindings = malloc(sizeof(KeyBinding) * total_bindings); + + // Add global bindings first + if (global && global->type == VAL_KEYMAP) { + for (int i = 0; i < global->data.keymap.count; i++) { + active_keybindings->bindings[active_keybindings->count].key_sequence = + strdup(global->data.keymap.keys[i]); + if (global->data.keymap.values[i]->type == VAL_SYMBOL) { + active_keybindings->bindings[active_keybindings->count].command = + strdup(global->data.keymap.values[i]->data.symbol); + } + active_keybindings->count++; + } + } + + // Add mode-specific bindings (these override global) + if (mode && mode->type == VAL_KEYMAP) { + for (int i = 0; i < mode->data.keymap.count; i++) { + // Check if this key already exists (override) + bool found = false; + for (int j = 0; j < active_keybindings->count; j++) { + if (strcmp(active_keybindings->bindings[j].key_sequence, + mode->data.keymap.keys[i]) == 0) { + // Override existing binding + free(active_keybindings->bindings[j].command); + if (mode->data.keymap.values[i]->type == VAL_SYMBOL) { + active_keybindings->bindings[j].command = + strdup(mode->data.keymap.values[i]->data.symbol); + } + found = true; + break; + } + } + + if (!found) { + // Add new binding + active_keybindings->bindings[active_keybindings->count].key_sequence = + strdup(mode->data.keymap.keys[i]); + if (mode->data.keymap.values[i]->type == VAL_SYMBOL) { + active_keybindings->bindings[active_keybindings->count].command = + strdup(mode->data.keymap.values[i]->data.symbol); + } + active_keybindings->count++; + } + } + } +} + +bool execute_editor_command(const char *command) { + // This is where you implement your editor's built-in commands + + if (strcmp(command, "save-file") == 0) { + printf("Saving current file...\n"); + // Call your editor's save function + return true; + } + + if (strcmp(command, "open-file") == 0) { + printf("Opening file dialog...\n"); + // Call your editor's open function + return true; + } + + if (strcmp(command, "quit-editor") == 0) { + printf("Quitting editor...\n"); + // Call your editor's quit function + exit(0); + return true; + } + + if (strcmp(command, "new-file") == 0) { + printf("Creating new file...\n"); + return true; + } + + if (strcmp(command, "compile-current") == 0) { + printf("Compiling current file...\n"); + return true; + } + + // Add more commands as needed + printf("Unknown command: %s\n", command); + return false; } diff --git a/src/init.c b/src/init.c new file mode 100644 index 0000000..bd0bbcc --- /dev/null +++ b/src/init.c @@ -0,0 +1,85 @@ +#include "../include/init.h" +#include "../include/function.h" +#include "../include/parser.h" +#include "../include/utils.h" +#include + +void init_builtins(Env *env) { + env_set(env, "+", make_builtin(builtin_add)); + env_set(env, "-", make_builtin(builtin_sub)); + env_set(env, "*", make_builtin(builtin_mul)); + env_set(env, "/", make_builtin(builtin_div)); + env_set(env, "=", make_builtin(builtin_eq)); + env_set(env, "list", make_builtin(builtin_list)); + env_set(env, "car", make_builtin(builtin_car)); + env_set(env, "cdr", make_builtin(builtin_cdr)); +} + +// Main interpreter functions +Value *lisp_eval(const char *input) { + Lexer lex = {input, 0, strlen(input)}; + Value *expr = parse_expr(&lex); + return eval_expr(expr, global_env); +} + +void lisp_init(void) { + global_env = make_env(NULL); + init_builtins(global_env); +} + +// REPL and file loading +void repl(void) { + char input[1024]; + printf("Lisp Config Interpreter\n"); + printf("Type 'quit' to exit\n\n"); + + while (1) { + printf("> "); + if (!fgets(input, sizeof(input), stdin)) + break; + + // Remove newline + input[strcspn(input, "\n")] = 0; + + if (strcmp(input, "quit") == 0) + break; + if (strlen(input) == 0) + continue; + + Value *result = lisp_eval(input); + print_value(result); + printf("\n"); + } +} + +void load_file(const char *filename) { + FILE *file = fopen(filename, "r"); + if (!file) { + printf("Error: Cannot open file %s\n", filename); + return; + } + + fprintf(stderr, "DEBUG : Reading file -> %s\n", filename); + + fseek(file, 0, SEEK_END); + long length = ftell(file); + fseek(file, 0, SEEK_SET); + + char *content = malloc(length + 1); + fread(content, 1, length, file); + content[length] = '\0'; + fclose(file); + + Lexer lex = {content, 0, length}; + + while (lex.pos < lex.length) { + Value *expr = parse_expr(&lex); + if (expr->type != VAL_NIL) { + fprintf(stderr, "DEBUG : Expr parsed\n"); + Value *result = eval_expr(expr, global_env); + // Optionally print results + } + } + + free(content); +} diff --git a/src/lexer.c b/src/lexer.c index df5e5f1..7055265 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,152 +1,86 @@ #include "../include/lexer.h" -#include "../include/define.h" -#include -#include -#include -#include -token_t next_token(lexer_t *lexer) { - token_t token = {0}; - token.line = lexer->line; - token.column = lexer->column; - - skip_whitespace(lexer); - skip_comment(lexer); - skip_whitespace(lexer); - - if (lexer->current_char == '\0') { - token.type = TOKEN_EOF; - return token; - } - - // Newline (statement separator) - if (lexer->current_char == '\n') { - token.type = TOKEN_NEWLINE; - advance_char(lexer); - return token; - } - - // Comma (function call indicator) - if (lexer->current_char == ',') { - token.type = TOKEN_COMMA; - token.value = (char *)malloc(2 * sizeof(char)); - token.value[0] = ','; - token.value[1] = '\0'; - advance_char(lexer); - fprintf(stderr, "DEBUG : next token = ,\n"); - return token; - } - - // Percent (function reference indicator) - if (lexer->current_char == '%') { - token.type = TOKEN_PERCENT; - token.value = (char *)malloc(2 * sizeof(char)); - token.value[0] = '%'; - token.value[1] = '\0'; - advance_char(lexer); - return token; - } - - // Parentheses - if (lexer->current_char == '(') { - token.type = TOKEN_LPAREN; - token.value = (char *)malloc(2 * sizeof(char)); - token.value[0] = '('; - token.value[1] = '\0'; - advance_char(lexer); - fprintf(stderr, "DEBUG : next token = (\n"); - return token; - } - - if (lexer->current_char == ')') { - token.type = TOKEN_RPAREN; - token.value = (char *)malloc(2 * sizeof(char)); - token.value[0] = ')'; - token.value[1] = '\0'; - fprintf(stderr, "DEBUG : next token = )\n"); - advance_char(lexer); - return token; - } - - // Strings - if (lexer->current_char == '"') { - token.type = TOKEN_STRING; - advance_char(lexer); // Skip opening quote - - int i = 0; - while (lexer->current_char != '"' && lexer->current_char != '\0') { - token.value = (char *)realloc(token.value, (i + 1) * sizeof(char)); - if (lexer->current_char == '\\' && lexer->input[lexer->pos + 1] != '\0') { - advance_char(lexer); - switch (lexer->current_char) { - case 'n': - token.value[i++] = '\n'; - break; - case 't': - token.value[i++] = '\t'; - break; - case 'r': - token.value[i++] = '\r'; - break; - case '\\': - token.value[i++] = '\\'; - break; - case '"': - token.value[i++] = '"'; - break; - default: - token.value[i++] = lexer->current_char; - break; - } - } else { - token.value[i++] = lexer->current_char; - } - advance_char(lexer); - } - token.value[i] = '\0'; - - if (lexer->current_char == '"') { - advance_char(lexer); // Skip closing quote - } - return token; - } - - // Numbers, symbols, and booleans - if (isalnum(lexer->current_char) || lexer->current_char == '-' || - lexer->current_char == '+' || lexer->current_char == '.' || - lexer->current_char == '_') { - - int i = 0; - while ( - (isalnum(lexer->current_char) || strchr("-+._", lexer->current_char))) { - token.value = (char *)realloc(token.value, (i + 1) * sizeof(char)); - token.value[i++] = lexer->current_char; - advance_char(lexer); - } - token.value[i] = '\0'; - - // Check for booleans - if (strcmp(token.value, "true") == 0 || strcmp(token.value, "false") == 0) { - token.type = TOKEN_BOOLEAN; - } else { - // Check for numbers - char *endptr; - strtod(token.value, &endptr); - if (*endptr == '\0' && strlen(token.value) > 0 && - (isdigit(token.value[0]) || token.value[0] == '-' || - token.value[0] == '+')) { - token.type = TOKEN_NUMBER; - } else { - token.type = TOKEN_SYMBOL; - fprintf(stderr, "DEBUG : next token = %s\n", token.value); +void skip_whitespace(Lexer *lex) { + while (lex->pos < lex->length && + (isspace(lex->input[lex->pos]) || lex->input[lex->pos] == ';')) { + if (lex->input[lex->pos] == ';') { + // Skip comment to end of line + while (lex->pos < lex->length && lex->input[lex->pos] != '\n') { + lex->pos++; } } - return token; + lex->pos++; } - - // Error case - token.type = TOKEN_ERROR; - snprintf(token.value, MAX_TOKEN_LENGTH - 1, "Unexpected character '%c'", - lexer->current_char); - return token; +} + +Token peek_token(Lexer *lex) { + int saved_pos = lex->pos; + Token tok = next_token(lex); + lex->pos = saved_pos; // Restore position + return tok; +} + +Token next_token(Lexer *lex) { + Token tok = {0}; + skip_whitespace(lex); + + if (lex->pos >= lex->length) { + tok.type = TOK_EOF; + return tok; + } + + char c = lex->input[lex->pos]; + + if (c == '(') { + tok.type = TOK_LPAREN; + lex->pos++; + } else if (c == ')') { + tok.type = TOK_RPAREN; + lex->pos++; + } else if (c == '\'') { + tok.type = TOK_QUOTE; + lex->pos++; + } else if (c == '"') { + // String literal + tok.type = TOK_STRING; + lex->pos++; // Skip opening quote + int start = lex->pos; + while (lex->pos < lex->length && lex->input[lex->pos] != '"') { + lex->pos++; + } + int len = lex->pos - start; + tok.value = malloc(len + 1); + strncpy(tok.value, lex->input + start, len); + tok.value[len] = '\0'; + lex->pos++; // Skip closing quote + } else if (isdigit(c) || (c == '-' && isdigit(lex->input[lex->pos + 1]))) { + // Number + tok.type = TOK_NUMBER; + int start = lex->pos; + if (c == '-') + lex->pos++; + while (lex->pos < lex->length && + (isdigit(lex->input[lex->pos]) || lex->input[lex->pos] == '.')) { + lex->pos++; + } + int len = lex->pos - start; + tok.value = malloc(len + 1); + strncpy(tok.value, lex->input + start, len); + tok.value[len] = '\0'; + } else { + // Symbol + tok.type = TOK_SYMBOL; + int start = lex->pos; + while (lex->pos < lex->length && !isspace(lex->input[lex->pos]) && + lex->input[lex->pos] != '(' && lex->input[lex->pos] != ')' && + lex->input[lex->pos] != ';') { + lex->pos++; + } + int len = lex->pos - start; + tok.value = malloc(len + 1); + strncpy(tok.value, lex->input + start, len); + tok.value[len] = '\0'; + } + + return tok; } diff --git a/src/node.c b/src/node.c deleted file mode 100644 index ddf5e09..0000000 --- a/src/node.c +++ /dev/null @@ -1,223 +0,0 @@ -#include "../include/node.h" -#include "../include/config_tools.h" -#include "../include/define.h" -#include "../include/function.h" -#include -#include -#include -#include - -// Node creation functions -node_t *create_node(node_type_t type) { - node_t *node = malloc(sizeof(node_t)); - if (!node) - return NULL; - - memset(node, 0, sizeof(node_t)); - node->type = type; - return node; -} - -node_t *create_symbol_node(const char *symbol) { - node_t *node = create_node(NODE_SYMBOL); - if (node) { - node->data.symbol = (char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char)); - strncpy(node->data.symbol, symbol, MAX_SYMBOL_LENGTH - 1); - node->data.symbol[MAX_SYMBOL_LENGTH - 1] = '\0'; - } - return node; -} - -node_t *create_string_node(const char *string) { - node_t *node = create_node(NODE_STRING); - if (node) { - node->data.string = (char *)malloc((MAX_STRING_LENGTH - 1) * sizeof(char)); - strncpy(node->data.string, string, MAX_STRING_LENGTH - 1); - node->data.string[MAX_STRING_LENGTH - 1] = '\0'; - } - return node; -} - -node_t *create_number_node(double number) { - node_t *node = create_node(NODE_NUMBER); - if (node) { - node->data.number = number; - } - return node; -} - -node_t *create_boolean_node(bool value) { - node_t *node = create_node(NODE_BOOLEAN); - if (node) { - node->data.boolean = value; - } - return node; -} - -node_t *create_function_ref_node(const char *function_name) { - node_t *node = create_node(NODE_FUNCTION_REF); - if (node) { - node->data.function_ref = - (char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char)); - strncpy(node->data.function_ref, function_name, MAX_SYMBOL_LENGTH - 1); - node->data.function_ref[MAX_SYMBOL_LENGTH - 1] = '\0'; - } - return node; -} - -node_t *create_function_call_node(const char *function_name) { - node_t *node = create_node(NODE_FUNCTION_CALL); - if (node) { - node->data.call.function_name = - (char *)malloc((MAX_SYMBOL_LENGTH - 1) * sizeof(char)); - strncpy(node->data.call.function_name, function_name, - MAX_SYMBOL_LENGTH - 1); - node->data.call.function_name[MAX_SYMBOL_LENGTH - 1] = '\0'; - node->data.call.arg_count = 0; - } - return node; -} - -node_t *copy_node(node_t *src) { - if (!src) - return NULL; - - node_t *copy = malloc(sizeof(node_t)); - if (!copy) - return NULL; - - copy->type = src->type; - - switch (src->type) { - case NODE_STRING: - copy->data.string = strdup(src->data.string); - break; - case NODE_NUMBER: - copy->data.number = src->data.number; - break; - case NODE_BOOLEAN: - copy->data.boolean = src->data.boolean; - break; - case NODE_SYMBOL: - copy->data.symbol = strdup(src->data.symbol); - break; - case NODE_FUNCTION_REF: - copy->data.function_ref = strdup(src->data.function_ref); - break; - case NODE_LIST: - copy->data.list.child_count = src->data.list.child_count; - copy->data.list.children = - malloc(sizeof(node_t *) * src->data.list.child_count); - for (int i = 0; i < src->data.list.child_count; i++) { - copy->data.list.children[i] = copy_node(src->data.list.children[i]); - } - break; - case NODE_FUNCTION_CALL: - copy->data.call.function_name = strdup(src->data.call.function_name); - copy->data.call.arg_count = src->data.call.arg_count; - copy->data.call.args = malloc(sizeof(node_t *) * src->data.call.arg_count); - for (int i = 0; i < src->data.call.arg_count; i++) { - copy->data.call.args[i] = copy_node(src->data.call.args[i]); - } - break; - default: - free(copy); - return NULL; - } - - return copy; -} - -void free_node(node_t *node) { - int i; - if (!node) - return; - - if (node->type == NODE_FUNCTION_CALL) { - for (i = 0; i < node->data.call.arg_count; i++) { - free_node(node->data.call.args[i]); - } - free(node->data.call.args); - } else if (node->type == NODE_LIST) { - for (i = 0; i < node->data.list.child_count; i++) { - free_node(node->data.list.children[i]); - } - free(node->data.list.children); - } - - // Free string data if present - if (node->type == NODE_STRING && node->data.string) { - free(node->data.string); - } else if (node->type == NODE_SYMBOL && node->data.symbol) { - free(node->data.symbol); - } else if (node->type == NODE_FUNCTION_REF && node->data.function_ref) { - free(node->data.function_ref); - } - - free(node); -} - -// Evaluate a node in the given context -node_t *evaluate_node(exec_context_t *ctx, node_t *node) { - fprintf(stderr, "DEBUG : evalute node type %d\n", node->type); - if (!node) - return NULL; - - switch (node->type) { - case NODE_STRING: - case NODE_NUMBER: - case NODE_BOOLEAN: - case NODE_FUNCTION_REF: - return copy_node(node); - - case NODE_SYMBOL: { - // Look up variable - for (int i = 0; i < ctx->local_vars.count; i++) { - if (strcmp(ctx->local_vars.names[i], node->data.symbol) == 0) { - return copy_node(ctx->local_vars.values[i]); - } - } - - node_t *var = find_variable(node->data.symbol); - if (var) { - return copy_node(var); - } - - fprintf(stderr, "Error: Undefined variable '%s'\n", node->data.symbol); - return NULL; - } - - case NODE_FUNCTION_CALL: - fprintf(stderr, "DEBUG: function call : %s\n", - node->data.call.function_name); - return execute_function_call_in_context(ctx, node); - - case NODE_LIST: { - // Execute all expressions in list and return last result - node_t *result = NULL; - fprintf(stderr, "DEBUG : child count %d\n", node->data.list.child_count); - for (int i = 0; i < node->data.list.child_count; i++) { - fprintf(stderr, "DEBUG : child number %d\n", i); - node_t *child = node->data.list.children[i]; - if (result) { - free_node(result); - } - // Evaluate child and handle function calls - if (child->type == NODE_FUNCTION_CALL) { - result = execute_function_call_in_context(ctx, child); - } else { - result = evaluate_node(ctx, child); - } - if (!result) { - fprintf(stderr, "Error evaluating list element %d\n", i); - return NULL; - } - } - return result; - } - - default: - fprintf(stderr, "Error: Cannot evaluate node type %d\n", node->type); - return NULL; - } -} diff --git a/src/parser.c b/src/parser.c index 8ffc376..20c5879 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,245 +1,41 @@ #include "../include/parser.h" #include "../include/lexer.h" -#include "../include/node.h" #include -#include -#include -node_t *parse_atom(lexer_t *lexer, token_t *token) { - // Variable - node_t *list = NULL; - size_t saved_pos = 0; - int saved_line = 0; - int saved_column = 0; - char saved_char = '\000'; +Value *parse_list(Lexer *lex) { - token_t peek; - token_t func_name; - token_t next; - token_t func_token; - - node_t *call = NULL; - node_t *arg = NULL; - node_t *element = NULL; - - // Code - switch (token->type) { - case TOKEN_SYMBOL: - return create_symbol_node(token->value); - - case TOKEN_STRING: - return create_string_node(token->value); - - case TOKEN_NUMBER: - return create_number_node(atof(token->value)); - - case TOKEN_BOOLEAN: - return create_boolean_node(strcmp(token->value, "true") == 0); - - case TOKEN_LPAREN: { - fprintf(stderr, "DEBUG : list parsing\n"); - list = create_list_node(); - - // Look ahead to see if this is a function call or just a list - saved_pos = lexer->pos; - saved_line = lexer->line; - saved_column = lexer->column; - saved_char = lexer->current_char; - - peek = next_token(lexer); - - // If first token is a comma, this is a function call - if (peek.type == TOKEN_COMMA) { - func_name = next_token(lexer); - - if (func_name.type == TOKEN_SYMBOL) { - call = create_function_call_node(func_name.value); - - // Parse arguments until closing paren - next = next_token(lexer); - while (next.type != TOKEN_RPAREN && next.type != TOKEN_EOF) { - arg = NULL; - - if (next.type == TOKEN_PERCENT) { - // Function reference argument - func_token = next_token(lexer); - if (func_token.type == TOKEN_SYMBOL) { - arg = create_function_ref_node(func_token.value); - } - } else { - // Parse the argument expression recursively - arg = parse_expression(lexer, &next); - } - - if (arg) { - add_arg_to_call(call, arg); - } - - next = next_token(lexer); - - // Skip commas between arguments - while (next.type == TOKEN_COMMA) { - next = next_token(lexer); - } - } - - return call; - } - } - - // Otherwise, parse as a regular list - // Restore lexer state - lexer->pos = saved_pos; - lexer->line = saved_line; - lexer->column = saved_column; - lexer->current_char = saved_char; - - // Parse elements in the list - while (1) { - // Skip whitespace and comments - skip_whitespace(lexer); - skip_comment(lexer); - skip_whitespace(lexer); - - // Check if we're at the end of the list - if (lexer->current_char == ')') { - // Consume the closing paren - lexer->pos++; - lexer->column++; - if (lexer->pos < strlen(lexer->input)) { - lexer->current_char = lexer->input[lexer->pos]; - } else { - lexer->current_char = '\0'; - } - break; - } - - if (lexer->current_char == '\0') { - break; - } - - // Parse the next element - element = parse_statement(lexer); - if (element) { - add_to_list(list, element); - } else { - // If we couldn't parse anything, advance one character to avoid - // infinite loop - lexer->pos++; - lexer->column++; - if (lexer->pos < strlen(lexer->input)) { - lexer->current_char = lexer->input[lexer->pos]; - } else { - lexer->current_char = '\0'; - } - } - } - - return list; + fprintf(stderr, "DEBUG : parsing list\n"); + Token tok = peek_token(lex); + if (tok.type == TOK_RPAREN) { + // Consume the closing paren + next_token(lex); + return make_nil(); } - case TOKEN_PERCENT: { - // Parse function reference: %function-name - next = next_token(lexer); - if (next.type == TOKEN_SYMBOL) { - return create_function_ref_node(next.value); - } - return NULL; - } + Value *car = parse_expr(lex); + fprintf(stderr, "DEBUG : head %s\n", car->data.symbol); + Value *cdr = parse_list(lex); + return make_list(car, cdr); +} - case TOKEN_COMMA: { - // Function call at top level: ,function-name - func_token = next_token(lexer); - if (func_token.type == TOKEN_SYMBOL) { - return create_function_call_node(func_token.value); - } - return NULL; - } +Value *parse_expr(Lexer *lex) { + fprintf(stderr, "DEBUG : Parsing new expression\n"); + Token tok = next_token(lex); + switch (tok.type) { + case TOK_NUMBER: + fprintf(stderr, "DEBUG : new number\n"); + return make_number(atof(tok.value)); + case TOK_STRING: + return make_string(tok.value); + case TOK_SYMBOL: + return make_symbol(tok.value); + case TOK_QUOTE: + return make_list(make_symbol("quote"), + make_list(parse_expr(lex), make_nil())); + case TOK_LPAREN: + return parse_list(lex); default: - return NULL; + return make_nil(); } } - -node_t *parse_expression(lexer_t *lexer, token_t *token) { - if (!token) { - token_t current = next_token(lexer); - return parse_expression(lexer, ¤t); - } - - // Check if this is a function call - if (token->type == TOKEN_COMMA) { - token_t func_token = next_token(lexer); - if (func_token.type == TOKEN_SYMBOL) { - return parse_function_call(lexer, func_token.value); - } - return NULL; - } - - // Otherwise parse as atom - return parse_atom(lexer, token); -} - -node_t *parse_function_call(lexer_t *lexer, const char *function_name) { - node_t *call = create_function_call_node(function_name); - if (!call) - return NULL; - - // Look for opening parenthesis (optional) - size_t saved_pos = lexer->pos; - int saved_line = lexer->line; - int saved_column = lexer->column; - char saved_char = lexer->current_char; - - token_t token = next_token(lexer); - - if (token.type != TOKEN_LPAREN) { - // No parentheses, restore position and return call with no args - lexer->pos = saved_pos; - lexer->line = saved_line; - lexer->column = saved_column; - lexer->current_char = saved_char; - return call; - } - - // Parse arguments - token = next_token(lexer); - while (token.type != TOKEN_RPAREN && token.type != TOKEN_EOF) { - node_t *arg = NULL; - - if (token.type == TOKEN_PERCENT) { - // Function reference argument - token_t func_token = next_token(lexer); - if (func_token.type == TOKEN_SYMBOL) { - arg = create_function_ref_node(func_token.value); - } - } else { - // Parse argument expression - arg = parse_expression(lexer, &token); - } - - if (arg) { - add_arg_to_call(call, arg); - } - - // Get next token - token = next_token(lexer); - - // Skip commas between arguments - while (token.type == TOKEN_COMMA) { - token = next_token(lexer); - } - } - - return call; -} - -node_t *parse_statement(lexer_t *lexer) { - skip_whitespace(lexer); - skip_comment(lexer); - skip_whitespace(lexer); - - token_t token = next_token(lexer); - - return parse_expression(lexer, &token); -} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..68a5321 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,82 @@ +#include "../include/utils.h" + +bool is_nil(Value *v) { return v->type == VAL_NIL; } + +bool is_symbol(Value *v, const char *sym) { + return v->type == VAL_SYMBOL && strcmp(v->data.symbol, sym) == 0; +} + +Value *car(Value *v) { + if (v->type == VAL_LIST) + return v->data.list.car; + return make_nil(); +} + +Value *cdr(Value *v) { + if (v->type == VAL_LIST) + return v->data.list.cdr; + return make_nil(); +} + +/** + * list_length(Value *v) + * + * @param v + * + * @return Length of the list of the argument value + */ +int list_length(Value *v) { + int len = 0; + while (v->type == VAL_LIST) { + len++; + v = v->data.list.cdr; + } + return len; +} + +void print_value(Value *v) { + switch (v->type) { + case VAL_NIL: + printf("nil"); + break; + case VAL_NUMBER: + if (v->data.number == (int)v->data.number) { + printf("%d", (int)v->data.number); + } else { + printf("%.2f", v->data.number); + } + break; + case VAL_STRING: + printf("\"%s\"", v->data.string); + break; + case VAL_SYMBOL: + printf("%s", v->data.symbol); + break; + case VAL_LIST: + printf("("); + Value *curr = v; + bool first = true; + while (curr->type == VAL_LIST) { + if (!first) + printf(" "); + print_value(curr->data.list.car); + curr = curr->data.list.cdr; + first = false; + } + if (curr->type != VAL_NIL) { + printf(" . "); + print_value(curr); + } + printf(")"); + break; + case VAL_FUNCTION: + printf(""); + break; + case VAL_BUILTIN: + printf(""); + break; + case VAL_KEYMAP: + printf("", v->data.keymap.count); + break; + } +}