barefoot_js 0.39.3 → 0.39.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a105aa386a05bd1cf0cc0fd24fd58516c1b65f7c83b25f448d6e2078af7d592b
4
- data.tar.gz: 50010c52f3a90fd2f7f80d2860c7c41efa56f628b8c82309b09593ddae08e978
3
+ metadata.gz: 4c4ebbb9319c464c569e177922099bf053ac8a57173ca1dd51e72ac45e68b27b
4
+ data.tar.gz: f211b6e607b11d954e29967c6cca359aa459853ce61c2979b3e415fb685a0db7
5
5
  SHA512:
6
- metadata.gz: 9447dbc63c3764e2963a3a3910468c4d63d4b0b2fb4c974648a0a693f61126ae4ca49cc677f547193618bc747f3db9638b13c529a5a2733c12159c362c420af6
7
- data.tar.gz: 6f7b774ec12dc05959a0f5b230001edddc2328403733b715c686097a6dab970faca390e56144e1e6e72badb8a96f88736559e4808acc9f43d5e042b11e6935c7
6
+ metadata.gz: 56ad319dee5b7974e917321dce07fef04f435e1a9c1f96ba365930eb0671bc671ba60777bfafb58f128f306d6c6edce9e4b8cf08856f4a37ee7e371693eb1ac1
7
+ data.tar.gz: 4ac7bcb135489b27fa363d9549af7421c1e21108dbb30acbc6292730b6b2460bb7c9167c9d2b8342e91a5d9325da5434525dff64ec9d1143c9af93b52f8bc8bd
@@ -225,38 +225,67 @@ module BarefootJS
225
225
  end
226
226
  private_class_method :parse_numeric_string
227
227
 
228
- # JS Number#toString. Integral finite values (however they arrived --
229
- # Integer or an integral Float) render without a decimal point
230
- # ("1.0" -> "1"); non-finite values use the JS spellings ("NaN" /
231
- # "Infinity" / "-Infinity"), which Ruby's own Float#to_s does not use.
232
- # Non-integral floats fall back to Ruby's shortest-round-trip Float#to_s
233
- # (the same class of algorithm V8 uses), reformatted to JS's exponent
234
- # style. This is not the full ECMA-262 Number::toString grammar (no
235
- # attempt to match JS's exact exponential-notation thresholds), but it
236
- # is exact for every value the golden vectors exercise.
228
+ # JS Number#toString. Integral finite values below 2**53 (however they
229
+ # arrived -- Integer or an integral Float) render exactly, without a
230
+ # decimal point ("1.0" -> "1"); non-finite values use the JS spellings
231
+ # ("NaN" / "Infinity" / "-Infinity"), which Ruby's own Float#to_s does
232
+ # not use. Everything else takes Ruby's shortest-round-trip Float#to_s
233
+ # digits (the same digits V8 picks) re-spelled with ECMA-262's notation
234
+ # rules: decimal within [1e-6, 1e21), otherwise an unpadded lower-case
235
+ # exponent (`1.23456789e-7`, `1.23456789e+21`) -- Ruby switches to an
236
+ # exponent below 1e-4 and pads it (`1.23456789e-06`) (#3380).
237
237
  def number_to_string(n)
238
238
  f = n.to_f
239
239
  return 'NaN' if f.nan?
240
240
  return f.negative? ? '-Infinity' : 'Infinity' if f.infinite?
241
241
  return '0' if f.zero?
