feat(codemode): support loop sequence syntax (#35618)
This commit is contained in:
parent
8dc9ac07a2
commit
b046bbe4e3
2 changed files with 68 additions and 5 deletions
|
|
@ -1088,7 +1088,7 @@ class Interpreter<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let declaration: { readonly pattern: AstNode; readonly mutable: boolean } | undefined
|
let declaration: { readonly pattern: AstNode; readonly mutable: boolean } | undefined
|
||||||
let assignmentName: string | undefined
|
let assignment: AstNode | undefined
|
||||||
|
|
||||||
if (left.type === "VariableDeclaration") {
|
if (left.type === "VariableDeclaration") {
|
||||||
const declarations = getArray(left, "declarations")
|
const declarations = getArray(left, "declarations")
|
||||||
|
|
@ -1098,8 +1098,13 @@ class Interpreter<R> {
|
||||||
|
|
||||||
const declarator = asNode(declarations[0], "declarations[0]")
|
const declarator = asNode(declarations[0], "declarations[0]")
|
||||||
declaration = { pattern: getNode(declarator, "id"), mutable: getString(left, "kind") !== "const" }
|
declaration = { pattern: getNode(declarator, "id"), mutable: getString(left, "kind") !== "const" }
|
||||||
} else if (left.type === "Identifier") {
|
} else if (
|
||||||
assignmentName = getString(left, "name")
|
left.type === "Identifier" ||
|
||||||
|
left.type === "MemberExpression" ||
|
||||||
|
left.type === "ArrayPattern" ||
|
||||||
|
left.type === "ObjectPattern"
|
||||||
|
) {
|
||||||
|
assignment = left
|
||||||
} else {
|
} else {
|
||||||
throw new InterpreterRuntimeError("Unsupported for...of binding.", left)
|
throw new InterpreterRuntimeError("Unsupported for...of binding.", left)
|
||||||
}
|
}
|
||||||
|
|
@ -1108,8 +1113,8 @@ class Interpreter<R> {
|
||||||
if (declaration) {
|
if (declaration) {
|
||||||
self.pushScope()
|
self.pushScope()
|
||||||
yield* self.declarePattern(declaration.pattern, value, declaration.mutable, left)
|
yield* self.declarePattern(declaration.pattern, value, declaration.mutable, left)
|
||||||
} else if (assignmentName) {
|
} else if (assignment) {
|
||||||
self.setIdentifierValue(assignmentName, value, left)
|
yield* self.assignPattern(assignment, value, left)
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = yield* self.evaluateStatement(body).pipe(
|
const result = yield* self.evaluateStatement(body).pipe(
|
||||||
|
|
@ -1507,6 +1512,16 @@ class Interpreter<R> {
|
||||||
return this.evaluateUnaryExpression(node)
|
return this.evaluateUnaryExpression(node)
|
||||||
case "AssignmentExpression":
|
case "AssignmentExpression":
|
||||||
return this.evaluateAssignmentExpression(node)
|
return this.evaluateAssignmentExpression(node)
|
||||||
|
case "SequenceExpression": {
|
||||||
|
const self = this
|
||||||
|
return Effect.gen(function* () {
|
||||||
|
let result: unknown
|
||||||
|
for (const expression of getArray(node, "expressions")) {
|
||||||
|
result = yield* self.evaluateExpression(asNode(expression, "expressions"))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
case "CallExpression":
|
case "CallExpression":
|
||||||
return this.evaluateCallExpression(node)
|
return this.evaluateCallExpression(node)
|
||||||
case "ArrowFunctionExpression":
|
case "ArrowFunctionExpression":
|
||||||
|
|
|
||||||
|
|
@ -464,6 +464,54 @@ describe("H5: builtin coercion functions work as array callbacks", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("for...of assignment destructuring", () => {
|
||||||
|
test("assigns entry pairs into predeclared variables", async () => {
|
||||||
|
expect(
|
||||||
|
await value(`
|
||||||
|
let key
|
||||||
|
let item
|
||||||
|
const out = []
|
||||||
|
for ([key, item] of Object.entries({ a: 1, b: 2 })) out.push(key + item)
|
||||||
|
return { key, item, out }
|
||||||
|
`),
|
||||||
|
).toEqual({ key: "b", item: 2, out: ["a1", "b2"] })
|
||||||
|
})
|
||||||
|
|
||||||
|
test("assigns object patterns and defaults", async () => {
|
||||||
|
expect(
|
||||||
|
await value(`
|
||||||
|
let id
|
||||||
|
let label
|
||||||
|
const labels = []
|
||||||
|
for ({ id, label = "unknown" } of [{ id: 1 }, { id: 2, label: "two" }]) labels.push(label)
|
||||||
|
return { id, label, labels }
|
||||||
|
`),
|
||||||
|
).toEqual({ id: 2, label: "two", labels: ["unknown", "two"] })
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("sequence expressions", () => {
|
||||||
|
test("evaluate left to right and return the final value", async () => {
|
||||||
|
expect(await value(`let x = 0; const result = (x += 1, x *= 3, x + 2); return { x, result }`)).toEqual({
|
||||||
|
x: 3,
|
||||||
|
result: 5,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test("support comma-separated for-loop updates", async () => {
|
||||||
|
expect(
|
||||||
|
await value(`
|
||||||
|
const pairs = []
|
||||||
|
for (let left = 0, right = 3; left < right; left++, right--) pairs.push([left, right])
|
||||||
|
return pairs
|
||||||
|
`),
|
||||||
|
).toEqual([
|
||||||
|
[0, 3],
|
||||||
|
[1, 2],
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("destructuring assignment", () => {
|
describe("destructuring assignment", () => {
|
||||||
test("assigns object and array patterns to existing bindings", async () => {
|
test("assigns object and array patterns to existing bindings", async () => {
|
||||||
expect(
|
expect(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue