public void ParseForeachDirective() { Parser parser = GetNewParser( "#foreach($item in $collection)text here#end text"); TemplateNode templateNode = parser.ParseTemplate(); // Do semantic checks so the scope is populated templateNode.DoSemanticChecks(new ErrorHandler()); // Check Template Assert.AreEqual(2, templateNode.Content.Count); Assert.AreEqual(" text", ((XmlTextNode)templateNode.Content[1]).Text); // Check NVForeachDirective NVForeachDirective foreachDirective = (NVForeachDirective)templateNode.Content[0]; AssertPosition(new Position(1, 1, 1, 44), foreachDirective.Position); Assert.AreEqual("item", foreachDirective.Iterator); //TODO: Assert.AreEqual("collection", ((NVDesignatorExpression)foreachDirective.Collection).Designator.Name); // Check directive content Assert.AreEqual(1, foreachDirective.Content.Count); Assert.AreEqual("text here", ((XmlTextNode)foreachDirective.Content[0]).Text); // Check iterator variable is only in the foreach scope Assert.IsFalse(templateNode.Scope.Exists("item")); Assert.IsTrue(foreachDirective.Scope.Exists("item")); AssertNoErrors(parser); }
private void AddNodesToTree(AstNode parentAstNode, TreeNode parentTreeNode) { if (parentAstNode is TemplateNode) { // Template Content foreach (AstNode node in ((TemplateNode)parentAstNode).Content) { AddNodesToTree(node, parentTreeNode); } } else if (parentAstNode is NVBinaryExpression) { NVBinaryExpression binExpr = (NVBinaryExpression)parentAstNode; TreeNode binExprTreeNode = new TreeNode(string.Format("NVBinaryExpression={{Op:\"{0}\"}}", binExpr.Op)); binExprTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(binExprTreeNode); AddNodesToTree(binExpr.Lhs, binExprTreeNode); AddNodesToTree(binExpr.Rhs, binExprTreeNode); } else if (parentAstNode is NVBoolExpression) { TreeNode boolTreeNode = new TreeNode(string.Format("NVBoolExpression={{Value:\"{0}\"}}", ((NVBoolExpression)parentAstNode).Value)); boolTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(boolTreeNode); } else if (parentAstNode is NVForeachDirective) { NVForeachDirective foreachDirective = (NVForeachDirective)parentAstNode; TreeNode foreachTreeNode = new TreeNode(string.Format("NVForeachDirective={{Iterator:\"{0}\"}}", foreachDirective.Iterator)); foreachTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(foreachTreeNode); // Content foreach (AstNode astNode in foreachDirective.Content) { AddNodesToTree(astNode, foreachTreeNode); } } else if (parentAstNode is NVDirective) { TreeNode directiveTreeNode = new TreeNode(string.Format("NVDirective={{Name:\"{0}\"}}", ((NVDirective)parentAstNode).Name)); directiveTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(directiveTreeNode); } else if (parentAstNode is NVNumExpression) { TreeNode numTreeNode = new TreeNode(string.Format("NVNumExpression={{Value:\"{0}\"}}", ((NVNumExpression)parentAstNode).Value)); numTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(numTreeNode); } else if (parentAstNode is NVReference) { TreeNode referenceTreeNode = new TreeNode(string.Format("NVReference={{Name:\"{0}\"}}", ((NVReference)parentAstNode).Designator.Name)); referenceTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(referenceTreeNode); foreach (NVSelector selector in ((NVReference)parentAstNode).Designator.Selectors) { AddNodesToTree(selector, referenceTreeNode); } } else if (parentAstNode is NVSelector) { NVSelector selector = (NVSelector)parentAstNode; TreeNode selectorTreeNode = new TreeNode(string.Format("NVSelector={{Name:\"{0}\", Type:\"{1}\"}}", selector.Name, selector.Type != null ? selector.Type.Name : "")); selectorTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(selectorTreeNode); if (selector.Actuals.Count > 0) { TreeNode actualsTreeNode = new TreeNode("Actuals:"); foreach (NVExpression actual in selector.Actuals) { AddNodesToTree(actual, actualsTreeNode); } selectorTreeNode.Nodes.Add(actualsTreeNode); } } else if (parentAstNode is NVStringExpression) { TreeNode stringTreeNode = new TreeNode(string.Format("NVStringExpression={{Value:\"{0}\"}}", ((NVStringExpression)parentAstNode).Value)); stringTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(stringTreeNode); } else if (parentAstNode is XmlAttribute) { TreeNode attributeTreeNode = new TreeNode(string.Format("XmlAttribute={{Name:\"{0}\"}}", ((XmlAttribute)parentAstNode).Name)); attributeTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(attributeTreeNode); // XML Attribute Content foreach (AstNode node in ((XmlAttribute)parentAstNode).Content) { AddNodesToTree(node, attributeTreeNode); } } else if (parentAstNode is XmlElement) { XmlElement xmlElement = (XmlElement)parentAstNode; TreeNode elementTreeNode = new TreeNode(string.Format("XmlElement={{Name:\"{0}\"}}", xmlElement.Name)); elementTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(elementTreeNode); // XML Element Attributes TreeNode attributesTreeNode = new TreeNode("Attributes:"); foreach (AstNode attribute in xmlElement.Attributes) { AddNodesToTree(attribute, attributesTreeNode); } elementTreeNode.Nodes.Add(attributesTreeNode); // XML Element Content TreeNode contentTreeNode = new TreeNode("Content:"); foreach (AstNode node in xmlElement.Content) { AddNodesToTree(node, contentTreeNode); } elementTreeNode.Nodes.Add(contentTreeNode); } else if (parentAstNode is XmlTextNode) { TreeNode textNodeTreeNode = new TreeNode(string.Format("XmlTextNode={{Text:\"{0}\"}}", ((XmlTextNode)parentAstNode).Text.Replace("\n", "\\n"))); textNodeTreeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(textNodeTreeNode); } else { if (parentAstNode != null) { TreeNode treeNode = new TreeNode("UNKNOWN===" + parentAstNode.GetType().Name); treeNode.Tag = parentAstNode; parentTreeNode.Nodes.Add(treeNode); } } }
private NVDirective ParseNVRestDirective(Position startPos) { // NVRestDirective -> "if" "(" NVExpression ")" Content { NVElseIfStatement } [ NVElseStatement ] NVEnd // -> "set" "(" NVReference "=" NVExpression ")" // -> "stop" // -> "foreach" "(" "$" nvIdentifier "in" NVExpression ")" Content NVEnd. // -> nvDirectiveName [ "(" { nvIdentifier | NVExpression } ")" [ Content NVEnd ] ]. NVDirective nvDirective; if (_scanner.CurrentToken != null && _scanner.CurrentToken.Type == TokenType.NVDirectiveName) { if (_scanner.CurrentToken.Image == "foreach") { nvDirective = new NVForeachDirective(); } else { nvDirective = new NVDirective(_scanner.CurrentToken.Image); } _scanner.GetToken(); } else { AddError("Expected directive name"); nvDirective = new NVDirective(""); nvDirective.Position = new Position(startPos, GetCurrentTokenPosition()); return(nvDirective); } // Match directive parameters if (CurrentTokenType == TokenType.NVDirectiveLParen) { _scanner.GetToken(); if (nvDirective is NVForeachDirective) { MatchToken(TokenType.NVDollar); if (_scanner.CurrentToken != null && _scanner.CurrentToken.Type == TokenType.NVIdentifier) { ((NVForeachDirective)nvDirective).Iterator = _scanner.CurrentToken.Image; _scanner.GetToken(); } else { AddError("Foreach variable declaration expected"); } MatchToken(TokenType.NVIn); ((NVForeachDirective)nvDirective).Collection = ParseNVExpression(); } else { while (!_scanner.EOF && !CurrentTokenIn(TokenType.NVDirectiveRParen, TokenType.NVDirectiveHash)) { _scanner.GetToken(); // If the tokens are errors break out if (CurrentTokenType == TokenType.Error) { AddError("Unable to parse all directive contents."); break; } } // If a new directive starts in the middle of an unfinished directive params then stop parsing this directive if (CurrentTokenType != TokenType.NVDirectiveRParen) { AddError("Incomplete directive."); nvDirective.Position = new Position(startPos, GetCurrentTokenPosition()); return(nvDirective); } } MatchToken(TokenType.NVDirectiveRParen); } // Match directive content and #end if required if (nvDirective is NVForeachDirective) { while (!(CurrentTokenType == TokenType.NVDirectiveHash && _scanner.PeekToken(1) != null && _scanner.PeekToken(1).Type == TokenType.NVDirectiveName && _scanner.PeekToken(1).Image == "end")) { List <AstNode> content = ParseContent(); ((NVForeachDirective)nvDirective).Content.AddRange(content); // If this is the end of the file then return what has been build if (_scanner.EOF) { AddError("Expected #end directive."); nvDirective.Position = new Position(startPos, _scanner.CurrentPos); return(nvDirective); } // Break out of the loop if no content was found because the directive is incomplete if (content.Count == 0) { AddError("The parser has been pre-emptively terminated because it appears " + "as if the parser is stuck. [In ParseNVForeachDirective()]"); break; } } // Match #end MatchToken(TokenType.NVDirectiveHash); if (CurrentTokenType == TokenType.NVDirectiveName) { if (_scanner.CurrentToken.Image != "end") { AddError("Expected #end directive."); } nvDirective.Position = new Position(startPos, _scanner.CurrentPos); _scanner.GetToken(); } else { _scanner.GetToken(); nvDirective.Position = new Position(startPos, _scanner.CurrentPos); } } else { nvDirective.Position = new Position(startPos, GetCurrentTokenPosition()); } return(nvDirective); }