diff --git a/src/main/resources/manuals/d711ba960cd12b76/bugfix.patch b/src/main/resources/manuals/d711ba960cd12b76/bugfix.patch index 01e63742f1..b0a32558ed 100644 --- a/src/main/resources/manuals/d711ba960cd12b76/bugfix.patch +++ b/src/main/resources/manuals/d711ba960cd12b76/bugfix.patch @@ -1,5 +1,5 @@ diff --git a/spec.html b/spec.html -index 5a4af52..5d516a1 100644 +index 5a4af52..3753675 100644 --- a/spec.html +++ b/spec.html @@ -7200,7 +7200,7 @@ @@ -110,6 +110,23 @@ index 5a4af52..5d516a1 100644 1. [id="step-assignmentexpression-evaluation-lgcl-nullish-getvalue"] Let _lval_ be ? GetValue(_lref_). 1. If _lval_ is neither *undefined* nor *null*, return _lval_. 1. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then +@@ -33723,12 +33723,12 @@ THH:mm:ss.sss + 1. Let _searchStr_ be ? ToString(_searchString_). + 1. Let _numPos_ be ? ToNumber(_position_). + 1. Assert: If _position_ is *undefined*, then _numPos_ is *NaN*. +- 1. If _numPos_ is *NaN*, let _pos_ be +∞; otherwise, let _pos_ be ! ToIntegerOrInfinity(_numPos_). ++ 1. If _numPos_ is *NaN*, let _pos_ be +∞; otherwise, let _pos_ be ! ToIntegerOrInfinity(_numPos_). + 1. Let _len_ be the length of _S_. +- 1. Let _start_ be the result of clamping _pos_ between 0 and _len_. +- 1. If _searchStr_ is the empty String, return 𝔽(_start_). + 1. Let _searchLen_ be the length of _searchStr_. +- 1. For each non-negative integer _i_ starting with _start_ such that _i_ ≤ _len_ - _searchLen_, in descending order, do ++ 1. Let _start_ be the result of clamping _pos_ between 0 and _len_ - _searchLen_. ++ 1. If _searchStr_ is the empty String, return 𝔽(_start_). ++ 1. For each integer _i_ such that 0 ≤ _i_ ≤ _start_, in descending order, do + 1. Let _candidate_ be the substring of _S_ from _i_ to _i_ + _searchLen_. + 1. If _candidate_ is the same sequence of code units as _searchStr_, return 𝔽(_i_). + 1. Return *-1*𝔽. @@ -34371,7 +34371,7 @@ THH:mm:ss.sss 1. Let _resultString_ be the substring of _s_ from _position_ to _nextIndex_. 1. Set _position_ to _nextIndex_. diff --git a/src/main/resources/manuals/default/test262/filtered.json b/src/main/resources/manuals/default/test262/filtered.json index be98127a81..510d1eec7e 100644 --- a/src/main/resources/manuals/default/test262/filtered.json +++ b/src/main/resources/manuals/default/test262/filtered.json @@ -332,14 +332,14 @@ "built-ins/GeneratorPrototype/throw/try-finally-within-try", "built-ins/Map/prototype/clear/map-data-list-is-preserved", "built-ins/Map/prototype/delete/does-not-break-iterators", - "built-ins/Map/prototype/entries/returns-iterator-empty", "built-ins/Map/prototype/entries/returns-iterator", - "built-ins/Map/prototype/keys/returns-iterator-empty", + "built-ins/Map/prototype/entries/returns-iterator-empty", "built-ins/Map/prototype/keys/returns-iterator", - "built-ins/Map/prototype/values/returns-iterator-empty", + "built-ins/Map/prototype/keys/returns-iterator-empty", "built-ins/Map/prototype/values/returns-iterator", - "built-ins/MapIteratorPrototype/next/iteration-mutable", + "built-ins/Map/prototype/values/returns-iterator-empty", "built-ins/MapIteratorPrototype/next/iteration", + "built-ins/MapIteratorPrototype/next/iteration-mutable", "built-ins/Number/prototype/S15.7.3.1_A3", "built-ins/Number/prototype/S15.7.4_A1", "built-ins/Object/S15.2.1.1_A2_T12", @@ -364,13 +364,13 @@ "built-ins/Promise/all/iter-arg-is-string-resolve", "built-ins/Promise/allSettled/iter-arg-is-string-resolve", "built-ins/Promise/any/iter-arg-is-empty-string-reject", - "built-ins/Set/prototype/entries/returns-iterator-empty", "built-ins/Set/prototype/entries/returns-iterator", - "built-ins/Set/prototype/values/returns-iterator-empty", + "built-ins/Set/prototype/entries/returns-iterator-empty", "built-ins/Set/prototype/values/returns-iterator", + "built-ins/Set/prototype/values/returns-iterator-empty", "built-ins/Set/prototype/values/values-iteration-mutable", - "built-ins/SetIteratorPrototype/next/iteration-mutable", "built-ins/SetIteratorPrototype/next/iteration", + "built-ins/SetIteratorPrototype/next/iteration-mutable", "built-ins/String/S15.5.2.1_A1_T1", "built-ins/String/S15.5.2.1_A1_T10", "built-ins/String/S15.5.2.1_A1_T11", @@ -522,9 +522,13 @@ "language/expressions/generators/dstr/dflt-ary-ptrn-elision-step-err", "language/expressions/generators/dstr/dflt-ary-ptrn-rest-id-elision-next-err", "language/expressions/generators/dstr/dflt-ary-ptrn-rest-id-iter-step-err", + "language/expressions/generators/named-strict-error-reassign-fn-name-in-body", "language/expressions/generators/named-strict-error-reassign-fn-name-in-body-in-arrow", "language/expressions/generators/named-strict-error-reassign-fn-name-in-body-in-eval", - "language/expressions/generators/named-strict-error-reassign-fn-name-in-body", + "language/expressions/greater-than-or-equal/bigint-and-number-extremes", + "language/expressions/greater-than/bigint-and-number-extremes", + "language/expressions/less-than-or-equal/bigint-and-number-extremes", + "language/expressions/less-than/bigint-and-number-extremes", "language/expressions/logical-assignment/lgcl-and-assignment-operator-lhs-before-rhs", "language/expressions/logical-assignment/lgcl-nullish-assignment-operator-lhs-before-rhs", "language/expressions/logical-assignment/lgcl-or-assignment-operator-lhs-before-rhs", @@ -647,13 +651,13 @@ "language/statements/for-of/dstr/var-ary-ptrn-rest-id-elision-next-err", "language/statements/for-of/dstr/var-ary-ptrn-rest-id-iter-step-err", "language/statements/for-of/generator-next-error", - "language/statements/for-of/map-contract-expand", + "language/statements/for-of/map", "language/statements/for-of/map-contract", - "language/statements/for-of/map-expand-contract", + "language/statements/for-of/map-contract-expand", "language/statements/for-of/map-expand", - "language/statements/for-of/map", - "language/statements/for-of/set-expand", + "language/statements/for-of/map-expand-contract", "language/statements/for-of/set", + "language/statements/for-of/set-expand", "language/statements/for/dstr/const-ary-ptrn-elision-step-err", "language/statements/for/dstr/const-ary-ptrn-rest-id-elision-next-err", "language/statements/for/dstr/const-ary-ptrn-rest-id-iter-step-err", diff --git a/src/main/scala/esmeta/compiler/Compiler.scala b/src/main/scala/esmeta/compiler/Compiler.scala index 099fac1713..5174ea27e4 100644 --- a/src/main/scala/esmeta/compiler/Compiler.scala +++ b/src/main/scala/esmeta/compiler/Compiler.scala @@ -259,13 +259,15 @@ class Compiler( }, ), ) - case ForEachIntegerStep(x, start, cond, ascending, body) => + case ForEachIntegerStep(x, low, high, ascending, body) => + val (start, end) = if (ascending) (low, high) else (high, low) val (i, iExpr) = compileWithExpr(x) fb.addInst(ILet(i, compile(fb, start))) fb.addInst( ILoop( "foreach-int", - compile(fb, cond), + if (ascending) not(lessThan(compile(fb, end), iExpr)) + else not(lessThan(iExpr, compile(fb, end))), fb.newScope { compile(fb, body) val op = if (ascending) add(_, _) else sub(_, _) diff --git a/src/main/scala/esmeta/lang/Step.scala b/src/main/scala/esmeta/lang/Step.scala index 26046e2c55..a9de9cf37a 100644 --- a/src/main/scala/esmeta/lang/Step.scala +++ b/src/main/scala/esmeta/lang/Step.scala @@ -34,8 +34,8 @@ case class ForEachStep( // for-each steps for integers case class ForEachIntegerStep( variable: Variable, - start: Expression, - cond: Condition, + low: Expression, + high: Expression, ascending: Boolean, body: Step, ) extends Step diff --git a/src/main/scala/esmeta/lang/util/Parser.scala b/src/main/scala/esmeta/lang/util/Parser.scala index 421b6b368e..df9c7407e3 100644 --- a/src/main/scala/esmeta/lang/util/Parser.scala +++ b/src/main/scala/esmeta/lang/util/Parser.scala @@ -133,15 +133,22 @@ trait Parsers extends IndentParsers { // for-each steps for integers lazy val forEachIntStep: PL[ForEachIntegerStep] = - lazy val ascending: Parser[Boolean] = - ("ascending" ^^^ true | "descending" ^^^ false) + lazy val interval: Parser[(Expression, Expression)] = + ("starting with" ~> expr) ~ ("such that" ~ variable ~> ( + "≤" ^^^ { (x: CalcExpression) => x } | + "<" ^^^ { BinaryExpression(_, BinaryExpressionOperator.Sub, one) } + ) ~ calcExpr) ^^ { + case l ~ (f ~ h) => (l, f(h)) + } | "such that" ~> calcExpr ~ ("≤" ~ variable ~ "≤" ~> calcExpr) ^^ { + case l ~ h => (l, h) + } + lazy val ascending: Parser[Boolean] = opt( + ", in" ~> ("ascending" ^^^ true | "descending" ^^^ false) <~ "order,", + ) ^^ { _.getOrElse(true) } ("for each" ~ "(non-negative )?integer".r ~> variable) ~ - ("starting with" ~> expr) ~ - ("such that" ~> cond) ~ - (", in" ~> ascending <~ "order,") ~ - (opt("do") ~> step) ^^ { - case x ~ start ~ cond ~ asc ~ body => - ForEachIntegerStep(x, start, cond, asc, body) + interval ~ ascending ~ (opt("do") ~> step) ^^ { + case x ~ (low, high) ~ asc ~ body => + ForEachIntegerStep(x, low, high, asc, body) } // for-each steps for array index property @@ -1266,4 +1273,7 @@ trait Parsers extends IndentParsers { // helper for creating expressions, conditions private def getRefExpr(r: Reference): Expression = ReferenceExpression(r) private def getExprCond(e: Expression): Condition = ExpressionCondition(e) + + // literal for mathematical one + private val one = DecimalMathValueLiteral(1) } diff --git a/src/main/scala/esmeta/lang/util/Stringifier.scala b/src/main/scala/esmeta/lang/util/Stringifier.scala index 148b67befd..dbfa66ffa7 100644 --- a/src/main/scala/esmeta/lang/util/Stringifier.scala +++ b/src/main/scala/esmeta/lang/util/Stringifier.scala @@ -106,9 +106,9 @@ class Stringifier(detail: Boolean, location: Boolean) { if (!ascending) app >> "in reverse List order, " if (body.isInstanceOf[BlockStep]) app >> "do" app >> body - case ForEachIntegerStep(x, start, cond, ascending, body) => - app >> First("for each integer ") >> x >> " starting with " >> start - app >> " such that " >> cond >> ", in " + case ForEachIntegerStep(x, low, high, ascending, body) => + app >> First("for each integer ") >> x >> " such that " >> low + app >> " ≤ " >> x >> " ≤ " >> high >> ", in " app >> (if (ascending) "ascending" else "descending") >> " order, " if (body.isInstanceOf[BlockStep]) app >> "do" app >> body diff --git a/src/main/scala/esmeta/lang/util/UnitWalker.scala b/src/main/scala/esmeta/lang/util/UnitWalker.scala index c29d274f0d..34a1663953 100644 --- a/src/main/scala/esmeta/lang/util/UnitWalker.scala +++ b/src/main/scala/esmeta/lang/util/UnitWalker.scala @@ -61,8 +61,8 @@ trait UnitWalker extends BasicUnitWalker { walk(cond) case ForEachStep(ty, elem, expr, ascending, body) => walkOpt(ty, walk); walk(elem); walk(expr); walk(body) - case ForEachIntegerStep(x, start, cond, ascending, body) => - walk(x); walk(start); walk(cond); walk(body) + case ForEachIntegerStep(x, low, high, ascending, body) => + walk(x); walk(low); walk(high); walk(body) case ForEachArrayIndexStep(key, array, start, ascending, body) => walk(key); walk(array); walk(start); walk(body) case ForEachParseNodeStep(x, expr, body) => diff --git a/src/main/scala/esmeta/lang/util/Walker.scala b/src/main/scala/esmeta/lang/util/Walker.scala index d1a090afb0..a9a2d18f55 100644 --- a/src/main/scala/esmeta/lang/util/Walker.scala +++ b/src/main/scala/esmeta/lang/util/Walker.scala @@ -67,11 +67,11 @@ trait Walker extends BasicWalker { ascending, walk(body), ) - case ForEachIntegerStep(x, start, cond, ascending, body) => + case ForEachIntegerStep(x, low, high, ascending, body) => ForEachIntegerStep( walk(x), - walk(start), - walk(cond), + walk(low), + walk(high), ascending, walk(body), ) diff --git a/src/main/scala/esmeta/state/package.scala b/src/main/scala/esmeta/state/package.scala index 76492ca8df..3427be6dd8 100644 --- a/src/main/scala/esmeta/state/package.scala +++ b/src/main/scala/esmeta/state/package.scala @@ -3,7 +3,7 @@ package esmeta.state import esmeta.state.util.* import esmeta.util.BaseUtils.* import esmeta.ir.Global -import java.math.MathContext.UNLIMITED +import java.math.MathContext.{UNLIMITED, DECIMAL128} /** IR state elements */ trait StateElem { @@ -64,58 +64,99 @@ val POS_INF = Number(Double.PositiveInfinity) val NEG_INF = Number(Double.NegativeInfinity) /** conversion number to string */ -def toStringHelper(m: Double, radix: Int = 10): String = { +def toStringHelper(x: Double, radix: Int = 10): String = { // get sign def getSign(n: Int): Char = if (n - 1 > 0) '+' else '-' // get string of number - def getStr(number: Long, radix: Int): String = + def getStr(number: scala.math.BigInt, radix: Int): String = var str = "" - var sLong = number - while (sLong > 0) { str += getRadixString(sLong % radix); sLong /= radix } + var s = number + while (s > 0) { str += getRadixString(s % radix); s /= radix } str.reverse // get radix string of number - def getRadixString(d: Long): String = + def getRadixString(d: scala.math.BigInt): String = if (d < 10) d.toString else ('a' + (d - 10)).toChar.toString - def INT(n: Int): BigDecimal = BigDecimal(n, UNLIMITED) - def DOUBLE(n: Double): BigDecimal = BigDecimal(n, UNLIMITED) - - if (m.isNaN) "NaN" - else if (m == 0) "0" - else if (m < 0) "-" + toStringHelper(-m, radix) - else if (m.isPosInfinity) "Infinity" + // 1. If _x_ is *NaN*, return the String *"NaN"*. + if (x.isNaN) "NaN" + // 2. If _x_ is *+0*𝔽 or *-0*𝔽, return the String + // *"0"*. + else if (x == 0) "0" + // 3. If _x_ < *-0*𝔽, return the string-concatenation of *"-"* and + // toStringHelper(-_x_). + else if (x < 0) "-" + toStringHelper(-x, radix) + // 4. If _x_ is *+∞*𝔽, return the String *"Infinity"*. + else if (x.isPosInfinity) "Infinity" else { - var s = DOUBLE(m) - var n = 0 - while (s % radix == INT(0) || s % 1 != INT(0)) { - if (s % radix == INT(0)) { s /= radix; n += 1 } - else { s *= radix; n -= 1 } - } - while ( - (((s - (s % radix)) / radix) * INT(radix).pow(n + 1)).toDouble == m - ) { - s = (s - (s % radix)) / radix - n = n + 1 - } - var sLong = s.toLong - var k = 0 - while (s >= INT(1)) { s /= radix; k += 1 } - n += k + // 5. Otherwise, let _n_, _k_, and _s_ be integers such that _k_ >= 1, + // _radix__k_ - 1 <= _s_ < _radix__k_, 𝔽(_s_ * + // _radix__n_ - _k_) is _x_, and _k_ is as small as possible. + val (n: Int, k: Int, s: scala.math.BigInt) = + var S = BigDecimal(x, UNLIMITED) + var N = 0 + while (S % radix == 0) { S /= radix; N += 1 } + while (S % 1 != 0) { S *= radix; N -= 1 } + var RK = BigDecimal(radix, UNLIMITED) + var K = 1 + while (S >= RK) { RK *= radix; K += 1 } + (N + K, K, S.toBigInt) + if (k <= n && n <= 21) { - getStr(sLong, radix) + ("0" * (n - k)) + // * the code units of the _k_ digits of the decimal representation of + // _s_ (in order, with no leading zeroes) + getStr(s, radix) + + // * _n_ - _k_ occurrences of the code unit 0x0030 (DIGIT ZERO) + "0" * (n - k) } else if (0 < n && n <= 21) { - val str = getStr(sLong, radix) - str.substring(0, n) + '.' + str.substring(n) + val str = getStr(s, radix) + // * the code units of the most significant _n_ digits of the decimal + // representation of _s_ + str.substring(0, n) + + // * the code unit 0x002E (FULL STOP) + '.' + + // * the code units of the remaining _k_ - _n_ digits of the decimal + // representation of _s_ + str.substring(n) } else if (-6 < n && n <= 0) { - "0." + ("0" * (-n)) + getStr(sLong, radix) + // * the code unit 0x0030 (DIGIT ZERO) + "0" + + // * the code unit 0x002E (FULL STOP) + "." + + // * -_n_ occurrences of the code unit 0x0030 (DIGIT ZERO) + "0" * -n + + // * the code units of the _k_ digits of the decimal representation of _s_ + getStr(s, radix) } else if (k == 1) { - getStr(sLong, radix) + "e" + getSign(n) + math.abs(n - 1).toString + // * the code unit of the single digit of _s_ + getStr(s, radix) + + // * the code unit 0x0065 (LATIN SMALL LETTER E) + "e" + + // * the code unit 0x002B (PLUS SIGN) or the code unit 0x002D + // (HYPHEN-MINUS) according to whether _n_ - 1 is positive or negative + getSign(n) + + // * the code units of the decimal representation of the integer abs(_n_ + // - 1) (with no leading zeroes) + math.abs(n - 1) } else { - val str = getStr(sLong, radix) - str.substring(0, 1) + '.' + str - .substring(1) + 'e' + getSign(n) + math.abs(n - 1).toString + val str = getStr(s, radix) + // * the code units of the most significant digit of the decimal + // representation of _s_ + str.substring(0, 1) + + // * the code unit 0x002E (FULL STOP) + '.' + + // * the code units of the remaining _k_ - 1 digits of the decimal + // representation of _s_ + str.substring(1) + + // * the code unit 0x0065 (LATIN SMALL LETTER E) + 'e' + + // * the code unit 0x002B (PLUS SIGN) or the code unit 0x002D + // (HYPHEN-MINUS) according to whether _n_ - 1 is positive or negative + getSign(n) + + // * the code units of the decimal representation of the integer abs(_n_ + // - 1) (with no leading zeroes) + math.abs(n - 1) } } } diff --git a/src/main/scala/esmeta/state/util/Stringifier.scala b/src/main/scala/esmeta/state/util/Stringifier.scala index a86554d72c..723e200556 100644 --- a/src/main/scala/esmeta/state/util/Stringifier.scala +++ b/src/main/scala/esmeta/state/util/Stringifier.scala @@ -4,6 +4,7 @@ import esmeta.cfg.* import esmeta.state.{*, given} import esmeta.ir.{Func => IRFunc, *, given} import esmeta.es.* +import esmeta.util.BaseUtils.* import esmeta.util.Appender.{given, *} /** stringifier for state elements */ @@ -152,7 +153,7 @@ class Stringifier(detail: Boolean, location: Boolean) { // simple values given svRule: Rule[SimpleValue] = (app, sv) => sv match - case Number(n) => app >> n >> "f" + case Number(n) => app >> toStringHelper(n) case BigInt(n) => app >> n >> "n" case Str(str) => app >> "\"" >> str >> "\"" case Bool(bool) => app >> bool diff --git a/src/test/scala/esmeta/lang/StringifyTinyTest.scala b/src/test/scala/esmeta/lang/StringifyTinyTest.scala index 8f6752f5ee..35d4a86b5e 100644 --- a/src/test/scala/esmeta/lang/StringifyTinyTest.scala +++ b/src/test/scala/esmeta/lang/StringifyTinyTest.scala @@ -66,10 +66,20 @@ class StringifyTinyTest extends LangTest { ForEachStep(Some(ty), x, refExpr, false, letStep) lazy val forEachStepNoType = ForEachStep(None, x, refExpr, true, letStep) - lazy val forEachIntStepTrue = - ForEachIntegerStep(x, refExpr, exprCond, true, letStep) - lazy val forEachIntStepFalse = - ForEachIntegerStep(x, refExpr, exprCond, false, letStep) + lazy val forEachIntStepTrue = ForEachIntegerStep( + x, + DecimalMathValueLiteral(BigDecimal(2)), + DecimalMathValueLiteral(BigDecimal(5)), + true, + letStep, + ) + lazy val forEachIntStepFalse = ForEachIntegerStep( + x, + DecimalMathValueLiteral(BigDecimal(2)), + DecimalMathValueLiteral(BigDecimal(5)), + false, + letStep, + ) lazy val forEachArrayIndexStep = ForEachArrayIndexStep(x, x, refExpr, false, blockStep) lazy val throwStep = ThrowStep(errObj) @@ -133,12 +143,12 @@ class StringifyTinyTest extends LangTest { forEachReverseStep -> "for each Base _x_ of _x_, in reverse List order, let _x_ be _x_.", forEachStepNoType -> "for each _x_ of _x_, let _x_ be _x_.", forEachIntStepTrue -> ( - "for each integer _x_ starting with _x_ such that _x_, " + - "in ascending order, let _x_ be _x_." + "for each integer _x_ such that 2 ≤ _x_ ≤ 5, in ascending order, " + + "let _x_ be _x_." ), forEachIntStepFalse -> ( - "for each integer _x_ starting with _x_ such that _x_, " + - "in descending order, let _x_ be _x_." + "for each integer _x_ such that 2 ≤ _x_ ≤ 5, in descending order, " + + "let _x_ be _x_." ), toBlockStep(forEachArrayIndexStep) -> """ | 1. For each own property key _x_ of _x_ that is an array index, whose numeric value is greater than or equal to _x_, in descending numeric index order, do diff --git a/src/test/scala/esmeta/state/StringifyTinyTest.scala b/src/test/scala/esmeta/state/StringifyTinyTest.scala index be6b041270..d012c7ea65 100644 --- a/src/test/scala/esmeta/state/StringifyTinyTest.scala +++ b/src/test/scala/esmeta/state/StringifyTinyTest.scala @@ -139,7 +139,7 @@ class StringifyTinyTest extends StateTest { lex -> "|Identifier|(x)", nt -> "|Identifier|[TF]", Math(3.2) -> "3.2", - Number(3.2) -> "3.2f", + Number(3.2) -> "3.2", BigInt(324) -> "324n", Str("abc") -> "\"abc\"", Bool(true) -> "true", diff --git a/tests/es/number2.ir b/tests/es/number2.ir index 398043c85b..68d18e372b 100644 --- a/tests/es/number2.ir +++ b/tests/es/number2.ir @@ -1,2 +1,4 @@ let map = @REALM.GlobalObject.SubMap assert (= map.x.Value "20") +assert (= map.y.Value "0.000001") +assert (= map.z.Value "1") diff --git a/tests/es/number2.js b/tests/es/number2.js index e9fbe9a48c..1883b0609a 100644 --- a/tests/es/number2.js +++ b/tests/es/number2.js @@ -1 +1,3 @@ var x = 64.0000.toString(32); +var y = String(1.0E-6); +var z = new Number(1).toString(3);