Compare commits
6 commits
b7f11d1fc2
...
bba1e2a00f
Author | SHA1 | Date | |
---|---|---|---|
bba1e2a00f | |||
b17df7cb40 | |||
2b9e33b106 | |||
|
06f385d6b0 | ||
|
78bb3321d8 | ||
|
2fefd8c04f |
16 changed files with 760 additions and 317 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
||||||
bin/
|
bin/
|
||||||
|
build/
|
||||||
|
.idea/
|
||||||
|
|
51
CMakeLists.txt
Normal file
51
CMakeLists.txt
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
cmake_minimum_required(VERSION 3.21)
|
||||||
|
project(Flup C)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
|
||||||
|
include_directories(src)
|
||||||
|
include_directories(submodules/utilitiec/src)
|
||||||
|
include_directories(templates)
|
||||||
|
|
||||||
|
add_executable(Flup
|
||||||
|
src/interpreter.c
|
||||||
|
src/main.c
|
||||||
|
src/tokenizer.c
|
||||||
|
src/builtin-functions.c
|
||||||
|
src/callframe.c
|
||||||
|
src/value.c
|
||||||
|
submodules/utilitiec/src/allocator-interface/allocator-interface.c
|
||||||
|
submodules/utilitiec/src/allocator-interface/allocator-interface.h
|
||||||
|
submodules/utilitiec/src/allocator-interface/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/argumentc/argumentc.c
|
||||||
|
submodules/utilitiec/src/argumentc/argumentc.h
|
||||||
|
submodules/utilitiec/src/argumentc/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/arraylist/arraylist.c
|
||||||
|
submodules/utilitiec/src/arraylist/arraylist.h
|
||||||
|
submodules/utilitiec/src/arraylist/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/dynamicarray/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/dynamicarray/dynamicarray.c
|
||||||
|
submodules/utilitiec/src/dynamicarray/dynamicarray.h
|
||||||
|
submodules/utilitiec/src/dynamicbuffer/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/dynamicbuffer/dynamicbuffer.c
|
||||||
|
submodules/utilitiec/src/dynamicbuffer/dynamicbuffer.h
|
||||||
|
submodules/utilitiec/src/pointers/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/pointers/pointers.c
|
||||||
|
submodules/utilitiec/src/pointers/pointers.h
|
||||||
|
submodules/utilitiec/src/Scratchpad/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/Scratchpad/Scratchpad.c
|
||||||
|
submodules/utilitiec/src/Scratchpad/Scratchpad.h
|
||||||
|
submodules/utilitiec/src/siphash/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/siphash/siphash.c
|
||||||
|
submodules/utilitiec/src/siphash/siphash.h
|
||||||
|
submodules/utilitiec/src/StringView/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/StringView/StringView.c
|
||||||
|
submodules/utilitiec/src/StringView/StringView.h
|
||||||
|
submodules/utilitiec/src/utf8/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/utf8/utf-8.c
|
||||||
|
submodules/utilitiec/src/utf8/utf-8.h
|
||||||
|
submodules/utilitiec/src/cmakegen.sh
|
||||||
|
submodules/utilitiec/src/CMakeLists.txt
|
||||||
|
submodules/utilitiec/src/errorcodes.h)
|
||||||
|
|
||||||
|
target_link_libraries(Flup m)
|
154
src/builtin-functions.c
Normal file
154
src/builtin-functions.c
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "builtin-functions.h"
|
||||||
|
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
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 BuiltinFunction_PrintLine(CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Value v1;
|
||||||
|
|
||||||
|
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (v1.type) {
|
||||||
|
case VALUETYPE_INT64:
|
||||||
|
printf("%i\n", v1.get.i64);
|
||||||
|
break;
|
||||||
|
case VALUETYPE_DOUBLE:
|
||||||
|
printf("%f\n", v1.get.f64);
|
||||||
|
break;
|
||||||
|
case VALUETYPE_BOOLEAN:
|
||||||
|
if (v1.get.boolean) {
|
||||||
|
printf("true\n");
|
||||||
|
} else {
|
||||||
|
printf("false\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BuiltinFunction_Duplicate(CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Value v1;
|
||||||
|
|
||||||
|
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CallFrame_StackPush(top_frame, &v1) || CallFrame_StackPush(top_frame, &v1)) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
34
src/builtin-functions.h
Normal file
34
src/builtin-functions.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef FLUP_BUILTINFUNCTION_H
|
||||||
|
#define FLUP_BUILTINFUNCTION_H
|
||||||
|
|
||||||
|
#include "callframe.h"
|
||||||
|
#include "tokenizer.h"
|
||||||
|
|
||||||
|
|
||||||
|
int BuiltinFunction_Minus(CallFrame* top_frame);
|
||||||
|
int BuiltinFunction_Plus(CallFrame* top_frame);
|
||||||
|
int BuiltinFunction_Equality(CallFrame* top_frame);
|
||||||
|
int BuiltinFunction_PrintLine(CallFrame* top_frame);
|
||||||
|
int BuiltinFunction_Duplicate(CallFrame* top_frame);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
125
src/callframe.c
Normal file
125
src/callframe.c
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "callframe.h"
|
||||||
|
|
||||||
|
#include <stdalign.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallFrame_Destroy(CallFrame* self)
|
||||||
|
{
|
||||||
|
if (self->memory_pad.memory != NULL) {
|
||||||
|
Scratchpad_Destroy(&self->memory_pad);
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicArray_Destroy(&self->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CallFrame_IsExecutingCondition(CallFrame* frame)
|
||||||
|
{
|
||||||
|
return frame->instruction_pointer >= frame->alternative->condition_token_start
|
||||||
|
&& frame->instruction_pointer <= frame->alternative->condition_token_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CallFrame_IsSelectingCondition(CallFrame* frame)
|
||||||
|
{
|
||||||
|
return frame->instruction_pointer == frame->alternative->condition_token_end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CallFrame_IsExecutingBody(CallFrame* frame)
|
||||||
|
{
|
||||||
|
return frame->instruction_pointer < frame->alternative->body_token_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CallFrame_IsReturningBody(CallFrame* frame)
|
||||||
|
{
|
||||||
|
return frame->instruction_pointer == frame->alternative->body_token_end;
|
||||||
|
}
|
||||||
|
|
59
src/callframe.h
Normal file
59
src/callframe.h
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef FLUP_CALLFRAME_H
|
||||||
|
#define FLUP_CALLFRAME_H
|
||||||
|
|
||||||
|
#include "function.h"
|
||||||
|
#include "variable.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include "dynamicarray/dynamicarray.h"
|
||||||
|
#include "StringView/StringView.h"
|
||||||
|
#include "Scratchpad/Scratchpad.h"
|
||||||
|
|
||||||
|
typedef struct CallFrame_s {
|
||||||
|
size_t instruction_pointer;
|
||||||
|
/* ip = condition start : start
|
||||||
|
* ip = condition_end + 1 : done
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
FlupFunction* self_function;
|
||||||
|
FlupFunctionAlternative* alternative;
|
||||||
|
FlupFunction* functions; // functions defined in this callframe
|
||||||
|
FlupVariable* variables; // variables defined in this callframe
|
||||||
|
DynamicArray stack; // Value
|
||||||
|
Scratchpad memory_pad;
|
||||||
|
} CallFrame;
|
||||||
|
|
||||||
|
int CallFrame_Create(CallFrame* self, FlupFunction* self_function);
|
||||||
|
void CallFrame_Destroy(CallFrame* self);
|
||||||
|
|
||||||
|
int CallFrame_DefineVariable(CallFrame* self, StringView name, Value value);
|
||||||
|
int CallFrame_StackPop(CallFrame* self, Value* dest);
|
||||||
|
int CallFrame_StackPush(CallFrame* self, Value* value);
|
||||||
|
FlupVariable* CallFrame_FindVariable(CallFrame* self, StringView name);
|
||||||
|
void* CallFrame_Reserve(CallFrame* self, size_t amount, size_t alignment);
|
||||||
|
bool CallFrame_IsExecutingCondition(CallFrame* frame);
|
||||||
|
bool CallFrame_IsSelectingCondition(CallFrame* frame);
|
||||||
|
bool CallFrame_IsExecutingBody(CallFrame* frame);
|
||||||
|
bool CallFrame_IsReturningBody(CallFrame* frame);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
48
src/function.h
Normal file
48
src/function.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef FLUP_FUNCTION_H
|
||||||
|
#define FLUP_FUNCTION_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "StringView/StringView.h"
|
||||||
|
|
||||||
|
typedef struct FlupFunctionAlternative_s {
|
||||||
|
size_t condition_token_start;
|
||||||
|
size_t condition_token_end;
|
||||||
|
size_t body_token_start;
|
||||||
|
size_t body_token_end;
|
||||||
|
struct FlupFunctionAlternative_s* next;
|
||||||
|
} FlupFunctionAlternative;
|
||||||
|
|
||||||
|
typedef struct ParameterDefinition_s {
|
||||||
|
StringView type;
|
||||||
|
StringView name;
|
||||||
|
struct ParameterDefinition_s* next;
|
||||||
|
} ParameterDefinition;
|
||||||
|
|
||||||
|
typedef struct FlupFunction_s {
|
||||||
|
StringView name;
|
||||||
|
ParameterDefinition* parameters;
|
||||||
|
StringView return_type;
|
||||||
|
FlupFunctionAlternative* alternatives;
|
||||||
|
struct FlupFunction_s* next;
|
||||||
|
} FlupFunction;
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,41 +1,9 @@
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
|
#include "builtin-functions.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdalign.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)
|
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;
|
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)
|
int Interpreter_Create(Interpreter* self, DynamicArray* tokens)
|
||||||
{
|
{
|
||||||
if (DynamicArray_Create(&self->call_frames, sizeof(CallFrame), 16, NULL)) {
|
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->tokens = tokens;
|
||||||
|
|
||||||
|
self->builtin_names = standard_builtin_names;
|
||||||
|
self->builtin_functions = standard_builtin_functions;
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +55,16 @@ Token* Interpreter_ExpectToken(Interpreter* self, CallFrame* top_frame, size_t s
|
||||||
return Interpreter_GetToken(self, top_frame->instruction_pointer);
|
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)
|
int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t stop_index)
|
||||||
{
|
{
|
||||||
FlupFunction* f = CallFrame_Reserve(top_frame, sizeof(FlupFunction), alignof(FlupFunction));
|
FlupFunction* f = CallFrame_Reserve(top_frame, sizeof(FlupFunction), alignof(FlupFunction));
|
||||||
|
@ -103,7 +95,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pdef = CallFrame_Reserve(top_frame, sizeof(**pdef), alignof(**pdef));
|
*pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition));
|
||||||
if (*pdef == NULL) {
|
if (*pdef == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -138,11 +130,14 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int nested_functions_count = 0;
|
||||||
|
|
||||||
FlupFunctionAlternative** fdef = &f->alternatives;
|
FlupFunctionAlternative** fdef = &f->alternatives;
|
||||||
while (alternative_start->type == TOKENTYPE_PIPE) {
|
while (alternative_start->type == TOKENTYPE_PIPE) {
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++; // pipe Token überspringen
|
||||||
size_t condition_start = top_frame->instruction_pointer;
|
size_t condition_start = top_frame->instruction_pointer;
|
||||||
|
|
||||||
|
// condition parsing
|
||||||
Token* current;
|
Token* current;
|
||||||
do {
|
do {
|
||||||
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
||||||
|
@ -150,23 +145,36 @@ 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
|
if (is_begin_of_nested_function_definition(self, top_frame, stop_index)) {
|
||||||
} while (current->type != TOKENTYPE_ARROW);
|
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;
|
size_t condition_end = top_frame->instruction_pointer - 2;
|
||||||
|
|
||||||
|
// condition body parsing
|
||||||
|
nested_functions_count = 0;
|
||||||
size_t body_start = top_frame->instruction_pointer;
|
size_t body_start = top_frame->instruction_pointer;
|
||||||
|
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
||||||
do {
|
do {
|
||||||
current = Interpreter_ExpectToken(self, top_frame, stop_index);
|
|
||||||
top_frame->instruction_pointer++;
|
|
||||||
if (current == NULL) {
|
if (current == NULL) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
// TODO: Count inner colon and semicolon to allow for nested functions
|
if (current->type == TOKENTYPE_COLON) {
|
||||||
} while (current->type != TOKENTYPE_PIPE && current->type != TOKENTYPE_SEMICOLON);
|
nested_functions_count++;
|
||||||
top_frame->instruction_pointer--;
|
}
|
||||||
|
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;
|
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) {
|
if (*fdef == NULL) {
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +190,7 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// one token colon
|
// one token colon
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
|
|
||||||
|
@ -205,49 +213,23 @@ FlupFunction* Interpreter_FindFunction(Interpreter* self, StringView name)
|
||||||
return NULL;
|
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"))) {
|
StringView function_name = name->get.identifier;
|
||||||
return true;
|
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);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return EXIT_FAILURE;
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token* name)
|
||||||
{
|
{
|
||||||
FlupFunction* function = Interpreter_FindFunction(self, name->get.identifier);
|
FlupFunction* function = Interpreter_FindFunction(self, name->get.identifier);
|
||||||
if (function == NULL) {
|
if (function == NULL) {
|
||||||
// TODO: Error message
|
return Interpreter_CallBuiltinFunction(self, parent_frame, name);
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CallFrame* new_frame;
|
CallFrame* new_frame;
|
||||||
|
@ -274,7 +256,7 @@ int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token*
|
||||||
ParameterDefinition* parameter_def = function->parameters;
|
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) {
|
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);
|
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
|
// TODO: Error message
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -292,137 +274,6 @@ int Interpreter_CallFunction(Interpreter* self, CallFrame* parent_frame, Token*
|
||||||
return EXIT_SUCCESS;
|
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)
|
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 open_paren_count = 0;
|
||||||
|
@ -601,9 +452,14 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
// TODO: Type-check the token
|
// TODO: Type-check the token
|
||||||
StringView variable_name = identifier_token->get.identifier;
|
StringView variable_name = identifier_token->get.identifier;
|
||||||
|
|
||||||
if (CallFrame_DefineVariable(top_frame, variable_name, variable_value)) {
|
FlupVariable* var = CallFrame_FindVariable(top_frame, variable_name);
|
||||||
// TODO: Error message
|
if (var != NULL) {
|
||||||
return EXIT_FAILURE;
|
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
|
top_frame->instruction_pointer += 2; // points to opening paren
|
||||||
|
@ -641,45 +497,11 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
case TOKENTYPE_NONE:
|
case TOKENTYPE_NONE:
|
||||||
case TOKENTYPE_ERROR:
|
case TOKENTYPE_ERROR:
|
||||||
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;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
#define RPN(a,b,c) a c b
|
||||||
int Interpreter_RunFrame(Interpreter* self)
|
int Interpreter_RunFrame(Interpreter* self)
|
||||||
|
@ -709,7 +531,7 @@ int Interpreter_RunFrame(Interpreter* self)
|
||||||
if (Value_IsTruthy(&alternative_success)) {
|
if (Value_IsTruthy(&alternative_success)) {
|
||||||
// into body
|
// into body
|
||||||
top_frame->instruction_pointer = top_frame->alternative->body_token_start;
|
top_frame->instruction_pointer = top_frame->alternative->body_token_start;
|
||||||
} else {
|
} else {
|
||||||
if (top_frame->alternative->next == NULL) {
|
if (top_frame->alternative->next == NULL) {
|
||||||
// TODO: Error message
|
// TODO: Error message
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -751,8 +573,9 @@ int Interpreter_RunFrame(Interpreter* self)
|
||||||
// char function_name[top_frame->self_function->name.length + 1];
|
// char function_name[top_frame->self_function->name.length + 1];
|
||||||
// memset(function_name, 0, sizeof(function_name));
|
// memset(function_name, 0, sizeof(function_name));
|
||||||
// StringView_Paste(function_name, top_frame->self_function->name);
|
// 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
|
// TODO: Error message
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@ -775,7 +598,7 @@ int Interpreter_RunFrame(Interpreter* self)
|
||||||
int Interpreter_Run(Interpreter* self)
|
int Interpreter_Run(Interpreter* self)
|
||||||
{
|
{
|
||||||
size_t frame_count = 1;
|
size_t frame_count = 1;
|
||||||
do {
|
do {
|
||||||
if (Interpreter_RunFrame(self)) {
|
if (Interpreter_RunFrame(self)) {
|
||||||
// TODO: Return the error code
|
// TODO: Return the error code
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -807,11 +630,11 @@ int Interpreter_Interpret(Interpreter* self)
|
||||||
}
|
}
|
||||||
first_frame->instruction_pointer = 0;
|
first_frame->instruction_pointer = 0;
|
||||||
|
|
||||||
Interpreter_Run(self);
|
int run_code = Interpreter_Run(self);
|
||||||
|
|
||||||
free(main_alternative);
|
free(main_alternative);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return run_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter_Destroy(Interpreter* self)
|
void Interpreter_Destroy(Interpreter* self)
|
||||||
|
|
|
@ -5,74 +5,24 @@
|
||||||
#include "../submodules/utilitiec/src/Scratchpad/Scratchpad.h"
|
#include "../submodules/utilitiec/src/Scratchpad/Scratchpad.h"
|
||||||
|
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
|
#include "callframe.h"
|
||||||
|
#include "value.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef struct FlupFunctionAlternative_s {
|
typedef struct Interpreter_s Interpreter;
|
||||||
size_t condition_token_start;
|
|
||||||
size_t condition_token_end;
|
|
||||||
size_t body_token_start;
|
|
||||||
size_t body_token_end;
|
|
||||||
struct FlupFunctionAlternative_s* next;
|
|
||||||
} FlupFunctionAlternative;
|
|
||||||
|
|
||||||
typedef struct ParameterDefinition_s {
|
typedef int (*BuiltinFunction)(CallFrame *);
|
||||||
StringView type;
|
|
||||||
StringView name;
|
|
||||||
struct ParameterDefinition_s* next;
|
|
||||||
} ParameterDefinition;
|
|
||||||
|
|
||||||
typedef struct FlupFunction_s {
|
struct Interpreter_s {
|
||||||
StringView name;
|
const char** builtin_names;
|
||||||
ParameterDefinition* parameters;
|
const BuiltinFunction* builtin_functions;
|
||||||
StringView return_type;
|
|
||||||
FlupFunctionAlternative* alternatives;
|
|
||||||
struct FlupFunction_s* next;
|
|
||||||
} FlupFunction;
|
|
||||||
|
|
||||||
enum ValueType {
|
|
||||||
VALUETYPE_INT64,
|
|
||||||
VALUETYPE_DOUBLE,
|
|
||||||
VALUETYPE_BOOLEAN,
|
|
||||||
};
|
|
||||||
|
|
||||||
union ValueContent {
|
|
||||||
int64_t i64;
|
|
||||||
double f64;
|
|
||||||
bool boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Value_s {
|
|
||||||
enum ValueType type;
|
|
||||||
union ValueContent get;
|
|
||||||
} Value;
|
|
||||||
|
|
||||||
typedef struct FlupVariable_s {
|
|
||||||
StringView name;
|
|
||||||
Value value;
|
|
||||||
struct FlupVariable_s* next;
|
|
||||||
} FlupVariable;
|
|
||||||
|
|
||||||
typedef struct CallFrame_s {
|
|
||||||
size_t instruction_pointer;
|
|
||||||
/* ip = condition start : start
|
|
||||||
* ip = condition_end + 1 : done
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
FlupFunction* self_function;
|
|
||||||
FlupFunctionAlternative* alternative;
|
|
||||||
FlupFunction* functions; // functions defined in this callframe
|
|
||||||
FlupVariable* variables; // variables defined in this callframe
|
|
||||||
DynamicArray stack; // Value
|
|
||||||
Scratchpad memory_pad;
|
|
||||||
} CallFrame;
|
|
||||||
|
|
||||||
typedef struct Interpreter_s {
|
|
||||||
DynamicArray* tokens;
|
DynamicArray* tokens;
|
||||||
DynamicArray call_frames; // stores CallFrame
|
DynamicArray call_frames; // stores CallFrame
|
||||||
} Interpreter;
|
};
|
||||||
|
|
||||||
int Interpreter_Create(Interpreter* self, DynamicArray* tokens);
|
int Interpreter_Create(Interpreter* self, DynamicArray* tokens);
|
||||||
int Interpreter_Interpret(Interpreter* self);
|
int Interpreter_Interpret(Interpreter* self);
|
||||||
void Interpreter_Destroy(Interpreter* self);
|
void Interpreter_Destroy(Interpreter* self);
|
||||||
|
|
||||||
#endif //header guard
|
#endif //FLUP_INTERPRETER_H
|
||||||
|
|
16
src/main.c
16
src/main.c
|
@ -39,7 +39,7 @@ int tokenize_all(StringView source, DynamicArray* a)
|
||||||
|
|
||||||
char* load_file_string(StringView path)
|
char* load_file_string(StringView path)
|
||||||
{
|
{
|
||||||
FILE* stream = fopen(path.source, "r");
|
FILE* stream = fopen(path.source, "rb");
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
fprintf(stderr, "Fatal Error: Failed to open file at %*s\n", (int) path.length, path.source);
|
fprintf(stderr, "Fatal Error: Failed to open file at %*s\n", (int) path.length, path.source);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -56,7 +56,10 @@ char* load_file_string(StringView path)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rewind(stream);
|
if (fseek(stream, 0, SEEK_SET)) {
|
||||||
|
perror("fseek");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char* buffer = malloc(length + 1);
|
char* buffer = malloc(length + 1);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
|
@ -64,9 +67,10 @@ char* load_file_string(StringView path)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t objects_read = fread(buffer, length, 1, stream);
|
size_t objects_read = fread(buffer, 1, length, stream);
|
||||||
if (objects_read != 1) {
|
if (objects_read != length) {
|
||||||
fprintf(stderr, "Fatal Error: Failed read %li bytes from script file, got only %li\n", length, objects_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;
|
||||||
}
|
}
|
||||||
|
@ -109,12 +113,12 @@ int main(int argc, const char* argv [])
|
||||||
Interpreter_Create(&interpreter, &tokens);
|
Interpreter_Create(&interpreter, &tokens);
|
||||||
|
|
||||||
|
|
||||||
Interpreter_Interpret(&interpreter);
|
int interpret_code = Interpreter_Interpret(&interpreter);
|
||||||
|
|
||||||
Interpreter_Destroy(&interpreter);
|
Interpreter_Destroy(&interpreter);
|
||||||
DynamicArray_Destroy(&tokens);
|
DynamicArray_Destroy(&tokens);
|
||||||
|
|
||||||
free(script_string);
|
free(script_string);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return interpret_code;
|
||||||
}
|
}
|
||||||
|
|
72
src/value.c
Normal file
72
src/value.c
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
49
src/value.h
Normal file
49
src/value.h
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef FLUP_VALUE_H
|
||||||
|
#define FLUP_VALUE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "StringView/StringView.h"
|
||||||
|
|
||||||
|
enum ValueType {
|
||||||
|
VALUETYPE_INT64,
|
||||||
|
VALUETYPE_DOUBLE,
|
||||||
|
VALUETYPE_BOOLEAN,
|
||||||
|
};
|
||||||
|
|
||||||
|
union ValueContent {
|
||||||
|
int64_t i64;
|
||||||
|
double f64;
|
||||||
|
bool boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Value_s {
|
||||||
|
enum ValueType type;
|
||||||
|
union ValueContent get;
|
||||||
|
} Value;
|
||||||
|
|
||||||
|
bool Value_IsTruthy(Value* v);
|
||||||
|
bool Value_Equal(Value* v1, Value* v2);
|
||||||
|
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
32
src/variable.h
Normal file
32
src/variable.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* This code is part of the programming language flup
|
||||||
|
* flup comes with ABSOLUTELY NO WARRANTY and is licensed under AGPL-3.0 or later.
|
||||||
|
* Copyright (C) 2024 VegOwOtenks
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
#ifndef FLUP_VARIABLE_H
|
||||||
|
#define FLUP_VARIABLE_H
|
||||||
|
|
||||||
|
#include "value.h"
|
||||||
|
#include "StringView/StringView.h"
|
||||||
|
|
||||||
|
typedef struct FlupVariable_s {
|
||||||
|
StringView name;
|
||||||
|
Value value;
|
||||||
|
struct FlupVariable_s* next;
|
||||||
|
} FlupVariable;
|
||||||
|
|
||||||
|
#endif
|
9
test-inputs/efficient-fibonacci.flup
Normal file
9
test-inputs/efficient-fibonacci.flup
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
fib: int n -> int
|
||||||
|
| 1 -> fib: int a int b int iterations -> int
|
||||||
|
| iterations 0 == -> a b +
|
||||||
|
| 1 -> a b + println b a b + iterations 1 - fib
|
||||||
|
;
|
||||||
|
1 1 n fib
|
||||||
|
;
|
||||||
|
|
||||||
|
50 fib println
|
7
test-inputs/fibonacci.flup
Normal file
7
test-inputs/fibonacci.flup
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
fib: int a -> int
|
||||||
|
| a 0 == -> 1
|
||||||
|
| a 1 == -> 1
|
||||||
|
| 1 1 == -> a 1 - fib a 2 - fib + duplicate println
|
||||||
|
;
|
||||||
|
|
||||||
|
10 fib
|
24
test-inputs/innere_function_definition.flup
Normal file
24
test-inputs/innere_function_definition.flup
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
test: int a -> int
|
||||||
|
| a 1 == -> inner: int b -> int
|
||||||
|
| b 0 == -> 5 fuenf
|
||||||
|
| 1 1 == -> 7 sieben
|
||||||
|
;
|
||||||
|
a inner
|
||||||
|
| 1 1 == -> 3 drei
|
||||||
|
;
|
||||||
|
|
||||||
|
fuenf: int a -> int
|
||||||
|
| 1 -> a
|
||||||
|
;
|
||||||
|
|
||||||
|
drei: int a -> int
|
||||||
|
| 1 -> a
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
sieben: int a -> int
|
||||||
|
| 1 -> a
|
||||||
|
;
|
||||||
|
|
||||||
|
0 test
|
Loading…
Reference in a new issue