implementation of useful error messages

This commit is contained in:
VegOwOtenks 2024-10-10 18:59:17 +02:00
parent 2ce8200366
commit c12e763b28
14 changed files with 295 additions and 68 deletions

View file

@ -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)

View file

@ -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;
} }

View file

@ -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
View 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
View 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

View file

@ -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;
} }

View file

@ -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

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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

View file

@ -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;
} }

View file

@ -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);

View file

@ -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

View 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