/// <summary> /// Tokenizes a block of whitespace. /// </summary> /// <returns>The state result.</returns> private StateResult WhiteSpace() { TakeUntil(c => !ParserHelpers.IsWhiteSpace(c) && !ParserHelpers.IsNewLine(c)); if (HaveContent) { return(Transition(EndSymbol(HandlebarsSymbolType.WhiteSpace), Data)); } return(Transition(Data)); }
/// <summary> /// Represents the default state of the tokenizer. /// </summary> /// <returns>The state result.</returns> private StateResult Data() { if (EndOfFile) { if (HaveContent) { return(Transition(EndSymbol(HandlebarsSymbolType.Text), Stop)); } return(Stop()); } if (ParserHelpers.IsWhiteSpace(CurrentCharacter) || ParserHelpers.IsNewLine(CurrentCharacter)) { if (HaveContent) { return(Transition(EndSymbol(HandlebarsSymbolType.Text), WhiteSpace)); } return(Transition(WhiteSpace)); } TakeUntil(c => c == '{' || ParserHelpers.IsWhiteSpace(c)); if (ParserHelpers.IsWhiteSpace(CurrentCharacter)) { return(Stay()); } if (HaveContent && CurrentCharacter == '{') { if (Buffer[Buffer.Length - 1] == '\\') { // The { character is being escaped, so move on. TakeCurrent(); return(Stay()); } if (Peek() == '{') { // We're at the start of a tag. return(Transition(EndSymbol(HandlebarsSymbolType.Text), BeginTag)); } } if (Peek() == '{') { // We're at the start of a tag. return(Transition(BeginTag)); } TakeCurrent(); return(Stay()); }
/// <summary> /// Continues the content of the tag. /// </summary> /// <param name="raw">True if we are expected a raw tag.</param> /// <returns>The state result.</returns> private StateResult ContinueTagContent(bool raw) { if (CurrentCharacter == '@') { TakeCurrent(); return(Stay(EndSymbol(HandlebarsSymbolType.At))); } if (HandlebarsHelpers.IsIdentifierStart(CurrentCharacter)) { return(Identifier()); } if (Char.IsDigit(CurrentCharacter)) { return(NumericLiteral()); } switch (CurrentCharacter) { case '.': { TakeCurrent(); if (CurrentCharacter == '/') { // We've matched a link to the current context. TakeCurrent(); return(Stay(EndSymbol(HandlebarsSymbolType.CurrentContext))); } if (CurrentCharacter == '.' && Peek() == '/') { // We've matched a link to the parent context. TakeCurrent(); TakeCurrent(); return(Stay(EndSymbol(HandlebarsSymbolType.ParentContext))); } // We've matched a dot, which could be part of an expression. return(Stay(EndSymbol(HandlebarsSymbolType.Dot))); } case '/': { TakeCurrent(); // We've matched a forward-slash, which could be part of an expression. return(Stay(EndSymbol(HandlebarsSymbolType.Slash))); } case ' ': { // Take all the available whitespace. TakeUntil(c => !ParserHelpers.IsWhiteSpace(c)); return(Stay(EndSymbol(HandlebarsSymbolType.WhiteSpace))); } case '~': { TakeCurrent(); // We've reached a '~' character, so jump to the end of the tag. return(Transition(EndSymbol(HandlebarsSymbolType.Tilde), () => EndTag(raw))); } case '"': case '\'': { var quote = CurrentCharacter; TakeCurrent(); // We've reached a quoted literal. return(QuotedLiteral(quote)); } case '=': { // We're reached a map assignment. TakeCurrent(); return(Stay(EndSymbol(HandlebarsSymbolType.Assign))); } case '}': { // We've reached a closing tag, so transition away. return(Transition(() => EndTag(raw))); } default: { CurrentErrors.Add(new Error("Unexpected character: " + CurrentCharacter, CurrentLocation)); return(Transition(Stop)); } } }
/// <summary> /// Returns a predicate that determines if the given character is a character or whitespace (including new lines). /// </summary> /// <param name="character">The character.</param> /// <returns></returns> protected Func <char, bool> CharOrWhiteSpace(char character) { return(c => c == character || ParserHelpers.IsWhiteSpace(character) || ParserHelpers.IsNewLine(character)); }