Ejemplo n.º 1
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);
                }
            }
        }
Ejemplo n.º 2
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);
            }
        }