Пример #1
0
        public void SimpleRead()
        {
            var sampleData = string.Format("{0}\n\t{1}\n\t{2}",
                                           "level1 t1 \"t2\" `t3`",
                                           "level2 \"t1\" t2 `t3`",
                                           "level2 t1 `t2` \"t3\""
                                           );


            var result = new DefReader().LoadDataFromString(sampleData, CancellationToken.None);

            var expectedRootNode = new DefNode();
            var l1node           = new DefNode();

            l1node.Tokens = new DefTokenCollection().Add("level1").Add("t1").Add("t2").Add("t3");
            l1node.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("level2").Add("t1").Add("t2").Add("t3")
            });
            l1node.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("level2").Add("t1").Add("t2").Add("t3")
            });
            expectedRootNode.ChildNodes.Add(l1node);

            var expectedResult = TestUtils.JsonSerialize(expectedRootNode);
            var actualResult   = TestUtils.JsonSerialize(result);

            Assert.AreEqual(expectedResult, actualResult);
        }
 public DefNode LoadDataFromFile(string filepath, DefNode rootNode, CancellationToken ct)
 {
     using (var stream = new FileStream(filepath, FileMode.Open))
     {
         return(LoadData(stream, rootNode, ct));
     }
 }
Пример #3
0
 public void Visit(DefNode node)
 {
     foreach (var subnode in node)
     {
         Visit((dynamic)subnode);
     }
 }
Пример #4
0
        public void GetCommand()
        {
            string name = "foo";
            IList <ArgumentInfo> arguments = new List <ArgumentInfo>()
            {
                new ArgumentInfo("a", TypeInfo.Int), new ArgumentInfo("b", TypeInfo.Double)
            };
            TypeInfo        typeinfo   = TypeInfo.Int;
            IExpressionNode expression = new ConstantNode(42);

            DefNode node = new DefNode(name, arguments, typeinfo, expression);

            var result = node.GetCommand();

            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(DefCommand));

            var dcmd = (DefCommand)result;

            Assert.AreEqual(name, dcmd.Name);
            Assert.AreEqual(TypeInfo.Int, dcmd.TypeInfo);
            Assert.IsNotNull(dcmd.Arguments);
            Assert.AreEqual(2, dcmd.Arguments.Count);
            Assert.AreSame(arguments, dcmd.Arguments);

            Assert.IsNotNull(dcmd.Body);
            Assert.IsInstanceOfType(dcmd.Body, typeof(ExpressionCommand));

            var body = (ExpressionCommand)dcmd.Body;

            Assert.IsInstanceOfType(body.Expression, typeof(ConstantExpression));
            Assert.AreEqual(42, ((ConstantExpression)body.Expression).Value);
        }
Пример #5
0
        public void RaiseIfTypeMismatch()
        {
            string name = "foo";
            IList <ArgumentInfo> arguments = new List <ArgumentInfo>()
            {
                new ArgumentInfo("a", TypeInfo.Int), new ArgumentInfo("b", TypeInfo.Double)
            };
            TypeInfo        typeinfo   = TypeInfo.String;
            IExpressionNode expression = new ConstantNode(42);

            DefNode node = new DefNode(name, arguments, typeinfo, expression);

            Assert.IsNotNull(node.TypeInfo);
            Assert.AreSame(TypeInfo.String, node.TypeInfo);

            try
            {
                node.CheckType(null);
                Assert.Fail();
            }
            catch (Exception ex)
            {
                Assert.AreEqual("type mismatch", ex.Message);
            }
        }
        public DefNode LoadDataFromFile(string filepath, CancellationToken ct)
        {
            var rootNode = new DefNode();

            rootNode.Tokens.Add("FILE");
            rootNode.Tokens.Add(filepath);

            return(LoadDataFromFile(filepath, rootNode, ct));
        }
        public DefNode LoadDataFromString(string s, CancellationToken ct)
        {
            var rootNode = new DefNode();

            var bytes  = Encoding.UTF8.GetBytes(s);
            var stream = new MemoryStream(bytes);

            return(LoadData(stream, rootNode, ct));
        }
