/// <summary>Extract a token from the front of a lexical input queue.</summary> /// <param name="input">The input from which to extract a token. The extracted lexical bits will be removed from the queue.</param> /// <param name="impliedBraces">Whether we're parsing a token context (so the outer '{{' and '}}' are implied); else parse as a tokenizable string which main contain a mix of literal and {{token}} values.</param> /// <returns>Returns the token.</returns> public LexTokenToken ExtractToken(Queue <LexBit> input, bool impliedBraces) { LexBit GetNextAndAssert(string expectedPhrase) { if (!input.Any()) { throw new LexFormatException($"Reached end of input, expected {expectedPhrase}."); } return(input.Dequeue()); } // start token if (!impliedBraces) { LexBit startToken = GetNextAndAssert("start of token ('{{')"); if (startToken.Type != LexBitType.StartToken) { throw new LexFormatException($"Unexpected {startToken.Type} at start of token."); } } // extract token name LexBit name = GetNextAndAssert("token name"); if (name.Type != LexBitType.Literal) { throw new LexFormatException($"Unexpected {name.Type} where token name should be."); } // extract input arguments if present // Note: the positional input argument separator (:) is the 'real' separator between // the token name and input arguments, but a token can skip positional arguments and // start named arguments directly like {{TokenName |key=value}}. In that case the ':' // is implied, and the '|' separator *is* included in the input arguments string. LexTokenInput inputArgs = null; if (input.Any()) { var next = input.Peek().Type; if (next == LexBitType.PositionalInputArgSeparator || next == LexBitType.NamedInputArgSeparator) { if (next == LexBitType.PositionalInputArgSeparator) { input.Dequeue(); } inputArgs = this.ExtractInputArguments(input); } } // end token if (!impliedBraces) { LexBit endToken = GetNextAndAssert("end of token ('}}')"); if (endToken.Type != LexBitType.EndToken) { throw new LexFormatException($"Unexpected {endToken.Type} before end of token."); } } return(new LexTokenToken(name.Text.Trim(), inputArgs, impliedBraces)); }
/// <summary>Construct an instance.</summary> /// <param name="inputArgs">The raw token input arguments.</param> /// <param name="context">The available token context.</param> /// <param name="path">The path to the value from the root content file.</param> public TokenString(LexTokenInput inputArgs, IContext context, LogPathBuilder path) : this(lexTokens : inputArgs?.Parts, context : context, path : path) { }