summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorA404M <ahmadmahmoudiprogrammer@gmail.com>2025-01-30 08:54:18 +0330
committerA404M <ahmadmahmoudiprogrammer@gmail.com>2025-01-30 08:54:18 +0330
commit9f2b1bdcfbbc084876c3ab7cc2cb8c15ffb88184 (patch)
treecf46656b50fa3d868a7bed4821667f6a31ea922c /src/compiler
parentd32d148cee5b3aec5e8943738aa30139d442478c (diff)
added assign operator
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/ast-tree.c104
-rw-r--r--src/compiler/ast-tree.h22
-rw-r--r--src/compiler/code-generator.c90
-rw-r--r--src/compiler/code-generator.h8
-rw-r--r--src/compiler/parser.c67
-rw-r--r--src/compiler/parser.h9
6 files changed, 293 insertions, 7 deletions
diff --git a/src/compiler/ast-tree.c b/src/compiler/ast-tree.c
index 8043561..c38a4b8 100644
--- a/src/compiler/ast-tree.c
+++ b/src/compiler/ast-tree.c
@@ -6,7 +6,7 @@
#include <stdlib.h>
#include <string.h>
-static const AstTree AST_TREE_U64_TYPE = {
+const AstTree AST_TREE_U64_TYPE = {
.token = AST_TREE_TOKEN_TYPE_U64,
.metadata = NULL,
};
@@ -26,6 +26,8 @@ const char *AST_TREE_TOKEN_STRINGS[] = {
"AST_TREE_TOKEN_VARIABLE_DEFINE",
"AST_TREE_TOKEN_VALUE_U64",
+ "AST_TREE_TOKEN_OPERATOR_ASSIGN",
+
"AST_TREE_TOKEN_NONE",
};
@@ -132,6 +134,34 @@ void astTreePrint(const AstTree *tree, int indent) {
metadata->name_begin);
}
goto RETURN_SUCCESS;
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
+ AstTreeInfix *metadata = tree->metadata;
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("left=\n");
+ astTreePrint(&metadata->left, indent + 1);
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("right=\n");
+ astTreePrint(&metadata->right, indent + 1);
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("leftType=\n");
+ astTreePrint(&metadata->leftType, indent + 1);
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("rightType=\n");
+ astTreePrint(&metadata->rightType, indent + 1);
+ printf("\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ }
+ goto RETURN_SUCCESS;
+
case AST_TREE_TOKEN_NONE:
}
@@ -208,6 +238,15 @@ void astTreeDestroy(AstTree tree) {
// AstTreeIdentifier *metadata = tree.metadata; // not needed
}
return;
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
+ AstTreeInfix *metadata = tree.metadata;
+ astTreeDestroy(metadata->left);
+ astTreeDestroy(metadata->right);
+ astTreeDestroy(metadata->leftType);
+ astTreeDestroy(metadata->rightType);
+ free(metadata);
+ }
+ return;
case AST_TREE_TOKEN_NONE:
}
printLog("Bad token '%d'", tree.token);
@@ -347,6 +386,7 @@ AstTreeRoot *makeAstTree(ParserNode *parsedRoot) {
case PARSER_TOKEN_SYMBOL_PARENTHESIS:
case PARSER_TOKEN_SYMBOL_COMMA:
case PARSER_TOKEN_FUNCTION_CALL:
+ case PARSER_TOKEN_OPERATOR_ASSIGN:
case PARSER_TOKEN_NONE:
printLog("Should not be here");
goto RETURN_ERROR;
@@ -460,6 +500,8 @@ AstTree *astTreeParse(ParserNode *parserNode, AstTreeVariables **variables,
(void *)(AstTreeU64)(ParserNodeU64Metadata)parserNode->metadata);
case PARSER_TOKEN_KEYWORD_PRINT_U64:
return astTreeParsePrintU64(parserNode, variables, variables_size);
+ case PARSER_TOKEN_OPERATOR_ASSIGN:
+ return astTreeParseAssign(parserNode, variables, variables_size);
case PARSER_TOKEN_VARIABLE:
case PARSER_TOKEN_CONSTANT:
case PARSER_TOKEN_SYMBOL_EOL:
@@ -694,6 +736,32 @@ AstTree *astTreeParsePrintU64(ParserNode *parserNode,
(AstTreeSingleChild *)operand);
}
+AstTree *astTreeParseAssign(ParserNode *parserNode,
+ AstTreeVariables **variables,
+ size_t variables_size) {
+ ParserNodeInfixMetadata *node_metadata = parserNode->metadata;
+
+ AstTree *left = astTreeParse(node_metadata->left, variables, variables_size);
+ if (left == NULL) {
+ return NULL;
+ }
+ AstTree *right =
+ astTreeParse(node_metadata->right, variables, variables_size);
+ if (right == NULL) {
+ return NULL;
+ }
+
+ AstTreeInfix *metadata = a404m_malloc(sizeof(*metadata));
+
+ metadata->left = *left;
+ metadata->right = *right;
+
+ free(left);
+ free(right);
+
+ return newAstTree(AST_TREE_TOKEN_OPERATOR_ASSIGN, metadata);
+}
+
bool astTreeParseConstant(ParserNode *parserNode, AstTreeVariables **variables,
size_t variables_size) {
ParserNodeVariableMetadata *node_metadata = parserNode->metadata;
@@ -800,7 +868,7 @@ bool hasTypeOf(AstTree *value, const AstTree *type) {
case AST_TREE_TOKEN_FUNCTION_CALL:
case AST_TREE_TOKEN_VARIABLE:
case AST_TREE_TOKEN_VALUE_U64:
- case AST_TREE_TOKEN_VARIABLE_DEFINE:
+ case AST_TREE_TOKEN_VARIABLE_DEFINE:
return false;
case AST_TREE_TOKEN_NONE:
}
@@ -829,7 +897,7 @@ bool hasTypeOf(AstTree *value, const AstTree *type) {
case AST_TREE_TOKEN_TYPE_U64:
case AST_TREE_TOKEN_FUNCTION_CALL:
case AST_TREE_TOKEN_VARIABLE:
- case AST_TREE_TOKEN_VARIABLE_DEFINE:
+ case AST_TREE_TOKEN_VARIABLE_DEFINE:
return false;
case AST_TREE_TOKEN_NONE:
}
@@ -1006,6 +1074,8 @@ bool setAllTypes(AstTree *tree) {
return setTypesFunctionCall(tree);
case AST_TREE_TOKEN_VARIABLE:
return setTypesVariable(tree);
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+ return setTypesOperatorAssign(tree);
case AST_TREE_TOKEN_NONE:
}
printLog("Bad token '%d'", tree->token);
@@ -1096,6 +1166,10 @@ bool setTypesVariable(AstTree *tree) {
return setTypesAstVariable(metadata);
}
+bool setTypesOperatorAssign(AstTree *tree) {
+ return setTypesAstInfix(tree->metadata);
+}
+
bool setTypesAstVariable(AstTreeVariable *variable) {
if (!setAllTypes(variable->value)) {
return false;
@@ -1115,6 +1189,29 @@ bool setTypesAstVariable(AstTreeVariable *variable) {
}
}
+bool setTypesAstInfix(AstTreeInfix *infix) {
+ if (!setAllTypes(&infix->left) || !setAllTypes(&infix->right)) {
+ printLog("Type mismatch");
+ return false;
+ }
+
+ AstTree *lType = makeTypeOf(&infix->left);
+ AstTree *rType = makeTypeOf(&infix->right);
+
+ if (!typeIsEqual(lType, rType)) {
+ printLog("Type mismatch");
+ return false;
+ }
+
+ infix->leftType = *lType;
+ infix->rightType = *rType;
+
+ free(lType);
+ free(rType);
+
+ return true;
+}
+
bool astTreeCleanRoot(AstTreeRoot *root) {
for (size_t i = 0; i < root->variables.size; ++i) {
astTreeClean(root->variables.data[i]->value);
@@ -1137,6 +1234,7 @@ bool astTreeClean(AstTree *tree) {
case AST_TREE_TOKEN_FUNCTION_CALL:
case AST_TREE_TOKEN_VALUE_U64:
case AST_TREE_TOKEN_VARIABLE_DEFINE:
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN:
return true;
case AST_TREE_TOKEN_NONE:
}
diff --git a/src/compiler/ast-tree.h b/src/compiler/ast-tree.h
index 90133a5..2e43973 100644
--- a/src/compiler/ast-tree.h
+++ b/src/compiler/ast-tree.h
@@ -19,15 +19,21 @@ typedef enum AstTreeToken {
AST_TREE_TOKEN_VARIABLE_DEFINE,
AST_TREE_TOKEN_VALUE_U64,
+ AST_TREE_TOKEN_OPERATOR_ASSIGN,
+
AST_TREE_TOKEN_NONE,
} AstTreeToken;
+extern const char *AST_TREE_TOKEN_STRINGS[];
+
typedef struct AstTree {
AstTreeToken token;
- void *metadata;
bool typeChecked;
+ void *metadata;
} AstTree;
+extern const AstTree AST_TREE_U64_TYPE;
+
typedef struct AstTreeVariable {
char *name_begin;
char *name_end;
@@ -73,7 +79,12 @@ typedef uint64_t AstTreeU64;
typedef AstTree AstTreeSingleChild;
-extern const char *AST_TREE_TOKEN_STRINGS[];
+typedef struct AstTreeInfix {
+ AstTree left;
+ AstTree right;
+ AstTree leftType;
+ AstTree rightType;
+} AstTreeInfix;
void astTreePrint(const AstTree *tree, int indent);
void astTreeRootPrint(const AstTreeRoot *root);
@@ -117,6 +128,10 @@ AstTree *astTreeParsePrintU64(ParserNode *parserNode,
AstTreeVariables **variables,
size_t variables_size);
+AstTree *astTreeParseAssign(ParserNode *parserNode,
+ AstTreeVariables **variables,
+ size_t variables_size);
+
bool astTreeParseConstant(ParserNode *parserNode, AstTreeVariables **variables,
size_t variables_size);
@@ -137,7 +152,10 @@ bool setTypesPrintU64(AstTree *tree);
bool setTypesTypeFunction(AstTree *tree);
bool setTypesFunctionCall(AstTree *tree);
bool setTypesVariable(AstTree *tree);
+bool setTypesOperatorAssign(AstTree *tree);
+
bool setTypesAstVariable(AstTreeVariable *variable);
+bool setTypesAstInfix(AstTreeInfix *infix);
bool astTreeCleanRoot(AstTreeRoot *root);
bool astTreeClean(AstTree *tree);
diff --git a/src/compiler/code-generator.c b/src/compiler/code-generator.c
index b52c5d3..4ddfe94 100644
--- a/src/compiler/code-generator.c
+++ b/src/compiler/code-generator.c
@@ -25,6 +25,13 @@ void codeGeneratorDelete(CodeGeneratorCodes *code) {
free(metadata);
}
continue;
+ case CODE_GENERATOR_INSTRUCTION_MOV_U64: {
+ CodeGeneratorDoubleOperand *metadata = current.metadata;
+ free(metadata->op0.value);
+ free(metadata->op1.value);
+ free(metadata);
+ }
+ continue;
}
printLog("Bad instruction %d", current.instruction);
exit(1);
@@ -42,6 +49,43 @@ CodeGeneratorOperand *newCodeGeneratorOperand(char *value, bool isReference) {
return result;
}
+CodeGeneratorOperand *makeCodeGeneratorOperand(AstTree tree) {
+ switch (tree.token) {
+ case AST_TREE_TOKEN_VALUE_U64:
+ return newCodeGeneratorOperand(u64ToString((AstTreeU64)tree.metadata),
+ false);
+ case AST_TREE_TOKEN_VARIABLE: {
+ AstTreeVariable *variable = tree.metadata;
+ if (!typeIsEqual(variable->type, &AST_TREE_U64_TYPE)) {
+ UNREACHABLE;
+ }
+ if (variable->isConst) {
+ return newCodeGeneratorOperand(
+ u64ToString((AstTreeU64)variable->value->metadata), false);
+ } else {
+ char *name = a404m_malloc(
+ (variable->name_end - variable->name_begin + 1) * sizeof(*name));
+ strncpy(name, variable->name_begin,
+ variable->name_end - variable->name_begin);
+ name[variable->name_end - variable->name_begin] = '\0';
+
+ return newCodeGeneratorOperand(name, true);
+ }
+ }
+ case AST_TREE_TOKEN_FUNCTION:
+ case AST_TREE_TOKEN_KEYWORD_PRINT_U64:
+ case AST_TREE_TOKEN_TYPE_TYPE:
+ case AST_TREE_TOKEN_TYPE_FUNCTION:
+ case AST_TREE_TOKEN_TYPE_VOID:
+ case AST_TREE_TOKEN_TYPE_U64:
+ case AST_TREE_TOKEN_FUNCTION_CALL:
+ case AST_TREE_TOKEN_VARIABLE_DEFINE:
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN:
+ case AST_TREE_TOKEN_NONE:
+ }
+ UNREACHABLE;
+}
+
CodeGeneratorCode createGenerateCode(char *label_begin, char *label_end,
CodeGeneratorInstruction instruction,
void *metadata) {
@@ -183,6 +227,31 @@ bool codeGeneratorAstTreeFunction(char *label_begin, char *label_end,
}
}
goto OK;
+ case AST_TREE_TOKEN_OPERATOR_ASSIGN: {
+ AstTreeInfix *infix = tree.metadata;
+
+ if (infix->left.token != AST_TREE_TOKEN_VARIABLE) {
+ printLog("Not implemented yet");
+ exit(1);
+ } else if (infix->leftType.token != AST_TREE_TOKEN_TYPE_U64) {
+ printLog("Not implemented yet");
+ exit(1);
+ }
+
+ CodeGeneratorDoubleOperand *operands = a404m_malloc(sizeof(*operands));
+ CodeGeneratorOperand *op0 = makeCodeGeneratorOperand(infix->left);
+ CodeGeneratorOperand *op1 = makeCodeGeneratorOperand(infix->right);
+ operands->op0 = *op0;
+ operands->op1 = *op1;
+ free(op0);
+ free(op1);
+
+ generateCodePushCode(
+ codes,
+ createGenerateCode(label_begin, label_end,
+ CODE_GENERATOR_INSTRUCTION_MOV_U64, operands));
+ }
+ goto OK;
case AST_TREE_TOKEN_VARIABLE_DEFINE:
case AST_TREE_TOKEN_VALUE_U64:
case AST_TREE_TOKEN_VARIABLE:
@@ -288,6 +357,27 @@ char *codeGeneratorToFlatASM(const CodeGeneratorCodes *codes) {
free(inst);
}
continue;
+ case CODE_GENERATOR_INSTRUCTION_MOV_U64: {
+ CodeGeneratorDoubleOperand *metadata = code.metadata;
+ char *inst;
+ if (metadata->op1.isReference) {
+ asprintf(&inst, "mov rax, [%s]\n", metadata->op1.value);
+ } else {
+ asprintf(&inst, "mov rax, %s\n", metadata->op1.value);
+ }
+ codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, inst,
+ strlen(inst));
+ free(inst);
+ if (metadata->op0.isReference) {
+ asprintf(&inst, "mov [%s], rax\n", metadata->op0.value);
+ } else {
+ UNREACHABLE;
+ }
+ codeGeneratorAppendFlatASMCommand(&fasm, &fasm_size, &fasm_inserted, inst,
+ strlen(inst));
+ free(inst);
+ }
+ continue;
}
printLog("Bad instruction %d", code.instruction);
}
diff --git a/src/compiler/code-generator.h b/src/compiler/code-generator.h
index a9c6490..ac47e76 100644
--- a/src/compiler/code-generator.h
+++ b/src/compiler/code-generator.h
@@ -9,6 +9,7 @@ typedef enum CodeGeneratorInstruction : uint8_t {
CODE_GENERATOR_INSTRUCTION_CALL,
CODE_GENERATOR_INSTRUCTION_RET,
CODE_GENERATOR_INSTRUCTION_DEF_VAR64,
+ CODE_GENERATOR_INSTRUCTION_MOV_U64,
} CodeGeneratorInstruction;
typedef struct CodeGeneratorCode {
@@ -28,6 +29,11 @@ typedef struct CodeGeneratorOperand {
bool isReference;
} CodeGeneratorOperand;
+typedef struct CodeGeneratorDoubleOperand {
+ CodeGeneratorOperand op0;
+ CodeGeneratorOperand op1;
+} CodeGeneratorDoubleOperand;
+
typedef struct CodeGeneratorCodes {
CodeGeneratorCode *codes;
size_t codes_size;
@@ -37,6 +43,8 @@ void codeGeneratorDelete(CodeGeneratorCodes *code);
CodeGeneratorOperand *newCodeGeneratorOperand(char *value, bool isReference);
+CodeGeneratorOperand *makeCodeGeneratorOperand(AstTree tree);
+
CodeGeneratorCode createGenerateCode(char *label_begin, char *label_end,
CodeGeneratorInstruction instruction,
void *metadata);
diff --git a/src/compiler/parser.c b/src/compiler/parser.c
index 2bdac64..7a9e0e3 100644
--- a/src/compiler/parser.c
+++ b/src/compiler/parser.c
@@ -30,6 +30,8 @@ const char *PARSER_TOKEN_STRINGS[] = {
"PARSER_TOKEN_SYMBOL_PARENTHESIS",
"PARSER_TOKEN_SYMBOL_COMMA",
+ "PARSER_TOKEN_OPERATOR_ASSIGN",
+
"PARSER_TOKEN_FUNCTION_DEFINITION",
"PARSER_TOKEN_FUNCTION_CALL",
@@ -62,6 +64,10 @@ static constexpr ParserOrder PARSER_ORDER[] = {
ORDER_ARRAY(LEXER_TOKEN_SYMBOL_COLON, LEXER_TOKEN_KEYWORD_PRINT_U64, ),
},
{
+ .ltr = false,
+ ORDER_ARRAY(LEXER_TOKEN_SYMBOL_ASSIGN, ),
+ },
+ {
.ltr = true,
ORDER_ARRAY(LEXER_TOKEN_SYMBOL_EOL, LEXER_TOKEN_SYMBOL_COMMA, ),
},
@@ -202,6 +208,23 @@ void parserNodePrint(const ParserNode *node, int indent) {
printf(" ");
}
goto RETURN_SUCCESS;
+ case PARSER_TOKEN_OPERATOR_ASSIGN: {
+ const ParserNodeInfixMetadata *metadata = node->metadata;
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("left=\n");
+ parserNodePrint(metadata->left, indent + 1);
+ printf(",\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ printf("right=\n");
+ parserNodePrint(metadata->right, indent + 1);
+ printf("\n");
+ for (int i = 0; i < indent; ++i)
+ printf(" ");
+ }
+ goto RETURN_SUCCESS;
case PARSER_TOKEN_NONE:
}
printLog("Bad token '%d'", node->token);
@@ -275,6 +298,12 @@ void parserNodeDelete(ParserNode *node) {
free(metadata);
}
goto RETURN_SUCCESS;
+ case PARSER_TOKEN_OPERATOR_ASSIGN: {
+ ParserNodeInfixMetadata *metadata = node->metadata;
+ parserNodeDelete(metadata->left);
+ parserNodeDelete(metadata->right);
+ }
+ goto RETURN_SUCCESS;
case PARSER_TOKEN_NONE:
}
@@ -403,11 +432,12 @@ ParserNode *parseNode(LexerNode *node, LexerNode *begin, LexerNode *end,
return parserComma(node, begin, parent);
case LEXER_TOKEN_NUMBER:
return parserNumber(node, parent);
- case LEXER_TOKEN_NONE:
+ case LEXER_TOKEN_SYMBOL_ASSIGN:
+ return parserAssign(node, begin, end, parent);
case LEXER_TOKEN_SYMBOL:
case LEXER_TOKEN_SYMBOL_OPEN_PARENTHESIS:
case LEXER_TOKEN_SYMBOL_OPEN_CURLY_BRACKET:
- case LEXER_TOKEN_SYMBOL_ASSIGN:
+ case LEXER_TOKEN_NONE:
}
printLog("Bad token '%d'", node->token);
return NULL;
@@ -790,6 +820,36 @@ RETURN_ERROR:
return NULL;
}
+ParserNode *parserAssign(LexerNode *node, LexerNode *begin, LexerNode *end,
+ ParserNode *parent) {
+ LexerNode *leftNode = node - 1;
+ LexerNode *rightNode = node + 1;
+
+ if (leftNode < begin || rightNode >= end) {
+ printLog("Bad assign");
+ return NULL;
+ }
+
+ ParserNode *left = getUntilCommonParent(leftNode->parserNode, parent);
+ ParserNode *right = getUntilCommonParent(rightNode->parserNode, parent);
+
+ if (left == NULL || right == NULL) {
+ printLog("Bad assign");
+ return NULL;
+ }
+
+ ParserNodeInfixMetadata *metadata = a404m_malloc(sizeof(*metadata));
+ metadata->left = left;
+ metadata->right = right;
+
+ return left->parent = right->parent = node->parserNode =
+ newParserNode(PARSER_TOKEN_OPERATOR_ASSIGN, left->str_begin,
+ right->str_end, metadata, parent);
+
+ printLog("Not implemented");
+ return NULL;
+}
+
bool isAllArguments(const ParserNodeArray *nodes) {
for (size_t i = 0; i < nodes->size; ++i) {
const ParserNode *node = nodes->data[i];
@@ -809,6 +869,7 @@ bool isExpression(ParserNode *node) {
case PARSER_TOKEN_FUNCTION_DEFINITION:
case PARSER_TOKEN_FUNCTION_CALL:
case PARSER_TOKEN_KEYWORD_PRINT_U64:
+ case PARSER_TOKEN_OPERATOR_ASSIGN:
return true;
case PARSER_TOKEN_ROOT:
case PARSER_TOKEN_TYPE_TYPE:
@@ -845,6 +906,7 @@ bool isType(ParserNode *node) {
case PARSER_TOKEN_FUNCTION_CALL:
case PARSER_TOKEN_VALUE_U64:
case PARSER_TOKEN_KEYWORD_PRINT_U64:
+ case PARSER_TOKEN_OPERATOR_ASSIGN:
return false;
case PARSER_TOKEN_NONE:
}
@@ -858,6 +920,7 @@ bool isValue(ParserNode *node) {
case PARSER_TOKEN_FUNCTION_CALL:
case PARSER_TOKEN_VALUE_U64:
case PARSER_TOKEN_IDENTIFIER:
+ case PARSER_TOKEN_OPERATOR_ASSIGN:
return true;
case PARSER_TOKEN_TYPE_FUNCTION:
case PARSER_TOKEN_TYPE_TYPE:
diff --git a/src/compiler/parser.h b/src/compiler/parser.h
index c20fc12..ea53042 100644
--- a/src/compiler/parser.h
+++ b/src/compiler/parser.h
@@ -26,6 +26,8 @@ typedef enum ParserToken {
PARSER_TOKEN_SYMBOL_PARENTHESIS,
PARSER_TOKEN_SYMBOL_COMMA,
+ PARSER_TOKEN_OPERATOR_ASSIGN,
+
PARSER_TOKEN_FUNCTION_DEFINITION,
PARSER_TOKEN_FUNCTION_CALL,
@@ -80,6 +82,11 @@ typedef ParserNode ParserNodeSingleChildMetadata;
typedef uint64_t ParserNodeU64Metadata;
+typedef struct ParserNodeInfixMetadata {
+ ParserNode *left;
+ ParserNode *right;
+} ParserNodeInfixMetadata;
+
void parserNodePrint(const ParserNode *node, int indent);
void parserNodeDelete(ParserNode *node);
@@ -110,6 +117,8 @@ ParserNode *parserFunction(LexerNode *node, LexerNode *begin, LexerNode *end,
ParserNode *parent);
ParserNode *parserVariable(LexerNode *node, LexerNode *begin, LexerNode *end,
ParserNode *parent);
+ParserNode *parserAssign(LexerNode *node, LexerNode *begin, LexerNode *end,
+ ParserNode *parent);
bool isAllArguments(const ParserNodeArray *nodes);