示例#1
0
        //
        // Traverses expressions in "parts" and concats all contiguous literal strings/bytes.
        // Notes:
        //  - We place the string/byte[] values that can be concatenated so far in to "concat" list thats keep track of their total length.
        //    If we reach a non-literal expression and we have some literals ready in "concat" list we perform concat and clear the list.
        //  - "result" contains argument expressions to be passed to a CreateMutableString* overload.
        //  - "opName" contains the name of the operation. This method appends either "non-literal" suffix (for each expression)
        //    or "encoding" suffix (for each concatenated literal).
        //  - "anyBinary" keeps track of whether any iteral visited so far is binary (byte[]).
        //
        private static void ConcatLiteralsAndTransformRecursive(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts,
                                                                LiteralConcatenation /*!*/ concat, MSAst.ExpressionCollectionBuilder /*!*/ result, StringBuilder /*!*/ opName, ref bool anyBinary)
        {
            for (int i = 0; i < parts.Count; i++)
            {
                Expression        part = parts[i];
                StringLiteral     literal;
                StringConstructor ctor;

                if ((literal = part as StringLiteral) != null)
                {
                    concat.Add(literal);
                }
                else if ((ctor = part as StringConstructor) != null)
                {
                    ConcatLiteralsAndTransformRecursive(gen, ctor.Parts, concat, result, opName, ref anyBinary);
                }
                else
                {
                    if (concat.Count > 0)
                    {
                        result.Add(MakeConstant(concat.GetValue()));
                        opName.Append(RubyOps.SuffixLiteral);
                        anyBinary |= concat.IsBinary;
                        concat.Clear();
                    }

                    result.Add(MakeConversion(gen, part));
                    opName.Append(RubyOps.SuffixMutable);
                }
            }
        }
示例#2
0
        internal static MSA.Expression /*!*/ TransformConcatentation(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts, IFactory /*!*/ factory)
        {
            // fast path for a single element:
            if (parts.Count == 1)
            {
                var literal = parts[0] as StringLiteral;
                if (literal != null)
                {
                    var str = literal.Value as string;
                    if (str != null)
                    {
                        return(factory.CreateExpression(gen, str));
                    }
                }
                else
                {
                    return(factory.CreateExpression(gen, "M", MakeConversion(gen, parts[0])));
                }
            }

            var opSuffix = new StringBuilder(Math.Min(parts.Count, 4));

            bool anyBinary = false;
            var  merged    = new MSAst.ExpressionCollectionBuilder();
            var  concat    = new LiteralConcatenation(gen.Encoding.Encoding);

            ConcatLiteralsAndTransformRecursive(gen, parts, concat, merged, opSuffix, ref anyBinary);

            // finish trailing literals:
            if (concat.Count > 0)
            {
                object value = concat.GetValue();

                // TODO (opt): We don't to optimize for binary strings, we can if it is needed.
                if (!concat.IsBinary && merged.Count == 0)
                {
                    return(factory.CreateExpression(gen, (string)value));
                }

                merged.Add(MakeConstant(value));
                opSuffix.Append(RubyOps.SuffixLiteral);
                anyBinary |= concat.IsBinary;
            }

            // TODO (opt): We don't to optimize for binary strings, we can if it is needed.
            if (!anyBinary && merged.Count <= RubyOps.MakeStringParamCount)
            {
                if (merged.Count == 0)
                {
                    return(factory.CreateExpression(gen, String.Empty));
                }

                return(factory.CreateExpression(gen, opSuffix.ToString(), merged));
            }
            else
            {
                return(factory.CreateExpression(gen, "N", Ast.NewArrayInit(typeof(object), merged)));
            }
        }
        internal static MSA.Expression /*!*/ TransformConcatentation(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts, IFactory /*!*/ factory)
        {
            // fast path for a single element:
            if (parts.Count == 1)
            {
                var literal = parts[0] as StringLiteral;
                if (literal != null)
                {
                    var str = literal.Value as string;
                    if (str != null)
                    {
                        return(factory.CreateExpression(gen, str, literal.Encoding));
                    }
                    else
                    {
                        return(factory.CreateExpression(gen, (byte[])literal.Value, literal.Encoding));
                    }
                }
                else
                {
                    return(factory.CreateExpressionM(gen, new MSAst.ExpressionCollectionBuilder {
                        MakeConversion(gen, parts[0])
                    }));
                }
            }

            var merged = new MSAst.ExpressionCollectionBuilder();
            var concat = new LiteralConcatenation(gen.Encoding);

            if (!ConcatLiteralsAndTransformRecursive(gen, parts, concat, merged))
            {
                // TODO: we should emit Append calls directly, and not create an array first
                // TODO: MRI reports a syntax error
                // we can't concatenate due to encoding incompatibilities, report error at runtime:
                return(factory.CreateExpressionN(gen, CollectionUtils.ConvertAll(parts, (e) => e.Transform(gen))));
            }

            // finish trailing literals:
            if (concat.Count > 0)
            {
                merged.Add(StringLiteral.Transform(concat.GetValue(), concat.Encoding));
            }

            if (merged.Count <= RubyOps.MakeStringParamCount)
            {
                if (merged.Count == 0)
                {
                    return(factory.CreateExpression(gen, String.Empty, gen.Encoding));
                }

                return(factory.CreateExpressionM(gen, merged));
            }
            else
            {
                // TODO: we should emit Append calls directly, and not create an array first
                return(factory.CreateExpressionN(gen, merged));
            }
        }
        //
        // Traverses expressions in "parts" and concats all contiguous literal strings/bytes.
        // Notes:
        //  - We place the string/byte[] values that can be concatenated so far in to "concat" list that keeps track of their total length.
        //    If we reach a non-literal expression and we have some literals ready in "concat" list we perform concat and clear the list.
        //  - "result" contains argument expressions to be passed to a CreateMutableString* overload.
        //  - "opName" contains the name of the operation. This method appends either "non-literal" suffix (for each expression)
        //    or "encoding" suffix (for each concatenated literal).
        //
        // Returns false if the parts can't be concatenated due to encoding incompatibilities.
        //
        private static bool ConcatLiteralsAndTransformRecursive(AstGenerator /*!*/ gen, List <Expression> /*!*/ parts,
                                                                LiteralConcatenation /*!*/ concat, MSAst.ExpressionCollectionBuilder /*!*/ result)
        {
            for (int i = 0; i < parts.Count; i++)
            {
                Expression        part = parts[i];
                StringLiteral     literal;
                StringConstructor ctor;

                if ((literal = part as StringLiteral) != null)
                {
                    if (!concat.Add(literal))
                    {
                        return(false);
                    }
                }
                else if ((ctor = part as StringConstructor) != null)
                {
                    if (!ConcatLiteralsAndTransformRecursive(gen, ctor.Parts, concat, result))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (concat.Count > 0)
                    {
                        result.Add(StringLiteral.Transform(concat.GetValue(), concat.Encoding));
                        concat.Clear();
                    }

                    result.Add(MakeConversion(gen, part));
                }
            }

            return(true);
        }