From 50d4163ff236a72d037fa2d11f278ec358b4af6e Mon Sep 17 00:00:00 2001 From: HeronErin Date: Mon, 22 Apr 2024 11:31:47 -0400 Subject: [PATCH] Indexing support --- source/parsing/tokenizer/make_tokens.d | 1 - source/parsing/tokenizer/tokens.d | 8 +- source/parsing/treegen/astTypes.d | 35 +- source/parsing/treegen/expressionParser.d | 16 +- source/parsing/treegen/tokenRelationships.d | 352 ++++++++++---------- source/tests/tokenizer.d | 1 - source/tests/treegen.d | 10 + 7 files changed, 222 insertions(+), 201 deletions(-) diff --git a/source/parsing/tokenizer/make_tokens.d b/source/parsing/tokenizer/make_tokens.d index acecc9c..9b4330f 100644 --- a/source/parsing/tokenizer/make_tokens.d +++ b/source/parsing/tokenizer/make_tokens.d @@ -8,7 +8,6 @@ import tern.typecons.common : Nullable, nullable; import parsing.tokenizer.tokens; -import std.stdio; dchar[] handleMultilineCommentsAtIndex(dchar[] input, ref size_t index) { diff --git a/source/parsing/tokenizer/tokens.d b/source/parsing/tokenizer/tokens.d index 9a85fc7..7bd81cf 100644 --- a/source/parsing/tokenizer/tokens.d +++ b/source/parsing/tokenizer/tokens.d @@ -57,7 +57,6 @@ dchar[] makeUnicodeString(in string input) const(dchar[]) testMultiLineStyle(dchar first, dchar secound) { - // validMultiLineCommentStyles.writeln; foreach (const(dchar[][]) style; validMultiLineCommentStyles) { if (style[0][0] == first && style[0][1] == secound) @@ -153,13 +152,8 @@ Nullable!Token nextToken(Token[] tokens, ref size_t index) { Nullable!Token found = null; if (tokens.length <= index + 1) - { - import std.stdio; - - "boinc".writeln; - found.ptr.writeln; return found; - } + found = tokens[++index]; return found; diff --git a/source/parsing/treegen/astTypes.d b/source/parsing/treegen/astTypes.d index 26f5313..a86ac6d 100644 --- a/source/parsing/treegen/astTypes.d +++ b/source/parsing/treegen/astTypes.d @@ -14,6 +14,7 @@ enum AstAction DefineFunction, DefineVariable, // Ex: int x; AssignVariable, // Ex: x = 5; + IndexInto, // X[...] SingleArgumentOperation, // Ex: x++, ++x, |x|, ||x||, -8 DoubleArgumentOperation, // Ex: 9+10 @@ -27,6 +28,12 @@ enum AstAction TokenHolder // A temporary Node that is yet to be parsed } +bool isExpressionLike(AstAction action) +{ + return action == AstAction.Expression + || action == AstAction.IndexInto; +} + struct KeywordNodeData { dchar[] keywordName; @@ -60,8 +67,8 @@ enum OperationVariety PostIncrement, PreDecrement, PostDecrement, - AbsuluteValue, - Magnitude, + // AbsuluteValue, + // Magnitude, Add, Substract, @@ -93,6 +100,11 @@ enum OperationVariety BitshiftLeftUnSigned, BitshiftRightUnSigned, + BitshiftLeftSignedEq, + BitshiftRightSignedEq, + BitshiftLeftUnSignedEq, + BitshiftRightUnSignedEq, + LogicalOr, LogicalAnd, LogicalNot, @@ -198,8 +210,12 @@ class AstNode import std.stdio; import std.conv; - foreach (i; 0 .. tabCount) - write("| "); + if (tabCount != -1) + { + foreach (i; 0 .. tabCount) + write("| "); + write("┼ "); + } switch (action) { @@ -212,6 +228,17 @@ class AstNode doubleArgumentOperationNodeData.left.tree(tabCount + 1); doubleArgumentOperationNodeData.right.tree(tabCount + 1); break; + case AstAction.SingleArgumentOperation: + writeln(singleArgumentOperationNodeData.operationVariety.to!string ~ ":"); + singleArgumentOperationNodeData.value.tree(tabCount + 1); + break; + case AstAction.IndexInto: + writeln("Indexing into with result of:"); + foreach (subnode; expressionNodeData.components) + { + subnode.tree(tabCount + 1); + } + break; case AstAction.Expression: writeln( "Result of expression with " ~ expressionNodeData.components.length.to!string ~ " components:"); diff --git a/source/parsing/treegen/expressionParser.d b/source/parsing/treegen/expressionParser.d index c5156a0..261facd 100644 --- a/source/parsing/treegen/expressionParser.d +++ b/source/parsing/treegen/expressionParser.d @@ -10,7 +10,7 @@ import std.stdio; import std.container.array; // Group letters.letters.letters into NamedUnit s -// Group Parenthesis into AstNode.Expression s to be parsed speratly +// Group Parenthesis and indexing into AstNode.Expression s to be parsed speratly public AstNode[] phaseOne(Token[] tokens) { AstNode[] ret; @@ -22,7 +22,10 @@ public AstNode[] phaseOne(Token[] tokens) if (token.tokenVariety == TokenType.OpenBraces) { AstNode newExpression = new AstNode(); - newExpression.action = AstAction.Expression; + if (token.value == "(" || token.value == "{") + newExpression.action = AstAction.Expression; + else if (token.value == "[") + newExpression.action = AstAction.IndexInto; newExpression.expressionNodeData = ExpressionNodeData( token.value[0], braceOpenToBraceClose[token.value[0]], @@ -35,12 +38,12 @@ public AstNode[] phaseOne(Token[] tokens) { if (parenthesisStack.length == 0) - throw new SyntaxError("Parenthesis closed but never opened"); + throw new SyntaxError("Group token("~cast(char)token.value[0]~") closed but never opened"); AstNode node = parenthesisStack[$ - 1]; if (node.expressionNodeData.closer != token.value[0]) - throw new SyntaxError("Parenthesis not closed with correct token"); + throw new SyntaxError("Group token("~cast(char)token.value[0]~") not closed with correct token"); parenthesisStack.length--; @@ -89,8 +92,7 @@ public void phaseTwo(Array!AstNode nodes) for (size_t index = 0; index < nodes.length; index++) { AstNode node = nodes[index]; - if (node.action == AstAction.NamedUnit && index + 1 < nodes.length && nodes[index + 1].action == AstAction - .Expression) + if (node.action == AstAction.NamedUnit && index + 1 < nodes.length && nodes[index + 1].action.isExpressionLike) { AstNode functionCall = new AstNode(); AstNode args = nodes[index + 1]; @@ -110,7 +112,7 @@ public void phaseTwo(Array!AstNode nodes) nodes[index] = functionCall; nodes.linearRemove(nodes[index + 1 .. index + 2]); } - else if (node.action == AstAction.Expression) + else if (node.action.isExpressionLike) { Array!AstNode components; components ~= node.expressionNodeData.components; diff --git a/source/parsing/treegen/tokenRelationships.d b/source/parsing/treegen/tokenRelationships.d index 94d73bb..6ee411e 100644 --- a/source/parsing/treegen/tokenRelationships.d +++ b/source/parsing/treegen/tokenRelationships.d @@ -113,8 +113,6 @@ bool matchesToken(in TokenGrepPacket[] testWith, Token[] tokens) return matchesToken(testWith, tokens, index); } -import std.stdio; - bool matchesToken(in TokenGrepPacket[] testWith, Token[] tokens, ref size_t index) { foreach (testIndex, packet; testWith) @@ -256,27 +254,27 @@ const OperatorPrecedenceLayer[] operatorPrecedence = [ // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ // // TODO: Unary // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.PreIncrement, [ - // OPR('+'), OPR('+'), Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.PreDecrement, [ - // OPR('-'), OPR('-'), Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.PostIncrement, [ - // Token(TokenType.Filler), OPR('+'), OPR('+') - // ]), - // OperationPrecedenceEntry(OperationVariety.PostDecrement, [ - // Token(TokenType.Filler), OPR('-'), OPR('-') - // ]), - - // OperationPrecedenceEntry(OperationVariety.LogicalNot, [ - // OPR('!'), Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.BitwiseNot, [ - // OPR('~'), Token(TokenType.Filler) - // ]), - // ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.PreIncrement, [ + OPR('+'), OPR('+'), Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.PreDecrement, [ + OPR('-'), OPR('-'), Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.PostIncrement, [ + Token(TokenType.Filler), OPR('+'), OPR('+') + ]), + OperationPrecedenceEntry(OperationVariety.PostDecrement, [ + Token(TokenType.Filler), OPR('-'), OPR('-') + ]), + + OperationPrecedenceEntry(OperationVariety.LogicalNot, [ + OPR('!'), Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitwiseNot, [ + OPR('~'), Token(TokenType.Filler) + ]), + ]), OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ OperationPrecedenceEntry(OperationVariety.Multiply, [ Token(TokenType.Filler), OPR('*'), Token(TokenType.Filler) @@ -296,111 +294,141 @@ const OperatorPrecedenceLayer[] operatorPrecedence = [ Token(TokenType.Filler), OPR('-'), Token(TokenType.Filler) ]), ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.BitshiftLeftSigned, [ - // Token(TokenType.Filler), OPR('<'), OPR('<'), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.BitshiftRightSigned, [ - // Token(TokenType.Filler), OPR('>'), OPR('>'), - // Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.LessThanEq, [ - // Token(TokenType.Filler), OPR('<'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.GreaterThanEq, [ - // Token(TokenType.Filler), OPR('>'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.LessThan, [ - // Token(TokenType.Filler), OPR('<'), Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.GreaterThan, [ - // Token(TokenType.Filler), OPR('>'), Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.NotEqualTo, [ - // Token(TokenType.Filler), OPR('!'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.EqualTo, [ - // Token(TokenType.Filler), OPR('='), OPR('='), - // Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.BitwiseAnd, [ - // Token(TokenType.Filler), OPR('&'), Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.BitwiseXor, [ - // Token(TokenType.Filler), OPR('^'), Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.BitwiseOr, [ - // Token(TokenType.Filler), OPR('|'), Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.LogicalAnd, [ - // Token(TokenType.Filler), OPR('&'), OPR('&'), - // Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ - // OperationPrecedenceEntry(OperationVariety.LogicalOr, [ - // Token(TokenType.Filler), OPR('|'), OPR('|'), - // Token(TokenType.Filler) - // ]), - // ]), - // OperatorPrecedenceLayer(OperatorOrder.RightToLeft, [ - // OperationPrecedenceEntry(OperationVariety.Assignment, [ - // Token(TokenType.Filler), OPR('='), Token(TokenType.Filler) - // ]), // asignment - // OperationPrecedenceEntry(OperationVariety.AddEq, [ - // Token(TokenType.Filler), OPR('+'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.SubstractEq, [ - // Token(TokenType.Filler), OPR('-'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.MultiplyEq, [ - // Token(TokenType.Filler), OPR('*'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.DivideEq, [ - // Token(TokenType.Filler), OPR('/'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.ModEq, [ - // Token(TokenType.Filler), OPR('%'), OPR('='), - // Token(TokenType.Filler) - // ]), - - // OperationPrecedenceEntry(OperationVariety.BitwiseAndEq, [ - // Token(TokenType.Filler), OPR('&'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.BitwiseXorEq, [ - // Token(TokenType.Filler), OPR('^'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.BitwiseOrEq, [ - // Token(TokenType.Filler), OPR('|'), OPR('='), - // Token(TokenType.Filler) - // ]), - // OperationPrecedenceEntry(OperationVariety.BitwiseNotEq, [ - // Token(TokenType.Filler), OPR('~'), OPR('='), - // Token(TokenType.Filler) - // ]), - // ]) + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.BitshiftLeftSigned, [ + Token(TokenType.Filler), OPR('<'), OPR('<'), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftRightSigned, [ + Token(TokenType.Filler), OPR('>'), OPR('>'), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftLeftUnSigned, [ + Token(TokenType.Filler), OPR('<'), OPR('<'), OPR('<'), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftRightUnSigned, [ + Token(TokenType.Filler), OPR('>'), OPR('>'), OPR('>'), + Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.LessThanEq, [ + Token(TokenType.Filler), OPR('<'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.GreaterThanEq, [ + Token(TokenType.Filler), OPR('>'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.LessThan, [ + Token(TokenType.Filler), OPR('<'), Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.GreaterThan, [ + Token(TokenType.Filler), OPR('>'), Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.NotEqualTo, [ + Token(TokenType.Filler), OPR('!'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.EqualTo, [ + Token(TokenType.Filler), OPR('='), OPR('='), + Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.BitwiseAnd, [ + Token(TokenType.Filler), OPR('&'), Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.BitwiseXor, [ + Token(TokenType.Filler), OPR('^'), Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.BitwiseOr, [ + Token(TokenType.Filler), OPR('|'), Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.LogicalAnd, [ + Token(TokenType.Filler), OPR('&'), OPR('&'), + Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.LeftToRight, [ + OperationPrecedenceEntry(OperationVariety.LogicalOr, [ + Token(TokenType.Filler), OPR('|'), OPR('|'), + Token(TokenType.Filler) + ]), + ]), + OperatorPrecedenceLayer(OperatorOrder.RightToLeft, [ + OperationPrecedenceEntry(OperationVariety.Assignment, [ + Token(TokenType.Filler), OPR('='), Token(TokenType.Filler) + ]), // asignment + OperationPrecedenceEntry(OperationVariety.AddEq, [ + Token(TokenType.Filler), OPR('+'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.SubstractEq, [ + Token(TokenType.Filler), OPR('-'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.MultiplyEq, [ + Token(TokenType.Filler), OPR('*'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.DivideEq, [ + Token(TokenType.Filler), OPR('/'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.ModEq, [ + Token(TokenType.Filler), OPR('%'), OPR('='), + Token(TokenType.Filler) + ]), + + OperationPrecedenceEntry(OperationVariety.BitwiseAndEq, [ + Token(TokenType.Filler), OPR('&'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitwiseXorEq, [ + Token(TokenType.Filler), OPR('^'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitwiseOrEq, [ + Token(TokenType.Filler), OPR('|'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitwiseNotEq, [ + Token(TokenType.Filler), OPR('~'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftLeftSignedEq, [ + Token(TokenType.Filler), OPR('<'), OPR('<'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftRightSignedEq, [ + Token(TokenType.Filler), OPR('>'), OPR('>'), OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftLeftUnSignedEq, [ + Token(TokenType.Filler), OPR('<'), OPR('<'), OPR('<'), + OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.BitshiftRightUnSignedEq, [ + Token(TokenType.Filler), OPR('>'), OPR('>'), OPR('<'), + OPR('='), + Token(TokenType.Filler) + ]), + OperationPrecedenceEntry(OperationVariety.Assignment, [ + Token(TokenType.Filler), OPR('='), + Token(TokenType.Filler) + ]) + ]) ]; import std.container.array; @@ -428,6 +456,7 @@ private bool testAndJoin(const(OperationPrecedenceEntry) entry, ref Array!AstNod return false; operands ~= node; break; + case TokenType.Equals: case TokenType.Operator: if (node.action != AstAction.TokenHolder) return false; @@ -467,51 +496,6 @@ private bool testAndJoin(const(OperationPrecedenceEntry) entry, ref Array!AstNod return true; } -// private void merge(const(OperationPrecedenceEntry) entry, ref Array!AstNode nodes, size_t startIndex) -// { -// AstNode[] nodeData; -// size_t nodeIndex = startIndex-1; -// for (size_t index = 0; index < entry.tokens.length; index++) -// { -// Nullable!AstNode nodeNullable = nodes.nextNonWhiteNode(nodeIndex); -// if (nodeNullable.ptr == null) -// assert(0, "Unexpected end of array in AST merge"); -// AstNode node = nodeNullable; -// switch (entry.tokens[index].tokenVariety) -// { -// case TokenType.Filler: -// nodeData ~= node; -// break; -// case TokenType.Operator: -// break; -// default: -// assert(0); -// } -// } -// AstNode oprNode = new AstNode(); -// oprNode.action = AstAction.DoubleArgumentOperation; -// if (nodeData.length == 0) -// assert(0); -// if (nodeData.length == 1) -// { -// oprNode.action = AstAction.SingleArgumentOperation; -// oprNode.singleArgumentOperationNodeData = SingleArgumentOperationNodeData( -// entry.operation, -// nodeData[0], -// ); -// } -// if (nodeData.length == 2) -// oprNode.doubleArgumentOperationNodeData = DoubleArgumentOperationNodeData( -// entry.operation, -// nodeData[0], -// nodeData[1] -// ); - -// nodes[startIndex] = oprNode; -// nodes.linearRemove(nodes[startIndex + 1 .. nodeIndex-1]); - -// } - void scanAndMergeOperators(Array!AstNode nodes) { // OperatorOrder order; @@ -534,13 +518,19 @@ void scanAndMergeOperators(Array!AstNode nodes) } } - // static if (layer.order == OperatorOrder.RightToLeft){ - // for (size_t index = nodes.length; index != -1; index--){ - // foreach (entry; layer.layer) - // { - // entry.testAndJoin(nodes, index); - // } - // } - // } + static if (layer.order == OperatorOrder.RightToLeft) + { + for (size_t index = nodes.length; index != -1; index--) + { + foreach (entry; layer.layer) + { + if (entry.testAndJoin(nodes, index)) + { + index++; + continue; + } + } + } + } } } diff --git a/source/tests/tokenizer.d b/source/tests/tokenizer.d index d8d51d1..30897d7 100644 --- a/source/tests/tokenizer.d +++ b/source/tests/tokenizer.d @@ -1,7 +1,6 @@ module tests.tokenizer; import parsing.tokenizer.tokens; import parsing.tokenizer.make_tokens; -import std.stdio; unittest { diff --git a/source/tests/treegen.d b/source/tests/treegen.d index 7b48e86..850545b 100644 --- a/source/tests/treegen.d +++ b/source/tests/treegen.d @@ -87,3 +87,13 @@ unittest ] == skipAndExtractKeywords(tokens, index)); assert(tokens[index].value == "int".makeUnicodeString); } + +unittest +{ + import parsing.tokenizer.make_tokens; + auto nodes = expressionNodeFromTokens("(p[t++]<<<=1) + 10 / x[9]++".tokenizeText); + assert(nodes.length == 1); + assert(nodes[0].action == AstAction.DoubleArgumentOperation); + assert(nodes[0].doubleArgumentOperationNodeData.operationVariety == OperationVariety.Add); + nodes[0].tree(-1); +} \ No newline at end of file