Example #1
0
        private void ResolveSubstitutions()
        {
            foreach (var sub in _substitutions)
            {
                // Retrieve value
                HoconValue res;
                try
                {
                    res = ResolveSubstitution(sub);
                }
                catch (HoconException e)
                {
                    throw HoconParserException.Create(sub, sub.Path, $"Invalid substitution declaration. {e.Message}.", e);
                }

                if (res != null)
                {
                    sub.ResolvedValue = res;
                    continue;
                }

                // Try to pull value from environment
                string envValue = null;
                try
                {
                    envValue = Environment.GetEnvironmentVariable(sub.Path.Value);
                }
                catch (Exception)
                {
                    // ignored
                }

                if (envValue != null)
                {
                    // undefined value resolved to an environment variable
                    res = new HoconValue(sub.Parent);
                    if (envValue.NeedQuotes())
                    {
                        res.Add(new HoconQuotedString(sub.Parent, envValue));
                    }
                    else
                    {
                        res.Add(new HoconUnquotedString(sub.Parent, envValue));
                    }

                    sub.ResolvedValue = res;
                    continue;
                }

                // ${ throws exception if it is not resolved
                if (sub.Required)
                {
                    throw HoconParserException.Create(sub, sub.Path, $"Unresolved substitution: {sub.Path}");
                }

                sub.ResolvedValue = new HoconEmptyValue(sub.Parent);
            }
        }
Example #2
0
 public void FallbackMerge(HoconObject other)
 {
     foreach (var kvp in other)
     {
         var path = kvp.Value.Path;
         if (!TryGetValue(path, out _))
         {
             var        currentObject = this;
             HoconField newField      = null;
             foreach (var key in path)
             {
                 newField = currentObject.GetOrCreateKey(key);
                 if (newField.Type == HoconType.Empty)
                 {
                     var emptyValue = new HoconValue(newField);
                     emptyValue.Add(new HoconObject(emptyValue));
                     newField.SetValue(emptyValue);
                 }
                 currentObject = newField.GetObject();
             }
             newField.SetValue(kvp.Value.Value);
         }
         else
         {
             if (kvp.Value.Type == HoconType.Object)
             {
                 FallbackMerge(kvp.Value.GetObject());
             }
         }
     }
 }
Example #3
0
        private static Config CreateEmpty()
        {
            var value = new HoconValue(null);

            value.Add(new HoconObject(value));
            return(new Config(value));
        }
Example #4
0
        /// <inheritdoc />
        public List <HoconValue> GetArray()
        {
            var result = new List <HoconValue>();

            foreach (var item in this)
            {
                switch (item)
                {
                case HoconValue value:
                    result.Add(value);
                    break;

                case HoconObject obj:
                    var val = new HoconValue(this);
                    val.Add(obj);
                    result.Add(val);
                    break;

                case HoconSubstitution sub:
                    if (sub.ResolvedValue != null)
                    {
                        result.AddRange(sub.ResolvedValue.GetArray());
                    }
                    break;

                default:
                    throw new HoconException($"Unknown type: {item.Type}");
                }
            }
            return(result);
        }
Example #5
0
        public virtual IHoconElement Clone(IHoconElement newParent)
        {
            var clone = new HoconValue(newParent);

            foreach (var value in this)
            {
                clone.Add(value.Clone(clone));
            }
            return(clone);
        }
Example #6
0
        /// <summary>
        ///     Wraps this <see cref="HoconValue" /> into a new <see cref="HoconObject" /> at the specified key.
        /// </summary>
        /// <param name="key">The key designated to be the new root element.</param>
        /// <returns>A new HOCON root.</returns>
        /// <remarks>
        ///     Immutable. Performs a deep copy on this <see cref="HoconValue" /> first.
        /// </remarks>
        public HoconRoot AtKey(string key)
        {
            var value = new HoconValue(null);
            var obj   = new HoconObject(value);
            var field = new HoconField(key, obj);

            field.SetValue(Clone(field) as HoconValue);
            obj.Add(key, field);
            value.Add(obj);

            return(new HoconRoot(value));
        }
Example #7
0
        internal void EnsureFieldIsObject()
        {
            if (Type == HoconType.Object)
            {
                return;
            }

            var v = new HoconValue(this);
            var o = new HoconObject(v);

            v.Add(o);
            _internalValues.Add(v);
        }
Example #8
0
        private void ParseTokens()
        {
            if (_tokens.Current.IsNonSignificant() || _tokens.Current.Type == TokenType.EndOfLine)
            {
                _tokens.ToNextSignificantLine();
            }

            // Array Hocon files are handled differently than normal Hocon file.
            // Array Hocon files HAVE to start with an angle bracket and can only contain ONE array
            if (_tokens.Current.Type == TokenType.StartOfArray)
            {
                _root.Add(ParseArray(_root));

                // Sanity check
                if (_tokens.Current.IsNonSignificant() || _tokens.Current.Type == TokenType.EndOfLine)
                {
                    _tokens.ToNextSignificantLine();
                }

                if (_tokens.Current.Type != TokenType.EndOfFile)
                {
                    throw HoconParserException.Create(_tokens.Current, null,
                                                      $"Illegal token type: {_tokens.Current.Type}. Hocon array file can only contain one array.",
                                                      null);
                }

                return;
            }

            if (_tokens.Current.Type != TokenType.StartOfObject)
            {
                // This is a "headless" Hocon file, we'll normalize the file
                // by inserting the proper open and close curly brackets
                _tokens.Insert(new Token("{", TokenType.StartOfObject, null));
                _tokens.Insert(_tokens.Count - 1, new Token("}", TokenType.EndOfObject, null));
            }

            ParseObject(ref _root);
        }
