diff --git a/CMakeLists.txt b/CMakeLists.txt index 52109fb..16599e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,6 @@ add_executable(Flup submodules/utilitiec/src/utf8/utf-8.h submodules/utilitiec/src/cmakegen.sh 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) diff --git a/src/builtin-functions.c b/src/builtin-functions.c index 2ede45d..4f238db 100644 --- a/src/builtin-functions.c +++ b/src/builtin-functions.c @@ -20,19 +20,21 @@ #include "builtin-functions.h" #include "value.h" +#include "error-message.h" +#include "interpreter.h" #include #include #include -int BuiltinFunction_Equality(CallFrame* top_frame) +int BuiltinFunction_Equality(CallFrame* top_frame, Interpreter* interpreter) { Value v1; Value v2; CallFrame_StackPop(top_frame, &v1); if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) { - // TODO: Error message + ErrorMessage_EmptyStackError(interpreter, top_frame); 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 v2; CallFrame_StackPop(top_frame, &v1); if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) { - // TODO: Error message + ErrorMessage_EmptyStackError(interpreter, top_frame); return EXIT_FAILURE; } if (v1.type != v2.type) { - // TODO: Error message + ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2); return EXIT_FAILURE; } @@ -73,6 +75,7 @@ int BuiltinFunction_Plus(CallFrame* top_frame) result.get.boolean = v2.get.boolean + v1.get.boolean; break; case VALUETYPE_OBJECT: + ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "+", &v1); return EXIT_FAILURE; case VALUETYPE_BYTE: return v1.get.byte + v2.get.byte; @@ -82,18 +85,18 @@ int BuiltinFunction_Plus(CallFrame* top_frame) return CallFrame_StackPush(top_frame, &result); } -int BuiltinFunction_Multiply(CallFrame* top_frame) +int BuiltinFunction_Multiply(CallFrame* top_frame, Interpreter* interpreter) { Value v1; Value v2; CallFrame_StackPop(top_frame, &v1); if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) { - // TODO: Error message + ErrorMessage_EmptyStackError(interpreter, top_frame); return EXIT_FAILURE; } if (v1.type != v2.type) { - // TODO: Error message + ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2); return EXIT_FAILURE; } @@ -110,6 +113,7 @@ int BuiltinFunction_Multiply(CallFrame* top_frame) result.get.boolean = v2.get.boolean * v1.get.boolean; break; case VALUETYPE_OBJECT: + ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "*", &v1); return EXIT_FAILURE; case VALUETYPE_BYTE: return v1.get.byte * v2.get.byte; @@ -119,18 +123,18 @@ int BuiltinFunction_Multiply(CallFrame* top_frame) return CallFrame_StackPush(top_frame, &result); } -int BuiltinFunction_Minus(CallFrame* top_frame) +int BuiltinFunction_Minus(CallFrame* top_frame, Interpreter* interpreter) { Value v1; Value v2; CallFrame_StackPop(top_frame, &v1); if (CallFrame_StackPop(top_frame, &v2) != EXIT_SUCCESS) { - // TODO: Error message + ErrorMessage_EmptyStackError(interpreter, top_frame); return EXIT_FAILURE; } if (v1.type != v2.type) { - // TODO: Error message + ErrorMessage_IncompatibleTypesError(interpreter, top_frame, &v1, &v2); return EXIT_FAILURE; } @@ -147,6 +151,7 @@ int BuiltinFunction_Minus(CallFrame* top_frame) result.get.boolean = v2.get.boolean - v1.get.boolean; break; case VALUETYPE_OBJECT: + ErrorMessage_UnknownOperationForTypeError(interpreter, top_frame, "-", &v1); return EXIT_FAILURE; case VALUETYPE_BYTE: return v1.get.byte - v2.get.byte; @@ -156,11 +161,12 @@ int BuiltinFunction_Minus(CallFrame* top_frame) return CallFrame_StackPush(top_frame, &result); } -int BuiltinFunction_Print(CallFrame* top_frame) +int BuiltinFunction_Print(CallFrame* top_frame, Interpreter* interpreter) { Value v1; if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) { + ErrorMessage_EmptyStackError(interpreter, top_frame); return EXIT_FAILURE; } @@ -197,9 +203,9 @@ int BuiltinFunction_Print(CallFrame* top_frame) 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; } else { 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; if (CallFrame_StackPop(top_frame, &v1) != EXIT_SUCCESS) { + ErrorMessage_EmptyStackError(interpreter, top_frame); return EXIT_FAILURE; } if (CallFrame_StackPush(top_frame, &v1) || CallFrame_StackPush(top_frame, &v1)) { + ErrorMessage_StackPushError(interpreter, top_frame); return EXIT_FAILURE; } diff --git a/src/builtin-functions.h b/src/builtin-functions.h index fc62b55..1e32102 100644 --- a/src/builtin-functions.h +++ b/src/builtin-functions.h @@ -22,15 +22,16 @@ #include "callframe.h" #include "tokenizer.h" +#include "interpreter.h" -int BuiltinFunction_Minus(CallFrame* top_frame); -int BuiltinFunction_Plus(CallFrame* top_frame); -int BuiltinFunction_Multiply(CallFrame* top_frame); -int BuiltinFunction_Equality(CallFrame* top_frame); -int BuiltinFunction_Print(CallFrame* top_frame); -int BuiltinFunction_PrintLine(CallFrame* top_frame); -int BuiltinFunction_Duplicate(CallFrame* top_frame); +int BuiltinFunction_Minus(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_Plus(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_Multiply(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_Equality(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_Print(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_PrintLine(CallFrame* top_frame, Interpreter* interpreter); +int BuiltinFunction_Duplicate(CallFrame* top_frame, Interpreter* interpreter); #endif diff --git a/src/error-message.c b/src/error-message.c new file mode 100644 index 0000000..624831f --- /dev/null +++ b/src/error-message.c @@ -0,0 +1,56 @@ +// +// Created by UserAlex on 10.10.2024. +// + +#include "error-message.h" +#include "interpreter.h" +#include "value.h" + +#include +#include +#include + + +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); +} \ No newline at end of file diff --git a/src/error-message.h b/src/error-message.h new file mode 100644 index 0000000..eadaf89 --- /dev/null +++ b/src/error-message.h @@ -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 diff --git a/src/interpreter.c b/src/interpreter.c index a66e8f5..92f51a2 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1,6 +1,7 @@ #include "interpreter.h" #include "builtin-functions.h" #include "object-type.h" +#include "error-message.h" #include #include @@ -90,16 +91,17 @@ int Interpreter_ParseFunction(Interpreter* self, CallFrame* top_frame, size_t st top_frame->instruction_pointer++; 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; } 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; } *pdef = CallFrame_Reserve(top_frame, sizeof(ParameterDefinition), alignof(ParameterDefinition)); if (*pdef == NULL) { + ErrorMessage_OutOfMemoryError("Failed to reserve memory for CallFrame in Function parsefunction", self, top_frame); return ENOMEM; } @@ -221,7 +223,7 @@ int Interpreter_CallBuiltinFunction(Interpreter* self, CallFrame* parent_frame, StringView function_name = name->get.identifier; for (size_t i = 0; self->builtin_names[i] != NULL; i++) { if (StringView_Equal(function_name, StringView_FromString(self->builtin_names[i]))) { - return self->builtin_functions[i](parent_frame); + return self->builtin_functions[i](parent_frame, self); } } @@ -350,22 +352,22 @@ int Interpreter_ExecuteNext(Interpreter* self, size_t stop_token) case TOKENTYPE_EQUALITY: { - return BuiltinFunction_Equality(top_frame); + return BuiltinFunction_Equality(top_frame, self); } case TOKENTYPE_PLUS: { - BuiltinFunction_Plus(top_frame); + BuiltinFunction_Plus(top_frame, self); break; } case TOKENTYPE_MINUS: { - BuiltinFunction_Minus(top_frame); + BuiltinFunction_Minus(top_frame, self); break; } case TOKENTYPE_MULTIPLY: { - BuiltinFunction_Multiply(top_frame); + BuiltinFunction_Multiply(top_frame, self); break; } diff --git a/src/interpreter.h b/src/interpreter.h index 4b48a25..a204dbf 100644 --- a/src/interpreter.h +++ b/src/interpreter.h @@ -11,7 +11,7 @@ typedef struct Interpreter_s Interpreter; -typedef int (*BuiltinFunction)(CallFrame *); +typedef int (*BuiltinFunction)(CallFrame *, Interpreter* interpreter); struct Interpreter_s { const char** builtin_names; @@ -29,4 +29,6 @@ int Interpreter_Create(Interpreter* self, DynamicArray* tokens); int Interpreter_Interpret(Interpreter* self); void Interpreter_Destroy(Interpreter* self); +Token* Interpreter_ExpectToken(Interpreter* self, CallFrame* top_frame, size_t stop_index); + #endif //FLUP_INTERPRETER_H diff --git a/src/main.c b/src/main.c index 3d83bea..8f48405 100644 --- a/src/main.c +++ b/src/main.c @@ -20,15 +20,69 @@ #include #include +#include #include "../submodules/utilitiec/src/argumentc/argumentc.h" #include "interpreter.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) { + TokenContext context = {.row = 1, .col = 1}; 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); if (append_code) return append_code; if (t.type == TOKENTYPE_ERROR) break; diff --git a/src/tokenizer.c b/src/tokenizer.c index 3a95999..db4a535 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -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; if (StringView_StartsWith(*source, StringView_FromString("-"))) { negative = true; *source = StringView_Drop(*source, 1); + token_length++; } StringView integerPart = StringViewOfNumberTillNextNonDigit(source); + token_length += integerPart.length; bool has_point = false; if (source->length != 0 && source->source[0] == '.') { *source = StringView_Drop(*source, 1); has_point = true; + token_length++; } StringView decimalPart = StringViewOfNumberTillNextNonDigit(source); + token_length += decimalPart.length; + + Token token; if (has_point) { - return _Tokenizer_ParseDouble(negative, integerPart, decimalPart); + token = _Tokenizer_ParseDouble(negative, integerPart, decimalPart); } 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) @@ -81,17 +94,21 @@ static bool _Tokenizer_IdentifierLetter(char 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); *source = StringView_Drop(*source, identifier.length); - return (Token) { + Token token = (Token) { .type = TOKENTYPE_IDENTIFIER, .get = { .identifier = identifier, - } + }, + .context = *current }; + + current->col += identifier.length; + return token; } static bool _Tokenizer_ContinueCommentFunction(char c) @@ -104,7 +121,7 @@ static bool _Tokenizer_ContinueStringFunction(char c) return c != '"'; } -static Token _Tokenizer_SimpleToken(StringView* source) +static Token _Tokenizer_SimpleToken(StringView* source, TokenContext* current) { const char* literal_table[] = { "{", "}", "&", ":", "+", "->", "-", "*", "/", "|", "==", "!=", "<", "<=", ">", ">=", ",", ";", "bind", "as", "(", ")" }; const enum TokenType type_table[] = { @@ -136,26 +153,32 @@ static Token _Tokenizer_SimpleToken(StringView* source) StringView literal_view = StringView_FromString(literal_table[i]); if (StringView_StartsWith(*source, literal_view)) { *source = StringView_Drop(*source, literal_view.length); - return (Token) { + Token token = (Token) { .type = type_table[i], - .get = { .identifier = STRINGVIEW_NONE } + .get = { .identifier = STRINGVIEW_NONE }, + .context = *current }; + current->col += literal_view.length; + return token; } } return TOKEN_NONE; } -Token _Tokenizer_CommentToken(StringView* source) +Token _Tokenizer_CommentToken(StringView* source, TokenContext* current) { StringView comment = StringView_SpanWhile(source, _Tokenizer_ContinueCommentFunction); - return (Token) { + Token token = (Token) { .type = TOKENTYPE_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); StringView string = StringView_SpanWhile(source, _Tokenizer_ContinueStringFunction); @@ -163,15 +186,34 @@ Token _Tokenizer_StringToken(StringView* source) string.length += 2; *source = StringView_Drop(*source, 1); - return (Token) { + Token token = (Token) { .type = TOKENTYPE_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])) { + if (source->source[0] == '\n') { + context->col = 1; + context->row++; + } else { + context->col++; + } 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) { return simple_token; } @@ -188,16 +230,18 @@ Token Tokenizer_NextToken(StringView* source) if (isdigit(source->source[0]) || StringView_StartsWith(*source, StringView_FromString("-"))) { // parse int/double - return _Tokenizer_NumberToken(source); + return _Tokenizer_NumberToken(source, context); } else if (isalpha(source->source[0])) { // parse name - return _Tokenizer_IdentifierToken(source); + return _Tokenizer_IdentifierToken(source, context); } else if (StringView_StartsWith(*source, StringView_FromString("#"))) { - return _Tokenizer_CommentToken(source); + return _Tokenizer_CommentToken(source, context); } else if (StringView_StartsWith(*source, StringView_FromString("\""))) { - return _Tokenizer_StringToken(source); + return _Tokenizer_StringToken(source, context); } 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; } } diff --git a/src/tokenizer.h b/src/tokenizer.h index d8ea088..bb05337 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -43,15 +43,21 @@ union TokenContent { double decimal; }; +typedef struct TokenContext_s { + uint32_t row; + uint32_t col; +} TokenContext; + typedef struct Token_s { enum TokenType type; union TokenContent get; + TokenContext context; } Token; #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); #endif //header guard diff --git a/src/value.c b/src/value.c index f0edbca..d90f0ee 100644 --- a/src/value.c +++ b/src/value.c @@ -57,24 +57,23 @@ bool Value_Equal(Value* v1, Value* v2) 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) { 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; + return StringView_Equal(type_name, StringView_FromString(Value_ToString(type))); } diff --git a/src/value.h b/src/value.h index 855facb..7d57101 100644 --- a/src/value.h +++ b/src/value.h @@ -43,6 +43,8 @@ typedef struct Value_s { bool Value_IsTruthy(Value* v); bool Value_Equal(Value* v1, Value* v2); + +const char * Value_ToString(enum ValueType type); bool Value_TypeMatchesStringName(enum ValueType type, StringView type_name); diff --git a/test-inputs/efficient-fibonacci.flup b/test-inputs/efficient-fibonacci.flup index 9ff7b63..ad0a5e9 100644 --- a/test-inputs/efficient-fibonacci.flup +++ b/test-inputs/efficient-fibonacci.flup @@ -3,7 +3,7 @@ fib: int n -> int | iterations 0 == -> a b + | 1 -> a b + println b a b + iterations 1 - fib ; - 1 1 n fib + 0 1 n fib ; 50 fib println diff --git a/test-inputs/test_error_messages.flup b/test-inputs/test_error_messages.flup new file mode 100644 index 0000000..2679ff6 --- /dev/null +++ b/test-inputs/test_error_messages.flup @@ -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 \ No newline at end of file