Example #1
0
        ///<summary>
        /// Copies all child nodes from source into heir, recursively.
        /// -If a node appears only in source or only in heir, it is included.
        /// -If a list appears in both source and heir, source's entries are appended to heir's entries.
        /// -If a non-list node appears in both source and heir, heir's node is overwritten.
        ///</summary>
        private static void ApplyInheritance(TydNode source, TydNode heir)
        {
            try
            {
                //They're strings: Copy source over heir
                {
                    TydString sourceStr = source as TydString;
                    if (sourceStr != null)
                    {
                        TydString heirStr = heir as TydString;
                        heirStr.Value = sourceStr.Value;
                        return;
                    }
                }

                //They're tables: Combine all children of source and heir, with source having priority in case of duplicates
                {
                    TydTable sourceObj = source as TydTable;
                    if (sourceObj != null)
                    {
                        TydTable heirObj = (TydTable)heir;
                        for (int i = 0; i < sourceObj.Count; i++)
                        {
                            var sourceChild       = sourceObj[i];
                            var heirMatchingChild = heirObj[sourceChild.Name];
                            if (heirMatchingChild != null)
                            {
                                ApplyInheritance(sourceChild, heirMatchingChild);
                            }
                            else
                            {
                                heirObj.AddChild(sourceChild); //Does this need to be DeepClone?
                            }
                        }
                        return;
                    }
                }

                //They're lists: Append source's entries to heir's entries
                {
                    TydList sourceList = source as TydList;
                    if (sourceList != null)
                    {
                        TydList heirList = (TydList)heir;
                        for (int i = 0; i < sourceList.Count; i++)
                        {
                            heirList.AddChild(sourceList[i]); //Does this need to be DeepClone?
                        }
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception("ApplyInheritance exception: " + e + ".\nsource: (" + source + ")\n" + TydToText.Write(source) + "\ntarget: (" + heir + ")\n" + TydToText.Write(heir));
            }
        }
Example #2
0
 ///<summary>
 /// Read an XML document and convert it to a sequence of Tyd nodes.
 /// This ignores the XML root and treats each of the root's children as a separate Tyd table.
 ///</summary>
 public static IEnumerable <TydNode> TydNodesFromXmlDocument(XmlDocument xmlDocument)
 {
     foreach (XmlNode xmlChild in xmlDocument.DocumentElement.ChildNodes)
     {
         TydNode newNode = TydNodeFromXmlNode(xmlChild, null);
         if (newNode != null)
         {
             yield return(newNode);
         }
     }
 }
Example #3
0
        /*
         *  Possible future features:
         *      - Ability to align string values into a single column
         *      - Ability to write lists/tables with 0 or 1 children on a single line
         *      - Some way to better control which strings get quotes and which don't
         */

        ///<summary>
        /// Writes a given TydNode, along with all its descendants, as a string, at a given indent level.
        /// This method is recursive.
        ///</summary>
        public static string Write(TydNode node, int indent = 0)
        {
            //It's a string
            TydString str = node as TydString;

            if (str != null)
            {
                return(IndentString(indent) + node.Name + " " + StringContentWriteable(str.Value));
            }

            //It's a table
            TydTable tab = node as TydTable;

            if (tab != null)
            {
                StringBuilder sb = new StringBuilder();

                //Intro line
                if (AppendNodeIntro(tab, sb, indent) && tab.Count > 0)
                {
                    sb.AppendLine();
                }

                if (tab.Count == 0)
                {
                    sb.Append(Constants.TableStartChar.ToString() + Constants.TableEndChar.ToString());
                }
                else
                {
                    //Sub-nodes
                    sb.AppendLine(IndentString(indent) + Constants.TableStartChar);
                    for (int i = 0; i < tab.Count; i++)
                    {
                        sb.AppendLine(Write(tab[i], indent + 1));
                    }
                    sb.Append(IndentString(indent) + Constants.TableEndChar);
                }

                return(sb.ToString());
            }

            //It's a list
            TydList list = node as TydList;

            if (list != null)
            {
                StringBuilder sb = new StringBuilder();

                //Intro line
                if (AppendNodeIntro(list, sb, indent) && list.Count > 0)
                {
                    sb.AppendLine();
                }

                if (list.Count == 0)
                {
                    sb.Append(Constants.ListStartChar.ToString() + Constants.ListEndChar.ToString());
                }
                else
                {
                    //Sub-nodes
                    sb.AppendLine(IndentString(indent) + Constants.ListStartChar);
                    for (int i = 0; i < list.Count; i++)
                    {
                        sb.AppendLine(Write(list[i], indent + 1));
                    }
                    sb.Append(IndentString(indent) + Constants.ListEndChar);
                }

                return(sb.ToString());
            }

            throw new ArgumentException();
        }
Example #4
0
        ///<summary>
        /// Copies all child nodes from source into heir, recursively.
        /// -If a node appears only in source or only in heir, it is included.
        /// -If a list appears in both source and heir, source's entries are appended to heir's entries.
        /// -If a non-list node appears in both source and heir, heir's node is overwritten.
        ///</summary>
        private static void ApplyInheritance(TydNode source, TydNode heir)
        {
            try
            {
                //They're either strings or nulls: We just keep the existing heir's value
                if (source is TydString)
                {
                    return;
                }

                //Heir has noinherit attribute: Skip this inheritance
                {
                    TydCollection heirCol = heir as TydCollection;
                    if (heirCol != null && heirCol.AttributeNoInherit)
                    {
                        return;
                    }
                }

                //They're tables: Combine all children of source and heir. Unique-name source nodes are prepended
                {
                    TydTable sourceObj = source as TydTable;
                    if (sourceObj != null)
                    {
                        TydTable heirTable = (TydTable)heir;
                        for (int i = 0; i < sourceObj.Count; i++)
                        {
                            var sourceChild       = sourceObj[i];
                            var heirMatchingChild = heirTable[sourceChild.Name];

                            if (heirMatchingChild != null)
                            {
                                ApplyInheritance(sourceChild, heirMatchingChild);
                            }
                            else
                            {
                                heirTable.InsertChild(sourceChild, 0); //Does this need to be DeepClone?
                            }
                        }
                        return;
                    }
                }

                //They're lists: Prepend source's children before heir's children
                {
                    TydList sourceList = source as TydList;
                    if (sourceList != null)
                    {
                        TydList heirList = (TydList)heir;
                        for (int i = 0; i < sourceList.Count; i++)
                        {
                            //Insert at i so the nodes stay in the same order from source to heir
                            heirList.InsertChild(sourceList[i], i); //Does this need to be DeepClone?
                        }
                        return;
                    }
                }
            }
            catch (Exception e)
            {
                throw new Exception("ApplyInheritance exception: " + e + ".\nsource: (" + source + ")\n" + TydToText.Write(source) + "\ntarget: (" + heir + ")\n" + TydToText.Write(heir));
            }
        }
Example #5
0
        ///<summary>
        /// Recursively parses the string 'doc' starting at char index 'startIndex' and ending when there is an unmatched closing bracket or EOF.
        /// doc should have any opening bracket already stripped off.
        /// This recursive method is used both for parsing files, as well as for parsing specific entries inside files.
        ///</summary>
        private static IEnumerable <TydNode> Parse(string doc, int startIndex, TydNode parent, bool expectNames = true)
        {
            int p = startIndex;

            //Main loop
            while (true)
            {
                string recordName        = null;
                string recordAttClass    = null;
                string recordAttHandle   = null;
                string recordAttSource   = null;
                bool   recordAttAbstract = false;

                try
                {
                    //Skip insubstantial chars
                    p = NextSubstanceIndex(doc, p);

                    //We reached EOF, so we're finished
                    if (p == doc.Length)
                    {
                        yield break;
                    }

                    //We reached a closing bracket, so we're finished with this record
                    if (doc[p] == Constants.TableEndChar || doc[p] == Constants.ListEndChar)
                    {
                        yield break;
                    }

                    //Read the record name if we're not reading anonymous records
                    if (expectNames)
                    {
                        recordName = ReadSymbol(doc, ref p);
                    }

                    //Skip whitespace
                    p = NextSubstanceIndex(doc, p);

                    //Read attributes
                    while (doc[p] == Constants.AttributeStartChar)
                    {
                        //Skip past the '*' character
                        p++;

                        //Read the att name
                        string attName = ReadSymbol(doc, ref p);
                        if (attName == Constants.AbstractAttributeName)
                        {
                            //Just reading the abstract name indicates it's abstract, no value is needed
                            recordAttAbstract = true;
                        }
                        else
                        {
                            p = NextSubstanceIndex(doc, p);

                            //Read the att value
                            string attVal = ReadSymbol(doc, ref p);
                            switch (attName)
                            {
                            case Constants.ClassAttributeName: recordAttClass = attVal; break;

                            case Constants.HandleAttributeName: recordAttHandle = attVal; break;

                            case Constants.SourceAttributeName: recordAttSource = attVal; break;

                            default: throw new Exception("Unknown attribute name '" + attName + "' at " + IndexToLocationString(doc, p));
                            }
                        }

                        p = NextSubstanceIndex(doc, p);
                    }
                }
                catch (Exception e)
                {
                    throw new Exception("Exception parsing Tyd headers at " + IndexToLocationString(doc, p) + ": " + e.ToString(), e);
                }

                //Read the record value.
                //After this is complete, p should be pointing at the char after the last char of the record.
                if (doc[p] == Constants.TableStartChar)
                {
                    //It's a table
                    TydTable newTable = new TydTable(recordName, parent, IndexToLine(doc, p));

                    //Skip past the opening bracket
                    p++;

                    p = NextSubstanceIndex(doc, p);

                    //Recursively parse all of new child's children and add them to it
                    try
                    {
                        foreach (var subNode in Parse(doc, p, newTable, expectNames: true))
                        {
                            if (usedNames.Contains(subNode.Name))
                            {
                                throw new FormatException("Duplicate record name " + subNode.Name + " at " + IndexToLocationString(doc, p));
                            }
                            usedNames.Add(subNode.Name);

                            newTable.AddChild(subNode);
                            p = subNode.docIndexEnd + 1;
                        }
                    }
                    finally
                    {
                        usedNames.Clear();
                    }

                    p = NextSubstanceIndex(doc, p);

                    if (doc[p] != Constants.TableEndChar)
                    {
                        throw new FormatException("Expected ']' at " + IndexToLocationString(doc, p));
                    }

                    newTable.docIndexEnd = p;
                    newTable.SetupAttributes(recordAttClass, recordAttHandle, recordAttSource, recordAttAbstract);
                    yield return(newTable);

                    //Move pointer one past the closing bracket
                    p++;
                }
                else if (doc[p] == Constants.ListStartChar)
                {
                    //It's a list
                    TydList newList = new TydList(recordName, parent, IndexToLine(doc, p));

                    //Skip past the opening bracket
                    p++;

                    p = NextSubstanceIndex(doc, p);

                    //Recursively parse all of new child's children and add them to it
                    foreach (var subNode in Parse(doc, p, newList, expectNames: false))
                    {
                        newList.AddChild(subNode);
                        p = subNode.docIndexEnd + 1;
                    }
                    p = NextSubstanceIndex(doc, p);

                    if (doc[p] != Constants.ListEndChar)
                    {
                        throw new FormatException("Expected " + Constants.ListEndChar + " at " + IndexToLocationString(doc, p));
                    }

                    newList.docIndexEnd = p;
                    newList.SetupAttributes(recordAttClass, recordAttHandle, recordAttSource, recordAttAbstract);
                    yield return(newList);

                    //Move pointer one past the closing bracket
                    p++;
                }
                else
                {
                    //It's a string
                    int    pStart = p;
                    string val;
                    ParseStringValue(doc, ref p, out val);

                    var strNode = new TydString(recordName, val, parent, IndexToLine(doc, pStart));
                    strNode.docIndexEnd = p - 1;
                    yield return(strNode);
                }
            }
        }
Example #6
0
        ///<summary>
        /// Convert a single XML tree into a Tyd tree.
        /// If expectName is false, it'll be parsed as a list item.
        ///</summary>
        public static TydNode TydNodeFromXmlNode(XmlNode xmlRoot, TydNode tydParent)
        {
            if (xmlRoot is XmlComment)
            {
                return(null);
            }

            string newTydName = xmlRoot.Name != "li"
            ? xmlRoot.Name
            : null;

            //Record attributes here so we can use them later
            string attClass      = null;
            string attHandle     = null;
            string attSource     = null;
            bool   attAbstract   = false;
            var    xmlAttributes = xmlRoot.Attributes;

            if (xmlAttributes != null)
            {
                foreach (XmlAttribute a in xmlAttributes)
                {
                    if (a.Name == "Class")
                    {
                        attClass = a.Value;
                    }
                    else if (a.Name == "Name")
                    {
                        attHandle = a.Value;
                    }
                    else if (a.Name == "ParentName")
                    {
                        attSource = a.Value;
                    }
                    else if (a.Name == "Abstract" && a.Value == "True")
                    {
                        attAbstract = true;
                    }
                }
            }

            if (xmlRoot.ChildNodes.Count == 1 && xmlRoot.FirstChild is XmlText)
            {
                //It's a string
                return(new TydString(newTydName, xmlRoot.FirstChild.InnerText, tydParent));
            }
            else if (xmlRoot.HasChildNodes && xmlRoot.FirstChild.Name == "li")
            {
                //Children are named 'li'
                //It's a list

                TydList tydRoot = new TydList(newTydName, tydParent);
                tydRoot.SetupAttributes(attClass, attHandle, attSource, attAbstract);
                foreach (XmlNode xmlChild in xmlRoot.ChildNodes)
                {
                    tydRoot.AddChild(TydNodeFromXmlNode(xmlChild, tydRoot));
                }
                return(tydRoot);
            }
            else
            {
                //This case catches nodes with no children.
                //Note that the case of no children is ambiguous between list and table; we choose list arbitrarily.

                //It's a table
                TydTable tydRoot = new TydTable(newTydName, tydParent);
                tydRoot.SetupAttributes(attClass, attHandle, attSource, attAbstract);
                foreach (XmlNode xmlChild in xmlRoot.ChildNodes)
                {
                    tydRoot.AddChild(TydNodeFromXmlNode(xmlChild, tydRoot));
                }
                return(tydRoot);
            }
        }
Example #7
0
        /*
         *  Possible future features:
         *      - Ability to align string values into a single column
         *      - Ability to write lists/tables with 0 or 1 children on a single line
         *      - Some way to better control which strings get quotes and which don't
         */

        ///<summary>
        /// Writes a given TydNode, along with all its descendants, as a string, at a given indent level.
        /// This method is recursive.
        ///</summary>
        public static string Write(TydNode node, bool whitesmiths, int indent = 0, int longestName = 0, bool forceQuotes = false, bool noInlineTables = false)
        {
            var braceIndent = whitesmiths ? indent + 1 : indent;
            //It's a string
            var str = node as TydString;

            if (str != null)
            {
                if (str.Name != null)
                {
                    return(IndentString(indent) + node.Name + RepeatString(" ", (Math.Max(0, longestName - node.Name.Length) + 1)) + StringContentWriteable(str.Value, forceQuotes));
                }
                else
                {
                    return(IndentString(indent) + StringContentWriteable(str.Value, forceQuotes));
                }
            }

            var doc = node as TydDocument;

            if (doc != null)
            {
                var nameLength = doc.Nodes.Max(x => x.Name.Length);
                var sb         = new StringBuilder();
                foreach (var subNode in doc)
                {
                    sb.AppendLine(Write(subNode, whitesmiths, indent, nameLength, forceQuotes, noInlineTables));
                    if (subNode is TydCollection)
                    {
                        sb.AppendLine();
                    }
                }
                return(sb.ToString());
            }

            //It's a table
            var tab = node as TydTable;

            if (tab != null)
            {
                var sb     = new StringBuilder();
                var simple = !noInlineTables && tab.Parent != null && !(tab.Parent is TydDocument) && IsSimpleCollection(tab);
                var intro  = AppendNodeIntro(tab, sb, indent);
                //Intro line
                if (intro && !simple)
                {
                    sb.AppendLine();
                }

                if (simple)
                {
                    if (!intro)
                    {
                        sb.Append(IndentString(indent) + Constants.TableStartChar);
                    }
                    else
                    {
                        sb.Append(RepeatString(" ", Math.Max(0, longestName - tab.Name.Length) + 1) + Constants.TableStartChar);
                    }
                    for (var i = 0; i < tab.Count; i++)
                    {
                        sb.Append(i == 0 ? " " : "; ");
                        sb.Append(Write(tab[i], whitesmiths, 0, 0, forceQuotes, noInlineTables));
                    }
                    sb.Append(" " + Constants.TableEndChar);
                }
                else
                {
                    var nameLength = tab.Nodes.Max(x => x.Name.Length);
                    //Sub-_nodes
                    sb.AppendLine(IndentString(braceIndent) + Constants.TableStartChar);
                    for (var i = 0; i < tab.Count; i++)
                    {
                        sb.AppendLine(Write(tab[i], whitesmiths, indent + 1, nameLength, forceQuotes, noInlineTables));
                    }
                    sb.Append(IndentString(braceIndent) + Constants.TableEndChar);
                }

                return(sb.ToString());
            }

            //It's a list
            var list = node as TydList;

            if (list != null)
            {
                var sb     = new StringBuilder();
                var simple = IsSimpleCollection(list);
                var intro  = AppendNodeIntro(list, sb, indent);
                //Intro line
                if (intro && !simple)
                {
                    sb.AppendLine();
                }

                if (simple)
                {
                    if (!intro)
                    {
                        sb.Append(IndentString(indent) + Constants.ListStartChar);
                    }
                    else
                    {
                        sb.Append(RepeatString(" ", Math.Max(0, longestName - list.Name.Length) + 1) + Constants.ListStartChar);
                    }
                    for (var i = 0; i < list.Count; i++)
                    {
                        sb.Append(i == 0 ? " " : "; ");
                        sb.Append(Write(list[i], whitesmiths, 0, 0, forceQuotes, noInlineTables));
                    }
                    sb.Append(" " + Constants.ListEndChar);
                }
                else
                {
                    //Sub-_nodes
                    sb.AppendLine(IndentString(braceIndent) + Constants.ListStartChar);
                    for (var i = 0; i < list.Count; i++)
                    {
                        sb.AppendLine(Write(list[i], whitesmiths, indent + 1, 0, forceQuotes, noInlineTables));
                    }
                    sb.Append(IndentString(braceIndent) + Constants.ListEndChar);
                }

                return(sb.ToString());
            }

            throw new ArgumentException();
        }
Example #8
0
 public TydList(string name, TydNode parent, int docLine = -1) : base(name, parent, docLine)
 {
 }