Exemple #1
0
        private HoconValue ResolveSubstitution(HoconSubstitution sub)
        {
            var subField = sub.ParentField;

            // first case, this substitution is a direct self-reference
            if (sub.Path == subField.Path)
            {
                var parent = sub.Parent;
                while (parent is HoconValue)
                {
                    parent = parent.Parent;
                }

                // Fail case
                if (parent is HoconArray)
                {
                    throw new HoconException("Self-referencing substitution may not be declared within an array.");
                }

                // try to resolve substitution by looking backward in the field assignment stack
                return(subField.OlderValueThan(sub));
            }

            // second case, the substitution references a field child in the past
            if (sub.Path.IsChildPathOf(subField.Path))
            {
                var olderValue = subField.OlderValueThan(sub);
                if (olderValue.Type == HoconType.Object)
                {
                    var difLength = sub.Path.Count - subField.Path.Count;
                    var deltaPath = sub.Path.SubPath(sub.Path.Count - difLength, difLength);

                    var olderObject = olderValue.GetObject();
                    if (olderObject.TryGetValue(deltaPath, out var innerValue))
                    {
                        return(innerValue.Type == HoconType.Object ? innerValue : null);
                    }
                }
            }

            // Detect invalid parent-referencing substitution
            if (subField.Path.IsChildPathOf(sub.Path))
            {
                throw new HoconException("Substitution may not reference one of its direct parents.");
            }

            // Detect invalid cyclic reference loop
            if (IsValueCyclic(subField, sub))
            {
                throw new HoconException("A cyclic substitution loop is detected in the Hocon file.");
            }

            // third case, regular substitution
            _root.GetObject().TryGetValue(sub.Path, out var field);
            return(field?.Clone(field.Parent) as HoconValue);
        }
Exemple #2
0
        // The owner in this context can be either an object or an array.
        private void ParseObject(ref HoconValue owner)
        {
            if (owner == null)
            {
                throw HoconParserException.Create(_tokens.Current, Path,
                                                  "ParseObject called with null parent.");
            }

            // Sanity check
            if (_tokens.Current.Type != TokenType.StartOfObject)
            {
                throw HoconParserException.Create(_tokens.Current, Path,
                                                  $"Failed to parse Hocon object. Expected `{TokenType.StartOfObject}`, found `{_tokens.Current.Type}` instead.");
            }

            // Consume curly bracket
            _tokens.ToNextSignificant();

            var hoconObject = owner.GetObject();

            if (hoconObject == null)
            {
                hoconObject = new HoconObject(owner);
                owner.Add(hoconObject);
            }

            var valueWasParsed = false;
            var parsing        = true;

            while (parsing)
            {
                switch (_tokens.Current.Type)
                {
                case TokenType.Include:
                    if (valueWasParsed)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Failed to parse Hocon object. Expected `{TokenType.Comma}` or `{TokenType.EndOfLine}`, " +
                                                          $"found `{_tokens.Current.Type}` instead.");
                    }

                    owner.ReParent(ParseInclude());
                    valueWasParsed = true;
                    break;

                case TokenType.LiteralValue:
                    if (_tokens.Current.IsNonSignificant())
                    {
                        _tokens.ToNextSignificant();
                    }

                    if (_tokens.Current.Type != TokenType.LiteralValue)
                    {
                        break;
                    }

                    if (valueWasParsed)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Failed to parse Hocon object. Expected `{TokenType.Comma}` or `{TokenType.EndOfLine}`, " +
                                                          $"found `{_tokens.Current.Type}` instead.");
                    }

                    ParseField(hoconObject);
                    valueWasParsed = true;
                    break;

                case TokenType.Comment:
                case TokenType.EndOfLine:
                    valueWasParsed = false;
                    _tokens.ToNextSignificantLine();
                    break;

                case TokenType.Comma:
                    if (!valueWasParsed)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Failed to parse Hocon object. Expected `{TokenType.Assign}` or `{TokenType.StartOfObject}`, " +
                                                          $"found `{_tokens.Current.Type}` instead.");
                    }

                    valueWasParsed = false;
                    _tokens.ToNextSignificant();
                    break;

                case TokenType.EndOfObject:
                    valueWasParsed = false;
                    parsing        = false;
                    break;

                case TokenType.EndOfFile:
                    throw HoconParserException.Create(_tokens.Current, Path,
                                                      $"Failed to parse Hocon object. Expected {TokenType.EndOfObject} but found {_tokens.Current.Type} instead.");

                default:
                    throw HoconParserException.Create(_tokens.Current, Path,
                                                      $"Failed to parse Hocon object. Unexpected token `{_tokens.Current.Type}`.");
                }
            }

            // Consume the closing curly bracket.
            _tokens.ToNextSignificant();
        }
Exemple #3
0
        private void ParseObject(HoconValue owner, bool root, string currentPath)
        {
            try
            {
                PushDiagnostics("{");

                if (owner.IsObject())
                {
                    //the value of this KVP is already an object
                }
                else
                {
                    //the value of this KVP is not an object, thus, we should add a new
                    owner.NewValue(new HoconObject());
                }

                HoconObject currentObject = owner.GetObject();

                while (!_reader.EoF)
                {
                    Token t = _reader.PullNext();
                    switch (t.Type)
                    {
                    case TokenType.Include:
                        var included      = _includeCallback(t.Value);
                        var substitutions = included.Substitutions;
                        foreach (var substitution in substitutions)
                        {
                            //fixup the substitution, add the current path as a prefix to the substitution path
                            substitution.Path = currentPath + "." + substitution.Path;
                        }
                        _substitutions.AddRange(substitutions);
                        var otherObj = included.Value.GetObject();
                        owner.GetObject().Merge(otherObj);

                        break;

                    case TokenType.EoF:
                        if (!string.IsNullOrEmpty(currentPath))
                        {
                            throw new HoconParserException(string.Format("Expected end of object but found EoF {0}", GetDiagnosticsStackTrace()));
                        }
                        break;

                    case TokenType.Key:
                        HoconValue value    = currentObject.GetOrCreateKey(t.Value);
                        var        nextPath = currentPath == "" ? t.Value : currentPath + "." + t.Value;
                        ParseKeyContent(value, nextPath);
                        if (!root)
                        {
                            return;
                        }
                        break;

                    case TokenType.ObjectEnd:
                        return;
                    }
                }
            }
            finally
            {
                PopDiagnostics();
            }
        }