Пример #8
0
        public void CheckType()
        {
            Context context = new Context();
            DefNode defnode = new DefNode("append", null, TypeInfo.Int, null);

            defnode.RegisterInContext(context);
            IList <INode> arguments = new List <INode>()
            {
                new ConstantNode(42)
            };
            InvokeNode node = new InvokeNode(new NameNode("append"), arguments);

            Assert.IsNull(node.TypeInfo);
            node.CheckType(context);
            Assert.AreEqual(TypeInfo.Int, node.TypeInfo);
        }
        public TradeMap Build(DefNode rootNode, CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            //ProgressEvents.DoEvent(this, new ProgressEventArgs("Starting map load"));
            var map = CreateMap(rootNode, ct);

            ct.ThrowIfCancellationRequested();
            ProgressEvents.DoEvent(this, new ProgressEventArgs(0, 0, ProgressEventStatus.Working, $"Matching planets to systems..."));
            CheckSystemsCanTrade(map);

            ct.ThrowIfCancellationRequested();
            ProgressEvents.DoEvent(this, new ProgressEventArgs(0, 0, ProgressEventStatus.Working, $"Completing links..."));
            CompleteLinks(map);

            return(map);
        }
Пример #10
0
        public void CreateDefNode()
        {
            string name = "foo";
            IList <ArgumentInfo> arguments = new List <ArgumentInfo>()
            {
                new ArgumentInfo("a", TypeInfo.Int), new ArgumentInfo("b", TypeInfo.Double)
            };
            TypeInfo        typeinfo   = TypeInfo.Int;
            IExpressionNode expression = new ConstantNode(42);

            DefNode node = new DefNode(name, arguments, typeinfo, expression);

            Assert.AreEqual(name, node.Name);
            Assert.AreSame(arguments, node.Arguments);
            Assert.AreSame(TypeInfo.Int, node.TypeInfo);
            Assert.AreSame(expression, node.Expression);
        }
Пример #11
0
        public void CreateDefNodeWithoutTypeInfo()
        {
            string name = "foo";
            IList <ArgumentInfo> arguments = new List <ArgumentInfo>()
            {
                new ArgumentInfo("a", TypeInfo.Int), new ArgumentInfo("b", TypeInfo.Double)
            };
            TypeInfo        typeinfo   = TypeInfo.Int;
            IExpressionNode expression = new ConstantNode(42);

            DefNode node = new DefNode(name, arguments, null, expression);

            Assert.IsNull(node.TypeInfo);

            node.CheckType(null);

            Assert.AreSame(TypeInfo.Int, node.TypeInfo);
        }
Пример #12
0
        public void RegisterInContext()
        {
            string name = "foo";
            IList <ArgumentInfo> arguments = new List <ArgumentInfo>()
            {
                new ArgumentInfo("a", TypeInfo.Int), new ArgumentInfo("b", TypeInfo.Double)
            };
            TypeInfo        typeinfo   = TypeInfo.Int;
            IExpressionNode expression = new ConstantNode(42);

            DefNode node = new DefNode(name, arguments, typeinfo, expression);

            Context context = new Context();

            node.RegisterInContext(context);

            Assert.IsNotNull(context.GetValue("foo"));
            Assert.AreSame(node, context.GetValue("foo"));
        }
Пример #13
0
        public void SomeComments()
        {
            var sampleData = string.Format("{0}\n{1}\n\t{2}\n\t{3}",
                                           "#This is a comment",
                                           "node1 t1 t2 #this is another comment",
                                           "#this is yet another comment",
                                           "node2 t1 t2"
                                           );

            var result = new DefReader().LoadDataFromString(sampleData, CancellationToken.None);

            var expectedResult = new DefNode();
            var node1          = new DefNode();

            node1.Tokens.Add("node1").Add("t1").Add("t2");
            expectedResult.ChildNodes.Add(node1);
            var node2 = new DefNode();

            node2.Tokens.Add("node2").Add("t1").Add("t2");
            node1.ChildNodes.Add(node2);

            Assert.AreEqual(TestUtils.JsonSerialize(expectedResult), TestUtils.JsonSerialize(result));
        }
