implementation of useful error messages
This commit is contained in:
parent
2ce8200366
commit
c12e763b28
14 changed files with 295 additions and 68 deletions
|
@ -46,6 +46,6 @@ add_executable(Flup
|
||||||
submodules/utilitiec/src/utf8/utf-8.h
|
submodules/utilitiec/src/utf8/utf-8.h
|
||||||
submodules/utilitiec/src/cmakegen.sh
|
submodules/utilitiec/src/cmakegen.sh
|
||||||
submodules/utilitiec/src/CMakeLists.txt
|
submodules/utilitiec/src/CMakeLists.txt
|
||||||
submodules/utilitiec/src/errorcodes.h)
|
submodules/utilitiec/src/errorcodes.h src/error-message.c src/error-message.h)
|
||||||
|
|
||||||
target_link_libraries(Flup m)
|
target_link_libraries(Flup m)
|
||||||
|
|
|
@ -20,19 +20,21 @@
|
||||||
#include "builtin-functions.h"
|
#include "builtin-functions.h"
|
||||||
|
|
||||||
#include "value.h"
|
#include "value.h"
|
||||||
|
#include "error-message.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
int BuiltinFunction_Equality(CallFrame* top_frame)
|
int BuiltinFunction_Equality(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
Value v2;
|
Value v2;
|
||||||
|
|
||||||
CallFrame_StackPop(top_frame, &v1);
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
// TODO: Error message
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,18 +47,18 @@ int BuiltinFunction_Equality(CallFrame* top_frame)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_Plus(CallFrame* top_frame)
|
int BuiltinFunction_Plus(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
Value v2;
|
Value v2;
|
||||||
|
|
||||||
CallFrame_StackPop(top_frame, &v1);
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
// TODO: Error message
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (v1.type != v2.type) {
|
if (v1.type != v2.type) {
|
||||||
// TODO: Error message
|
ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ int BuiltinFunction_Plus(CallFrame* top_frame)
|
||||||
result.get.boolean = v2.get.boolean + v1.get.boolean;
|
result.get.boolean = v2.get.boolean + v1.get.boolean;
|
||||||
break;
|
break;
|
||||||
case VALUETYPE_OBJECT:
|
case VALUETYPE_OBJECT:
|
||||||
|
ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "+", &v1);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
case VALUETYPE_BYTE:
|
case VALUETYPE_BYTE:
|
||||||
return v1.get.byte + v2.get.byte;
|
return v1.get.byte + v2.get.byte;
|
||||||
|
@ -82,18 +85,18 @@ int BuiltinFunction_Plus(CallFrame* top_frame)
|
||||||
return CallFrame_StackPush(top_frame, &result);
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_Multiply(CallFrame* top_frame)
|
int BuiltinFunction_Multiply(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
Value v2;
|
Value v2;
|
||||||
|
|
||||||
CallFrame_StackPop(top_frame, &v1);
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
// TODO: Error message
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (v1.type != v2.type) {
|
if (v1.type != v2.type) {
|
||||||
// TODO: Error message
|
ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +113,7 @@ int BuiltinFunction_Multiply(CallFrame* top_frame)
|
||||||
result.get.boolean = v2.get.boolean * v1.get.boolean;
|
result.get.boolean = v2.get.boolean * v1.get.boolean;
|
||||||
break;
|
break;
|
||||||
case VALUETYPE_OBJECT:
|
case VALUETYPE_OBJECT:
|
||||||
|
ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "*", &v1);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
case VALUETYPE_BYTE:
|
case VALUETYPE_BYTE:
|
||||||
return v1.get.byte * v2.get.byte;
|
return v1.get.byte * v2.get.byte;
|
||||||
|
@ -119,18 +123,18 @@ int BuiltinFunction_Multiply(CallFrame* top_frame)
|
||||||
return CallFrame_StackPush(top_frame, &result);
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_Minus(CallFrame* top_frame)
|
int BuiltinFunction_Minus(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
Value v2;
|
Value v2;
|
||||||
|
|
||||||
CallFrame_StackPop(top_frame, &v1);
|
CallFrame_StackPop(top_frame, &v1);
|
||||||
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) {
|
||||||
// TODO: Error message
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (v1.type != v2.type) {
|
if (v1.type != v2.type) {
|
||||||
// TODO: Error message
|
ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +151,7 @@ int BuiltinFunction_Minus(CallFrame* top_frame)
|
||||||
result.get.boolean = v2.get.boolean - v1.get.boolean;
|
result.get.boolean = v2.get.boolean - v1.get.boolean;
|
||||||
break;
|
break;
|
||||||
case VALUETYPE_OBJECT:
|
case VALUETYPE_OBJECT:
|
||||||
|
ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "-", &v1);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
case VALUETYPE_BYTE:
|
case VALUETYPE_BYTE:
|
||||||
return v1.get.byte - v2.get.byte;
|
return v1.get.byte - v2.get.byte;
|
||||||
|
@ -156,11 +161,12 @@ int BuiltinFunction_Minus(CallFrame* top_frame)
|
||||||
return CallFrame_StackPush(top_frame, &result);
|
return CallFrame_StackPush(top_frame, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_Print(CallFrame* top_frame)
|
int BuiltinFunction_Print(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
|
|
||||||
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
||||||
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,9 +203,9 @@ int BuiltinFunction_Print(CallFrame* top_frame)
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_PrintLine(CallFrame* top_frame)
|
int BuiltinFunction_PrintLine(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
if (BuiltinFunction_Print(top_frame)) {
|
if (BuiltinFunction_Print(top_frame, interpreter)) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
} else {
|
} else {
|
||||||
puts("");
|
puts("");
|
||||||
|
@ -207,15 +213,17 @@ int BuiltinFunction_PrintLine(CallFrame* top_frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int BuiltinFunction_Duplicate(CallFrame* top_frame)
|
int BuiltinFunction_Duplicate(CallFrame* top_frame, Interpreter* interpreter)
|
||||||
{
|
{
|
||||||
Value v1;
|
Value v1;
|
||||||
|
|
||||||
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) {
|
||||||
|
ErrorMessage_EmptyStackError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CallFrame_StackPush(top_frame, &v1) || CallFrame_StackPush(top_frame, &v1)) {
|
if (CallFrame_StackPush(top_frame, &v1) || CallFrame_StackPush(top_frame, &v1)) {
|
||||||
|
ErrorMessage_StackPushError(interpreter, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,15 +22,16 @@
|
||||||
|
|
||||||
#include "callframe.h"
|
#include "callframe.h"
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
int BuiltinFunction_Minus(CallFrame* top_frame);
|
int BuiltinFunction_Minus(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_Plus(CallFrame* top_frame);
|
int BuiltinFunction_Plus(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_Multiply(CallFrame* top_frame);
|
int BuiltinFunction_Multiply(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_Equality(CallFrame* top_frame);
|
int BuiltinFunction_Equality(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_Print(CallFrame* top_frame);
|
int BuiltinFunction_Print(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_PrintLine(CallFrame* top_frame);
|
int BuiltinFunction_PrintLine(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
int BuiltinFunction_Duplicate(CallFrame* top_frame);
|
int BuiltinFunction_Duplicate(CallFrame* top_frame, Interpreter* interpreter);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
56
src/error-message.c
Normal file
56
src/error-message.c
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
//
|
||||||
|
// Created by UserAlex on 10.10.2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "error-message.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
#include "value.h"
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
|
||||||
|
void ErrorMessage_err(char* message, Interpreter* interpreter, CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
Token* token = Interpreter_ExpectToken(interpreter, top_frame, top_frame->instruction_pointer + 1);
|
||||||
|
printf("Error in line: % " PRIi32 ", column: %" PRIi32, token->context.row, token->context.col);
|
||||||
|
printf(": %s\n", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorMessage_EmptyStackError(Interpreter* interpreter, CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
ErrorMessage_err("Trying to pop from stack while stack is empty", interpreter, top_frame);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorMessage_StackPushError(Interpreter* interpreter, CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
ErrorMessage_err("Error while trying to push to stack", interpreter, top_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ErrorMessage_IncompatibleTypesError(Interpreter* interpreter, CallFrame* top_frame, Value* expect, Value* got)
|
||||||
|
{
|
||||||
|
// TODO: die nächsten drei Zeilen kommen in den anderen Funktionen auch so ähnlich vor -> da am besten in Funktion auslagern
|
||||||
|
size_t total_length = snprintf(NULL, 0, "Incompatible types, expected %s but got %s", Value_ToString(expect->type), Value_ToString(got->type));
|
||||||
|
char string[total_length + 1];
|
||||||
|
snprintf(string, total_length + 1, "Incompatible types, expected %s but got %s", Value_ToString(expect->type), Value_ToString(got->type));
|
||||||
|
ErrorMessage_err( string, interpreter, top_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorMessage_UnknownOperationForTypeError(Interpreter* interpreter, CallFrame* top_frame, char* operation, Value* value)
|
||||||
|
{
|
||||||
|
size_t total_length = snprintf(NULL, 0, "Unknown operation %s for type %s", operation, Value_ToString(value->type));
|
||||||
|
char string[total_length + 1];
|
||||||
|
snprintf(string, total_length + 1, "Unknown operation %s for type %s", operation, Value_ToString(value->type));
|
||||||
|
ErrorMessage_err( string, interpreter, top_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ErrorMessage_OutOfMemoryError(char* context, Interpreter* interpreter, CallFrame* top_frame)
|
||||||
|
{
|
||||||
|
size_t total_length = snprintf(NULL, 0, "Out of memory: %s", context);
|
||||||
|
char string[total_length + 1];
|
||||||
|
snprintf(string, total_length + 1, "Out of memory: %s", context);
|
||||||
|
ErrorMessage_err(string, interpreter, top_frame);
|
||||||
|
}
|
40
src/error-message.h
Normal file
40
src/error-message.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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_ERROR_MESSAGES_H
|
||||||
|
#define FLUP_ERROR_MESSAGES_H
|
||||||
|
|
||||||
|
#include "tokenizer.h"
|
||||||
|
#include "interpreter.h"
|
||||||
|
|
||||||
|
|
||||||
|
void ErrorMessage_err(char* message, Interpreter* interpreter, CallFrame* top_frame);
|
||||||
|
|
||||||
|
void ErrorMessage_EmptyStackError(Interpreter* interpreter, CallFrame* top_frame);
|
||||||
|
|
||||||
|
void ErrorMessage_StackPushError(Interpreter* interpreter, CallFrame* top_frame);
|
||||||
|
|
||||||
|
void ErrorMessage_IncompatibleTypesError(Interpreter* interpreter, CallFrame* top_frame, Value* expect, Value* got);
|
||||||
|
|
||||||
|
void ErrorMessage_UnknownOperationForTypeError(Interpreter* interpreter, CallFrame* top_frame, char* operation, Value* value);
|
||||||
|
|
||||||
|
void ErrorMessage_OutOfMemoryError(char* context, Interpreter* interpreter, CallFrame* top_frame);
|
||||||
|
|
||||||
|
#endif //FLUP_ERROR_MESSAGES_H
|
|
@ -1,6 +1,7 @@
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "builtin-functions.h"
|
#include "builtin-functions.h"
|
||||||
#include "object-type.h"
|
#include "object-type.h"
|
||||||
|
#include "error-message.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdalign.h>
|
#include <stdalign.h>
|
||||||
|
@ -90,16 +91,17 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st
|
||||||
top_frame->instruction_pointer++;
|
top_frame->instruction_pointer++;
|
||||||
|
|
||||||
if (parameter_type->type != TOKENTYPE_IDENTIFIER) {
|
if (parameter_type->type != TOKENTYPE_IDENTIFIER) {
|
||||||
// TODO: Error message
|
ErrorMessage_err("Expected identifier for parameter type-definition in function definition", self, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (parameter_name->type != TOKENTYPE_IDENTIFIER) {
|
if (parameter_name->type != TOKENTYPE_IDENTIFIER) {
|
||||||
// TODO: Error message
|
ErrorMessage_err("Expected identifier for parameter name-declaration in function definition", self, top_frame);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition));
|
*pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition));
|
||||||
if (*pdef == NULL) {
|
if (*pdef == NULL) {
|
||||||
|
ErrorMessage_OutOfMemoryError("Failed to reserve memory for CallFrame in Function parsefunction", self, top_frame);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +223,7 @@ int Interpreter_CallBuiltinFunction(Interpreter* self, CallFrame* parent_frame,
|
||||||
StringView function_name = name->get.identifier;
|
StringView function_name = name->get.identifier;
|
||||||
for (size_t i = 0; self->builtin_names[i] != NULL; i++) {
|
for (size_t i = 0; self->builtin_names[i] != NULL; i++) {
|
||||||
if (StringView_Equal(function_name, StringView_FromString(self->builtin_names[i]))) {
|
if (StringView_Equal(function_name, StringView_FromString(self->builtin_names[i]))) {
|
||||||
return self->builtin_functions[i](parent_frame);
|
return self->builtin_functions[i](parent_frame, self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,22 +352,22 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token)
|
||||||
|
|
||||||
case TOKENTYPE_EQUALITY:
|
case TOKENTYPE_EQUALITY:
|
||||||
{
|
{
|
||||||
return BuiltinFunction_Equality(top_frame);
|
return BuiltinFunction_Equality(top_frame, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
case TOKENTYPE_PLUS:
|
case TOKENTYPE_PLUS:
|
||||||
{
|
{
|
||||||
BuiltinFunction_Plus(top_frame);
|
BuiltinFunction_Plus(top_frame, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKENTYPE_MINUS:
|
case TOKENTYPE_MINUS:
|
||||||
{
|
{
|
||||||
BuiltinFunction_Minus(top_frame);
|
BuiltinFunction_Minus(top_frame, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TOKENTYPE_MULTIPLY:
|
case TOKENTYPE_MULTIPLY:
|
||||||
{
|
{
|
||||||
BuiltinFunction_Multiply(top_frame);
|
BuiltinFunction_Multiply(top_frame, self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
typedef struct Interpreter_s Interpreter;
|
typedef struct Interpreter_s Interpreter;
|
||||||
|
|
||||||
typedef int (*BuiltinFunction)(CallFrame *);
|
typedef int (*BuiltinFunction)(CallFrame *, Interpreter* interpreter);
|
||||||
|
|
||||||
struct Interpreter_s {
|
struct Interpreter_s {
|
||||||
const char** builtin_names;
|
const char** builtin_names;
|
||||||
|
@ -29,4 +29,6 @@ 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);
|
||||||
|
|
||||||
|
Token* Interpreter_ExpectToken(Interpreter* self, CallFrame* top_frame, size_t stop_index);
|
||||||
|
|
||||||
#endif //FLUP_INTERPRETER_H
|
#endif //FLUP_INTERPRETER_H
|
||||||
|
|
56
src/main.c
56
src/main.c
|
@ -20,15 +20,69 @@
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "../submodules/utilitiec/src/argumentc/argumentc.h"
|
#include "../submodules/utilitiec/src/argumentc/argumentc.h"
|
||||||
#include "interpreter.h"
|
#include "interpreter.h"
|
||||||
#include "tokenizer.h"
|
#include "tokenizer.h"
|
||||||
|
|
||||||
|
//Debug
|
||||||
|
//Temp
|
||||||
|
|
||||||
|
void tokencontent_tostring(Token* token) {
|
||||||
|
switch (token->type) {
|
||||||
|
case TOKENTYPE_INTEGER:
|
||||||
|
printf("%" PRIi64, token->get.integer);
|
||||||
|
break;
|
||||||
|
case TOKENTYPE_DOUBLE:
|
||||||
|
printf("%f", token->get.decimal);
|
||||||
|
break;
|
||||||
|
case TOKENTYPE_IDENTIFIER:
|
||||||
|
case TOKENTYPE_COMMENT:
|
||||||
|
case TOKENTYPE_STRING:
|
||||||
|
case TOKENTYPE_ERROR:
|
||||||
|
printf("%s", token->get.identifier);
|
||||||
|
break;
|
||||||
|
case TOKENTYPE_NONE:
|
||||||
|
case TOKENTYPE_LEFT_BRACE:
|
||||||
|
case TOKENTYPE_RIGHT_BRACE:
|
||||||
|
case TOKENTYPE_AMPERSAND:
|
||||||
|
case TOKENTYPE_PLUS:
|
||||||
|
case TOKENTYPE_MINUS:
|
||||||
|
case TOKENTYPE_MULTIPLY:
|
||||||
|
case TOKENTYPE_DIVIDE:
|
||||||
|
case TOKENTYPE_PIPE:
|
||||||
|
case TOKENTYPE_ARROW:
|
||||||
|
case TOKENTYPE_COLON:
|
||||||
|
case TOKENTYPE_SEMICOLON:
|
||||||
|
case TOKENTYPE_EQUALITY:
|
||||||
|
case TOKENTYPE_INEQUALITY:
|
||||||
|
case TOKENTYPE_LESSTHAN:
|
||||||
|
case TOKENTYPE_LESSEQUAL:
|
||||||
|
case TOKENTYPE_GREATERTHAN:
|
||||||
|
case TOKENTYPE_GREATEREQUAL:
|
||||||
|
case TOKENTYPE_COMMA:
|
||||||
|
case TOKENTYPE_BIND:
|
||||||
|
case TOKENTYPE_AS:
|
||||||
|
case TOKENTYPE_LEFT_PAREN:
|
||||||
|
case TOKENTYPE_RIGHT_PAREN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_token(Token* token) {
|
||||||
|
printf("Token: type: %s, TokenContent: ", TokenType_ToString(token->type));
|
||||||
|
tokencontent_tostring(token);
|
||||||
|
printf(" , contex: row: %i, col: %i\n", token->context.row, token->context.col);
|
||||||
|
}
|
||||||
|
|
||||||
int tokenize_all(StringView source, DynamicArray* a)
|
int tokenize_all(StringView source, DynamicArray* a)
|
||||||
{
|
{
|
||||||
|
TokenContext context = {.row = 1, .col = 1};
|
||||||
Token t;
|
Token t;
|
||||||
while ((t = Tokenizer_NextToken(&source)).type != TOKENTYPE_NONE) {
|
while ((t = Tokenizer_NextToken(&source, &context)).type != TOKENTYPE_NONE) {
|
||||||
|
//Debug
|
||||||
|
print_token(&t);
|
||||||
int append_code = DynamicArray_Append(a, &t);
|
int append_code = DynamicArray_Append(a, &t);
|
||||||
if (append_code) return append_code;
|
if (append_code) return append_code;
|
||||||
if (t.type == TOKENTYPE_ERROR) break;
|
if (t.type == TOKENTYPE_ERROR) break;
|
||||||
|
|
|
@ -53,27 +53,40 @@ static Token _Tokenizer_ParseDouble(bool negative, StringView integerPart, Strin
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token _Tokenizer_NumberToken(StringView* source)
|
static Token _Tokenizer_NumberToken(StringView* source, TokenContext* current)
|
||||||
{
|
{
|
||||||
|
uint32_t token_length = 0;
|
||||||
bool negative = false;
|
bool negative = false;
|
||||||
if (StringView_StartsWith(*source, StringView_FromString("-"))) {
|
if (StringView_StartsWith(*source, StringView_FromString("-"))) {
|
||||||
negative = true;
|
negative = true;
|
||||||
*source = StringView_Drop(*source, 1);
|
*source = StringView_Drop(*source, 1);
|
||||||
|
token_length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView integerPart = StringViewOfNumberTillNextNonDigit(source);
|
StringView integerPart = StringViewOfNumberTillNextNonDigit(source);
|
||||||
|
token_length += integerPart.length;
|
||||||
bool has_point = false;
|
bool has_point = false;
|
||||||
if (source->length != 0 && source->source[0] == '.') {
|
if (source->length != 0 && source->source[0] == '.') {
|
||||||
*source = StringView_Drop(*source, 1);
|
*source = StringView_Drop(*source, 1);
|
||||||
has_point = true;
|
has_point = true;
|
||||||
|
token_length++;
|
||||||
}
|
}
|
||||||
StringView decimalPart = StringViewOfNumberTillNextNonDigit(source);
|
StringView decimalPart = StringViewOfNumberTillNextNonDigit(source);
|
||||||
|
token_length += decimalPart.length;
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
|
||||||
if (has_point) {
|
if (has_point) {
|
||||||
return _Tokenizer_ParseDouble(negative, integerPart, decimalPart);
|
token = _Tokenizer_ParseDouble(negative, integerPart, decimalPart);
|
||||||
} else {
|
} else {
|
||||||
return _Tokenizer_ParseInt64(negative, integerPart);
|
token = _Tokenizer_ParseInt64(negative, integerPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//udpate context
|
||||||
|
token.context = *current;
|
||||||
|
current->col += token_length;
|
||||||
|
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _Tokenizer_IdentifierLetter(char c)
|
static bool _Tokenizer_IdentifierLetter(char c)
|
||||||
|
@ -81,17 +94,21 @@ static bool _Tokenizer_IdentifierLetter(char c)
|
||||||
return isalnum(c);
|
return isalnum(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token _Tokenizer_IdentifierToken(StringView* source)
|
static Token _Tokenizer_IdentifierToken(StringView* source, TokenContext* current)
|
||||||
{
|
{
|
||||||
StringView identifier = StringView_TakeWhile(*source, _Tokenizer_IdentifierLetter);
|
StringView identifier = StringView_TakeWhile(*source, _Tokenizer_IdentifierLetter);
|
||||||
*source = StringView_Drop(*source, identifier.length);
|
*source = StringView_Drop(*source, identifier.length);
|
||||||
|
|
||||||
return (Token) {
|
Token token = (Token) {
|
||||||
.type = TOKENTYPE_IDENTIFIER,
|
.type = TOKENTYPE_IDENTIFIER,
|
||||||
.get = {
|
.get = {
|
||||||
.identifier = identifier,
|
.identifier = identifier,
|
||||||
}
|
},
|
||||||
|
.context = *current
|
||||||
};
|
};
|
||||||
|
|
||||||
|
current->col += identifier.length;
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _Tokenizer_ContinueCommentFunction(char c)
|
static bool _Tokenizer_ContinueCommentFunction(char c)
|
||||||
|
@ -104,7 +121,7 @@ static bool _Tokenizer_ContinueStringFunction(char c)
|
||||||
return c != '"';
|
return c != '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token _Tokenizer_SimpleToken(StringView* source)
|
static Token _Tokenizer_SimpleToken(StringView* source, TokenContext* current)
|
||||||
{
|
{
|
||||||
const char* literal_table[] = { "{", "}", "&", ":", "+", "->", "-", "*", "/", "|", "==", "!=", "<", "<=", ">", ">=", ",", ";", "bind", "as", "(", ")" };
|
const char* literal_table[] = { "{", "}", "&", ":", "+", "->", "-", "*", "/", "|", "==", "!=", "<", "<=", ">", ">=", ",", ";", "bind", "as", "(", ")" };
|
||||||
const enum TokenType type_table[] = {
|
const enum TokenType type_table[] = {
|
||||||
|
@ -136,26 +153,32 @@ static Token _Tokenizer_SimpleToken(StringView* source)
|
||||||
StringView literal_view = StringView_FromString(literal_table[i]);
|
StringView literal_view = StringView_FromString(literal_table[i]);
|
||||||
if (StringView_StartsWith(*source, literal_view)) {
|
if (StringView_StartsWith(*source, literal_view)) {
|
||||||
*source = StringView_Drop(*source, literal_view.length);
|
*source = StringView_Drop(*source, literal_view.length);
|
||||||
return (Token) {
|
Token token = (Token) {
|
||||||
.type = type_table[i],
|
.type = type_table[i],
|
||||||
.get = { .identifier = STRINGVIEW_NONE }
|
.get = { .identifier = STRINGVIEW_NONE },
|
||||||
|
.context = *current
|
||||||
};
|
};
|
||||||
|
current->col += literal_view.length;
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return TOKEN_NONE;
|
return TOKEN_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token _Tokenizer_CommentToken(StringView* source)
|
Token _Tokenizer_CommentToken(StringView* source, TokenContext* current)
|
||||||
{
|
{
|
||||||
StringView comment = StringView_SpanWhile(source, _Tokenizer_ContinueCommentFunction);
|
StringView comment = StringView_SpanWhile(source, _Tokenizer_ContinueCommentFunction);
|
||||||
|
|
||||||
return (Token) {
|
Token token = (Token) {
|
||||||
.type = TOKENTYPE_COMMENT,
|
.type = TOKENTYPE_COMMENT,
|
||||||
.get = { .identifier = comment },
|
.get = { .identifier = comment },
|
||||||
|
.context = *current
|
||||||
};
|
};
|
||||||
|
current->col += comment.length;
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token _Tokenizer_StringToken(StringView* source)
|
Token _Tokenizer_StringToken(StringView* source, TokenContext* current)
|
||||||
{
|
{
|
||||||
*source = StringView_Drop(*source, 1);
|
*source = StringView_Drop(*source, 1);
|
||||||
StringView string = StringView_SpanWhile(source, _Tokenizer_ContinueStringFunction);
|
StringView string = StringView_SpanWhile(source, _Tokenizer_ContinueStringFunction);
|
||||||
|
@ -163,15 +186,34 @@ Token _Tokenizer_StringToken(StringView* source)
|
||||||
string.length += 2;
|
string.length += 2;
|
||||||
*source = StringView_Drop(*source, 1);
|
*source = StringView_Drop(*source, 1);
|
||||||
|
|
||||||
return (Token) {
|
Token token = (Token) {
|
||||||
.type = TOKENTYPE_STRING,
|
.type = TOKENTYPE_STRING,
|
||||||
.get = { .identifier = string },
|
.get = { .identifier = string },
|
||||||
|
.context = *current
|
||||||
};
|
};
|
||||||
|
|
||||||
|
size_t newline_count = StringView_Count(string, StringView_FromString("\n"));
|
||||||
|
if(newline_count == 0) {
|
||||||
|
current->col += string.length;
|
||||||
|
} else {
|
||||||
|
current->row += newline_count;
|
||||||
|
current->col = 1;
|
||||||
|
StringView last_newline_split;
|
||||||
|
StringView_LastSplit(&last_newline_split, &string, StringView_FromString("\n"));
|
||||||
|
current->col += last_newline_split.length;
|
||||||
|
}
|
||||||
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
Token Tokenizer_NextToken(StringView* source)
|
Token Tokenizer_NextToken(StringView* source, TokenContext* context)
|
||||||
{
|
{
|
||||||
while (source->length != 0 && isspace(source->source[0])) {
|
while (source->length != 0 && isspace(source->source[0])) {
|
||||||
|
if (source->source[0] == '\n') {
|
||||||
|
context->col = 1;
|
||||||
|
context->row++;
|
||||||
|
} else {
|
||||||
|
context->col++;
|
||||||
|
}
|
||||||
0[source] = StringView_Slice(*source, 1, source->length);
|
0[source] = StringView_Slice(*source, 1, source->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +222,7 @@ Token Tokenizer_NextToken(StringView* source)
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Token simple_token = _Tokenizer_SimpleToken(source);
|
Token simple_token = _Tokenizer_SimpleToken(source, context);
|
||||||
if (simple_token.type != TOKENTYPE_NONE) {
|
if (simple_token.type != TOKENTYPE_NONE) {
|
||||||
return simple_token;
|
return simple_token;
|
||||||
}
|
}
|
||||||
|
@ -188,16 +230,18 @@ Token Tokenizer_NextToken(StringView* source)
|
||||||
|
|
||||||
if (isdigit(source->source[0]) || StringView_StartsWith(*source, StringView_FromString("-"))) {
|
if (isdigit(source->source[0]) || StringView_StartsWith(*source, StringView_FromString("-"))) {
|
||||||
// parse int/double
|
// parse int/double
|
||||||
return _Tokenizer_NumberToken(source);
|
return _Tokenizer_NumberToken(source, context);
|
||||||
} else if (isalpha(source->source[0])) {
|
} else if (isalpha(source->source[0])) {
|
||||||
// parse name
|
// parse name
|
||||||
return _Tokenizer_IdentifierToken(source);
|
return _Tokenizer_IdentifierToken(source, context);
|
||||||
} else if (StringView_StartsWith(*source, StringView_FromString("#"))) {
|
} else if (StringView_StartsWith(*source, StringView_FromString("#"))) {
|
||||||
return _Tokenizer_CommentToken(source);
|
return _Tokenizer_CommentToken(source, context);
|
||||||
} else if (StringView_StartsWith(*source, StringView_FromString("\""))) {
|
} else if (StringView_StartsWith(*source, StringView_FromString("\""))) {
|
||||||
return _Tokenizer_StringToken(source);
|
return _Tokenizer_StringToken(source, context);
|
||||||
} else {
|
} else {
|
||||||
return (Token) {.type = TOKENTYPE_ERROR, .get = {.error = *source } };
|
Token non_token = (Token) {.type = TOKENTYPE_ERROR, .get = {.error = *source }, .context = *context };
|
||||||
|
context->col++;
|
||||||
|
return non_token;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,15 +43,21 @@ union TokenContent {
|
||||||
double decimal;
|
double decimal;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct TokenContext_s {
|
||||||
|
uint32_t row;
|
||||||
|
uint32_t col;
|
||||||
|
} TokenContext;
|
||||||
|
|
||||||
typedef struct Token_s {
|
typedef struct Token_s {
|
||||||
enum TokenType type;
|
enum TokenType type;
|
||||||
union TokenContent get;
|
union TokenContent get;
|
||||||
|
TokenContext context;
|
||||||
} Token;
|
} Token;
|
||||||
|
|
||||||
|
|
||||||
#define TOKEN_NONE ((Token) {.type = TOKENTYPE_NONE, .get = {.error = STRINGVIEW_NONE } } )
|
#define TOKEN_NONE ((Token) {.type = TOKENTYPE_NONE, .get = {.error = STRINGVIEW_NONE } } )
|
||||||
|
|
||||||
Token Tokenizer_NextToken(StringView* source);
|
Token Tokenizer_NextToken(StringView* source, TokenContext* context);
|
||||||
const char* TokenType_ToString(enum TokenType type);
|
const char* TokenType_ToString(enum TokenType type);
|
||||||
|
|
||||||
#endif //header guard
|
#endif //header guard
|
||||||
|
|
27
src/value.c
27
src/value.c
|
@ -57,24 +57,23 @@ bool Value_Equal(Value* v1, Value* v2)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char * Value_ToString(enum ValueType type) {
|
||||||
|
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 (type == type_mapping[i] ) {
|
||||||
|
return name_mapping[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name)
|
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name)
|
||||||
{
|
{
|
||||||
if (StringView_Equal(type_name, StringView_FromString("any"))) {
|
if (StringView_Equal(type_name, StringView_FromString("any"))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
return StringView_Equal(type_name, StringView_FromString(Value_ToString(type)));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ typedef struct Value_s {
|
||||||
|
|
||||||
bool Value_IsTruthy(Value* v);
|
bool Value_IsTruthy(Value* v);
|
||||||
bool Value_Equal(Value* v1, Value* v2);
|
bool Value_Equal(Value* v1, Value* v2);
|
||||||
|
|
||||||
|
const char * Value_ToString(enum ValueType type);
|
||||||
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name);
|
bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ fib: int n -> int
|
||||||
| iterations 0 == -> a b +
|
| iterations 0 == -> a b +
|
||||||
| 1 -> a b + println b a b + iterations 1 - fib
|
| 1 -> a b + println b a b + iterations 1 - fib
|
||||||
;
|
;
|
||||||
1 1 n fib
|
0 1 n fib
|
||||||
;
|
;
|
||||||
|
|
||||||
50 fib println
|
50 fib println
|
||||||
|
|
13
test-inputs/test_error_messages.flup
Normal file
13
test-inputs/test_error_messages.flup
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# test stack pop while stack empty in builtin-function equal
|
||||||
|
# 0 ==
|
||||||
|
|
||||||
|
# test incompatible types
|
||||||
|
# 1 1.1 +
|
||||||
|
|
||||||
|
# test expected identifier for type in function param list
|
||||||
|
# a: 1 b -> int
|
||||||
|
# |1 -> 0
|
||||||
|
|
||||||
|
# test expected identifier for name in function param list
|
||||||
|
a: int 1 -> int
|
||||||
|
|1 -> 0
|
Loading…
Reference in a new issue