public StatementNode Parse(TextReader reader) { var swixTokens = new Token <ParserTokenType>[] { new Token <ParserTokenType>(ParserTokenType.Object, "swix", new Range(new Position(-1, -1, -1), 0)) }; this.RootStatementNode = new StatementNode(-1, null, new Statement <StatementType, ParserTokenType>(StatementType.Object, swixTokens, swixTokens)); this.Errors = new List <Error>(); using (ReaderTextProvider textProvider = new ReaderTextProvider(reader)) { var statements = RtypeStatementParser.ParseStatements(new Position(0, 0, 0), textProvider); Stack <StatementNode> parentStack = new Stack <StatementNode>(); StatementNode lastStatementNode = null; char requiredLeadingWhitespaceStyle = '\0'; parentStack.Push(this.RootStatementNode); foreach (var statement in statements) { if (statement.HasError) { // Propagate the error... foreach (var token in statement.Tokens) { if (token.Errors != null) { foreach (var error in token.Errors) { this.AddError(error.Range, error.Message); } } } } if (statement.StatementType == StatementType.Ignorable) { // TODO: Should we continue to pass along the ignorable statements? continue; } // Look at the leading whitespace (if any!) and decide if we're a child, a sibling, or // if we need to pop the stack some... int indent = 0; Token <ParserTokenType> leadingWhitespace = statement.AllTokens .Take(1) .Where(t => t.TokenType == ParserTokenType.Whitespace) .FirstOrDefault(); if (leadingWhitespace != null) { string whitespace = leadingWhitespace.Value; // If we haven't decided whether we require leading tabs or spaces, just use the // first character in this leading whitespace! if (requiredLeadingWhitespaceStyle == '\0') { requiredLeadingWhitespaceStyle = whitespace[0]; } if (!whitespace.All(c => c == requiredLeadingWhitespaceStyle)) { this.AddError(leadingWhitespace, "Leading whitespace must be either all tabs or all spaces."); } indent = leadingWhitespace.Value.Length; } // Look at the indent of this statement, and decide where it goes... if (lastStatementNode != null && indent > lastStatementNode.Indent) { parentStack.Push(lastStatementNode); } else if (lastStatementNode != null && indent < lastStatementNode.Indent) { // Pop the parent stack until we have a parent with less indentation... while (parentStack.Peek().Indent >= indent) { parentStack.Pop(); } } // Now we've fixed up the parent stack, so we can add this statement to the // proper parent... lastStatementNode = new StatementNode(indent, parentStack.Peek(), statement); parentStack.Peek().Add(lastStatementNode); } } return(this.RootStatementNode); }
public void Add(StatementNode childStatementNode) { this.Children.Add(childStatementNode); }
public StatementNode Parse(TextReader reader) { ////var swixTokens = new Token<ParserTokenType>[] { new Token<ParserTokenType>(ParserTokenType.Object, "swix", new Range(new Position(-1, -1, -1), 0)) }; ////this.RootStatementNode = new StatementNode(-1, null, new Statement<StatementType, ParserTokenType>(StatementType.Object, swixTokens, swixTokens)); this.Errors = new List <Error>(); using (ReaderTextProvider textProvider = new ReaderTextProvider(reader)) { var statements = XmlStatementParser.ParseStatements(new Position(0, 0, 0), textProvider); Stack <StatementNode> parentStack = new Stack <StatementNode>(); ////parentStack.Push(this.RootStatementNode); foreach (var statement in statements) { if (statement.HasError) { // Propagate the error... foreach (var token in statement.Tokens) { if (token.Errors != null) { foreach (var error in token.Errors) { this.AddError(error.Range, error.Message); } } } } if (statement.StatementType == StatementType.Ignorable || statement.StatementType == StatementType.Comment) { // TODO: Should we continue to pass along the ignorable statements? continue; } if (statement.StatementType == StatementType.Object || statement.StatementType == StatementType.ObjectStart) { StatementNode parent = null; int indent = 0; if (parentStack.Count > 0) { parent = parentStack.Peek(); indent = parent.Indent + 1; } var node = new StatementNode(indent, parent, statement); if (this.RootStatementNode == null) { this.RootStatementNode = node; } if (parent != null) { parent.Add(node); } if (statement.StatementType == StatementType.ObjectStart) { parentStack.Push(node); } } else if (statement.StatementType == StatementType.ObjectEnd) { // Should we push the close statement to the end of // the children? I think so! var parent = parentStack.Pop(); while (parent != null && !ObjectEndMatches(parent.Statement, statement)) { parent = parentStack.Pop(); } if (parent != null) { // push the close statement... var node = new StatementNode(parent.Indent + 1, parent, statement); parent.Add(node); } // Flag an error? ////// If we over-pop, push the root node back on... ////if (parentStack.Count == 0) ////{ //// parentStack.Push(this.RootStatementNode); ////} } } } return(this.RootStatementNode); }