public int HandleMatch(IProcessorState processor, int bufferLength, ref int currentBufferPosition, int token, Stream target) { bool flag; if (processor.Config.Flags.TryGetValue(OperationName, out flag) && !flag) { target.Write(Tokens[token].Value, Tokens[token].Start, Tokens[token].Length); return(Tokens[token].Length); } // conditional has not started, or this is the "if" if (_current != null || IsTokenIndexOfType(token, IfTokenBaseIndex) || IsTokenIndexOfType(token, IfTokenActionableBaseIndex)) { if (_definition._wholeLine) { processor.SeekBackUntil(processor.EncodingConfig.LineEndings); } else if (_definition._trimWhitespace) { processor.TrimWhitespace(false, true, ref bufferLength, ref currentBufferPosition); } } BEGIN: //Got the "if" token... if (IsTokenIndexOfType(token, IfTokenBaseIndex) || IsTokenIndexOfType(token, IfTokenActionableBaseIndex)) { if (_current == null) { _current = new EvaluationState(this); } else { _pendingCompletion.Push(_current); _current = new EvaluationState(this); } //If the "if" branch is taken, all else and elseif blocks will be omitted, return // control to the processor so nested "if"s/mutations can be processed. Note that // this block will not be terminated until the corresponding endif is found if (_current.Evaluate(processor, ref bufferLength, ref currentBufferPosition)) { if (_definition.WholeLine) { processor.SeekForwardThrough(processor.EncodingConfig.LineEndings, ref bufferLength, ref currentBufferPosition); } if (IsTokenIndexOfType(token, IfTokenActionableBaseIndex)) { // "Actionable" if token, so enable the flag operation(s) _current.ToggleActionableOperations(true, processor); } // if (true_condition) was found. return(0); } else { // if (false_condition) was found. Skip to the next token of the if-elseif-elseif-...elseif-else-endif SeekToNextTokenAtSameLevel(processor, ref bufferLength, ref currentBufferPosition, out token); goto BEGIN; } } // If we've got an unbalanced statement, emit the token if (_current == null) { target.Write(Tokens[token].Value, Tokens[token].Start, Tokens[token].Length); return(Tokens[token].Length); } //Got the endif token, exit to the parent "if" scope if it exists if (IsTokenIndexOfType(token, EndTokenBaseIndex)) { if (_pendingCompletion.Count > 0) { _current = _pendingCompletion.Pop(); _current.ToggleActionableOperations(_current.ActionableOperationsEnabled, processor); } else { // disable the special case operations (note: they may already be disabled, but cheaper to do than check) _current.ToggleActionableOperations(false, processor); _current = null; } if (_definition._wholeLine) { processor.SeekForwardThrough(processor.EncodingConfig.LineEndings, ref bufferLength, ref currentBufferPosition); } else if (_definition._trimWhitespace) { processor.TrimWhitespace(true, false, ref bufferLength, ref currentBufferPosition); } return(0); } if (_current.BranchTaken) { processor.SeekBackUntil(processor.EncodingConfig.LineEndings, true); //A previous branch was taken. Skip to the endif token. // NOTE: this can probably use the new method SeekToNextTokenAtSameLevel() - they do almost the same thing. SkipToMatchingEndif(processor, ref bufferLength, ref currentBufferPosition, ref token); if (_pendingCompletion.Count > 0) { _current = _pendingCompletion.Pop(); _current.ToggleActionableOperations(_current.ActionableOperationsEnabled, processor); } else { // disable the special case operation (note: it may already be disabled, but cheaper to do than check) _current.ToggleActionableOperations(false, processor); _current = null; } if (_definition._wholeLine) { processor.SeekForwardUntil(processor.EncodingConfig.LineEndings, ref bufferLength, ref currentBufferPosition); } else if (_definition._trimWhitespace) { processor.TrimWhitespace(true, false, ref bufferLength, ref currentBufferPosition); } return(0); } //We have an "elseif" and haven't taken a previous branch if (IsTokenIndexOfType(token, ElseIfTokenBaseIndex) || IsTokenIndexOfType(token, ElseIfTokenActionableBaseIndex)) { // 8-19 attempt to make the same as if() handling // if (_current.Evaluate(processor, ref bufferLength, ref currentBufferPosition)) { if (_definition.WholeLine) { processor.SeekForwardThrough(processor.EncodingConfig.LineEndings, ref bufferLength, ref currentBufferPosition); } if (IsTokenIndexOfType(token, ElseIfTokenActionableBaseIndex)) { // the elseif branch is taken. _current.ToggleActionableOperations(true, processor); } return(0); } else { SeekToNextTokenAtSameLevel(processor, ref bufferLength, ref currentBufferPosition, out token); // In the original version this was conditional on SeekToToken() succeeding. // Not sure if it should be conditional. It should never fail, unless the template is malformed. goto BEGIN; } } //We have an "else" token and haven't taken any other branches, return control // after setting that a branch has been taken if (IsTokenIndexOfType(token, ElseTokenBaseIndex) || IsTokenIndexOfType(token, ElseTokenActionableBaseIndex)) { if (IsTokenIndexOfType(token, ElseTokenActionableBaseIndex)) { _current.ToggleActionableOperations(true, processor); } _current.BranchTaken = true; processor.WhitespaceHandler(ref bufferLength, ref currentBufferPosition, wholeLine: _definition._wholeLine, trim: _definition._trimWhitespace); return(0); } else { Debug.Assert(true, "Unknown token index: " + token); return(0); // TODO: revisit. Not sure what's best here. } }