├── tests ├── empty.ud ├── use-system.ud ├── operators.ud └── keywords.ud ├── Manual ├── ReadMe.md ├── Internals │ └── ReadMe.md └── Introduction │ └── ReadMe.md ├── compile_flags.txt ├── samples ├── HelloWorld.ud ├── Statment.ud ├── Expression.ud ├── Macro.ud ├── Vector.ud ├── Algorithm.ud ├── Shapes.ud └── kernel.ud ├── librarie ├── io │ ├── println.ud │ └── Stream.ud └── builtin.ud ├── udfore ├── source │ ├── SourceLocation.h │ ├── Source.c │ ├── Source.h │ ├── FileSource.c │ └── StringSource.c ├── ast │ ├── Program.h │ ├── Node.h │ ├── expression │ │ ├── Value.c │ │ ├── Identifier.c │ │ └── InfixOperator.c │ ├── Node.c │ ├── Expression.h │ ├── statement │ │ ├── ReturnStatement.c │ │ ├── ExpressionStatement.c │ │ ├── LetStatement.c │ │ └── BlockStatement.c │ ├── Program.c │ └── Statement.h ├── value │ ├── Value.h │ └── Value.c ├── utils │ ├── Utils.h │ ├── Buffer.h │ ├── Utils.c │ ├── Logger.h │ ├── Logger.c │ ├── Buffer.c │ ├── List.h │ └── List.c ├── lexer │ ├── Lexer.h │ └── Lexer.c ├── parser │ ├── Program.c │ ├── Parser.h │ ├── Expression.h │ ├── Parser.c │ ├── Statement.c │ └── Expression.c ├── main.c ├── token │ ├── Keyword.c │ ├── Token.c │ ├── Operator.c │ └── Token.h └── tests │ └── Lexer.test.c ├── .gitignore ├── README.md ├── Makefile ├── License.md └── udfore.svg /tests/empty.ud: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Manual/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Udfore -------------------------------------------------------------------------------- /compile_flags.txt: -------------------------------------------------------------------------------- 1 | -I. 2 | -------------------------------------------------------------------------------- /tests/use-system.ud: -------------------------------------------------------------------------------- 1 | use System; -------------------------------------------------------------------------------- /Manual/Internals/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Udfore -------------------------------------------------------------------------------- /Manual/Introduction/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Udfore -------------------------------------------------------------------------------- /tests/operators.ud: -------------------------------------------------------------------------------- 1 | = != > < := + ++ - -- * % / . .. -> ( ) { } [ ] , ; ? : 2 | -------------------------------------------------------------------------------- /samples/HelloWorld.ud: -------------------------------------------------------------------------------- 1 | take println from io; 2 | 3 | main 4 | { 5 | println("Hello, World!"); 6 | } 7 | -------------------------------------------------------------------------------- /librarie/io/println.ud: -------------------------------------------------------------------------------- 1 | take Size from builtin; 2 | 3 | function println(String line) -> Size 4 | { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /udfore/source/SourceLocation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct 4 | { 5 | int line; 6 | int column; 7 | } SourceLocation; 8 | -------------------------------------------------------------------------------- /tests/keywords.ud: -------------------------------------------------------------------------------- 1 | cast 2 | constructor 3 | destructor 4 | from 5 | function 6 | let 7 | module 8 | return 9 | spec 10 | take 11 | type 12 | use 13 | -------------------------------------------------------------------------------- /samples/Statment.ud: -------------------------------------------------------------------------------- 1 | let v1 := a; 2 | let v2 := b; 3 | let v3 := c; 4 | 5 | println(`{v1} + {v2} = {v3}`); 6 | 7 | if (pomme == poire) 8 | { 9 | print lol; 10 | } 11 | -------------------------------------------------------------------------------- /librarie/builtin.ud: -------------------------------------------------------------------------------- 1 | if @ArchIs64bit 2 | { 3 | type Size alias u64; 4 | type Ptr alias u64; 5 | } 6 | else 7 | { 8 | type Size alias u32; 9 | type Ptr alias u32; 10 | } 11 | -------------------------------------------------------------------------------- /samples/Expression.ud: -------------------------------------------------------------------------------- 1 | a; 2 | abc; 3 | dddd; 4 | _lol; 5 | pomme1234; 6 | 7 | a + b; 8 | b - c; 9 | a * b; 10 | b / c; 11 | 12 | a + b * c; 13 | pomme / a + b * c; 14 | 15 | 1 + 1; 16 | -------------------------------------------------------------------------------- /librarie/io/Stream.ud: -------------------------------------------------------------------------------- 1 | take Size from builtin; 2 | 3 | spec Stream 4 | { 5 | function write(const u8[] buffer, Size size) -> Size; 6 | function read(u8[] buffer, Size size) -> Size; 7 | } 8 | -------------------------------------------------------------------------------- /udfore/ast/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/ast/Node.h" 4 | #include "udfore/utils/List.h" 5 | 6 | struct ASTStatement; 7 | 8 | typedef struct 9 | { 10 | ASTNode node; 11 | 12 | List *statements; 13 | } ASTProgram; 14 | 15 | ASTProgram *astprogram_create(void); 16 | 17 | void astprogram_append_statement(ASTProgram *program, struct ASTStatement *statement); 18 | -------------------------------------------------------------------------------- /udfore/value/Value.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/utils/Buffer.h" 4 | 5 | typedef enum 6 | { 7 | VALUE_NONE, 8 | VALUE_S32, 9 | } ValueType; 10 | 11 | typedef struct 12 | { 13 | ValueType type; 14 | 15 | union { 16 | int32_t s32; 17 | }; 18 | } Value; 19 | 20 | void value_serialize(Value value, Buffer *buffer); 21 | 22 | Value value_create_s32(int32_t s32); -------------------------------------------------------------------------------- /udfore/utils/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define __create(__type) (__type *)calloc(1, sizeof(__type)); 10 | 11 | bool utils_is_white_space(char chr); 12 | 13 | bool utils_is_letter(char chr); 14 | 15 | bool utils_is_identifier(char chr); 16 | 17 | bool utils_is_number(char chr); 18 | -------------------------------------------------------------------------------- /udfore/lexer/Lexer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/source/Source.h" 4 | #include "udfore/source/SourceLocation.h" 5 | #include "udfore/token/Token.h" 6 | 7 | typedef struct 8 | { 9 | Source *source; 10 | 11 | SourceLocation current; 12 | } Lexer; 13 | 14 | Lexer *lexer_create(Source *source); 15 | 16 | void lexer_destroy(Lexer *lexer); 17 | 18 | bool lexer_is_EOF(Lexer *lexer); 19 | 20 | Token *lexer_next_token(Lexer *lexer); 21 | -------------------------------------------------------------------------------- /samples/Macro.ud: -------------------------------------------------------------------------------- 1 | decorator ToString(@Enum type) 2 | { 3 | inject cast -> String 4 | { 5 | for (EnumMember member in type) 6 | { 7 | if (this == member.constant_value){ 8 | return member.name; 9 | } 10 | } 11 | 12 | return "undefined" 13 | } 14 | } 15 | 16 | @ToString 17 | enum Truc { 18 | Foo, 19 | Bar, 20 | FooBar, 21 | }; 22 | 23 | 24 | println(Truc::Foo); 25 | -------------------------------------------------------------------------------- /udfore/utils/Buffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/utils/Utils.h" 4 | 5 | typedef struct 6 | { 7 | size_t used; 8 | size_t size; 9 | char *buffer; 10 | } Buffer; 11 | 12 | Buffer *buffer_create(size_t preallocated); 13 | 14 | void buffer_destroy(Buffer *buffer); 15 | 16 | char *buffer_finalize(Buffer *buffer); 17 | 18 | void buffer_append_str(Buffer *buffer, const char *str); 19 | 20 | void buffer_append_chr(Buffer *buffer, char chr); 21 | -------------------------------------------------------------------------------- /udfore/utils/Utils.c: -------------------------------------------------------------------------------- 1 | #include "udfore/utils/Utils.h" 2 | 3 | bool utils_is_white_space(char chr) 4 | { 5 | return chr == ' ' || chr == '\n' || chr == '\r' || chr == '\t'; 6 | } 7 | 8 | bool utils_is_letter(char chr) 9 | { 10 | return (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z'); 11 | } 12 | 13 | bool utils_is_identifier(char chr) 14 | { 15 | return (chr == '_') || utils_is_letter(chr); 16 | } 17 | 18 | bool utils_is_number(char chr) 19 | { 20 | return (chr >= '0' && chr <= '9'); 21 | } 22 | -------------------------------------------------------------------------------- /udfore/parser/Program.c: -------------------------------------------------------------------------------- 1 | #include "udfore/parser/Parser.h" 2 | 3 | ASTProgram *parser_parse_program(Parser *parser) 4 | { 5 | ASTProgram *program = astprogram_create(); 6 | 7 | while (!parser_current_is(parser, TOKEN_EOF)) 8 | { 9 | ASTStatement *statement = parser_parse_statement(parser); 10 | 11 | if (statement) 12 | { 13 | astprogram_append_statement(program, statement); 14 | } 15 | 16 | parser_advance(parser); // skip rbrace 17 | } 18 | 19 | return program; 20 | } -------------------------------------------------------------------------------- /udfore/value/Value.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/value/Value.h" 4 | 5 | void value_serialize(Value value, Buffer *buffer) 6 | { 7 | switch (value.type) 8 | { 9 | case VALUE_S32: 10 | { 11 | char b[14]; 12 | sprintf(b, "%" PRId32, value.s32); 13 | 14 | buffer_append_str(buffer, b); 15 | } 16 | break; 17 | 18 | default: 19 | buffer_append_str(buffer, ""); 20 | break; 21 | } 22 | } 23 | 24 | Value value_create_s32(int32_t s32) 25 | { 26 | return (Value){VALUE_S32, {.s32 = s32}}; 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | 54 | .vscode/ 55 | -------------------------------------------------------------------------------- /udfore/ast/Node.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/source/SourceLocation.h" 4 | #include "udfore/utils/Buffer.h" 5 | 6 | struct ASTNode; 7 | 8 | typedef void (*ASTNodeDestroyCallback)(struct ASTNode *node); 9 | typedef void (*ASTNodeSerializeCallback)(struct ASTNode *node, Buffer *buffer); 10 | 11 | typedef struct ASTNode 12 | { 13 | SourceLocation location; 14 | 15 | ASTNodeDestroyCallback destroy; 16 | ASTNodeSerializeCallback serialize; 17 | } ASTNode; 18 | 19 | #define ASTNODE(__subclass) ((ASTNode *)(__subclass)) 20 | 21 | void astnode_destroy(ASTNode *node); 22 | 23 | char *astnode_serialize(ASTNode *node); 24 | 25 | void astnode_serialize_continue(ASTNode *node, Buffer *buffer); 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![udfore](udfore.svg) 2 | 3 | ``` 4 | take println from io; 5 | 6 | type Vector 7 | { 8 | int x; 9 | int y; 10 | int z; 11 | 12 | constructor (float x, float y, float z) 13 | { 14 | .x = x; 15 | .y = y; 16 | .z = z; 17 | } 18 | 19 | operator + (Vector vector) -> Vector 20 | { 21 | return Vector( 22 | x + vector.x, 23 | y + vector.y, 24 | z + vector.z, 25 | ); 26 | } 27 | 28 | cast String 29 | { 30 | return `[{x}, {y}, {z}]`; 31 | } 32 | } 33 | 34 | let v1 := Vector(1, 2, 3); 35 | let v2 := Vector(4, 5, 6); 36 | let v3 := v1 + v2; 37 | 38 | println(`{v1} + {v2} = {v3}`); 39 | ``` 40 | -------------------------------------------------------------------------------- /samples/Vector.ud: -------------------------------------------------------------------------------- 1 | take println from io; 2 | 3 | type Vector 4 | { 5 | int x; 6 | int y; 7 | int z; 8 | 9 | constructor (float x, float y, float z) 10 | { 11 | .x = x; 12 | .y = y; 13 | .z = z; 14 | } 15 | 16 | operator + (Vector vector) -> Vector 17 | { 18 | return Vector( 19 | x + vector.x, 20 | y + vector.y, 21 | z + vector.z, 22 | ); 23 | } 24 | 25 | cast -> String 26 | { 27 | return `[{x}, {y}, {z}]`; 28 | } 29 | } 30 | 31 | main 32 | { 33 | let v1 := Vector(1, 2, 3); 34 | let v2 := Vector(4, 5, 6); 35 | let v3 := v1 + v2; 36 | 37 | println(`{v1} + {v2} = {v3}`); 38 | } 39 | -------------------------------------------------------------------------------- /udfore/ast/expression/Value.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Expression.h" 2 | 3 | void expression_value_destroy(ASTValueExpression *expression) 4 | { 5 | free(expression); 6 | } 7 | 8 | void expression_value_serialize(ASTValueExpression *expression, Buffer *buffer) 9 | { 10 | value_serialize(expression->value, buffer); 11 | } 12 | 13 | ASTValueExpression *expression_value_create(Value value) 14 | { 15 | ASTValueExpression *expression = __create(ASTValueExpression); 16 | 17 | ASTNODE(expression)->destroy = (ASTNodeDestroyCallback)expression_value_destroy; 18 | ASTNODE(expression)->serialize = (ASTNodeSerializeCallback)expression_value_serialize; 19 | 20 | expression->value = value; 21 | 22 | return expression; 23 | } -------------------------------------------------------------------------------- /udfore/ast/Node.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Node.h" 2 | 3 | void astnode_destroy(ASTNode *node) 4 | { 5 | if (!node) 6 | { 7 | return; 8 | } 9 | 10 | if (node->destroy) 11 | { 12 | node->destroy(node); 13 | } 14 | } 15 | 16 | char *astnode_serialize(ASTNode *node) 17 | { 18 | Buffer *buffer = buffer_create(128); 19 | 20 | astnode_serialize_continue(node, buffer); 21 | 22 | return buffer_finalize(buffer); 23 | } 24 | 25 | void astnode_serialize_continue(ASTNode *node, Buffer *buffer) 26 | { 27 | if (node == NULL) 28 | { 29 | buffer_append_str(buffer, ""); 30 | } 31 | else if (!node->serialize) 32 | { 33 | buffer_append_str(buffer, ""); 34 | } 35 | else 36 | { 37 | node->serialize(node, buffer); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /udfore/utils/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum 4 | { 5 | LOGGER_TRACE, 6 | LOGGER_DEBUG, 7 | LOGGER_INFO, 8 | LOGGER_WARN, 9 | LOGGER_ERROR, 10 | LOGGER_FATAL 11 | }; 12 | 13 | #define logger_trace(...) logger_log(LOGGER_TRACE, __FILE__, __LINE__, __VA_ARGS__) 14 | #define logger_debug(...) logger_log(LOGGER_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 15 | #define logger_info(...) logger_log(LOGGER_INFO, __FILE__, __LINE__, __VA_ARGS__) 16 | #define logger_warn(...) logger_log(LOGGER_WARN, __FILE__, __LINE__, __VA_ARGS__) 17 | #define logger_error(...) logger_log(LOGGER_ERROR, __FILE__, __LINE__, __VA_ARGS__) 18 | #define logger_fatal(...) logger_log(LOGGER_FATAL, __FILE__, __LINE__, __VA_ARGS__) 19 | 20 | void logger_set_level(int level); 21 | 22 | void logger_log(int level, const char *file, int line, const char *fmt, ...); 23 | -------------------------------------------------------------------------------- /udfore/main.c: -------------------------------------------------------------------------------- 1 | #include "udfore/lexer/Lexer.h" 2 | #include "udfore/parser/Parser.h" 3 | #include "udfore/source/Source.h" 4 | #include "udfore/utils/Logger.h" 5 | 6 | int main(int argc, char const *argv[]) 7 | { 8 | logger_set_level(LOGGER_TRACE); 9 | 10 | if (argc > 1) 11 | { 12 | Source *source = file_source_create(argv[1]); 13 | Lexer *lexer = lexer_create(source); 14 | Parser *parser = parser_create(lexer); 15 | 16 | ASTProgram *program = parser_parse_program(parser); 17 | 18 | parser_destroy(parser); 19 | lexer_destroy(lexer); 20 | source_destroy(source); 21 | 22 | char *output = astnode_serialize(ASTNODE(program)); 23 | 24 | printf("%s", output); 25 | 26 | free(output); 27 | astnode_destroy(ASTNODE(program)); 28 | } 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /udfore/ast/expression/Identifier.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Expression.h" 2 | #include 3 | 4 | void expression_identifier_destroy(ASTExpressionIdentifier *expression) 5 | { 6 | if (expression->name) 7 | { 8 | free(expression->name); 9 | } 10 | 11 | free(expression); 12 | } 13 | 14 | void expression_identifier_serialize(ASTExpressionIdentifier *expression, Buffer *buffer) 15 | { 16 | buffer_append_str(buffer, expression->name); 17 | } 18 | 19 | ASTExpressionIdentifier *expression_identifier_create(const char *name) 20 | { 21 | ASTExpressionIdentifier *expression = __create(ASTExpressionIdentifier); 22 | 23 | ASTNODE(expression)->destroy = (ASTNodeDestroyCallback)expression_identifier_destroy; 24 | ASTNODE(expression)->serialize = (ASTNodeSerializeCallback)expression_identifier_serialize; 25 | 26 | expression->name = strdup(name); 27 | 28 | return expression; 29 | } -------------------------------------------------------------------------------- /udfore/ast/Expression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/ast/Node.h" 4 | #include "udfore/token/Token.h" 5 | #include "udfore/value/Value.h" 6 | 7 | typedef struct ASTExpression 8 | { 9 | ASTNode node; 10 | } ASTExpression; 11 | 12 | typedef struct 13 | { 14 | ASTExpression expression; 15 | 16 | char *name; 17 | } ASTExpressionIdentifier; 18 | 19 | ASTExpressionIdentifier *expression_identifier_create(const char *name); 20 | 21 | typedef struct 22 | { 23 | ASTExpression expression; 24 | 25 | TokenType operator; 26 | ASTExpression *lhs; 27 | ASTExpression *rhs; 28 | } ASTInfixExpression; 29 | 30 | ASTInfixExpression *expression_infix_operator_create(TokenType operator, ASTExpression *lhs, ASTExpression *rhs); 31 | 32 | typedef struct 33 | { 34 | ASTExpression expression; 35 | Value value; 36 | } ASTValueExpression; 37 | 38 | ASTValueExpression *expression_value_create(Value value); 39 | -------------------------------------------------------------------------------- /udfore/ast/statement/ReturnStatement.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Statement.h" 2 | 3 | void returnstatement_destroy(ASTReturnStatement *statement) 4 | { 5 | astnode_destroy(ASTNODE(statement->expression)); 6 | 7 | free(statement); 8 | } 9 | 10 | void returnstatement_serialize(ASTReturnStatement *statement, Buffer *buffer) 11 | { 12 | buffer_append_str(buffer, "(return "); 13 | astnode_serialize_continue(ASTNODE(statement->expression), buffer); 14 | buffer_append_str(buffer, ")"); 15 | } 16 | 17 | ASTReturnStatement *returnstatement_create(ASTExpression *expression) 18 | { 19 | ASTReturnStatement *statement = __create(ASTReturnStatement); 20 | 21 | statement->expression = expression; 22 | 23 | ASTNODE(statement)->destroy = (ASTNodeDestroyCallback)returnstatement_destroy; 24 | ASTNODE(statement)->serialize = (ASTNodeSerializeCallback)returnstatement_serialize; 25 | 26 | return statement; 27 | } -------------------------------------------------------------------------------- /samples/Algorithm.ud: -------------------------------------------------------------------------------- 1 | take { Index, Size } from builtin.types; 2 | 3 | concept Indexable 4 | { 5 | operator [] (Index index) -> T&; 6 | 7 | operator [] (Index index, T& value); 8 | 9 | operator lengthof -> Size; 10 | } 11 | 12 | function swap(T &left, T &right) 13 | { 14 | T tmp = left; 15 | left = right; 16 | right = tmp; 17 | } 18 | 19 | concept Swappable 20 | { 21 | function swap_indexes(Index i, Index j); 22 | } 23 | 24 | adapter Swappable for Indexable 25 | { 26 | function swap_indexes(Index i, Index j) 27 | { 28 | swap([i], [j]) 29 | } 30 | } 31 | 32 | concept Sortable = Indexable + Swappable; 33 | 34 | function sort(Sortable container) 35 | { 36 | for (Index x in 0..lengthof(sortable) - 1) 37 | for (Index y in (x + 1)..lengthof(sortable)) 38 | if (sortable[i] > sortable[j]) 39 | container.swap_indexes(i, j); 40 | } 41 | -------------------------------------------------------------------------------- /udfore/ast/statement/ExpressionStatement.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Statement.h" 2 | 3 | void expressionstatement_destroy(ASTExpressionStatement *statement) 4 | { 5 | astnode_destroy(ASTNODE(statement->expression)); 6 | free(statement); 7 | } 8 | 9 | void expressionstatement_serialize(ASTExpressionStatement *statement, Buffer *buffer) 10 | { 11 | buffer_append_str(buffer, "(expression "); 12 | astnode_serialize_continue(ASTNODE(statement->expression), buffer); 13 | buffer_append_str(buffer, ")"); 14 | } 15 | 16 | ASTExpressionStatement *expressionstatement_create(ASTExpression *expression) 17 | { 18 | ASTExpressionStatement *statement = __create(ASTExpressionStatement); 19 | 20 | statement->expression = expression; 21 | 22 | ASTNODE(statement)->destroy = (ASTNodeDestroyCallback)expressionstatement_destroy; 23 | ASTNODE(statement)->serialize = (ASTNodeSerializeCallback)expressionstatement_serialize; 24 | 25 | return statement; 26 | } 27 | -------------------------------------------------------------------------------- /udfore/source/Source.c: -------------------------------------------------------------------------------- 1 | #include "udfore/source/Source.h" 2 | 3 | void source_destroy(Source *source) 4 | { 5 | if (source->destroy) 6 | { 7 | source->destroy(source); 8 | } 9 | 10 | free(source); 11 | } 12 | 13 | void source_next_char(Source *source) 14 | { 15 | if (source_is_EOF(source)) 16 | { 17 | source->current_char = source->peeked_char; 18 | source->peeked_char = EOF; 19 | } 20 | else 21 | { 22 | source->current_char = source->peeked_char; 23 | source->peeked_char = source->next_char(source); 24 | } 25 | } 26 | 27 | bool source_is_EOF(Source *source) 28 | { 29 | return source->is_EOF(source); 30 | } 31 | 32 | char source_current_char(Source *source) 33 | { 34 | return source->current_char; 35 | } 36 | 37 | char source_peek_char(Source *source) 38 | { 39 | return source->peeked_char; 40 | } 41 | 42 | void source_initialize(Source *source) 43 | { 44 | source_next_char(source); 45 | source_next_char(source); 46 | } 47 | -------------------------------------------------------------------------------- /udfore/source/Source.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/utils/Utils.h" 4 | 5 | struct Source; 6 | 7 | typedef char (*SourceNextCharCallback)(struct Source *source); 8 | typedef void (*SourceDestroyCallback)(struct Source *source); 9 | typedef bool (*SourceIsEOFCallback)(struct Source *source); 10 | 11 | typedef struct Source 12 | { 13 | char peeked_char; 14 | char current_char; 15 | 16 | SourceDestroyCallback destroy; 17 | SourceNextCharCallback next_char; 18 | SourceIsEOFCallback is_EOF; 19 | } Source; 20 | 21 | #define SOURCE(__subclass) ((Source *)(__subclass)) 22 | 23 | void source_initialize(Source *source); 24 | 25 | Source *file_source_create(const char *path); 26 | 27 | Source *string_source_create(const char *source_code, size_t lenght); 28 | 29 | void source_destroy(Source *source); 30 | 31 | void source_next_char(Source *source); 32 | 33 | bool source_is_EOF(Source *source); 34 | 35 | char source_current_char(Source *source); 36 | 37 | char source_peek_char(Source *source); 38 | -------------------------------------------------------------------------------- /udfore/source/FileSource.c: -------------------------------------------------------------------------------- 1 | #include "udfore/source/Source.h" 2 | 3 | typedef struct 4 | { 5 | Source source; 6 | FILE *file; 7 | } FileSource; 8 | 9 | void file_source_destroy(FileSource *source) 10 | { 11 | fclose(source->file); 12 | } 13 | 14 | char file_source_next_char(FileSource *source) 15 | { 16 | return fgetc(source->file); 17 | } 18 | 19 | bool file_source_is_EOF(FileSource *source) 20 | { 21 | return feof(source->file); 22 | } 23 | 24 | Source *file_source_create(const char *path) 25 | { 26 | FILE *file = fopen(path, "r"); 27 | 28 | if (file == NULL) 29 | { 30 | return NULL; 31 | } 32 | 33 | FileSource *source = __create(FileSource); 34 | 35 | source->file = file; 36 | 37 | SOURCE(source)->destroy = (SourceDestroyCallback)file_source_destroy; 38 | SOURCE(source)->next_char = (SourceNextCharCallback)file_source_next_char; 39 | SOURCE(source)->is_EOF = (SourceIsEOFCallback)file_source_is_EOF; 40 | 41 | source_initialize(SOURCE(source)); 42 | 43 | return SOURCE(source); 44 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT=udfore 2 | 3 | TESTS := $(wildcard $(PROJECT)/tests/*.test.c) 4 | SOURCES := $(filter-out $(wildcard $(PROJECT)/tests/*.test.c), $(wildcard $(PROJECT)/*/*.c) $(wildcard $(PROJECT)/*/*/*.c)) 5 | OBJECTS := $(SOURCES:.c=.o) 6 | 7 | CC := gcc 8 | LDFLAGS := -lm 9 | CFLAGS := -g \ 10 | -std=c11 \ 11 | -pedantic \ 12 | -MD \ 13 | -I. \ 14 | -Wall \ 15 | -Wextra \ 16 | -Werror \ 17 | -fsanitize=address \ 18 | -fsanitize=undefined \ 19 | -D_XOPEN_SOURCE=500 20 | 21 | .PHONY: all clean test 22 | 23 | all: $(PROJECT).out 24 | 25 | clean: 26 | rm -f $(OBJECTS) $(SOURCES:.c=.d) $(TESTS:.c=.d) $(PROJECT).out 27 | 28 | run: $(PROJECT).out 29 | ./$(PROJECT).out 30 | 31 | test: $(TESTS:.c=.run) 32 | 33 | $(PROJECT).out: $(PROJECT)/main.o $(OBJECTS) 34 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 35 | 36 | $(PROJECT)/tests/%.test.run: $(PROJECT)/tests/%.test.out 37 | $^ 38 | 39 | $(PROJECT)/tests/%.test.out: $(PROJECT)/tests/%.test.o $(OBJECTS) 40 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 41 | 42 | 43 | -include $(SOURCES:.c=.d) $(TESTS:.c=.d) 44 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 skift 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | **THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.** 22 | -------------------------------------------------------------------------------- /udfore/ast/Program.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Program.h" 2 | 3 | void astprogram_append_statement(ASTProgram *program, struct ASTStatement *statement) 4 | { 5 | list_pushback(program->statements, statement); 6 | } 7 | 8 | void astprogram_destroy(ASTProgram *program) 9 | { 10 | list_destroy_with_callback(program->statements, (ListDestroyElementCallback)astnode_destroy); 11 | free(program); 12 | } 13 | 14 | void astprogram_serialize(ASTProgram *program, Buffer *buffer) 15 | { 16 | buffer_append_str(buffer, "(program"); 17 | list_foreach(struct ASTStatement, statement, program->statements) 18 | { 19 | buffer_append_str(buffer, " "); 20 | astnode_serialize_continue(ASTNODE(statement), buffer); 21 | } 22 | buffer_append_str(buffer, ")"); 23 | } 24 | 25 | ASTProgram *astprogram_create(void) 26 | { 27 | ASTProgram *program = __create(ASTProgram); 28 | 29 | program->statements = list_create(); 30 | 31 | ASTNODE(program)->destroy = (ASTNodeDestroyCallback)astprogram_destroy; 32 | ASTNODE(program)->serialize = (ASTNodeSerializeCallback)astprogram_serialize; 33 | 34 | return program; 35 | } 36 | -------------------------------------------------------------------------------- /udfore/ast/statement/LetStatement.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Statement.h" 2 | 3 | void letstatement_destroy(ASTLetStatement *statement) 4 | { 5 | if (statement->identifier) 6 | { 7 | free(statement->identifier); 8 | } 9 | 10 | astnode_destroy(ASTNODE(statement->expression)); 11 | 12 | free(statement); 13 | } 14 | 15 | void letstatement_serialize(ASTLetStatement *statement, Buffer *buffer) 16 | { 17 | buffer_append_str(buffer, "(let "); 18 | buffer_append_str(buffer, statement->identifier); 19 | buffer_append_str(buffer, " = "); 20 | astnode_serialize_continue(ASTNODE(statement->expression), buffer); 21 | buffer_append_str(buffer, ")"); 22 | } 23 | 24 | ASTLetStatement *letstatement_create(char *identifier, ASTExpression *expression) 25 | { 26 | ASTLetStatement *statement = __create(ASTLetStatement); 27 | 28 | statement->identifier = identifier; 29 | statement->expression = expression; 30 | 31 | ASTNODE(statement)->destroy = (ASTNodeDestroyCallback)letstatement_destroy; 32 | ASTNODE(statement)->serialize = (ASTNodeSerializeCallback)letstatement_serialize; 33 | 34 | return statement; 35 | } 36 | -------------------------------------------------------------------------------- /udfore/token/Keyword.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/token/Token.h" 4 | 5 | TokenLiteralToType keyword_tokens[] = { 6 | {"cast", TOKEN_CAST}, 7 | {"constructor", TOKEN_CONSTRUCTOR}, 8 | {"destructor", TOKEN_DESTRUCTOR}, 9 | {"from", TOKEN_FROM}, 10 | {"function", TOKEN_FUNCTION}, 11 | {"let", TOKEN_LET}, 12 | {"module", TOKEN_MODULE}, 13 | {"return", TOKEN_RETURN}, 14 | {"spec", TOKEN_SPEC}, 15 | {"take", TOKEN_TAKE}, 16 | {"type", TOKEN_TYPE}, 17 | {"use", TOKEN_USE}, 18 | {NULL, -1}, 19 | }; 20 | 21 | bool token_literal_is_keyword(const char *literal) 22 | { 23 | for (size_t i = 0; keyword_tokens[i].literal != NULL; i++) 24 | { 25 | if (strcmp(keyword_tokens[i].literal, literal) == 0) 26 | { 27 | return true; 28 | } 29 | } 30 | 31 | return false; 32 | } 33 | 34 | TokenType keyword_literal_to_token_type(const char *literal) 35 | { 36 | for (size_t i = 0; keyword_tokens[i].literal != NULL; i++) 37 | { 38 | if (strcmp(keyword_tokens[i].literal, literal) == 0) 39 | { 40 | return keyword_tokens[i].type; 41 | } 42 | } 43 | 44 | return TOKEN_ILLEGAL; 45 | } 46 | -------------------------------------------------------------------------------- /udfore/utils/Logger.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "udfore/utils/Logger.h" 8 | 9 | static int _log_level; 10 | 11 | static const char *level_names[] = { 12 | "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"}; 13 | 14 | static const char *level_colors[] = { 15 | "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m"}; 16 | 17 | void logger_set_level(int level) 18 | { 19 | _log_level = level; 20 | } 21 | 22 | void logger_log(int level, const char *file, int line, const char *fmt, ...) 23 | { 24 | if (level < _log_level) 25 | { 26 | return; 27 | } 28 | 29 | /* Get current time */ 30 | time_t t = time(NULL); 31 | struct tm *lt = localtime(&t); 32 | 33 | va_list args; 34 | char buf[16]; 35 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", lt)] = '\0'; 36 | 37 | fprintf( 38 | stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 39 | buf, level_colors[level], level_names[level], file, line); 40 | 41 | va_start(args, fmt); 42 | vfprintf(stderr, fmt, args); 43 | va_end(args); 44 | fprintf(stderr, "\n"); 45 | fflush(stderr); 46 | } 47 | -------------------------------------------------------------------------------- /udfore/ast/statement/BlockStatement.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Statement.h" 2 | 3 | void blockstatement_destroy(ASTBlockStatement *statement) 4 | { 5 | list_destroy_with_callback(statement->statements, (ListDestroyElementCallback)astnode_destroy); 6 | free(statement); 7 | } 8 | 9 | void blockstatement_serialize(ASTBlockStatement *statement, Buffer *buffer) 10 | { 11 | buffer_append_str(buffer, "(block "); 12 | 13 | list_foreach(struct ASTStatement, statement, statement->statements) 14 | { 15 | astnode_serialize_continue(ASTNODE(statement), buffer); 16 | buffer_append_str(buffer, ", "); 17 | } 18 | 19 | buffer_append_str(buffer, ")"); 20 | } 21 | 22 | void blockstatement_appent_statement(ASTBlockStatement *block_statement, ASTStatement *statement) 23 | { 24 | list_pushback(block_statement->statements, statement); 25 | } 26 | 27 | ASTBlockStatement *blockstatement_create(void) 28 | { 29 | ASTBlockStatement *statement = __create(ASTBlockStatement); 30 | 31 | statement->statements = list_create(); 32 | 33 | ASTNODE(statement)->destroy = (ASTNodeDestroyCallback)blockstatement_destroy; 34 | ASTNODE(statement)->serialize = (ASTNodeSerializeCallback)blockstatement_serialize; 35 | 36 | return statement; 37 | } 38 | -------------------------------------------------------------------------------- /udfore/ast/Statement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/ast/Expression.h" 4 | #include "udfore/ast/Node.h" 5 | #include "udfore/utils/List.h" 6 | 7 | typedef struct ASTStatement 8 | { 9 | ASTNode node; 10 | } ASTStatement; 11 | 12 | #define ASTSTATEMENT(__subclass) ((ASTStatement *)(__subclass)) 13 | 14 | typedef struct 15 | { 16 | ASTStatement statement; 17 | 18 | char *identifier; 19 | ASTExpression *expression; 20 | } ASTLetStatement; 21 | 22 | ASTLetStatement *letstatement_create(char *identifier, ASTExpression *expression); 23 | 24 | typedef struct 25 | { 26 | ASTStatement statement; 27 | 28 | ASTExpression *expression; 29 | } ASTReturnStatement; 30 | 31 | ASTReturnStatement *returnstatement_create(ASTExpression *expression); 32 | 33 | typedef struct 34 | { 35 | ASTStatement statement; 36 | 37 | List *statements; 38 | } ASTBlockStatement; 39 | 40 | ASTBlockStatement *blockstatement_create(void); 41 | 42 | void blockstatement_appent_statement(ASTBlockStatement *blockstatement, ASTStatement *statement); 43 | 44 | typedef struct 45 | { 46 | ASTStatement statement; 47 | 48 | ASTExpression *expression; 49 | } ASTExpressionStatement; 50 | 51 | ASTExpressionStatement *expressionstatement_create(ASTExpression *expression); 52 | -------------------------------------------------------------------------------- /udfore/parser/Parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/ast/Expression.h" 4 | #include "udfore/ast/Program.h" 5 | #include "udfore/ast/Statement.h" 6 | #include "udfore/lexer/Lexer.h" 7 | #include "udfore/parser/Expression.h" 8 | 9 | typedef struct Parser 10 | { 11 | Lexer *lexer; 12 | 13 | Token *current; 14 | Token *next; 15 | Token *previous; 16 | } Parser; 17 | 18 | Parser *parser_create(Lexer *lexer); 19 | 20 | void parser_destroy(Parser *parser); 21 | 22 | void parser_advance(Parser *parser); 23 | 24 | // 25 | 26 | Token *parser_previous(Parser *parser); 27 | 28 | Token *parser_current(Parser *parser); 29 | 30 | Token *parser_next(Parser *parser); 31 | 32 | // 33 | 34 | bool parser_current_is(Parser *parser, TokenType expected); 35 | 36 | bool parser_next_is(Parser *parser, TokenType expected); 37 | 38 | // 39 | 40 | bool parser_expect_current(Parser *parser, TokenType *expected); 41 | 42 | bool parser_expect_next(Parser *parser, TokenType *expected); 43 | 44 | // 45 | 46 | ASTProgram *parser_parse_program(Parser *parser); 47 | 48 | ASTStatement *parser_parse_statement(Parser *parser); 49 | 50 | ASTExpression *parser_parse_expression(Parser *parser); 51 | 52 | ASTExpression *parser_parse_expression_with_precedence(Parser *parser, ExpressionPrecedence precedence); 53 | -------------------------------------------------------------------------------- /udfore/ast/expression/InfixOperator.c: -------------------------------------------------------------------------------- 1 | #include "udfore/ast/Expression.h" 2 | 3 | void expression_infix_operator_destroy(ASTInfixExpression *expression) 4 | { 5 | astnode_destroy(ASTNODE(expression->lhs)); 6 | astnode_destroy(ASTNODE(expression->rhs)); 7 | 8 | free(expression); 9 | } 10 | 11 | void expression_infix_operator_serialize(ASTInfixExpression *expression, Buffer *buffer) 12 | { 13 | buffer_append_str(buffer, "("); 14 | astnode_serialize_continue(ASTNODE(expression->lhs), buffer); 15 | buffer_append_str(buffer, " "); 16 | buffer_append_str(buffer, operator_token_type_to_literal(expression->operator)); 17 | buffer_append_str(buffer, " "); 18 | astnode_serialize_continue(ASTNODE(expression->rhs), buffer); 19 | buffer_append_str(buffer, ")"); 20 | } 21 | 22 | ASTInfixExpression *expression_infix_operator_create(TokenType operator, ASTExpression *lhs, ASTExpression *rhs) 23 | { 24 | ASTInfixExpression *expression = __create(ASTInfixExpression); 25 | 26 | ASTNODE(expression)->destroy = (ASTNodeDestroyCallback)expression_infix_operator_destroy; 27 | ASTNODE(expression)->serialize = (ASTNodeSerializeCallback)expression_infix_operator_serialize; 28 | 29 | expression->operator= operator; 30 | expression->lhs = lhs; 31 | expression->rhs = rhs; 32 | 33 | return expression; 34 | } 35 | -------------------------------------------------------------------------------- /udfore/utils/Buffer.c: -------------------------------------------------------------------------------- 1 | #include "udfore/utils/Buffer.h" 2 | 3 | Buffer *buffer_create(size_t preallocated) 4 | { 5 | Buffer *buffer = __create(Buffer); 6 | 7 | buffer->buffer = calloc(preallocated, sizeof(char)); 8 | buffer->size = preallocated; 9 | buffer->used = 0; 10 | 11 | return buffer; 12 | } 13 | 14 | void buffer_destroy(Buffer *buffer) 15 | { 16 | if (buffer->buffer) 17 | { 18 | free(buffer->buffer); 19 | } 20 | 21 | free(buffer); 22 | } 23 | 24 | char *buffer_finalize(Buffer *buffer) 25 | { 26 | char *result = buffer->buffer; 27 | buffer->buffer = NULL; 28 | 29 | buffer_destroy(buffer); 30 | 31 | return result; 32 | } 33 | 34 | void buffer_append_str(Buffer *buffer, const char *str) 35 | { 36 | if (str) 37 | { 38 | for (size_t i = 0; str[i]; i++) 39 | { 40 | buffer_append_chr(buffer, str[i]); 41 | } 42 | } 43 | else 44 | { 45 | buffer_append_str(buffer, ""); 46 | } 47 | } 48 | 49 | void buffer_append_chr(Buffer *buffer, char chr) 50 | { 51 | if (buffer->used + 1 == buffer->size) 52 | { 53 | buffer->size *= 1.25; 54 | buffer->buffer = realloc(buffer->buffer, buffer->size); 55 | } 56 | 57 | buffer->buffer[buffer->used] = chr; 58 | buffer->buffer[buffer->used + 1] = '\0'; 59 | buffer->used++; 60 | } 61 | -------------------------------------------------------------------------------- /udfore/source/StringSource.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "udfore/source/Source.h" 5 | 6 | typedef struct 7 | { 8 | Source source; 9 | 10 | size_t offset; 11 | size_t lenght; 12 | char *buffer; 13 | } StringSource; 14 | 15 | void string_source_destroy(StringSource *source) 16 | { 17 | free(source->buffer); 18 | } 19 | 20 | char string_source_next_char(StringSource *source) 21 | { 22 | assert(source->offset <= source->lenght); 23 | char chr = source->buffer[source->offset]; 24 | source->offset++; 25 | 26 | return chr; 27 | } 28 | 29 | bool string_source_is_EOF(StringSource *source) 30 | { 31 | return !(source->offset < source->lenght); 32 | } 33 | 34 | Source *string_source_create(const char *source_code, size_t lenght) 35 | { 36 | StringSource *source = __create(StringSource); 37 | 38 | char *buffer = calloc(lenght, sizeof(char)); 39 | memcpy(buffer, source_code, lenght); 40 | 41 | source->buffer = buffer; 42 | source->lenght = lenght; 43 | source->offset = 0; 44 | 45 | SOURCE(source)->destroy = (SourceDestroyCallback)string_source_destroy; 46 | SOURCE(source)->next_char = (SourceNextCharCallback)string_source_next_char; 47 | SOURCE(source)->is_EOF = (SourceIsEOFCallback)string_source_is_EOF; 48 | 49 | source_initialize(SOURCE(source)); 50 | 51 | return SOURCE(source); 52 | } -------------------------------------------------------------------------------- /udfore/token/Token.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "udfore/token/Token.h" 5 | #include "udfore/utils/Utils.h" 6 | 7 | Token *token_create(TokenType type, SourceLocation location, char c) 8 | { 9 | Token *token = malloc(sizeof(Token)); 10 | 11 | token->type = type; 12 | 13 | token->location = location; 14 | 15 | token->lenght = 1; 16 | 17 | token->chr = malloc(2); 18 | token->chr[0] = c; 19 | token->chr[1] = '\0'; 20 | 21 | return token; 22 | } 23 | 24 | void token_destroy(Token *token) 25 | { 26 | assert(token); 27 | assert(token->chr); 28 | 29 | free(token->chr); 30 | free(token); 31 | } 32 | 33 | Token *token_append(Token *token, char c) 34 | { 35 | token->chr = realloc(token->chr, token->lenght + 2); 36 | token->lenght = token->lenght + 1; 37 | token->chr[token->lenght - 1] = c; 38 | token->chr[token->lenght] = '\0'; 39 | 40 | return token; 41 | } 42 | 43 | static const char *token_type_string[] = { 44 | #define TOKEN_TYPE_STRING_ENTRY(__entry) #__entry, 45 | TOKEN_TYPES_LIST(TOKEN_TYPE_STRING_ENTRY)}; 46 | 47 | const char *token_as_string(Token *token) 48 | { 49 | assert(token); 50 | assert(token->type >= 0 && token->type < __TOKEN_TYPE_COUNT); 51 | 52 | return token_type_string[token->type]; 53 | } 54 | 55 | const char *token_type_as_string(TokenType type) 56 | { 57 | return token_type_string[type]; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /udfore/parser/Expression.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/token/Token.h" 4 | 5 | struct Parser; 6 | struct ASTExpression; 7 | 8 | typedef struct ASTExpression *(*ParserPrefixCallback)(struct Parser *parser); 9 | typedef struct ASTExpression *(*ParserInfixCallback)(struct Parser *parser, struct ASTExpression *lhs); 10 | typedef struct ASTExpression *(*ParserPostfixCallback)(struct Parser *parser, struct ASTExpression *lhs); 11 | 12 | typedef enum 13 | { 14 | PRECEDENCE_LOWEST, 15 | PRECEDENCE_COND, // OR or AND 16 | PRECEDENCE_ASSIGN, // = 17 | PRECEDENCE_TERNARY, // ? : 18 | PRECEDENCE_EQUALS, // == or != 19 | PRECEDENCE_LESSGREATER, // > or < 20 | PRECEDENCE_SUM, // + or - 21 | PRECEDENCE_PRODUCT, // * or / 22 | PRECEDENCE_POWER, // ** 23 | PRECEDENCE_MOD, // % 24 | PRECEDENCE_PREFIX, // -X or !X 25 | PRECEDENCE_CALL, // myFunction(X) 26 | PRECEDENCE_INDEX, // array[index], map[key] 27 | } ExpressionPrecedence; 28 | 29 | typedef struct 30 | { 31 | TokenType token; 32 | ExpressionPrecedence precedence; 33 | 34 | struct 35 | { 36 | ParserPrefixCallback prefix; 37 | ParserInfixCallback infix; 38 | ParserPostfixCallback postfix; 39 | }; 40 | } ExpressionParserCallback; 41 | 42 | ParserPrefixCallback parser_get_prefix_callback(TokenType type); 43 | 44 | ParserInfixCallback parser_get_infix_callback(TokenType type); 45 | 46 | ParserPostfixCallback parser_get_postfix_callback(TokenType type); 47 | 48 | ExpressionPrecedence parser_get_precedence(TokenType type); 49 | -------------------------------------------------------------------------------- /udfore/utils/List.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define list_foreach(__type, __item, __list) \ 6 | for (ListItem *__i = __list->head; __i != NULL; __i = __i->next) \ 7 | for (__type *__item = (__type *)__i->value, *__loop_once = (__type *)1; __loop_once; __loop_once = 0) 8 | 9 | typedef struct ListItem 10 | { 11 | void *value; 12 | 13 | struct ListItem *prev; 14 | struct ListItem *next; 15 | } ListItem; 16 | 17 | typedef struct list 18 | { 19 | int count; 20 | 21 | ListItem *head; 22 | ListItem *tail; 23 | } List; 24 | 25 | typedef bool (*ListCompareElementCallback)(void *left, void *right); 26 | typedef void (*ListDestroyElementCallback)(void *element); 27 | 28 | List *list_create(void); 29 | 30 | void list_destroy(List *list); 31 | 32 | void list_destroy_with_callback(List *list, ListDestroyElementCallback callback); 33 | 34 | void list_clear(List *list); 35 | 36 | void list_clear_with_callback(List *list, ListDestroyElementCallback callback); 37 | 38 | List *list_clone(List *list); 39 | 40 | void list_insert_sorted(List *list, void *value, ListCompareElementCallback comparator); 41 | 42 | bool list_peek(List *list, void **value); 43 | 44 | bool list_peekback(List *list, void **value); 45 | 46 | bool list_peekat(List *list, int index, void **value); 47 | 48 | int list_indexof(List *list, void *value); 49 | 50 | void list_push(List *list, void *value); 51 | 52 | void list_pushback(List *list, void *value); 53 | 54 | bool list_pop(List *list, void **value); 55 | 56 | bool list_popback(List *list, void **value); 57 | 58 | bool list_contains(List *list, void *value); 59 | 60 | bool list_remove(List *list, void *value); 61 | 62 | #define list_empty(__list) ((__list)->count == 0) 63 | 64 | #define list_any(__list) ((__list)->count != 0) 65 | 66 | #define list_count(__list) ((__list)->count) 67 | -------------------------------------------------------------------------------- /udfore/token/Operator.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/token/Token.h" 4 | 5 | TokenLiteralToType operator_tokens[] = { 6 | {"=", TOKEN_EQUAL}, 7 | {"!=", TOKEN_NOTEQUAL}, 8 | {">", TOKEN_BIGGER_THAN}, 9 | {"<", TOKEN_LESS_THAN}, 10 | {">=", TOKEN_BIGGER_OR_EQUAL_THAN}, 11 | {"<=", TOKEN_LESS_OR_EQUAL_THAN}, 12 | 13 | {":=", TOKEN_ASSIGN}, 14 | {"+", TOKEN_PLUS}, 15 | {"++", TOKEN_PLUSPLUS}, 16 | {"-", TOKEN_MINUS}, 17 | {"--", TOKEN_MINUSMINUS}, 18 | {"*", TOKEN_MULT}, 19 | {"%", TOKEN_MOD}, 20 | {"/", TOKEN_DIV}, 21 | 22 | {".", TOKEN_DOT}, 23 | {"..", TOKEN_DOTDOT}, 24 | {"->", TOKEN_ARROW}, 25 | 26 | {"(", TOKEN_LPARENT}, 27 | {")", TOKEN_RPARENT}, 28 | {"{", TOKEN_LBRACE}, 29 | {"}", TOKEN_RBRACE}, 30 | {"[", TOKEN_LBRACKET}, 31 | {"]", TOKEN_RBRACKET}, 32 | {",", TOKEN_COMMA}, 33 | {";", TOKEN_SEMICOLON}, 34 | 35 | {"?", TOKEN_QUESTION}, 36 | {":", TOKEN_COLON}, 37 | {NULL, -1}, 38 | }; 39 | 40 | bool token_literal_is_operator(const char *literal) 41 | { 42 | for (size_t i = 0; operator_tokens[i].literal != NULL; i++) 43 | { 44 | if (strcmp(operator_tokens[i].literal, literal) == 0) 45 | { 46 | return true; 47 | } 48 | } 49 | 50 | return false; 51 | } 52 | 53 | TokenType operator_literal_to_token_type(const char *literal) 54 | { 55 | for (size_t i = 0; operator_tokens[i].literal != NULL; i++) 56 | { 57 | if (strcmp(operator_tokens[i].literal, literal) == 0) 58 | { 59 | return operator_tokens[i].type; 60 | } 61 | } 62 | 63 | return TOKEN_ILLEGAL; 64 | } 65 | 66 | const char *operator_token_type_to_literal(TokenType type) 67 | { 68 | for (size_t i = 0; operator_tokens[i].literal != NULL; i++) 69 | { 70 | if (operator_tokens[i].type == type) 71 | { 72 | return operator_tokens[i].literal; 73 | } 74 | } 75 | 76 | return "ILLEGAL"; 77 | } 78 | -------------------------------------------------------------------------------- /samples/Shapes.ud: -------------------------------------------------------------------------------- 1 | take println from io; 2 | take PI from Math; 3 | 4 | spec Shape 5 | { 6 | function width() -> float; 7 | function height() -> float; 8 | function perimeter() -> float; 9 | function surface() -> float; 10 | } 11 | 12 | type Rectangle 13 | { 14 | float width; 15 | float height; 16 | 17 | constructor(float width, float height) 18 | { 19 | .width := width; 20 | .height := height; 21 | } 22 | 23 | function width() -> float 24 | { 25 | return width; 26 | } 27 | 28 | function height() -> float 29 | { 30 | return height; 31 | } 32 | 33 | function perimeter() -> float 34 | { 35 | return (width + height) * 2; 36 | } 37 | 38 | function surface() -> float 39 | { 40 | return width * height; 41 | } 42 | 43 | cast string 44 | { 45 | return "Rectangle " .. width .. " by " .. height; 46 | } 47 | } 48 | 49 | type Circle 50 | { 51 | float radius; 52 | 53 | constructor(float radius) 54 | { 55 | .radius := radius; 56 | } 57 | 58 | function width() -> float 59 | { 60 | return radius * 2; 61 | } 62 | 63 | function height() -> float 64 | { 65 | return radius * 2; 66 | } 67 | 68 | methode perimeter() -> float 69 | { 70 | return 2 * PI * radius; 71 | } 72 | 73 | function surface() -> float 74 | { 75 | return PI * radius ** 2; 76 | } 77 | 78 | cast string -> "Circle of radius " .. radius; 79 | } 80 | 81 | function is_bigger (Shape left, Shape right) -> bool 82 | { 83 | return left.surface() > right.surface(); 84 | } 85 | 86 | main 87 | { 88 | let square := Rectangle(10, 10); 89 | let circle := Circle(25); 90 | 91 | println("square is Shape = " .. square is Shape); 92 | println("circle is Shape = " .. circle is Shape); 93 | println("square is Rectangle = " .. square is Rectangle); 94 | println("circle is Circle = " .. circle is Circle); 95 | println("circle is Rectangle = " .. circle is Rectangle); 96 | println("square is Circle = " .. square is Circle); 97 | 98 | println("I have two shapes:"); 99 | println("a" .. square); 100 | println("and a" .. circle); 101 | 102 | println("Is a " .. square .. " bigger than a " .. circle .. "?" .. (isBigger(square, circle) ? "yes" : "no")); 103 | } 104 | -------------------------------------------------------------------------------- /udfore/parser/Parser.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/ast/Expression.h" 4 | #include "udfore/ast/Statement.h" 5 | #include "udfore/parser/Parser.h" 6 | #include "udfore/token/Token.h" 7 | #include "udfore/utils/Logger.h" 8 | 9 | Parser *parser_create(Lexer *lexer) 10 | { 11 | Parser *parser = __create(Parser); 12 | 13 | parser->lexer = lexer; 14 | 15 | parser_advance(parser); 16 | parser_advance(parser); 17 | 18 | return parser; 19 | } 20 | 21 | void parser_destroy(Parser *parser) 22 | { 23 | if (parser->current) 24 | { 25 | token_destroy(parser->current); 26 | } 27 | 28 | if (parser->next) 29 | { 30 | token_destroy(parser->next); 31 | } 32 | 33 | if (parser->previous) 34 | { 35 | token_destroy(parser->previous); 36 | } 37 | 38 | free(parser); 39 | } 40 | 41 | void parser_advance(Parser *parser) 42 | { 43 | if (parser->previous) 44 | { 45 | token_destroy(parser->previous); 46 | } 47 | 48 | parser->previous = parser->current; 49 | parser->current = parser->next; 50 | parser->next = lexer_next_token(parser->lexer); 51 | } 52 | 53 | Token *parser_current(Parser *parser) 54 | { 55 | return parser->current; 56 | } 57 | 58 | Token *parser_next(Parser *parser) 59 | { 60 | return parser->next; 61 | } 62 | 63 | Token *parser_previous(Parser *parser) 64 | { 65 | return parser->previous; 66 | } 67 | 68 | bool parser_current_is(Parser *parser, TokenType expected) 69 | { 70 | return parser->current->type == expected; 71 | } 72 | 73 | bool parser_next_is(Parser *parser, TokenType expected) 74 | { 75 | return parser->next->type == expected; 76 | } 77 | 78 | bool parser_expect_current(Parser *parser, TokenType *expected) 79 | { 80 | Token *token = parser_current(parser); 81 | 82 | for (size_t i = 0; expected[i]; i++) 83 | { 84 | if (token->type == expected[i]) 85 | { 86 | return true; 87 | } 88 | } 89 | 90 | logger_error( 91 | "Unexpected token %s at line %d column %d", 92 | token_as_string(token), 93 | token->location.line, 94 | token->location.column); 95 | 96 | return false; 97 | } 98 | 99 | bool parser_expect_next(Parser *parser, TokenType *expected) 100 | { 101 | Token *token = parser_next(parser); 102 | 103 | for (size_t i = 0; expected[i]; i++) 104 | { 105 | if (token->type == expected[i]) 106 | { 107 | return true; 108 | } 109 | } 110 | 111 | logger_error( 112 | "Unexpected token %s at line %d column %d", 113 | token_as_string(token), 114 | token->location.line, 115 | token->location.column); 116 | 117 | return false; 118 | } 119 | -------------------------------------------------------------------------------- /udfore/parser/Statement.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/parser/Parser.h" 4 | 5 | ASTLetStatement *parser_parse_letstatement(Parser *parser) 6 | { 7 | if (!parser_expect_current(parser, (TokenType[]){TOKEN_LET, 0})) 8 | { 9 | return NULL; 10 | } 11 | 12 | parser_advance(parser); // skip the let keyword 13 | 14 | if (!parser_expect_current(parser, (TokenType[]){TOKEN_IDENTIFIER, 0})) 15 | { 16 | return NULL; 17 | } 18 | 19 | char *identifier = strdup(parser_current(parser)->chr); 20 | 21 | if (!parser_expect_next(parser, (TokenType[]){TOKEN_ASSIGN, 0})) 22 | { 23 | free(identifier); 24 | 25 | return NULL; 26 | } 27 | 28 | parser_advance(parser); // skip the identifier 29 | parser_advance(parser); // skip the assign operator 30 | 31 | return letstatement_create(identifier, parser_parse_expression(parser)); 32 | } 33 | 34 | ASTReturnStatement *parser_parse_returnstatement(Parser *parser) 35 | { 36 | if (!parser_expect_current(parser, (TokenType[]){TOKEN_RETURN, 0})) 37 | { 38 | return NULL; 39 | } 40 | 41 | parser_advance(parser); // skip the return keyword 42 | 43 | return returnstatement_create(parser_parse_expression(parser)); 44 | } 45 | 46 | ASTBlockStatement *parser_parse_blockstatement(Parser *parser) 47 | { 48 | if (!parser_expect_current(parser, (TokenType[]){TOKEN_LBRACE, 0})) 49 | { 50 | return NULL; 51 | } 52 | 53 | parser_advance(parser); //skip the lbrace 54 | 55 | ASTBlockStatement *block_statement = blockstatement_create(); 56 | 57 | while (!parser_current_is(parser, TOKEN_RBRACE) && !parser_current_is(parser, TOKEN_EOF)) 58 | { 59 | ASTStatement *inner_statement = parser_parse_statement(parser); 60 | 61 | if (inner_statement) 62 | { 63 | blockstatement_appent_statement(block_statement, inner_statement); 64 | } 65 | } 66 | 67 | return block_statement; 68 | } 69 | 70 | ASTExpressionStatement *parser_parse_expressionstatement(Parser *parser) 71 | { 72 | return expressionstatement_create(parser_parse_expression(parser)); 73 | } 74 | 75 | ASTStatement *parser_parse_statement(Parser *parser) 76 | { 77 | ASTStatement *statement = NULL; 78 | 79 | switch (parser_current(parser)->type) 80 | { 81 | case TOKEN_LET: 82 | statement = (ASTStatement *)parser_parse_letstatement(parser); 83 | break; 84 | 85 | case TOKEN_RETURN: 86 | statement = (ASTStatement *)parser_parse_returnstatement(parser); 87 | break; 88 | 89 | case TOKEN_LBRACE: 90 | statement = (ASTStatement *)parser_parse_blockstatement(parser); 91 | break; 92 | 93 | default: 94 | statement = (ASTStatement *)parser_parse_expressionstatement(parser); 95 | break; 96 | } 97 | 98 | if (parser_next_is(parser, TOKEN_SEMICOLON)) 99 | { 100 | parser_advance(parser); // skip the semi colon 101 | } 102 | 103 | return statement; 104 | } 105 | -------------------------------------------------------------------------------- /udfore.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /samples/kernel.ud: -------------------------------------------------------------------------------- 1 | take Size from builtin.types; 2 | 3 | module kernel 4 | { 5 | module vga 6 | { 7 | Size WIDTH := 80; 8 | Size HEIGHT := 25; 9 | 10 | enum Color : u8 11 | { 12 | BLACK, 13 | BLUE, 14 | GREEN, 15 | CYAN, 16 | RED, 17 | MAGENTA, 18 | BROWN, 19 | LIGHT_GREY, 20 | DARK_GREY, 21 | LIGHT_BLUE, 22 | LIGHT_GREEN, 23 | LIGHT_CYAN, 24 | LIGHT_RED, 25 | LIGHT_MAGENTA, 26 | LIGHT_BROWN, 27 | WHITE, 28 | } 29 | 30 | type Cell 31 | { 32 | u8 character; 33 | u8 color; 34 | 35 | property foreground -> Color 36 | { 37 | get -> .color & 0x0f; 38 | set -> .color = .color & 0xf0 | value; 39 | } 40 | 41 | property background -> Color 42 | { 43 | get -> .color & 0xf0 >> 4; 44 | set -> .color := .color & 0x0f | value << 4; 45 | } 46 | 47 | constructor() -> .(' ', Color.WHITE, Color.BLACK) 48 | 49 | constructor(u8 character, Color foreground, Color background) 50 | { 51 | .character = character; 52 | .foreground := foreground 53 | .background := background; 54 | } 55 | } 56 | 57 | const Cell DEFAULT := Cell(' ', Color.WHITE, Color.BLACK); 58 | 59 | type Screen 60 | { 61 | Cell[WIDTH, HEIGHT] cells; 62 | 63 | property[x, y] 64 | { 65 | get -> cells[x, y]; 66 | set -> cells[x, y] := value; 67 | } 68 | 69 | constructor() 70 | { 71 | clear(); 72 | } 73 | 74 | function clear() 75 | { 76 | for x in 0..WIDTH 77 | for y in 0..WIDTH 78 | cells[x, y] := DEFAULT; 79 | } 80 | } 81 | } 82 | 83 | 84 | function strlen(const char[] str) -> Size 85 | { 86 | Size size = 0; 87 | 88 | while (str[len]) 89 | { 90 | len++; 91 | } 92 | 93 | return len; 94 | } 95 | 96 | type Terminal 97 | { 98 | vga.Screen& screen; 99 | Size x := 0; 100 | Size y := 0; 101 | 102 | constructor(vga.Screen& screen) 103 | { 104 | .screen = screen; 105 | } 106 | 107 | function write(u8 chr) 108 | { 109 | screen[x, y] = vga.Cell(char, vga.Color.WHITE, vga.Color.BLACK); 110 | 111 | x++; 112 | 113 | if (x == vga.WIDTH) 114 | { 115 | x := 0; 116 | 117 | y++; 118 | 119 | if (y == vga.HEIGHT) 120 | { 121 | y = 0; 122 | } 123 | } 124 | } 125 | 126 | function write(const u8[] str) -> Size 127 | { 128 | for i in 0..strlen(str) 129 | { 130 | write(str[i]); 131 | } 132 | } 133 | } 134 | 135 | export function kmain 136 | { 137 | let screen := @RefFromPtr(0xB8000); 138 | 139 | let terminal := Terminal(screen); 140 | 141 | terminal.write("Hello, kernel World!\n"); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /udfore/token/Token.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "udfore/source/SourceLocation.h" 4 | #include "udfore/utils/Utils.h" 5 | 6 | #define TOKEN_TYPES_LIST(__ENTRY) \ 7 | __ENTRY(TOKEN_ILLEGAL) \ 8 | \ 9 | /* Operators */ \ 10 | __ENTRY(TOKEN_EQUAL) \ 11 | __ENTRY(TOKEN_NOTEQUAL) \ 12 | __ENTRY(TOKEN_BIGGER_THAN) \ 13 | __ENTRY(TOKEN_LESS_THAN) \ 14 | __ENTRY(TOKEN_BIGGER_OR_EQUAL_THAN) \ 15 | __ENTRY(TOKEN_LESS_OR_EQUAL_THAN) \ 16 | __ENTRY(TOKEN_ASSIGN) \ 17 | __ENTRY(TOKEN_PLUS) \ 18 | __ENTRY(TOKEN_PLUSPLUS) \ 19 | __ENTRY(TOKEN_MINUS) \ 20 | __ENTRY(TOKEN_MINUSMINUS) \ 21 | __ENTRY(TOKEN_MOD) \ 22 | __ENTRY(TOKEN_MULT) \ 23 | __ENTRY(TOKEN_DIV) \ 24 | \ 25 | __ENTRY(TOKEN_DOT) \ 26 | __ENTRY(TOKEN_DOTDOT) \ 27 | __ENTRY(TOKEN_ARROW) \ 28 | \ 29 | /* Literals */ \ 30 | __ENTRY(TOKEN_NUMBER) \ 31 | __ENTRY(TOKEN_STRING) \ 32 | __ENTRY(TOKEN_IDENTIFIER) \ 33 | \ 34 | /* Separators */ \ 35 | __ENTRY(TOKEN_LPARENT) \ 36 | __ENTRY(TOKEN_RPARENT) \ 37 | __ENTRY(TOKEN_LBRACE) \ 38 | __ENTRY(TOKEN_RBRACE) \ 39 | __ENTRY(TOKEN_LBRACKET) \ 40 | __ENTRY(TOKEN_RBRACKET) \ 41 | __ENTRY(TOKEN_COMMA) \ 42 | __ENTRY(TOKEN_SEMICOLON) \ 43 | __ENTRY(TOKEN_QUESTION) \ 44 | __ENTRY(TOKEN_COLON) \ 45 | \ 46 | /* Keywords */ \ 47 | __ENTRY(TOKEN_CAST) \ 48 | __ENTRY(TOKEN_CONSTRUCTOR) \ 49 | __ENTRY(TOKEN_DESTRUCTOR) \ 50 | __ENTRY(TOKEN_FROM) \ 51 | __ENTRY(TOKEN_FUNCTION) \ 52 | __ENTRY(TOKEN_LET) \ 53 | __ENTRY(TOKEN_MODULE) \ 54 | __ENTRY(TOKEN_RETURN) \ 55 | __ENTRY(TOKEN_SPEC) \ 56 | __ENTRY(TOKEN_TAKE) \ 57 | __ENTRY(TOKEN_TYPE) \ 58 | __ENTRY(TOKEN_USE) \ 59 | \ 60 | __ENTRY(TOKEN_EOF) 61 | 62 | #define TOKEN_TYPE_ENUM_ENTRY(__entry) __entry, 63 | typedef enum 64 | { 65 | TOKEN_TYPES_LIST(TOKEN_TYPE_ENUM_ENTRY) 66 | __TOKEN_TYPE_COUNT, 67 | } TokenType; 68 | #undef TOKEN_TYPE_ENUM_ENTRY 69 | 70 | typedef struct 71 | { 72 | TokenType type; 73 | 74 | SourceLocation location; 75 | 76 | int lenght; 77 | char *chr; 78 | } Token; 79 | 80 | typedef struct 81 | { 82 | const char *literal; 83 | TokenType type; 84 | } TokenLiteralToType; 85 | 86 | Token *token_create(TokenType type, SourceLocation location, char c); 87 | 88 | void token_destroy(Token *token); 89 | 90 | Token *token_append(Token *token, char c); 91 | 92 | const char *token_as_string(Token *token); 93 | 94 | const char *token_type_as_string(TokenType type); 95 | 96 | bool token_literal_is_keyword(const char *literal); 97 | 98 | bool token_literal_is_operator(const char *literal); 99 | 100 | TokenType keyword_literal_to_token_type(const char *literal); 101 | 102 | TokenType operator_literal_to_token_type(const char *literal); 103 | 104 | const char *operator_token_type_to_literal(TokenType type); 105 | -------------------------------------------------------------------------------- /udfore/tests/Lexer.test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/lexer/Lexer.h" 4 | #include "udfore/source/Source.h" 5 | #include "udfore/token/Token.h" 6 | #include "udfore/utils/Logger.h" 7 | 8 | bool test_lexer_expect(Source *src, const TokenType expected[]) 9 | { 10 | Lexer *lex = lexer_create(src); 11 | 12 | bool passed = true; 13 | 14 | for (size_t i = 0; expected[i] != TOKEN_EOF; i++) 15 | { 16 | Token *current_token = lexer_next_token(lex); 17 | 18 | if (current_token->type != expected[i]) 19 | { 20 | logger_error("test_lexer_expect failled got %s expected %s!", token_as_string(current_token), token_type_as_string(expected[i])); 21 | passed = false; 22 | } 23 | 24 | token_destroy(current_token); 25 | } 26 | 27 | if (!lexer_is_EOF(lex)) 28 | { 29 | logger_error("Didn't reached EOF!"); 30 | passed = false; 31 | } 32 | 33 | lexer_destroy(lex); 34 | 35 | return passed; 36 | } 37 | 38 | void test_lexer_expect_from_string(const char *input, const TokenType expected[]) 39 | { 40 | Source *src = string_source_create(input, strlen(input)); 41 | bool passed = test_lexer_expect(src, expected); 42 | source_destroy(src); 43 | 44 | if (passed) 45 | { 46 | logger_info("test_lexer_expect_from_string '%s' passed!", input); 47 | } 48 | else 49 | { 50 | logger_error("test_lexer_expect_from_string '%s' failled!", input); 51 | } 52 | } 53 | 54 | void test_lexer_expect_from_file(const char *file, const TokenType expected[]) 55 | { 56 | Source *src = file_source_create(file); 57 | bool passed = test_lexer_expect(src, expected); 58 | source_destroy(src); 59 | 60 | if (passed) 61 | { 62 | logger_info("test_lexer_expect_from_file '%s' passed!", file); 63 | } 64 | else 65 | { 66 | logger_error("test_lexer_expect_from_file '%s' failled!", file); 67 | } 68 | } 69 | 70 | int main(int argc, char const *argv[]) 71 | { 72 | (void)argc, (void)argv; 73 | 74 | const TokenType expected_empty[] = {TOKEN_EOF}; 75 | test_lexer_expect_from_file("./tests/empty.ud", expected_empty); 76 | test_lexer_expect_from_string("", expected_empty); 77 | 78 | const TokenType expected_use_system[] = {TOKEN_USE, TOKEN_IDENTIFIER, TOKEN_SEMICOLON, TOKEN_EOF}; 79 | test_lexer_expect_from_file("./tests/use-system.ud", expected_use_system); 80 | test_lexer_expect_from_string("use System;", expected_use_system); 81 | 82 | const TokenType expected_keywords[] = { 83 | TOKEN_CAST, 84 | TOKEN_CONSTRUCTOR, 85 | TOKEN_DESTRUCTOR, 86 | TOKEN_FROM, 87 | TOKEN_FUNCTION, 88 | TOKEN_LET, 89 | TOKEN_MODULE, 90 | TOKEN_RETURN, 91 | TOKEN_SPEC, 92 | TOKEN_TAKE, 93 | TOKEN_TYPE, 94 | TOKEN_USE, 95 | TOKEN_EOF, 96 | }; 97 | test_lexer_expect_from_file("./tests/keywords.ud", expected_keywords); 98 | test_lexer_expect_from_string("cast constructor destructor from function let module return spec take type use", expected_keywords); 99 | 100 | const TokenType expected_operators[] = { 101 | TOKEN_EQUAL, 102 | TOKEN_NOTEQUAL, 103 | TOKEN_BIGGER_THAN, 104 | TOKEN_LESS_THAN, 105 | TOKEN_ASSIGN, 106 | TOKEN_PLUS, 107 | TOKEN_PLUSPLUS, 108 | TOKEN_MINUS, 109 | TOKEN_MINUSMINUS, 110 | TOKEN_MULT, 111 | TOKEN_MOD, 112 | TOKEN_DIV, 113 | TOKEN_DOT, 114 | TOKEN_DOTDOT, 115 | TOKEN_ARROW, 116 | TOKEN_LPARENT, 117 | TOKEN_RPARENT, 118 | TOKEN_LBRACE, 119 | TOKEN_RBRACE, 120 | TOKEN_LBRACKET, 121 | TOKEN_RBRACKET, 122 | TOKEN_COMMA, 123 | TOKEN_SEMICOLON, 124 | TOKEN_QUESTION, 125 | TOKEN_COLON, 126 | TOKEN_EOF, 127 | }; 128 | 129 | test_lexer_expect_from_file("./tests/operators.ud", expected_operators); 130 | test_lexer_expect_from_string("= != > < := + ++ - -- * % / . .. -> ( ) { } [ ] , ; ? :", expected_operators); 131 | 132 | const TokenType expected_identifier[] = { 133 | TOKEN_IDENTIFIER, 134 | TOKEN_IDENTIFIER, 135 | TOKEN_IDENTIFIER, 136 | TOKEN_IDENTIFIER, 137 | TOKEN_NUMBER, 138 | TOKEN_EOF, 139 | }; 140 | 141 | test_lexer_expect_from_string("_abc123 _abc abc_ a_bc 1234", expected_identifier); 142 | 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /udfore/lexer/Lexer.c: -------------------------------------------------------------------------------- 1 | #include "udfore/lexer/Lexer.h" 2 | #include "udfore/utils/Logger.h" 3 | 4 | Lexer *lexer_create(Source *source) 5 | { 6 | Lexer *lexer = __create(Lexer); 7 | 8 | lexer->source = source; 9 | lexer->current.line = 1; 10 | lexer->current.column = 1; 11 | 12 | return lexer; 13 | } 14 | 15 | void lexer_destroy(Lexer *lexer) 16 | { 17 | free(lexer); 18 | } 19 | 20 | bool lexer_is_EOF(Lexer *lexer) 21 | { 22 | return source_is_EOF(lexer->source); 23 | } 24 | 25 | void lexer_next_char(Lexer *lexer) 26 | { 27 | source_next_char(lexer->source); 28 | 29 | if (!source_is_EOF(lexer->source)) 30 | { 31 | if (source_current_char(lexer->source) == '\n') 32 | { 33 | lexer->current.line++; 34 | lexer->current.column = 1; 35 | } 36 | else 37 | { 38 | lexer->current.column++; 39 | } 40 | } 41 | } 42 | 43 | char lexer_current_char(Lexer *lexer) 44 | { 45 | return source_current_char(lexer->source); 46 | } 47 | 48 | char lexer_peek_char(Lexer *lexer) 49 | { 50 | return source_peek_char(lexer->source); 51 | } 52 | 53 | void lexer_eat_white_space(Lexer *lexer) 54 | { 55 | while (utils_is_white_space(lexer_current_char(lexer))) 56 | { 57 | lexer_next_char(lexer); 58 | } 59 | } 60 | 61 | bool lexer_read_number(Lexer *lexer, Token *current_token) 62 | { 63 | if (!utils_is_number(lexer_current_char(lexer))) 64 | { 65 | return false; 66 | } 67 | 68 | while (utils_is_number(lexer_peek_char(lexer))) 69 | { 70 | lexer_next_char(lexer); 71 | token_append(current_token, lexer_current_char(lexer)); 72 | } 73 | 74 | current_token->type = TOKEN_NUMBER; 75 | 76 | return true; 77 | } 78 | 79 | bool lexer_read_string(Lexer *lexer, Token *current_token) 80 | { 81 | if (!(lexer_current_char(lexer) == '"')) 82 | { 83 | return false; 84 | } 85 | 86 | // Trim the " a the start of the token 87 | current_token->lenght = 0; 88 | 89 | while (lexer_peek_char(lexer) != '"' && !lexer_is_EOF(lexer)) 90 | { 91 | lexer_next_char(lexer); 92 | token_append(current_token, lexer_current_char(lexer)); 93 | } 94 | 95 | // Skip the last " 96 | if (lexer_peek_char(lexer) == '"') 97 | { 98 | lexer_next_char(lexer); 99 | } 100 | 101 | current_token->type = TOKEN_STRING; 102 | 103 | return true; 104 | } 105 | 106 | bool lexer_read_operator(Lexer *lexer, Token *current_token) 107 | { 108 | char literal1[] = { 109 | lexer_current_char(lexer), 110 | '\0', 111 | }; 112 | 113 | char literal2[] = { 114 | lexer_current_char(lexer), 115 | lexer_peek_char(lexer), 116 | '\0', 117 | }; 118 | 119 | if (token_literal_is_operator(literal2)) 120 | { 121 | lexer_next_char(lexer); 122 | token_append(current_token, lexer_current_char(lexer)); 123 | 124 | current_token->type = operator_literal_to_token_type(literal2); 125 | 126 | return true; 127 | } 128 | 129 | if (token_literal_is_operator(literal1)) 130 | { 131 | current_token->type = operator_literal_to_token_type(literal1); 132 | 133 | return true; 134 | } 135 | 136 | return false; 137 | } 138 | 139 | bool lexer_read_identifier_or_keyword(Lexer *lexer, Token *current_token) 140 | { 141 | if (!utils_is_identifier(lexer_current_char(lexer))) 142 | { 143 | return false; 144 | } 145 | 146 | while (utils_is_identifier(lexer_peek_char(lexer)) || 147 | utils_is_number(lexer_peek_char(lexer))) 148 | { 149 | lexer_next_char(lexer); 150 | token_append(current_token, lexer_current_char(lexer)); 151 | } 152 | 153 | current_token->type = TOKEN_IDENTIFIER; 154 | 155 | if (token_literal_is_keyword(current_token->chr)) 156 | { 157 | current_token->type = keyword_literal_to_token_type(current_token->chr); 158 | } 159 | 160 | return true; 161 | } 162 | 163 | Token *lexer_next_token(Lexer *lexer) 164 | { 165 | lexer_eat_white_space(lexer); 166 | 167 | Token *tok = token_create(TOKEN_ILLEGAL, lexer->current, lexer_current_char(lexer)); 168 | 169 | if (!(lexer_read_operator(lexer, tok) || 170 | lexer_read_number(lexer, tok) || 171 | lexer_read_string(lexer, tok) || 172 | lexer_read_identifier_or_keyword(lexer, tok))) 173 | { 174 | if (lexer_is_EOF(lexer)) 175 | { 176 | tok->type = TOKEN_EOF; 177 | } 178 | else 179 | { 180 | logger_warn("lexer_next_token got an illegale token: ln%d, col%d \"%s\"", tok->location.line, tok->location.column, tok->chr); 181 | } 182 | } 183 | 184 | lexer_next_char(lexer); 185 | // logger_trace("lexer_next_token return ln%d, col%d %s: \"%s\"", tok->location.line, tok->location.column, token_as_string(tok), tok->chr); 186 | 187 | return tok; 188 | } -------------------------------------------------------------------------------- /udfore/parser/Expression.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "udfore/parser/Expression.h" 4 | #include "udfore/parser/Parser.h" 5 | 6 | ASTExpressionIdentifier *parser_parse_identifier(Parser *parser) 7 | { 8 | return expression_identifier_create(parser_current(parser)->chr); 9 | } 10 | 11 | ASTValueExpression *parser_parse_value_expression(Parser *parser) 12 | { 13 | int32_t s32 = 0; 14 | 15 | sscanf(parser_current(parser)->chr, "%" SCNd32, &s32); 16 | 17 | return expression_value_create(value_create_s32(s32)); 18 | } 19 | 20 | ASTInfixExpression *parser_parse_infix_operator(Parser *parser, ASTExpression *lhs) 21 | { 22 | TokenType op = parser_current(parser)->type; 23 | 24 | parser_advance(parser); 25 | 26 | return expression_infix_operator_create(op, lhs, parser_parse_expression_with_precedence(parser, parser_get_precedence(op))); 27 | } 28 | 29 | static ExpressionParserCallback expression_parser_callback[] = { 30 | {TOKEN_IDENTIFIER, PRECEDENCE_LOWEST, {.prefix = (ParserPrefixCallback)parser_parse_identifier}}, 31 | {TOKEN_NUMBER, PRECEDENCE_LOWEST, {.prefix = (ParserPrefixCallback)parser_parse_value_expression}}, 32 | 33 | {TOKEN_EQUAL, PRECEDENCE_EQUALS, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 34 | {TOKEN_NOTEQUAL, PRECEDENCE_EQUALS, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 35 | {TOKEN_BIGGER_THAN, PRECEDENCE_LESSGREATER, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 36 | {TOKEN_LESS_THAN, PRECEDENCE_LESSGREATER, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 37 | {TOKEN_BIGGER_OR_EQUAL_THAN, PRECEDENCE_LESSGREATER, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 38 | {TOKEN_LESS_OR_EQUAL_THAN, PRECEDENCE_LESSGREATER, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 39 | 40 | {TOKEN_PLUS, PRECEDENCE_SUM, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 41 | {TOKEN_MINUS, PRECEDENCE_SUM, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 42 | {TOKEN_MULT, PRECEDENCE_PRODUCT, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 43 | {TOKEN_DIV, PRECEDENCE_PRODUCT, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 44 | {TOKEN_MOD, PRECEDENCE_MOD, {.infix = (ParserInfixCallback)parser_parse_infix_operator}}, 45 | 46 | {TOKEN_ILLEGAL, -1, {NULL, NULL, NULL}}, 47 | }; 48 | 49 | ParserPrefixCallback parser_get_prefix_callback(TokenType type) 50 | { 51 | for (size_t i = 0; expression_parser_callback[i].token != TOKEN_ILLEGAL; i++) 52 | { 53 | if (expression_parser_callback[i].token == type && 54 | expression_parser_callback[i].prefix != NULL) 55 | { 56 | return expression_parser_callback[i].prefix; 57 | } 58 | } 59 | 60 | return NULL; 61 | } 62 | 63 | ParserInfixCallback parser_get_infix_callback(TokenType type) 64 | { 65 | for (size_t i = 0; expression_parser_callback[i].token != TOKEN_ILLEGAL; i++) 66 | { 67 | if (expression_parser_callback[i].token == type && 68 | expression_parser_callback[i].infix != NULL) 69 | { 70 | return expression_parser_callback[i].infix; 71 | } 72 | } 73 | 74 | return NULL; 75 | } 76 | 77 | ParserPostfixCallback parser_get_postfix_callback(TokenType type) 78 | { 79 | for (size_t i = 0; expression_parser_callback[i].token != TOKEN_ILLEGAL; i++) 80 | { 81 | if (expression_parser_callback[i].token == type && 82 | expression_parser_callback[i].postfix != NULL) 83 | { 84 | return expression_parser_callback[i].postfix; 85 | } 86 | } 87 | 88 | return NULL; 89 | } 90 | 91 | ExpressionPrecedence parser_get_precedence(TokenType type) 92 | { 93 | for (size_t i = 0; expression_parser_callback[i].token != TOKEN_ILLEGAL; i++) 94 | { 95 | if (expression_parser_callback[i].token == type) 96 | { 97 | return expression_parser_callback[i].precedence; 98 | } 99 | } 100 | 101 | return PRECEDENCE_LOWEST; 102 | } 103 | 104 | ExpressionPrecedence parser_next_precedence(Parser *parser) 105 | { 106 | return parser_get_precedence(parser_next(parser)->type); 107 | } 108 | 109 | ASTExpression *parser_parse_expression(Parser *parser) 110 | { 111 | return parser_parse_expression_with_precedence(parser, PRECEDENCE_LOWEST); 112 | } 113 | 114 | ASTExpression *parser_parse_expression_with_precedence(Parser *parser, ExpressionPrecedence precedence) 115 | { 116 | ParserPrefixCallback prefix = parser_get_prefix_callback(parser_current(parser)->type); 117 | 118 | if (!prefix) 119 | { 120 | return NULL; 121 | } 122 | 123 | ASTExpression *lhs = prefix(parser); 124 | 125 | while (!parser_next_is(parser, TOKEN_SEMICOLON) && 126 | precedence < parser_next_precedence(parser)) 127 | { 128 | ParserInfixCallback infix = parser_get_infix_callback(parser_next(parser)->type); 129 | 130 | if (infix) 131 | { 132 | parser_advance(parser); 133 | lhs = infix(parser, lhs); 134 | } 135 | else 136 | { 137 | return lhs; 138 | } 139 | } 140 | 141 | return lhs; 142 | } -------------------------------------------------------------------------------- /udfore/utils/List.c: -------------------------------------------------------------------------------- 1 | #include "udfore/utils/List.h" 2 | #include "udfore/utils/Utils.h" 3 | 4 | List *list_create(void) 5 | { 6 | List *this = __create(List); 7 | 8 | this->count = 0; 9 | this->head = NULL; 10 | this->tail = NULL; 11 | 12 | return this; 13 | } 14 | 15 | void list_destroy(List *list) { list_destroy_with_callback(list, NULL); } 16 | void list_destroy_with_callback(List *list, ListDestroyElementCallback callback) 17 | { 18 | list_clear_with_callback(list, callback); 19 | free(list); 20 | } 21 | 22 | void list_clear(List *list) { list_clear_with_callback(list, NULL); } 23 | void list_clear_with_callback(List *list, ListDestroyElementCallback callback) 24 | { 25 | ListItem *current = list->head; 26 | 27 | while (current) 28 | { 29 | ListItem *next = current->next; 30 | 31 | if (callback) 32 | { 33 | callback(current->value); 34 | } 35 | 36 | free(current); 37 | 38 | current = next; 39 | } 40 | 41 | list->count = 0; 42 | list->head = NULL; 43 | list->tail = NULL; 44 | } 45 | 46 | List *list_clone(List *this) 47 | { 48 | List *copy = list_create(); 49 | 50 | list_foreach(void, value, this) 51 | { 52 | list_pushback(copy, value); 53 | } 54 | 55 | return copy; 56 | } 57 | 58 | void list_insert_sorted(List *this, void *value, ListCompareElementCallback callback) 59 | { 60 | if (this->head == NULL || callback(value, this->head->value)) 61 | { 62 | list_push(this, value); 63 | } 64 | else 65 | { 66 | ListItem *current = this->head; 67 | 68 | while (current->next != NULL && callback(current->next->value, value)) 69 | { 70 | current = current->next; 71 | } 72 | 73 | ListItem *item = malloc(sizeof(ListItem)); 74 | 75 | item->prev = current; 76 | item->next = current->next; 77 | item->value = value; 78 | 79 | if (current->next == NULL) 80 | { 81 | this->tail = item; 82 | } 83 | else 84 | { 85 | current->next->prev = item; 86 | } 87 | 88 | current->next = item; 89 | 90 | this->count++; 91 | } 92 | } 93 | 94 | bool list_peek(List *this, void **value) 95 | { 96 | if (this->head != NULL) 97 | { 98 | *value = this->head->value; 99 | 100 | return true; 101 | } 102 | else 103 | { 104 | *value = NULL; 105 | 106 | return false; 107 | } 108 | } 109 | 110 | bool list_peekback(List *this, void **value) 111 | { 112 | if (this->tail != NULL) 113 | { 114 | *value = this->tail->value; 115 | 116 | return true; 117 | } 118 | else 119 | { 120 | return false; 121 | } 122 | } 123 | 124 | static void list_peekat_from_head(List *this, int index, void **value) 125 | { 126 | ListItem *current = this->head; 127 | 128 | for (int i = 0; i < index; i++) 129 | { 130 | current = current->next; 131 | } 132 | 133 | *value = current->value; 134 | } 135 | 136 | static void list_peekat_from_back(List *this, int index, void **value) 137 | { 138 | ListItem *current = this->tail; 139 | 140 | for (int i = 0; i < (this->count - index - 1); i++) 141 | { 142 | current = current->prev; 143 | } 144 | 145 | *value = current->value; 146 | } 147 | 148 | bool list_peekat(List *this, int index, void **value) 149 | { 150 | if (this->count >= 1 && index >= 0 && index < this->count) 151 | { 152 | if (index < this->count / 2) 153 | { 154 | list_peekat_from_head(this, index, value); 155 | } 156 | else 157 | { 158 | list_peekat_from_back(this, index, value); 159 | } 160 | 161 | return true; 162 | } 163 | else 164 | { 165 | return false; 166 | } 167 | } 168 | 169 | int list_indexof(List *this, void *value) 170 | { 171 | int index = 0; 172 | 173 | list_foreach(void, item, this) 174 | { 175 | if (item == value) 176 | { 177 | return index; 178 | } 179 | 180 | index++; 181 | } 182 | 183 | return -1; 184 | } 185 | 186 | void list_push(List *this, void *value) 187 | { 188 | ListItem *item = malloc(sizeof(ListItem)); 189 | 190 | item->prev = NULL; 191 | item->next = NULL; 192 | item->value = value; 193 | 194 | this->count++; 195 | 196 | if (this->head == NULL) 197 | { 198 | this->head = item; 199 | this->tail = item; 200 | } 201 | else 202 | { 203 | this->head->prev = item; 204 | item->next = this->head; 205 | this->head = item; 206 | } 207 | } 208 | 209 | bool list_pop(List *this, void **value) 210 | { 211 | ListItem *item = this->head; 212 | 213 | if (this->count == 0) 214 | { 215 | return false; 216 | } 217 | else if (this->count == 1) 218 | { 219 | this->count = 0; 220 | this->head = NULL; 221 | this->tail = NULL; 222 | } 223 | else if (this->count > 1) 224 | { 225 | item->next->prev = NULL; 226 | this->head = item->next; 227 | 228 | this->count--; 229 | } 230 | 231 | if (value != NULL) 232 | { 233 | *value = item->value; 234 | } 235 | 236 | return true; 237 | } 238 | 239 | void list_pushback(List *this, void *value) 240 | { 241 | ListItem *item = malloc(sizeof(ListItem)); 242 | 243 | item->prev = NULL; 244 | item->next = NULL; 245 | item->value = value; 246 | 247 | this->count++; 248 | 249 | if (this->tail == NULL) 250 | { 251 | this->tail = item; 252 | this->head = item; 253 | } 254 | else 255 | { 256 | this->tail->next = item; 257 | item->prev = this->tail; 258 | this->tail = item; 259 | } 260 | } 261 | 262 | bool list_popback(List *this, void **value) 263 | { 264 | ListItem *item = this->tail; 265 | 266 | if (this->count == 0) 267 | { 268 | return NULL; 269 | } 270 | else if (this->count == 1) 271 | { 272 | this->count = 0; 273 | this->head = NULL; 274 | this->tail = NULL; 275 | } 276 | else if (this->count > 1) 277 | { 278 | item->prev->next = NULL; 279 | this->tail = item->prev; 280 | 281 | this->count--; 282 | } 283 | 284 | if (value != NULL) 285 | { 286 | *value = item->value; 287 | } 288 | 289 | return true; 290 | } 291 | 292 | bool list_remove(List *this, void *value) 293 | { 294 | for (ListItem *item = this->head; item != NULL; item = item->next) 295 | { 296 | if (item->value == value) 297 | { 298 | if (item->prev != NULL) 299 | { 300 | item->prev->next = item->next; 301 | } 302 | else 303 | { 304 | this->head = item->next; 305 | } 306 | 307 | if (item->next != NULL) 308 | { 309 | item->next->prev = item->prev; 310 | } 311 | else 312 | { 313 | this->tail = item->prev; 314 | } 315 | 316 | this->count--; 317 | free(item); 318 | 319 | return true; 320 | } 321 | } 322 | 323 | return false; 324 | } 325 | 326 | bool list_contains(List *this, void *value) 327 | { 328 | list_foreach(void, item, this) 329 | { 330 | if (item == value) 331 | { 332 | return true; 333 | } 334 | } 335 | 336 | return false; 337 | } --------------------------------------------------------------------------------