Improve handling of frame slots (#1634)

This makes various improvements to the handling of frame slot vars, and
includes some bug fixes introduced by
https://github.com/apple/pkl/pull/1622

* Refactor SymbolTable to track for-generator and parameter slots in
each scope
* Execute let expressions in their own root node in some places
* Unify how frame slots are managed; they are all represented as
`FrameSlotVariable`, created in `AstBuilder`, and passed into
`SymbolTable`.
* Fix how let expressions are executed in custom this scopes (introduce
a new root node when needed)
This commit is contained in:
Daniel Chao
2026-06-10 20:02:42 -07:00
committed by GitHub
parent 27fe06c796
commit 84d2c32d10
30 changed files with 1000 additions and 278 deletions
@@ -0,0 +1,30 @@
// let expr inside custom this scopes
typealias Foo = String(let (x = this) this == x)
typealias Foo2 = String(let (x = "foo") this.startsWith(x), let (y = "o") this.endsWith(y))
typealias Foo3 = String(let (x = "foo") this.startsWith(x))(let (y = "o") this.endsWith(y))
res1: Foo = "foo"
res2: Foo2 = "foo"
res3: Foo3 = "foo"
hidden bar {
new {
name = "fooey"
}
}
res4 = (bar) {
[[let (x = "foo") this.name.startsWith(x)]] {
name = "bob"
}
}
res5 = (bar) {
[[let (x = this) x.name.startsWith("foo")]] {
name = "bob"
}
}
@@ -0,0 +1,53 @@
res =
let (
x = new Listing {
for (elem in List(1, 2)) {
elem + 5
}
}
)
x
res2 =
let (qux = 1)
let (
x = new Listing {
for (num in List(1, 2)) {
qux + num
}
}
)
x
res3 =
let (qux = 1)
let (
x = new Listing {
for (num in List(1, 2)) {
qux + num
}
}
)
let (y = 5)
let (
z = new Listing {
for (nummm in List(1, 2)) {
when (qux + y == nummm) {
nummm + y
}
}
}
)
new { ...x; ...z }
res4 =
let (m: Mapping<String, String> = new Mapping {
["foo"] = "bar"
})
new Mapping {
for (k, _ in Map("foo", "bar")) {
[k] {
m[k]
}
}
}
@@ -0,0 +1,11 @@
prop = "qux"
res =
new Mapping {
default {
when (module.prop == "qux") {
myProp = "qux"
}
}
["bar"] {}
}
@@ -480,3 +480,16 @@ whenWithElse = new Dynamic {
}
}
}
local func = (it) -> new Listing {
for (elem1 in List(1, 2)) {
it
new Listing {
for (elem2 in List(1, 2)) {
elem1 + elem2
}
}
}
}
nestedForsWithinLambda = func.apply("hi")
@@ -475,3 +475,42 @@ withinLetExpr =
[k] = v
}
}
// object bodies that are children of for-generators inherit the frame descriptor of the parent object
nestedObjectInsideFor {
for (idx, qux in List(1, 2)) {
[idx] {
for (baz in List(1, 2)) {
when (baz == qux) {
baz
}
}
}
}
}
// object bodies inherit the frame descriptor of the parent object
doublyNestedObjectInsideFor {
for (idx, qux in List(1, 2)) {
[idx] {
new Listing {
for (baz in List(1, 2)) {
when (baz == qux) {
baz
}
}
}
}
}
}
insideObjectBodyWithParam: Mapping<String, Dynamic> = new {
default { key ->
for (key, value in Map("foo", List(new Dynamic { bar = 1 }))) {
[key] {
...value
}
}
}
["res"] {}
}
@@ -1,7 +1,7 @@
examples {
local a = List("1", "2", "3", "4")
local b = List("a", "b", "c", "d")
["shadow key variable"] {
new {
for (key, outerValue in a) {
@@ -0,0 +1,5 @@
res {
for (prefix in List("foo")) {
"foobar" as String(let (y = this) y.startsWith(prefix))
}
}
@@ -43,7 +43,8 @@ res5 = new {
// nested predicate
res6 = (people) {
[[(people) { [[name == "Barn Owl"]] { age = 99 } }.toList().find((it) -> it.age == 99).name == name]] {
[[(people) { [[name == "Barn Owl"]] { age = 99 } }.toList().find((it) -> it.age == 99).name
== name]] {
age = 55
}
}
@@ -86,3 +87,28 @@ res12 = (people) {
[[name == "Pigeon"]] { age = 122 }
}
}
res13 = (people) {
[[(() -> this.name == "Pigeon").apply()]] {
age = 99
}
}
res14 = (people) {
for (foo in List(1, 2)) {
[[foo == 1]] {
age = foo
}
}
}
res15 =
(
(it) -> (people) {
for (foo in List(1, 2)) {
[[foo == 1]] {
age = foo
}
}
}
).apply("hi")
@@ -0,0 +1,13 @@
res1 = "foo"
res2 = "foo"
res3 = "foo"
res4 {
new {
name = "bob"
}
}
res5 {
new {
name = "bob"
}
}
@@ -0,0 +1,17 @@
res {
6
7
}
res2 {
2
3
}
res3 {
2
3
}
res4 {
["foo"] {
"bar"
}
}
@@ -0,0 +1,6 @@
prop = "qux"
res {
["bar"] {
myProp = "qux"
}
}
@@ -335,3 +335,15 @@ whenWithElse {
20
40
}
nestedForsWithinLambda {
"hi"
new {
2
3
}
"hi"
new {
3
4
}
}
@@ -323,3 +323,32 @@ withinLetExpr {
["a"] = 1
["b"] = 2
}
nestedObjectInsideFor {
[0] {
1
}
[1] {
2
}
}
doublyNestedObjectInsideFor {
[0] {
new {
1
}
}
[1] {
new {
2
}
}
}
insideObjectBodyWithParam {
["res"] {
["foo"] {
new {
bar = 1
}
}
}
}
@@ -0,0 +1,3 @@
res {
"foobar"
}
@@ -153,3 +153,45 @@ res12 {
age = 33
}
}
res13 {
new {
name = "Pigeon"
age = 99
}
new {
name = "Barn Owl"
age = 21
}
new {
name = "Parrot"
age = 33
}
}
res14 {
new {
name = "Pigeon"
age = 1
}
new {
name = "Barn Owl"
age = 1
}
new {
name = "Parrot"
age = 1
}
}
res15 {
new {
name = "Pigeon"
age = 1
}
new {
name = "Barn Owl"
age = 1
}
new {
name = "Parrot"
age = 1
}
}