/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="prototypes">A list with node types</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Will be set to where the next node should start parsing</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { if (offset > line.Data.Length - 1) throw new CodeGeneratorException(line.LineNumber, line.Data, "Tried to parse after end of line"); if (line.Data[offset] != '%') throw new CodeGeneratorException(line.LineNumber, line.Data, "Not a tag node"); int pos = -1; for (int i = offset + 1; i < line.Data.Length; ++i) { if (!char.IsLetterOrDigit(line.Data[i])) { pos = i; break; } } if (pos == -1) pos = line.Data.Length; TagNode node = (TagNode) prototypes.CreateNode("%", parent); node.Name = line.Data.Substring(offset + 1, pos - offset - 1); if (node._name == "br" || node._name == "input" || node._name == "style" || node._name == "img") { line.SelfClosed = true; node.LineInfo = line; node.LineInfo.SelfClosed = true; } offset = pos; return node; }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { offset = line.Data.Length; return new DocTypeTag( @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Strict//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"">".Replace("\"", "\"\""), parent); }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { // text on tag rows are identified by a single space. if (parent != null && line.Data[offset] == ' ') ++offset; TextNode node = new TextNode(parent, line.Data.Substring(offset)); if (parent == null) node.LineInfo = line; offset = line.Data.Length; return node; }
/// <summary> /// Creates a DIV node and add's the specified node to it. /// </summary> /// <param name="prototypes">Contains all prototypes for each control char. used to instanciate new nodes.</param> /// <param name="parent">parent node</param> /// <param name="line">current line information</param> /// <param name="me">node to add to the DIV node</param> /// <returns>current node</returns> public Node AddMe(NodeList prototypes, Node parent, LineInfo line, Node me) { if (parent == null) { TagNode tag = (TagNode)prototypes.CreateNode("%", parent); tag.Name = "div"; tag.LineInfo = line; tag.AddModifier(me); return tag; } return me; }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { if (offset > line.Data.Length) throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data"); int pos = line.Data.Length; ++offset; string code = line.Data.Substring(offset, pos - offset); offset = pos; SilentCodeNode node = (SilentCodeNode) prototypes.CreateNode("-", parent); node._code = code; if (parent != null) node.LineInfo = line; return node; }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { if (offset > line.Data.Length - 1) throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data"); int pos = GetEndPos(offset, line.Data); if (pos == -1) pos = line.Data.Length; ++offset; string name = line.Data.Substring(offset, pos - offset); offset = pos; ClassNode node = (ClassNode) prototypes.CreateNode(".", parent); node._name = name; return AddMe(prototypes, parent, line, node); }
public void TestPartial3() { LineInfo line = new LineInfo(1, string.Empty); line.Set("%a{href=\"/settings/divert/remove/\", title=Language[\"RemoveDivert\"] }", 0, 0); TagNode tagNode = new TagNode(null); NodeList nodes = new NodeList(); AttributeNode node = new AttributeNode(tagNode); nodes.Add(node); nodes.Add(tagNode); int offset = 2; AttributeNode myNode = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset); bool inStr = true; string res = myNode.ToCode(ref inStr, false); //Assert.Equal("\"this\"+testCase.Id+\"id\"", myNode.GetAttribute("value").Value); //Assert.Equal("value=\"\"\"); sb.Append(\"this\"+testCase.Id+\"id\"); sb.Append(@\"\"\"", res); }
public void TestPartial2() { LineInfo line = new LineInfo(1, string.Empty); line.Set("%input{ value=\"http://\"+domain+\"/voicemail/listen/\" + item.Id }", 0, 0); TagNode tagNode = new TagNode(null); NodeList nodes = new NodeList(); AttributeNode node = new AttributeNode(tagNode); nodes.Add(node); nodes.Add(tagNode); int offset = 6; AttributeNode myNode = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset); bool inStr = true; string res = myNode.ToCode(ref inStr, false); Assert.Equal("\"this\"+testCase.Id+\"id\"", myNode.GetAttribute("value").Value); Assert.Equal("value=\"\"\"); sb.Append(\"this\"+testCase.Id+\"id\"); sb.Append(@\"\"\"", res); }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { if (offset >= line.Data.Length) throw new CodeGeneratorException(line.LineNumber, line.Data, "Too little data"); int pos = line.Data.Length; ++offset; string name = line.Data.Substring(offset, pos - offset); offset = pos; string trimmedData = line.Data.Trim(); if (trimmedData.Length > 0 && trimmedData[trimmedData.Length-1] == ';') throw new CodeGeneratorException(line.LineNumber, line.Data, "Displayed code should not end with semicolon."); DisplayCodeNode node = (DisplayCodeNode)prototypes.CreateNode("=", parent); node._code = name; if (parent == null) node.LineInfo = line; return node; }
public void Test() { LineInfo line = new LineInfo(1, string.Empty); line.Set("%input{ type=\"checkbox\", value=testCase.Id, name=\"case\", class=lastCat.Replace(' ', '-')}", 0, 0); TagNode tagNode = new TagNode(null); NodeList nodes = new NodeList(); AttributeNode node = new AttributeNode(tagNode); nodes.Add(node); nodes.Add(tagNode); int offset = 6; AttributeNode myNode = (AttributeNode)node.Parse(nodes, tagNode, line, ref offset); bool t = false; string temp = myNode.ToCode(ref t, false); Assert.Equal("\"checkbox\"", myNode.GetAttribute("type").Value); Assert.Equal("testCase.Id", myNode.GetAttribute("value").Value); Assert.Equal("\"case\"", myNode.GetAttribute("name").Value); Assert.Equal("lastCat.Replace(' ', '-')", myNode.GetAttribute("class").Value); }
/// <summary> /// Will check that all rule conditions have been met. /// Will also remove the rules if they are done. /// </summary> /// <param name="line"></param> /// <returns></returns> private bool CheckUnfinishedRule(LineInfo line) { if (_unfinishedRule != null) { // rule is done, remove it. // we can exit extra lines may have rules that are done too. if (!_unfinishedRule.IsMultiLine(line, false)) _unfinishedRule = null; else return true; } bool res = false; foreach (LineInfo subLine in _extraLines) { if (subLine.CheckUnfinishedRule(line)) res = true; } return res; }
/// <summary> /// Append another line /// </summary> /// <param name="line"></param> public void Append(LineInfo line) { SetParsedData(_data + line.Data); _extraLines.AddLast(line); if (CheckUnfinishedRule(this)) _appendNextLine = true; else _appendNextLine = false; }
/// <summary> /// check if current line is a multi line /// </summary> /// <param name="prevLine">previous line</param> /// <param name="line">current line</param> protected void CheckMultiLine(LineInfo prevLine, LineInfo line) { if (prevLine != null && prevLine.UnfinishedRule != null) { if (prevLine.UnfinishedRule.IsMultiLine(line, true)) { _log.Write(this, LogPrio.Trace, line.LineNumber + ": " + prevLine.UnfinishedRule.GetType().Name + " says that the next line should be appended."); line.AppendNextLine = true; return; } } foreach (Rule rule in _rules) { if (rule.IsMultiLine(line, false)) { _log.Write(this, LogPrio.Trace, line.LineNumber + ": " + rule.GetType().Name + " says that the next line should be appended."); line.AppendNextLine = true; continue; } } }
/// <summary> /// Parse a node /// todo: improve doc /// </summary> /// <param name="theLine"></param> /// <param name="prototypes"></param> /// <param name="parent"></param> /// <param name="textNode"></param> protected static void ParseNode(LineInfo theLine, NodeList prototypes, Node parent, TextNode textNode) { Node curNode = null; int offset = 0; // parse each part of a line while (offset <= theLine.Data.Length - 1) { Node node = prototypes.GetPrototype(GetWord(theLine.Data, offset), curNode == null) ?? textNode; node = node.Parse(prototypes, curNode, theLine, ref offset); // first node on line, set it as current if (curNode == null) { curNode = node; curNode.LineInfo = theLine; parent.Children.AddLast(node); } else curNode.AddModifier(node); // append attributes etc. } foreach (LineInfo child in theLine.Children) ParseNode(child, prototypes, curNode, textNode); }
/// <summary> /// PreParse goes through the text add handles indentation /// and all multi line cases. /// </summary> /// <param name="reader">Reader containing the text</param> protected void PreParse(TextReader reader) { if (reader == null) throw new ArgumentNullException("reader"); // Read first line to be able to assign it to the mother. if (!ReadLine()) throw new CodeGeneratorException(1, "No data."); if (_currentLine.Intendation != 0) throw new CodeGeneratorException(1, "Invalid indentation, should be 0."); _currentLine.Parent = _mother; CheckIntendation(_currentLine); CheckMultiLine(_prevLine, _currentLine); while (ReadLine()) { if (_currentLine.UnparsedData.Length == 0) continue; CheckIntendation(_currentLine); CheckMultiLine(_prevLine, _currentLine); if (_prevLine.AppendNextLine) { _prevLine.Append(_currentLine); if(_currentLine.AppendNextLine) _prevLine.AppendNextLine = true; _currentLine = _prevLine; continue; } HandlePlacement(); } }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public abstract Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset);
/// <summary> /// Check and validate indentation /// </summary> /// <param name="line">line to check</param> /// <param name="ws">number of white spaces</param> /// <param name="intendation">number of indentations (2 white spaces = 1 intend, 1 tab = 1 intend)</param> protected static void CheckIntendation(LineInfo line, out int ws, out int intendation) { intendation = 0; ws = -1; char prevUnusedCh = line.UnparsedData[0]; if (prevUnusedCh == '\t') { ++intendation; prevUnusedCh = char.MinValue; } else if (prevUnusedCh != ' ') { ws = 0; return; } for (int i = 1; i < line.UnparsedData.Length; ++i) { char ch = line.UnparsedData[i]; if (ch == ' ') { if (prevUnusedCh == '\t') { ++intendation; prevUnusedCh = ' '; continue; } if (prevUnusedCh == ' ') { prevUnusedCh = char.MinValue; ++intendation; continue; } prevUnusedCh = ' '; } else if (ch == '\t') { if (prevUnusedCh == ' ') throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid intendation sequence: One space + one tab. Should either be one tab or two spaces."); if (prevUnusedCh == char.MinValue) { ++intendation; prevUnusedCh = char.MinValue; continue; } } else { if (prevUnusedCh != char.MinValue) throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid intendation at char " + i + ", expected a space."); if (i == 1 && !char.IsWhiteSpace(line.UnparsedData[0])) ws = 0; else ws = i; return; } } }
private static void ParseAttributes(LineInfo line, string attributes, List<Attribute> col) { bool inQuote = false; int parenthisCount = 0; string name = null; int start = -1; int step = 0; //0 = start of name, 1 = end of name, 2 = equal sign, 3 = start of value, 4 = end of value, 5 = comma for (int i = 0; i < attributes.Length; ++i) { char ch = attributes[i]; if (ch == '"') { inQuote = !inQuote; if (inQuote && step == 3) { ++step; start = i; } } if (inQuote) continue; if (ch == '(') ++parenthisCount; if (ch == ')') --parenthisCount; if (parenthisCount > 0) continue; // find start of name if (step == 0) { if (!char.IsWhiteSpace(ch)) { start = i; ++step; } } // find end of name else if (step == 1) { if (char.IsWhiteSpace(ch) || ch == '=') { name = attributes.Substring(start, i - start); start = -1; ++step; } } // find equal if (step == 2) { if (ch == '=') ++step; continue; } // start of value if (step == 3) { if (!char.IsWhiteSpace(ch)) { start = i; ++step; } } // end of value else if (step == 4) { if (ch == ',') { AddAttribute(col, name, attributes.Substring(start, i - start).Trim()); start = -1; ++step; } } // find comma if (step == 5) { if (ch == ',') step = 0; continue; } } if (step > 0 && step < 4) throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid attributes"); if (step == 4) AddAttribute(col, name, attributes.Substring(start, attributes.Length - start)); }
/// <summary> /// Print line information to the console /// </summary> /// <param name="line"></param> public void PrintNode(LineInfo line) { _log.Write(this, LogPrio.Debug, Spaces(line.Intendation) + line.Data); foreach (LineInfo info in line.Children) PrintNode(info); }
/// <summary> /// Check indentation /// </summary> /// <param name="line">fills line with intend info</param> protected static void CheckIntendation(LineInfo line) { int ws, intendation; CheckIntendation(line, out ws, out intendation); if (ws == -1) throw new CodeGeneratorException(line.LineNumber, line.Data, "Failed to find indentation on line #" + line.LineNumber); line.Set(ws, intendation); }
/// <summary> /// Read next line from file /// </summary> /// <returns>true if line could be read; false if EOF.</returns> protected bool ReadLine() { string line = _reader.ReadLine(); string trimmedLine = (line != null) ? line.Trim(new char[] {' ', '\t'}) : string.Empty; while (line != null && (trimmedLine == string.Empty || (trimmedLine.Length > 0 && trimmedLine[0] == '-' && trimmedLine[1] == '/') )) { ++_lineNo; line = _reader.ReadLine(); trimmedLine = (line != null) ? line.Trim(new char[] {' ', '\t'}) : string.Empty; } if (line == null) return false; ++_lineNo; _prevLine = _currentLine; _currentLine = new LineInfo(_lineNo, line); return true; }
/// <summary> /// Parse node contents add return a fresh node. /// </summary> /// <param name="prototypes">List containing all node types</param> /// <param name="parent">Node that this is a subnode to. Can be null</param> /// <param name="line">Line to parse</param> /// <param name="offset">Where to start the parsing. Should be set to where the next node should start parsing.</param> /// <returns>A node corresponding to the bla bla; null if parsing failed.</returns> /// <exception cref="CodeGeneratorException"></exception> public override Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset) { if (line.Data[offset] != '{') throw new CodeGeneratorException(line.LineNumber, line.Data, "Attribute cant handle info at char " + offset + 1); int endPos = GetEndPos(offset, line.Data, '}'); if (endPos == -1) throw new CodeGeneratorException(line.LineNumber, line.Data, "Failed to find end of attribute list: '" + line.UnparsedData + "'."); List<Attribute> col = new List<Attribute>(); string attributes = line.Data.Substring(offset + 1, endPos - offset - 1); ParseAttributes(line, attributes, col); offset = endPos + 1; AttributeNode node = (AttributeNode)prototypes.CreateNode("{", parent); node._attributes = col; return AddMe(prototypes, parent, line, node); }
/// <summary> /// Check and validate indentation /// </summary> /// <param name="line">line to check</param> /// <param name="ws">number of white spaces</param> /// <param name="intendation">number of indentations (2 white spaces = 1 intend, 1 tab = 1 intend)</param> protected static void CheckIntendation(LineInfo line, out int ws, out int intendation) { intendation = 0; ws = -1; char prevUnusedCh = line.UnparsedData[0]; if (prevUnusedCh == '\t') { ++intendation; prevUnusedCh = char.MinValue; } else if (prevUnusedCh != ' ') { ws = 0; return; } for (int i = 1; i < line.UnparsedData.Length; ++i) { char ch = line.UnparsedData[i]; if (ch == ' ') { if (prevUnusedCh == '\t') { ++intendation; prevUnusedCh = ' '; continue; } if (prevUnusedCh == ' ') { prevUnusedCh = char.MinValue; ++intendation; continue; } prevUnusedCh = ' '; } else if (ch == '\t') { if (prevUnusedCh == ' ') { throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid intendation sequence: One space + one tab. Should either be one tab or two spaces."); } if (prevUnusedCh == char.MinValue) { ++intendation; prevUnusedCh = char.MinValue; continue; } } else { if (prevUnusedCh != char.MinValue) { throw new CodeGeneratorException(line.LineNumber, line.Data, "Invalid intendation at char " + i + ", expected a space."); } if (i == 1 && !char.IsWhiteSpace(line.UnparsedData[0])) { ws = 0; } else { ws = i; } return; } } }
/// <summary> /// Parse a file and convert into to our own template object code. /// </summary> /// <param name="reader">A <see cref="TextReader"/> containing our template</param> /// <exception cref="CodeGeneratorException">If something is incorrect in the template.</exception> public void Parse(TextReader reader) { _lineNo = -1; _reader = reader; _mother = new LineInfo(-1, string.Empty); _prevLine = null; _currentLine = null; PreParse(reader); NodeList prototypes = new NodeList(); prototypes.Add(new AttributeNode(null)); prototypes.Add(new TagNode(null)); prototypes.Add(new IdNode(null)); prototypes.Add(new SilentCodeNode(null)); prototypes.Add(new ClassNode(null)); prototypes.Add(new DisplayCodeNode(null)); prototypes.Add(new DocTypeTag(null, null)); prototypes.Add(new PartialNode(null)); TextNode textNode = new TextNode(null, "prototype"); _parentNode = new TextNode(null, string.Empty); foreach (LineInfo info in _mother.Children) ParseNode(info, prototypes, _parentNode, textNode); }