/// <summary> /// Adds the given <paramref name="token"/> to pattern token sequence. /// </summary> /// <param name="token">Token to add</param> private void AddToken(IInstructionPatternToken token) { iInstructionTokens.Add(token); }
/// <summary> /// Evaluates the given <paramref name="instruction"/> using the given <paramref name="instructionInfo"/>. Any resolved parameter is added /// to <paramref name="paramCache"/>. /// </summary> /// <param name="instruction">Directive to evaluate</param> /// <param name="instructionInfo">Instruction that provides the meta data</param> /// <param name="paramCache">Parameter cache</param> /// <returns>Evaluation result</returns> public IInstructionEvaluationResult Evaluate(string instruction, InstructionTranslationInfo instructionInfo, IDictionary <string, IPatternParameter> paramCache) { if (string.IsNullOrEmpty(instruction)) { throw new ArgumentNullException(nameof(instruction)); } if (instructionInfo == null) { throw new ArgumentNullException(nameof(instructionInfo)); } string wordSequence = instruction; // Remove dot if (wordSequence.EndsWith(".")) { wordSequence = wordSequence.Substring(0, wordSequence.Length - 1); } // Value sequence recognition string valueSequenceString = null; wordSequence = Regex.Replace(wordSequence, @"(?<top>""[^""]+"")(?<nav>\s(?<child>""[^""]+""))*\s(?<value>""[^""]+"")", match => { string prime = match.Groups["top"].Value; string sslValue = string.Join(", ", match.Groups["child"].Captures.ToArray()); string value = match.Groups["value"].Value; string[] joinSet = string.IsNullOrEmpty(sslValue) ? new[] { prime, value } : new[] { prime, sslValue, value }; valueSequenceString = string.Join(", ", joinSet); return(ValueSequenceToken); }); // Split to words string[] words = wordSequence.SplitToBuddyTokens(); if (words.Length == 0) { return(EvaluationResult.Error(wordSequence, instructionInfo.Instruction, "Instruction is empty after split")); } words = words.StripSpecialCharacters(); if (words.Length == 0) { return(EvaluationResult.Error(wordSequence, instructionInfo.Instruction, "Instruction is empty after strip")); } // Normalize variants if (instructionInfo.Instruction is IVariantInstruction variantInstruction) { words = variantInstruction.Normalize(words); } // Iterate words and check for match int wordIndex = 0; for (IEnumerator <IInstructionPatternToken> tokenItr = instructionInfo.GetInstructionPatternTokenEnumerator(); tokenItr.MoveNext();) { IInstructionPatternToken token = tokenItr.Current; if (token == null) { throw new InvalidOperationException("Token iterator provided NULL token"); } string word; // Take the word from the sequence if (wordIndex < words.Length) { word = words[wordIndex]; } else // We have more tokens than words // All remaining tokens must be not mandatory or we have an error // So they must handle an unset value { word = PatternParameter.Unset; } // If we have a match, everything is fine if (token.DoesMatch(word)) { wordIndex++; // Resolve parametrized tokens if (token is IParametrizedInstructionPatternToken parametrizedToken) { IPatternParameter patternParameter = parametrizedToken.Value; string parameterName = patternParameter.Name; // If the value has been replaced by a ValueSequenceToken before, we have to re-replace it now if (valueSequenceString != null) // Something must have been replaced { if (patternParameter.Value.Value.Equals(ValueSequenceToken)) // Is this the correct parameter? { ((AbstractPatternParameter)patternParameter).SetValue(valueSequenceString); } } // Add value to cache paramCache.Add(parameterName, patternParameter); } continue; } // If the token is not mandatory, we can go forward if (!token.IsMandatory) { continue; } return(EvaluationResult.Error( wordSequence, instructionInfo.Instruction, $"{FormatWordIndex(wordIndex)} word of instruction " + $"does not match expected token '{token.ToHumanReadableString()}'. " + $"Word is '{word}'" )); } return(EvaluationResult.Ok); }