Turing-Complete now
This commit is contained in:
parent
3bf4a73c2e
commit
9dbb9e882c
6 changed files with 405 additions and 30 deletions
2
make.sh
2
make.sh
|
@ -5,4 +5,4 @@ gcc `find src/ -name '*.c'` \
|
||||||
submodules/utilitiec/build/lib/liballocator-interface.a \
|
submodules/utilitiec/build/lib/liballocator-interface.a \
|
||||||
submodules/utilitiec/build/lib/libStringView.a \
|
submodules/utilitiec/build/lib/libStringView.a \
|
||||||
submodules/utilitiec/build/lib/libScratchpad.a \
|
submodules/utilitiec/build/lib/libScratchpad.a \
|
||||||
-lm -ggdb -Wall -o bin/flup
|
-lm -ggdb -Wall -Wextra -pedantic -o bin/flup
|
||||||
|
|
|
@ -2,18 +2,31 @@
|
||||||
|
|
||||||
#include <stdalign.h>
|
#include <stdalign.h>
|
||||||
|
|
||||||
static int CallFrame_Create(CallFrame* self, FlupFunctionAlternative* f)
|
static int CallFrame_Create(CallFrame* self, FlupFunction* self_function)
|
||||||
{
|
{
|
||||||
if (DynamicArray_Create(&self->stack, sizeof(Value), 8, NULL)) {
|
if (DynamicArray_Create(&self->stack, sizeof(Value), 8, NULL)) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
self->memory_pad.memory = NULL;
|
self->memory_pad.memory = NULL;
|
||||||
self->function = f;
|
self->self_function = self_function;
|
||||||
self->instruction_pointer = f->body_token_start;
|
self->alternative = self->self_function->alternatives;
|
||||||
|
self->instruction_pointer = self->alternative->condition_token_start;
|
||||||
|
|
||||||
|
self->variables = NULL;
|
||||||
|
self->functions = NULL;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CallFrame_Destroy(CallFrame* self)
|
||||||
|
{
|
||||||
|
if (self->memory_pad.memory != NULL) {
|
||||||
|
Scratchpad_Destroy(&self->memory_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicArray_Destroy(&self->stack);
|
||||||
|
}
|
||||||
|
|
||||||
static void* CallFrame_Reserve(CallFrame* self, size_t amount, size_t alignment)
|
static void* CallFrame_Reserve(CallFrame* self, size_t amount, size_t alignment)
|
||||||
{
|
{
|
||||||
if (self->memory_pad.memory == NULL) {
|
if (self->memory_pad.memory == NULL) {
|
||||||
|
@ -66,6 +79,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
|
|
||||||
Token* function_name = Interpreter_GetToken(self, top_frame->instruction_pointer);
|
Token* function_name = Interpreter_GetToken(self, top_frame->instruction_pointer);
|
||||||
|
|
||||||
|
memset(f, 0, sizeof(*f));
|
||||||
f->name = function_name->get.identifier;
|
f->name = function_name->get.identifier;
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
|
|
||||||
|
@ -122,7 +136,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlupFunctionAlternative** fdef = &f->alternative;
|
FlupFunctionAlternative** fdef = &f->alternatives;
|
||||||
while (alternative_start->type == TOKENTYPE_PIPE) {
|
while (alternative_start->type == TOKENTYPE_PIPE) {
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
size_t condition_start = top_frame->instruction_pointer;
|
size_t condition_start = top_frame->instruction_pointer;
|
||||||
|
@ -134,17 +148,19 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
if (current == NULL) {
|
if (current == NULL) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
// TODO: Count inner colon and semicolon to allow for nested functions
|
||||||
} while (current->type != TOKENTYPE_ARROW);
|
} while (current->type != TOKENTYPE_ARROW);
|
||||||
size_t condition_end = top_frame->instruction_pointer - 1;
|
size_t condition_end = top_frame->instruction_pointer - 2;
|
||||||
|
|
||||||
size_t body_start = top_frame->instruction_pointer + 1;
|
size_t body_start = top_frame->instruction_pointer;
|
||||||
do {
|
do {
|
||||||
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
if (current == NULL) {
|
if (current == NULL) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
} while (current->type != TOKENTYPE_PIPE && current->type != TOKENTYPE_COLON);
|
// TODO: Count inner colon and semicolon to allow for nested functions
|
||||||
|
} while (current->type != TOKENTYPE_PIPE && current->type != TOKENTYPE_SEMICOLON);
|
||||||
top_frame->instruction_pointer--;
|
top_frame->instruction_pointer--;
|
||||||
size_t body_end = top_frame->instruction_pointer;
|
size_t body_end = top_frame->instruction_pointer;
|
||||||
|
|
||||||
|
@ -168,9 +184,239 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
// one token colon
|
// one token colon
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
|
|
||||||
|
f->next = top_frame->functions;
|
||||||
|
top_frame->functions = f;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _are_types_compatible(enum ValueType type, StringView type_name)
|
||||||
|
{
|
||||||
|
const enum ValueType type_mapping[] = {VALUETYPE_INT64, VALUETYPE_DOUBLE};
|
||||||
|
const char* name_mapping[] = {"int", "double"};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(name_mapping) / sizeof(name_mapping[0]); i++) {
|
||||||
|
if (1==1
|
||||||
|
&& type == type_mapping[i]
|
||||||
|
&& StringView_Equal(type_name, StringView_FromString(name_mapping[i]))
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallFrame_DefineVariable(CallFrame* self, StringView name, Value value)
|
||||||
|
{
|
||||||
|
FlupVariable* v = CallFrame_Reserve(self, sizeof(FlupVariable), alignof(FlupVariable));
|
||||||
|
if (v == NULL) {
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
v->name = name;
|
||||||
|
v->value = value;
|
||||||
|
|
||||||
|
v->next = self->variables;
|
||||||
|
self->variables = v;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token* name)
|
||||||
|
{
|
||||||
|
FlupFunction* function = Interpreter_FindFunction(self, name->get.identifier);
|
||||||
|
if (function == NULL) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (! _are_types_compatible(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlupVariable* CallFrame_FindVariable(CallFrame* self, StringView name)
|
||||||
|
{
|
||||||
|
for (FlupVariable* variable = self->variables; variable != NULL; variable = variable->next) {
|
||||||
|
if (StringView_Equal(variable->name, name)) {
|
||||||
|
return variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallFrame_StackPop(CallFrame* self, Value* dest)
|
||||||
|
{
|
||||||
|
size_t stack_size = DynamicArray_GetLength(&self->stack);
|
||||||
|
Value* popped = DynamicArray_GetPointer(&self->stack, stack_size - 1);
|
||||||
|
if (popped == NULL) {
|
||||||
|
return ENOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest = *popped;
|
||||||
|
DynamicArray_Remove(&self->stack, stack_size - 1);
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallFrame_StackPush(CallFrame* self, Value* value)
|
||||||
|
{
|
||||||
|
return DynamicArray_Append(&self->stack, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Value_Equal(Value* v1, Value* v2)
|
||||||
|
{
|
||||||
|
if (v1->type != v2->type) return false;
|
||||||
|
switch (v1->type) {
|
||||||
|
case VALUETYPE_INT64:
|
||||||
|
return v1->get.i64 == v2->get.i64;
|
||||||
|
case VALUETYPE_DOUBLE:
|
||||||
|
return v1->get.f64 == v2->get.f64;
|
||||||
|
case VALUETYPE_BOOLEAN:
|
||||||
|
return v1->get.boolean = v2->get.boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BuiltinFunction_Equality(CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Value v1;
|
||||||
|
Value v2;
|
||||||
|
|
||||||
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value result;
|
||||||
|
result.type = VALUETYPE_BOOLEAN;
|
||||||
|
result.get.boolean = Value_Equal(&v1, &v2);
|
||||||
|
|
||||||
|
top_frame->instruction_pointer++;
|
||||||
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int BuiltinFunction_Plus(CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Value v1;
|
||||||
|
Value v2;
|
||||||
|
|
||||||
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (v1.type != v2.type) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value result;
|
||||||
|
result.type = v1.type;
|
||||||
|
switch (v1.type) {
|
||||||
|
case VALUETYPE_INT64:
|
||||||
|
result.get.i64 = v2.get.i64 + v1.get.i64;
|
||||||
|
break;
|
||||||
|
case VALUETYPE_DOUBLE:
|
||||||
|
result.get.f64 = v2.get.f64 + v1.get.f64;
|
||||||
|
break;
|
||||||
|
case VALUETYPE_BOOLEAN:
|
||||||
|
result.get.boolean = v2.get.boolean + v1.get.boolean;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
top_frame->instruction_pointer++;
|
||||||
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int BuiltinFunction_Minus(CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Value v1;
|
||||||
|
Value v2;
|
||||||
|
|
||||||
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (v1.type != v2.type) {
|
||||||
|
// TODO: Error message
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Value result;
|
||||||
|
result.type = v1.type;
|
||||||
|
switch (v1.type) {
|
||||||
|
case VALUETYPE_INT64:
|
||||||
|
result.get.i64 = v2.get.i64 - v1.get.i64;
|
||||||
|
break;
|
||||||
|
case VALUETYPE_DOUBLE:
|
||||||
|
result.get.f64 = v2.get.f64 - v1.get.f64;
|
||||||
|
break;
|
||||||
|
case VALUETYPE_BOOLEAN:
|
||||||
|
result.get.boolean = v2.get.boolean - v1.get.boolean;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
top_frame->instruction_pointer++;
|
||||||
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
|
}
|
||||||
|
|
||||||
int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
{
|
{
|
||||||
size_t frame_count = DynamicArray_GetLength(&self->call_frames);
|
size_t frame_count = DynamicArray_GetLength(&self->call_frames);
|
||||||
|
@ -200,24 +446,82 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
case TOKENTYPE_IDENTIFIER:
|
case TOKENTYPE_IDENTIFIER:
|
||||||
{
|
{
|
||||||
Token* next = Interpreter_GetToken(self, top_frame->instruction_pointer + 1);
|
Token* next = Interpreter_GetToken(self, top_frame->instruction_pointer + 1);
|
||||||
|
FlupVariable* var;
|
||||||
if (next != NULL && next->type == TOKENTYPE_COLON) {
|
if (next != NULL && next->type == TOKENTYPE_COLON) {
|
||||||
// function definition
|
// function definition
|
||||||
return Interpreter_ParseFunction(self, top_frame, stop_token);
|
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 {
|
} else {
|
||||||
|
top_frame->instruction_pointer++;
|
||||||
|
return Interpreter_CallFunction(self, top_frame, t);
|
||||||
// regular call
|
// regular call
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKENTYPE_EQUALITY:
|
||||||
|
{
|
||||||
|
return BuiltinFunction_Equality(top_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
case TOKENTYPE_PIPE:
|
||||||
|
case TOKENTYPE_SEMICOLON:
|
||||||
|
{
|
||||||
|
// return from function body
|
||||||
|
if (StringView_Equal(top_frame->self_function->return_type, StringView_FromString("void"))) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (! _are_types_compatible(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case TOKENTYPE_LEFT_BRACE:
|
case TOKENTYPE_LEFT_BRACE:
|
||||||
case TOKENTYPE_RIGHT_BRACE:
|
case TOKENTYPE_RIGHT_BRACE:
|
||||||
case TOKENTYPE_AMPERSAND:
|
case TOKENTYPE_AMPERSAND:
|
||||||
case TOKENTYPE_PLUS:
|
case TOKENTYPE_PLUS:
|
||||||
|
{
|
||||||
|
BuiltinFunction_Plus(top_frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TOKENTYPE_MINUS:
|
case TOKENTYPE_MINUS:
|
||||||
|
{
|
||||||
|
BuiltinFunction_Minus(top_frame);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case TOKENTYPE_MULTIPLY:
|
case TOKENTYPE_MULTIPLY:
|
||||||
case TOKENTYPE_DIVIDE:
|
case TOKENTYPE_DIVIDE:
|
||||||
case TOKENTYPE_PIPE:
|
|
||||||
case TOKENTYPE_ARROW:
|
case TOKENTYPE_ARROW:
|
||||||
case TOKENTYPE_COLON:
|
case TOKENTYPE_COLON:
|
||||||
case TOKENTYPE_EQUALITY:
|
|
||||||
case TOKENTYPE_INEQUALITY:
|
case TOKENTYPE_INEQUALITY:
|
||||||
case TOKENTYPE_LESSTHAN:
|
case TOKENTYPE_LESSTHAN:
|
||||||
case TOKENTYPE_LESSEQUAL:
|
case TOKENTYPE_LESSEQUAL:
|
||||||
|
@ -228,9 +532,24 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
|
|
||||||
case TOKENTYPE_NONE:
|
case TOKENTYPE_NONE:
|
||||||
case TOKENTYPE_ERROR:
|
case TOKENTYPE_ERROR:
|
||||||
default:
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Value_IsTruthy(Value* v)
|
||||||
|
{
|
||||||
|
switch (v->type) {
|
||||||
|
case VALUETYPE_INT64:
|
||||||
|
return v->get.i64 != 0;
|
||||||
|
case VALUETYPE_DOUBLE:
|
||||||
|
return v->get.f64 != 0.0;
|
||||||
|
case VALUETYPE_BOOLEAN:
|
||||||
|
return v->get.boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RPN(a,b,c) a c b
|
#define RPN(a,b,c) a c b
|
||||||
|
@ -239,22 +558,50 @@ int Interpreter_RunFrame(Interpreter* self)
|
||||||
size_t frame_count = DynamicArray_GetLength(&self->call_frames);
|
size_t frame_count = DynamicArray_GetLength(&self->call_frames);
|
||||||
CallFrame* top_frame = DynamicArray_GetPointer(&self->call_frames, frame_count - 1);
|
CallFrame* top_frame = DynamicArray_GetPointer(&self->call_frames, frame_count - 1);
|
||||||
if (
|
if (
|
||||||
top_frame->instruction_pointer >= top_frame->function->condition_token_start
|
top_frame->instruction_pointer >= top_frame->alternative->condition_token_start
|
||||||
&& top_frame->instruction_pointer <= top_frame->function->condition_token_end
|
&& top_frame->instruction_pointer <= top_frame->alternative->condition_token_end
|
||||||
) {
|
) {
|
||||||
// alternative executing
|
// alternative executing
|
||||||
while (top_frame->instruction_pointer <= top_frame->function->condition_token_end) {
|
while (top_frame->instruction_pointer <= top_frame->alternative->condition_token_end) {
|
||||||
Interpreter_ExecuteNext(self, top_frame->function->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), !=)) {
|
if (RPN(frame_count, DynamicArray_GetLength(&self->call_frames), !=)) {
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (top_frame->instruction_pointer == top_frame->alternative->condition_token_end + 1) {
|
||||||
|
// 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 {
|
} else {
|
||||||
// function executing
|
// function executing
|
||||||
while (top_frame->instruction_pointer <= top_frame->function->body_token_end) {
|
while (top_frame->instruction_pointer <= top_frame->alternative->body_token_end) {
|
||||||
Interpreter_ExecuteNext(self, top_frame->function->body_token_end);
|
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), !=)) {
|
if (RPN(frame_count, DynamicArray_GetLength(&self->call_frames), !=)) {
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -268,15 +615,14 @@ int Interpreter_RunFrame(Interpreter* self)
|
||||||
|
|
||||||
int Interpreter_Run(Interpreter* self)
|
int Interpreter_Run(Interpreter* self)
|
||||||
{
|
{
|
||||||
size_t frame_count;
|
size_t frame_count = 1;
|
||||||
do {
|
do {
|
||||||
frame_count = DynamicArray_GetLength(&self->call_frames);
|
|
||||||
|
|
||||||
if (Interpreter_RunFrame(self)) {
|
if (Interpreter_RunFrame(self)) {
|
||||||
// TODO: Return the error code
|
// TODO: Return the error code
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame_count = DynamicArray_GetLength(&self->call_frames);
|
||||||
} while (frame_count != 0);
|
} while (frame_count != 0);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -284,18 +630,28 @@ int Interpreter_Run(Interpreter* self)
|
||||||
int Interpreter_Interpret(Interpreter* self)
|
int Interpreter_Interpret(Interpreter* self)
|
||||||
{
|
{
|
||||||
CallFrame* first_frame;
|
CallFrame* first_frame;
|
||||||
FlupFunctionAlternative* file_function = FlupFunctionAlternative_Malloc(SIZE_MAX, SIZE_MAX, 0, DynamicArray_GetLength(self->tokens));
|
FlupFunctionAlternative* main_alternative = FlupFunctionAlternative_Malloc(SIZE_MAX-1, SIZE_MAX-1, 0, DynamicArray_GetLength(self->tokens));
|
||||||
if (file_function == NULL) {
|
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;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicArray_AppendEmpty(&self->call_frames, (void**) &first_frame);
|
DynamicArray_AppendEmpty(&self->call_frames, (void**) &first_frame);
|
||||||
if (CallFrame_Create(first_frame, file_function)) {
|
if (CallFrame_Create(first_frame, &main_function)) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
first_frame->instruction_pointer = 0;
|
||||||
|
|
||||||
Interpreter_Run(self);
|
Interpreter_Run(self);
|
||||||
|
|
||||||
|
free(main_alternative);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,17 +25,20 @@ typedef struct FlupFunction_s {
|
||||||
StringView name;
|
StringView name;
|
||||||
ParameterDefinition* parameters;
|
ParameterDefinition* parameters;
|
||||||
StringView return_type;
|
StringView return_type;
|
||||||
FlupFunctionAlternative* alternative;
|
FlupFunctionAlternative* alternatives;
|
||||||
|
struct FlupFunction_s* next;
|
||||||
} FlupFunction;
|
} FlupFunction;
|
||||||
|
|
||||||
enum ValueType {
|
enum ValueType {
|
||||||
VALUETYPE_INT64,
|
VALUETYPE_INT64,
|
||||||
VALUETYPE_DOUBLE
|
VALUETYPE_DOUBLE,
|
||||||
|
VALUETYPE_BOOLEAN,
|
||||||
};
|
};
|
||||||
|
|
||||||
union ValueContent {
|
union ValueContent {
|
||||||
int64_t i64;
|
int64_t i64;
|
||||||
double f64;
|
double f64;
|
||||||
|
bool boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Value_s {
|
typedef struct Value_s {
|
||||||
|
@ -43,13 +46,22 @@ typedef struct Value_s {
|
||||||
union ValueContent get;
|
union ValueContent get;
|
||||||
} Value;
|
} Value;
|
||||||
|
|
||||||
|
typedef struct FlupVariable_s {
|
||||||
|
StringView name;
|
||||||
|
Value value;
|
||||||
|
struct FlupVariable_s* next;
|
||||||
|
} FlupVariable;
|
||||||
|
|
||||||
typedef struct CallFrame_s {
|
typedef struct CallFrame_s {
|
||||||
size_t instruction_pointer;
|
size_t instruction_pointer;
|
||||||
/* ip = condition start : start
|
/* ip = condition start : start
|
||||||
* ip = condition_end + 1 : done
|
* ip = condition_end + 1 : done
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
FlupFunctionAlternative* function;
|
FlupFunction* self_function;
|
||||||
|
FlupFunctionAlternative* alternative;
|
||||||
|
FlupFunction* functions; // functions defined in this callframe
|
||||||
|
FlupVariable* variables; // variables defined in this callframe
|
||||||
DynamicArray stack; // Value
|
DynamicArray stack; // Value
|
||||||
Scratchpad memory_pad;
|
Scratchpad memory_pad;
|
||||||
} CallFrame;
|
} CallFrame;
|
||||||
|
|
|
@ -64,9 +64,9 @@ char* load_file_string(StringView path)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_read = fread(buffer, 1, length + 1, stream);
|
size_t objects_read = fread(buffer, length, 1, stream);
|
||||||
if (bytes_read != length) {
|
if (objects_read != 1) {
|
||||||
fprintf(stderr, "Fatal Error: Failed read %li bytes from script file, got only %li\n", length, bytes_read);
|
fprintf(stderr, "Fatal Error: Failed read %li bytes from script file, got only %li\n", length, objects_read);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ static Token _Tokenizer_IdentifierToken(StringView* source)
|
||||||
|
|
||||||
static Token _Tokenizer_SimpleToken(StringView* source)
|
static Token _Tokenizer_SimpleToken(StringView* source)
|
||||||
{
|
{
|
||||||
const char* literal_table[] = { "{", "}", "&", ":", "+", "->", "-", "*", "/", "|", "==", "!=", "<", "<=", ">", ">=", "," };
|
const char* literal_table[] = { "{", "}", "&", ":", "+", "->", "-", "*", "/", "|", "==", "!=", "<", "<=", ">", ">=", ",", ";" };
|
||||||
const enum TokenType type_table[] = {
|
const enum TokenType type_table[] = {
|
||||||
TOKENTYPE_LEFT_BRACE,
|
TOKENTYPE_LEFT_BRACE,
|
||||||
TOKENTYPE_RIGHT_BRACE,
|
TOKENTYPE_RIGHT_BRACE,
|
||||||
|
@ -115,6 +115,7 @@ static Token _Tokenizer_SimpleToken(StringView* source)
|
||||||
TOKENTYPE_GREATERTHAN,
|
TOKENTYPE_GREATERTHAN,
|
||||||
TOKENTYPE_GREATEREQUAL,
|
TOKENTYPE_GREATEREQUAL,
|
||||||
TOKENTYPE_COMMA,
|
TOKENTYPE_COMMA,
|
||||||
|
TOKENTYPE_SEMICOLON,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(literal_table) / sizeof(literal_table[0]); i++) {
|
for (size_t i = 0; i < sizeof(literal_table) / sizeof(literal_table[0]); i++) {
|
||||||
|
@ -205,5 +206,10 @@ const char* TokenType_ToString(enum TokenType type)
|
||||||
return "TOKENTYPE_GREATEREQUAL";
|
return "TOKENTYPE_GREATEREQUAL";
|
||||||
case TOKENTYPE_COMMA:
|
case TOKENTYPE_COMMA:
|
||||||
return "TOKENTYPE_COMMA";
|
return "TOKENTYPE_COMMA";
|
||||||
|
case TOKENTYPE_SEMICOLON:
|
||||||
|
return "TOKENTYPE_SEMICOLON";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "INVALID";
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ enum TokenType {
|
||||||
TOKENTYPE_PIPE,
|
TOKENTYPE_PIPE,
|
||||||
TOKENTYPE_ARROW,
|
TOKENTYPE_ARROW,
|
||||||
TOKENTYPE_COLON,
|
TOKENTYPE_COLON,
|
||||||
|
TOKENTYPE_SEMICOLON,
|
||||||
TOKENTYPE_EQUALITY,
|
TOKENTYPE_EQUALITY,
|
||||||
TOKENTYPE_INEQUALITY,
|
TOKENTYPE_INEQUALITY,
|
||||||
TOKENTYPE_LESSTHAN,
|
TOKENTYPE_LESSTHAN,
|
||||||
|
|
Loading…
Reference in a new issue