718 lines
22 KiB
C
718 lines
22 KiB
C
#include "interpreter.h"
|
|
#include "builtin-functions.h"
|
|
#include "object-type.h"
|
|
#include "error-message.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdalign.h>
|
|
|
|
|
|
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,
|
|
};
|
|
|
|
int Interpreter_Create(Interpreter* self, DynamicArray* tokens)
|
|
{
|
|
if (TracingHeap_Create(&self->heap, NULL)) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (DynamicArray_Create(&self->call_frames, sizeof(CallFrame), 16, NULL)) {
|
|
return ENOMEM;
|
|
}
|
|
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);
|
|
|
|
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("<main>"),
|
|
.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);
|
|
}
|