242
- return n.to_i.to_s if f == f.to_i && f.abs < 1e21
243
-
244
- s = f.to_s
245
- if s.include?('e')
246
- mantissa, exp = s.split('e')
247
- mantissa = mantissa.sub(/\.0\z/, '')
248
- sign = exp.start_with?('-') ? '-' : '+'
249
- digits = exp.sub(/\A[+-]/, '').sub(/\A0+(?=\d)/, '')
250
- "#{mantissa}e#{sign}#{digits}"
251
- else
252
- s
253
- end
242
+ return n.to_i.to_s if f == f.to_i && f.abs < 2**53
243
+
244
+ js_notation(f.to_s)
245
+ end
246
+
247
+ # Re-spell a shortest round-trip decimal (`[-]d[.ddd][e[+-]x]`) with the
248
+ # ECMA-262 Number::toString notation rules: `digits` holds the
249
+ # significant digits, `point` where the decimal point falls in them.
250
+ def js_notation(shortest)
251
+ sign = shortest.start_with?('-') ? '-' : ''
252
+ mantissa, exp = shortest.delete_prefix('-').downcase.split('e', 2)
253
+ int_part, frac_part = mantissa.split('.', 2)
254
+ raw = int_part + (frac_part || '')
255
+ point = int_part.length + (exp ? exp.to_i : 0)
256
+ digits = raw.sub(/\A0+/, '')
257
+ point -= raw.length - digits.length
258
+ digits = digits.sub(/0+\z/, '')
259
+ digits = '0' if digits.empty?
260
+ k = digits.length
261
+ out =
262
+ if k <= point && point <= 21
263
+ digits + ('0' * (point - k))
264
+ elsif point.positive? && point <= 21
265
+ "#{digits[0, point]}.#{digits[point..]}"
266
+ elsif point > -6 && point <= 0
267
+ "0.#{'0' * -point}#{digits}"
268
+ else
269
+ e = point - 1
270
+ "#{digits[0]}#{k > 1 ? ".#{digits[1..]}" : ''}e#{e >= 0 ? '+' : '-'}#{e.abs}"
271
+ end
272
+ sign + out
254
273
  end
274
+ private_class_method :js_notation
255
275
 
256
276
  # ---------------------------------------------------------------------
257
277
  # Operators
258
278
  # ---------------------------------------------------------------------
259
279
 
280
+ # JS `/`: both operands through `to_number` (JS `Number()`), then IEEE
281
+ # Float division, which already gives JS's division-by-zero results
282
+ # (`1 / 0` -> Infinity, `1 / -0` -> -Infinity, `0 / 0` -> NaN). Shared by
283
+ # callback-body evaluation (`binary`) and template-emitted division
284
+ # (`Context#div`), so both coerce and divide identically (#3328).
285
+ def divide(l, r)
286
+ to_number(l).to_f / to_number(r).to_f
287
+ end
288
+
260
289
  def binary(op, l, r)
261
290
  case op
262
291
  when '+'
@@ -267,19 +296,7 @@ module BarefootJS
267
296
  to_number(l) + to_number(r)
268
297
  when '-' then to_number(l) - to_number(r)
269
298
  when '*' then to_number(l) * to_number(r)
270
- when '/'
271
- ln = to_number(l).to_f
272
- rn = to_number(r).to_f
273
- if rn.zero?
274
- # JS division by zero is finite-valued, not an error.
275
- if ln.zero? || ln.nan?
276
- Float::NAN
277
- else
278
- ln.positive? ? Float::INFINITY : -Float::INFINITY
279
- end
280
- else
281
- ln / rn
282
- end
299
+ when '/' then divide(l, r)
283
300
  when '%'
284
301
  rn = to_number(r).to_f
285
302
  rn.zero? ? Float::NAN : to_number(l).to_f.remainder(rn)
data/lib/barefoot_js.rb CHANGED
@@ -521,6 +521,15 @@ module BarefootJS
521
521
  html_escape(string(value))
522
522
  end
523
523
 
524
+ # JS `/`: always a Number quotient. Ruby's `/` on two Integers is
525
+ # integer division (`1234567890 / 4` -> `308641972`, `-7 / 4` -> `-2`),
526
+ # so template-emitted division goes through the shared evaluator's JS
527
+ # division instead -- JS operand coercion, fractional quotient kept,
528
+ # division by zero yielding Infinity / -Infinity / NaN (#3328).
529
+ def div(left, right)
530
+ Evaluator.divide(left, right)
531
+ end
532
+
524
533
  # JS truthiness (falsy: false, nil, 0, NaN, ""). Delegates to the
525
534
  # shared evaluator so template-emitted conditionals
526
535
  # (`if bf.truthy?(x)`) and callback-body evaluation agree byte-for-byte.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: barefoot_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.39.3
4
+ version: 0.39.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - kobaken
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-05 00:00:00.000000000 Z
11
+ date: 2026-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tzinfo