private void ApplyGrammar(List <ASTNode> nodes, int from = 0, bool allowNoSemicolon = false, params GrammarRule[] additionalPatterns) { int i = from; while (i < nodes.Count) { if (nodes[i] is NopNode) { nodes.RemoveAt(i); // Remove the nopnode -> Should never pass through this method continue; } if (additionalPatterns != null) { bool skipStandard = false; for (int j = 0; j < additionalPatterns.Length; j++) { if (additionalPatterns[j](nodes, ref i)) { skipStandard = true; break; } } if (skipStandard) { i++; continue; } } if (nodes[i].LexicalType == LexTokenType.Keyword) { switch (nodes[i].Content) { case "class": this.ApplyClassGrammar(nodes, ref i); break; case "return": this.ApplyReturnStatementGrammar(nodes, i); break; case "if": this.ApplyIfStatementGrammar(nodes, i); break; case "while": this.ApplyWhileStatementGrammar(nodes, i); break; case "for": this.ApplyForStatementGrammar(nodes, i); break; case "do": this.ApplyDoStatementGrammar(nodes, i); break; case "public": case "private": case "protected": case "external": case "internal": nodes[i] = new AccessModifierNode(nodes[i].Content, nodes[i].Pos); break; case "namespace": this.ApplyNamespaceGrammar(nodes, i); break; default: throw new NotImplementedException(nodes[i].Content); } } else if (TypeSequence <ASTNode, IdentifierNode, IdentifierNode, SeperatorNode> .Match(nodes, i)) // int x; { this.ApplyModifierGrammar(nodes, ref i, out AccessModifierNode accessModifier, out HashSet <StorageModifierNode> storageModifiers); nodes[i] = new VarDeclNode(nodes[i].Pos, nodes[i].ToTypeIdentifier(), nodes[i + 1].Content); this.ApplyModifiers(nodes[i] as VarDeclNode, accessModifier, storageModifiers); this.RemoveNode(nodes, i + 1, 2); } else if (TypeSequence <ASTNode, IdentifierNode, AssignmentNode, SeperatorNode> .Match(nodes, i) || TypeSequence <ASTNode, TypeArrayIdentifierNode, AssignmentNode, SeperatorNode> .Match(nodes, i)) // int x = <expr>; OR int[] x = <expr>; { this.ApplyModifierGrammar(nodes, ref i, out AccessModifierNode accessModifier, out HashSet <StorageModifierNode> storageModifiers); AssignmentNode assignOp = nodes[i + 1] as AssignmentNode; bool doRecursive = true; if (assignOp.Right is ScopeNode initializer) { if (this.ApplyInitializerGrammar(initializer, out IInitializer init)) { assignOp.Update(LeftRight.LHS, assignOp.Left); assignOp.Update(LeftRight.RHS, init as ASTNode); doRecursive = false; } } if (doRecursive) { this.ApplySingleNodeGrammar(assignOp.Right, true); } nodes[i] = new VarDeclNode(nodes[i].Pos, nodes[i].ToTypeIdentifier(), assignOp); this.ApplyModifiers(nodes[i] as VarDeclNode, accessModifier, storageModifiers); this.RemoveNode(nodes, i + 1, 2); } else if (TypeSequence <ASTNode, IdentifierNode, ExpressionNode, ASTNode, IdentifierNode, ScopeNode> .Match(nodes, i)) { if (nodes[i + 2].Content.CompareTo(":") == 0) { this.ApplyFunctionGrammar(nodes, ref i); } } else if (TypeSequence <ASTNode, IExpr, ExpressionNode> .Match(nodes, i)) { ExpressionNode groupNode = nodes[i + 1] as ExpressionNode; this.ApplyGrammar(groupNode.Nodes, 0, true); // apply grammar on arguments ==> should lead to a nice arg1,arg2,arg3 setup (otherwise error) CallNode callNode = new CallNode(nodes[i], nodes[i].Pos) { Arguments = new ArgumentsNode(groupNode) // Note: This constructor will apply the grammar rule on its own }; if (!callNode.Arguments.IsValid) { throw new Exception(); } this.RemoveNode(nodes, i + 1); nodes[i] = callNode; } else if (nodes[i] is IGroupedASTNode groupNode) { this.ApplyGrammar(groupNode.Nodes); } else { ApplySingleNodeGrammar(nodes[i]); } if (nodes[i] is IExpr && i + 1 < nodes.Count && nodes[i + 1] is SeperatorNode sepNode && sepNode.Content.CompareTo(";") == 0) { this.RemoveNode(nodes, i + 1); }