Skip to content

Commit 8131114

Browse files
Added support for predefined function calls
1 parent cd5c65e commit 8131114

4 files changed

Lines changed: 288 additions & 11 deletions

File tree

project/main.galo

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
struct Color
2+
r byte
3+
g byte
4+
b byte
5+
end
6+
let c Color
7+
c r = 0
8+
c g = 0
9+
c b = 0
10+
let i int = 0
11+
while (i < 100)
12+
i = (i + 1)
13+
c r = i
14+
print(c, "!\n")
15+
end
16+
17+
~
118
struct P_empty
219
q float
320
z bool

src/galo_headers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ typedef struct FunctionCall_t {
189189
int scope_size;
190190
Node* arguments;
191191
int argument_count;
192+
int id;
192193
} FunctionCall;
193194

194195
typedef struct WhileLoop_t {
@@ -381,6 +382,9 @@ typedef struct Interpreter_Object_t {
381382

382383
Interpreter_Object* create_interpreter_object(NodeList* ast, Validator_Object* validator_object);
383384
void free_interpreter_object(Interpreter_Object* interpreter_object);
385+
GaloObject predefined_function_call(Interpreter_Object* interp, PredefinedFunction* predefined_function, int argument_count, GaloObject* arguments);
386+
GaloObject function_call(Interpreter_Object* interp, FunctionDeclaration* function, int argument_count, GaloObject* arguments);
387+
void add_builtin_function(Interpreter_Object* interp, char* name, GaloObject (*function)(Interpreter_Object* interp, GaloObject* args, int arg_count));
384388

385389
/////////////////////////////////////////////////////////////////////
386390
// FUNCTIONS AND THEIR DEBUGGER FUNCTIONS

src/interpreter.c

Lines changed: 237 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,38 @@ static void scope_add_variable(Interpreter_Object* interp, int var_id) {
175175
scope->variable_ids[scope->count++] = var_id;
176176
}
177177

178+
void resolve_escape_characters(char *str) {
179+
char *src = str;
180+
char *dst = str;
181+
182+
while (*src) {
183+
if (*src == '\\') {
184+
src++;
185+
switch (*src) {
186+
case 'n': *dst++ = '\n'; break;
187+
case 't': *dst++ = '\t'; break;
188+
case 'r': *dst++ = '\r'; break;
189+
case '0': *dst++ = '\0'; break;
190+
case '\\': *dst++ = '\\'; break;
191+
case '"': *dst++ = '"'; break;
192+
case '\'': *dst++ = '\''; break;
193+
default:
194+
*dst++ = '\\';
195+
*dst++ = *src;
196+
break;
197+
}
198+
199+
if (*src) {
200+
src++;
201+
}
202+
} else {
203+
*dst++ = *src++;
204+
}
205+
}
206+
207+
*dst = '\0';
208+
}
209+
178210
GaloObject interpret_node(Interpreter_Object* interp, Node* node) {
179211
if (node->type == NODE_STRUCT_DECLARATION || node->type == NODE_FUNCTION_DECLARATION) {
180212
return void_object_value(); // handled by validator
@@ -294,7 +326,8 @@ GaloObject interpret_node(Interpreter_Object* interp, Node* node) {
294326
*(float*)object.data = value;
295327
return object;
296328
} else if (token->type == TOKEN_CONSTANT_STRING) {
297-
const char* value = token->value;
329+
char* value = (char*)token->value;
330+
resolve_escape_characters(value);
298331
object.type_id = STRING_TYPE;
299332
object.size = strlen(value) + 1;
300333
object.data = malloc(object.size);
@@ -550,14 +583,210 @@ GaloObject interpret_node(Interpreter_Object* interp, Node* node) {
550583
} else if (node->type == NODE_CONTINUE_STATEMENT) {
551584
interp->did_continue = true;
552585
return void_object_value();
586+
} else if (node->type == NODE_RETURN_STATEMENT) {
587+
interp->did_return = true;
588+
ReturnStatement* return_stmt = (ReturnStatement*)node->data;
589+
if (return_stmt->value.type != NODE_EMPTY) {
590+
GaloObject value = interpret_node(interp, &return_stmt->value);
591+
return value;
592+
}
593+
return void_object_value();
594+
} else if (node->type == NODE_FUNCTION_CALL) {
595+
FunctionCall* func_call = (FunctionCall*)node->data;
596+
597+
int argument_count = func_call->argument_count;
598+
GaloObject* arguments = calloc(argument_count, sizeof(GaloObject));
599+
600+
for (int i = 0; i < argument_count; i++) {
601+
Node arg = func_call->arguments[i];
602+
arguments[i] = interpret_node(interp, &arg);
603+
}
604+
605+
GaloObject return_value = void_object_value();
606+
607+
if (func_call->id < interp->validator_object->predefined_functions->size) {
608+
// predefined function call
609+
PredefinedFunction* predefined_function = (PredefinedFunction*)get_object(interp->validator_object->predefined_functions, func_call->id);
610+
return_value = predefined_function_call(interp, predefined_function, argument_count, arguments);
611+
} else {
612+
// user defined function call
613+
FunctionDeclaration* func = (FunctionDeclaration*)get_object(interp->validator_object->functions, func_call->id);
614+
return_value = function_call(interp, func, argument_count, arguments);
615+
}
616+
617+
for (int i = 0; i < argument_count; i++) {
618+
GaloObject arg = arguments[i];
619+
free(arg.data);
620+
}
621+
free(arguments);
622+
623+
return return_value;
553624
} else {
554-
printf("TODO nodetype: %s\n", get_node_type_name(node->type));
625+
printf("ERROR: Unknown nodetype: %s\n", get_node_type_name(node->type));
555626
exit(1);
556627
}
557628

558629
return void_object_value();
559630
}
560631

632+
GaloObject predefined_function_call(Interpreter_Object* interp, PredefinedFunction* predefined_function, int argument_count, GaloObject* arguments) {
633+
int id = predefined_function->id;
634+
GaloObject (*function)(Interpreter_Object* interp, GaloObject* args, int arg_count) = interp->builtins[id];
635+
return function(interp, arguments, argument_count);
636+
}
637+
GaloObject function_call(Interpreter_Object* interp, FunctionDeclaration* function, int argument_count, GaloObject* arguments) {
638+
printf("TODO: function_call\n");
639+
exit(1);
640+
}
641+
void add_builtin_function(Interpreter_Object* interp, char* name, GaloObject (*function)(Interpreter_Object* interp, GaloObject* args, int arg_count)) {
642+
PredefinedFunction* pf = NULL;
643+
for (int i = 0; i < interp->validator_object->predefined_functions->size; i++) {
644+
PredefinedFunction* index = (PredefinedFunction*)get_object(interp->validator_object->predefined_functions, i);
645+
if (strcmp(index->name, name) == 0) {
646+
pf = index;
647+
break;
648+
}
649+
}
650+
651+
if (pf == NULL) {
652+
printf("DEVELOPER ERROR: Function %s not found in predefined functions from the validator object\n", name);
653+
exit(1);
654+
}
655+
656+
interp->builtins[pf->id] = function;
657+
}
658+
659+
static void append_to_string(char** buffer, size_t* capacity, size_t* length, const char* text) {
660+
size_t add = strlen(text);
661+
662+
if (*length + add + 1 > *capacity) {
663+
*capacity = (*capacity + add + 1) * 2;
664+
char* new_buf = realloc(*buffer, *capacity);
665+
if (!new_buf) {
666+
printf("Out of memory\n");
667+
exit(1);
668+
}
669+
*buffer = new_buf;
670+
}
671+
672+
memcpy(*buffer + *length, text, add);
673+
*length += add;
674+
(*buffer)[*length] = '\0';
675+
}
676+
677+
GaloObject string_object_value(char* string) {
678+
GaloObject object;
679+
object.type_id = STRING_TYPE;
680+
object.size = strlen(string) + 1;
681+
object.data = string;
682+
return object;
683+
}
684+
685+
GaloObject builtin_to_string(Interpreter_Object* interp, GaloObject* args, int arg_count) {
686+
if (arg_count != 1) {
687+
printf("ERROR: to_string() takes 1 argument\n");
688+
exit(1);
689+
}
690+
GaloObject object = args[0];
691+
if (object.type_id == STRING_TYPE) {
692+
char* string = strdup((char*)object.data);
693+
GaloObject new_object = string_object_value(string);
694+
return new_object;
695+
} else if (object.type_id == INT_TYPE) {
696+
char* string = calloc(32, sizeof(char));
697+
sprintf(string, "%d", *(int*)object.data);
698+
GaloObject new_object = string_object_value(string);
699+
return new_object;
700+
} else if (object.type_id == FLOAT_TYPE) {
701+
char* string = calloc(32, sizeof(char));
702+
sprintf(string, "%f", *(float*)object.data);
703+
GaloObject new_object = string_object_value(string);
704+
return new_object;
705+
} else if (object.type_id == BOOLEAN_TYPE) {
706+
char* string = calloc(6, sizeof(char));
707+
if (*(bool*)object.data) {
708+
sprintf(string, "true");
709+
} else {
710+
sprintf(string, "false");
711+
}
712+
GaloObject new_object = string_object_value(string);
713+
return new_object;
714+
} else if (object.type_id == BYTE_TYPE) {
715+
char* string = calloc(8, sizeof(char));
716+
sprintf(string, "%d", *(unsigned char*)object.data);
717+
GaloObject new_object = string_object_value(string);
718+
return new_object;
719+
} else if (object.type_id == LIST_TYPE) {
720+
size_t cap = 64;
721+
size_t len = 0;
722+
char* string = malloc(cap);
723+
string[0] = '\0';
724+
725+
append_to_string(&string, &cap, &len, "[");
726+
727+
ObjectList* list = (ObjectList*)object.data;
728+
729+
for (int i = 0; i < list->size; i++) {
730+
GaloObject* item = get_object(list, i);
731+
GaloObject item_str = builtin_to_string(interp, item, 1);
732+
733+
append_to_string(&string, &cap, &len, (char*)item_str.data);
734+
735+
if (i != list->size - 1) {
736+
append_to_string(&string, &cap, &len, ", ");
737+
}
738+
739+
free(item_str.data);
740+
}
741+
742+
append_to_string(&string, &cap, &len, "]");
743+
744+
return string_object_value(string);
745+
} else {
746+
size_t cap = 64;
747+
size_t len = 0;
748+
char* string = malloc(cap);
749+
string[0] = '\0';
750+
751+
append_to_string(&string, &cap, &len, "{");
752+
753+
StructDeclaration* decl = get_struct_from_id(object.type_id, interp->validator_object);
754+
755+
for (int i = 0; i < decl->field_count; i++) {
756+
GaloObject field = get_field_in_struct(interp, object, object.type_id, decl->fields[i].name.name);
757+
758+
GaloObject field_str = builtin_to_string(interp, &field, 1);
759+
760+
append_to_string(&string, &cap, &len, decl->fields[i].name.name->value);
761+
append_to_string(&string, &cap, &len, " = ");
762+
append_to_string(&string, &cap, &len, (char*)field_str.data);
763+
764+
if (i != decl->field_count - 1) {
765+
append_to_string(&string, &cap, &len, ", ");
766+
}
767+
768+
free(field_str.data);
769+
}
770+
771+
append_to_string(&string, &cap, &len, "}");
772+
773+
return string_object_value(string);
774+
}
775+
}
776+
777+
GaloObject builtin_print(Interpreter_Object* interp, GaloObject* args, int arg_count) {
778+
for (int i = 0; i < arg_count; i++) {
779+
GaloObject arg = args[i];
780+
GaloObject arg_to_string = builtin_to_string(interp, &arg, 1);
781+
char* string = (char*)arg_to_string.data;
782+
printf("%s", string);
783+
free(arg_to_string.data);
784+
}
785+
786+
return void_object_value();
787+
}
788+
789+
561790
Interpreter_Object* create_interpreter_object(NodeList* ast, Validator_Object* validator_object) {
562791
Interpreter_Object* interp = calloc(1, sizeof(Interpreter_Object));
563792

@@ -573,6 +802,12 @@ Interpreter_Object* create_interpreter_object(NodeList* ast, Validator_Object* v
573802
interp->call_capacity = 64;
574803
interp->call_stack = calloc(interp->call_capacity, sizeof(CallFrame));
575804

805+
interp->builtin_count = validator_object->predefined_functions->size;
806+
interp->builtins = calloc(interp->builtin_count, sizeof(GaloObject (*)(Interpreter_Object* interp, GaloObject* args, int arg_count)));
807+
808+
add_builtin_function(interp, "to_string", builtin_to_string);
809+
add_builtin_function(interp, "print", builtin_print);
810+
576811
return interp;
577812
}
578813

0 commit comments

Comments
 (0)