Пример #14
0
        private DefNode parseDef()
        {
            expect(TokenType.DEF);
            next();

            var def = new DefNode(parseIdent());

            expect(TokenType.LPAREN);
            next();

            while (more() && current().Type != TokenType.RPAREN)
            {
                def.Parameters.Add(parseIdent());

                if (accept(TokenType.COMMA))
                {
                    next();
                    expectNot(TokenType.RPAREN);
                }
            }

            expect(TokenType.RPAREN);
            next();

            expect(TokenType.LBRACE);
            next();

            while (more() && current().Type != TokenType.RBRACE)
            {
                def.Code.Add(parseStatement());
            }

            expect(TokenType.RBRACE);
            next();

            return(def);
        }
        //public Task<RouteScannerResults> Scan(CancellationToken ct)
        public RouteScannerResults Scan(CancellationToken ct)
        {
            State = ScanWorkerState.Working;
            try
            {
                ct.ThrowIfCancellationRequested();

                // Make the root node
                var rootNode = new DefNode();

                // Read def files
                var defReader = new DefReader();
                defReader.ProgressEvents.ProgressEvent += new EventHandler <ProgressEventArgs>((sender, args) => {
                    DoProgressEvent(sender, args);
                });
                foreach (var filepath in _defFiles)
                {
                    ct.ThrowIfCancellationRequested();
                    defReader.LoadDataFromFile(filepath, rootNode, ct);
                }


                // Build map
                var mapBuilder = new TradeMapBuilder();
                mapBuilder.ProgressEvents.ProgressEvent += new EventHandler <ProgressEventArgs>((sender, args) => {
                    DoProgressEvent(sender, args);
                });
                ct.ThrowIfCancellationRequested();
                var map = mapBuilder.Build(rootNode, ct);

                // Check that there are systems in the map
                if (map.Systems.Count == 0)
                {
                    DoProgressEvent(this, new ProgressEventArgs(ProgressEventStatus.Error, "No systems were found. Are the correct def files selected?"));
                    //return Task.FromResult(new RouteScannerResults() { Successful = false });
                    return(new RouteScannerResults()
                    {
                        Successful = false
                    });
                }

                // Scan for runs & routes
                var tradeScanner = new RouteScanner();
                tradeScanner.ProgressEvents.ProgressEvent += new EventHandler <ProgressEventArgs>((sender, args) => {
                    DoProgressEvent(sender, args);
                });
                ct.ThrowIfCancellationRequested();
                var results = tradeScanner.Scan(map, _options, ct);

                DoProgressEvent(this, new ProgressEventArgs(ProgressEventStatus.Complete, "Route scanning complete"));

                // Done
                //return Task.FromResult(results);
                return(results);
            }
            catch (OperationCanceledException)
            {
                // Operation was cancelled. Stop gracefully.

                DoProgressEvent(this, new ProgressEventArgs(ProgressEventStatus.Complete, "Cancelled"));
                //return Task.FromResult(new RouteScannerResults() { Successful = false });
                return(new RouteScannerResults()
                {
                    Successful = false
                });
            }
            catch (Exception ex)
            {
                DoProgressEvent(this, new ProgressEventArgs(ProgressEventStatus.Error, $"An error occurred: {ex.GetType().ToString()}\n{ex.Message}"));
                //return Task.FromResult(new RouteScannerResults() { Successful = false });
                return(new RouteScannerResults()
                {
                    Successful = false
                });
            }
            finally
            {
                State = ScanWorkerState.Idle;
            }
        }
        public TradeMap CreateMap(DefNode rootNode, CancellationToken ct)
        {
            var map = new TradeMap();

            //foreach (var topNode in rootNode.ChildNodes)
            for (int iNode = 0; iNode < rootNode.ChildNodes.Count; iNode++)
            {
                ProgressEvents.DoEvent(this, new ProgressEventArgs(iNode, rootNode.ChildNodes.Count, ProgressEventStatus.Working, $"Reading node {iNode}/{rootNode.ChildNodes.Count}"));
                var topNode = rootNode.ChildNodes[iNode];
                // Only care about "system" nodes
                if (topNode.Tokens.Count >= 2 && topNode.Tokens[0] == NODE_NAME_SYSTEM)
                {
                    // Is a system node
                    var newSystem = new TradeMapSystem();
                    newSystem.Name = topNode.Tokens[1].Trim();
                    // TODO handle blank system name

                    foreach (var subNode in topNode.ChildNodes)
                    {
                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_LINK)
                        {
                            // TODO handle blank system name in link
                            newSystem.Links.Add(new TradeMapSystemLink()
                            {
                                Name = subNode.Tokens[1].Trim()
                            });
                        }

                        if (subNode.Tokens.Count >= 3 && subNode.Tokens[0] == NODE_NAME_TRADE)
                        {
                            int tradePrice;
                            if (!int.TryParse(subNode.Tokens[2].Trim(), out tradePrice))
                            {
                                // TODO Handle bad number on trade price
                            }
                            else
                            {
                                // TODO handle empty comodity name
                                newSystem.Comodities.Add(new TradeMapComodity()
                                {
                                    Name = subNode.Tokens[1].Trim(), Price = tradePrice
                                });
                            }
                        }

                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_OBJECT)
                        {
                            newSystem.NamedObjects.Add(subNode.Tokens[1].Trim());
                        }
                    }

                    newSystem.Name = newSystem.Name.Trim();
                    map.Systems.Add(newSystem);
                }
                else if (topNode.Tokens.Count >= 2 && topNode.Tokens[0] == NODE_NAME_PLANET)
                {
                    // Is a planet
                    // I was really annoyed when I found out that a bunch of systems in the map
                    // have trade & comoddity information, but no planets to trade on.
                    // I had to change the way I did things, shat me to tears :(
                    var newPlanet = new TradeMapPlanet();
                    newPlanet.Name = topNode.Tokens[1].Trim();

                    foreach (var subNode in topNode.ChildNodes)
                    {
                        if (subNode.Tokens.Count >= 2 && subNode.Tokens[0] == NODE_NAME_SPACEPORT)
                        {
                            newPlanet.HasSpaceport = true;
                        }
                    }

                    // Only save planets that have spaceports
                    if (newPlanet.HasSpaceport)
                    {
                        map.Planets.Add(newPlanet);
                    }
                }
                else
                {
                    // skipping node I don't care about, like "galaxy"
                }
            }

            return(map);
        }
        public void MapBuilder_SimpleRead()
        {
            var sampleDataRoot = new DefNode();

            var sampleDataSystem1 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem1);
            sampleDataSystem1.Tokens.Add("system").Add("Tarazed");
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Enif")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("305")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("761")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("395")
            });
            sampleDataSystem1.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("238")
            });

            var sampleDataSystem2 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem2);
            sampleDataSystem2.Tokens.Add("system").Add("Enif");
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Tarazed")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Sadalmelik")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("361")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("800")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("485")
            });
            sampleDataSystem2.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("335")
            });

            var sampleDataSystem3 = new DefNode();

            sampleDataRoot.ChildNodes.Add(sampleDataSystem3);
            sampleDataSystem3.Tokens.Add("system").Add("Sadalmelik");
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("belt").Add("1169")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("link").Add("Enif")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Clothing").Add("361")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Electronics").Add("800")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Equipment").Add("485")
            });
            sampleDataSystem3.ChildNodes.Add(new DefNode()
            {
                Tokens = new DefTokenCollection().Add("trade").Add("Food").Add("335")
            });

            var resultMap = new TradeMapBuilder().Build(sampleDataRoot, CancellationToken.None);

            var expectedMap = new TradeMap();

            var tradeSystem1 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem1);
            tradeSystem1.Name = "Tarazed";
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 305
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 761
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 395
            });
            tradeSystem1.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 238
            });

            var tradeSystem2 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem2);
            tradeSystem2.Name = "Enif";
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 361
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 800
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 485
            });
            tradeSystem2.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 335
            });

            var tradeSystem3 = new TradeMapSystem();

            expectedMap.Systems.Add(tradeSystem3);
            tradeSystem3.Name = "Sadalmelik";
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Clothing", Price = 361
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Electronics", Price = 800
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Equipment", Price = 485
            });
            tradeSystem3.Comodities.Add(new TradeMapComodity {
                Name = "Food", Price = 335
            });

            tradeSystem1.Links.Add(new TradeMapSystemLink()
            {
                Name = "Enif", System = tradeSystem2
            });
            tradeSystem2.Links.Add(new TradeMapSystemLink()
            {
                Name = "Tarazed", System = tradeSystem1
            });
            tradeSystem2.Links.Add(new TradeMapSystemLink()
            {
                Name = "Sadalmelik", System = tradeSystem3
            });
            tradeSystem3.Links.Add(new TradeMapSystemLink()
            {
                Name = "Enif", System = tradeSystem2
            });

            // TODO assert
        }
