cleanup and implementation of builtin functions
This commit is contained in:
parent
78bb3321d8
commit
06f385d6b0
11 changed files with 621 additions and 302 deletions
|
@ -1,41 +1,9 @@
|
|||
#include "interpreter.h"
|
||||
#include "builtin-functions.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
static int CallFrame_Create(CallFrame* self, FlupFunction* self_function)
|
||||
{
|
||||
if (DynamicArray_Create(&self->stack, sizeof(Value), 8, NULL)) {
|
||||
return ENOMEM;
|
||||
}
|
||||
self->memory_pad.memory = NULL;
|
||||
self->self_function = self_function;
|
||||
self->alternative = self->self_function->alternatives;
|
||||
self->instruction_pointer = self->alternative->condition_token_start;
|
||||
|
||||
self->variables = NULL;
|
||||
self->functions = NULL;
|
||||
|
||||
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)
|
||||
{
|
||||
if (self->memory_pad.memory == NULL) {
|
||||
if (Scratchpad_Create(&self->memory_pad, 1024, NULL)) return NULL;
|
||||
}
|
||||
|
||||
return Scratchpad_ReserveAligned(&self->memory_pad, amount, alignment);
|
||||
}
|
||||
|
||||
static FlupFunctionAlternative* FlupFunctionAlternative_Malloc(size_t condition_token_start, size_t condition_token_end, size_t body_token_start, size_t body_token_end)
|
||||
{
|
||||
|
@ -49,6 +17,17 @@ static FlupFunctionAlternative* FlupFunctionAlternative_Malloc(size_t condition_
|
|||
return a;
|
||||
}
|
||||
|
||||
const char* standard_builtin_names[] = {
|
||||
"println",
|
||||
"duplicate",
|
||||
NULL
|
||||
};
|
||||
|
||||
const BuiltinFunction standard_builtin_functions[] = {
|
||||
BuiltinFunction_PrintLine,
|
||||
BuiltinFunction_Duplicate,
|
||||
};
|
||||
|
||||
int Interpreter_Create(Interpreter* self, DynamicArray* tokens)
|
||||
{
|
||||
if (DynamicArray_Create(&self->call_frames, sizeof(CallFrame), 16, NULL)) {
|
||||
|
@ -56,6 +35,9 @@ int Interpreter_Create(Interpreter* self, DynamicArray* tokens)
|
|||
}
|
||||
self->tokens = tokens;
|
||||
|
||||
self->builtin_names = standard_builtin_names;
|
||||
self->builtin_functions = standard_builtin_functions;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -113,7 +95,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
*pdef = CallFrame_Reserve(top_frame, sizeof(**pdef), alignof(**pdef));
|
||||
*pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition));
|
||||
if (*pdef == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
@ -192,7 +174,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
|||
nested_functions_count > 0);
|
||||
size_t body_end = top_frame->instruction_pointer;
|
||||
|
||||
*fdef = CallFrame_Reserve(top_frame, sizeof(**pdef), alignof(**pdef));
|
||||
*fdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition));
|
||||
if (*fdef == NULL) {
|
||||
return ENOMEM;
|
||||
}
|
||||
|
@ -208,7 +190,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// one token colon
|
||||
top_frame->instruction_pointer++;
|
||||
|
||||
|
@ -231,49 +213,23 @@ FlupFunction* Interpreter_FindFunction(Interpreter* self, StringView name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
bool _are_types_compatible(enum ValueType type, StringView type_name)
|
||||
int Interpreter_CallBuiltinFunction(Interpreter* self, CallFrame* parent_frame, Token* name)
|
||||
{
|
||||
if (StringView_Equal(type_name, StringView_FromString("any"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const enum ValueType type_mapping[] = {VALUETYPE_INT64, VALUETYPE_DOUBLE, VALUETYPE_BOOLEAN, VALUETYPE_BOOLEAN};
|
||||
const char* name_mapping[] = {"int", "double", "bool", "boolean"};
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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;
|
||||
return Interpreter_CallBuiltinFunction(self, parent_frame, name);
|
||||
}
|
||||
|
||||
CallFrame* new_frame;
|
||||
|
@ -300,7 +256,7 @@ int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token*
|
|||
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)) {
|
||||
if (!Value_TypeMatchesStringName(parameter_value->type, parameter_def->type)) {
|
||||
// TODO: Error message
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -318,137 +274,6 @@ int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token*
|
|||
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_GetParenthesizedRange(Interpreter* self, CallFrame* top_frame, size_t* paren_start, size_t* paren_end, size_t stop_token)
|
||||
{
|
||||
size_t open_paren_count = 0;
|
||||
|
@ -627,9 +452,14 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
|||
// TODO: Type-check the token
|
||||
StringView variable_name = identifier_token->get.identifier;
|
||||
|
||||
if (CallFrame_DefineVariable(top_frame, variable_name, variable_value)) {
|
||||
// TODO: Error message
|
||||
return EXIT_FAILURE;
|
||||
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
|
||||
|
@ -672,40 +502,6 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
|||
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;
|
||||
}
|
||||
|
||||
static bool CallFrame_IsExecutingCondition(CallFrame* frame)
|
||||
{
|
||||
return frame->instruction_pointer >= frame->alternative->condition_token_start
|
||||
&& frame->instruction_pointer <= frame->alternative->condition_token_end;
|
||||
}
|
||||
|
||||
static bool CallFrame_IsSelectingCondition(CallFrame* frame)
|
||||
{
|
||||
return frame->instruction_pointer == frame->alternative->condition_token_end + 1;
|
||||
}
|
||||
|
||||
static bool CallFrame_IsExecutingBody(CallFrame* frame)
|
||||
{
|
||||
return frame->instruction_pointer < frame->alternative->body_token_end;
|
||||
}
|
||||
|
||||
static bool CallFrame_IsReturningBody(CallFrame* frame)
|
||||
{
|
||||
return frame->instruction_pointer == frame->alternative->body_token_end;
|
||||
}
|
||||
|
||||
#define RPN(a,b,c) a c b
|
||||
int Interpreter_RunFrame(Interpreter* self)
|
||||
|
@ -779,7 +575,7 @@ int Interpreter_RunFrame(Interpreter* self)
|
|||
// StringView_Paste(function_name, top_frame->self_function->name);
|
||||
// printf("%s\n", function_name);
|
||||
|
||||
if (! _are_types_compatible(return_value.type, top_frame->self_function->return_type)) {
|
||||
if (!Value_TypeMatchesStringName(return_value.type, top_frame->self_function->return_type)) {
|
||||
// TODO: Error message
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
@ -834,11 +630,11 @@ int Interpreter_Interpret(Interpreter* self)
|
|||
}
|
||||
first_frame->instruction_pointer = 0;
|
||||
|
||||
Interpreter_Run(self);
|
||||
int run_code = Interpreter_Run(self);
|
||||
|
||||
free(main_alternative);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
return run_code;
|
||||
}
|
||||
|
||||
void Interpreter_Destroy(Interpreter* self)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue