/// <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> /// Modifiers are used to modify the first node on the line. /// Typical modifiers are attribute lists, class names and IDs. /// </summary> /// <param name="node">Modifier node</param> public void AddModifier(Node node) { if (node.IsTextNode) _children.AddLast(node); else _modifiers.AddLast(node); }
/// <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 PartialNode"); // From the first " sign (offset + 2) find the next " sign int pos = -1; for (int i = offset + 2; i < line.Data.Length; ++i) { if (line.Data[i] == '\"') { pos = i; break; } } if (pos == -1) throw new CodeGeneratorException(line.LineNumber, line.Data, "PartialNode does not contain an end paranthesis."); // Cut out the data between the two above found " signs and then start processing the address // The address is converted from the format /example/example/ to \\example\\example.haml PartialNode node = (PartialNode)prototypes.CreateNode("_", parent); node._target = line.Data.Substring(offset + 2, pos - offset - 2); if (node._target[node._target.Length - 1] == '/') node._target = node._target.Substring(0, node._target.Length - 1); if (node._target[0] == '/') node._target = node._target.Substring(1); node._target = node._target.Replace("/", "\\\\"); node._target += ".haml"; offset = pos + 1; 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> /// Creates the node. /// </summary> /// <param name="word">node identifier.</param> /// <param name="parent">parent node.</param> /// <returns>created node if identifier was found; otherwise null.</returns> public Node CreateNode(string word, Node parent) { foreach (Node node in _nodes) { if (node.CanHandle(word, parent == null)) return (Node) Activator.CreateInstance(node.GetType(), new object[]{parent}); } return null; }
/// <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); }
/// <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, "Node is not an id node."); int endPos = GetEndPos(offset, line.Data); if (endPos == -1) endPos = line.Data.Length; ++offset; string id = line.Data.Substring(offset, endPos - offset); offset = endPos; IdNode node = (IdNode)prototypes.CreateNode("#", parent); node._id = id; return AddMe(prototypes, parent, line, 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) 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; }
/// <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); }
/// <summary> /// Add a prototype /// </summary> /// <param name="node">prototype node</param> public void Add(Node node) { //todo: Replace types. _nodes.Add(node); }
public IdNode(Node parent) : base(parent) {}
/// <summary> /// Child nodes may not be the first node on a line /// </summary> /// <param name="parent">parent node</param> public ChildNode(Node parent) : base(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 abstract Node Parse(NodeList prototypes, Node parent, LineInfo line, ref int offset);
/// <summary> /// Create a new HTML tag node. /// </summary> /// <param name="parent">parent node</param> public TagNode(Node parent) : base(parent) { }
public SilentCodeNode(Node parent) : base(parent) {}
/// <summary> /// /// </summary> /// <param name="parent">parent node</param> /// <param name="text">plain text</param> public TextNode(Node parent, string text) : base(parent) { Text = text; }
/// <summary> /// create a new partial node. /// </summary> /// <param name="parent">parent node</param> public PartialNode(Node parent) : base(parent) { }
public DocTypeTag(string docType, Node parent) : base(parent) { _docType = docType; }
/// <summary> /// Contains C# code that will be rendered into the view. /// </summary> /// <param name="parent">Parent node</param> public DisplayCodeNode(Node parent) : base(parent) {}
bool IsLastNode(Node parent) { if (parent == null) return false; if (parent.ModifierCount == 0) return false; return parent.LastModifier == this; }
public ClassNode(Node parent) : base(parent) { }
/// <summary> /// create an attribute node /// </summary> /// <param name="parent">parent node</param> public AttributeNode(Node parent) : base(parent) { _attributes = new List<Attribute>(); }
/// <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> /// Add a new node /// </summary> /// <param name="parent">parent node.</param> public Node(Node parent) { _parent = parent; }
/// <summary> /// Create a new node /// </summary> /// <param name="parent">parent node</param> /// <param name="col">collection of attributes</param> public AttributeNode(Node parent, List<Attribute> col) : base(parent) { _attributes = col; }
/// <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); }