summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorA404M <ahmadmahmoudiprogrammer@gmail.com>2025-02-18 23:42:10 +0330
committerA404M <ahmadmahmoudiprogrammer@gmail.com>2025-02-18 23:42:10 +0330
commitdf4604f27bbd8ed42ea2c7026c7e4845aafd1a8b (patch)
treed877ced731ba28bf0ae8878d18b7eb392ff51404 /src/compiler
parent9eb9be33d7623a4759b0794073bd32489b865b3d (diff)
add while
fix some memory leaks
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/ast-tree.c73
-rw-r--r--src/compiler/ast-tree.h9
-rw-r--r--src/compiler/lexer.c10
-rw-r--r--src/compiler/lexer.h1
-rw-r--r--src/compiler/parser.c72
-rw-r--r--src/compiler/parser.h7
6 files changed, 166 insertions, 6 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);