diff options
author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-04-04 18:31:59 +0330 |
---|---|---|
committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-04-04 18:31:59 +0330 |
commit | 6bfad51dbde77267368811737d4ecbd557eac2e9 (patch) | |
tree | 3bb12aa2ba13926bd03591dd7560b38bfb58f222 | |
parent | 2a03e1e42906605be5ea093bcaca212c41acb62f (diff) |
first stuff to have a struct
-rw-r--r-- | code/main.felan | 14 | ||||
-rw-r--r-- | src/compiler/ast-tree.c | 142 | ||||
-rw-r--r-- | src/compiler/ast-tree.h | 10 | ||||
-rw-r--r-- | src/compiler/lexer.c | 10 | ||||
-rw-r--r-- | src/compiler/lexer.h | 1 | ||||
-rw-r--r-- | src/compiler/parser.c | 33 | ||||
-rw-r--r-- | src/compiler/parser.h | 2 |
7 files changed, 192 insertions, 20 deletions
diff --git a/code/main.felan b/code/main.felan index 532afaa..f755d37 100644 --- a/code/main.felan +++ b/code/main.felan @@ -5,14 +5,12 @@ long :: i64; float :: f32; double :: f64; -main :: () -> void { - f := foo(); - f(3); +st :: struct { + a : int; + b : double; }; -foo :: ()->((u64)->void){ - f :: (a:u64)->void{ - print_u64 a; - }; - return f; +main :: () -> void { + print_u64 1234; }; + diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c index 4c6d36d..261e13b 100644 --- a/src/compiler/ast-tree.c +++ b/src/compiler/ast-tree.c @@ -112,6 +112,7 @@ const char *AST_TREE_TOKEN_STRINGS[] = { "AST_TREE_TOKEN_KEYWORD_IF", "AST_TREE_TOKEN_KEYWORD_WHILE", "AST_TREE_TOKEN_KEYWORD_COMPTIME", + "AST_TREE_TOKEN_KEYWORD_STRUCT", "AST_TREE_TOKEN_TYPE_FUNCTION", "AST_TREE_TOKEN_TYPE_TYPE", @@ -341,7 +342,6 @@ void astTreePrint(const AstTree *tree, int indent) { case AST_TREE_TOKEN_OPERATOR_SMALLER: case AST_TREE_TOKEN_OPERATOR_GREATER_OR_EQUAL: case AST_TREE_TOKEN_OPERATOR_SMALLER_OR_EQUAL: { - AstTreeInfix *metadata = tree->metadata; printf(",\n"); for (int i = 0; i < indent; ++i) @@ -412,6 +412,23 @@ void astTreePrint(const AstTree *tree, int indent) { printf("]"); } goto RETURN_SUCCESS; + case AST_TREE_TOKEN_KEYWORD_STRUCT: { + AstTreeStruct *metadata = tree->metadata; + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("variables=[\n"); + for (size_t i = 0; i < metadata->variables.size; ++i) { + astTreeVariablePrint(metadata->variables.data[i], indent + 1); + printf(",\n"); + } + for (int i = 0; i < indent; ++i) { + printf(" "); + } + printf("]"); + + goto RETURN_SUCCESS; + } case AST_TREE_TOKEN_NONE: } @@ -421,14 +438,21 @@ RETURN_SUCCESS: printf("}"); } +void astTreeVariablePrint(const AstTreeVariable *variable, int indent) { + for (int i = 0; i < indent; ++i) { + printf(" "); + } + printf("{\nname=\"%.*s\",\nvalue=\n", + (int)(variable->name_end - variable->name_begin), + variable->name_begin); + astTreePrint(variable->value, indent); + printf("\n}"); +} + void astTreeRootPrint(const AstTreeRoot *root) { for (size_t i = 0; i < root->variables.size; ++i) { - const AstTreeVariable *variable = root->variables.data[i]; - printf("{\nname=\"%.*s\",\nvalue=\n", - (int)(variable->name_end - variable->name_begin), - variable->name_begin); - astTreePrint(variable->value, 1); - printf("\n}\n"); + astTreeVariablePrint(root->variables.data[i], 0); + printf("\n"); } } @@ -581,6 +605,15 @@ void astTreeDestroy(AstTree tree) { free(metadata); } return; + case AST_TREE_TOKEN_KEYWORD_STRUCT: { + AstTreeStruct *metadata = tree.metadata; + for (size_t i = 0; i < metadata->variables.size; ++i) { + astTreeVariableDelete(metadata->variables.data[i]); + } + free(metadata->variables.data); + free(metadata); + } + return; case AST_TREE_TOKEN_NONE: } printLog("token = %d", tree.token); @@ -908,6 +941,18 @@ AstTree *copyAstTreeBack(AstTree *tree, AstTreeVariables oldVariables[], new_newVariables, new_variables_size), tree->str_begin, tree->str_end); } + case AST_TREE_TOKEN_KEYWORD_STRUCT: { + AstTreeStruct *metadata = tree->metadata; + AstTreeStruct *new_metadata = a404m_malloc(sizeof(*new_metadata)); + + new_metadata->variables = copyAstTreeVariables( + metadata->variables, oldVariables, newVariables, variables_size); + + return newAstTree( + tree->token, new_metadata, + copyAstTreeBack(tree->type, oldVariables, newVariables, variables_size), + tree->str_begin, tree->str_end); + } case AST_TREE_TOKEN_NONE: } printLog("Bad token %d", tree->token); @@ -1078,6 +1123,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) { case PARSER_TOKEN_OPERATOR_POINTER: case PARSER_TOKEN_OPERATOR_ADDRESS: case PARSER_TOKEN_OPERATOR_DEREFERENCE: + case PARSER_TOKEN_KEYWORD_STRUCT: goto AFTER_SWITCH; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_KEYWORD_PRINT_U64: @@ -1337,6 +1383,8 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) { return astTreeParseCurlyBracket(parserNode, helper); case PARSER_TOKEN_SYMBOL_PARENTHESIS: return astTreeParseParenthesis(parserNode, helper); + case PARSER_TOKEN_KEYWORD_STRUCT: + return astTreeParseStruct(parserNode, helper); case PARSER_TOKEN_CONSTANT: case PARSER_TOKEN_SYMBOL_COMMA: case PARSER_TOKEN_NONE: @@ -1450,6 +1498,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *p_helper) { case PARSER_TOKEN_KEYWORD_PRINT_U64: case PARSER_TOKEN_KEYWORD_RETURN: case PARSER_TOKEN_KEYWORD_COMPTIME: + case PARSER_TOKEN_KEYWORD_STRUCT: case PARSER_TOKEN_CONSTANT: case PARSER_TOKEN_VARIABLE: case PARSER_TOKEN_SYMBOL_CURLY_BRACKET: @@ -1991,6 +2040,7 @@ AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, case PARSER_TOKEN_KEYWORD_PRINT_U64: case PARSER_TOKEN_KEYWORD_RETURN: case PARSER_TOKEN_KEYWORD_COMPTIME: + case PARSER_TOKEN_KEYWORD_STRUCT: case PARSER_TOKEN_CONSTANT: case PARSER_TOKEN_VARIABLE: case PARSER_TOKEN_SYMBOL_CURLY_BRACKET: @@ -2078,6 +2128,56 @@ AstTree *astTreeParseParenthesis(ParserNode *parserNode, } } +AstTree *astTreeParseStruct(ParserNode *parserNode, AstTreeHelper *helper) { + ParserNode *body = parserNode->metadata; + ParserNodeArray *body_metadata = body->metadata; + AstTreeVariables variables = { + .data = a404m_malloc(sizeof(*variables.data) * body_metadata->size), + .size = body_metadata->size, + }; + + for (size_t i = 0; i < body_metadata->size; ++i) { + ParserNode *node = body_metadata->data[i]; + if (node->token != PARSER_TOKEN_SYMBOL_EOL) { + printError(node->str_begin, node->str_end, + "Semicolon is required, maybe forget a semicolon?"); + return NULL; + } + node = (ParserNodeSingleChildMetadata *)node->metadata; + + if (node->token != PARSER_TOKEN_VARIABLE) { + printError(node->str_begin, node->str_end, + "Only variable definitions are allowed here"); + return NULL; + } + ParserNodeVariableMetadata *node_variable = node->metadata; + + AstTreeVariable *variable = a404m_malloc(sizeof(*variable)); + variable->name_begin = node_variable->name->str_begin; + variable->name_end = node_variable->name->str_end; + if (node_variable->type != NULL) { + variable->type = astTreeParse(node_variable->type, helper); + } else { + variable->type = NULL; + } + if (node_variable->value != NULL) { + printError(node->str_begin, node->str_end, "Can't have default values"); + NOT_IMPLEMENTED; + } + variable->value = NULL; + variable->isConst = false; + + variables.data[i] = variable; + } + + AstTreeStruct *metadata = a404m_malloc(sizeof(*metadata)); + metadata->variables = variables; + metadata->id = (size_t)metadata; // TODO: change it + + return newAstTree(AST_TREE_TOKEN_KEYWORD_STRUCT, metadata, NULL, + parserNode->str_begin, parserNode->str_end); +} + bool isFunction(AstTree *value) { return value->type->token == AST_TREE_TOKEN_TYPE_FUNCTION; } @@ -2107,6 +2207,7 @@ bool isConst(AstTree *tree, AstTreeHelper *helper) { case AST_TREE_TOKEN_VALUE_BOOL: case AST_TREE_TOKEN_KEYWORD_COMPTIME: case AST_TREE_TOKEN_SCOPE: + case AST_TREE_TOKEN_KEYWORD_STRUCT: return true; case AST_TREE_TOKEN_KEYWORD_IF: { AstTreeIf *metadata = tree->metadata; @@ -2179,6 +2280,7 @@ AstTree *makeTypeOf(AstTree *value) { case AST_TREE_TOKEN_TYPE_F128: case AST_TREE_TOKEN_TYPE_BOOL: case AST_TREE_TOKEN_OPERATOR_POINTER: + case AST_TREE_TOKEN_KEYWORD_STRUCT: return &AST_TREE_TYPE_TYPE; case AST_TREE_TOKEN_OPERATOR_ADDRESS: { AstTreeSingleChild *metadata = value->metadata; @@ -2348,6 +2450,14 @@ bool typeIsEqual(const AstTree *type0, const AstTree *type1) { case AST_TREE_TOKEN_VARIABLE: return type1->token == AST_TREE_TOKEN_VARIABLE && type0->metadata == type1->metadata; + case AST_TREE_TOKEN_KEYWORD_STRUCT: { + if (type1->token != AST_TREE_TOKEN_KEYWORD_STRUCT) + return false; + + AstTreeStruct *type0_metadata = type0->metadata; + AstTreeStruct *type1_metadata = type1->metadata; + return type0_metadata->id == type1_metadata->id; + } case AST_TREE_TOKEN_NONE: } UNREACHABLE; @@ -2411,6 +2521,7 @@ AstTree *getValue(AstTree *tree, AstTreeSetTypesHelper helper) { } return value; } + case AST_TREE_TOKEN_KEYWORD_STRUCT: case AST_TREE_TOKEN_FUNCTION: { return tree; } @@ -2437,7 +2548,6 @@ bool isCircularDependenciesBack(AstTreeHelper *helper, AstTreeVariable *variable, AstTree *tree, AstTreeVariables *checkedVariables) { switch (tree->token) { - case AST_TREE_TOKEN_SCOPE: case AST_TREE_TOKEN_TYPE_TYPE: case AST_TREE_TOKEN_TYPE_FUNCTION: case AST_TREE_TOKEN_TYPE_VOID: @@ -2517,9 +2627,11 @@ bool isCircularDependenciesBack(AstTreeHelper *helper, } return false; } + case AST_TREE_TOKEN_KEYWORD_STRUCT: case AST_TREE_TOKEN_FUNCTION: { return false; } + case AST_TREE_TOKEN_SCOPE: case AST_TREE_TOKEN_KEYWORD_PRINT_U64: case AST_TREE_TOKEN_KEYWORD_RETURN: case AST_TREE_TOKEN_VARIABLE_DEFINE: @@ -2668,6 +2780,8 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper, return setTypesScope(tree, helper, function); case AST_TREE_TOKEN_KEYWORD_COMPTIME: return setTypesComptime(tree, helper); + case AST_TREE_TOKEN_KEYWORD_STRUCT: + return setTypesStruct(tree, helper); case AST_TREE_TOKEN_NONE: break; } @@ -3302,6 +3416,18 @@ bool setTypesComptime(AstTree *tree, AstTreeSetTypesHelper helper) { return true; } +bool setTypesStruct(AstTree *tree, AstTreeSetTypesHelper helper) { + AstTreeStruct *metadata = tree->metadata; + + for (size_t i = 0; i < metadata->variables.size; ++i) { + if (!setAllTypes(metadata->variables.data[i]->type, helper, NULL)) { + return false; + } + } + tree->type = &AST_TREE_TYPE_TYPE; + return true; +} + bool setTypesAstInfix(AstTreeInfix *infix, AstTreeSetTypesHelper helper) { if (!setAllTypes(&infix->left, helper, NULL)) { return false; diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h index 1513284..a62e195 100644 --- a/src/compiler/ast-tree.h +++ b/src/compiler/ast-tree.h @@ -3,6 +3,7 @@ #include "compiler/parser.h" #include <stddef.h> #include <stdint.h> +#include <sys/types.h> typedef enum AstTreeToken { AST_TREE_TOKEN_FUNCTION, @@ -12,6 +13,7 @@ typedef enum AstTreeToken { AST_TREE_TOKEN_KEYWORD_IF, AST_TREE_TOKEN_KEYWORD_WHILE, AST_TREE_TOKEN_KEYWORD_COMPTIME, + AST_TREE_TOKEN_KEYWORD_STRUCT, AST_TREE_TOKEN_TYPE_FUNCTION, AST_TREE_TOKEN_TYPE_TYPE, @@ -186,7 +188,13 @@ typedef struct AstTreeSetTypesHelper { AstTreeHelper *treeHelper; } AstTreeSetTypesHelper; +typedef struct AstTreeStruct { + size_t id; + AstTreeVariables variables; +} AstTreeStruct; + void astTreePrint(const AstTree *tree, int indent); +void astTreeVariablePrint(const AstTreeVariable *variable, int indent); void astTreeRootPrint(const AstTreeRoot *root); void astTreeDestroy(AstTree tree); @@ -241,6 +249,7 @@ AstTree *astTreeParseComptime(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseParenthesis(ParserNode *parserNode, AstTreeHelper *helper); +AstTree *astTreeParseStruct(ParserNode *parserNode, AstTreeHelper *helper); bool isFunction(AstTree *value); bool isConst(AstTree *tree, AstTreeHelper *helper); @@ -287,6 +296,7 @@ bool setTypesWhile(AstTree *tree, AstTreeSetTypesHelper helper, bool setTypesScope(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function); bool setTypesComptime(AstTree *tree, AstTreeSetTypesHelper helper); +bool setTypesStruct(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesAstVariable(AstTreeVariable *variable, AstTreeSetTypesHelper helper); diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 75fb04b..618851d 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -36,6 +36,7 @@ const char *LEXER_TOKEN_STRINGS[] = { "LEXER_TOKEN_KEYWORD_WHILE", "LEXER_TOKEN_KEYWORD_COMPTIME", "LEXER_TOKEN_KEYWORD_NULL", + "LEXER_TOKEN_KEYWORD_STRUCT", "LEXER_TOKEN_NUMBER", @@ -111,9 +112,10 @@ const size_t LEXER_SYMBOL_SIZE = sizeof(LEXER_SYMBOL_TOKENS) / sizeof(*LEXER_SYMBOL_TOKENS); const char *LEXER_KEYWORD_STRINGS[] = { - "type", "void", "i8", "u8", "i16", "u16", "i32", "u32", - "i64", "u64", "f16", "f32", "f64", "f128", "bool", "print_u64", - "return", "true", "false", "if", "else", "while", "comptime", "null", + "type", "void", "i8", "u8", "i16", "u16", "i32", + "u32", "i64", "u64", "f16", "f32", "f64", "f128", + "bool", "print_u64", "return", "true", "false", "if", "else", + "while", "comptime", "null", "struct", }; const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_TYPE, LEXER_TOKEN_KEYWORD_VOID, @@ -128,6 +130,7 @@ const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_IF, LEXER_TOKEN_KEYWORD_ELSE, LEXER_TOKEN_KEYWORD_WHILE, LEXER_TOKEN_KEYWORD_COMPTIME, LEXER_TOKEN_KEYWORD_NULL, + LEXER_TOKEN_KEYWORD_STRUCT, }; const size_t LEXER_KEYWORD_SIZE = sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS); @@ -281,6 +284,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter, case LEXER_TOKEN_KEYWORD_WHILE: case LEXER_TOKEN_KEYWORD_COMPTIME: case LEXER_TOKEN_KEYWORD_NULL: + case LEXER_TOKEN_KEYWORD_STRUCT: case LEXER_TOKEN_NUMBER: case LEXER_TOKEN_SYMBOL_EOL: case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS: diff --git a/src/compiler/lexer.h b/src/compiler/lexer.h index 5e2496b..6daa893 100644 --- a/src/compiler/lexer.h +++ b/src/compiler/lexer.h @@ -29,6 +29,7 @@ typedef enum LexerToken { LEXER_TOKEN_KEYWORD_WHILE, LEXER_TOKEN_KEYWORD_COMPTIME, LEXER_TOKEN_KEYWORD_NULL, + LEXER_TOKEN_KEYWORD_STRUCT, LEXER_TOKEN_NUMBER, diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 69a9c8a..d7fbade 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -41,6 +41,7 @@ const char *PARSER_TOKEN_STRINGS[] = { "PARSER_TOKEN_KEYWORD_WHILE", "PARSER_TOKEN_KEYWORD_COMPTIME", "PARSER_TOKEN_KEYWORD_NULL", + "PARSER_TOKEN_KEYWORD_STRUCT", "PARSER_TOKEN_CONSTANT", "PARSER_TOKEN_VARIABLE", @@ -106,7 +107,7 @@ static constexpr ParserOrder PARSER_ORDER[] = { { .ltr = false, ORDER_ARRAY(LEXER_TOKEN_SYMBOL_FUNCTION_ARROW, - LEXER_TOKEN_SYMBOL_POINTER, ), + LEXER_TOKEN_SYMBOL_POINTER, LEXER_TOKEN_KEYWORD_STRUCT, ), }, { .ltr = true, @@ -245,6 +246,7 @@ void parserNodePrint(const ParserNode *node, int indent) { printf(" "); } goto RETURN_SUCCESS; + case PARSER_TOKEN_KEYWORD_STRUCT: case PARSER_TOKEN_OPERATOR_POINTER: case PARSER_TOKEN_OPERATOR_ADDRESS: case PARSER_TOKEN_OPERATOR_DEREFERENCE: @@ -482,6 +484,7 @@ void parserNodeDelete(ParserNode *node) { free(metadata); } goto RETURN_SUCCESS; + case PARSER_TOKEN_KEYWORD_STRUCT: case PARSER_TOKEN_OPERATOR_POINTER: case PARSER_TOKEN_OPERATOR_ADDRESS: case PARSER_TOKEN_OPERATOR_DEREFERENCE: @@ -816,6 +819,8 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end, return parserWhile(node, end, parent); case LEXER_TOKEN_KEYWORD_COMPTIME: return parserComptime(node, end, parent); + case LEXER_TOKEN_KEYWORD_STRUCT: + return parserStruct(node, end, parent); case LEXER_TOKEN_KEYWORD_ELSE: case LEXER_TOKEN_SYMBOL: case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS: @@ -1209,6 +1214,7 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end, case PARSER_TOKEN_KEYWORD_NULL: case PARSER_TOKEN_KEYWORD_PRINT_U64: case PARSER_TOKEN_KEYWORD_RETURN: + case PARSER_TOKEN_KEYWORD_STRUCT: case PARSER_TOKEN_CONSTANT: case PARSER_TOKEN_VARIABLE: case PARSER_TOKEN_SYMBOL_CURLY_BRACKET: @@ -1599,6 +1605,28 @@ ParserNode *parserComptime(LexerNode *node, LexerNode *end, (ParserNodeSingleChildMetadata *)operand, parent); } +ParserNode *parserStruct(LexerNode *node, LexerNode *end, ParserNode *parent) { + LexerNode *next = node + 1; + if (next >= end) { + printError(node->str_begin, node->str_end, "Bad struct without a body"); + return NULL; + } + + ParserNode *operand = getUntilCommonParent(next->parserNode, parent); + + if (operand == NULL) { + printError(node->str_begin, node->str_end, "Bad struct without a body"); + return NULL; + } else if (operand->token != PARSER_TOKEN_SYMBOL_CURLY_BRACKET) { + printError(node->str_begin, node->str_end, "Bad body"); + return NULL; + } + + return operand->parent = node->parserNode = newParserNode( + PARSER_TOKEN_KEYWORD_STRUCT, node->str_begin, operand->str_end, + (ParserNodeSingleChildMetadata *)operand, parent); +} + bool isAllArguments(const ParserNodeArray *nodes) { for (size_t i = 0; i < nodes->size; ++i) { const ParserNode *node = nodes->data[i]; @@ -1664,6 +1692,7 @@ bool isExpression(ParserNode *node) { case PARSER_TOKEN_TYPE_F64: case PARSER_TOKEN_TYPE_F128: case PARSER_TOKEN_KEYWORD_NULL: + case PARSER_TOKEN_KEYWORD_STRUCT: return true; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_SYMBOL_EOL: @@ -1700,6 +1729,7 @@ bool isType(ParserNode *node) { case PARSER_TOKEN_KEYWORD_COMPTIME: case PARSER_TOKEN_OPERATOR_POINTER: case PARSER_TOKEN_SYMBOL_CURLY_BRACKET: + case PARSER_TOKEN_KEYWORD_STRUCT: return true; case PARSER_TOKEN_OPERATOR_ADDRESS: case PARSER_TOKEN_KEYWORD_NULL: @@ -1791,6 +1821,7 @@ bool isValue(ParserNode *node) { case PARSER_TOKEN_KEYWORD_IF: case PARSER_TOKEN_KEYWORD_COMPTIME: case PARSER_TOKEN_SYMBOL_PARENTHESIS: + case PARSER_TOKEN_KEYWORD_STRUCT: return true; case PARSER_TOKEN_CONSTANT: case PARSER_TOKEN_VARIABLE: diff --git a/src/compiler/parser.h b/src/compiler/parser.h index e566696..317e913 100644 --- a/src/compiler/parser.h +++ b/src/compiler/parser.h @@ -37,6 +37,7 @@ typedef enum ParserToken { PARSER_TOKEN_KEYWORD_WHILE, PARSER_TOKEN_KEYWORD_COMPTIME, PARSER_TOKEN_KEYWORD_NULL, + PARSER_TOKEN_KEYWORD_STRUCT, PARSER_TOKEN_CONSTANT, PARSER_TOKEN_VARIABLE, @@ -197,6 +198,7 @@ ParserNode *parserRightOperator(LexerNode *node, LexerNode *begin, ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent); ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent); ParserNode *parserComptime(LexerNode *node, LexerNode *end, ParserNode *parent); +ParserNode *parserStruct(LexerNode *node, LexerNode *end, ParserNode *parent); bool isAllArguments(const ParserNodeArray *nodes); |