瀏覽代碼

Fix template literal object to string handling (#1423)

fixes https://github.com/sebastienros/jint/issues/1421
Marko Lahma 2 年之前
父節點
當前提交
2ebe0f18af

+ 9 - 0
Jint.Tests/Runtime/StringTests.cs

@@ -63,4 +63,13 @@ bar += 'bar';
         Assert.Equal(0, engine.Evaluate("''.indexOf('', 0)"));
         Assert.Equal(0, engine.Evaluate("''.indexOf('', 1)"));
     }
+
+    [Fact]
+    public void TemplateLiteralsWithArrays()
+    {
+        var engine = new Engine();
+        engine.Execute("var a = [1,2,'three',true];");
+        Assert.Equal("test 1,2,three,true", engine.Evaluate("'test ' + a"));
+        Assert.Equal("test 1,2,three,true", engine.Evaluate("`test ${a}`"));
+    }
 }

+ 8 - 6
Jint/Runtime/Interpreter/Expressions/JintTaggedTemplateExpression.cs

@@ -37,7 +37,7 @@ internal sealed class JintTaggedTemplateExpression : JintExpression
             ExceptionHelper.ThrowTypeError(engine.Realm, "Argument must be callable");
         }
 
-        var expressions = _quasi._expressions;
+        ref readonly var expressions = ref _quasi._expressions;
 
         var args = engine._jsValueArrayPool.RentArray(expressions.Length + 1);
 
@@ -72,12 +72,14 @@ internal sealed class JintTaggedTemplateExpression : JintExpression
             return cached;
         }
 
-        var count = (uint) _quasi._templateLiteralExpression.Quasis.Count;
-        var template = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
-        var rawObj = context.Engine.Realm.Intrinsics.Array.ArrayCreate(count);
-        for (uint i = 0; i < _quasi._templateLiteralExpression.Quasis.Count; ++i)
+        ref readonly var elements = ref _quasi._templateLiteralExpression.Quasis;
+        var count = (uint) elements.Count;
+
+        var template = new JsArray(context.Engine, count, length: count);
+        var rawObj = new JsArray(context.Engine, count, length: count);
+        for (uint i = 0; i < elements.Count; ++i)
         {
-            var templateElementValue = _quasi._templateLiteralExpression.Quasis[(int) i].Value;
+            var templateElementValue = elements[(int) i].Value;
             template.SetIndexValue(i, templateElementValue.Cooked, updateLength: false);
             rawObj.SetIndexValue(i, templateElementValue.Raw, updateLength: false);
         }

+ 38 - 38
Jint/Runtime/Interpreter/Expressions/JintTemplateLiteralExpression.cs

@@ -2,56 +2,56 @@ using Esprima.Ast;
 using Jint.Native;
 using Jint.Pooling;
 
-namespace Jint.Runtime.Interpreter.Expressions
+namespace Jint.Runtime.Interpreter.Expressions;
+
+internal sealed class JintTemplateLiteralExpression : JintExpression
 {
-    internal sealed class JintTemplateLiteralExpression : JintExpression
+    internal readonly TemplateLiteral _templateLiteralExpression;
+    internal JintExpression[] _expressions = Array.Empty<JintExpression>();
+
+    public JintTemplateLiteralExpression(TemplateLiteral expression) : base(expression)
     {
-        internal readonly TemplateLiteral _templateLiteralExpression;
-        internal JintExpression[] _expressions = Array.Empty<JintExpression>();
+        _templateLiteralExpression = expression;
+        _initialized = false;
+    }
 
-        public JintTemplateLiteralExpression(TemplateLiteral expression) : base(expression)
-        {
-            _templateLiteralExpression = expression;
-            _initialized = false;
-        }
+    protected override void Initialize(EvaluationContext context)
+    {
+        DoInitialize();
+    }
 
-        protected override void Initialize(EvaluationContext context)
+    internal void DoInitialize()
+    {
+        ref readonly var expressions = ref _templateLiteralExpression.Expressions;
+        _expressions = new JintExpression[expressions.Count];
+        for (var i = 0; i < expressions.Count; i++)
         {
-            DoInitialize();
+            _expressions[i] = Build(expressions[i]);
         }
 
-        internal void DoInitialize()
-        {
-            _expressions = new JintExpression[_templateLiteralExpression.Expressions.Count];
-            for (var i = 0; i < _templateLiteralExpression.Expressions.Count; i++)
-            {
-                var exp = _templateLiteralExpression.Expressions[i];
-                _expressions[i] = Build(exp);
-            }
-
-            _initialized = true;
-        }
+        _initialized = true;
+    }
 
-        private JsString BuildString(EvaluationContext context)
+    private JsString BuildString(EvaluationContext context)
+    {
+        using var sb = StringBuilderPool.Rent();
+        ref readonly var elements = ref _templateLiteralExpression.Quasis;
+        for (var i = 0; i < elements.Count; i++)
         {
-            using var sb = StringBuilderPool.Rent();
-            for (var i = 0; i < _templateLiteralExpression.Quasis.Count; i++)
+            var quasi = elements[i];
+            sb.Builder.Append(quasi.Value.Cooked);
+            if (i < _expressions.Length)
             {
-                var quasi = _templateLiteralExpression.Quasis[i];
-                sb.Builder.Append(quasi.Value.Cooked);
-                if (i < _expressions.Length)
-                {
-                    var completion = _expressions[i].GetValue(context);
-                    sb.Builder.Append(completion);
-                }
+                var value = _expressions[i].GetValue(context);
+                sb.Builder.Append(TypeConverter.ToString(value));
             }
-
-            return JsString.Create(sb.ToString());
         }
 
-        protected override object EvaluateInternal(EvaluationContext context)
-        {
-            return BuildString(context);
-        }
+        return JsString.Create(sb.ToString());
+    }
+
+    protected override object EvaluateInternal(EvaluationContext context)
+    {
+        return BuildString(context);
     }
 }