/// <summary> /// Updates the state of the parser by processing the specified token. /// State is updated based on contents of token (e.g. verse change), but position /// is the beginning of token, not the end. /// </summary> /// <param name="tokens">list of all tokens being processed</param> /// <param name="index">index of the token to be processed</param> /// <param name="tokensPreserveWhitespace">True if the tokens were created while preserving whitespace, /// false otherwise</param> public void UpdateState(List <UsfmToken> tokens, int index, bool tokensPreserveWhitespace = false) { if (this.tokens != null && this.tokens != tokens) { parser = null; // Reset parser } this.tokens = tokens; this.preserveWhitespace = tokensPreserveWhitespace; // Create parser if not done already if (parser == null) { parser = new UsfmParser(ScrStylesheet, tokens, this, new ScrParserUsfmParserSink(this), tokensPreserveWhitespace); } // Check that token to process is next token if (index != parser.Index + 1) { throw new ArgumentException("Tokens must be processed sequentially"); } // Reset paraStart and cellStart ParaStart = false; CellStart = false; parser.ProcessToken(); }
private static void LookaheadParser(UsfmParserState state, UsfmParser lookaheadParser, string marker, out bool isTokenClosed) { // BEWARE: This method is fairly performance-critical // Determine current marker string endMarker = marker + "*"; // Process tokens until either the start of the stack doesn't match (it was closed // improperly) or a matching close marker is found while (lookaheadParser.ProcessToken()) { UsfmToken currentToken = lookaheadParser.tokens[lookaheadParser.index]; // Check if same marker was reopened without a close bool reopened = currentToken.Marker == marker && lookaheadParser.State.Stack.SequenceEqual(state.Stack); if (reopened) { isTokenClosed = false; return; } // Check if beginning of stack is unchanged. If token is unclosed, it will be unchanged bool markerStillOpen = lookaheadParser.State.Stack.Take(state.Stack.Count).SequenceEqual(state.Stack); if (!markerStillOpen) { // Record whether marker is an end for this marker isTokenClosed = currentToken.Marker == endMarker && currentToken.Type == UsfmTokenType.End; return; } } isTokenClosed = false; }
/// <summary> /// Determines if the current token is closed by a matching end marker /// </summary> /// <returns></returns> bool IsTokenClosed() { // Clone current parser if (tokenClosedParser == null) { tokenClosedParser = new UsfmParser(this); } tokenClosedParser.UpdateParser(this); bool isTokenClosed; string marker = tokens[index].Marker; LookaheadParser(State, tokenClosedParser, marker, out isTokenClosed); return(isTokenClosed); }
private bool CheckInternal(List <UsfmToken> tokens, int bookNum, ScrStylesheet scrStylesheet) { VerseRef startVerse = new VerseRef(bookNum, 1, 0, ScrVers.English); if (tokens.Count > 0 && tokens[0].Marker != "id") { RecordError(startVerse, "", 0, "#" + missingIdMarker); } MarkerCheckSink markerCheckSink = new MarkerCheckSink(scrStylesheet, startVerse.Book, this); UsfmParser parser = new UsfmParser(scrStylesheet, tokens, startVerse, markerCheckSink); parser.ProcessTokens(); markerCheckSink.ReportPendingVerseNoParaError(); markerCheckSink.ReportOpenMilestoneErrors(); return(markerErrors || markerCheckSink.MarkerErrors); }
/// <summary> /// Updates the state of this parser to be the same as the state of the specified parser. /// </summary> internal void UpdateParser(UsfmParser usfmParser) { state = usfmParser.State.Clone(); index = usfmParser.index; skip = 0; }
/// <summary> /// Constructor for making a duplicate for looking ahead to find closing /// tokens of notes and character styles. /// </summary> UsfmParser(UsfmParser usfmParser, UsfmParserSink sink = null) { scrStylesheet = usfmParser.scrStylesheet; tokens = usfmParser.tokens; this.sink = sink; }