Пример #1
0
        private HoconValue ParseInclude()
        {
            // Sanity check
            if (_tokens.Current.Type != TokenType.Include)
            {
                throw HoconParserException.Create(_tokens.Current, Path,
                                                  $"Internal parser error, ParseInclude() is called on an invalid token: `{_tokens.Current.Type}`");
            }

            var    parenthesisCount = 0;
            var    required         = false;
            var    callbackType     = HoconCallbackType.File;
            string fileName         = null;
            var    includeToken     = _tokens.Current;

            var expectedTokens = new List <TokenType>(new[]
            {
                TokenType.Required,
                TokenType.Url,
                TokenType.File,
                TokenType.Classpath,
                TokenType.LiteralValue,
                TokenType.ParenthesisEnd,
                TokenType.EndOfLine
            });

            var parsing = true;

            while (parsing)
            {
                _tokens.ToNextSignificant();
                var currentType = _tokens.Current.Type;
                if (expectedTokens.All(t => t != currentType))
                {
                    throw HoconParserException.Create(_tokens.Current, Path,
                                                      $"Invalid token in include: `{currentType}`", null);
                }

                switch (currentType)
                {
                case TokenType.ParenthesisEnd:
                    if (parenthesisCount <= 0)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          "Unexpected closing parenthesis.", null);
                    }

                    parenthesisCount--;
                    parsing = parenthesisCount > 0;
                    break;

                case TokenType.Required:
                    _tokens.ToNextSignificant();
                    // The next token after the "required" keyword have to be an open paren
                    if (_tokens.Current.Type != TokenType.ParenthesisStart)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Expected {TokenType.ParenthesisStart}, found `{_tokens.Current.Type}` instead.");
                    }

                    parenthesisCount++;
                    required = true;
                    expectedTokens.Remove(TokenType.Required);
                    break;

                case TokenType.Url:
                    _tokens.ToNextSignificant();
                    // The next token after the "url" keyword have to be an open paren
                    if (_tokens.Current.Type != TokenType.ParenthesisStart)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Expected {TokenType.ParenthesisStart}, found `{_tokens.Current.Type}` instead.");
                    }

                    parenthesisCount++;
                    callbackType = HoconCallbackType.Url;
                    expectedTokens.Remove(TokenType.Required);
                    expectedTokens.Remove(TokenType.Url);
                    expectedTokens.Remove(TokenType.File);
                    expectedTokens.Remove(TokenType.Classpath);
                    break;

                case TokenType.File:
                    _tokens.ToNextSignificant();
                    // The next token after the "file" keyword have to be an open paren
                    if (_tokens.Current.Type != TokenType.ParenthesisStart)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Expected {TokenType.ParenthesisStart}, found `{_tokens.Current.Type}` instead.");
                    }

                    parenthesisCount++;
                    callbackType = HoconCallbackType.File;
                    expectedTokens.Remove(TokenType.Required);
                    expectedTokens.Remove(TokenType.Url);
                    expectedTokens.Remove(TokenType.File);
                    expectedTokens.Remove(TokenType.Classpath);
                    break;

                case TokenType.Classpath:
                    _tokens.ToNextSignificant();
                    // The next token after the "classpath" keyword have to be an open paren
                    if (_tokens.Current.Type != TokenType.ParenthesisStart)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Expected {TokenType.ParenthesisStart}, found `{_tokens.Current.Type}` instead.");
                    }

                    parenthesisCount++;
                    callbackType = HoconCallbackType.Resource;
                    expectedTokens.Remove(TokenType.Required);
                    expectedTokens.Remove(TokenType.Url);
                    expectedTokens.Remove(TokenType.File);
                    expectedTokens.Remove(TokenType.Classpath);
                    break;

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

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

                    if (_tokens.Current.LiteralType != TokenLiteralType.QuotedLiteralValue)
                    {
                        throw HoconParserException.Create(_tokens.Current, Path,
                                                          $"Invalid literal type for declaring file name. Expected {TokenLiteralType.QuotedLiteralValue}, " +
                                                          $"found `{_tokens.Current.LiteralType}` instead.");
                    }

                    fileName = _tokens.Current.Value;
                    expectedTokens.Remove(TokenType.LiteralValue);
                    expectedTokens.Remove(TokenType.Required);
                    expectedTokens.Remove(TokenType.Url);
                    expectedTokens.Remove(TokenType.File);
                    expectedTokens.Remove(TokenType.Classpath);

                    parsing = parenthesisCount > 0;
                    break;

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

            if (parenthesisCount > 0)
            {
                throw HoconParserException.Create(_tokens.Current, Path,
                                                  $"Expected {TokenType.ParenthesisEnd}, found `{_tokens.Current.Type}`");
            }

            if (fileName == null)
            {
                throw HoconParserException.Create(_tokens.Current, Path,
                                                  "Include does not contain any quoted file name value.");
            }

            // Consume the last token
            _tokens.ToNextSignificant();

            var includeHocon = _includeCallback(callbackType, fileName).ConfigureAwait(false).GetAwaiter().GetResult();

            if (string.IsNullOrWhiteSpace(includeHocon))
            {
                if (required)
                {
                    throw HoconParserException.Create(includeToken, Path,
                                                      "Invalid Hocon include. Include was declared as required but include callback returned a null or empty string.");
                }
                return(new HoconEmptyValue(null));
            }

            var includeRoot = new HoconParser().ParseText(includeHocon, false, _includeCallback);

            /*
             * if (owner != null && owner.Type != HoconType.Empty && owner.Type != includeRoot.Value.Type)
             *  throw HoconParserException.Create(includeToken, Path,
             *      "Invalid Hocon include. Hocon config substitution type must be the same as the field it's merged into. " +
             *      $"Expected type: `{owner.Type}`, type returned by include callback: `{includeRoot.Value.Type}`");
             */

            // fixup the substitution, add the current path as a prefix to the substitution path
            foreach (var substitution in includeRoot.Substitutions)
            {
                substitution.Path.InsertRange(0, Path);
            }
            _substitutions.AddRange(includeRoot.Substitutions);

            // re-parent the value returned by the callback to the owner of the include declaration
            return(includeRoot.Value);
        }
Пример #2
0
        /// <summary>
        ///     Generates a configuration defined in the supplied
        ///     HOCON (Human-Optimized Config Object Notation) string.
        /// </summary>
        /// <param name="hocon">A string that contains configuration options to use.</param>
        /// <param name="includeCallback">callback used to resolve includes</param>
        /// <returns>The configuration defined in the supplied HOCON string.</returns>
        public static Config ParseString(string hocon, HoconIncludeCallbackAsync includeCallback)
        {
            HoconRoot res = HoconParser.Parse(hocon, includeCallback);

            return(new Config(res));
        }