[engine] Update starlark-go

The latest version of starlark-go deprecates the global `resolve.Allow*`
fields in favor of a `syntax.FileOptions` object that gets passed into
the parsing function.

I added a test to make sure the optional features are still enabled. I
didn't include a test for `while` because it's not supported by
buildifier.

Change-Id: I5495674963624c2d303a95615ea7942a625aa645
Reviewed-on: https://fuchsia-review.googlesource.com/c/shac-project/shac/+/930355
Reviewed-by: Anthony Fandrianto <atyfto@google.com>
Fuchsia-Auto-Submit: Oliver Newman <olivernewman@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/doc/stdlib.md b/doc/stdlib.md
index b63737c..115505a 100644
--- a/doc/stdlib.md
+++ b/doc/stdlib.md
@@ -11,11 +11,12 @@
 a few are explicitly documented here to highlight them.
 
 These [experimental
-features](https://pkg.go.dev/go.starlark.net/resolve#pkg-variables) are enabled:
+options](https://pkg.go.dev/go.starlark.net/syntax#FileOptions) are enabled:
 
-- AllowSet: "set" built-in is enabled.
-- AllowRecursion: allow while statements and recursion. This allows potentially
-  unbounded runtime.
+- Set: "set" built-in is enabled.
+- While: while statements are allowed. This allows potentially unbounded
+  runtime.
+- Recursion: recursive function calls are allowed.
 
 ## Table of contents
 
diff --git a/doc/stdlib.star b/doc/stdlib.star
index 84473dc..c22229b 100644
--- a/doc/stdlib.star
+++ b/doc/stdlib.star
@@ -28,11 +28,12 @@
 a few are explicitly documented here to highlight them.
 
 These [experimental
-features](https://pkg.go.dev/go.starlark.net/resolve#pkg-variables) are enabled:
+options](https://pkg.go.dev/go.starlark.net/syntax#FileOptions) are enabled:
 
-- AllowSet: "set" built-in is enabled.
-- AllowRecursion: allow while statements and recursion. This allows potentially
-  unbounded runtime.
+- Set: "set" built-in is enabled.
+- While: while statements are allowed. This allows potentially unbounded
+  runtime.
+- Recursion: recursive function calls are allowed.
 """
 
 # Note: The shac runtime standard library is implemented in native Go.
diff --git a/go.mod b/go.mod
index 23cdc90..72adf1a 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,8 @@
 	github.com/mattn/go-colorable v0.1.13
 	github.com/mattn/go-isatty v0.0.19
 	github.com/spf13/pflag v1.0.5
-	go.starlark.net v0.0.0-20230807144010-2aa75752d1da
+	go.chromium.org/luci v0.0.0-20231012044737-639b0ba8e396
+	go.starlark.net v0.0.0-20230925163745-10651d5192ab
 	golang.org/x/mod v0.13.0
 	golang.org/x/sync v0.4.0
 	golang.org/x/tools v0.14.0
@@ -33,8 +34,6 @@
 	google.golang.org/protobuf v1.31.1-0.20230927161544-6352deccdb59
 )
 
-require go.chromium.org/luci v0.0.0-20231012044737-639b0ba8e396
-
 require (
 	github.com/golang/mock v1.6.0 // indirect
 	github.com/golang/protobuf v1.5.3 // indirect
diff --git a/go.sum b/go.sum
index 0405556..08c3b1a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,45 +1,21 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
-github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
-github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrOvKnuittYVdA=
 github.com/go-git/go-git v4.7.0+incompatible/go.mod h1:6+421e08gnZWn30y26Vchf7efgYLe4dl5OQbBSUXShE=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
 github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -74,7 +50,6 @@
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/smarty/assertions v1.15.1 h1:812oFiXI+G55vxsFf+8bIZ1ux30qtkdqzKbEFwyX3Tk=
 github.com/smarty/assertions v1.15.1/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec=
@@ -91,37 +66,25 @@
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.chromium.org/luci v0.0.0-20231012044737-639b0ba8e396 h1:Mkm6j/Tfgmv6b23OC6aF7GgiFV8ieSIzLjmwTWNWr84=
 go.chromium.org/luci v0.0.0-20231012044737-639b0ba8e396/go.mod h1:GGSuHJlnYhsASDay7s0fadZ8HxTtG4Yp4YfPwvaUIdc=
-go.starlark.net v0.0.0-20230807144010-2aa75752d1da h1:FlKSIJl+UmVFgpyCr4Bdmj443NNBDW5ZSDP/HciJ96g=
-go.starlark.net v0.0.0-20230807144010-2aa75752d1da/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
+go.starlark.net v0.0.0-20230925163745-10651d5192ab h1:7QkXlIVjYdSsKKSGnM0jQdw/2w9W5qcFDGTc00zKqgI=
+go.starlark.net v0.0.0-20230925163745-10651d5192ab/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM=
 golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
 golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
 golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
 golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -129,24 +92,17 @@
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -156,30 +112,14 @@
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20231009173412-8bfb1ae86b6c h1:ml3TAUoIIzQUtX88s/icpXCFW9lV5VwsuIuS1htNjKY=
 google.golang.org/genproto v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:MugzuwC+GYOxyF0XUGQvsT97bOgWCV7MM1XMc5FZv8E=
 google.golang.org/genproto/googleapis/api v0.0.0-20231009173412-8bfb1ae86b6c h1:0RtEmmHjemvUXloH7+RuBSIw7n+GEHMOMY1CkGYnWq4=
 google.golang.org/genproto/googleapis/api v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:Wth13BrWMRN/G+guBLupKa6fslcWZv14R0ZKDRkNfY8=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c h1:jHkCUWkseRf+W+edG5hMzr/Uh1xkDREY4caybAq4dpY=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20231009173412-8bfb1ae86b6c/go.mod h1:4cYg8o5yUbm77w8ZX00LhMVNl/YVBFJRYWDc0uYWMs0=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ=
 google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.31.1-0.20230927161544-6352deccdb59 h1:VEyoIMQ5ezAWTdg2i5ZPPmEgGs1HU6krWTttP6lOLBg=
@@ -194,5 +134,3 @@
 gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/internal/engine/env.go b/internal/engine/env.go
index f9d93c0..c6ac293 100644
--- a/internal/engine/env.go
+++ b/internal/engine/env.go
@@ -113,6 +113,8 @@
 	globals starlark.StringDict
 	// packages are all the available packages. It must include __main__.
 	packages map[string]fs.FS
+	// Options for parsing Starlark.
+	opts *syntax.FileOptions
 
 	// Mutable.
 	mu sync.Mutex
@@ -200,7 +202,7 @@
 				oldsk := th.Local("shac.pkg").(sourceKey)
 				th.SetLocal("shac.pkg", sk)
 				fp := syntax.FilePortion{Content: d, FirstLine: 1, FirstCol: 1}
-				source.globals, source.err = starlark.ExecFile(th, sk.String(), fp, e.globals)
+				source.globals, source.err = starlark.ExecFileOptions(e.opts, th, sk.String(), fp, e.globals)
 				th.SetLocal("shac.pkg", oldsk)
 				var errl resolve.ErrorList
 				if errors.As(source.err, &errl) {
diff --git a/internal/engine/run.go b/internal/engine/run.go
index c341870..b7e83ab 100644
--- a/internal/engine/run.go
+++ b/internal/engine/run.go
@@ -37,17 +37,20 @@
 	"github.com/go-git/go-git/plumbing/format/gitignore"
 	flag "github.com/spf13/pflag"
 	"go.fuchsia.dev/shac-project/shac/internal/sandbox"
-	"go.starlark.net/resolve"
 	"go.starlark.net/starlark"
+	"go.starlark.net/syntax"
 	"golang.org/x/sync/errgroup"
 	"golang.org/x/sync/semaphore"
 	"google.golang.org/protobuf/encoding/prototext"
 )
 
-func init() {
-	// Enable not-yet-standard Starlark features.
-	resolve.AllowRecursion = true
-	resolve.AllowSet = true
+func starlarkOptions() *syntax.FileOptions {
+	return &syntax.FileOptions{
+		// Enable not-yet-standard Starlark features.
+		Set:       true,
+		While:     true,
+		Recursion: true,
+	}
 }
 
 // Cursor represents a point in a content; generally a source file but it can
@@ -363,6 +366,7 @@
 		globals:  getPredeclared(),
 		sources:  map[string]*loadedSource{},
 		packages: packages,
+		opts:     starlarkOptions(),
 	}
 
 	subprocessSem := semaphore.NewWeighted(int64(runtime.NumCPU()) + 2)
diff --git a/internal/engine/run_test.go b/internal/engine/run_test.go
index 6dcd96c..4dffac2 100644
--- a/internal/engine/run_test.go
+++ b/internal/engine/run_test.go
@@ -2337,6 +2337,11 @@
 				"[//load-diamond_dependency.star:19] i am a constant #2\n",
 		},
 		{
+			name: "optional-features.star",
+			want: "[//optional-features.star:17] recursion complete\n" +
+				"[//optional-features.star:23] set([\"foo\"])\n",
+		},
+		{
 			name: "print-shac-version.star",
 			want: "[//print-shac-version.star:15] " + v + "\n",
 		},
diff --git a/internal/engine/testdata/print/optional-features.star b/internal/engine/testdata/print/optional-features.star
new file mode 100644
index 0000000..7e0f310
--- /dev/null
+++ b/internal/engine/testdata/print/optional-features.star
@@ -0,0 +1,25 @@
+# Copyright 2023 The Shac Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+def recurse(i = 0):
+    if i == 5:
+        print("recursion complete")
+        return
+    recurse(i + 1)
+
+def cb(ctx):
+    recurse()
+    print(set(["foo"]))
+
+shac.register_check(cb)
diff --git a/internal/engine/version.go b/internal/engine/version.go
index 8e1d778..214600b 100644
--- a/internal/engine/version.go
+++ b/internal/engine/version.go
@@ -26,7 +26,7 @@
 	// Version is the current tool version.
 	//
 	// TODO(maruel): Add proper version, preferably from git tag.
-	Version = shacVersion{0, 1, 15}
+	Version = shacVersion{0, 1, 16}
 )
 
 func (v shacVersion) String() string {
diff --git a/vendor/go.starlark.net/internal/compile/compile.go b/vendor/go.starlark.net/internal/compile/compile.go
index 888d95c..ecf689f 100644
--- a/vendor/go.starlark.net/internal/compile/compile.go
+++ b/vendor/go.starlark.net/internal/compile/compile.go
@@ -23,7 +23,6 @@
 //
 // Operands, logically uint32s, are encoded using little-endian 7-bit
 // varints, the top bit indicating that more bytes follow.
-//
 package compile // import "go.starlark.net/internal/compile"
 
 import (
@@ -47,7 +46,7 @@
 const debug = false // make code generation verbose, for debugging the compiler
 
 // Increment this to force recompilation of saved bytecode files.
-const Version = 13
+const Version = 14
 
 type Opcode uint8
 
@@ -317,6 +316,7 @@
 	Functions []*Funcode
 	Globals   []Binding // for error messages and tracing
 	Toplevel  *Funcode  // module initialization function
+	Recursion bool      // disable recursion check for functions in this file
 }
 
 // The type of a bytes literal value, to distinguish from text string.
@@ -486,17 +486,20 @@
 }
 
 // Expr compiles an expression to a program whose toplevel function evaluates it.
-func Expr(expr syntax.Expr, name string, locals []*resolve.Binding) *Program {
+// The options must be consistent with those used when parsing expr.
+func Expr(opts *syntax.FileOptions, expr syntax.Expr, name string, locals []*resolve.Binding) *Program {
 	pos := syntax.Start(expr)
 	stmts := []syntax.Stmt{&syntax.ReturnStmt{Result: expr}}
-	return File(stmts, pos, name, locals, nil)
+	return File(opts, stmts, pos, name, locals, nil)
 }
 
 // File compiles the statements of a file into a program.
-func File(stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*resolve.Binding) *Program {
+// The options must be consistent with those used when parsing stmts.
+func File(opts *syntax.FileOptions, stmts []syntax.Stmt, pos syntax.Position, name string, locals, globals []*resolve.Binding) *Program {
 	pcomp := &pcomp{
 		prog: &Program{
-			Globals: bindings(globals),
+			Globals:   bindings(globals),
+			Recursion: opts.Recursion,
 		},
 		names:     make(map[string]uint32),
 		constants: make(map[interface{}]uint32),
diff --git a/vendor/go.starlark.net/internal/compile/serial.go b/vendor/go.starlark.net/internal/compile/serial.go
index adadabf..4d71738 100644
--- a/vendor/go.starlark.net/internal/compile/serial.go
+++ b/vendor/go.starlark.net/internal/compile/serial.go
@@ -25,6 +25,7 @@
 //	toplevel	Funcode
 //	numfuncs	varint
 //	funcs		[]Funcode
+//	recursion	varint (0 or 1)
 //	<strings>	[]byte		# concatenation of all referenced strings
 //	EOF
 //
@@ -130,6 +131,7 @@
 	for _, fn := range prog.Functions {
 		e.function(fn)
 	}
+	e.int(b2i(prog.Recursion))
 
 	// Patch in the offset of the string data section.
 	binary.LittleEndian.PutUint32(e.p[4:8], uint32(len(e.p)))
@@ -270,6 +272,7 @@
 	for i := range funcs {
 		funcs[i] = d.function()
 	}
+	recursion := d.int() != 0
 
 	prog := &Program{
 		Loads:     loads,
@@ -278,6 +281,7 @@
 		Globals:   globals,
 		Functions: funcs,
 		Toplevel:  toplevel,
+		Recursion: recursion,
 	}
 	toplevel.Prog = prog
 	for _, f := range funcs {
diff --git a/vendor/go.starlark.net/resolve/binding.go b/vendor/go.starlark.net/resolve/binding.go
index 6b99f4b..8507e64 100644
--- a/vendor/go.starlark.net/resolve/binding.go
+++ b/vendor/go.starlark.net/resolve/binding.go
@@ -10,7 +10,7 @@
 // We cannot guarantee API stability for these types
 // as they are closely tied to the implementation.
 
-// A Binding contains resolver information about an identifer.
+// A Binding contains resolver information about an identifier.
 // The resolver populates the Binding field of each syntax.Identifier.
 // The Binding ties together all identifiers that denote the same variable.
 type Binding struct {
diff --git a/vendor/go.starlark.net/resolve/resolve.go b/vendor/go.starlark.net/resolve/resolve.go
index 09b9acd..c576a6b 100644
--- a/vendor/go.starlark.net/resolve/resolve.go
+++ b/vendor/go.starlark.net/resolve/resolve.go
@@ -97,6 +97,9 @@
 // global options
 // These features are either not standard Starlark (yet), or deprecated
 // features of the BUILD language, so we put them behind flags.
+//
+// Deprecated: use an explicit [syntax.FileOptions] argument instead,
+// as it avoids all the usual problems of global variables.
 var (
 	AllowSet            = false // allow the 'set' built-in
 	AllowGlobalReassign = false // allow reassignment to top-level names; also, allow if/for/while at top-level
@@ -130,7 +133,7 @@
 // REPLChunk is a generalization of the File function that supports a
 // non-empty initial global block, as occurs in a REPL.
 func REPLChunk(file *syntax.File, isGlobal, isPredeclared, isUniversal func(name string) bool) error {
-	r := newResolver(isGlobal, isPredeclared, isUniversal)
+	r := newResolver(file.Options, isGlobal, isPredeclared, isUniversal)
 	r.stmts(file.Stmts)
 
 	r.env.resolveLocalUses()
@@ -151,12 +154,18 @@
 	return nil
 }
 
-// Expr resolves the specified expression.
+// Expr calls [ExprOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
+	return ExprOptions(syntax.LegacyFileOptions(), expr, isPredeclared, isUniversal)
+}
+
+// ExprOptions resolves the specified expression.
 // It returns the local variables bound within the expression.
 //
-// The isPredeclared and isUniversal predicates behave as for the File function.
-func Expr(expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
-	r := newResolver(nil, isPredeclared, isUniversal)
+// The isPredeclared and isUniversal predicates behave as for the File function
+func ExprOptions(opts *syntax.FileOptions, expr syntax.Expr, isPredeclared, isUniversal func(name string) bool) ([]*Binding, error) {
+	r := newResolver(opts, nil, isPredeclared, isUniversal)
 	r.expr(expr)
 	r.env.resolveLocalUses()
 	r.resolveNonLocalUses(r.env) // globals & universals
@@ -179,9 +188,10 @@
 
 func (e Error) Error() string { return e.Pos.String() + ": " + e.Msg }
 
-func newResolver(isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver {
+func newResolver(options *syntax.FileOptions, isGlobal, isPredeclared, isUniversal func(name string) bool) *resolver {
 	file := new(block)
 	return &resolver{
+		options:       options,
 		file:          file,
 		env:           file,
 		isGlobal:      isGlobal,
@@ -193,6 +203,8 @@
 }
 
 type resolver struct {
+	options *syntax.FileOptions
+
 	// env is the current local environment:
 	// a linked list of blocks, innermost first.
 	// The tail of the list is the file block.
@@ -314,7 +326,7 @@
 				r.moduleGlobals = append(r.moduleGlobals, bind)
 			}
 		}
-		if ok && !AllowGlobalReassign {
+		if ok && !r.options.GlobalReassign {
 			r.errorf(id.NamePos, "cannot reassign %s %s declared at %s",
 				bind.Scope, id.Name, bind.First.NamePos)
 		}
@@ -382,7 +394,7 @@
 	// We will piggyback support for the legacy semantics on the
 	// AllowGlobalReassign flag, which is loosely related and also
 	// required for Bazel.
-	if AllowGlobalReassign && r.env == r.file {
+	if r.options.GlobalReassign && r.env == r.file {
 		r.useToplevel(use)
 		return
 	}
@@ -420,7 +432,7 @@
 		r.predeclared[id.Name] = bind // save it
 	} else if r.isUniversal(id.Name) {
 		// use of universal name
-		if !AllowSet && id.Name == "set" {
+		if !r.options.Set && id.Name == "set" {
 			r.errorf(id.NamePos, doesnt+"support sets")
 		}
 		bind = &Binding{Scope: Universal}
@@ -493,7 +505,7 @@
 		}
 
 	case *syntax.IfStmt:
-		if !AllowGlobalReassign && r.container().function == nil {
+		if !r.options.TopLevelControl && r.container().function == nil {
 			r.errorf(stmt.If, "if statement not within a function")
 		}
 		r.expr(stmt.Cond)
@@ -519,7 +531,7 @@
 		r.function(fn, stmt.Def)
 
 	case *syntax.ForStmt:
-		if !AllowGlobalReassign && r.container().function == nil {
+		if !r.options.TopLevelControl && r.container().function == nil {
 			r.errorf(stmt.For, "for loop not within a function")
 		}
 		r.expr(stmt.X)
@@ -530,10 +542,10 @@
 		r.loops--
 
 	case *syntax.WhileStmt:
-		if !AllowRecursion {
+		if !r.options.While {
 			r.errorf(stmt.While, doesnt+"support while loops")
 		}
-		if !AllowGlobalReassign && r.container().function == nil {
+		if !r.options.TopLevelControl && r.container().function == nil {
 			r.errorf(stmt.While, "while loop not within a function")
 		}
 		r.expr(stmt.Cond)
@@ -569,9 +581,9 @@
 			}
 
 			id := stmt.To[i]
-			if LoadBindsGlobally {
+			if r.options.LoadBindsGlobally {
 				r.bind(id)
-			} else if r.bindLocal(id) && !AllowGlobalReassign {
+			} else if r.bindLocal(id) && !r.options.GlobalReassign {
 				// "Global" in AllowGlobalReassign is a misnomer for "toplevel".
 				// Sadly we can't report the previous declaration
 				// as id.Binding may not be set yet.
diff --git a/vendor/go.starlark.net/starlark/eval.go b/vendor/go.starlark.net/starlark/eval.go
index 949cb93..99e83a1 100644
--- a/vendor/go.starlark.net/starlark/eval.go
+++ b/vendor/go.starlark.net/starlark/eval.go
@@ -7,7 +7,6 @@
 import (
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
 	"math/big"
 	"sort"
@@ -325,7 +324,13 @@
 	return err
 }
 
-// ExecFile parses, resolves, and executes a Starlark file in the
+// ExecFile calls [ExecFileOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func ExecFile(thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) {
+	return ExecFileOptions(syntax.LegacyFileOptions(), thread, filename, src, predeclared)
+}
+
+// ExecFileOptions parses, resolves, and executes a Starlark file in the
 // specified global environment, which may be modified during execution.
 //
 // Thread is the state associated with the Starlark thread.
@@ -340,11 +345,11 @@
 // Execution does not modify this dictionary, though it may mutate
 // its values.
 //
-// If ExecFile fails during evaluation, it returns an *EvalError
+// If ExecFileOptions fails during evaluation, it returns an *EvalError
 // containing a backtrace.
-func ExecFile(thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) {
+func ExecFileOptions(opts *syntax.FileOptions, thread *Thread, filename string, src interface{}, predeclared StringDict) (StringDict, error) {
 	// Parse, resolve, and compile a Starlark source file.
-	_, mod, err := SourceProgram(filename, src, predeclared.Has)
+	_, mod, err := SourceProgramOptions(opts, filename, src, predeclared.Has)
 	if err != nil {
 		return nil, err
 	}
@@ -354,7 +359,13 @@
 	return g, err
 }
 
-// SourceProgram produces a new program by parsing, resolving,
+// SourceProgram calls [SourceProgramOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func SourceProgram(filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) {
+	return SourceProgramOptions(syntax.LegacyFileOptions(), filename, src, isPredeclared)
+}
+
+// SourceProgramOptions produces a new program by parsing, resolving,
 // and compiling a Starlark source file.
 // On success, it returns the parsed file and the compiled program.
 // The filename and src parameters are as for syntax.Parse.
@@ -363,8 +374,8 @@
 // a pre-declared identifier of the current module.
 // Its typical value is predeclared.Has,
 // where predeclared is a StringDict of pre-declared values.
-func SourceProgram(filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) {
-	f, err := syntax.Parse(filename, src, 0)
+func SourceProgramOptions(opts *syntax.FileOptions, filename string, src interface{}, isPredeclared func(string) bool) (*syntax.File, *Program, error) {
+	f, err := opts.Parse(filename, src, 0)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -396,7 +407,7 @@
 	}
 
 	module := f.Module.(*resolve.Module)
-	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
+	compiled := compile.File(f.Options, f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
 
 	return &Program{compiled}, nil
 }
@@ -404,7 +415,7 @@
 // CompiledProgram produces a new program from the representation
 // of a compiled program previously saved by Program.Write.
 func CompiledProgram(in io.Reader) (*Program, error) {
-	data, err := ioutil.ReadAll(in)
+	data, err := io.ReadAll(in)
 	if err != nil {
 		return nil, err
 	}
@@ -453,7 +464,7 @@
 	}
 
 	module := f.Module.(*resolve.Module)
-	compiled := compile.File(f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
+	compiled := compile.File(f.Options, f.Stmts, pos, "<toplevel>", module.Locals, module.Globals)
 	prog := &Program{compiled}
 
 	// -- variant of Program.Init --
@@ -512,7 +523,13 @@
 	}
 }
 
-// Eval parses, resolves, and evaluates an expression within the
+// Eval calls [EvalOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func Eval(thread *Thread, filename string, src interface{}, env StringDict) (Value, error) {
+	return EvalOptions(syntax.LegacyFileOptions(), thread, filename, src, env)
+}
+
+// EvalOptions parses, resolves, and evaluates an expression within the
 // specified (predeclared) environment.
 //
 // Evaluation cannot mutate the environment dictionary itself,
@@ -520,58 +537,71 @@
 //
 // The filename and src parameters are as for syntax.Parse.
 //
-// If Eval fails during evaluation, it returns an *EvalError
+// If EvalOptions fails during evaluation, it returns an *EvalError
 // containing a backtrace.
-func Eval(thread *Thread, filename string, src interface{}, env StringDict) (Value, error) {
-	expr, err := syntax.ParseExpr(filename, src, 0)
+func EvalOptions(opts *syntax.FileOptions, thread *Thread, filename string, src interface{}, env StringDict) (Value, error) {
+	expr, err := opts.ParseExpr(filename, src, 0)
 	if err != nil {
 		return nil, err
 	}
-	f, err := makeExprFunc(expr, env)
+	f, err := makeExprFunc(opts, expr, env)
 	if err != nil {
 		return nil, err
 	}
 	return Call(thread, f, nil, nil)
 }
 
-// EvalExpr resolves and evaluates an expression within the
+// EvalExpr calls [EvalExprOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func EvalExpr(thread *Thread, expr syntax.Expr, env StringDict) (Value, error) {
+	return EvalExprOptions(syntax.LegacyFileOptions(), thread, expr, env)
+}
+
+// EvalExprOptions resolves and evaluates an expression within the
 // specified (predeclared) environment.
 // Evaluating a comma-separated list of expressions yields a tuple value.
 //
 // Resolving an expression mutates it.
-// Do not call EvalExpr more than once for the same expression.
+// Do not call EvalExprOptions more than once for the same expression.
 //
 // Evaluation cannot mutate the environment dictionary itself,
 // though it may modify variables reachable from the dictionary.
 //
-// If Eval fails during evaluation, it returns an *EvalError
+// If EvalExprOptions fails during evaluation, it returns an *EvalError
 // containing a backtrace.
-func EvalExpr(thread *Thread, expr syntax.Expr, env StringDict) (Value, error) {
-	fn, err := makeExprFunc(expr, env)
+func EvalExprOptions(opts *syntax.FileOptions, thread *Thread, expr syntax.Expr, env StringDict) (Value, error) {
+	fn, err := makeExprFunc(opts, expr, env)
 	if err != nil {
 		return nil, err
 	}
 	return Call(thread, fn, nil, nil)
 }
 
+// ExprFunc calls [ExprFuncOptions] using [syntax.LegacyFileOptions].
+// Deprecated: relies on legacy global variables.
+func ExprFunc(filename string, src interface{}, env StringDict) (*Function, error) {
+	return ExprFuncOptions(syntax.LegacyFileOptions(), filename, src, env)
+}
+
 // ExprFunc returns a no-argument function
 // that evaluates the expression whose source is src.
-func ExprFunc(filename string, src interface{}, env StringDict) (*Function, error) {
-	expr, err := syntax.ParseExpr(filename, src, 0)
+func ExprFuncOptions(options *syntax.FileOptions, filename string, src interface{}, env StringDict) (*Function, error) {
+	expr, err := options.ParseExpr(filename, src, 0)
 	if err != nil {
 		return nil, err
 	}
-	return makeExprFunc(expr, env)
+	return makeExprFunc(options, expr, env)
 }
 
 // makeExprFunc returns a no-argument function whose body is expr.
-func makeExprFunc(expr syntax.Expr, env StringDict) (*Function, error) {
-	locals, err := resolve.Expr(expr, env.Has, Universe.Has)
+// The options must be consistent with those used when parsing expr.
+func makeExprFunc(opts *syntax.FileOptions, expr syntax.Expr, env StringDict) (*Function, error) {
+	locals, err := resolve.ExprOptions(opts, expr, env.Has, Universe.Has)
 	if err != nil {
 		return nil, err
 	}
 
-	return makeToplevelFunction(compile.Expr(expr, "<expr>", locals), env), nil
+	return makeToplevelFunction(compile.Expr(opts, expr, "<expr>", locals), env), nil
 }
 
 // The following functions are primitive operations of the byte code interpreter.
@@ -795,6 +825,12 @@
 				}
 				return x - yf, nil
 			}
+		case *Set: // difference
+			if y, ok := y.(*Set); ok {
+				iter := y.Iterate()
+				defer iter.Done()
+				return x.Difference(iter)
+			}
 		}
 
 	case syntax.STAR:
@@ -1066,17 +1102,9 @@
 			}
 		case *Set: // intersection
 			if y, ok := y.(*Set); ok {
-				set := new(Set)
-				if x.Len() > y.Len() {
-					x, y = y, x // opt: range over smaller set
-				}
-				for xe := x.ht.head; xe != nil; xe = xe.next {
-					// Has, Insert cannot fail here.
-					if found, _ := y.Has(xe.key); found {
-						set.Insert(xe.key)
-					}
-				}
-				return set, nil
+				iter := y.Iterate()
+				defer iter.Done()
+				return x.Intersection(iter)
 			}
 		}
 
@@ -1088,18 +1116,9 @@
 			}
 		case *Set: // symmetric difference
 			if y, ok := y.(*Set); ok {
-				set := new(Set)
-				for xe := x.ht.head; xe != nil; xe = xe.next {
-					if found, _ := y.Has(xe.key); !found {
-						set.Insert(xe.key)
-					}
-				}
-				for ye := y.ht.head; ye != nil; ye = ye.next {
-					if found, _ := x.Has(ye.key); !found {
-						set.Insert(ye.key)
-					}
-				}
-				return set, nil
+				iter := y.Iterate()
+				defer iter.Done()
+				return x.SymmetricDifference(iter)
 			}
 		}
 
diff --git a/vendor/go.starlark.net/starlark/int_generic.go b/vendor/go.starlark.net/starlark/int_generic.go
index d54bc2a..244a60c 100644
--- a/vendor/go.starlark.net/starlark/int_generic.go
+++ b/vendor/go.starlark.net/starlark/int_generic.go
@@ -1,5 +1,4 @@
 //go:build (!linux && !darwin && !dragonfly && !freebsd && !netbsd && !solaris) || (!amd64 && !arm64 && !mips64x && !ppc64 && !ppc64le && !loong64 && !s390x)
-// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!solaris !amd64,!arm64,!mips64x,!ppc64,!ppc64le,!loong64,!s390x
 
 package starlark
 
diff --git a/vendor/go.starlark.net/starlark/int_posix64.go b/vendor/go.starlark.net/starlark/int_posix64.go
index 36c56e5..70c949e 100644
--- a/vendor/go.starlark.net/starlark/int_posix64.go
+++ b/vendor/go.starlark.net/starlark/int_posix64.go
@@ -1,6 +1,4 @@
 //go:build (linux || darwin || dragonfly || freebsd || netbsd || solaris) && (amd64 || arm64 || mips64x || ppc64 || ppc64le || loong64 || s390x)
-// +build linux darwin dragonfly freebsd netbsd solaris
-// +build amd64 arm64 mips64x ppc64 ppc64le loong64 s390x
 
 package starlark
 
diff --git a/vendor/go.starlark.net/starlark/interp.go b/vendor/go.starlark.net/starlark/interp.go
index b41905a..d29e525 100644
--- a/vendor/go.starlark.net/starlark/interp.go
+++ b/vendor/go.starlark.net/starlark/interp.go
@@ -10,7 +10,6 @@
 
 	"go.starlark.net/internal/compile"
 	"go.starlark.net/internal/spell"
-	"go.starlark.net/resolve"
 	"go.starlark.net/syntax"
 )
 
@@ -24,19 +23,19 @@
 	// Postcondition: args is not mutated. This is stricter than required by Callable,
 	// but allows CALL to avoid a copy.
 
-	if !resolve.AllowRecursion {
+	f := fn.funcode
+	if !f.Prog.Recursion {
 		// detect recursion
 		for _, fr := range thread.stack[:len(thread.stack)-1] {
 			// We look for the same function code,
 			// not function value, otherwise the user could
 			// defeat the check by writing the Y combinator.
-			if frfn, ok := fr.Callable().(*Function); ok && frfn.funcode == fn.funcode {
+			if frfn, ok := fr.Callable().(*Function); ok && frfn.funcode == f {
 				return nil, fmt.Errorf("function %s called recursively", fn.Name())
 			}
 		}
 	}
 
-	f := fn.funcode
 	fr := thread.frameAt(0)
 
 	// Allocate space for stack and locals.
diff --git a/vendor/go.starlark.net/starlark/library.go b/vendor/go.starlark.net/starlark/library.go
index 1c801be..ef032ee 100644
--- a/vendor/go.starlark.net/starlark/library.go
+++ b/vendor/go.starlark.net/starlark/library.go
@@ -140,7 +140,17 @@
 	}
 
 	setMethods = map[string]*Builtin{
-		"union": NewBuiltin("union", set_union),
+		"add":                  NewBuiltin("add", set_add),
+		"clear":                NewBuiltin("clear", set_clear),
+		"difference":           NewBuiltin("difference", set_difference),
+		"discard":              NewBuiltin("discard", set_discard),
+		"intersection":         NewBuiltin("intersection", set_intersection),
+		"issubset":             NewBuiltin("issubset", set_issubset),
+		"issuperset":           NewBuiltin("issuperset", set_issuperset),
+		"pop":                  NewBuiltin("pop", set_pop),
+		"remove":               NewBuiltin("remove", set_remove),
+		"symmetric_difference": NewBuiltin("symmetric_difference", set_symmetric_difference),
+		"union":                NewBuiltin("union", set_union),
 	}
 )
 
@@ -2168,6 +2178,162 @@
 	return NewList(list), nil
 }
 
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·add.
+func set_add(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var elem Value
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &elem); err != nil {
+		return nil, err
+	}
+	if found, err := b.Receiver().(*Set).Has(elem); err != nil {
+		return nil, nameErr(b, err)
+	} else if found {
+		return None, nil
+	}
+	err := b.Receiver().(*Set).Insert(elem)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return None, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·clear.
+func set_clear(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {
+		return nil, err
+	}
+	if b.Receiver().(*Set).Len() > 0 {
+		if err := b.Receiver().(*Set).Clear(); err != nil {
+			return nil, nameErr(b, err)
+		}
+	}
+	return None, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·difference.
+func set_difference(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	// TODO: support multiple others: s.difference(*others)
+	var other Iterable
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil {
+		return nil, err
+	}
+	iter := other.Iterate()
+	defer iter.Done()
+	diff, err := b.Receiver().(*Set).Difference(iter)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return diff, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_intersection.
+func set_intersection(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	// TODO: support multiple others: s.difference(*others)
+	var other Iterable
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil {
+		return nil, err
+	}
+	iter := other.Iterate()
+	defer iter.Done()
+	diff, err := b.Receiver().(*Set).Intersection(iter)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return diff, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_issubset.
+func set_issubset(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var other Iterable
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil {
+		return nil, err
+	}
+	iter := other.Iterate()
+	defer iter.Done()
+	diff, err := b.Receiver().(*Set).IsSubset(iter)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return Bool(diff), nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set_issuperset.
+func set_issuperset(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var other Iterable
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil {
+		return nil, err
+	}
+	iter := other.Iterate()
+	defer iter.Done()
+	diff, err := b.Receiver().(*Set).IsSuperset(iter)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return Bool(diff), nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·discard.
+func set_discard(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var k Value
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k); err != nil {
+		return nil, err
+	}
+	if found, err := b.Receiver().(*Set).Has(k); err != nil {
+		return nil, nameErr(b, err)
+	} else if !found {
+		return None, nil
+	}
+	if _, err := b.Receiver().(*Set).Delete(k); err != nil {
+		return nil, nameErr(b, err) // set is frozen
+	}
+	return None, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·pop.
+func set_pop(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0); err != nil {
+		return nil, err
+	}
+	recv := b.Receiver().(*Set)
+	k, ok := recv.ht.first()
+	if !ok {
+		return nil, nameErr(b, "empty set")
+	}
+	_, err := recv.Delete(k)
+	if err != nil {
+		return nil, nameErr(b, err) // set is frozen
+	}
+	return k, nil
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·remove.
+func set_remove(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var k Value
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 1, &k); err != nil {
+		return nil, err
+	}
+	if found, err := b.Receiver().(*Set).Delete(k); err != nil {
+		return nil, nameErr(b, err) // dict is frozen or key is unhashable
+	} else if found {
+		return None, nil
+	}
+	return nil, nameErr(b, "missing key")
+}
+
+// https://github.com/google/starlark-go/blob/master/doc/spec.md#set·symmetric_difference.
+func set_symmetric_difference(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
+	var other Iterable
+	if err := UnpackPositionalArgs(b.Name(), args, kwargs, 0, &other); err != nil {
+		return nil, err
+	}
+	iter := other.Iterate()
+	defer iter.Done()
+	diff, err := b.Receiver().(*Set).SymmetricDifference(iter)
+	if err != nil {
+		return nil, nameErr(b, err)
+	}
+	return diff, nil
+}
+
 // https://github.com/google/starlark-go/blob/master/doc/spec.md#set·union.
 func set_union(_ *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
 	var iterable Iterable
diff --git a/vendor/go.starlark.net/starlark/profile.go b/vendor/go.starlark.net/starlark/profile.go
index 38da2b2..590a4e2 100644
--- a/vendor/go.starlark.net/starlark/profile.go
+++ b/vendor/go.starlark.net/starlark/profile.go
@@ -101,11 +101,11 @@
 	return nil
 }
 
-// StopProfiler stops the profiler started by a prior call to
+// StopProfile stops the profiler started by a prior call to
 // StartProfile and finalizes the profile. It returns an error if the
 // profile could not be completed.
 //
-// StopProfiler must not be called concurrently with Starlark execution.
+// StopProfile must not be called concurrently with Starlark execution.
 func StopProfile() error {
 	// Terminate the profiler goroutine and get its result.
 	close(profiler.events)
diff --git a/vendor/go.starlark.net/starlark/value.go b/vendor/go.starlark.net/starlark/value.go
index 1f14a29..db9ba11 100644
--- a/vendor/go.starlark.net/starlark/value.go
+++ b/vendor/go.starlark.net/starlark/value.go
@@ -1134,6 +1134,34 @@
 	case syntax.NEQ:
 		ok, err := setsEqual(x, y, depth)
 		return !ok, err
+	case syntax.GE: // superset
+		if x.Len() < y.Len() {
+			return false, nil
+		}
+		iter := y.Iterate()
+		defer iter.Done()
+		return x.IsSuperset(iter)
+	case syntax.LE: // subset
+		if x.Len() > y.Len() {
+			return false, nil
+		}
+		iter := y.Iterate()
+		defer iter.Done()
+		return x.IsSubset(iter)
+	case syntax.GT: // proper superset
+		if x.Len() <= y.Len() {
+			return false, nil
+		}
+		iter := y.Iterate()
+		defer iter.Done()
+		return x.IsSuperset(iter)
+	case syntax.LT: // proper subset
+		if x.Len() >= y.Len() {
+			return false, nil
+		}
+		iter := y.Iterate()
+		defer iter.Done()
+		return x.IsSubset(iter)
 	default:
 		return false, fmt.Errorf("%s %s %s not implemented", x.Type(), op, y.Type())
 	}
@@ -1151,11 +1179,28 @@
 	return true, nil
 }
 
-func (s *Set) Union(iter Iterator) (Value, error) {
+func setFromIterator(iter Iterator) (*Set, error) {
+	var x Value
+	set := new(Set)
+	for iter.Next(&x) {
+		err := set.Insert(x)
+		if err != nil {
+			return set, err
+		}
+	}
+	return set, nil
+}
+
+func (s *Set) clone() *Set {
 	set := new(Set)
 	for e := s.ht.head; e != nil; e = e.next {
 		set.Insert(e.key) // can't fail
 	}
+	return set
+}
+
+func (s *Set) Union(iter Iterator) (Value, error) {
+	set := s.clone()
 	var x Value
 	for iter.Next(&x) {
 		if err := set.Insert(x); err != nil {
@@ -1165,6 +1210,74 @@
 	return set, nil
 }
 
+func (s *Set) Difference(other Iterator) (Value, error) {
+	diff := s.clone()
+	var x Value
+	for other.Next(&x) {
+		if _, err := diff.Delete(x); err != nil {
+			return nil, err
+		}
+	}
+	return diff, nil
+}
+
+func (s *Set) IsSuperset(other Iterator) (bool, error) {
+	var x Value
+	for other.Next(&x) {
+		found, err := s.Has(x)
+		if err != nil {
+			return false, err
+		}
+		if !found {
+			return false, nil
+		}
+	}
+	return true, nil
+}
+
+func (s *Set) IsSubset(other Iterator) (bool, error) {
+	otherset, err := setFromIterator(other)
+	if err != nil {
+		return false, err
+	}
+	iter := s.Iterate()
+	defer iter.Done()
+	return otherset.IsSuperset(iter)
+}
+
+func (s *Set) Intersection(other Iterator) (Value, error) {
+	intersect := new(Set)
+	var x Value
+	for other.Next(&x) {
+		found, err := s.Has(x)
+		if err != nil {
+			return nil, err
+		}
+		if found {
+			err = intersect.Insert(x)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return intersect, nil
+}
+
+func (s *Set) SymmetricDifference(other Iterator) (Value, error) {
+	diff := s.clone()
+	var x Value
+	for other.Next(&x) {
+		found, err := diff.Delete(x)
+		if err != nil {
+			return nil, err
+		}
+		if !found {
+			diff.Insert(x)
+		}
+	}
+	return diff, nil
+}
+
 // toString returns the string form of value v.
 // It may be more efficient than v.String() for larger values.
 func toString(v Value) string {
@@ -1453,7 +1566,7 @@
 // Bytes is the type of a Starlark binary string.
 //
 // A Bytes encapsulates an immutable sequence of bytes.
-// It is comparable, indexable, and sliceable, but not direcly iterable;
+// It is comparable, indexable, and sliceable, but not directly iterable;
 // use bytes.elems() for an iterable view.
 //
 // In this Go implementation, the elements of 'string' and 'bytes' are
diff --git a/vendor/go.starlark.net/syntax/options.go b/vendor/go.starlark.net/syntax/options.go
new file mode 100644
index 0000000..51b2638
--- /dev/null
+++ b/vendor/go.starlark.net/syntax/options.go
@@ -0,0 +1,63 @@
+// Copyright 2023 The Bazel Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syntax
+
+import _ "unsafe" // for linkname
+
+// FileOptions specifies various per-file options that affect static
+// aspects of an individual file such as parsing, name resolution, and
+// code generation. (Options that affect global dynamics are typically
+// controlled through [starlark.Thread].)
+//
+// The zero value of FileOptions is the default behavior.
+//
+// Many functions in this package come in two versions: the legacy
+// standalone function (such as [Parse]) uses [LegacyFileOptions],
+// whereas the more recent method (such as [Options.Parse]) honors the
+// provided options. The second form is preferred. In other packages,
+// the modern version is a standalone function with a leading
+// FileOptions parameter and the name suffix "Options", such as
+// [starlark.ExecFileOptions].
+type FileOptions struct {
+	// resolver
+	Set               bool // allow references to the 'set' built-in function
+	While             bool // allow 'while' statements
+	TopLevelControl   bool // allow if/for/while statements at top-level
+	GlobalReassign    bool // allow reassignment to top-level names
+	LoadBindsGlobally bool // load creates global not file-local bindings (deprecated)
+
+	// compiler
+	Recursion bool // disable recursion check for functions in this file
+}
+
+// TODO(adonovan): provide a canonical flag parser for FileOptions.
+// (And use it in the testdata "options:" strings.)
+
+// LegacyFileOptions returns a new FileOptions containing the current
+// values of the resolver package's legacy global variables such as
+// [resolve.AllowRecursion], etc.
+// These variables may be associated with command-line flags.
+func LegacyFileOptions() *FileOptions {
+	return &FileOptions{
+		Set:               resolverAllowSet,
+		While:             resolverAllowGlobalReassign,
+		TopLevelControl:   resolverAllowGlobalReassign,
+		GlobalReassign:    resolverAllowGlobalReassign,
+		Recursion:         resolverAllowRecursion,
+		LoadBindsGlobally: resolverLoadBindsGlobally,
+	}
+}
+
+// Access resolver (legacy) flags, if they are linked in; false otherwise.
+var (
+	//go:linkname resolverAllowSet go.starlark.net/resolve.AllowSet
+	resolverAllowSet bool
+	//go:linkname resolverAllowGlobalReassign go.starlark.net/resolve.AllowGlobalReassign
+	resolverAllowGlobalReassign bool
+	//go:linkname resolverAllowRecursion go.starlark.net/resolve.AllowRecursion
+	resolverAllowRecursion bool
+	//go:linkname resolverLoadBindsGlobally go.starlark.net/resolve.LoadBindsGlobally
+	resolverLoadBindsGlobally bool
+)
diff --git a/vendor/go.starlark.net/syntax/parse.go b/vendor/go.starlark.net/syntax/parse.go
index f4c8fff..1183a03 100644
--- a/vendor/go.starlark.net/syntax/parse.go
+++ b/vendor/go.starlark.net/syntax/parse.go
@@ -23,19 +23,25 @@
 	RetainComments Mode = 1 << iota // retain comments in AST; see Node.Comments
 )
 
+// Parse calls the Parse method of LegacyFileOptions().
+// Deprecated: relies on legacy global variables.
+func Parse(filename string, src interface{}, mode Mode) (f *File, err error) {
+	return LegacyFileOptions().Parse(filename, src, mode)
+}
+
 // Parse parses the input data and returns the corresponding parse tree.
 //
-// If src != nil, ParseFile parses the source from src and the filename
+// If src != nil, Parse parses the source from src and the filename
 // is only used when recording position information.
 // The type of the argument for the src parameter must be string,
 // []byte, io.Reader, or FilePortion.
-// If src == nil, ParseFile parses the file specified by filename.
-func Parse(filename string, src interface{}, mode Mode) (f *File, err error) {
+// If src == nil, Parse parses the file specified by filename.
+func (opts *FileOptions) Parse(filename string, src interface{}, mode Mode) (f *File, err error) {
 	in, err := newScanner(filename, src, mode&RetainComments != 0)
 	if err != nil {
 		return nil, err
 	}
-	p := parser{in: in}
+	p := parser{options: opts, in: in}
 	defer p.in.recover(&err)
 
 	p.nextToken() // read first lookahead token
@@ -47,6 +53,12 @@
 	return f, nil
 }
 
+// ParseCompoundStmt calls the ParseCompoundStmt method of LegacyFileOptions().
+// Deprecated: relies on legacy global variables.
+func ParseCompoundStmt(filename string, readline func() ([]byte, error)) (f *File, err error) {
+	return LegacyFileOptions().ParseCompoundStmt(filename, readline)
+}
+
 // ParseCompoundStmt parses a single compound statement:
 // a blank line, a def, for, while, or if statement, or a
 // semicolon-separated list of simple statements followed
@@ -54,13 +66,13 @@
 // ParseCompoundStmt does not consume any following input.
 // The parser calls the readline function each
 // time it needs a new line of input.
-func ParseCompoundStmt(filename string, readline func() ([]byte, error)) (f *File, err error) {
+func (opts *FileOptions) ParseCompoundStmt(filename string, readline func() ([]byte, error)) (f *File, err error) {
 	in, err := newScanner(filename, readline, false)
 	if err != nil {
 		return nil, err
 	}
 
-	p := parser{in: in}
+	p := parser{options: opts, in: in}
 	defer p.in.recover(&err)
 
 	p.nextToken() // read first lookahead token
@@ -79,18 +91,24 @@
 		}
 	}
 
-	return &File{Path: filename, Stmts: stmts}, nil
+	return &File{Options: opts, Path: filename, Stmts: stmts}, nil
+}
+
+// ParseExpr calls the ParseExpr method of LegacyFileOptions().
+// Deprecated: relies on legacy global variables.
+func ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) {
+	return LegacyFileOptions().ParseExpr(filename, src, mode)
 }
 
 // ParseExpr parses a Starlark expression.
 // A comma-separated list of expressions is parsed as a tuple.
 // See Parse for explanation of parameters.
-func ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) {
+func (opts *FileOptions) ParseExpr(filename string, src interface{}, mode Mode) (expr Expr, err error) {
 	in, err := newScanner(filename, src, mode&RetainComments != 0)
 	if err != nil {
 		return nil, err
 	}
-	p := parser{in: in}
+	p := parser{options: opts, in: in}
 	defer p.in.recover(&err)
 
 	p.nextToken() // read first lookahead token
@@ -112,9 +130,10 @@
 }
 
 type parser struct {
-	in     *scanner
-	tok    Token
-	tokval tokenValue
+	options *FileOptions
+	in      *scanner
+	tok     Token
+	tokval  tokenValue
 }
 
 // nextToken advances the scanner and returns the position of the
@@ -139,7 +158,7 @@
 		}
 		stmts = p.parseStmt(stmts)
 	}
-	return &File{Stmts: stmts}
+	return &File{Options: p.options, Stmts: stmts}
 }
 
 func (p *parser) parseStmt(stmts []Stmt) []Stmt {
@@ -158,15 +177,17 @@
 func (p *parser) parseDefStmt() Stmt {
 	defpos := p.nextToken() // consume DEF
 	id := p.parseIdent()
-	p.consume(LPAREN)
+	lparen := p.consume(LPAREN)
 	params := p.parseParams()
-	p.consume(RPAREN)
+	rparen := p.consume(RPAREN)
 	p.consume(COLON)
 	body := p.parseSuite()
 	return &DefStmt{
 		Def:    defpos,
 		Name:   id,
+		Lparen: lparen,
 		Params: params,
+		Rparen: rparen,
 		Body:   body,
 	}
 }
@@ -275,10 +296,11 @@
 }
 
 // small_stmt = RETURN expr?
-//            | PASS | BREAK | CONTINUE
-//            | LOAD ...
-//            | expr ('=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=') expr   // assign
-//            | expr
+//
+//	| PASS | BREAK | CONTINUE
+//	| LOAD ...
+//	| expr ('=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=') expr   // assign
+//	| expr
 func (p *parser) parseSmallStmt() Stmt {
 	switch p.tok {
 	case RETURN:
@@ -415,21 +437,23 @@
 }
 
 // params = (param COMMA)* param COMMA?
-//        |
+//
+//	|
 //
 // param = IDENT
-//       | IDENT EQ test
-//       | STAR
-//       | STAR IDENT
-//       | STARSTAR IDENT
+//
+//	| IDENT EQ test
+//	| STAR
+//	| STAR IDENT
+//	| STARSTAR IDENT
 //
 // parseParams parses a parameter list.  The resulting expressions are of the form:
 //
-//      *Ident                                          x
-//      *Binary{Op: EQ, X: *Ident, Y: Expr}             x=y
-//      *Unary{Op: STAR}                                *
-//      *Unary{Op: STAR, X: *Ident}                     *args
-//      *Unary{Op: STARSTAR, X: *Ident}                 **kwargs
+//	*Ident                                          x
+//	*Binary{Op: EQ, X: *Ident, Y: Expr}             x=y
+//	*Unary{Op: STAR}                                *
+//	*Unary{Op: STAR, X: *Ident}                     *args
+//	*Unary{Op: STARSTAR, X: *Ident}                 **kwargs
 func (p *parser) parseParams() []Expr {
 	var params []Expr
 	for p.tok != RPAREN && p.tok != COLON && p.tok != EOF {
@@ -651,9 +675,10 @@
 }
 
 // primary_with_suffix = primary
-//                     | primary '.' IDENT
-//                     | primary slice_suffix
-//                     | primary call_suffix
+//
+//	| primary '.' IDENT
+//	| primary slice_suffix
+//	| primary call_suffix
 func (p *parser) parsePrimaryWithSuffix() Expr {
 	x := p.parsePrimary()
 	for {
@@ -770,12 +795,13 @@
 	return args
 }
 
-//  primary = IDENT
-//          | INT | FLOAT | STRING | BYTES
-//          | '[' ...                    // list literal or comprehension
-//          | '{' ...                    // dict literal or comprehension
-//          | '(' ...                    // tuple or parenthesized expression
-//          | ('-'|'+'|'~') primary_with_suffix
+// primary = IDENT
+//
+//	| INT | FLOAT | STRING | BYTES
+//	| '[' ...                    // list literal or comprehension
+//	| '{' ...                    // dict literal or comprehension
+//	| '(' ...                    // tuple or parenthesized expression
+//	| ('-'|'+'|'~') primary_with_suffix
 func (p *parser) parsePrimary() Expr {
 	switch p.tok {
 	case IDENT:
@@ -836,9 +862,10 @@
 }
 
 // list = '[' ']'
-//      | '[' expr ']'
-//      | '[' expr expr_list ']'
-//      | '[' expr (FOR loop_variables IN expr)+ ']'
+//
+//	| '[' expr ']'
+//	| '[' expr expr_list ']'
+//	| '[' expr (FOR loop_variables IN expr)+ ']'
 func (p *parser) parseList() Expr {
 	lbrack := p.nextToken()
 	if p.tok == RBRACK {
@@ -865,8 +892,9 @@
 }
 
 // dict = '{' '}'
-//      | '{' dict_entry_list '}'
-//      | '{' dict_entry FOR loop_variables IN expr '}'
+//
+//	| '{' dict_entry_list '}'
+//	| '{' dict_entry FOR loop_variables IN expr '}'
 func (p *parser) parseDict() Expr {
 	lbrace := p.nextToken()
 	if p.tok == RBRACE {
@@ -904,8 +932,9 @@
 }
 
 // comp_suffix = FOR loopvars IN expr comp_suffix
-//             | IF expr comp_suffix
-//             | ']'  or  ')'                              (end)
+//
+//	| IF expr comp_suffix
+//	| ']'  or  ')'                              (end)
 //
 // There can be multiple FOR/IF clauses; the first is always a FOR.
 func (p *parser) parseComprehensionSuffix(lbrace Position, body Expr, endBrace Token) Expr {
diff --git a/vendor/go.starlark.net/syntax/scan.go b/vendor/go.starlark.net/syntax/scan.go
index b080202..9549977 100644
--- a/vendor/go.starlark.net/syntax/scan.go
+++ b/vendor/go.starlark.net/syntax/scan.go
@@ -9,7 +9,6 @@
 import (
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
 	"math/big"
 	"os"
@@ -287,7 +286,7 @@
 	case []byte:
 		return src, nil
 	case io.Reader:
-		data, err := ioutil.ReadAll(src)
+		data, err := io.ReadAll(src)
 		if err != nil {
 			err = &os.PathError{Op: "read", Path: filename, Err: err}
 			return nil, err
@@ -296,7 +295,7 @@
 	case FilePortion:
 		return src.Content, nil
 	case nil:
-		return ioutil.ReadFile(filename)
+		return os.ReadFile(filename)
 	default:
 		return nil, fmt.Errorf("invalid source: %T", src)
 	}
diff --git a/vendor/go.starlark.net/syntax/syntax.go b/vendor/go.starlark.net/syntax/syntax.go
index 3756637..5bfbcec 100644
--- a/vendor/go.starlark.net/syntax/syntax.go
+++ b/vendor/go.starlark.net/syntax/syntax.go
@@ -70,7 +70,8 @@
 	Path  string
 	Stmts []Stmt
 
-	Module interface{} // a *resolve.Module, set by resolver
+	Module  interface{} // a *resolve.Module, set by resolver
+	Options *FileOptions
 }
 
 func (x *File) Span() (start, end Position) {
@@ -99,9 +100,10 @@
 func (*ReturnStmt) stmt() {}
 
 // An AssignStmt represents an assignment:
+//
 //	x = 0
 //	x, y = y, x
-// 	x += 1
+//	x += 1
 type AssignStmt struct {
 	commentsRef
 	OpPos Position
@@ -121,7 +123,9 @@
 	commentsRef
 	Def    Position
 	Name   *Ident
+	Lparen Position
 	Params []Expr // param = ident | ident=expr | * | *ident | **ident
+	Rparen Position
 	Body   []Stmt
 
 	Function interface{} // a *resolve.Function, set by resolver
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9a02d37..a77d51e 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -71,8 +71,8 @@
 go.chromium.org/luci/starlark/docgen/ast
 go.chromium.org/luci/starlark/docgen/docstring
 go.chromium.org/luci/starlark/docgen/symbols
-# go.starlark.net v0.0.0-20230807144010-2aa75752d1da
-## explicit; go 1.16
+# go.starlark.net v0.0.0-20230925163745-10651d5192ab
+## explicit; go 1.18
 go.starlark.net/internal/compile
 go.starlark.net/internal/spell
 go.starlark.net/lib/json