Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ForEachOwnPropertyKeyStep #201

Merged
merged 13 commits into from
Jan 18, 2024

This file was deleted.

3 changes: 1 addition & 2 deletions src/main/resources/manuals/default/rule.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
"Set _obj_'s essential internal methods to the default ordinary object definitions specified in <emu-xref href=\"#sec-ordinary-object-internal-methods-and-internal-slots\"></emu-xref>.": "nop",
"Set the bound value for _N_ in _envRec_ to _V_.": "envRec.SubMap[N].BoundValue = V",
"_op_ is `|`. Let _result_ be the result of applying the bitwise inclusive OR operation to _lbits_ and _rbits_.": "let result = (| lbits rbits)",
"change its bound value to _V_.": "envRec.SubMap[N].BoundValue = V",
"For each own property key _P_ of _A_ such that _P_ is an array index and ! ToUint32(_P_) ≥ _newLen_, in descending numeric index order, do\n 1. Let _deleteSucceeded_ be ! _A_.[[Delete]](_P_).\n 1. If _deleteSucceeded_ is *false*, then\n 1. Set _newLenDesc_.[[Value]] to ! ToUint32(_P_) + *1*<sub>𝔽</sub>.\n 1. If _newWritable_ is *false*, set _newLenDesc_.[[Writable]] to *false*.\n 1. Perform ! OrdinaryDefineOwnProperty(_A_, *\"length\"*, _newLenDesc_).\n 1. Return *false*.": "{ %9 = (keys-int A.SubMap) %8 = %9.length loop[foreach-array] (< 0 %8) { %8 = (- %8 1) let P = %9[%8] if (&& (array-index P) (! (< ([number] P) newLen))) { method-call %10 = A->Delete(P) let deleteSucceeded = [! %10] if (= deleteSucceeded false) { call %11 = clo<ToUint32>(P) newLenDesc.Value = (+ [! %11] 1.0f) if (= newWritable false) { newLenDesc.Writable = false } else {} call %12 = clo<OrdinaryDefineOwnProperty>(A, \"length\", newLenDesc) [! %12] return false } else {} } else {} } }"
"change its bound value to _V_.": "envRec.SubMap[N].BoundValue = V"
}
}
10 changes: 9 additions & 1 deletion src/main/resources/manuals/default/test262/categorized.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,18 @@
"language/expressions/conditional/tco-pos",
"language/expressions/logical-and/tco-right",
"language/expressions/logical-or/tco-right",
"language/expressions/tagged-template/tco-call",
"language/expressions/tagged-template/tco-member",
"language/expressions/tco-pos",
"language/reserved-words/ident-name-keyword-accessor",
"language/reserved-words/ident-name-keyword-prop-name",
"language/statements/block/tco-stmt",
"language/statements/block/tco-stmt-list",
"language/statements/do-while/S12.6.1_A4_T5",
"language/statements/do-while/S12.6.1_A5",
"language/statements/do-while/S12.6.1_A8",
"language/statements/do-while/S12.6.1_A9",
"language/statements/do-while/cptn-abrupt-empty",
"language/statements/do-while/tco-body",
"language/statements/for/tco-const-body",
"language/statements/for/tco-let-body",
Expand All @@ -293,7 +300,8 @@
"language/statements/try/tco-catch-finally",
"language/statements/try/tco-finally",
"language/statements/while/tco-body",
"language/types/number/8.5.1"
"language/types/number/8.5.1",
"language/types/number/S8.5_A13_T2"
],
"wrong": [
"built-ins/AsyncGeneratorPrototype/return/return-state-completed-broken-promise",
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/result/complete-funcs
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,7 @@ StrUnsignedDecimalLiteral[3,1].StringNumericValue
StringCreate
StringExoticObject.DefineOwnProperty
StringExoticObject.GetOwnProperty
StringExoticObject.OwnPropertyKeys
StringGetOwnProperty
StringIndexOf
StringNumericLiteral[0,0].StringNumericValue
Expand Down
12 changes: 6 additions & 6 deletions src/main/resources/result/spec-summary
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
- numeric string: 17
- syntactic: 195
- extended productions for web: 28
- algorithms: 2656 (88.78%)
- complete: 2358
- incomplete: 298
- algorithm steps: 19559 (96.62%)
- complete: 18898
- incomplete: 661
- algorithms: 2656 (88.86%)
- complete: 2360
- incomplete: 296
- algorithm steps: 19567 (96.66%)
- complete: 18914
- incomplete: 653
- types: 7000 (91.49%)
- known: 6404
- yet: 596
Expand Down
27 changes: 11 additions & 16 deletions src/main/scala/esmeta/compiler/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -275,35 +275,30 @@ class Compiler(
},
),
)
case ForEachArrayIndexStep(x, array, start, ascending, body) =>
case ForEachOwnPropertyKeyStep(x, obj, cond, ascending, order, body) =>
val (i, iExpr) = fb.newTIdWithExpr
val (list, listExpr) = fb.newTIdWithExpr
val (key, keyExpr) = compileWithExpr(x)
val intSorted = order == ForEachOwnPropertyKeyStepOrder.NumericIndexOrder
fb.addInst(
IAssign(list, EKeys(toStrERef(compile(fb, array), "SubMap"), true)),
IAssign(i, toStrERef(list, "length")),
IAssign(list, EKeys(toStrERef(compile(fb, obj), "SubMap"), intSorted)),
if (ascending) IAssign(i, zero)
else IAssign(i, toStrERef(list, "length")),
ILoop(
"foreach-array",
lessThan(zero, iExpr),
"repeat",
if (ascending) lessThan(iExpr, toStrERef(list, "length"))
else lessThan(zero, iExpr),
fb.newScope {
val cond = and(
EIsArrayIndex(keyExpr),
not(
lessThan(
EConvert(COp.ToNumber, keyExpr),
compile(fb, start),
),
),
)
fb.addInst(IAssign(i, sub(iExpr, one)))
if (!ascending) fb.addInst(IAssign(i, sub(iExpr, one)))
fb.addInst(ILet(key, toERef(list, iExpr)))
fb.addInst(
IIf(
cond,
compile(fb, cond),
compileWithScope(fb, body),
emptyInst,
),
)
if (ascending) fb.addInst(IAssign(i, add(iExpr, one)))
},
),
)
Expand Down
11 changes: 7 additions & 4 deletions src/main/scala/esmeta/lang/Step.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,17 @@ case class ForEachIntegerStep(
body: Step,
) extends Step

