This commit is contained in:
Arthur Barraux
2025-06-12 17:00:19 +02:00
parent 04464ec2e7
commit 5818a8ecfc
14 changed files with 977 additions and 232 deletions
+16 -22
View File
@@ -5,30 +5,24 @@
#include "parser.h" #include "parser.h"
#include <stdio.h> #include <stdio.h>
config_t *config_create(void); void config_create(void);
void free_node(node_t *node); void init_builtin_functions(void);
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);
const char *config_get_key_mapping(config_t *config, const char *key_combo); int handle_map_key(node_t **args, int arg_count);
node_t *find_variable(config_t *config, const char *name); 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, int execute_function_call(node_t *call);
const char *default_value); int config_parse_string(const char *input);
int config_get_int(config_t *config, const char *path, int default_value); int config_parse_file(const char *filename);
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);
static struct { const char *config_get_key_mapping(const char *key_combo);
const char *name; node_t *find_variable(const char *name);
int (*handler)(config_t *config, node_t **args, int arg_count);
} builtin_functions[] = { const char *config_get_string(const char *path, const char *default_value);
{"map-key", handle_map_key}, {"define", handle_define}, {NULL, NULL}}; 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 #endif
+71 -20
View File
@@ -1,12 +1,7 @@
#ifndef DATA_H_PARSER #ifndef DATA_H_PARSER
#define DATA_H_PARSER #define DATA_H_PARSER
#include "define.h"
#include <ctype.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Token types for lexical analysis // Token types for lexical analysis
@@ -26,7 +21,7 @@ typedef enum {
typedef struct { typedef struct {
token_type_t type; token_type_t type;
char value[MAX_TOKEN_LENGTH]; char *value;
int line; int line;
int column; int column;
} token_t; } token_t;
@@ -38,22 +33,27 @@ typedef enum {
NODE_NUMBER, NODE_NUMBER,
NODE_BOOLEAN, NODE_BOOLEAN,
NODE_FUNCTION_REF, // %function-name NODE_FUNCTION_REF, // %function-name
NODE_FUNCTION_CALL // ,function-name() NODE_FUNCTION_CALL, // ,function-name()
NODE_LIST
} node_type_t; } node_type_t;
typedef struct node { typedef struct node {
node_type_t type; node_type_t type;
union { union {
char symbol[MAX_SYMBOL_LENGTH]; char *symbol;
char string[MAX_STRING_LENGTH]; char *string;
double number; double number;
bool boolean; bool boolean;
char function_ref[MAX_SYMBOL_LENGTH]; char *function_ref;
struct { struct {
char function_name[MAX_SYMBOL_LENGTH]; char *function_name;
struct node *args[MAX_ARGS]; struct node **args;
int arg_count; int arg_count;
} call; } call;
struct {
struct node **children;
int child_count;
} list;
} data; } data;
} node_t; } node_t;
@@ -79,22 +79,73 @@ typedef struct config_var {
struct config_var *next; struct config_var *next;
} config_var_t; } config_var_t;
typedef struct { typedef struct config {
key_mapping_t *key_mappings; key_mapping_t *key_mappings;
config_var_t *variables; config_var_t *variables;
} config_t; } 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 advance_char(lexer_t *lexer);
void skip_whitespace(lexer_t *lexer); void skip_whitespace(lexer_t *lexer);
void skip_comment(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_arg_to_call(node_t *call, node_t *args);
void add_to_list(node_t *node, node_t *element);
#endif #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
+24
View File
@@ -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
+2
View File
@@ -2,6 +2,8 @@
#define LEXER_H_ #define LEXER_H_
#include "data.h" #include "data.h"
#include <ctype.h>
#include <string.h>
token_t next_token(lexer_t *lexer); token_t next_token(lexer_t *lexer);
+20
View File
@@ -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
+1 -1
View File
@@ -2,10 +2,10 @@
#define PARSER_H_ #define PARSER_H_
#include "data.h" #include "data.h"
#include "lexer.h"
node_t *parse_atom(lexer_t *lexer, token_t *token); 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_function_call(lexer_t *lexer, const char *function_name);
node_t *parse_statement(lexer_t *lexer); node_t *parse_statement(lexer_t *lexer);
node_t *parse_expression(lexer_t *lexer, token_t *token);
#endif #endif
+5
View File
@@ -8,5 +8,10 @@
,map-key("CTRL-w s h" %window-split-horizontal) ,map-key("CTRL-w s h" %window-split-horizontal)
,map-key("CTRL-w s v" %window-split-vertical) ,map-key("CTRL-w s v" %window-split-vertical)
,fun(saveQuit () (
,editorSave
,editorQuit
))
,define(theme "dark") ,define(theme "dark")
,define(auto-save true) ,define(auto-save true)
+14 -18
View File
@@ -1,38 +1,34 @@
#include "src/data.h" #define GLOBAL_EDITOR
#include "src/config_tools.h"
int main() { #include "include/config_tools.h"
#include "include/data.h"
int main(void) {
// Parse the configuration // Parse the configuration
config_t *config = config_create(); config_create();
char *config_file = "init.bl"; 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"); fprintf(stderr, "Error: Failed to parse config file\n");
config_destroy(config);
return 1; return 1;
} }
printf("Successfully parsed Lisp config file: %s\n\n", config_file); printf("Successfully parsed Lisp config file: %s\n\n", config_file);
// Print all entries // Print all entries
config_print_all(config); config_print_all();
printf("\n"); printf("\n");
// Demonstrate usage // Demonstrate usage
printf("Example usage:\n"); printf("Example usage:\n");
printf("CTRL-s maps to: %s\n", config_get_key_mapping(config, "CTRL-s")); 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(config, "CTRL-f o")); printf("CTRL-f o maps to: %s\n", config_get_key_mapping("CTRL-f o"));
printf("Window width: %d\n", config_get_int(config, "window-width", 1024)); printf("Window width: %d\n", config_get_int("window-width", 1024));
printf("Theme: %s\n", config_get_string(config, "theme", "light")); printf("Theme: %s\n", config_get_string("theme", "light"));
printf("Auto-save: %s\n", printf("Auto-save: %s\n",
config_get_bool(config, "auto-save", false) ? "enabled" : "disabled"); config_get_bool("auto-save", false) ? "enabled" : "disabled");
printf("Font size: %d\n", config_get_int(config, "font-size", 12)); printf("Font size: %d\n", config_get_int("font-size", 12));
config_destroy(config);
return 0; return 0;
} }
+150 -99
View File
@@ -1,62 +1,29 @@
#include "../include/config_tools.h" #include "../include/config_tools.h"
#include "../include/function.h"
#include "../include/node.h"
#define GLOBAL_CONFIG
#include "../include/data.h" #include "../include/data.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
config_t *config_create(void) { void config_create(void) {
/* /*
* @brief Initialize config structure * @brief Initialize config structure
*/ */
config_t *config = malloc(sizeof(config_t)); config.key_mappings = NULL;
if (config) { config.variables = NULL;
config->key_mappings = NULL;
config->variables = NULL;
}
return config;
} }
void free_node(node_t *node) { void init_builtin_functions(void) {
int i; register_builtin_function("map-key", handle_map_key, true);
if (!node) register_builtin_function("define", handle_define, false); // Don't eval args
return; register_builtin_function("func", handle_function, false); // Don't eval args
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);
} }
// Built-in function handlers // 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 || if (arg_count != 2 || args[0]->type != NODE_STRING ||
args[1]->type != NODE_FUNCTION_REF) { args[1]->type != NODE_FUNCTION_REF) {
fprintf(stderr, "Error: map-key requires (key_combo, function_ref)\n"); 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->key_combo = strdup(args[0]->data.string);
mapping->function_name = strdup(args[1]->data.function_ref); mapping->function_name = strdup(args[1]->data.function_ref);
mapping->next = config->key_mappings; mapping->next = config.key_mappings;
config->key_mappings = mapping; config.key_mappings = mapping;
return 0; return 0;
} }
int handle_define(config_t *config, node_t **args, int arg_count) { int handle_define(node_t **args, int arg_count) {
if (arg_count != 2 || args[0]->type != NODE_SYMBOL) {
fprintf(stderr, "Error: define requires (variable_name, value)\n"); 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; return -1;
} }
config_var_t *var = malloc(sizeof(config_var_t)); 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; return -1;
}
var->name = strdup(args[0]->data.symbol); var->name = strdup(args[0]->data.symbol);
var->value = args[1]; // Transfer ownership if (!var->name) {
var->next = config->variables; free(var);
config->variables = 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; return 0;
} }
int execute_function_call(config_t *config, node_t *call) { int handle_function(node_t **args, int arg_count) {
if (call->type != NODE_FUNCTION_CALL) if (arg_count != 3) {
return -1; fprintf(stderr, "Error: func requires exactly 3 arguments, got %d\n",
arg_count);
// 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);
}
}
fprintf(stderr, "Error: Unknown function '%s'\n",
call->data.call.function_name);
return -1; return -1;
} }
int config_parse_string(config_t *config, const char *input) { 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_t lexer = {0};
lexer.input = input; lexer.input = input;
lexer.pos = 0; lexer.pos = 0;
@@ -119,7 +172,6 @@ int config_parse_string(config_t *config, const char *input) {
lexer.current_char = input[0]; lexer.current_char = input[0];
while (lexer.current_char != '\0') { while (lexer.current_char != '\0') {
printf("%c", lexer.current_char);
skip_whitespace(&lexer); skip_whitespace(&lexer);
skip_comment(&lexer); skip_comment(&lexer);
skip_whitespace(&lexer); skip_whitespace(&lexer);
@@ -133,12 +185,13 @@ int config_parse_string(config_t *config, const char *input) {
node_t *stmt = parse_statement(&lexer); node_t *stmt = parse_statement(&lexer);
if (stmt) { 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); fprintf(stderr, "Error executing statement at line %d\n", lexer.line);
} }
if (stmt->type != NODE_FUNCTION_CALL || if (stmt->type != NODE_FUNCTION_CALL ||
strcmp(stmt->data.call.function_name, "define") != 0) { (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, "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; return 0;
} }
int config_parse_file(config_t *config, const char *filename) { int config_parse_file(const char *filename) {
FILE *file = fopen(filename, "r"); FILE *file = fopen(filename, "r");
long file_size = 0; long file_size = 0;
char *content = NULL; char *content = NULL;
@@ -175,7 +228,7 @@ int config_parse_file(config_t *config, const char *filename) {
content[file_size] = '\0'; content[file_size] = '\0';
fclose(file); fclose(file);
result = config_parse_string(config, content); result = config_parse_string(content);
free(content); free(content);
return result; return result;
@@ -183,8 +236,8 @@ int config_parse_file(config_t *config, const char *filename) {
// Getter functions // Getter functions
const char *config_get_key_mapping(config_t *config, const char *key_combo) { const char *config_get_key_mapping(const char *key_combo) {
key_mapping_t *mapping = config->key_mappings; key_mapping_t *mapping = config.key_mappings;
while (mapping) { while (mapping) {
if (strcmp(mapping->key_combo, key_combo) == 0) { if (strcmp(mapping->key_combo, key_combo) == 0) {
return mapping->function_name; return mapping->function_name;
@@ -194,8 +247,8 @@ const char *config_get_key_mapping(config_t *config, const char *key_combo) {
return NULL; return NULL;
} }
node_t *find_variable(config_t *config, const char *name) { node_t *find_variable(const char *name) {
config_var_t *var = config->variables; config_var_t *var = config.variables;
while (var) { while (var) {
if (strcmp(var->name, name) == 0) { if (strcmp(var->name, name) == 0) {
return var->value; return var->value;
@@ -205,58 +258,56 @@ node_t *find_variable(config_t *config, const char *name) {
return NULL; return NULL;
} }
const char *config_get_string(config_t *config, const char *path, const char *config_get_string(const char *path, const char *default_value) {
const char *default_value) { node_t *node = find_variable(path);
node_t *node = find_variable(config, path);
if (node && node->type == NODE_STRING) { if (node && node->type == NODE_STRING) {
return node->data.string; return node->data.string;
} }
return default_value; return default_value;
} }
int config_get_int(config_t *config, const char *path, int default_value) { int config_get_int(const char *path, int default_value) {
node_t *node = find_variable(config, path); node_t *node = find_variable(path);
if (node && node->type == NODE_NUMBER) { if (node && node->type == NODE_NUMBER) {
return (int)node->data.number; return (int)node->data.number;
} }
return default_value; return default_value;
} }
double config_get_double(config_t *config, const char *path, double config_get_double(const char *path, double default_value) {
double default_value) { node_t *node = find_variable(path);
node_t *node = find_variable(config, path);
if (node && node->type == NODE_NUMBER) { if (node && node->type == NODE_NUMBER) {
return node->data.number; return node->data.number;
} }
return default_value; return default_value;
} }
bool config_get_bool(config_t *config, const char *path, bool default_value) { bool config_get_bool(const char *path, bool default_value) {
node_t *node = find_variable(config, path); node_t *node = find_variable(path);
if (node && node->type == NODE_BOOLEAN) { if (node && node->type == NODE_BOOLEAN) {
return node->data.boolean; return node->data.boolean;
} }
return default_value; return default_value;
} }
void config_print_all(config_t *config) { void config_print_all(void) {
printf("Key Mappings:\n"); printf("Key Mappings:\n");
printf("%-20s -> %s\n", "Key Combination", "Function"); printf("%-20s -> %s\n", "Key Combination", "Function\n");
printf("%-20s %s\n", "---------------", "--------"); printf("%-20s %s\n", "---------------", "--------\n");
key_mapping_t *mapping = config->key_mappings; key_mapping_t *mapping = config.key_mappings;
while (mapping) { while (mapping) {
printf("%-20s -> %s\n", mapping->key_combo, mapping->function_name); printf("%-20s -> %s\n", mapping->key_combo, mapping->function_name);
mapping = mapping->next; mapping = mapping->next;
} }
printf("\nVariables:\n"); printf("\nVariables:\n");
printf("%-20s = %s\n", "Name", "Value"); printf("%-20s = %s\n", "Name", "Value\n");
printf("%-20s %s\n", "----", "-----"); printf("%-20s %s\n", "----", "-----\n");
config_var_t *var = config->variables; config_var_t *var = config.variables;
while (var) { while (var) {
printf("%-20s = ", var->name); printf("%-20s = \n", var->name);
switch (var->value->type) { switch (var->value->type) {
case NODE_STRING: case NODE_STRING:
+49 -57
View File
@@ -1,5 +1,8 @@
#include "../include/data.h" #include "../include/data.h"
#include "../include/define.h" #include "../include/define.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
void advance_char(lexer_t *lexer) { void advance_char(lexer_t *lexer) {
@@ -27,74 +30,63 @@ void skip_comment(lexer_t *lexer) {
} }
} }
// Node creation functions node_t *create_list_node(void) {
node_t *create_node(node_type_t type) {
node_t *node = malloc(sizeof(node_t)); node_t *node = malloc(sizeof(node_t));
if (!node) if (!node) {
return NULL; return NULL;
memset(node, 0, sizeof(node_t));
node->type = type;
return node;
} }
node_t *create_symbol_node(const char *symbol) { node->type = NODE_LIST;
node_t *node = create_node(NODE_SYMBOL); node->data.list.child_count = 0;
if (node) { node->data.list.children = NULL;
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_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; return node;
} }
void add_arg_to_call(node_t *call, node_t *arg) { void add_arg_to_call(node_t *call, node_t *arg) {
if (call->type == NODE_FUNCTION_CALL && if (call->type == NODE_FUNCTION_CALL &&
call->data.call.arg_count < MAX_ARGS) { 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; 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);
}
+215
View File
@@ -0,0 +1,215 @@
#include "../include/function.h"
#include "../include/data.h"
#include "../include/node.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
}
+17 -5
View File
@@ -1,5 +1,9 @@
#include "../include/lexer.h" #include "../include/lexer.h"
#include "../include/define.h"
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <sys/ucontext.h>
token_t next_token(lexer_t *lexer) { token_t next_token(lexer_t *lexer) {
token_t token = {0}; token_t token = {0};
@@ -25,15 +29,18 @@ token_t next_token(lexer_t *lexer) {
// Comma (function call indicator) // Comma (function call indicator)
if (lexer->current_char == ',') { if (lexer->current_char == ',') {
token.type = TOKEN_COMMA; token.type = TOKEN_COMMA;
token.value = (char *)malloc(2 * sizeof(char));
token.value[0] = ','; token.value[0] = ',';
token.value[1] = '\0'; token.value[1] = '\0';
advance_char(lexer); advance_char(lexer);
fprintf(stderr, "DEBUG : next token = ,\n");
return token; return token;
} }
// Percent (function reference indicator) // Percent (function reference indicator)
if (lexer->current_char == '%') { if (lexer->current_char == '%') {
token.type = TOKEN_PERCENT; token.type = TOKEN_PERCENT;
token.value = (char *)malloc(2 * sizeof(char));
token.value[0] = '%'; token.value[0] = '%';
token.value[1] = '\0'; token.value[1] = '\0';
advance_char(lexer); advance_char(lexer);
@@ -43,16 +50,20 @@ token_t next_token(lexer_t *lexer) {
// Parentheses // Parentheses
if (lexer->current_char == '(') { if (lexer->current_char == '(') {
token.type = TOKEN_LPAREN; token.type = TOKEN_LPAREN;
token.value = (char *)malloc(2 * sizeof(char));
token.value[0] = '('; token.value[0] = '(';
token.value[1] = '\0'; token.value[1] = '\0';
advance_char(lexer); advance_char(lexer);
fprintf(stderr, "DEBUG : next token = (\n");
return token; return token;
} }
if (lexer->current_char == ')') { if (lexer->current_char == ')') {
token.type = TOKEN_RPAREN; token.type = TOKEN_RPAREN;
token.value = (char *)malloc(2 * sizeof(char));
token.value[0] = ')'; token.value[0] = ')';
token.value[1] = '\0'; token.value[1] = '\0';
fprintf(stderr, "DEBUG : next token = )\n");
advance_char(lexer); advance_char(lexer);
return token; return token;
} }
@@ -63,8 +74,8 @@ token_t next_token(lexer_t *lexer) {
advance_char(lexer); // Skip opening quote advance_char(lexer); // Skip opening quote
int i = 0; int i = 0;
while (lexer->current_char != '"' && lexer->current_char != '\0' && while (lexer->current_char != '"' && lexer->current_char != '\0') {
i < MAX_TOKEN_LENGTH - 1) { token.value = (char *)realloc(token.value, (i + 1) * sizeof(char));
if (lexer->current_char == '\\' && lexer->input[lexer->pos + 1] != '\0') { if (lexer->current_char == '\\' && lexer->input[lexer->pos + 1] != '\0') {
advance_char(lexer); advance_char(lexer);
switch (lexer->current_char) { switch (lexer->current_char) {
@@ -107,8 +118,8 @@ token_t next_token(lexer_t *lexer) {
int i = 0; int i = 0;
while ( while (
(isalnum(lexer->current_char) || strchr("-+._", lexer->current_char)) && (isalnum(lexer->current_char) || strchr("-+._", lexer->current_char))) {
i < MAX_TOKEN_LENGTH - 1) { token.value = (char *)realloc(token.value, (i + 1) * sizeof(char));
token.value[i++] = lexer->current_char; token.value[i++] = lexer->current_char;
advance_char(lexer); advance_char(lexer);
} }
@@ -127,6 +138,7 @@ token_t next_token(lexer_t *lexer) {
token.type = TOKEN_NUMBER; token.type = TOKEN_NUMBER;
} else { } else {
token.type = TOKEN_SYMBOL; token.type = TOKEN_SYMBOL;
fprintf(stderr, "DEBUG : next token = %s\n", token.value);
} }
} }
return token; return token;
@@ -134,7 +146,7 @@ token_t next_token(lexer_t *lexer) {
// Error case // Error case
token.type = TOKEN_ERROR; 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); lexer->current_char);
return token; return token;
} }
+223
View File
@@ -0,0 +1,223 @@
#include "../include/node.h"
#include "../include/config_tools.h"
#include "../include/define.h"
#include "../include/function.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ucontext.h>
// 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;
}
}
+174 -14
View File
@@ -1,6 +1,28 @@
#include "../include/parser.h" #include "../include/parser.h"
#include "../include/lexer.h"
#include "../include/node.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
node_t *parse_atom(lexer_t *lexer, token_t *token) { 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) { switch (token->type) {
case TOKEN_SYMBOL: case TOKEN_SYMBOL:
return create_symbol_node(token->value); return create_symbol_node(token->value);
@@ -14,29 +36,169 @@ node_t *parse_atom(lexer_t *lexer, token_t *token) {
case TOKEN_BOOLEAN: case TOKEN_BOOLEAN:
return create_boolean_node(strcmp(token->value, "true") == 0); 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: { case TOKEN_PERCENT: {
// Parse function reference: %function-name // Parse function reference: %function-name
token_t next = next_token(lexer); next = next_token(lexer);
if (next.type == TOKEN_SYMBOL) { if (next.type == TOKEN_SYMBOL) {
return create_function_ref_node(next.value); return create_function_ref_node(next.value);
} }
return NULL; 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: default:
return NULL; return NULL;
} }
} }
node_t *parse_expression(lexer_t *lexer, token_t *token) {
if (!token) {
token_t current = next_token(lexer);
return parse_expression(lexer, &current);
}
// 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 *parse_function_call(lexer_t *lexer, const char *function_name) {
node_t *call = create_function_call_node(function_name); node_t *call = create_function_call_node(function_name);
if (!call) if (!call)
return NULL; 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); token_t token = next_token(lexer);
if (token.type != TOKEN_LPAREN) { if (token.type != TOKEN_LPAREN) {
// Function call without parentheses - no arguments // No parentheses, restore position and return call with no args
printf("no paren\n"); lexer->pos = saved_pos;
lexer->line = saved_line;
lexer->column = saved_column;
lexer->current_char = saved_char;
return call; 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); arg = create_function_ref_node(func_token.value);
} }
} else { } else {
// Regular argument // Parse argument expression
arg = parse_atom(lexer, &token); arg = parse_expression(lexer, &token);
} }
if (arg) { if (arg) {
add_arg_to_call(call, arg); add_arg_to_call(call, arg);
} }
// Get next token
token = next_token(lexer); token = next_token(lexer);
// Skip commas between arguments
while (token.type == TOKEN_COMMA) {
token = next_token(lexer);
}
} }
return call; return call;
@@ -73,13 +241,5 @@ node_t *parse_statement(lexer_t *lexer) {
token_t token = next_token(lexer); token_t token = next_token(lexer);
if (token.type == TOKEN_COMMA) { return parse_expression(lexer, &token);
// 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;
} }