Пример #18
0
 public TurtProcedure(DefNode procedure)
 {
     this.procedure = procedure;
 }
        public DefNode LoadData(Stream dataStream, DefNode rootNode, CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();
            var sr = new StreamReader(dataStream, UTF8Encoding.UTF8);

            int             indentLevel = 0; // Indentation level
            Stack <DefNode> nodeStack   = new Stack <DefNode>();
            Stack <int>     indentStack = new Stack <int>();
            char            c;
            StringBuilder   tokenBuffer;

            // Add the root node
            nodeStack.Push(rootNode);
            indentStack.Push(-1); // Start with -1 in it

            // At the root level
            // Read through the lines of characters, until there are none left
            c = GetNextChar(sr);
            while (sr.Peek() >= 0)
            {
                ct.ThrowIfCancellationRequested();

                indentLevel = 0; // Reset the indent level

                // Read through spaces
                while (c == CHAR_WHITESPACE_TAB)
                {
                    indentLevel++;
                    c = GetNextChar(sr); // keep reading
                }

                // Skip empty lines
                if (c == CHAR_NEWLINE)
                {
                    c = GetNextChar(sr);
                    continue;
                }


                if (c == CHAR_COMMENT)
                {
                    // Is a comment line. Read until new line.
                    while (c != CHAR_NEWLINE)
                    {
                        // Read until newline
                        c = GetNextChar(sr);
                    }
                    continue; // Start reading line again
                }

                // Is a valid line.

                // Determine where in the node tree we are inserting this node, based on
                // whether it has more indentation that the previous node, less, or the same.
                // If the previous line's indentation level is equal or greater this row's indentation level,
                // then this row is not a child of the previous row. Keep going backwards in the stack until the same
                // indentation level is met.
                while (indentStack.Peek() >= indentLevel)
                {
                    indentStack.Pop();
                    nodeStack.Pop();
                }

                // Ready to read this node
                DefNode parent = nodeStack.Peek(); // Because the root node should be in there, there should ALWAYS be something in there

                // Read the line
                //var newNode = ReadLine(sr, c);
                var  newDefNode = new DefNode();
                char quoteChar  = Char.MinValue;

                // Loop for each token, or until the stream runs out
                while (sr.Peek() >= 0)
                {
                    ct.ThrowIfCancellationRequested();

                    // Reset some things
                    quoteChar   = Char.MinValue;
                    tokenBuffer = new StringBuilder();

                    // If the next character is a whitespace, end of line
                    if (c == CHAR_NEWLINE)
                    {
                        break;
                    }

                    // Wait for the next non-whitespace character
                    if (Char.IsWhiteSpace(c))
                    {
                        // Don't care, next char
                        c = GetNextChar(sr);
                        continue;
                    }

                    // If there's a comment, do nothing
                    if (c == CHAR_COMMENT)
                    {
                        // Comment. Don't care about the rest of the line.
                        while (c != CHAR_NEWLINE)
                        {
                            c = GetNextChar(sr);
                        }
                        break;
                    }

                    // Read the token

                    // If the token starts with a quotation, remember what quotation was used, and ignore this character
                    if (c == CHAR_QUOTE_QUOTE || c == CHAR_QUOTE_TILDE)
                    {
                        quoteChar = c; // Remember what quote character was used

                        // ADvance a character
                        c = GetNextChar(sr);
                    }

                    // Read until the end of line, or an unquoted space, or the end of the quotation
                    while (c != CHAR_NEWLINE && ((quoteChar != Char.MinValue && c != quoteChar) || (quoteChar == Char.MinValue && c != ' ')))
                    {
                        tokenBuffer.Append(c);
                        c = GetNextChar(sr);
                    }

                    // Made it out here, end of token

                    if (tokenBuffer.Length > 0)
                    {
                        newDefNode.Tokens.Add(tokenBuffer.ToString());
                    }

                    if (c == quoteChar)
                    {
                        c = GetNextChar(sr); // Skip the trailing quote char
                    }
                    // Warn about unterminated quote
                    if (quoteChar != Char.MinValue && c == CHAR_NEWLINE)
                    {
                        // warn
                    }
                }

                // Done reading the line

                parent.ChildNodes.Add(newDefNode);

                // Remember where we are
                indentStack.Push(indentLevel);
                nodeStack.Push(newDefNode);
            }

            // Done reading
            return(rootNode);
        }
        public DefNode LoadDataFromStream(Stream s, CancellationToken ct)
        {
            var rootNode = new DefNode();

            return(LoadData(s, rootNode, ct));
        }