diff options
author | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-02-18 23:42:10 +0330 |
---|---|---|
committer | A404M <ahmadmahmoudiprogrammer@gmail.com> | 2025-02-18 23:42:10 +0330 |
commit | df4604f27bbd8ed42ea2c7026c7e4845aafd1a8b (patch) | |
tree | d877ced731ba28bf0ae8878d18b7eb392ff51404 | |
parent | 9eb9be33d7623a4759b0794073bd32489b865b3d (diff) |
add while
fix some memory leaks
-rw-r--r-- | src/compiler/ast-tree.c | 73 | ||||
-rw-r--r-- | src/compiler/ast-tree.h | 9 | ||||
-rw-r--r-- | src/compiler/lexer.c | 10 | ||||
-rw-r--r-- | src/compiler/lexer.h | 1 | ||||
-rw-r--r-- | src/compiler/parser.c | 72 | ||||
-rw-r--r-- | src/compiler/parser.h | 7 | ||||
-rw-r--r-- | src/runner/runner.c | 49 | ||||
-rw-r--r-- | test/main.felan | 11 |
8 files changed, 205 insertions, 27 deletions
diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c index 66a5f6b..3d7c675 100644 --- a/src/compiler/ast-tree.c +++ b/src/compiler/ast-tree.c @@ -110,6 +110,7 @@ const char *AST_TREE_TOKEN_STRINGS[] = { "AST_TREE_TOKEN_KEYWORD_PRINT_U64", "AST_TREE_TOKEN_KEYWORD_RETURN", "AST_TREE_TOKEN_KEYWORD_IF", + "AST_TREE_TOKEN_KEYWORD_WHILE", "AST_TREE_TOKEN_TYPE_FUNCTION", "AST_TREE_TOKEN_TYPE_TYPE", @@ -337,6 +338,23 @@ void astTreePrint(const AstTree *tree, int indent) { printf(" "); } goto RETURN_SUCCESS; + case AST_TREE_TOKEN_KEYWORD_WHILE: { + AstTreeWhile *metadata = tree->metadata; + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("condition=\n"); + astTreePrint(metadata->condition, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("body=\n"); + astTreePrint(metadata->body, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + } + goto RETURN_SUCCESS; case AST_TREE_TOKEN_SCOPE: { AstTreeScope *metadata = tree->metadata; printf(",\n"); @@ -487,6 +505,13 @@ void astTreeDestroy(AstTree tree) { free(metadata); } return; + case AST_TREE_TOKEN_KEYWORD_WHILE: { + AstTreeWhile *metadata = tree.metadata; + astTreeDelete(metadata->condition); + astTreeDelete(metadata->body); + free(metadata); + } + return; case AST_TREE_TOKEN_SCOPE: { AstTreeScope *metadata = tree.metadata; for (size_t i = 0; i < metadata->expressions_size; ++i) { @@ -676,6 +701,7 @@ AstTree *copyAstTree(AstTree *tree) { tree->str_begin, tree->str_end); } case AST_TREE_TOKEN_KEYWORD_IF: + case AST_TREE_TOKEN_KEYWORD_WHILE: case AST_TREE_TOKEN_SCOPE: case AST_TREE_TOKEN_NONE: } @@ -802,6 +828,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) { case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: case PARSER_TOKEN_SYMBOL_PARENTHESIS: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: goto AFTER_SWITCH; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_TYPE_TYPE: @@ -1036,6 +1063,8 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeHelper *helper) { return astTreeParseVariable(parserNode, helper); case PARSER_TOKEN_KEYWORD_IF: return astTreeParseIf(parserNode, helper); + case PARSER_TOKEN_KEYWORD_WHILE: + return astTreeParseWhile(parserNode, helper); case PARSER_TOKEN_SYMBOL_EOL: return astTreeParse((ParserNodeSingleChildMetadata *)parserNode->metadata, helper); @@ -1130,6 +1159,7 @@ AstTree *astTreeParseFunction(ParserNode *parserNode, AstTreeHelper *p_helper) { node = (ParserNodeSingleChildMetadata *)node->metadata; goto OK_NODE; case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: goto OK_NODE; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_IDENTIFIER: @@ -1512,6 +1542,27 @@ AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper) { parserNode->str_begin, parserNode->str_end); } +AstTree *astTreeParseWhile(ParserNode *parserNode, AstTreeHelper *helper) { + ParserNodeWhileMetadata *node_metadata = parserNode->metadata; + + AstTree *condition = astTreeParse(node_metadata->condition, helper); + if (condition == NULL) { + return NULL; + } + + AstTree *body = astTreeParse(node_metadata->body, helper); + if (body == NULL) { + return NULL; + } + + AstTreeWhile *metadata = a404m_malloc(sizeof(*metadata)); + metadata->condition = condition; + metadata->body = body; + + return newAstTree(AST_TREE_TOKEN_KEYWORD_WHILE, metadata, NULL, + parserNode->str_begin, parserNode->str_end); +} + AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *p_helper) { ParserNodeArray *body = parserNode->metadata; @@ -2054,6 +2105,8 @@ bool setAllTypes(AstTree *tree, AstTreeSetTypesHelper helper, return setTypesVariableDefine(tree, helper); case AST_TREE_TOKEN_KEYWORD_IF: return setTypesIf(tree, helper, function); + case AST_TREE_TOKEN_KEYWORD_WHILE: + return setTypesWhile(tree, helper, function); case AST_TREE_TOKEN_SCOPE: return setTypesScope(tree, helper, function); case AST_TREE_TOKEN_NONE: @@ -2448,6 +2501,25 @@ bool setTypesIf(AstTree *tree, AstTreeSetTypesHelper helper, return true; } +bool setTypesWhile(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunction *function) { + AstTreeWhile *metadata = tree->metadata; + + if (!setAllTypes(metadata->condition, helper, function) || + !setAllTypes(metadata->body, helper, function)) { + return false; + } + + if (!typeIsEqual(metadata->condition->type, &AST_TREE_BOOL_TYPE)) { + printError(metadata->condition->str_begin, metadata->condition->str_end, + "If condition must be boolean"); + return false; + } + + tree->type = &AST_TREE_VOID_TYPE; + return true; +} + bool setTypesScope(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function) { AstTreeScope *metadata = tree->metadata; @@ -2497,6 +2569,7 @@ bool astTreeClean(AstTree *tree) { case AST_TREE_TOKEN_KEYWORD_PRINT_U64: case AST_TREE_TOKEN_KEYWORD_RETURN: case AST_TREE_TOKEN_KEYWORD_IF: + case AST_TREE_TOKEN_KEYWORD_WHILE: case AST_TREE_TOKEN_TYPE_TYPE: case AST_TREE_TOKEN_TYPE_FUNCTION: case AST_TREE_TOKEN_TYPE_VOID: diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h index eaf8b07..b58d413 100644 --- a/src/compiler/ast-tree.h +++ b/src/compiler/ast-tree.h @@ -10,6 +10,7 @@ typedef enum AstTreeToken { AST_TREE_TOKEN_KEYWORD_PRINT_U64, AST_TREE_TOKEN_KEYWORD_RETURN, AST_TREE_TOKEN_KEYWORD_IF, + AST_TREE_TOKEN_KEYWORD_WHILE, AST_TREE_TOKEN_TYPE_FUNCTION, AST_TREE_TOKEN_TYPE_TYPE, @@ -149,6 +150,11 @@ typedef struct AstTreeIf { AstTree *elseBody; } AstTreeIf; +typedef struct AstTreeWhile { + AstTree *condition; + AstTree *body; +} AstTreeWhile; + typedef struct AstTreeHelper { AstTreeVariables **variables; size_t variables_size; @@ -198,6 +204,7 @@ AstTree *astTreeParseUnaryOperator(ParserNode *parserNode, bool astTreeParseConstant(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseVariable(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseIf(ParserNode *parserNode, AstTreeHelper *helper); +AstTree *astTreeParseWhile(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseCurlyBracket(ParserNode *parserNode, AstTreeHelper *helper); AstTree *astTreeParseParenthesis(ParserNode *parserNode, AstTreeHelper *helper); @@ -230,6 +237,8 @@ bool setTypesOperatorUnary(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesVariableDefine(AstTree *tree, AstTreeSetTypesHelper helper); bool setTypesIf(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function); +bool setTypesWhile(AstTree *tree, AstTreeSetTypesHelper helper, + AstTreeFunction *function); bool setTypesScope(AstTree *tree, AstTreeSetTypesHelper helper, AstTreeFunction *function); diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 7fef9be..6263854 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -33,6 +33,7 @@ const char *LEXER_TOKEN_STRINGS[] = { "LEXER_TOKEN_KEYWORD_FALSE", "LEXER_TOKEN_KEYWORD_IF", "LEXER_TOKEN_KEYWORD_ELSE", + "LEXER_TOKEN_KEYWORD_WHILE", "LEXER_TOKEN_NUMBER", @@ -93,9 +94,9 @@ 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", + "type", "void", "i8", "u8", "i16", "u16", "i32", "u32", + "i64", "u64", "f16", "f32", "f64", "f128", "bool", "print_u64", + "return", "true", "false", "if", "else", "while", }; const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_TYPE, LEXER_TOKEN_KEYWORD_VOID, @@ -108,7 +109,7 @@ const LexerToken LEXER_KEYWORD_TOKENS[] = { LEXER_TOKEN_KEYWORD_BOOL, LEXER_TOKEN_KEYWORD_PRINT_U64, LEXER_TOKEN_KEYWORD_RETURN, LEXER_TOKEN_KEYWORD_TRUE, LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_IF, - LEXER_TOKEN_KEYWORD_ELSE, + LEXER_TOKEN_KEYWORD_ELSE, LEXER_TOKEN_KEYWORD_WHILE, }; const size_t LEXER_KEYWORD_SIZE = sizeof(LEXER_KEYWORD_TOKENS) / sizeof(*LEXER_KEYWORD_TOKENS); @@ -255,6 +256,7 @@ void lexerPushClear(LexerNodeArray *array, size_t *array_size, char *iter, case LEXER_TOKEN_KEYWORD_FALSE: case LEXER_TOKEN_KEYWORD_IF: case LEXER_TOKEN_KEYWORD_ELSE: + case LEXER_TOKEN_KEYWORD_WHILE: 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 0a6da3a..92d943e 100644 --- a/src/compiler/lexer.h +++ b/src/compiler/lexer.h @@ -26,6 +26,7 @@ typedef enum LexerToken { LEXER_TOKEN_KEYWORD_FALSE, LEXER_TOKEN_KEYWORD_IF, LEXER_TOKEN_KEYWORD_ELSE, + LEXER_TOKEN_KEYWORD_WHILE, LEXER_TOKEN_NUMBER, diff --git a/src/compiler/parser.c b/src/compiler/parser.c index 84dca1c..9f6b060 100644 --- a/src/compiler/parser.c +++ b/src/compiler/parser.c @@ -38,6 +38,7 @@ const char *PARSER_TOKEN_STRINGS[] = { "PARSER_TOKEN_KEYWORD_PRINT_U64", "PARSER_TOKEN_KEYWORD_RETURN", "PARSER_TOKEN_KEYWORD_IF", + "PARSER_TOKEN_KEYWORD_WHILE", "PARSER_TOKEN_CONSTANT", "PARSER_TOKEN_VARIABLE", @@ -129,7 +130,7 @@ static constexpr ParserOrder PARSER_ORDER[] = { }, { .ltr = true, - ORDER_ARRAY(LEXER_TOKEN_KEYWORD_IF, ), + ORDER_ARRAY(LEXER_TOKEN_KEYWORD_IF, LEXER_TOKEN_KEYWORD_WHILE, ), }, }; @@ -354,7 +355,27 @@ void parserNodePrint(const ParserNode *node, int indent) { printf("\n"); for (int i = 0; i < indent; ++i) printf(" "); - free(metadata); + } + case PARSER_TOKEN_KEYWORD_WHILE: { + ParserNodeIfMetadata *metadata = node->metadata; + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("condition=\n"); + parserNodePrint(metadata->condition, indent + 1); + printf(",\n"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("ifBody=\n"); + parserNodePrint(metadata->ifBody, indent + 1); + printf("\n,"); + for (int i = 0; i < indent; ++i) + printf(" "); + printf("elseBody=\n"); + parserNodePrint(metadata->elseBody, indent + 1); + printf("\n"); + for (int i = 0; i < indent; ++i) + printf(" "); } goto RETURN_SUCCESS; case PARSER_TOKEN_NONE: @@ -483,6 +504,13 @@ void parserNodeDelete(ParserNode *node) { free(metadata); } goto RETURN_SUCCESS; + case PARSER_TOKEN_KEYWORD_WHILE: { + ParserNodeWhileMetadata *metadata = node->metadata; + parserNodeDelete(metadata->condition); + parserNodeDelete(metadata->body); + free(metadata); + } + goto RETURN_SUCCESS; case PARSER_TOKEN_NONE: } UNREACHABLE; @@ -692,6 +720,8 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end, } case LEXER_TOKEN_KEYWORD_IF: return parserIf(node, end, parent); + case LEXER_TOKEN_KEYWORD_WHILE: + return parserWhile(node, end, parent); case LEXER_TOKEN_KEYWORD_ELSE: case LEXER_TOKEN_SYMBOL: case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS: @@ -1058,6 +1088,7 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end, switch (bodyArray->data[i]->token) { case PARSER_TOKEN_SYMBOL_EOL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: continue; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_IDENTIFIER: @@ -1364,6 +1395,40 @@ ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent) { elseBody->str_end, metadata, parent); } +ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent) { + LexerNode *conditionNode = node + 1; + if (conditionNode >= end) { + printError(node->str_begin, node->str_end, "While has no condition"); + return NULL; + } + + ParserNode *condition = + getUntilCommonParent(conditionNode->parserNode, parent); + + if (condition == NULL) { + printError(conditionNode->str_begin, conditionNode->str_end, + "While has bad condition"); + return NULL; + } + + LexerNode *bodyNode = + getNextLexerNodeUsingCommonParent(conditionNode, end, parent); + ParserNode *body = getUntilCommonParent(bodyNode->parserNode, parent); + + if (body == NULL) { + printError(node->str_begin, node->str_end, "While has bad body"); + return NULL; + } + + ParserNodeWhileMetadata *metadata = a404m_malloc(sizeof(*metadata)); + metadata->condition = condition; + metadata->body = body; + + return condition->parent = body->parent = node->parserNode = + newParserNode(PARSER_TOKEN_KEYWORD_WHILE, node->str_begin, + body->str_end, metadata, parent); +} + bool isAllArguments(const ParserNodeArray *nodes) { for (size_t i = 0; i < nodes->size; ++i) { const ParserNode *node = nodes->data[i]; @@ -1402,6 +1467,7 @@ bool isExpression(ParserNode *node) { case PARSER_TOKEN_VALUE_FLOAT: case PARSER_TOKEN_VALUE_BOOL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: return true; case PARSER_TOKEN_ROOT: case PARSER_TOKEN_TYPE_TYPE: @@ -1478,6 +1544,7 @@ bool isType(ParserNode *node) { case PARSER_TOKEN_OPERATOR_GREATER_OR_EQUAL: case PARSER_TOKEN_OPERATOR_SMALLER_OR_EQUAL: case PARSER_TOKEN_KEYWORD_IF: + case PARSER_TOKEN_KEYWORD_WHILE: return false; case PARSER_TOKEN_NONE: } @@ -1533,6 +1600,7 @@ bool isValue(ParserNode *node) { case PARSER_TOKEN_SYMBOL_COMMA: case PARSER_TOKEN_KEYWORD_PRINT_U64: case PARSER_TOKEN_KEYWORD_RETURN: + case PARSER_TOKEN_KEYWORD_WHILE: return false; case PARSER_TOKEN_NONE: } diff --git a/src/compiler/parser.h b/src/compiler/parser.h index 3af47e7..6fe6d6f 100644 --- a/src/compiler/parser.h +++ b/src/compiler/parser.h @@ -34,6 +34,7 @@ typedef enum ParserToken { PARSER_TOKEN_KEYWORD_PRINT_U64, PARSER_TOKEN_KEYWORD_RETURN, PARSER_TOKEN_KEYWORD_IF, + PARSER_TOKEN_KEYWORD_WHILE, PARSER_TOKEN_CONSTANT, PARSER_TOKEN_VARIABLE, @@ -131,6 +132,11 @@ typedef struct ParserNodeIfMetadata { ParserNode *elseBody; } ParserNodeIfMetadata; +typedef struct ParserNodeWhileMetadata { + ParserNode *condition; + ParserNode *body; +} ParserNodeWhileMetadata; + void parserNodePrint(const ParserNode *node, int indent); void parserNodeDelete(ParserNode *node); @@ -175,6 +181,7 @@ ParserNode *parserBinaryOrLeftOperator(LexerNode *node, LexerNode *begin, ParserToken token, LexerToken laterToken); ParserNode *parserIf(LexerNode *node, LexerNode *end, ParserNode *parent); +ParserNode *parserWhile(LexerNode *node, LexerNode *end, ParserNode *parent); bool isAllArguments(const ParserNodeArray *nodes); diff --git a/src/runner/runner.c b/src/runner/runner.c index 0c8fbdd..54d6cfc 100644 --- a/src/runner/runner.c +++ b/src/runner/runner.c @@ -17,24 +17,24 @@ (void *)(u64)((type) * (originalType *)(op0)->metadata operator(type) * \ (originalType *)(op1)->metadata) -#define doLogicalOperation(op0, op1, operator, originalType, _type) \ +#define doLogicalOperation(op0, op1, operator, originalType, _type) \ { \ - bool res = (bool)((_type)(originalType)(op0) \ + bool res = (bool)((_type)(originalType)(op0) \ ->metadata \ - operator(_type)(originalType)(op1) \ + operator(_type)(originalType)(op1) \ ->metadata); \ astTreeDestroy(*(op0)); \ - (op0)->metadata = (void*)(u64)res; \ - (op0)->type = &AST_TREE_BOOL_TYPE; \ + (op0)->metadata = (void *)(u64)res; \ + (op0)->type = &AST_TREE_BOOL_TYPE; \ } -#define doLogicalOperationFloat(op0, op1, operator, originalType, _type) \ +#define doLogicalOperationFloat(op0, op1, operator, originalType, _type) \ { \ - bool res = (bool)(((_type) * ((originalType *)(op0)->metadata)) operator( \ - (_type) * ((originalType *)(op1)->metadata))); \ + bool res = (bool)(((_type) * ((originalType *)(op0)->metadata)) operator( \ + (_type) * ((originalType *)(op1)->metadata))); \ astTreeDestroy(*(op0)); \ - (op0)->metadata = (void*)(u64)res; \ - (op0)->type = &AST_TREE_BOOL_TYPE; \ + (op0)->metadata = (void *)(u64)res; \ + (op0)->type = &AST_TREE_BOOL_TYPE; \ } #define doLeftOperation(op0, operator, originalType, type) \ @@ -340,7 +340,20 @@ AstTree *runExpression(AstTree *expr, RunnerVariablePages *pages) { astTreeDelete(tree); return ret; } - return NULL; + case AST_TREE_TOKEN_KEYWORD_WHILE: { + AstTreeWhile *metadata = expr->metadata; + AstTree *ret = NULL; + while (true) { + AstTree *tree = calcAstTreeValue(metadata->condition, pages); + bool conti = (AstTreeBool)tree->metadata; + astTreeDelete(tree); + if (!conti) { + break; + } + ret = runExpression(metadata->body, pages); + } + return ret; + } case AST_TREE_TOKEN_SCOPE: { AstTreeScope *metadata = expr->metadata; @@ -365,12 +378,20 @@ AstTree *runExpression(AstTree *expr, RunnerVariablePages *pages) { runnerVariablePush(newPages.data[newPages.size - 1], variable); } + AstTree *ret = NULL; for (size_t i = 0; i < metadata->expressions_size; ++i) { - AstTree *r = runExpression(metadata->expressions[i], &newPages); - if (r) { - return r; + ret = runExpression(metadata->expressions[i], &newPages); + } + for (size_t i = 0; i < newPages.data[pages->size]->size; ++i) { + if (newPages.data[pages->size]->data[i]->value) { + astTreeDelete(newPages.data[pages->size]->data[i]->value); } + free(newPages.data[pages->size]->data[i]); } + free(newPages.data[pages->size]->data); + free(newPages.data[pages->size]); + free(newPages.data); + return ret; } return NULL; case AST_TREE_TOKEN_OPERATOR_PLUS: diff --git a/test/main.felan b/test/main.felan index 9d77aea..b99a284 100644 --- a/test/main.felan +++ b/test/main.felan @@ -1,10 +1,7 @@ main :: () -> void { - a :f32 = 23; - b :f64 = 54.5; - c :f128 = 1.0; - d :f16 = 5.5; - if -a == -23.0 - print_u64 1; - else + a := 10000; + while a > 0 { print_u64 2; + a = a -1; + } }; |