From b8bd03960b79e92d38ee7094a88e246253dad800 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sun, 5 Jul 2020 23:26:48 -0700 Subject: Improve compiler performance by removing regex and other string fixes --- src/WixToolset.Core/VariableResolver.cs | 188 +++++++++++++------------------- 1 file changed, 73 insertions(+), 115 deletions(-) (limited to 'src/WixToolset.Core/VariableResolver.cs') diff --git a/src/WixToolset.Core/VariableResolver.cs b/src/WixToolset.Core/VariableResolver.cs index 88067673..140e7def 100644 --- a/src/WixToolset.Core/VariableResolver.cs +++ b/src/WixToolset.Core/VariableResolver.cs @@ -79,150 +79,108 @@ namespace WixToolset.Core public IVariableResolution ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool errorOnUnknown) { - var matches = Common.WixVariableRegex.Matches(value); + var start = 0; + var defaulted = true; + var delayed = false; + var updated = false; - // the value is the default unless it's substituted further down - var result = this.ServiceProvider.GetService(); - result.IsDefault = true; - result.Value = value; - - var finalizeEscapes = false; - - while (matches.Count > 0) + while (Common.TryParseWixVariable(value, start, out var parsed)) { - var updatedResultThisPass = false; - var sb = new StringBuilder(value); + var variableNamespace = parsed.Namespace; + var variableId = parsed.Name; + var variableDefaultValue = parsed.DefaultValue; - // notice how this code walks backward through the list - // because it modifies the string as we move through it - for (var i = matches.Count - 1; 0 <= i; i--) + // check for an escape sequence of !! indicating the match is not a variable expression + if (0 < parsed.Index && '!' == value[parsed.Index - 1]) { - var variableNamespace = matches[i].Groups["namespace"].Value; - var variableId = matches[i].Groups["fullname"].Value; - string variableDefaultValue = null; + var sb = new StringBuilder(value); + sb.Remove(parsed.Index - 1, 1); + value = sb.ToString(); - // get the default value if one was specified - if (matches[i].Groups["value"].Success) - { - variableDefaultValue = matches[i].Groups["value"].Value; + updated = true; + start = parsed.Index + parsed.Length - 1; - // localization variables do not support inline default values - if ("loc" == variableNamespace) - { - this.Messaging.Write(ErrorMessages.IllegalInlineLocVariable(sourceLineNumbers, variableId, variableDefaultValue)); - } + continue; + } + + string resolvedValue = null; + + if ("loc" == variableNamespace) + { + // localization variables do not support inline default values + if (variableDefaultValue != null) + { + this.Messaging.Write(ErrorMessages.IllegalInlineLocVariable(sourceLineNumbers, variableId, variableDefaultValue)); + continue; } - // get the scope if one was specified - if (matches[i].Groups["scope"].Success) + if (this.locVariables.TryGetValue(variableId, out var bindVariable)) { - if ("bind" == variableNamespace) - { - variableId = matches[i].Groups["name"].Value; - } + resolvedValue = bindVariable.Value; + } + } + else if ("wix" == variableNamespace) + { + if (this.wixVariables.TryGetValue(variableId, out var bindVariable)) + { + resolvedValue = bindVariable.Value ?? String.Empty; + defaulted = false; } + else if (null != variableDefaultValue) // default the resolved value to the inline value if one was specified + { + resolvedValue = variableDefaultValue; + } + } - // check for an escape sequence of !! indicating the match is not a variable expression - if (0 < matches[i].Index && '!' == sb[matches[i].Index - 1]) + if ("bind" == variableNamespace) + { + // Can't resolve these yet, but keep track of where we find them so they can be resolved later with less effort. + delayed = true; + start = parsed.Index + parsed.Length - 1; + } + else + { + // insert the resolved value if it was found or display an error + if (null != resolvedValue) { - if (finalizeEscapes) + if (parsed.Index == 0 && parsed.Length == value.Length) { - sb.Remove(matches[i].Index - 1, 1); - - result.UpdatedValue = true; + value = resolvedValue; } else { - continue; + var sb = new StringBuilder(value); + sb.Remove(parsed.Index, parsed.Length); + sb.Insert(parsed.Index, resolvedValue); + value = sb.ToString(); } + + updated = true; + start = parsed.Index; } else { - string resolvedValue = null; - - if ("loc" == variableNamespace) + if ("loc" == variableNamespace && errorOnUnknown) // unresolved loc variable { - // warn about deprecated syntax of $(loc.var) - if ('$' == sb[matches[i].Index]) - { - this.Messaging.Write(WarningMessages.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId)); - } - - if (this.locVariables.TryGetValue(variableId, out var bindVariable)) - { - resolvedValue = bindVariable.Value; - } + this.Messaging.Write(ErrorMessages.LocalizationVariableUnknown(sourceLineNumbers, variableId)); } - else if ("wix" == variableNamespace) + else if ("wix" == variableNamespace && errorOnUnknown) // unresolved wix variable { - // illegal syntax of $(wix.var) - if ('$' == sb[matches[i].Index]) - { - this.Messaging.Write(ErrorMessages.IllegalWixVariablePrefix(sourceLineNumbers, variableId)); - } - else - { - if (this.wixVariables.TryGetValue(variableId, out var bindVariable)) - { - resolvedValue = bindVariable.Value ?? String.Empty; - result.IsDefault = false; - } - else if (null != variableDefaultValue) // default the resolved value to the inline value if one was specified - { - resolvedValue = variableDefaultValue; - } - } + this.Messaging.Write(ErrorMessages.WixVariableUnknown(sourceLineNumbers, variableId)); } - if ("bind" == variableNamespace) - { - // can't resolve these yet, but keep track of where we find them so they can be resolved later with less effort - result.DelayedResolve = true; - } - else - { - // insert the resolved value if it was found or display an error - if (null != resolvedValue) - { - sb.Remove(matches[i].Index, matches[i].Length); - sb.Insert(matches[i].Index, resolvedValue); - - result.UpdatedValue = true; - updatedResultThisPass = true; - } - else if ("loc" == variableNamespace && errorOnUnknown) // unresolved loc variable - { - this.Messaging.Write(ErrorMessages.LocalizationVariableUnknown(sourceLineNumbers, variableId)); - } - else if ("wix" == variableNamespace && errorOnUnknown) // unresolved wix variable - { - this.Messaging.Write(ErrorMessages.WixVariableUnknown(sourceLineNumbers, variableId)); - } - } + start = parsed.Index + parsed.Length; } } - - result.Value = sb.ToString(); - value = result.Value; - - if (finalizeEscapes) - { - // escaped references have been un-escaped, so we're done - break; - } - else if (updatedResultThisPass) - { - // we substituted loc strings, so make another pass to see if that brought in more loc strings - matches = Common.WixVariableRegex.Matches(value); - } - else - { - // make one final pass to un-escape any escaped references - finalizeEscapes = true; - } } - return result; + return new VariableResolution + { + DelayedResolve = delayed, + IsDefault = defaulted, + UpdatedValue = updated, + Value = value, + }; } private static bool TryAddWixVariable(IDictionary variables, BindVariable variable) -- cgit v1.2.3-55-g6feb