Example #9
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();
        }
Example #10
0
 static Config()
 {
     EmptyValue = new HoconValue(null);
     EmptyValue.Add(new HoconObject(EmptyValue));
 }
Example #11
0
        /// <summary>
        /// Retrieves the next value token from the tokenizer and appends it
        /// to the supplied element <paramref name="owner"/>.
        /// </summary>
        /// <param name="owner">The element to append the next token.</param>
        /// <exception cref="System.Exception">End of file reached while trying to read a value</exception>
        private HoconValue ParseValue(IHoconElement owner)
        {
            var value   = new HoconValue(owner);
            var parsing = true;

            while (parsing)
            {
                switch (_tokens.Current.Type)
                {
                case TokenType.Include:
                    value.Add(ParseInclude(value));
                    break;

                case TokenType.LiteralValue:
                    // Consume leading whitespaces.
                    if (_tokens.Current.IsNonSignificant())
                    {
                        ConsumeWhitespace();
                    }
                    if (_tokens.Current.Type != TokenType.LiteralValue)
                    {
                        break;
                    }

                    while (_tokens.Current.Type == TokenType.LiteralValue)
                    {
                        value.Add(HoconLiteral.Create(value, _tokens.Current));
                        _tokens.Next();
                    }
                    break;

                case TokenType.StartOfObject:
                    value.Add(ParseObject(value));
                    break;

                case TokenType.StartOfArray:
                    value.Add(ParseArray(value));
                    break;

                case TokenType.SubstituteOptional:
                case TokenType.SubstituteRequired:
                    var pointerPath       = HoconPath.Parse(_tokens.Current.Value);
                    HoconSubstitution sub = new HoconSubstitution(value, pointerPath, _tokens.Current,
                                                                  _tokens.Current.Type == TokenType.SubstituteRequired);
                    _substitutions.Add(sub);
                    value.Add(sub);
                    _tokens.Next();
                    break;

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

                // comments automatically stop value parsing.
                case TokenType.Comment:
                    ConsumeWhitelines();
                    parsing = false;
                    break;

                case TokenType.EndOfLine:
                    parsing = false;
                    break;

                case TokenType.EndOfFile:
                case TokenType.Comma:
                    parsing = false;
                    break;

                case TokenType.PlusEqualAssign:
                    HoconSubstitution subAssign = new HoconSubstitution(value, new HoconPath(Path), _tokens.Current, false);
                    _substitutions.Add(subAssign);
                    value.Add(subAssign);

                    value.Add(ParsePlusEqualAssignArray(value));
                    parsing = false;
                    break;

                case TokenType.Assign:
                    ConsumeWhitelines();
                    break;

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

            // trim trailing whitespace if result is a literal
            if (value.Type == HoconType.Literal)
            {
                if (value[value.Count - 1] is HoconWhitespace)
                {
                    value.RemoveAt(value.Count - 1);
                }
            }
            return(value);
        }
Example #12
0
        private void ParseTokens()
        {
            if (_tokens.Current.IsNonSignificant())
            {
                ConsumeWhitelines();
            }

            while (_tokens.Current.Type != TokenType.EndOfFile)
            {
                switch (_tokens.Current.Type)
                {
                case TokenType.Include:
                    var parsedInclude = ParseInclude(null);
                    if (_root.Type != HoconType.Object)
                    {
                        _root.Clear();
                        _root.Add(parsedInclude.GetObject());
                    }
                    else
                    {
                        _root.Add(parsedInclude.GetObject());
                    }
                    break;

                // Hocon config file may contain one array and one array only
                case TokenType.StartOfArray:
                    _root.Clear();
                    _root.Add(ParseArray(null));
                    ConsumeWhitelines();
                    if (_tokens.Current.Type != TokenType.EndOfFile)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path, "Hocon config can only contain one array or one object.");
                    }
                    return;

                case TokenType.StartOfObject:
                {
                    var parsedObject = ParseObject(null);
                    if (_root.Type != HoconType.Object)
                    {
                        _root.Clear();
                        _root.Add(parsedObject);
                    }
                    else
                    {
                        _root.Add(parsedObject.GetObject());
                    }
                    break;
                }

                case TokenType.LiteralValue:
                {
                    if (_tokens.Current.IsNonSignificant())
                    {
                        ConsumeWhitelines();
                    }
                    if (_tokens.Current.Type != TokenType.LiteralValue)
                    {
                        break;
                    }

                    var parsedObject = ParseObject(null);
                    if (_root.Type != HoconType.Object)
                    {
                        _root.Clear();
                        _root.Add(parsedObject);
                    }
                    else
                    {
                        _root.Add(parsedObject.GetObject());
                    }
                    break;
                }

                case TokenType.Comment:
                case TokenType.EndOfLine:
                case TokenType.EndOfFile:
                case TokenType.EndOfObject:
                case TokenType.EndOfArray:
                    _tokens.Next();
                    break;

                default:
                    throw HoconParserException.Create(_tokens.Current, null, $"Illegal token type: {_tokens.Current.Type}", null);
                }
            }
        }