IsTokenValid( string token, MacroList customMacros) { // step 1 : is the token positional, i.e. was set up at creation time var positional = GetMatches(token, PositionalTokenRegExPattern).FirstOrDefault(); if (!System.String.IsNullOrEmpty(positional)) { var positionalIndex = System.Convert.ToInt32(positional); return(positionalIndex <= this.PositionalTokens.Count); } // step 2 : try to resolve with custom macros passed to the Parse function else if (null != customMacros && customMacros.Dict.ContainsKey(token)) { return(true); } // step 3 : try macros in the global Graph, common to all modules else if (Graph.Instance.Macros.Dict.ContainsKey(token)) { return(true); } else if (this.ModuleWithMacros != null) { var tool = this.ModuleWithMacros.Tool; // step 4 : try macros in the specific module if (this.ModuleWithMacros.Macros.Dict.ContainsKey(token)) { return(true); } // step 5 : try macros in the Tool attached to the specific module else if (null != tool && tool.Macros.Dict.ContainsKey(token)) { return(true); } } // step 6 : try the immediate environment var strippedToken = SplitIntoTokens(token, ExtractTokenRegExPattern).First(); var envVar = System.Environment.GetEnvironmentVariable(strippedToken); if (null != envVar) { return(true); } // step 7 : fail else { return(false); } }
/// <summary> /// Parse, and if the parsed string contains a space, surround with quotes. /// </summary> /// <returns>The and quote if necessary.</returns> /// <param name="customMacros">Custom macros.</param> public string ParseAndQuoteIfNecessary( MacroList customMacros = null) { if (this.IsAliased) { return(this.Alias.ParseAndQuoteIfNecessary(customMacros)); } var parsed = this.Parse(customMacros); if (!this.ContainsSpace) { return(parsed); } return(System.String.Format("\"{0}\"", parsed)); }
EvaluatePreFunctions( string originalExpression, MacroList customMacros) { System.Text.RegularExpressions.MatchCollection matches = null; try { matches = System.Text.RegularExpressions.Regex.Matches( originalExpression, PreFunctionRegExPattern, System.Text.RegularExpressions.RegexOptions.None, RegExTimeout); if (0 == matches.Count) { if (originalExpression.Contains("#")) { throw new Exception("Expression '{0}' did not match for pre-functions, but does contain # - are there mismatching brackets?. Tokenized string '{1}' created at{2}{3}", originalExpression, this.OriginalString, System.Environment.NewLine, this.CreationStackTrace); } return originalExpression; } } catch (System.Text.RegularExpressions.RegexMatchTimeoutException) { var message = new System.Text.StringBuilder(); message.AppendFormat("TokenizedString pre-function regular expression matching timed out after {0} seconds. Check details below for errors.", RegExTimeout.Seconds); message.AppendLine(); message.AppendFormat("String being parsed: {0}", originalExpression); message.AppendLine(); message.AppendFormat("Regex : {0}", PreFunctionRegExPattern); message.AppendLine(); message.AppendFormat("Tokenized string {0} created at", this.OriginalString); message.AppendLine(); message.AppendLine(this.CreationStackTrace); throw new Exception(message.ToString()); } var modifiedString = originalExpression; foreach (System.Text.RegularExpressions.Match match in matches) { var functionName = match.Groups["func"].Value; // this correctly obtains the expression when nested functions are present var expressionText = new System.Text.StringBuilder(); foreach (System.Text.RegularExpressions.Capture capture in match.Groups["expression"].Captures) { expressionText.Append(capture.Value); } var expression = this.EvaluatePreFunctions(expressionText.ToString(), customMacros); switch (functionName) { case "valid": { var tokens = SplitIntoTokens(expression, TokenRegExPattern); var allTokensValid = true; foreach (var token in tokens) { if (!(token.StartsWith(TokenPrefix) && token.EndsWith(TokenSuffix))) { continue; } // Note: with nested valid pre-functions, macros can be validated as many times as they are nested if (this.IsTokenValid(token, customMacros)) { continue; } allTokensValid = false; break; } if (allTokensValid) { modifiedString = modifiedString.Replace(match.Value, expression); } else { modifiedString = modifiedString.Replace(match.Value, string.Empty); } } break; default: throw new Exception("Unknown pre-function '{0}' in TokenizedString '{1}'", functionName, this.OriginalString); } } return modifiedString; }
IsTokenValid( string token, MacroList customMacros) { // step 1 : is the token positional, i.e. was set up at creation time var positional = GetMatches(token, PositionalTokenRegExPattern).FirstOrDefault(); if (!System.String.IsNullOrEmpty(positional)) { var positionalIndex = System.Convert.ToInt32(positional); return (positionalIndex <= this.PositionalTokens.Count); } // step 2 : try to resolve with custom macros passed to the Parse function else if (null != customMacros && customMacros.Dict.ContainsKey(token)) { return true; } // step 3 : try macros in the global Graph, common to all modules else if (Graph.Instance.Macros.Dict.ContainsKey(token)) { return true; } else if (this.ModuleWithMacros != null) { var tool = this.ModuleWithMacros.Tool; // step 4 : try macros in the specific module if (this.ModuleWithMacros.Macros.Dict.ContainsKey(token)) { return true; } // step 5 : try macros in the Tool attached to the specific module else if (null != tool && tool.Macros.Dict.ContainsKey(token)) { return true; } } // step 6 : try the immediate environment var strippedToken = SplitIntoTokens(token, ExtractTokenRegExPattern).First(); var envVar = System.Environment.GetEnvironmentVariable(strippedToken); if (null != envVar) { return true; } // step 7 : fail else { return false; } }
/// <summary> /// Parse, and if the parsed string contains a space, surround with quotes. /// </summary> /// <returns>The and quote if necessary.</returns> /// <param name="customMacros">Custom macros.</param> public string ParseAndQuoteIfNecessary( MacroList customMacros = null) { if (this.IsAliased) { return this.Alias.ParseAndQuoteIfNecessary(customMacros); } var parsed = this.Parse(customMacros); if (!this.ContainsSpace) { return parsed; } return System.String.Format("\"{0}\"", parsed); }
Parse( MacroList customMacros) { if (this.IsInline) { throw new Exception("Inline TokenizedString cannot be parsed, {0}", this.OriginalString); } if (this.IsAliased) { return this.Alias.Parse(customMacros); } if (this.IsExpanded && (null == customMacros)) { return this.ParsedString; } this.Tokens = SplitIntoTokens(this.EvaluatePreFunctions(this.OriginalString, customMacros), TokenRegExPattern).ToList<string>(); System.Func<TokenizedString, TokenizedString, int, string> expandTokenizedString = (source, tokenString, currentIndex) => { if (!tokenString.IsExpanded) { if (source == tokenString) { throw new Exception("Infinite recursion for {0}. Created at {3}", source.OriginalString, source.CreationStackTrace); } if (tokenString.IsInline) { // current token expands to nothing, and the inline string's tokens are processed next source.Tokens.InsertRange(currentIndex + 1, SplitIntoTokens(tokenString.EvaluatePreFunctions(tokenString.OriginalString, source.ModuleWithMacros.Macros), TokenRegExPattern).ToList<string>()); return string.Empty; } // recursive tokenString.Parse(null); } return tokenString.ToString(); }; var graph = Graph.Instance; var parsedString = new System.Text.StringBuilder(); for (int index = 0; index < this.Tokens.Count; ++index) { var token = this.Tokens[index]; if (!(token.StartsWith(TokenPrefix) && token.EndsWith(TokenSuffix))) { parsedString.Append(token); continue; } // step 1 : is the token positional, i.e. was set up at creation time var positional = GetMatches(token, PositionalTokenRegExPattern).FirstOrDefault(); if (!System.String.IsNullOrEmpty(positional)) { var positionalIndex = System.Convert.ToInt32(positional); if (positionalIndex > this.PositionalTokens.Count) { throw new Exception("TokenizedString positional token at index {0} requested, but only {1} positional values given. Created at {2}.", positionalIndex, this.PositionalTokens.Count, this.CreationStackTrace); } parsedString.Append(expandTokenizedString(this, this.PositionalTokens[positionalIndex], index)); continue; } // step 2 : try to resolve with custom macros passed to the Parse function else if (null != customMacros && customMacros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, customMacros.Dict[token], index)); continue; } // step 3 : try macros in the global Graph, common to all modules else if (graph.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, graph.Macros.Dict[token], index)); continue; } else if (this.ModuleWithMacros != null) { var tool = this.ModuleWithMacros.Tool; // step 4 : try macros in the specific module if (this.ModuleWithMacros.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, this.ModuleWithMacros.Macros.Dict[token], index)); continue; } // step 5 : try macros in the Tool attached to the specific module else if (null != tool && tool.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, tool.Macros.Dict[token], index)); continue; } } // step 6 : try the immediate environment var strippedToken = SplitIntoTokens(token, ExtractTokenRegExPattern).First(); var envVar = System.Environment.GetEnvironmentVariable(strippedToken); if (null != envVar) { parsedString.Append(envVar); continue; } // step 7 : fail else { // TODO: this could be due to the user not having set a property, e.g. inputpath // is there a better error message that could be returned, other than this in those // circumstances? var message = new System.Text.StringBuilder(); message.AppendFormat("Unrecognized token '{0}' from original string '{1}'", token, this.OriginalString); message.AppendLine(); if (null != customMacros) { message.AppendLine("Searched in custom macros"); } message.AppendLine("Searched in global macros"); if (null != this.ModuleWithMacros) { message.AppendFormat("Searched in module {0}", this.ModuleWithMacros.ToString()); message.AppendLine(); if (null != this.ModuleWithMacros.Tool) { message.AppendFormat("Searched in tool {0}", this.ModuleWithMacros.Tool.ToString()); message.AppendLine(); } } message.AppendLine("TokenizedString created with this stack trace:"); message.AppendLine(this.CreationStackTrace); throw new Exception(message.ToString()); } } var functionEvaluated = this.EvaluatePostFunctions(NormalizeDirectorySeparators(parsedString.ToString())); if (null == customMacros) { this.ParsedString = functionEvaluated; Log.DebugMessage("Converted '{0}' to '{1}'", this.OriginalString, this.ToString()); } return functionEvaluated; }
EvaluatePreFunctions( string originalExpression, MacroList customMacros) { System.Text.RegularExpressions.MatchCollection matches = null; try { matches = System.Text.RegularExpressions.Regex.Matches( originalExpression, PreFunctionRegExPattern, System.Text.RegularExpressions.RegexOptions.None, RegExTimeout); if (0 == matches.Count) { return(originalExpression); } } catch (System.Text.RegularExpressions.RegexMatchTimeoutException) { var message = new System.Text.StringBuilder(); message.AppendFormat("TokenizedString pre-function regular expression matching timed out after {0} seconds. Check details below for errors.", RegExTimeout.Seconds); message.AppendLine(); message.AppendFormat("String being parsed: {0}", originalExpression); message.AppendLine(); message.AppendFormat("Regex : {0}", PreFunctionRegExPattern); message.AppendLine(); message.AppendFormat("Tokenized string {0} created at", this.OriginalString); message.AppendLine(); message.AppendLine(this.CreationStackTrace); throw new Exception(message.ToString()); } var modifiedString = originalExpression; foreach (System.Text.RegularExpressions.Match match in matches) { var functionName = match.Groups["func"].Value; // this correctly obtains the expression when nested functions are present var expressionText = new System.Text.StringBuilder(); foreach (System.Text.RegularExpressions.Capture capture in match.Groups["expression"].Captures) { expressionText.Append(capture.Value); } var expression = this.EvaluatePreFunctions(expressionText.ToString(), customMacros); switch (functionName) { case "valid": { var split = expression.Split(','); var replacement = (1 == split.Length) ? string.Empty : split[1]; var tokens = SplitIntoTokens(split[0], TokenRegExPattern); var allTokensValid = true; foreach (var token in tokens) { if (!(token.StartsWith(TokenPrefix) && token.EndsWith(TokenSuffix))) { continue; } // Note: with nested valid pre-functions, macros can be validated as many times as they are nested if (this.IsTokenValid(token, customMacros)) { continue; } allTokensValid = false; break; } if (allTokensValid) { modifiedString = modifiedString.Replace(match.Value, split[0]); } else { modifiedString = modifiedString.Replace(match.Value, replacement); } } break; default: throw new Exception("Unknown pre-function '{0}' in TokenizedString '{1}'", functionName, this.OriginalString); } } return(modifiedString); }
Parse( MacroList customMacros) { if (this.IsInline) { throw new Exception("Inline TokenizedString cannot be parsed, {0}", this.OriginalString); } if (this.IsAliased) { return(this.Alias.Parse(customMacros)); } if (this.IsExpanded && (null == customMacros)) { return(this.ParsedString); } this.Tokens = SplitIntoTokens(this.EvaluatePreFunctions(this.OriginalString, customMacros), TokenRegExPattern).ToList <string>(); System.Func <TokenizedString, TokenizedString, int, string> expandTokenizedString = (source, tokenString, currentIndex) => { if (!tokenString.IsExpanded) { if (source == tokenString) { throw new Exception("Infinite recursion for {0}. Created at {3}", source.OriginalString, source.CreationStackTrace); } if (tokenString.IsInline) { // current token expands to nothing, and the inline string's tokens are processed next source.Tokens.InsertRange(currentIndex + 1, SplitIntoTokens(tokenString.EvaluatePreFunctions(tokenString.OriginalString, source.ModuleWithMacros.Macros), TokenRegExPattern).ToList <string>()); return(string.Empty); } // recursive tokenString.Parse(null); } return(tokenString.ToString()); }; var graph = Graph.Instance; var parsedString = new System.Text.StringBuilder(); for (int index = 0; index < this.Tokens.Count; ++index) { var token = this.Tokens[index]; if (!(token.StartsWith(TokenPrefix) && token.EndsWith(TokenSuffix))) { parsedString.Append(token); continue; } // step 1 : is the token positional, i.e. was set up at creation time var positional = GetMatches(token, PositionalTokenRegExPattern).FirstOrDefault(); if (!System.String.IsNullOrEmpty(positional)) { var positionalIndex = System.Convert.ToInt32(positional); if (positionalIndex > this.PositionalTokens.Count) { throw new Exception("TokenizedString positional token at index {0} requested, but only {1} positional values given. Created at {2}.", positionalIndex, this.PositionalTokens.Count, this.CreationStackTrace); } parsedString.Append(expandTokenizedString(this, this.PositionalTokens[positionalIndex], index)); continue; } // step 2 : try to resolve with custom macros passed to the Parse function else if (null != customMacros && customMacros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, customMacros.Dict[token], index)); continue; } // step 3 : try macros in the global Graph, common to all modules else if (graph.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, graph.Macros.Dict[token], index)); continue; } else if (this.ModuleWithMacros != null) { var tool = this.ModuleWithMacros.Tool; // step 4 : try macros in the specific module if (this.ModuleWithMacros.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, this.ModuleWithMacros.Macros.Dict[token], index)); continue; } // step 5 : try macros in the Tool attached to the specific module else if (null != tool && tool.Macros.Dict.ContainsKey(token)) { parsedString.Append(expandTokenizedString(this, tool.Macros.Dict[token], index)); continue; } } // step 6 : try the immediate environment var strippedToken = SplitIntoTokens(token, ExtractTokenRegExPattern).First(); var envVar = System.Environment.GetEnvironmentVariable(strippedToken); if (null != envVar) { parsedString.Append(envVar); continue; } // step 7 : fail else { // TODO: this could be due to the user not having set a property, e.g. inputpath // is there a better error message that could be returned, other than this in those // circumstances? var message = new System.Text.StringBuilder(); message.AppendFormat("Unrecognized token '{0}' from original string '{1}'", token, this.OriginalString); message.AppendLine(); if (null != customMacros) { message.AppendLine("Searched in custom macros"); } message.AppendLine("Searched in global macros"); if (null != this.ModuleWithMacros) { message.AppendFormat("Searched in module {0}", this.ModuleWithMacros.ToString()); message.AppendLine(); if (null != this.ModuleWithMacros.Tool) { message.AppendFormat("Searched in tool {0}", this.ModuleWithMacros.Tool.ToString()); message.AppendLine(); } } message.AppendLine("TokenizedString created with this stack trace:"); message.AppendLine(this.CreationStackTrace); throw new Exception(message.ToString()); } } var functionEvaluated = this.EvaluatePostFunctions(NormalizeDirectorySeparators(parsedString.ToString())); if (null == customMacros) { this.ParsedString = functionEvaluated; Log.DebugMessage("Converted '{0}' to '{1}'", this.OriginalString, this.ToString()); } return(functionEvaluated); }