// for-each steps for array index property
case class ForEachArrayIndexStep(
// for-each steps for OwnPropertyKey
case class ForEachOwnPropertyKeyStep(
key: Variable,
array: Variable,
start: Expression,
obj: Variable,
cond: Condition,
ascending: Boolean,
order: ForEachOwnPropertyKeyStepOrder,
body: Step,
) extends Step
enum ForEachOwnPropertyKeyStepOrder extends LangElem:
case NumericIndexOrder, ChronologicalOrder

// for-each steps for parse node
case class ForEachParseNodeStep(
Expand Down
22 changes: 14 additions & 8 deletions src/main/scala/esmeta/lang/util/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ trait Parsers extends IndentParsers {
removeFirstStep |
removeCtxtStep |
ifStep |
forEachArrayIndexStep |
forEachOwnPropertyKeyStep |
forEachStep |
forEachIntStep |
forEachParseNodeStep |
Expand Down Expand Up @@ -160,15 +160,21 @@ trait Parsers extends IndentParsers {
ForEachIntegerStep(x, low, high, asc, body)
}

// for-each steps for array index property
lazy val forEachArrayIndexStep: PL[ForEachArrayIndexStep] =
// for-each steps for OwnPropertyKey
lazy val forEachOwnPropertyKeyStep: PL[ForEachOwnPropertyKeyStep] =
import ForEachOwnPropertyKeyStepOrder.*
lazy val ascending: Parser[Boolean] =
opt("in descending numeric index order,") ^^ { !_.isDefined }
("ascending" ^^^ true | "descending" ^^^ false)
lazy val order: Parser[ForEachOwnPropertyKeyStepOrder] =
"numeric index order" ^^^ NumericIndexOrder |
"chronological order of property creation" ^^^ ChronologicalOrder
("for each own property key" ~> variable) ~
("of" ~> variable <~ "that is an array index,") ~
("whose numeric value is greater than or equal to" ~> expr <~ ",") ~
ascending ~ (opt("do") ~> step) ^^ {
case k ~ x ~ s ~ a ~ b => ForEachArrayIndexStep(k, x, s, a, b)
("of" ~> variable <~ "such that") ~
cond ~
(", in" ~> ascending) ~
order ~
("," ~ opt("do") ~> step) ^^ {
case k ~ x ~ c ~ a ~ o ~ b => ForEachOwnPropertyKeyStep(k, x, c, a, o, b)
}

// for-each steps for parse node
Expand Down
25 changes: 20 additions & 5 deletions src/main/scala/esmeta/lang/util/Stringifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,16 @@ class Stringifier(detail: Boolean, location: Boolean) {
app >> (if (ascending) "ascending" else "descending") >> " order, "
if (body.isInstanceOf[BlockStep]) app >> "do"
app >> body
case ForEachArrayIndexStep(key, array, start, ascending, body) =>
app >> First("for each own property key ") >> key >> " of " >> array
app >> " that is an array index,"
app >> " whose numeric value is greater than or equal to "
app >> start >> ", " >> "in descending numeric index order, "
case ForEachOwnPropertyKeyStep(key, obj, cond, ascending, order, body) =>
import ForEachOwnPropertyKeyStepOrder.*
app >> First("for each own property key ") >> key >> " of " >> obj
app >> " such that " >> cond >> ", in "
if (ascending) app >> "ascending " else app >> "descending "
order match
case NumericIndexOrder => app >> "numeric index order"
case ChronologicalOrder =>
app >> "chronological order of property creation"
app >> ", "
if (body.isInstanceOf[BlockStep]) app >> "do"
app >> body
case ForEachParseNodeStep(x, expr, body) =>
Expand Down Expand Up @@ -203,6 +208,16 @@ class Stringifier(detail: Boolean, location: Boolean) {
app >> expr
}
}

// ForEachOwnPropertyKeyStepOrder
given ForEachOwnPropertyKeyStepOrderRule
: Rule[ForEachOwnPropertyKeyStepOrder] =
(app, order) =>
import ForEachOwnPropertyKeyStepOrder.*
app >> (order match
case NumericIndexOrder => "numeric index order"
case ChronologicalOrder => "chronological order of property creation"
)
private case class First(str: String)
private def firstRule(upper: Boolean): Rule[First] = (app, first) => {
val First(str) = first
Expand Down
25 changes: 14 additions & 11 deletions src/main/scala/esmeta/lang/util/UnitWalker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import esmeta.lang.*
/** a unit walker for metalanguage */
trait UnitWalker extends BasicUnitWalker {
def walk(elem: LangElem): Unit = elem match {
case elem: Syntax => walk(elem)
case elem: ConversionExpressionOperator => walk(elem)
case elem: PredicateConditionOperator => walk(elem)
case elem: MathFuncExpressionOperator => walk(elem)
case elem: BinaryExpressionOperator => walk(elem)
case elem: UnaryExpressionOperator => walk(elem)
case elem: XRefExpressionOperator => walk(elem)
case elem: BinaryConditionOperator => walk(elem)
case elem: CompoundConditionOperator => walk(elem)
case elem: Syntax => walk(elem)
case elem: ForEachOwnPropertyKeyStepOrder => walk(elem)
case elem: ConversionExpressionOperator => walk(elem)
case elem: PredicateConditionOperator => walk(elem)
case elem: MathFuncExpressionOperator => walk(elem)
case elem: BinaryExpressionOperator => walk(elem)
case elem: UnaryExpressionOperator => walk(elem)
case elem: XRefExpressionOperator => walk(elem)
case elem: BinaryConditionOperator => walk(elem)
case elem: CompoundConditionOperator => walk(elem)
}

def walk(syn: Syntax): Unit = syn match {
Expand Down Expand Up @@ -63,8 +64,8 @@ trait UnitWalker extends BasicUnitWalker {
walkOpt(ty, walk); walk(elem); walk(expr); 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 ForEachOwnPropertyKeyStep(key, obj, cond, ascending, order, body) =>
walk(key); walk(obj); walk(cond); walk(body)
case ForEachParseNodeStep(x, expr, body) =>
walk(x); walk(expr); walk(body)
case ThrowStep(expr) => walk(expr)
Expand Down Expand Up @@ -168,6 +169,8 @@ trait UnitWalker extends BasicUnitWalker {
walk(lit)
}

def walk(order: ForEachOwnPropertyKeyStepOrder): Unit = {}

def walk(op: MathOpExpressionOperator): Unit = {}

def walk(op: MathFuncExpressionOperator): Unit = {}
Expand Down
32 changes: 19 additions & 13 deletions src/main/scala/esmeta/lang/util/Walker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import esmeta.lang.*
/** a walker for metalanguage */
trait Walker extends BasicWalker {
def walk(elem: LangElem): LangElem = elem match {
case elem: Syntax => walk(elem)
case elem: ConversionExpressionOperator => walk(elem)
case elem: PredicateConditionOperator => walk(elem)
case elem: MathFuncExpressionOperator => walk(elem)
case elem: BinaryExpressionOperator => walk(elem)
case elem: UnaryExpressionOperator => walk(elem)
case elem: XRefExpressionOperator => walk(elem)
case elem: BinaryConditionOperator => walk(elem)
case elem: CompoundConditionOperator => walk(elem)
case elem: Syntax => walk(elem)
case elem: ForEachOwnPropertyKeyStepOrder => walk(elem)
case elem: ConversionExpressionOperator => walk(elem)
case elem: PredicateConditionOperator => walk(elem)
case elem: MathFuncExpressionOperator => walk(elem)
case elem: BinaryExpressionOperator => walk(elem)
case elem: UnaryExpressionOperator => walk(elem)
case elem: XRefExpressionOperator => walk(elem)
case elem: BinaryConditionOperator => walk(elem)
case elem: CompoundConditionOperator => walk(elem)
}

def walk(syn: Syntax): Syntax = syn match {
Expand Down Expand Up @@ -75,12 +76,13 @@ trait Walker extends BasicWalker {
ascending,
walk(body),
)
case ForEachArrayIndexStep(key, array, start, ascending, body) =>
ForEachArrayIndexStep(
case ForEachOwnPropertyKeyStep(key, obj, cond, ascending, order, body) =>
ForEachOwnPropertyKeyStep(
walk(key),
walk(array),
walk(start),
walk(obj),
walk(cond),
ascending,
walk(order),
walk(body),
)
case ForEachParseNodeStep(x, expr, body) =>
Expand Down Expand Up @@ -205,6 +207,10 @@ trait Walker extends BasicWalker {
UnaryExpression(walk(op), walk(expr))
}

def walk(
order: ForEachOwnPropertyKeyStepOrder,
): ForEachOwnPropertyKeyStepOrder = order

def walk(op: MathOpExpressionOperator): MathOpExpressionOperator = op

def walk(op: MathFuncExpressionOperator): MathFuncExpressionOperator = op
Expand Down
11 changes: 8 additions & 3 deletions src/test/scala/esmeta/lang/JsonTinyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@ class JsonTinyTest extends LangTest {
"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
| 1. Let _x_ be _x_.""".stripMargin,
forEachAscOPKStep -> (
"for each own property key _x_ of _x_ such that _x_ and _x_, in ascending numeric index order, " +
"let _x_ be _x_."
),
forEachDscOPKStep -> (
"for each own property key _x_ of _x_ such that _x_ and _x_, in descending chronological order of property creation, " +
"let _x_ be _x_."
),
throwStep -> "throw a newly created *TypeError* object.",
performStep -> "perform ToObject(_x_ + _x_, -_x_).",
appendStep -> "append _x_ to _x_.[[Value]].",
Expand Down
18 changes: 16 additions & 2 deletions src/test/scala/esmeta/lang/LangTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,22 @@ object LangTest {
false,
letStep,
)
lazy val forEachArrayIndexStep =
ForEachArrayIndexStep(x, x, refExpr, false, blockStep)
lazy val forEachAscOPKStep = ForEachOwnPropertyKeyStep(
x,
x,
compCond,
true,
ForEachOwnPropertyKeyStepOrder.NumericIndexOrder,
letStep,
)
lazy val forEachDscOPKStep = ForEachOwnPropertyKeyStep(
x,
x,
compCond,
false,
ForEachOwnPropertyKeyStepOrder.ChronologicalOrder,
letStep,
)
lazy val throwStep = ThrowStep(errObj)
lazy val performStep = PerformStep(invokeAOExpr)
lazy val appendStep = AppendStep(refExpr, fieldRef)
Expand Down
Loading
Loading