protected bool ReadSimpleObject(ref string l, out StellarisData d)
        {
            d = null;

            var m = _numericDataPattern.Match(l);

            if (m.Success)
            {
                d = new StellarisData(CurrentFileName, m.Groups["name"].Value, decimal.Parse(m.Groups["value"].Value), EnumEx.GetValueFromDescription <ComparisonOperator>(m.Groups["operator"].Value));
                l = m.Groups["rest"]?.Value;
                return(true);
            }

            m = _textDataPattern.Match(l);
            if (m.Success)
            {
                d = new StellarisData(CurrentFileName, m.Groups["name"].Value, m.Groups["value"].Value);
                l = m.Groups["rest"]?.Value;
                return(true);
            }

            m = _numericOnlyPattern.Match(l);
            if (m.Success)
            {
                d = new StellarisData(CurrentFileName, null, decimal.Parse(m.Groups["value"].Value), ComparisonOperator.EQ);
                l = m.Groups["rest"]?.Value;
                return(true);
            }

            m = _textOnlyPattern.Match(l);
            if (m.Success)
            {
                d = new StellarisData(CurrentFileName, null, m.Groups["value"].Value);
                l = m.Groups["rest"]?.Value;
                return(true);
            }

            return(false);
        }
        protected void ReadComplexObject(ref string l, StreamReader sr, int level, List <StellarisData> context)
        {
            while (l != null)
            {
                // First immediately ignore empty lines
                var m = _emptyPattern.Match(l);
                if (m.Success)
                {
                    l = sr.ReadLine();
#if DEBUG_SHOW
                    System.Diagnostics.Debug.WriteLine("(" + level + ")[empty] " + l);
#endif
                    continue;
                }

                // Determine if the current line is a "complex" object
                m = _complexDataPattern.Match(l);
                if (m.Success)
                {
                    // If it is, recurse into it
                    var    d    = new StellarisData(CurrentFileName, m.Groups["name"].Value, true);
                    string rest = m.Groups["rest"]?.Value;

                    if (rest == null || rest.Length == 0)
                    {
                        rest = sr.ReadLine();
                    }

                    l = rest;
#if DEBUG_SHOW
                    System.Diagnostics.Debug.WriteLine("(" + level + ")[rest] " + l);
#endif
                    ReadComplexObject(ref l, sr, level + 1, d.SubValues);
#if DEBUG_SHOW
                    System.Diagnostics.Debug.WriteLine("(" + level + ")[complexend] " + l);
#endif

                    context.Add(d);
                }
                else
                {
                    // If it's not a "complex" object, it could be a closing bracket
                    m = _complexDataEndPattern.Match(l);
                    if (m.Success)
                    {
                        l = m.Groups["rest"]?.Value;
#if DEBUG_SHOW
                        System.Diagnostics.Debug.WriteLine("(" + level + ")[end] " + l);
#endif
                        return;
                    }

                    // Otherwise, check for a define
                    if (level == 0)
                    {
                        // Defines only exist at the root of the document
                        m = _definePattern.Match(l);
                        if (m.Success)
                        {
                            Defines.Add(new StellarisDefine(CurrentFileName, m.Groups["name"].Value, decimal.Parse(m.Groups["value"].Value)));
                            l = sr.ReadLine();
#if DEBUG_SHOW
                            System.Diagnostics.Debug.WriteLine("(" + level + ")[define] " + l);
#endif
                            continue;
                        }
                    }

                    // Otherwise we should be looking at a "simple" object
                    StellarisData d;
                    if (ReadSimpleObject(ref l, out d))
                    {
                        context.Add(d);

                        if (l == null || l.Length == 0)
                        {
                            l = sr.ReadLine();
                        }
#if DEBUG_SHOW
                        System.Diagnostics.Debug.WriteLine("(" + level + ")[simple] " + l);
#endif
                    }
                    else
                    {
                        l = sr.ReadLine();
#if DEBUG_SHOW
                        System.Diagnostics.Debug.WriteLine("(" + level + ")[none] " + l);
#endif
                    }
                }
            }
        }