diff options
| author | Rob Mensching <rob@firegiant.com> | 2020-07-05 23:26:48 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2020-07-08 15:18:09 -0700 |
| commit | b8bd03960b79e92d38ee7094a88e246253dad800 (patch) | |
| tree | 89fec2cf4003832110bcbdd0633c8dcd492efd54 /src/WixToolset.Core/VariableResolver.cs | |
| parent | 7b583330fd42356930bdc5a28820e546f6ca45a4 (diff) | |
| download | wix-b8bd03960b79e92d38ee7094a88e246253dad800.tar.gz wix-b8bd03960b79e92d38ee7094a88e246253dad800.tar.bz2 wix-b8bd03960b79e92d38ee7094a88e246253dad800.zip | |
Improve compiler performance by removing regex and other string fixes
Diffstat (limited to 'src/WixToolset.Core/VariableResolver.cs')
| -rw-r--r-- | src/WixToolset.Core/VariableResolver.cs | 188 |
1 files changed, 73 insertions, 115 deletions
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 | |||
| 79 | 79 | ||
| 80 | public IVariableResolution ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool errorOnUnknown) | 80 | public IVariableResolution ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool errorOnUnknown) |
| 81 | { | 81 | { |
| 82 | var matches = Common.WixVariableRegex.Matches(value); | 82 | var start = 0; |
| 83 | var defaulted = true; | ||
| 84 | var delayed = false; | ||
| 85 | var updated = false; | ||
| 83 | 86 | ||
| 84 | // the value is the default unless it's substituted further down | 87 | while (Common.TryParseWixVariable(value, start, out var parsed)) |
| 85 | var result = this.ServiceProvider.GetService<IVariableResolution>(); | ||
| 86 | result.IsDefault = true; | ||
| 87 | result.Value = value; | ||
| 88 | |||
| 89 | var finalizeEscapes = false; | ||
| 90 | |||
| 91 | while (matches.Count > 0) | ||
| 92 | { | 88 | { |
| 93 | var updatedResultThisPass = false; | 89 | var variableNamespace = parsed.Namespace; |
| 94 | var sb = new StringBuilder(value); | 90 | var variableId = parsed.Name; |
| 91 | var variableDefaultValue = parsed.DefaultValue; | ||
| 95 | 92 | ||
| 96 | // notice how this code walks backward through the list | 93 | // check for an escape sequence of !! indicating the match is not a variable expression |
| 97 | // because it modifies the string as we move through it | 94 | if (0 < parsed.Index && '!' == value[parsed.Index - 1]) |
| 98 | for (var i = matches.Count - 1; 0 <= i; i--) | ||
| 99 | { | 95 | { |
| 100 | var variableNamespace = matches[i].Groups["namespace"].Value; | 96 | var sb = new StringBuilder(value); |
| 101 | var variableId = matches[i].Groups["fullname"].Value; | 97 | sb.Remove(parsed.Index - 1, 1); |
| 102 | string variableDefaultValue = null; | 98 | value = sb.ToString(); |
| 103 | 99 | ||
| 104 | // get the default value if one was specified | 100 | updated = true; |
| 105 | if (matches[i].Groups["value"].Success) | 101 | start = parsed.Index + parsed.Length - 1; |
| 106 | { | ||
| 107 | variableDefaultValue = matches[i].Groups["value"].Value; | ||
| 108 | 102 | ||
| 109 | // localization variables do not support inline default values | 103 | continue; |
| 110 | if ("loc" == variableNamespace) | 104 | } |
| 111 | { | 105 | |
| 112 | this.Messaging.Write(ErrorMessages.IllegalInlineLocVariable(sourceLineNumbers, variableId, variableDefaultValue)); | 106 | string resolvedValue = null; |
| 113 | } | 107 | |
| 108 | if ("loc" == variableNamespace) | ||
| 109 | { | ||
| 110 | // localization variables do not support inline default values | ||
| 111 | if (variableDefaultValue != null) | ||
| 112 | { | ||
| 113 | this.Messaging.Write(ErrorMessages.IllegalInlineLocVariable(sourceLineNumbers, variableId, variableDefaultValue)); | ||
| 114 | continue; | ||
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | // get the scope if one was specified | 117 | if (this.locVariables.TryGetValue(variableId, out var bindVariable)) |
| 117 | if (matches[i].Groups["scope"].Success) | ||
| 118 | { | 118 | { |
| 119 | if ("bind" == variableNamespace) | 119 | resolvedValue = bindVariable.Value; |
| 120 | { | 120 | } |
| 121 | variableId = matches[i].Groups["name"].Value; | 121 | } |
| 122 | } | 122 | else if ("wix" == variableNamespace) |
| 123 | { | ||
| 124 | if (this.wixVariables.TryGetValue(variableId, out var bindVariable)) | ||
| 125 | { | ||
| 126 | resolvedValue = bindVariable.Value ?? String.Empty; | ||
| 127 | defaulted = false; | ||
| 123 | } | 128 | } |
| 129 | else if (null != variableDefaultValue) // default the resolved value to the inline value if one was specified | ||
| 130 | { | ||
| 131 | resolvedValue = variableDefaultValue; | ||
| 132 | } | ||
| 133 | } | ||
| 124 | 134 | ||
| 125 | // check for an escape sequence of !! indicating the match is not a variable expression | 135 | if ("bind" == variableNamespace) |
| 126 | if (0 < matches[i].Index && '!' == sb[matches[i].Index - 1]) | 136 | { |
| 137 | // Can't resolve these yet, but keep track of where we find them so they can be resolved later with less effort. | ||
| 138 | delayed = true; | ||
| 139 | start = parsed.Index + parsed.Length - 1; | ||
| 140 | } | ||
| 141 | else | ||
| 142 | { | ||
| 143 | // insert the resolved value if it was found or display an error | ||
| 144 | if (null != resolvedValue) | ||
| 127 | { | 145 | { |
| 128 | if (finalizeEscapes) | 146 | if (parsed.Index == 0 && parsed.Length == value.Length) |
| 129 | { | 147 | { |
| 130 | sb.Remove(matches[i].Index - 1, 1); | 148 | value = resolvedValue; |
| 131 | |||
| 132 | result.UpdatedValue = true; | ||
| 133 | } | 149 | } |
| 134 | else | 150 | else |
| 135 | { | 151 | { |
| 136 | continue; | 152 | var sb = new StringBuilder(value); |
| 153 | sb.Remove(parsed.Index, parsed.Length); | ||
| 154 | sb.Insert(parsed.Index, resolvedValue); | ||
| 155 | value = sb.ToString(); | ||
| 137 | } | 156 | } |
| 157 | |||
| 158 | updated = true; | ||
| 159 | start = parsed.Index; | ||
| 138 | } | 160 | } |
| 139 | else | 161 | else |
| 140 | { | 162 | { |
| 141 | string resolvedValue = null; | 163 | if ("loc" == variableNamespace && errorOnUnknown) // unresolved loc variable |
| 142 | |||
| 143 | if ("loc" == variableNamespace) | ||
| 144 | { | 164 | { |
| 145 | // warn about deprecated syntax of $(loc.var) | 165 | this.Messaging.Write(ErrorMessages.LocalizationVariableUnknown(sourceLineNumbers, variableId)); |
| 146 | if ('$' == sb[matches[i].Index]) | ||
| 147 | { | ||
| 148 | this.Messaging.Write(WarningMessages.DeprecatedLocalizationVariablePrefix(sourceLineNumbers, variableId)); | ||
| 149 | } | ||
| 150 | |||
| 151 | if (this.locVariables.TryGetValue(variableId, out var bindVariable)) | ||
| 152 | { | ||
| 153 | resolvedValue = bindVariable.Value; | ||
| 154 | } | ||
| 155 | } | 166 | } |
| 156 | else if ("wix" == variableNamespace) | 167 | else if ("wix" == variableNamespace && errorOnUnknown) // unresolved wix variable |
| 157 | { | 168 | { |
| 158 | // illegal syntax of $(wix.var) | 169 | this.Messaging.Write(ErrorMessages.WixVariableUnknown(sourceLineNumbers, variableId)); |
| 159 | if ('$' == sb[matches[i].Index]) | ||
| 160 | { | ||
| 161 | this.Messaging.Write(ErrorMessages.IllegalWixVariablePrefix(sourceLineNumbers, variableId)); | ||
| 162 | } | ||
| 163 | else | ||
| 164 | { | ||
| 165 | if (this.wixVariables.TryGetValue(variableId, out var bindVariable)) | ||
| 166 | { | ||
| 167 | resolvedValue = bindVariable.Value ?? String.Empty; | ||
| 168 | result.IsDefault = false; | ||
| 169 | } | ||
| 170 | else if (null != variableDefaultValue) // default the resolved value to the inline value if one was specified | ||
| 171 | { | ||
| 172 | resolvedValue = variableDefaultValue; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | } | 170 | } |
| 176 | 171 | ||
| 177 | if ("bind" == variableNamespace) | 172 | start = parsed.Index + parsed.Length; |
| 178 | { | ||
| 179 | // can't resolve these yet, but keep track of where we find them so they can be resolved later with less effort | ||
| 180 | result.DelayedResolve = true; | ||
| 181 | } | ||
| 182 | else | ||
| 183 | { | ||
| 184 | // insert the resolved value if it was found or display an error | ||
| 185 | if (null != resolvedValue) | ||
| 186 | { | ||
| 187 | sb.Remove(matches[i].Index, matches[i].Length); | ||
| 188 | sb.Insert(matches[i].Index, resolvedValue); | ||
| 189 | |||
| 190 | result.UpdatedValue = true; | ||
| 191 | updatedResultThisPass = true; | ||
| 192 | } | ||
| 193 | else if ("loc" == variableNamespace && errorOnUnknown) // unresolved loc variable | ||
| 194 | { | ||
| 195 | this.Messaging.Write(ErrorMessages.LocalizationVariableUnknown(sourceLineNumbers, variableId)); | ||
| 196 | } | ||
| 197 | else if ("wix" == variableNamespace && errorOnUnknown) // unresolved wix variable | ||
| 198 | { | ||
| 199 | this.Messaging.Write(ErrorMessages.WixVariableUnknown(sourceLineNumbers, variableId)); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | } | 173 | } |
| 203 | } | 174 | } |
| 204 | |||
| 205 | result.Value = sb.ToString(); | ||
| 206 | value = result.Value; | ||
| 207 | |||
| 208 | if (finalizeEscapes) | ||
| 209 | { | ||
| 210 | // escaped references have been un-escaped, so we're done | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | else if (updatedResultThisPass) | ||
| 214 | { | ||
| 215 | // we substituted loc strings, so make another pass to see if that brought in more loc strings | ||
| 216 | matches = Common.WixVariableRegex.Matches(value); | ||
| 217 | } | ||
| 218 | else | ||
| 219 | { | ||
| 220 | // make one final pass to un-escape any escaped references | ||
| 221 | finalizeEscapes = true; | ||
| 222 | } | ||
| 223 | } | 175 | } |
| 224 | 176 | ||
| 225 | return result; | 177 | return new VariableResolution |
| 178 | { | ||
| 179 | DelayedResolve = delayed, | ||
| 180 | IsDefault = defaulted, | ||
| 181 | UpdatedValue = updated, | ||
| 182 | Value = value, | ||
| 183 | }; | ||
| 226 | } | 184 | } |
| 227 | 185 | ||
| 228 | private static bool TryAddWixVariable(IDictionary<string, BindVariable> variables, BindVariable variable) | 186 | private static bool TryAddWixVariable(IDictionary<string, BindVariable> variables, BindVariable variable) |
