protected override QilNode VisitStrConcat(QilStrConcat ndStrConcat) {
LocalBuilder locStringConcat;
bool fasterConcat;
QilNode delimiter;
QilNode listStrings;
Debug.Assert(!ndStrConcat.Values.XmlType.IsSingleton, "Optimizer should have folded StrConcat of a singleton value");
// Get delimiter (assuming it's not the empty string)
delimiter = ndStrConcat.Delimiter;
if (delimiter.NodeType == QilNodeType.LiteralString && ((string) (QilLiteral) delimiter).Length == 0) {
delimiter = null;
}
listStrings = ndStrConcat.Values;
if (listStrings.NodeType == QilNodeType.Sequence && listStrings.Count < 5) {
// Faster concat possible only if cardinality can be guaranteed at compile-time and there's no delimiter
fasterConcat = true;
foreach (QilNode ndStr in listStrings) {
if (!ndStr.XmlType.IsSingleton)
fasterConcat = false;
}
}
else {
// If more than 4 strings, array will need to be built
fasterConcat = false;
}
if (fasterConcat) {
foreach (QilNode ndStr in listStrings)
NestedVisitEnsureStack(ndStr);
this.helper.CallConcatStrings(listStrings.Count);
}
else {
// Create StringConcat helper internal class
locStringConcat = this.helper.DeclareLocal("$$$strcat", typeof(StringConcat));
this.helper.Emit(OpCodes.Ldloca, locStringConcat);
this.helper.Call(XmlILMethods.StrCatClear);
// Set delimiter, if it's not empty string
if (delimiter != null) {
this.helper.Emit(OpCodes.Ldloca, locStringConcat);
NestedVisitEnsureStack(delimiter);
this.helper.Call(XmlILMethods.StrCatDelim);
}
this.helper.Emit(OpCodes.Ldloca, locStringConcat);
if (listStrings.NodeType == QilNodeType.Sequence) {
foreach (QilNode ndStr in listStrings)
GenerateConcat(ndStr, locStringConcat);
}
else {
GenerateConcat(listStrings, locStringConcat);
}
// Push resulting string onto stack
this.helper.Call(XmlILMethods.StrCatResult);
}
this.iterCurr.Storage = StorageDescriptor.Stack(typeof(string), false);
return ndStrConcat;
}