Esempio n. 1
0
        /// <summary>
        /// Processes the given instruction pattern <paramref name="token"/> and creates a meta information object.
        /// </summary>
        /// <param name="token">Token to process</param>
        /// <param name="instructionInfo">Instruction meta info to extend</param>
        /// <exception cref="InvalidInstructionTranslationPatternException">If the instruction pattern is invalid</exception>
        private void ProcessToken(string token, InstructionTranslationInfo instructionInfo)
        {
            if (string.IsNullOrEmpty(token))
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Token of directive pattern of instruction '{0}' is empty. ", instructionInfo.Instruction.GetType()));
            }

            char tokenHead = token[0];

            // Token is special char
            if (tokenHead == '<')
            {
                CreateSpecialCharacterToken(token, instructionInfo, "<", ">");
                return;
            }
            if (tokenHead == '[')
            {
                CreateSpecialCharacterToken(token, instructionInfo, "[", "]");
                return;
            }

            // Token is a parameter
            if (tokenHead == '{')
            {
                CreateParameterToken(token, instructionInfo);
                return;
            }

            throw new InvalidInstructionTranslationPatternException(string.Format("Token of instruction pattern '{0}' contains an unexpected character '{1}'", instructionInfo.Instruction.GetType(), tokenHead));
        }
Esempio n. 2
0
        /// <summary>
        /// Processes the given <paramref name="token"/> in the case of a special character token.
        /// </summary>
        /// <param name="token">Token to process</param>
        /// <param name="instructionInfo">Instruction info to extend</param>
        /// <param name="tokenHead">Token head</param>
        /// <param name="tokenTail">Token tail</param>
        private void CreateSpecialCharacterToken(string token, InstructionTranslationInfo instructionInfo, string tokenHead, string tokenTail)
        {
            if (!token.EndsWith(tokenTail))
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern token does not finish with '{1}'. Token is '{0}'", token, tokenTail));
            }

            string tokenCore = token.Substring(1, token.Length - 2);

            // Head
            instructionInfo.AddToken(new SpecialCharacterToken {
                Value = tokenHead
            });

            // Content
            ProcessToken(tokenCore, instructionInfo);

            // Tail
            instructionInfo.AddToken(new SpecialCharacterToken {
                Value = tokenTail
            });
        }
Esempio n. 3
0
        /// <summary>
        /// Processes and evaluates the given <paramref name="instruction"/> to create the instruction meta data.
        /// </summary>
        /// <param name="instruction">Instruction to process</param>
        /// <exception cref="InvalidInstructionTranslationPatternException">If the instruction pattern is invalid</exception>
        private void CreateMetaInfo(IBuddyTranslationInstruction instruction)
        {
            string directivePattern = instruction.InstructionPattern;

            if (string.IsNullOrEmpty(directivePattern))
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern of instruction '{0}' is NULL or empty", instruction.GetType()));
            }

            string[] directiveTokens = directivePattern.SplitToBuddyTokens();
            if (directiveTokens.Length == 0)
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern of instruction '{0}' has no tokens. Pattern is '{1}'", instruction.GetType(), directivePattern));
            }

            string leadingWord = directiveTokens[0];

            if (string.IsNullOrEmpty(leadingWord))
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern of instruction '{0}' has an empty leading word. Pattern is '{1}'", instruction.GetType(), directivePattern));
            }

            InstructionTranslationInfo instructionInfo = this;

            // Add leading word token
            instructionInfo.AddToken(new WordToken {
                Value = leadingWord
            });

            // Process remaining tokens
            for (int i = 0; ++i != directiveTokens.Length;)
            {
                string token = directiveTokens[i];
                ProcessToken(token, instructionInfo);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Processes the given <paramref name="token"/> in the case of a parameter token.
        /// </summary>
        /// <param name="token">Token to process</param>
        /// <param name="instructionInfo">Instruction info to extend</param>
        private void CreateParameterToken(string token, InstructionTranslationInfo instructionInfo)
        {
            if (!token.EndsWith("}"))
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern token does not finish with '}}'. Token is '{0}'", token));
            }

            string tokenCore = token.Substring(1, token.Length - 2);

            string[] parameterParts = tokenCore.Split(',');
            if (parameterParts.Length < 2)
            {
                throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern token does not match expected token structure. Token is '{0}'", token));
            }

            Dictionary <string, string> valueSet = new Dictionary <string, string>();

            for (int i = -1; ++i != parameterParts.Length;)
            {
                string   parameterPart = parameterParts[i];
                string[] keyValueSet   = parameterPart.Split(':');
                if (keyValueSet.Length != 2)
                {
                    throw new InvalidInstructionTranslationPatternException(string.Format("Directive pattern parameter token does not declare values in 'key:value' format!. Token is '{0}'", token));
                }
                string key   = keyValueSet[0];
                string value = keyValueSet[1];
                valueSet.Add(key, value);
            }

            IPatternParameter patternParameter = new PatternParameterFactory().CreatePatternParameter(valueSet);

            instructionInfo.AddToken(new ParameterToken {
                Value = patternParameter
            });
        }
        /// <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);
        }