barefoot_js 0.39.7 → 0.39.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/barefoot_js/evaluator.rb +21 -3
- data/lib/barefoot_js.rb +76 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ca01f4cd2478ff3996932ab0ea7102c799e74c2602f63313ca3ea6ed1e3e7ef7
|
|
4
|
+
data.tar.gz: 546f0e92374f3947eae8965b2771a3ba6928526eddaa8b9f1e3ced6883deed1f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de992621414ebaf15ae3237dc62c1190bab959f516ed0047026af8a64a1dc87db978d8d43c86e30278f3087c6e45953ff676c9ffb486d8499dc3eb010586cfa5
|
|
7
|
+
data.tar.gz: dc2aa7213b1e63646a13f0c9340377731ab62baf7731ffcbed0bb517a78ff79d866f08a3a7c985990f666f01532a79237be42c346791d7bff213fa1e83f3a5c6
|
|
@@ -286,6 +286,26 @@ module BarefootJS
|
|
|
286
286
|
to_number(l).to_f / to_number(r).to_f
|
|
287
287
|
end
|
|
288
288
|
|
|
289
|
+
# JS `%`: the truncated remainder, which takes the dividend's sign
|
|
290
|
+
# (`-7 % 2` -> -1) and keeps a fraction (`7.5 % 2` -> 1.5); Ruby's `%`
|
|
291
|
+
# floors instead (`-7 % 2` -> 1). A zero divisor, or a NaN / infinite
|
|
292
|
+
# dividend, gives NaN. Two Integer operands keep an Integer result, as
|
|
293
|
+
# Ruby's own `%` did, except for a zero remainder of a negative dividend:
|
|
294
|
+
# JS gives -0 there (`-4 % 2`), which only shows through later
|
|
295
|
+
# arithmetic (`1 / (-4 % 2)` is -Infinity), so it is the Float -0.0. An
|
|
296
|
+
# Array still takes it as index 0 and `number_to_string` spells it "0".
|
|
297
|
+
# Shared by callback-body evaluation (`binary`) and the template-emitted
|
|
298
|
+
# remainder (`Context#mod`, #3474).
|
|
299
|
+
def remainder(l, r)
|
|
300
|
+
ln = to_number(l)
|
|
301
|
+
rn = to_number(r)
|
|
302
|
+
return Float::NAN if rn.zero?
|
|
303
|
+
return ln.to_f.remainder(rn.to_f) unless ln.is_a?(Integer) && rn.is_a?(Integer)
|
|
304
|
+
|
|
305
|
+
m = ln.remainder(rn)
|
|
306
|
+
m.zero? && ln.negative? ? -0.0 : m
|
|
307
|
+
end
|
|
308
|
+
|
|
289
309
|
def binary(op, l, r)
|
|
290
310
|
case op
|
|
291
311
|
when '+'
|
|
@@ -297,9 +317,7 @@ module BarefootJS
|
|
|
297
317
|
when '-' then to_number(l) - to_number(r)
|
|
298
318
|
when '*' then to_number(l) * to_number(r)
|
|
299
319
|
when '/' then divide(l, r)
|
|
300
|
-
when '%'
|
|
301
|
-
rn = to_number(r).to_f
|
|
302
|
-
rn.zero? ? Float::NAN : to_number(l).to_f.remainder(rn)
|
|
320
|
+
when '%' then remainder(l, r)
|
|
303
321
|
when '<', '<=', '>', '>=' then relational(op, l, r)
|
|
304
322
|
when '===' then strict_eq(l, r)
|
|
305
323
|
when '!==' then !strict_eq(l, r)
|
data/lib/barefoot_js.rb
CHANGED
|
@@ -530,6 +530,15 @@ module BarefootJS
|
|
|
530
530
|
Evaluator.divide(left, right)
|
|
531
531
|
end
|
|
532
532
|
|
|
533
|
+
# JS `%`: the truncated remainder, which takes the dividend's sign
|
|
534
|
+
# (`-7 % 2` -> -1). Ruby's `%` floors (`-7 % 2` -> 1), so
|
|
535
|
+
# template-emitted remainders go through the shared evaluator's JS
|
|
536
|
+
# remainder instead: a fraction is kept, and a zero divisor gives NaN
|
|
537
|
+
# rather than raising (#3474).
|
|
538
|
+
def mod(left, right)
|
|
539
|
+
Evaluator.remainder(left, right)
|
|
540
|
+
end
|
|
541
|
+
|
|
533
542
|
# JS truthiness (falsy: false, nil, 0, NaN, ""). Delegates to the
|
|
534
543
|
# shared evaluator so template-emitted conditionals
|
|
535
544
|
# (`if bf.truthy?(x)`) and callback-body evaluation agree byte-for-byte.
|
|
@@ -1025,18 +1034,28 @@ module BarefootJS
|
|
|
1025
1034
|
end
|
|
1026
1035
|
|
|
1027
1036
|
# `Array.prototype.indexOf(x)` / `.lastIndexOf(x)` -- value-equality
|
|
1028
|
-
# search.
|
|
1037
|
+
# search. A String receiver is `String.prototype.indexOf`, counted in
|
|
1038
|
+
# UTF-16 code units like JS (#3613). Other receivers return -1.
|
|
1029
1039
|
def index_of(recv, elem)
|
|
1040
|
+
return utf16_index_of(recv, elem, false) if recv.is_a?(String)
|
|
1041
|
+
|
|
1030
1042
|
array_index_of(recv, elem, false)
|
|
1031
1043
|
end
|
|
1032
1044
|
|
|
1033
1045
|
def last_index_of(recv, elem)
|
|
1046
|
+
return utf16_index_of(recv, elem, true) if recv.is_a?(String)
|
|
1047
|
+
|
|
1034
1048
|
array_index_of(recv, elem, true)
|
|
1035
1049
|
end
|
|
1036
1050
|
|
|
1037
1051
|
# `Array.prototype.at(i)` -- negative indices count from the end;
|
|
1038
1052
|
# out-of-bounds -> nil (renders as '' via `h`, matching JS `undefined`).
|
|
1053
|
+
# A String receiver is indexed in UTF-16 code units (#3613). Half of a
|
|
1054
|
+
# surrogate pair, a lone surrogate in JS, comes back as U+FFFD: a
|
|
1055
|
+
# UTF-8 Ruby String can't hold one, so the halves compare equal and
|
|
1056
|
+
# don't rejoin (limitation `string-at-lone-surrogate`).
|
|
1039
1057
|
def at(recv, i)
|
|
1058
|
+
return utf16_at(recv, i) if recv.is_a?(String)
|
|
1040
1059
|
return nil unless recv.is_a?(Array)
|
|
1041
1060
|
return nil if i.nil?
|
|
1042
1061
|
|
|
@@ -1228,9 +1247,10 @@ module BarefootJS
|
|
|
1228
1247
|
def starts_with(recv, prefix, position = nil)
|
|
1229
1248
|
s = recv.nil? ? '' : string(recv)
|
|
1230
1249
|
p = prefix.nil? ? '' : string(prefix)
|
|
1250
|
+
# `position` counts UTF-16 code units, like JS (#3613).
|
|
1231
1251
|
unless position.nil?
|
|
1232
|
-
|
|
1233
|
-
|
|
1252
|
+
units = utf16_units(s)
|
|
1253
|
+
return utf16_has_at?(units, utf16_units(p), clamp_index(to_integer_or_infinity(position), units.length))
|
|
1234
1254
|
end
|
|
1235
1255
|
s.start_with?(p)
|
|
1236
1256
|
end
|
|
@@ -1239,9 +1259,11 @@ module BarefootJS
|
|
|
1239
1259
|
def ends_with(recv, suffix, end_position = nil)
|
|
1240
1260
|
s = recv.nil? ? '' : string(recv)
|
|
1241
1261
|
x = suffix.nil? ? '' : string(suffix)
|
|
1262
|
+
# `endPosition` counts UTF-16 code units, like JS (#3613).
|
|
1242
1263
|
unless end_position.nil?
|
|
1243
|
-
|
|
1244
|
-
|
|
1264
|
+
units = utf16_units(s)
|
|
1265
|
+
needle = utf16_units(x)
|
|
1266
|
+
return utf16_has_at?(units, needle, clamp_index(to_integer_or_infinity(end_position), units.length) - needle.length)
|
|
1245
1267
|
end
|
|
1246
1268
|
s.end_with?(x)
|
|
1247
1269
|
end
|
|
@@ -1697,6 +1719,55 @@ module BarefootJS
|
|
|
1697
1719
|
-1
|
|
1698
1720
|
end
|
|
1699
1721
|
|
|
1722
|
+
# `s` as JS sees it: an Array of UTF-16 code units. JS string positions
|
|
1723
|
+
# (`indexOf`, `at`, `startsWith`'s position, ...) count these, so an
|
|
1724
|
+
# astral character such as '😀' is two units (#3613).
|
|
1725
|
+
def utf16_units(s)
|
|
1726
|
+
s.to_s.encode('UTF-16LE', invalid: :replace, undef: :replace).unpack('v*')
|
|
1727
|
+
end
|
|
1728
|
+
|
|
1729
|
+
MAX_SAFE_INDEX = 2**53
|
|
1730
|
+
|
|
1731
|
+
# JS `ToIntegerOrInfinity` for a string position or index (#3613): NaN
|
|
1732
|
+
# -> 0, truncation toward zero, and +/-Infinity clamped to +/-2**53 so
|
|
1733
|
+
# the caller's range check treats it as out of range instead of
|
|
1734
|
+
# `Float#to_i` raising FloatDomainError.
|
|
1735
|
+
def to_integer_or_infinity(value)
|
|
1736
|
+
n = number(value)
|
|
1737
|
+
return 0 if n.respond_to?(:nan?) && n.nan?
|
|
1738
|
+
return MAX_SAFE_INDEX if n >= MAX_SAFE_INDEX
|
|
1739
|
+
return -MAX_SAFE_INDEX if n <= -MAX_SAFE_INDEX
|
|
1740
|
+
|
|
1741
|
+
n.to_i
|
|
1742
|
+
end
|
|
1743
|
+
|
|
1744
|
+
def utf16_has_at?(hay, needle, at)
|
|
1745
|
+
return false if at.negative? || at + needle.length > hay.length
|
|
1746
|
+
|
|
1747
|
+
hay[at, needle.length] == needle
|
|
1748
|
+
end
|
|
1749
|
+
|
|
1750
|
+
def utf16_index_of(recv, elem, reverse)
|
|
1751
|
+
hay = utf16_units(recv)
|
|
1752
|
+
needle = utf16_units(string(elem))
|
|
1753
|
+
last = hay.length - needle.length
|
|
1754
|
+
indices = reverse ? last.downto(0) : 0.upto(last)
|
|
1755
|
+
indices.each { |i| return i if utf16_has_at?(hay, needle, i) }
|
|
1756
|
+
-1
|
|
1757
|
+
end
|
|
1758
|
+
|
|
1759
|
+
def utf16_at(recv, i)
|
|
1760
|
+
return nil if i.nil?
|
|
1761
|
+
|
|
1762
|
+
units = utf16_units(recv)
|
|
1763
|
+
idx = to_integer_or_infinity(i)
|
|
1764
|
+
idx += units.length if idx.negative?
|
|
1765
|
+
return nil if idx.negative? || idx >= units.length
|
|
1766
|
+
|
|
1767
|
+
u = units[idx]
|
|
1768
|
+
(0xD800..0xDFFF).cover?(u) ? "\uFFFD" : [u].pack('U')
|
|
1769
|
+
end
|
|
1770
|
+
|
|
1700
1771
|
def clamp_index(n, len)
|
|
1701
1772
|
n = 0 if n.negative?
|
|
1702
1773
|
n = len if n > len
|