#include "interpreter.h" #include "builtin-functions.h" #include "object-type.h" #include "error-message.h" #include "heap.h" #include #include static FlupFunctionAlternative* FlupFunctionAlternative_Malloc(size_t condition_token_start, size_t condition_token_end, size_t body_token_start, size_t body_token_end) { FlupFunctionAlternative* a = malloc(sizeof(FlupFunctionAlternative)); a->next = NULL; a->condition_token_start = condition_token_start; a->condition_token_end = condition_token_end; a->body_token_start = body_token_start; a->body_token_end = body_token_end; return a; } const char* standard_builtin_names[] = { "println", "duplicate", "print", NULL }; const BuiltinFunction standard_builtin_functions[] = { BuiltinFunction_PrintLine, BuiltinFunction_Duplicate, BuiltinFunction_Print, }; static TracingHeapDataDestructor heap_destructors[] = { [HEAPDATAKIND_OBJECT] = (TracingHeapDataDestructor) Object_Destroy, }; static void* heap_destructor_args[] = { [HEAPDATAKIND_OBJECT] = NULL, }; static TracingHeapSizeQuery heap_size_queries[] = { [HEAPDATAKIND_OBJECT] = (TracingHeapSizeQuery) Object_SizeQuery, }; static void* heap_size_queries_args[] = { [HEAPDATAKIND_OBJECT] = NULL, }; static TracingHeapTraceData heap_trace_data[] = { [HEAPDATAKIND_OBJECT] = (TracingHeapTraceData) Object_ReferenceTrace, }; static void* heap_trace_data_args[] = { [HEAPDATAKIND_OBJECT] = NULL, }; static void _Interpreter_WriteHeapConfig(TracingHeap* heap) { heap->config = (TracingHeapConfig) { .destructor = heap_destructors, .destructor_context = heap_destructor_args, .size_query = heap_size_queries, .size_query_context = heap_size_queries_args, .trace_data = heap_trace_data, .trace_context = heap_trace_data_args, }; return; } int Interpreter_Create(Interpreter* self, DynamicArray* tokens) { if (DynamicArray_Create(&self->call_frames, sizeof(CallFrame), 16, NULL)) { return ENOMEM; } _Interpreter_WriteHeapConfig(&self->heap); if (TracingHeap_Create(&self->heap, NULL)) { return EXIT_FAILURE; } self->tokens = tokens; self->builtin_names = standard_builtin_names; self->builtin_functions = standard_builtin_functions; return EXIT_SUCCESS; } Token* Interpreter_GetToken(Interpreter* self, size_t index) { return DynamicArray_GetPointer(self->tokens, index); } Token* Interpreter_ExpectToken(Interpreter* self, CallFrame* top_frame, size_t stop_index) { if (top_frame->instruction_pointer > stop_index) { return NULL; } return Interpreter_GetToken(self, top_frame->instruction_pointer); } bool is_begin_of_nested_function_definition(Interpreter* self, CallFrame* top_frame, size_t stop_index) { Token* possible_colon = Interpreter_ExpectToken(self, top_frame, stop_index); return possible_colon != NULL && possible_colon->type == TOKENTYPE_COLON; } bool is_end_of_nested_function_definition(Interpreter* self, CallFrame* top_frame, size_t stop_index) { Token* possible_semicolon = Interpreter_ExpectToken(self, top_frame, stop_index); return possible_semicolon != NULL && possible_semicolon->type == TOKENTYPE_SEMICOLON; } int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t stop_index) { FlupFunction* f = CallFrame_Reserve(top_frame, sizeof(FlupFunction), alignof(FlupFunction)); if (f == NULL) return ENOMEM; Token* function_name = Interpreter_GetToken(self, top_frame->instruction_pointer); f->name = function_name->get.identifier; top_frame->instruction_pointer++; // one token colon top_frame->instruction_pointer++; Token* parameter_type = Interpreter_ExpectToken(self, top_frame, stop_index); f->parameters = NULL; ParameterDefinition** pdef = &f->parameters; while (parameter_type->type != TOKENTYPE_ARROW) { top_frame->instruction_pointer++; Token* parameter_name = Interpreter_ExpectToken(self, top_frame, stop_index); top_frame->instruction_pointer++; if (parameter_type->type != TOKENTYPE_IDENTIFIER) { ErrorMessage_err("Expected identifier for parameter type-definition in function definition", self, top_frame); return EXIT_FAILURE; } if (parameter_name->type != TOKENTYPE_IDENTIFIER) { ErrorMessage_err("Expected identifier for parameter name-declaration in function definition", self, top_frame); return EXIT_FAILURE; } *pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition)); if (*pdef == NULL) { ErrorMessage_OutOfMemoryError("Failed to reserve memory for CallFrame in Function parsefunction", self, top_frame); return ENOMEM; } (*pdef)->type = parameter_type->get.identifier; (*pdef)->name = parameter_name->get.identifier; (*pdef)->next = NULL; pdef = &((*pdef)->next); parameter_type = Interpreter_ExpectToken(self, top_frame, stop_index); } // one arrow token top_frame->instruction_pointer++; { Token* return_type = Interpreter_ExpectToken(self, top_frame, stop_index); if (return_type == NULL) { return EXIT_FAILURE; } if (return_type->type != TOKENTYPE_IDENTIFIER) { return EXIT_FAILURE; } top_frame->instruction_pointer++; f->return_type = return_type->get.identifier; } // pipe token Token* alternative_start = Interpreter_ExpectToken(self, top_frame, stop_index); if (alternative_start == NULL) { return EXIT_FAILURE; } int nested_functions_count = 0; FlupFunctionAlternative** fdef = &f->alternatives; while (alternative_start->type == TOKENTYPE_PIPE) { top_frame->instruction_pointer++; // pipe Token überspringen size_t condition_start = top_frame->instruction_pointer; // condition parsing Token* current; do { current = Interpreter_ExpectToken(self, top_frame, stop_index); top_frame->instruction_pointer++; if (current == NULL) { return EXIT_FAILURE; } if (is_begin_of_nested_function_definition(self, top_frame, stop_index)) { nested_functions_count++; } if (is_end_of_nested_function_definition(self, top_frame, stop_index)) { nested_functions_count--; } } while (current->type != TOKENTYPE_ARROW || nested_functions_count != 0); size_t condition_end = top_frame->instruction_pointer - 2; // condition body parsing nested_functions_count = 0; size_t body_start = top_frame->instruction_pointer; current = Interpreter_ExpectToken(self, top_frame, stop_index); do { if (current == NULL) { return EXIT_FAILURE; } if (current->type == TOKENTYPE_COLON) { nested_functions_count++; } if (current->type == TOKENTYPE_SEMICOLON && nested_functions_count > 0) { nested_functions_count--; } top_frame->instruction_pointer++; current = Interpreter_ExpectToken(self, top_frame, stop_index); } while ((current->type != TOKENTYPE_PIPE && current->type != TOKENTYPE_SEMICOLON) || nested_functions_count > 0); size_t body_end = top_frame->instruction_pointer; *fdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition)); if (*fdef == NULL) { return ENOMEM; } (*fdef)->condition_token_start = condition_start; (*fdef)->condition_token_end = condition_end; (*fdef)->body_token_start = body_start; (*fdef)->body_token_end = body_end; fdef = &((*fdef)->next); alternative_start = Interpreter_ExpectToken(self, top_frame, stop_index); if (alternative_start == NULL) { return EXIT_FAILURE; } } // one token colon top_frame->instruction_pointer++; f->next = top_frame->functions; top_frame->functions = f; return EXIT_SUCCESS; } FlupFunction* Interpreter_FindFunction(Interpreter* self, StringView name) { DYNAMICARRAY_REVERSEITERATE(self->call_frames, CallFrame, frame) { for (FlupFunction* function = frame->functions; function != NULL; function = function->next) { if (StringView_Equal(function->name, name)) { return function; } } } return NULL; } int Interpreter_CallBuiltinFunction(Interpreter* self, CallFrame* parent_frame, Token* name) { StringView function_name = name->get.identifier; for (size_t i = 0; self->builtin_names[i] != NULL; i++) { if (StringView_Equal(function_name, StringView_FromString(self->builtin_names[i]))) { return self->builtin_functions[i](parent_frame, self); } } return EXIT_FAILURE; } int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token* name) { FlupFunction* function = Interpreter_FindFunction(self, name->get.identifier); if (function == NULL) { return Interpreter_CallBuiltinFunction(self, parent_frame, name); } CallFrame* new_frame; DynamicArray_AppendEmpty(&self->call_frames, (void**) &new_frame); parent_frame = DynamicArray_GetPointer(&self->call_frames, DynamicArray_GetLength(&self->call_frames) - 2); if (new_frame == NULL) { // TODO: Error message return ENOMEM; } CallFrame_Create(new_frame, function); size_t argument_count = 0; size_t stack_size = DynamicArray_GetLength(&parent_frame->stack); for ( ParameterDefinition* d = function->parameters; d != NULL; d = d->next, argument_count++); if (stack_size < argument_count) { // TODO: Error message return EXIT_FAILURE; } ParameterDefinition* parameter_def = function->parameters; for (size_t stack_index = stack_size - argument_count; stack_index != stack_size; stack_index++, parameter_def = parameter_def->next) { Value* parameter_value = DynamicArray_GetPointer(&parent_frame->stack, stack_index); if (!Value_TypeMatchesStringName(parameter_value->type, parameter_def->type)) { // TODO: Error message return EXIT_FAILURE; } int define_code = CallFrame_DefineVariable(new_frame, parameter_def->name, *parameter_value); if (define_code != EXIT_SUCCESS) { return define_code; } } for (size_t i = 0; i < argument_count; i++) { DynamicArray_Remove(&parent_frame->stack, DynamicArray_GetLength(&parent_frame->stack) - 1); } return EXIT_SUCCESS; } int Interpreter_GetParenthesizedRange(Interpreter* self, CallFrame* top_frame, size_t* paren_start, size_t* paren_end, size_t stop_token) { size_t open_paren_count = 0; size_t start_paren_index = top_frame->instruction_pointer; do { Token* t = Interpreter_ExpectToken(self, top_frame, stop_token); if (t == NULL) { // TODO: Error message return EXIT_FAILURE; } top_frame->instruction_pointer++; open_paren_count += t->type == TOKENTYPE_LEFT_PAREN; open_paren_count -= t->type == TOKENTYPE_RIGHT_PAREN; } while (open_paren_count != 0); size_t stop_paren_index = --top_frame->instruction_pointer; if (paren_start != NULL) *paren_start = start_paren_index; if (paren_end != NULL) *paren_end = stop_paren_index; return EXIT_SUCCESS; } Object* _Interpreter_MakeObject(Interpreter* self, ObjectType* otype) { size_t object_size = Object_AllocationSizeForType(otype); Object* new_object = TracingHeap_Allocate(&self->heap, object_size, HEAPDATAKIND_OBJECT); return new_object; } static int _Interpreter_ConstructString(Interpreter* self, StringView view) { Object* string_head = _Interpreter_MakeObject(self, self->native_list_type); return EXIT_SUCCESS; } int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token) { size_t frame_count = DynamicArray_GetLength(&self->call_frames); CallFrame* top_frame = DynamicArray_GetPointer(&self->call_frames, frame_count - 1); Token* t = Interpreter_GetToken(self, top_frame->instruction_pointer); switch (t->type) { case TOKENTYPE_INTEGER: { Value* v; DynamicArray_AppendEmpty(&top_frame->stack, (void**) &v); if (v == NULL) return ENOMEM; v->type = VALUETYPE_INT64; v->get.i64 = t->get.integer; top_frame->instruction_pointer++; break; } case TOKENTYPE_DOUBLE: { Value* v; DynamicArray_AppendEmpty(&top_frame->stack, (void**) &v); if (v == NULL) return ENOMEM; v->type = VALUETYPE_DOUBLE; v->get.f64 = t->get.decimal; top_frame->instruction_pointer++; break; } case TOKENTYPE_IDENTIFIER: { Token* next = Interpreter_GetToken(self, top_frame->instruction_pointer + 1); FlupVariable* var; if (next != NULL && next->type == TOKENTYPE_COLON) { // function definition return Interpreter_ParseFunction(self, top_frame, stop_token); } else if ((var = CallFrame_FindVariable(top_frame, t->get.identifier)) != NULL) { Value* stack_value; DynamicArray_AppendEmpty(&top_frame->stack, (void**) &stack_value); if (stack_value == NULL) { return ENOMEM; } *stack_value = var->value; top_frame->instruction_pointer++; } else { top_frame->instruction_pointer++; return Interpreter_CallFunction(self, top_frame, t); // regular call } break; } case TOKENTYPE_EQUALITY: { return BuiltinFunction_Equality(top_frame, self); } case TOKENTYPE_PLUS: { BuiltinFunction_Plus(top_frame, self); break; } case TOKENTYPE_MINUS: { BuiltinFunction_Minus(top_frame, self); break; } case TOKENTYPE_MULTIPLY: { BuiltinFunction_Multiply(top_frame, self); break; } case TOKENTYPE_BIND: { top_frame->instruction_pointer++; Token* identifier_token = Interpreter_ExpectToken(self, top_frame, stop_token); if (identifier_token == NULL) { // TODO: Error message return EXIT_FAILURE; } // char variable_name[identifier_token->get.identifier.length + 1]; // StringView_Paste(variable_name, identifier_token->get.identifier); // variable_name[identifier_token->get.identifier.length] = '\0'; // printf("Binding variable with name %s\n", variable_name); top_frame->instruction_pointer++; Token* as_token = Interpreter_ExpectToken(self, top_frame, stop_token); if (as_token == NULL) { // TODO: Error message return EXIT_FAILURE; } size_t as_token_index = top_frame->instruction_pointer; top_frame->instruction_pointer++; size_t paren_start, paren_end; if (Interpreter_GetParenthesizedRange(self, top_frame, &paren_start, &paren_end, stop_token)) { // TODO: Error message return EXIT_FAILURE; } top_frame->instruction_pointer = as_token_index; FlupFunction* evaluation_function = CallFrame_Reserve(top_frame, sizeof(FlupFunction), alignof(FlupFunction)); if (evaluation_function == NULL) { return ENOMEM; } StringView evaluation_name = identifier_token->get.identifier; while (!StringView_StartsWith(evaluation_name, StringView_FromString("bind"))) { evaluation_name = (StringView) { .source = evaluation_name.source - 1, .length = evaluation_name.length + 1, }; } evaluation_function->name = evaluation_name; evaluation_function->return_type = StringView_FromString("any"); FlupFunctionAlternative* evaluation_alternative = CallFrame_Reserve(top_frame, sizeof(FlupFunctionAlternative), alignof(FlupFunctionAlternative)); if (evaluation_alternative == NULL) { return ENOMEM; } evaluation_alternative->body_token_start = paren_start + 1; evaluation_alternative->body_token_end = paren_end; evaluation_alternative->next = NULL; evaluation_function->alternatives = evaluation_alternative; FlupVariable* parent_variables = top_frame->variables; CallFrame* evaluation_frame; DynamicArray_AppendEmpty(&self->call_frames, (void**) &evaluation_frame); if (evaluation_frame == NULL) { return ENOMEM; } if (CallFrame_Create(evaluation_frame, evaluation_function)) { return ENOMEM; } evaluation_frame->instruction_pointer = evaluation_alternative->body_token_start; evaluation_frame->variables = parent_variables; break; } case TOKENTYPE_AS: { Value variable_value; if (CallFrame_StackPop(top_frame, &variable_value)) { // TODO: Error message return EXIT_FAILURE; } top_frame->instruction_pointer--; Token* identifier_token = Interpreter_ExpectToken(self, top_frame, stop_token); if (identifier_token == NULL) { // TODO: Error message return EXIT_FAILURE; } // TODO: Type-check the token StringView variable_name = identifier_token->get.identifier; FlupVariable* var = CallFrame_FindVariable(top_frame, variable_name); if (var != NULL) { var->value = variable_value; } else { if (CallFrame_DefineVariable(top_frame, variable_name, variable_value)) { // TODO: Error message return EXIT_FAILURE; } } top_frame->instruction_pointer += 2; // points to opening paren size_t paren_end_index; if (Interpreter_GetParenthesizedRange(self, top_frame, NULL, &paren_end_index, stop_token)) { // TODO: Error message return EXIT_FAILURE; } top_frame->instruction_pointer = paren_end_index + 1; break; } case TOKENTYPE_COMMENT: top_frame->instruction_pointer++; break; case TOKENTYPE_STRING: { StringView v = StringView_Slice(t->get.identifier, 1, t->get.identifier.length - 1); // drop the "s int construct_code = _Interpreter_ConstructString(self, v); if (construct_code) { return construct_code; } break; } case TOKENTYPE_PIPE: case TOKENTYPE_SEMICOLON: case TOKENTYPE_LEFT_BRACE: case TOKENTYPE_RIGHT_BRACE: case TOKENTYPE_AMPERSAND: case TOKENTYPE_DIVIDE: case TOKENTYPE_ARROW: case TOKENTYPE_COLON: case TOKENTYPE_INEQUALITY: case TOKENTYPE_LESSTHAN: case TOKENTYPE_LESSEQUAL: case TOKENTYPE_GREATERTHAN: case TOKENTYPE_GREATEREQUAL: case TOKENTYPE_COMMA: case TOKENTYPE_LEFT_PAREN: case TOKENTYPE_RIGHT_PAREN: fprintf(stderr, "Unexpected token with type: %s, continuing with next token...\n", TokenType_ToString(t->type)); top_frame->instruction_pointer++; break; case TOKENTYPE_NONE: case TOKENTYPE_ERROR: return EXIT_FAILURE; } return EXIT_SUCCESS; } #define RPN(a,b,c) a c b int Interpreter_RunFrame(Interpreter* self) { size_t frame_count = DynamicArray_GetLength(&self->call_frames); CallFrame* top_frame = DynamicArray_GetPointer(&self->call_frames, frame_count - 1); if (CallFrame_IsExecutingCondition(top_frame)) { // alternative executing while (top_frame->instruction_pointer <= top_frame->alternative->condition_token_end) { int execute_code = Interpreter_ExecuteNext(self, top_frame->alternative->condition_token_end); if (execute_code != EXIT_SUCCESS) { return execute_code; } if (RPN(frame_count, DynamicArray_GetLength(&self->call_frames), !=)) { return EXIT_SUCCESS; } } } else if (CallFrame_IsSelectingCondition(top_frame)) { // alternative evaluation done Value alternative_success; if (CallFrame_StackPop(top_frame, &alternative_success) != EXIT_SUCCESS) { // TODO: Error message return EXIT_FAILURE; } if (Value_IsTruthy(&alternative_success)) { // into body top_frame->instruction_pointer = top_frame->alternative->body_token_start; } else { if (top_frame->alternative->next == NULL) { // TODO: Error message return EXIT_FAILURE; } top_frame->alternative = top_frame->alternative->next; top_frame->instruction_pointer = top_frame->alternative->condition_token_start; // next alternative } return EXIT_SUCCESS; } else if (CallFrame_IsExecutingBody(top_frame)) { // function executing do { int execute_code = Interpreter_ExecuteNext(self, top_frame->alternative->body_token_end); if (execute_code != EXIT_SUCCESS) { return execute_code; } if (RPN(frame_count, DynamicArray_GetLength(&self->call_frames), !=)) { return EXIT_SUCCESS; } } while (top_frame->instruction_pointer < top_frame->alternative->body_token_end); } else if (CallFrame_IsReturningBody(top_frame)) { // Function return if (StringView_Equal(top_frame->self_function->return_type, StringView_FromString("void"))) { CallFrame_Destroy(top_frame); DynamicArray_Remove(&self->call_frames, frame_count - 1); return EXIT_SUCCESS; } CallFrame* parent_frame = DynamicArray_GetPointer(&self->call_frames, frame_count - 2); Value return_value; if (CallFrame_StackPop(top_frame, &return_value)) { // TODO: Error message return EXIT_FAILURE; } // char function_name[top_frame->self_function->name.length + 1]; // memset(function_name, 0, sizeof(function_name)); // StringView_Paste(function_name, top_frame->self_function->name); // printf("%s\n", function_name); if (!Value_TypeMatchesStringName(return_value.type, top_frame->self_function->return_type)) { // TODO: Error message return EXIT_FAILURE; } CallFrame_Destroy(top_frame); DynamicArray_Remove(&self->call_frames, frame_count - 1); if (CallFrame_StackPush(parent_frame, &return_value)) { return ENOMEM; } } else { // Invalid instruction pointer // TODO: Error message return EXIT_FAILURE; } return EXIT_SUCCESS; } int Interpreter_Run(Interpreter* self) { size_t frame_count = 1; do { if (Interpreter_RunFrame(self)) { // TODO: Return the error code return EXIT_FAILURE; } frame_count = DynamicArray_GetLength(&self->call_frames); } while (frame_count != 0); return EXIT_SUCCESS; } int Interpreter_Startup(Interpreter* self, CallFrame* root_frame) { ObjectType* base_type = CallFrame_Reserve(root_frame, sizeof(ObjectType), alignof(ObjectType)); if (ObjectType_Create(base_type, StringView_FromString("Base"), base_type, 0, NULL)) { return ENOMEM; } ObjectType* list_type = CallFrame_Reserve(root_frame, sizeof(ObjectType), alignof(ObjectType)); if (ObjectType_Create(list_type, StringView_FromString("List"), base_type, 2, NULL)) { return ENOMEM; } if (ObjectType_DefineObjectAttribute(list_type, base_type, StringView_FromString("value"))) { return ENOMEM; } if (ObjectType_DefineObjectAttribute(list_type, list_type, StringView_FromString("tail"))) { return ENOMEM; } if (CallFrame_DefineObjectType(root_frame, list_type)) { return ENOMEM; } ObjectType* char_type = CallFrame_Reserve(root_frame, sizeof(ObjectType), alignof(ObjectType)); if (ObjectType_Create(char_type, StringView_FromString("Char"), base_type, 2, NULL)) { return ENOMEM; } if (ObjectType_DefinePrimitiveAttribute(list_type, VALUETYPE_BYTE, StringView_FromString("char"))) { return ENOMEM; } self->implicit_char_type = char_type; self->implicit_base_type = base_type; self->native_list_type = list_type; return EXIT_SUCCESS; } int Interpreter_Interpret(Interpreter* self) { CallFrame* first_frame; FlupFunctionAlternative* main_alternative = FlupFunctionAlternative_Malloc(SIZE_MAX-1, SIZE_MAX-1, 0, DynamicArray_GetLength(self->tokens)); FlupFunction main_function = { .name = StringView_FromString("
"), .alternatives = main_alternative, .return_type = StringView_FromString("void"), .next = NULL, .parameters = NULL, }; if (main_alternative == NULL) { return ENOMEM; } DynamicArray_AppendEmpty(&self->call_frames, (void**) &first_frame); if (CallFrame_Create(first_frame, &main_function)) { return ENOMEM; } first_frame->instruction_pointer = 0; int run_code = Interpreter_Run(self); free(main_alternative); return run_code; } void Interpreter_Destroy(Interpreter* self) { DynamicArray_Destroy(&self->call_frames); }