diff --git a/include/config_tools.h b/include/config_tools.h index be87dba..be22c8a 100644 --- a/include/config_tools.h +++ b/include/config_tools.h @@ -5,30 +5,24 @@ #include "parser.h" #include -config_t *config_create(void); -void free_node(node_t *node); -void config_destroy(config_t *config); -int handle_map_key(config_t *config, node_t **args, int arg_count); -int handle_define(config_t *config, node_t **args, int arg_count); -int execute_function_call(config_t *config, node_t *call); -int config_parse_string(config_t *config, const char *input); -int config_parse_file(config_t *config, const char *filename); +void config_create(void); +void init_builtin_functions(void); -const char *config_get_key_mapping(config_t *config, const char *key_combo); -node_t *find_variable(config_t *config, const char *name); +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); -const char *config_get_string(config_t *config, const char *path, - const char *default_value); -int config_get_int(config_t *config, const char *path, int default_value); -double config_get_double(config_t *config, const char *path, - double default_value); -bool config_get_bool(config_t *config, const char *path, bool default_value); -void config_print_all(config_t *config); +int execute_function_call(node_t *call); +int config_parse_string(const char *input); +int config_parse_file(const char *filename); -static struct { - const char *name; - int (*handler)(config_t *config, node_t **args, int arg_count); -} builtin_functions[] = { - {"map-key", handle_map_key}, {"define", handle_define}, {NULL, NULL}}; +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 fccb8c4..8c8270e 100644 --- a/include/data.h +++ b/include/data.h @@ -1,12 +1,7 @@ #ifndef DATA_H_PARSER #define DATA_H_PARSER -#include "define.h" -#include #include -#include -#include -#include // Token types for lexical analysis @@ -26,7 +21,7 @@ typedef enum { typedef struct { token_type_t type; - char value[MAX_TOKEN_LENGTH]; + char *value; int line; int column; } token_t; @@ -37,23 +32,28 @@ typedef enum { NODE_STRING, NODE_NUMBER, NODE_BOOLEAN, - NODE_FUNCTION_REF, // %function-name - NODE_FUNCTION_CALL // ,function-name() + NODE_FUNCTION_REF, // %function-name + NODE_FUNCTION_CALL, // ,function-name() + NODE_LIST } node_type_t; typedef struct node { node_type_t type; union { - char symbol[MAX_SYMBOL_LENGTH]; - char string[MAX_STRING_LENGTH]; + char *symbol; + char *string; double number; bool boolean; - char function_ref[MAX_SYMBOL_LENGTH]; + char *function_ref; struct { - char function_name[MAX_SYMBOL_LENGTH]; - struct node *args[MAX_ARGS]; + char *function_name; + struct node **args; int arg_count; } call; + struct { + struct node **children; + int child_count; + } list; } data; } node_t; @@ -79,22 +79,73 @@ typedef struct config_var { struct config_var *next; } config_var_t; -typedef struct { +typedef struct config { key_mapping_t *key_mappings; config_var_t *variables; } config_t; +// Execution context for function calls +typedef struct exec_context { + struct { + char **names; + node_t **values; + int count; + } local_vars; +} exec_context_t; + +typedef void (*command_func_t)(void); + +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); -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_function_ref_node(const char *function_name); -node_t *create_function_call_node(const char *function_name); 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 config_t config; +#endif diff --git a/include/function.h b/include/function.h new file mode 100644 index 0000000..739f2f1 --- /dev/null +++ b/include/function.h @@ -0,0 +1,24 @@ +#ifndef FUNCTION_H_ +#define FUNCTION_H_ + +#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); + +int register_function(const char *name, command_func_t func); + +unified_function_t *find_unified_function(const char *name); + +node_t *execute_unified_function(exec_context_t *ctx, const char *name, + node_t **args, int arg_count); + +command_func_t find_function(const char *name); +int execute_command(const char *name); + +node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call); + +#endif diff --git a/include/lexer.h b/include/lexer.h index 081a23b..ba7a3ef 100644 --- a/include/lexer.h +++ b/include/lexer.h @@ -2,6 +2,8 @@ #define LEXER_H_ #include "data.h" +#include +#include token_t next_token(lexer_t *lexer); diff --git a/include/node.h b/include/node.h new file mode 100644 index 0000000..68027fd --- /dev/null +++ b/include/node.h @@ -0,0 +1,20 @@ +#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 6029a10..d6dce27 100644 --- a/include/parser.h +++ b/include/parser.h @@ -2,10 +2,10 @@ #define PARSER_H_ #include "data.h" -#include "lexer.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); #endif diff --git a/init.bl b/init.bl index 741a275..6f20209 100644 --- a/init.bl +++ b/init.bl @@ -8,5 +8,10 @@ ,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 index acf8bdd..365f9bf 100644 --- a/main.c +++ b/main.c @@ -1,38 +1,34 @@ -#include "src/data.h" -#include "src/config_tools.h" +#define GLOBAL_EDITOR -int main() { +#include "include/config_tools.h" +#include "include/data.h" + +int main(void) { // Parse the configuration - config_t *config = config_create(); + config_create(); char *config_file = "init.bl"; - if (!config) { - fprintf(stderr, "Error: Failed to create config structure\n"); - return 1; - } - if (config_parse_file(config, config_file) != 0) { + if (config_parse_file(config_file) != 0) { fprintf(stderr, "Error: Failed to parse config file\n"); - config_destroy(config); return 1; } printf("Successfully parsed Lisp config file: %s\n\n", config_file); // Print all entries - config_print_all(config); + config_print_all(); printf("\n"); // Demonstrate usage printf("Example usage:\n"); - printf("CTRL-s maps to: %s\n", config_get_key_mapping(config, "CTRL-s")); - printf("CTRL-f o maps to: %s\n", config_get_key_mapping(config, "CTRL-f o")); - printf("Window width: %d\n", config_get_int(config, "window-width", 1024)); - printf("Theme: %s\n", config_get_string(config, "theme", "light")); + 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(config, "auto-save", false) ? "enabled" : "disabled"); - printf("Font size: %d\n", config_get_int(config, "font-size", 12)); + config_get_bool("auto-save", false) ? "enabled" : "disabled"); + printf("Font size: %d\n", config_get_int("font-size", 12)); - config_destroy(config); return 0; } diff --git a/src/config_tools.c b/src/config_tools.c index 1098633..baedad0 100644 --- a/src/config_tools.c +++ b/src/config_tools.c @@ -1,62 +1,29 @@ + #include "../include/config_tools.h" +#include "../include/function.h" +#include "../include/node.h" +#define GLOBAL_CONFIG #include "../include/data.h" #include +#include +#include -config_t *config_create(void) { +void config_create(void) { /* * @brief Initialize config structure */ - config_t *config = malloc(sizeof(config_t)); - if (config) { - config->key_mappings = NULL; - config->variables = NULL; - } - return config; + config.key_mappings = NULL; + config.variables = NULL; } -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); - } - - free(node); -} - -void config_destroy(config_t *config) { - if (!config) - return; - - key_mapping_t *mapping = config->key_mappings; - while (mapping) { - key_mapping_t *next = mapping->next; - free(mapping->key_combo); - free(mapping->function_name); - free(mapping); - mapping = next; - } - - // Free variables - config_var_t *var = config->variables; - while (var) { - config_var_t *next = var->next; - free(var->name); - free_node(var->value); - free(var); - var = next; - } - - free(config); +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(config_t *config, node_t **args, int arg_count) { +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"); @@ -69,48 +36,134 @@ int handle_map_key(config_t *config, node_t **args, int arg_count) { 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; + mapping->next = config.key_mappings; + config.key_mappings = mapping; return 0; } -int handle_define(config_t *config, node_t **args, int arg_count) { - if (arg_count != 2 || args[0]->type != NODE_SYMBOL) { - fprintf(stderr, "Error: define requires (variable_name, value)\n"); +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) + if (!var) { + fprintf(stderr, "Error: Failed to allocate memory for variable\n"); return -1; + } var->name = strdup(args[0]->data.symbol); - var->value = args[1]; // Transfer ownership - var->next = config->variables; - config->variables = var; + 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 execute_function_call(config_t *config, node_t *call) { - if (call->type != NODE_FUNCTION_CALL) +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; + } - // Look for built-in function - for (int i = 0; builtin_functions[i].name; i++) { - if (strcmp(call->data.call.function_name, builtin_functions[i].name) == 0) { - return builtin_functions[i].handler(config, call->data.call.args, - call->data.call.arg_count); + 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); } } - fprintf(stderr, "Error: Unknown function '%s'\n", - call->data.call.function_name); + // 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(config_t *config, const char *input) { +int config_parse_string(const char *input) { lexer_t lexer = {0}; lexer.input = input; lexer.pos = 0; @@ -119,7 +172,6 @@ int config_parse_string(config_t *config, const char *input) { lexer.current_char = input[0]; while (lexer.current_char != '\0') { - printf("%c", lexer.current_char); skip_whitespace(&lexer); skip_comment(&lexer); skip_whitespace(&lexer); @@ -133,12 +185,13 @@ int config_parse_string(config_t *config, const char *input) { node_t *stmt = parse_statement(&lexer); if (stmt) { - if (execute_function_call(config, stmt) != 0) { + 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) { - free_node(stmt); // Don't free if ownership was transferred to define + (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 } } @@ -151,7 +204,7 @@ int config_parse_string(config_t *config, const char *input) { return 0; } -int config_parse_file(config_t *config, const char *filename) { +int config_parse_file(const char *filename) { FILE *file = fopen(filename, "r"); long file_size = 0; char *content = NULL; @@ -175,7 +228,7 @@ int config_parse_file(config_t *config, const char *filename) { content[file_size] = '\0'; fclose(file); - result = config_parse_string(config, content); + result = config_parse_string(content); free(content); return result; @@ -183,8 +236,8 @@ int config_parse_file(config_t *config, const char *filename) { // Getter functions -const char *config_get_key_mapping(config_t *config, const char *key_combo) { - key_mapping_t *mapping = config->key_mappings; +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; @@ -194,8 +247,8 @@ const char *config_get_key_mapping(config_t *config, const char *key_combo) { return NULL; } -node_t *find_variable(config_t *config, const char *name) { - config_var_t *var = config->variables; +node_t *find_variable(const char *name) { + config_var_t *var = config.variables; while (var) { if (strcmp(var->name, name) == 0) { return var->value; @@ -205,58 +258,56 @@ node_t *find_variable(config_t *config, const char *name) { return NULL; } -const char *config_get_string(config_t *config, const char *path, - const char *default_value) { - node_t *node = find_variable(config, path); +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(config_t *config, const char *path, int default_value) { - node_t *node = find_variable(config, path); +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(config_t *config, const char *path, - double default_value) { - node_t *node = find_variable(config, path); +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(config_t *config, const char *path, bool default_value) { - node_t *node = find_variable(config, path); +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(config_t *config) { +void config_print_all(void) { printf("Key Mappings:\n"); - printf("%-20s -> %s\n", "Key Combination", "Function"); - printf("%-20s %s\n", "---------------", "--------"); + printf("%-20s -> %s\n", "Key Combination", "Function\n"); + printf("%-20s %s\n", "---------------", "--------\n"); - key_mapping_t *mapping = config->key_mappings; + 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"); - printf("%-20s %s\n", "----", "-----"); + printf("%-20s = %s\n", "Name", "Value\n"); + printf("%-20s %s\n", "----", "-----\n"); - config_var_t *var = config->variables; + config_var_t *var = config.variables; while (var) { - printf("%-20s = ", var->name); + printf("%-20s = \n", var->name); switch (var->value->type) { case NODE_STRING: diff --git a/src/data.c b/src/data.c index 3e32e3a..5814076 100644 --- a/src/data.c +++ b/src/data.c @@ -1,5 +1,8 @@ #include "../include/data.h" #include "../include/define.h" +#include +#include +#include #include void advance_char(lexer_t *lexer) { @@ -27,74 +30,63 @@ void skip_comment(lexer_t *lexer) { } } -// Node creation functions -node_t *create_node(node_type_t type) { +node_t *create_list_node(void) { node_t *node = malloc(sizeof(node_t)); - if (!node) + 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) { - 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) { - strncpy(node->data.string, string, MAX_STRING_LENGTH - 1); - node->data.string[MAX_STRING_LENGTH - 1] = '\0'; - } - return node; -} + node->type = NODE_LIST; + node->data.list.child_count = 0; + node->data.list.children = NULL; -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) { - 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) { - 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; } 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; } } + +void add_to_list(node_t *list, node_t *element) { + node_t **new_children = NULL; + if (!list || !element) { + return; + } + + // Ensure this is actually a list node + if (list->type != NODE_LIST) { + return; + } + + // If this is the first element + if (list->data.list.children == NULL) { + + 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 + } + 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 + } + + 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); +} diff --git a/src/function.c b/src/function.c new file mode 100644 index 0000000..e57eac7 --- /dev/null +++ b/src/function.c @@ -0,0 +1,215 @@ +#include "../include/function.h" +#include "../include/data.h" +#include "../include/node.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; + + 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; + } + func = func->next; + } + return NULL; +} + +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; + } + + switch (func->type) { + case FUNC_BUILTIN: { + node_t **eval_args = args; + + // Evaluate arguments if needed + if (func->data.builtin.eval_args) { + eval_args = malloc(sizeof(node_t *) * arg_count); + if (!eval_args) + return NULL; + + 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]); + } + free(eval_args); + return NULL; + } + } + } + + int result = func->data.builtin.handler(eval_args, arg_count); + + // 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); + } + + return create_boolean_node(result == 0); + } + + 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]); + } + free(new_ctx.local_vars.names); + free(new_ctx.local_vars.values); + return NULL; + } + } + } + + 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); + } + + default: + fprintf(stderr, "Error: Unknown function type for '%s'\n", name); + return NULL; + } +} + +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; + } + + 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; + } + } + + return -1; +} + +// Execute function call with context support +node_t *execute_function_call_in_context(exec_context_t *ctx, node_t *call) { + + if (call->type != NODE_FUNCTION_CALL) { + return NULL; + } + 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); +} diff --git a/src/lexer.c b/src/lexer.c index 2783676..df5e5f1 100644 --- a/src/lexer.c +++ b/src/lexer.c @@ -1,5 +1,9 @@ #include "../include/lexer.h" +#include "../include/define.h" +#include #include +#include +#include token_t next_token(lexer_t *lexer) { token_t token = {0}; @@ -25,15 +29,18 @@ token_t next_token(lexer_t *lexer) { // 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); @@ -43,16 +50,20 @@ token_t next_token(lexer_t *lexer) { // 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; } @@ -63,8 +74,8 @@ token_t next_token(lexer_t *lexer) { advance_char(lexer); // Skip opening quote int i = 0; - while (lexer->current_char != '"' && lexer->current_char != '\0' && - i < MAX_TOKEN_LENGTH - 1) { + 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) { @@ -107,8 +118,8 @@ token_t next_token(lexer_t *lexer) { int i = 0; while ( - (isalnum(lexer->current_char) || strchr("-+._", lexer->current_char)) && - i < MAX_TOKEN_LENGTH - 1) { + (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); } @@ -127,6 +138,7 @@ token_t next_token(lexer_t *lexer) { token.type = TOKEN_NUMBER; } else { token.type = TOKEN_SYMBOL; + fprintf(stderr, "DEBUG : next token = %s\n", token.value); } } return token; @@ -134,7 +146,7 @@ token_t next_token(lexer_t *lexer) { // Error case token.type = TOKEN_ERROR; - snprintf(token.value, MAX_TOKEN_LENGTH, "Unexpected character '%c'", + snprintf(token.value, MAX_TOKEN_LENGTH - 1, "Unexpected character '%c'", lexer->current_char); return token; } diff --git a/src/node.c b/src/node.c new file mode 100644 index 0000000..ddf5e09 --- /dev/null +++ b/src/node.c @@ -0,0 +1,223 @@ +#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 ebf9557..8ffc376 100644 --- a/src/parser.c +++ b/src/parser.c @@ -1,6 +1,28 @@ #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'; + + 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); @@ -14,29 +36,169 @@ node_t *parse_atom(lexer_t *lexer, token_t *token) { 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; + } + case TOKEN_PERCENT: { // Parse function reference: %function-name - token_t next = next_token(lexer); + next = next_token(lexer); if (next.type == TOKEN_SYMBOL) { return create_function_ref_node(next.value); } return NULL; } + 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; + } + default: return NULL; } } +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) { - // Function call without parentheses - no arguments - printf("no paren\n"); + // 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; } @@ -52,15 +214,21 @@ node_t *parse_function_call(lexer_t *lexer, const char *function_name) { arg = create_function_ref_node(func_token.value); } } else { - // Regular argument - arg = parse_atom(lexer, &token); + // 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; @@ -73,13 +241,5 @@ node_t *parse_statement(lexer_t *lexer) { token_t token = next_token(lexer); - if (token.type == TOKEN_COMMA) { - // Function call: ,function-name(args) - token_t func_token = next_token(lexer); - if (func_token.type == TOKEN_SYMBOL) { - return parse_function_call(lexer, func_token.value); - } - } - - return NULL; + return parse_expression(lexer, &token); }