difftreelog
Merge pull request #132 from CertainLach/lsp
in: master
Introduce experimental rowan parser and pretty-printer
74 files changed
.cargo/config.tomldiffbeforeafterboth--- /dev/null
+++ b/.cargo/config.toml
@@ -0,0 +1,2 @@
+[alias]
+xtask = "run --package xtask --bin xtask --"
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,6 +3,21 @@
version = 3
[[package]]
+name = "addr2line"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
name = "ahash"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -25,24 +40,23 @@
[[package]]
name = "anstream"
-version = "0.3.2"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
+checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
- "is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
-version = "1.0.1"
+version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
+checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
[[package]]
name = "anstyle-parse"
@@ -59,34 +73,57 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
-version = "1.0.1"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
+checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
-version = "1.0.72"
+version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
+checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+
+[[package]]
+name = "ass-stroke"
+version = "0.1.0"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
+ "random_color",
+ "range-map",
+ "smallvec",
+]
[[package]]
+name = "ass-stroke"
+version = "0.1.0"
+source = "git+https://github.com/CertainLach/ass-stroke#c98c0213b9c5f775c0bddaa7b233a38c60859008"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
+ "random_color",
+ "range-map",
+ "smallvec",
+]
+
+[[package]]
name = "async-trait"
-version = "0.1.71"
+version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf"
+checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.28",
+ "syn 2.0.31",
]
[[package]]
@@ -96,10 +133,40 @@
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
+name = "backtrace"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
+
+[[package]]
+name = "backtrace-ext"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50"
+dependencies = [
+ "backtrace",
+]
+
+[[package]]
name = "base64"
-version = "0.21.2"
+version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
+
+[[package]]
+name = "beef"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
[[package]]
name = "bincode"
@@ -118,9 +185,9 @@
[[package]]
name = "bitflags"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "block-buffer"
@@ -132,10 +199,19 @@
]
[[package]]
+name = "bumpalo"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+
+[[package]]
name = "cc"
-version = "1.0.79"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "libc",
+]
[[package]]
name = "cfg-if"
@@ -145,20 +221,19 @@
[[package]]
name = "clap"
-version = "4.3.12"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3eab9e8ceb9afdade1ab3f0fd8dbce5b1b2f468ad653baf10e771781b2b67b73"
+checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
dependencies = [
"clap_builder",
"clap_derive",
- "once_cell",
]
[[package]]
name = "clap_builder"
-version = "4.3.12"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f2763db829349bf00cfc06251268865ed4363b93a943174f638daf3ecdba2cd"
+checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
@@ -168,30 +243,30 @@
[[package]]
name = "clap_complete"
-version = "4.3.2"
+version = "4.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5fc443334c81a804575546c5a8a79b4913b50e28d69232903604cada1de817ce"
+checksum = "586a385f7ef2f8b4d86bddaa0c094794e7ccbfe5ffef1f434fe928143fc783a5"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
-version = "4.3.12"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050"
+checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
"quote",
- "syn 2.0.28",
+ "syn 2.0.31",
]
[[package]]
name = "clap_lex"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
+checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "colorchoice"
@@ -200,6 +275,24 @@
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
+name = "console"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "countme"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
+
+[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -209,6 +302,25 @@
]
[[package]]
+name = "crossbeam-channel"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -240,14 +352,46 @@
]
[[package]]
+name = "dprint-core"
+version = "0.63.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77fb4fc41e8a0217e1c0031c26640126e3ff3aba40a98db8b1db7b4e13bfce29"
+dependencies = [
+ "anyhow",
+ "bumpalo",
+ "indexmap",
+ "rustc-hash",
+ "serde",
+ "unicode-width",
+]
+
+[[package]]
+name = "drop_bomb"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1"
+
+[[package]]
+name = "either"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+
+[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
name = "errno"
-version = "0.3.1"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
+checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
dependencies = [
"errno-dragonfly",
"libc",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -261,6 +405,27 @@
]
[[package]]
+name = "fastrand"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -271,6 +436,34 @@
]
[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "gimli"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+
+[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -298,6 +491,16 @@
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
+name = "idna"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -305,9 +508,29 @@
dependencies = [
"autocfg",
"hashbrown 0.12.3",
+ "serde",
]
[[package]]
+name = "indoc"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
+
+[[package]]
+name = "insta"
+version = "1.31.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0770b0a3d4c70567f0d58331f3088b0e4c4f56c9b8d764efe654b4a5d46de3a"
+dependencies = [
+ "console",
+ "lazy_static",
+ "linked-hash-map",
+ "similar",
+ "yaml-rust",
+]
+
+[[package]]
name = "is-terminal"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -315,7 +538,22 @@
dependencies = [
"hermit-abi",
"rustix",
- "windows-sys",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "is_ci"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
]
[[package]]
@@ -328,6 +566,7 @@
name = "jrsonnet"
version = "0.5.0-pre95"
dependencies = [
+ "ass-stroke 0.1.0 (git+https://github.com/CertainLach/ass-stroke)",
"clap",
"clap_complete",
"jrsonnet-cli",
@@ -376,6 +615,20 @@
]
[[package]]
+name = "jrsonnet-fmt"
+version = "0.5.0-pre95"
+dependencies = [
+ "ass-stroke 0.1.0",
+ "clap",
+ "dprint-core",
+ "indoc",
+ "insta",
+ "jrsonnet-rowan-parser",
+ "tempfile",
+ "thiserror",
+]
+
+[[package]]
name = "jrsonnet-gcmodule"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -408,6 +661,19 @@
]
[[package]]
+name = "jrsonnet-lsp"
+version = "0.5.0-pre95"
+dependencies = [
+ "anyhow",
+ "jrsonnet-evaluator",
+ "jrsonnet-rowan-parser",
+ "lsp-server",
+ "lsp-types",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
name = "jrsonnet-macros"
version = "0.5.0-pre95"
dependencies = [
@@ -429,6 +695,22 @@
]
[[package]]
+name = "jrsonnet-rowan-parser"
+version = "0.5.0-pre95"
+dependencies = [
+ "anyhow",
+ "backtrace",
+ "drop_bomb",
+ "indoc",
+ "insta",
+ "logos",
+ "miette",
+ "rowan",
+ "text-size",
+ "thiserror",
+]
+
+[[package]]
name = "jrsonnet-stdlib"
version = "0.5.0-pre95"
dependencies = [
@@ -467,6 +749,12 @@
]
[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -490,9 +778,9 @@
[[package]]
name = "linux-raw-sys"
-version = "0.4.3"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0"
+checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]]
name = "lock_api"
@@ -505,12 +793,113 @@
]
[[package]]
+name = "log"
+version = "0.4.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
+
+[[package]]
+name = "logos"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1"
+dependencies = [
+ "logos-derive",
+]
+
+[[package]]
+name = "logos-derive"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c"
+dependencies = [
+ "beef",
+ "fnv",
+ "proc-macro2",
+ "quote",
+ "regex-syntax",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "lsp-server"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f70570c1c29cf6654029b8fe201a5507c153f0d85be6f234d471d756bc36775a"
+dependencies = [
+ "crossbeam-channel",
+ "log",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "lsp-types"
+version = "0.93.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51"
+dependencies = [
+ "bitflags 1.3.2",
+ "serde",
+ "serde_json",
+ "serde_repr",
+ "url",
+]
+
+[[package]]
name = "md5"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771"
[[package]]
+name = "memchr"
+version = "2.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
+
+[[package]]
+name = "memoffset"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "miette"
+version = "5.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e"
+dependencies = [
+ "backtrace",
+ "backtrace-ext",
+ "is-terminal",
+ "miette-derive",
+ "once_cell",
+ "owo-colors",
+ "supports-color",
+ "supports-hyperlinks",
+ "supports-unicode",
+ "terminal_size",
+ "textwrap",
+ "thiserror",
+ "unicode-width",
+]
+
+[[package]]
+name = "miette-derive"
+version = "5.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.31",
+]
+
+[[package]]
name = "mimalloc-sys"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -530,10 +919,19 @@
]
[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+]
+
+[[package]]
name = "num-bigint"
-version = "0.4.3"
+version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
dependencies = [
"autocfg",
"num-integer",
@@ -553,20 +951,35 @@
[[package]]
name = "num-traits"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg",
]
[[package]]
+name = "object"
+version = "0.32.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
+name = "owo-colors"
+version = "3.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
+
+[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -586,7 +999,7 @@
"libc",
"redox_syscall",
"smallvec",
- "windows-targets",
+ "windows-targets 0.48.5",
]
[[package]]
@@ -623,24 +1036,135 @@
checksum = "9fa00462b37ead6d11a82c9d568b26682d78e0477dc02d1966c013af80969739"
[[package]]
+name = "percent-encoding"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
name = "proc-macro2"
-version = "1.0.65"
+version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92de25114670a878b1261c79c9f8f729fb97e95bac93f6312f583c60dd6a1dfe"
+checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.30"
+version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5907a1b7c277254a8b15170f6e7c97cfa60ee7872a3217663bb81151e48184bb"
+checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc",
+ "rand_pcg",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.10",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_pcg"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "random_color"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f5f34bd6526786b2ce5141fd37a4084b5da1ebae74595b5b0d05482a7cef7181"
+dependencies = [
+ "rand 0.7.3",
+]
+
+[[package]]
+name = "range-map"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12a5a2d6c7039059af621472a4389be1215a816df61aa4d531cfe85264aee95f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -650,6 +1174,31 @@
]
[[package]]
+name = "regex-syntax"
+version = "0.6.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
+
+[[package]]
+name = "rowan"
+version = "0.15.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64449cfef9483a475ed56ae30e2da5ee96448789fb2aa240a04beb6a055078bf"
+dependencies = [
+ "countme",
+ "hashbrown 0.12.3",
+ "memoffset",
+ "rustc-hash",
+ "text-size",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+
+[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -657,15 +1206,15 @@
[[package]]
name = "rustix"
-version = "0.38.4"
+version = "0.38.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
+checksum = "c0c3dde1fc030af041adc40e79c0e7fbcf431dd24870053d187d7c66e4b87453"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -676,9 +1225,9 @@
[[package]]
name = "scopeguard"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
@@ -697,14 +1246,14 @@
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.28",
+ "syn 2.0.31",
]
[[package]]
name = "serde_json"
-version = "1.0.104"
+version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
+checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [
"itoa",
"ryu",
@@ -712,6 +1261,17 @@
]
[[package]]
+name = "serde_repr"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.31",
+]
+
+[[package]]
name = "serde_yaml_with_quirks"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -756,12 +1316,24 @@
]
[[package]]
+name = "similar"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
+
+[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
+name = "smawk"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f67ad224767faa3c7d8b6d91985b78e70a1324408abcb1cfcc2be4c06bc06043"
+
+[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -796,6 +1368,34 @@
]
[[package]]
+name = "supports-color"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4950e7174bffabe99455511c39707310e7e9b440364a2fcb1cc21521be57b354"
+dependencies = [
+ "is-terminal",
+ "is_ci",
+]
+
+[[package]]
+name = "supports-hyperlinks"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
+dependencies = [
+ "is-terminal",
+]
+
+[[package]]
+name = "supports-unicode"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7"
+dependencies = [
+ "is-terminal",
+]
+
+[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -808,9 +1408,9 @@
[[package]]
name = "syn"
-version = "2.0.28"
+version = "2.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
+checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398"
dependencies = [
"proc-macro2",
"quote",
@@ -818,6 +1418,29 @@
]
[[package]]
+name = "tempfile"
+version = "3.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "terminal_size"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
name = "tests"
version = "0.1.0"
dependencies = [
@@ -828,44 +1451,115 @@
]
[[package]]
+name = "text-size"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f18aa187839b2bdb1ad2fa35ead8c4c2976b64e4363c386d45ac0f7ee85c9233"
+
+[[package]]
+name = "textwrap"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
+dependencies = [
+ "smawk",
+ "unicode-linebreak",
+ "unicode-width",
+]
+
+[[package]]
name = "thiserror"
-version = "1.0.43"
+version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42"
+checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.43"
+version = "1.0.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f"
+checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.28",
+ "syn 2.0.31",
]
[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
+name = "ungrammar"
+version = "1.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e5df347f0bf3ec1d670aad6ca5c6a1859cd9ea61d2113125794654ccced68f"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+
+[[package]]
name = "unicode-ident"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
+name = "unicode-linebreak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
+name = "url"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+ "serde",
+]
+
+[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -878,6 +1572,18 @@
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -901,69 +1607,163 @@
[[package]]
name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
+name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
]
[[package]]
name = "windows-targets"
-version = "0.48.1"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
]
[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "xshell"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
+dependencies = [
+ "xshell-macros",
+]
+
+[[package]]
+name = "xshell-macros"
+version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"
+
+[[package]]
+name = "xtask"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "indexmap",
+ "itertools",
+ "proc-macro2",
+ "quote",
+ "ungrammar",
+ "xshell",
+]
[[package]]
name = "yaml-rust"
Cargo.tomldiffbeforeafterboth--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
[workspace]
package.version = "0.5.0-pre95"
package.repository = "https://github.com/CertainLach/jrsonnet"
-members = ["crates/*", "bindings/jsonnet", "cmds/jrsonnet", "tests"]
+members = ["crates/*", "bindings/jsonnet", "cmds/*", "tests", "xtask"]
default-members = ["cmds/jrsonnet"]
resolver = "2"
@@ -9,6 +9,7 @@
jrsonnet-evaluator = { path = "./crates/jrsonnet-evaluator", version = "0.5.0-pre95" }
jrsonnet-macros = { path = "./crates/jrsonnet-macros", version = "0.5.0-pre95" }
jrsonnet-parser = { path = "./crates/jrsonnet-parser", version = "0.5.0-pre95" }
+jrsonnet-rowan-parser = { path = "./crates/jrsonnet-rowan-parser", version = "0.5.0-pre95" }
jrsonnet-interner = { path = "./crates/jrsonnet-interner", version = "0.5.0-pre95" }
jrsonnet-stdlib = { path = "./crates/jrsonnet-stdlib", version = "0.5.0-pre95" }
jrsonnet-cli = { path = "./crates/jrsonnet-cli", version = "0.5.0-pre95" }
cmds/jrsonnet-fmt/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "jrsonnet-fmt"
+version.workspace = true
+edition = "2021"
+
+[dependencies]
+dprint-core = "0.63.2"
+jrsonnet-rowan-parser.workspace = true
+insta = "1.15"
+indoc = "1.0"
+ass-stroke = { git = "https://github.com/CertainLach/ass-stroke.git", version = "0.1.0" }
+clap = { version = "4.4.2", features = ["derive"] }
+tempfile = "3.8.0"
+thiserror = "1.0.48"
cmds/jrsonnet-fmt/src/children.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/src/children.rs
@@ -0,0 +1,290 @@
+// TODO: Return errors as trivia
+
+use std::{fmt::Debug, mem};
+
+use jrsonnet_rowan_parser::{
+ nodes::{CustomError, Trivia, TriviaKind},
+ AstNode, AstToken, SyntaxElement, SyntaxNode, TS,
+};
+
+pub type ChildTrivia = Vec<Result<Trivia, String>>;
+
+/// Node should have no non-trivia tokens before element
+pub fn trivia_before(node: SyntaxNode, end: Option<&SyntaxElement>) -> ChildTrivia {
+ let mut out = Vec::new();
+ for item in node.children_with_tokens() {
+ if Some(&item) == end {
+ break;
+ }
+
+ if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()));
+ } else if end.is_none() {
+ break;
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()),
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+ out
+}
+/// Node should have no non-trivia tokens after element
+pub fn trivia_after(node: SyntaxNode, start: Option<&SyntaxElement>) -> ChildTrivia {
+ if start.is_none() {
+ return Vec::new();
+ }
+ let mut iter = node.children_with_tokens().peekable();
+ while iter.peek() != start {
+ iter.next();
+ }
+ iter.next();
+ let mut out = Vec::new();
+ for item in iter {
+ if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()))
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()),
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+ out
+}
+
+pub fn trivia_between(
+ node: SyntaxNode,
+ start: Option<&SyntaxElement>,
+ end: Option<&SyntaxElement>,
+) -> EndingComments {
+ let mut iter = node.children_with_tokens().peekable();
+ while iter.peek() != start {
+ iter.next();
+ }
+ iter.next();
+
+ let loose = start.is_none() || end.is_none();
+
+ let mut out = Vec::new();
+ for item in iter.take_while(|i| Some(i) != end) {
+ if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ out.push(Ok(trivia));
+ } else if CustomError::can_cast(item.kind()) {
+ out.push(Err(item.to_string()))
+ } else if loose {
+ break;
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()),
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+ EndingComments {
+ should_start_with_newline: should_start_with_newline(None, &out),
+ trivia: out,
+ }
+}
+
+pub fn children_between<T: AstNode + Debug>(
+ node: SyntaxNode,
+ start: Option<&SyntaxElement>,
+ end: Option<&SyntaxElement>,
+ trailing: Option<ChildTrivia>,
+) -> (Vec<Child<T>>, EndingComments) {
+ let mut iter = node.children_with_tokens().peekable();
+ if start.is_some() {
+ while iter.peek() != start {
+ iter.next();
+ }
+ iter.next();
+ }
+ children(
+ iter.take_while(|i| Some(i) != end),
+ start.is_none() && end.is_none(),
+ trailing,
+ )
+}
+
+pub fn should_start_with_newline(prev_inline: Option<&ChildTrivia>, tt: &ChildTrivia) -> bool {
+ count_newlines_before(tt)
+ + prev_inline
+ .map(count_newlines_after)
+ .unwrap_or_default()
+
+ // First for previous item end, second for current item
+ >= 2
+}
+
+fn count_newlines_before(tt: &ChildTrivia) -> usize {
+ let mut nl_count = 0;
+ for t in tt {
+ match t {
+ Ok(t) => match t.kind() {
+ TriviaKind::Whitespace => {
+ nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
+ }
+ _ => break,
+ },
+ Err(_) => {
+ nl_count += 1;
+ }
+ }
+ }
+ nl_count
+}
+fn count_newlines_after(tt: &ChildTrivia) -> usize {
+ let mut nl_count = 0;
+ for t in tt.iter().rev() {
+ match t {
+ Ok(t) => match t.kind() {
+ TriviaKind::Whitespace => {
+ nl_count += t.text().bytes().filter(|b| *b == b'\n').count();
+ }
+ TriviaKind::SingleLineHashComment => {
+ nl_count += 1;
+ break;
+ }
+ TriviaKind::SingleLineSlashComment => {
+ nl_count += 1;
+ break;
+ }
+ _ => {}
+ },
+ Err(_) => nl_count += 1,
+ }
+ }
+ nl_count
+}
+
+pub fn children<T: AstNode + Debug>(
+ items: impl Iterator<Item = SyntaxElement>,
+ loose: bool,
+ mut trailing: Option<ChildTrivia>,
+) -> (Vec<Child<T>>, EndingComments) {
+ let mut out = Vec::new();
+ let mut current_child = None::<Child<T>>;
+ let mut next = ChildTrivia::new();
+ // Previous element ended, do not add more inline comments
+ let mut started_next = false;
+ let mut had_some = false;
+
+ for item in items {
+ if let Some(value) = item.as_node().cloned().and_then(T::cast) {
+ let before_trivia = if let Some(trailing) = trailing.take() {
+ assert!(next.is_empty());
+ trailing
+ } else {
+ mem::take(&mut next)
+ };
+ let last_child = current_child.replace(Child {
+ // First item should not start with newline
+ should_start_with_newline: had_some
+ && should_start_with_newline(
+ current_child.as_ref().map(|c| &c.inline_trivia),
+ &before_trivia,
+ ),
+ before_trivia,
+ value,
+ inline_trivia: Vec::new(),
+ });
+ if let Some(last_child) = last_child {
+ out.push(last_child)
+ }
+ had_some = true;
+ started_next = false;
+ } else if let Some(trivia) = item.as_token().cloned().and_then(Trivia::cast) {
+ let is_single_line_comment = trivia.kind() == TriviaKind::SingleLineHashComment
+ || trivia.kind() == TriviaKind::SingleLineSlashComment;
+ if trailing.is_some() {
+ // Someone have already parsed trivia for us
+ continue;
+ } else if started_next
+ || current_child.is_none()
+ || trivia.text().contains('\n') && !is_single_line_comment
+ {
+ next.push(Ok(trivia.clone()));
+ started_next = true;
+ } else {
+ let cur = current_child.as_mut().expect("checked not none");
+ cur.inline_trivia.push(Ok(trivia));
+ if is_single_line_comment {
+ started_next = true;
+ }
+ }
+ had_some = true;
+ } else if CustomError::can_cast(item.kind()) {
+ next.push(Err(item.to_string()))
+ } else if loose {
+ if had_some {
+ break;
+ }
+ started_next = true;
+ } else {
+ assert!(
+ TS![, ;].contains(item.kind()),
+ "silently eaten token: {:?}",
+ item.kind()
+ )
+ }
+ }
+
+ let ending_comments = EndingComments {
+ should_start_with_newline: should_start_with_newline(
+ current_child.as_ref().map(|c| &c.inline_trivia),
+ &next,
+ ),
+ trivia: next,
+ };
+
+ if let Some(current_child) = current_child {
+ out.push(current_child);
+ }
+
+ (out, ending_comments)
+}
+
+#[derive(Debug)]
+pub struct Child<T> {
+ /// If this child has two newlines above in source code, so it needs to have it in the output
+ pub should_start_with_newline: bool,
+ /// Comment before item, i.e
+ ///
+ /// ```ignore
+ /// // Comment
+ /// item
+ /// ```
+ pub before_trivia: ChildTrivia,
+ pub value: T,
+ /// Comment after line, but located at same line
+ ///
+ /// ```ignore
+ /// item1, // Inline comment
+ /// // Not inline comment
+ /// item2,
+ /// ```
+ pub inline_trivia: ChildTrivia,
+}
+
+pub struct EndingComments {
+ /// If this child has two newlines above in source code, so it needs to have it in the output
+ pub should_start_with_newline: bool,
+ pub trivia: ChildTrivia,
+}
+impl EndingComments {
+ pub fn is_empty(&self) -> bool {
+ !self.should_start_with_newline && self.trivia.is_empty()
+ }
+ pub fn extract_trailing(&mut self) -> ChildTrivia {
+ mem::take(&mut self.trivia)
+ }
+}
cmds/jrsonnet-fmt/src/comments.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/src/comments.rs
@@ -0,0 +1,183 @@
+use dprint_core::formatting::PrintItems;
+use jrsonnet_rowan_parser::{nodes::TriviaKind, AstToken};
+
+use crate::{children::ChildTrivia, p, pi};
+
+pub enum CommentLocation {
+ /// Above local, field, other things
+ AboveItem,
+ /// After item
+ ItemInline,
+ /// After all items in object
+ EndOfItems,
+}
+
+#[must_use]
+pub fn format_comments(comments: &ChildTrivia, loc: CommentLocation) -> PrintItems {
+ let mut pi = p!(new:);
+
+ for c in comments {
+ let Ok(c) = c else {
+ let mut text = c.as_ref().unwrap_err() as &str;
+ while !text.is_empty() {
+ let pos = text.find(|c| c == '\n' || c == '\t').unwrap_or(text.len());
+ let sliced = &text[..pos];
+ p!(pi: string(sliced.to_string()));
+ text = &text[pos..];
+ if !text.is_empty() {
+ match text.as_bytes()[0] {
+ b'\n' => p!(pi: nl),
+ b'\t' => p!(pi: tab),
+ _ => unreachable!(),
+ }
+ text = &text[1..];
+ }
+ }
+ continue;
+ };
+ match c.kind() {
+ TriviaKind::Whitespace => {}
+ TriviaKind::MultiLineComment => {
+ let mut text = c
+ .text()
+ .strip_prefix("/*")
+ .expect("ml comment starts with /*")
+ .strip_suffix("*/")
+ .expect("ml comment ends with */");
+ // doc-style comment, /**
+ let doc = if text.starts_with('*') {
+ text = &text[1..];
+ true
+ } else {
+ false
+ };
+ // Is comment starts with text immediatly, i.e /*text
+ let mut immediate_start = true;
+ let mut lines = text
+ .split('\n')
+ .map(|l| l.trim_end().to_string())
+ .skip_while(|l| {
+ if l.is_empty() {
+ immediate_start = false;
+ true
+ } else {
+ false
+ }
+ })
+ .collect::<Vec<_>>();
+ while lines.last().map(|l| l.is_empty()).unwrap_or(false) {
+ lines.pop();
+ }
+ if lines.len() == 1 && !doc {
+ if matches!(loc, CommentLocation::ItemInline) {
+ p!(pi: str(" "));
+ }
+ p!(pi: str("/* ") string(lines[0].trim().to_string()) str(" */"))
+ } else if !lines.is_empty() {
+ fn common_ws_prefix<'a>(a: &'a str, b: &str) -> &'a str {
+ let offset = a
+ .bytes()
+ .zip(b.bytes())
+ .take_while(|(a, b)| a == b && (a.is_ascii_whitespace() || *a == b'*'))
+ .count();
+ &a[..offset]
+ }
+ // First line is not empty, extract ws prefix of it
+ let mut common_ws_padding = (if immediate_start && lines.len() > 1 {
+ common_ws_prefix(&lines[1], &lines[1])
+ } else {
+ common_ws_prefix(&lines[0], &lines[0])
+ })
+ .to_string();
+ for line in lines
+ .iter()
+ .skip(if immediate_start { 2 } else { 1 })
+ .filter(|l| !l.is_empty())
+ {
+ common_ws_padding = common_ws_prefix(&common_ws_padding, line).to_string();
+ }
+ for line in lines
+ .iter_mut()
+ .skip(if immediate_start { 1 } else { 0 })
+ .filter(|l| !l.is_empty())
+ {
+ *line = line
+ .strip_prefix(&common_ws_padding)
+ .expect("all non-empty lines start with this padding")
+ .to_string();
+ }
+
+ p!(pi: str("/*"));
+ if doc {
+ p!(pi: str("*"));
+ }
+ p!(pi: nl);
+ for mut line in lines {
+ if doc {
+ p!(pi: str(" *"));
+ }
+ if line.is_empty() {
+ p!(pi: nl);
+ } else {
+ if doc {
+ p!(pi: str(" "));
+ }
+ while let Some(new_line) = line.strip_prefix('\t') {
+ if doc {
+ p!(pi: str(" "));
+ } else {
+ p!(pi: tab);
+ }
+ line = new_line.to_string();
+ }
+ p!(pi: string(line.to_string()) nl)
+ }
+ }
+ if doc {
+ p!(pi: str(" "));
+ }
+ p!(pi: str("*/") nl)
+ }
+ }
+ // TODO: Keep common padding for multiple continous lines of single-line comments
+ // I.e
+ // ```
+ // # Line1
+ // # Line2
+ // ```
+ // Should be reformatted as
+ // ```
+ // # Line1
+ // # Line2
+ // ```
+ // But currently comment formatter is not aware of continous comment lines, and reformats it as
+ // ```
+ // # Line1
+ // # Line2
+ // ```
+ TriviaKind::SingleLineHashComment => {
+ if matches!(loc, CommentLocation::ItemInline) {
+ p!(pi: str(" "))
+ }
+ p!(pi: str("# ") string(c.text().strip_prefix('#').expect("hash comment starts with #").trim().to_string()));
+ if !matches!(loc, CommentLocation::ItemInline) {
+ p!(pi: nl)
+ }
+ }
+ TriviaKind::SingleLineSlashComment => {
+ if matches!(loc, CommentLocation::ItemInline) {
+ p!(pi: str(" "))
+ }
+ p!(pi: str("// ") string(c.text().strip_prefix("//").expect("comment starts with //").trim().to_string()));
+ if !matches!(loc, CommentLocation::ItemInline) {
+ p!(pi: nl)
+ }
+ }
+ // Garbage in - garbage out
+ TriviaKind::ErrorCommentTooShort => p!(pi: str("/*/")),
+ TriviaKind::ErrorCommentUnterminated => p!(pi: string(c.text().to_string())),
+ }
+ }
+
+ pi
+}
cmds/jrsonnet-fmt/src/main.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/src/main.rs
@@ -0,0 +1,804 @@
+use std::{
+ any::type_name,
+ fs,
+ io::{self, Write},
+ path::PathBuf,
+ process,
+};
+
+use children::{children_between, trivia_before};
+use clap::Parser;
+use dprint_core::formatting::{PrintItems, PrintOptions};
+use jrsonnet_rowan_parser::{
+ nodes::{
+ ArgsDesc, Assertion, BinaryOperator, Bind, CompSpec, Destruct, DestructArrayPart,
+ DestructRest, Expr, ExprBase, FieldName, ForSpec, IfSpec, ImportKind, Literal, Member,
+ Name, Number, ObjBody, ObjLocal, ParamsDesc, SliceDesc, SourceFile, Stmt, Suffix, Text,
+ UnaryOperator, Visibility,
+ },
+ AstNode, AstToken, SyntaxToken,
+};
+
+use crate::{
+ children::{trivia_after, trivia_between},
+ comments::{format_comments, CommentLocation},
+};
+
+mod children;
+mod comments;
+#[cfg(test)]
+mod tests;
+
+pub trait Printable {
+ fn print(&self) -> PrintItems;
+}
+
+macro_rules! pi {
+ (@i; $($t:tt)*) => {{
+ #[allow(unused_mut)]
+ let mut o = dprint_core::formatting::PrintItems::new();
+ pi!(@s; o: $($t)*);
+ o
+ }};
+ (@s; $o:ident: str($e:expr $(,)?) $($t:tt)*) => {{
+ $o.push_str($e);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: string($e:expr $(,)?) $($t:tt)*) => {{
+ $o.push_string($e);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: nl $($t:tt)*) => {{
+ $o.push_signal(dprint_core::formatting::Signal::NewLine);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: tab $($t:tt)*) => {{
+ $o.push_signal(dprint_core::formatting::Signal::Tab);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: >i $($t:tt)*) => {{
+ $o.push_signal(dprint_core::formatting::Signal::StartIndent);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: <i $($t:tt)*) => {{
+ $o.push_signal(dprint_core::formatting::Signal::FinishIndent);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: {$expr:expr} $($t:tt)*) => {{
+ $o.extend($expr.print());
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: items($expr:expr) $($t:tt)*) => {{
+ $o.extend($expr);
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: if ($e:expr)($($then:tt)*) $($t:tt)*) => {{
+ if $e {
+ pi!(@s; $o: $($then)*);
+ }
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $o:ident: ifelse ($e:expr)($($then:tt)*)($($else:tt)*) $($t:tt)*) => {{
+ if $e {
+ pi!(@s; $o: $($then)*);
+ } else {
+ pi!(@s; $o: $($else)*);
+ }
+ pi!(@s; $o: $($t)*);
+ }};
+ (@s; $i:ident:) => {}
+}
+macro_rules! p {
+ (new: $($t:tt)*) => {
+ pi!(@i; $($t)*)
+ };
+ ($o:ident: $($t:tt)*) => {
+ pi!(@s; $o: $($t)*)
+ };
+}
+pub(crate) use p;
+pub(crate) use pi;
+
+impl<P> Printable for Option<P>
+where
+ P: Printable,
+{
+ fn print(&self) -> PrintItems {
+ if let Some(v) = self {
+ v.print()
+ } else {
+ p!(new: string(
+ format!(
+ "/*missing {}*/",
+ type_name::<P>().replace("jrsonnet_rowan_parser::generated::nodes::", "")
+ ),
+ ))
+ }
+ }
+}
+
+impl Printable for SyntaxToken {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.to_string()))
+ }
+}
+
+impl Printable for Text {
+ fn print(&self) -> PrintItems {
+ p!(new: string(format!("{}", self)))
+ }
+}
+impl Printable for Number {
+ fn print(&self) -> PrintItems {
+ p!(new: string(format!("{}", self)))
+ }
+}
+
+impl Printable for Name {
+ fn print(&self) -> PrintItems {
+ p!(new: {self.ident_lit()})
+ }
+}
+
+impl Printable for DestructRest {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new: str("..."));
+ if let Some(name) = self.into() {
+ p!(pi: {name});
+ }
+ pi
+ }
+}
+
+impl Printable for Destruct {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new:);
+ match self {
+ Destruct::DestructFull(f) => {
+ p!(pi: {f.name()})
+ }
+ Destruct::DestructSkip(_) => p!(pi: str("?")),
+ Destruct::DestructArray(a) => {
+ p!(pi: str("[") >i nl);
+ for el in a.destruct_array_parts() {
+ match el {
+ DestructArrayPart::DestructArrayElement(e) => {
+ p!(pi: {e.destruct()} str(",") nl)
+ }
+ DestructArrayPart::DestructRest(d) => {
+ p!(pi: {d} str(",") nl)
+ }
+ }
+ }
+ p!(pi: <i str("]"));
+ }
+ Destruct::DestructObject(o) => {
+ p!(pi: str("{") >i nl);
+ for item in o.destruct_object_fields() {
+ p!(pi: {item.field()});
+ if let Some(des) = item.destruct() {
+ p!(pi: str(": ") {des})
+ }
+ if let Some(def) = item.expr() {
+ p!(pi: str(" = ") {def});
+ }
+ p!(pi: str(",") nl);
+ }
+ if let Some(rest) = o.destruct_rest() {
+ p!(pi: {rest} nl)
+ }
+ p!(pi: <i str("}"));
+ }
+ }
+ pi
+ }
+}
+
+impl Printable for FieldName {
+ fn print(&self) -> PrintItems {
+ match self {
+ FieldName::FieldNameFixed(f) => {
+ if let Some(id) = f.id() {
+ p!(new: {id})
+ } else if let Some(str) = f.text() {
+ p!(new: {str})
+ } else {
+ p!(new: str("/*missing FieldName*/"))
+ }
+ }
+ FieldName::FieldNameDynamic(d) => {
+ p!(new: str("[") {d.expr()} str("]"))
+ }
+ }
+ }
+}
+
+impl Printable for Visibility {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.to_string()))
+ }
+}
+
+impl Printable for ObjLocal {
+ fn print(&self) -> PrintItems {
+ p!(new: str("local ") {self.bind()})
+ }
+}
+
+impl Printable for Assertion {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new: str("assert ") {self.condition()});
+ if self.colon_token().is_some() || self.message().is_some() {
+ p!(pi: str(": ") {self.message()})
+ }
+ pi
+ }
+}
+
+impl Printable for ParamsDesc {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new: str("(") >i nl);
+ for param in self.params() {
+ p!(pi: {param.destruct()});
+ if param.assign_token().is_some() || param.expr().is_some() {
+ p!(pi: str(" = ") {param.expr()})
+ }
+ p!(pi: str(",") nl)
+ }
+ p!(pi: <i str(")"));
+ pi
+ }
+}
+impl Printable for ArgsDesc {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new: str("(") >i nl);
+ for arg in self.args() {
+ if arg.name().is_some() || arg.assign_token().is_some() {
+ p!(pi: {arg.name()} str(" = "));
+ }
+ p!(pi: {arg.expr()} str(",") nl)
+ }
+ p!(pi: <i str(")"));
+ pi
+ }
+}
+impl Printable for SliceDesc {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new: str("["));
+ if self.from().is_some() {
+ p!(pi: {self.from()});
+ }
+ p!(pi: str(":"));
+ if self.end().is_some() {
+ p!(pi: {self.end().map(|e|e.expr())})
+ }
+ // Keep only one : in case if we don't need step
+ if self.step().is_some() {
+ p!(pi: str(":") {self.step().map(|e|e.expr())});
+ }
+ p!(pi: str("]"));
+ pi
+ }
+}
+
+impl Printable for Member {
+ fn print(&self) -> PrintItems {
+ match self {
+ Member::MemberBindStmt(b) => {
+ p!(new: {b.obj_local()})
+ }
+ Member::MemberAssertStmt(ass) => {
+ p!(new: {ass.assertion()})
+ }
+ Member::MemberFieldNormal(n) => {
+ p!(new: {n.field_name()} if(n.plus_token().is_some())({n.plus_token()}) {n.visibility()} str(" ") {n.expr()})
+ }
+ Member::MemberFieldMethod(m) => {
+ p!(new: {m.field_name()} {m.params_desc()} {m.visibility()} str(" ") {m.expr()})
+ }
+ }
+ }
+}
+
+impl Printable for ObjBody {
+ fn print(&self) -> PrintItems {
+ match self {
+ ObjBody::ObjBodyComp(l) => {
+ let (children, mut end_comments) = children_between::<Member>(
+ l.syntax().clone(),
+ l.l_brace_token().map(Into::into).as_ref(),
+ Some(
+ &(l.comp_specs()
+ .next()
+ .expect("at least one spec is defined")
+ .syntax()
+ .clone())
+ .into(),
+ ),
+ None,
+ );
+ let trailing_for_comp = end_comments.extract_trailing();
+ let mut pi = p!(new: str("{") >i nl);
+ for mem in children.into_iter() {
+ if mem.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {mem.value} str(","));
+ p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
+ p!(pi: nl)
+ }
+
+ if end_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+
+ let (compspecs, end_comments) = children_between::<CompSpec>(
+ l.syntax().clone(),
+ l.member_comps()
+ .last()
+ .map(|m| m.syntax().clone())
+ .map(Into::into)
+ .or_else(|| l.l_brace_token().map(Into::into))
+ .as_ref(),
+ l.r_brace_token().map(Into::into).as_ref(),
+ Some(trailing_for_comp),
+ );
+ for mem in compspecs.into_iter() {
+ if mem.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {mem.value});
+ p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
+ }
+ if end_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+
+ p!(pi: nl <i str("}"));
+ pi
+ }
+ ObjBody::ObjBodyMemberList(l) => {
+ let (children, end_comments) = children_between::<Member>(
+ l.syntax().clone(),
+ l.l_brace_token().map(Into::into).as_ref(),
+ l.r_brace_token().map(Into::into).as_ref(),
+ None,
+ );
+ if children.is_empty() && end_comments.is_empty() {
+ return p!(new: str("{ }"));
+ }
+ let mut pi = p!(new: str("{") >i nl);
+ for mem in children.into_iter() {
+ if mem.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&mem.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {mem.value} str(","));
+ p!(pi: items(format_comments(&mem.inline_trivia, CommentLocation::ItemInline)));
+ p!(pi: nl)
+ }
+
+ if end_comments.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+ p!(pi: <i str("}"));
+ pi
+ }
+ }
+ }
+}
+impl Printable for UnaryOperator {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.text().to_string()))
+ }
+}
+impl Printable for BinaryOperator {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.text().to_string()))
+ }
+}
+impl Printable for Bind {
+ fn print(&self) -> PrintItems {
+ match self {
+ Bind::BindDestruct(d) => {
+ p!(new: {d.into()} str(" = ") {d.value()})
+ }
+ Bind::BindFunction(f) => {
+ p!(new: {f.name()} {f.params()} str(" = ") {f.value()})
+ }
+ }
+ }
+}
+impl Printable for Literal {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.syntax().to_string()))
+ }
+}
+impl Printable for ImportKind {
+ fn print(&self) -> PrintItems {
+ p!(new: string(self.syntax().to_string()))
+ }
+}
+impl Printable for ForSpec {
+ fn print(&self) -> PrintItems {
+ p!(new: str("for ") {self.bind()} str(" in ") {self.expr()})
+ }
+}
+impl Printable for IfSpec {
+ fn print(&self) -> PrintItems {
+ p!(new: str("if ") {self.expr()})
+ }
+}
+impl Printable for CompSpec {
+ fn print(&self) -> PrintItems {
+ match self {
+ CompSpec::ForSpec(f) => f.print(),
+ CompSpec::IfSpec(i) => i.print(),
+ }
+ }
+}
+impl Printable for Expr {
+ fn print(&self) -> PrintItems {
+ let mut o = p!(new:);
+ let (stmts, ending) = children_between::<Stmt>(
+ self.syntax().clone(),
+ None,
+ self.expr_base()
+ .as_ref()
+ .map(ExprBase::syntax)
+ .cloned()
+ .map(Into::into)
+ .as_ref(),
+ None,
+ );
+ for stmt in stmts {
+ p!(o: {stmt.value});
+ }
+ p!(o: {self.expr_base()});
+ let (suffixes, ending) = children_between::<Suffix>(
+ self.syntax().clone(),
+ self.expr_base()
+ .as_ref()
+ .map(ExprBase::syntax)
+ .cloned()
+ .map(Into::into)
+ .as_ref(),
+ None,
+ None,
+ );
+ for suffix in suffixes {
+ p!(o: {suffix.value});
+ }
+ o
+ }
+}
+impl Printable for Suffix {
+ fn print(&self) -> PrintItems {
+ let mut o = p!(new:);
+ match self {
+ Suffix::SuffixIndex(i) => {
+ if i.question_mark_token().is_some() {
+ p!(o: str("?"));
+ }
+ p!(o: str(".") {i.index()});
+ }
+ Suffix::SuffixIndexExpr(e) => {
+ if e.question_mark_token().is_some() {
+ p!(o: str(".?"));
+ }
+ p!(o: str("[") {e.index()} str("]"))
+ }
+ Suffix::SuffixSlice(d) => {
+ p!(o: {d.slice_desc()})
+ }
+ Suffix::SuffixApply(a) => {
+ p!(o: {a.args_desc()})
+ }
+ }
+ o
+ }
+}
+impl Printable for Stmt {
+ fn print(&self) -> PrintItems {
+ match self {
+ Stmt::StmtLocal(l) => {
+ let mut pi = p!(new:);
+ let (binds, end_comments) = children_between::<Bind>(
+ l.syntax().clone(),
+ l.local_kw_token().map(Into::into).as_ref(),
+ l.semi_token().map(Into::into).as_ref(),
+ None,
+ );
+ if binds.len() == 1 {
+ let bind = &binds[0];
+ p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: str("local ") {bind.value});
+ // TODO: keep end_comments, child.inline_trivia somehow, force multiple locals formatting in case of presence?
+ } else {
+ p!(pi: str("local") >i nl);
+ for bind in binds {
+ if bind.should_start_with_newline {
+ p!(pi: nl);
+ }
+ p!(pi: items(format_comments(&bind.before_trivia, CommentLocation::AboveItem)));
+ p!(pi: {bind.value} str(","));
+ p!(pi: items(format_comments(&bind.inline_trivia, CommentLocation::ItemInline)) nl);
+ }
+ if end_comments.should_start_with_newline {
+ p!(pi: nl)
+ }
+ p!(pi: items(format_comments(&end_comments.trivia, CommentLocation::EndOfItems)));
+ p!(pi: <i);
+ }
+ p!(pi: str(";") nl);
+ pi
+ }
+ Stmt::StmtAssert(a) => {
+ p!(new: {a.assertion()} str(";") nl)
+ }
+ }
+ }
+}
+impl Printable for ExprBase {
+ fn print(&self) -> PrintItems {
+ match self {
+ Self::ExprBinary(b) => {
+ p!(new: {b.lhs_work()} str(" ") {b.binary_operator()} str(" ") {b.rhs_work()})
+ }
+ Self::ExprUnary(u) => p!(new: {u.unary_operator()} {u.rhs()}),
+ // Self::ExprSlice(s) => {
+ // p!(new: {s.expr()} {s.slice_desc()})
+ // }
+ // Self::ExprIndex(i) => {
+ // p!(new: {i.expr()} str(".") {i.index()})
+ // }
+ // Self::ExprIndexExpr(i) => p!(new: {i.base()} str("[") {i.index()} str("]")),
+ // Self::ExprApply(a) => {
+ // let mut pi = p!(new: {a.expr()} {a.args_desc()});
+ // if a.tailstrict_kw_token().is_some() {
+ // p!(pi: str(" tailstrict"));
+ // }
+ // pi
+ // }
+ Self::ExprObjExtend(ex) => {
+ p!(new: {ex.lhs_work()} str(" ") {ex.rhs_work()})
+ }
+ Self::ExprParened(p) => {
+ p!(new: str("(") {p.expr()} str(")"))
+ }
+ Self::ExprString(s) => p!(new: {s.text()}),
+ Self::ExprNumber(n) => p!(new: {n.number()}),
+ Self::ExprArray(a) => {
+ let mut pi = p!(new: str("[") >i nl);
+ for el in a.exprs() {
+ p!(pi: {el} str(",") nl);
+ }
+ p!(pi: <i str("]"));
+ pi
+ }
+ Self::ExprObject(obj) => {
+ p!(new: {obj.obj_body()})
+ }
+ Self::ExprArrayComp(arr) => {
+ let mut pi = p!(new: str("[") {arr.expr()});
+ for spec in arr.comp_specs() {
+ p!(pi: str(" ") {spec});
+ }
+ p!(pi: str("]"));
+ pi
+ }
+ Self::ExprImport(v) => {
+ p!(new: {v.import_kind()} str(" ") {v.text()})
+ }
+ Self::ExprVar(n) => p!(new: {n.name()}),
+ // Self::ExprLocal(l) => {
+ // }
+ Self::ExprIfThenElse(ite) => {
+ let mut pi =
+ p!(new: str("if ") {ite.cond()} str(" then ") {ite.then().map(|t| t.expr())});
+ if ite.else_kw_token().is_some() || ite.else_().is_some() {
+ p!(pi: str(" else ") {ite.else_().map(|t| t.expr())})
+ }
+ pi
+ }
+ Self::ExprFunction(f) => p!(new: str("function") {f.params_desc()} nl {f.expr()}),
+ // Self::ExprAssert(a) => p!(new: {a.assertion()} str("; ") {a.expr()}),
+ Self::ExprError(e) => p!(new: str("error ") {e.expr()}),
+ Self::ExprLiteral(l) => {
+ p!(new: {l.literal()})
+ }
+ }
+ }
+}
+
+impl Printable for SourceFile {
+ fn print(&self) -> PrintItems {
+ let mut pi = p!(new:);
+ let before = trivia_before(
+ self.syntax().clone(),
+ self.expr()
+ .map(|e| e.syntax().clone())
+ .map(Into::into)
+ .as_ref(),
+ );
+ let after = trivia_after(
+ self.syntax().clone(),
+ self.expr()
+ .map(|e| e.syntax().clone())
+ .map(Into::into)
+ .as_ref(),
+ );
+ p!(pi: items(format_comments(&before, CommentLocation::AboveItem)));
+ p!(pi: {self.expr()} nl);
+ p!(pi: items(format_comments(&after, CommentLocation::EndOfItems)));
+ pi
+ }
+}
+
+struct FormatOptions {
+ // 0 for hard tabs
+ indent: u8,
+}
+fn format(input: &str, opts: &FormatOptions) -> Option<String> {
+ let (parsed, errors) = jrsonnet_rowan_parser::parse(input);
+ if !errors.is_empty() {
+ let mut builder = ass_stroke::SnippetBuilder::new(input);
+ for error in errors {
+ builder
+ .error(ass_stroke::Text::single(
+ format!("{:?}", error.error).chars(),
+ Default::default(),
+ ))
+ .range(
+ error.range.start().into()
+ ..=(usize::from(error.range.end()) - 1).max(error.range.start().into()),
+ )
+ .build();
+ }
+ let snippet = builder.build();
+ let ansi = ass_stroke::source_to_ansi(&snippet);
+ eprintln!("{ansi}");
+ // It is possible to recover from this failure, but the output may be broken, as formatter is free to skip
+ // ERROR rowan nodes.
+ // Recovery needs to be enabled for LSP, though.
+ //
+ // TODO: Verify how formatter interacts in cases of missing positional values, i.e `if cond then /*missing Expr*/ else residual`.
+ return None;
+ }
+ Some(dprint_core::formatting::format(
+ || parsed.print(),
+ PrintOptions {
+ indent_width: if opts.indent == 0 {
+ // Reasonable max length for both 2 and 4 space sized tabs.
+ 3
+ } else {
+ opts.indent
+ },
+ max_width: 100,
+ use_tabs: opts.indent == 0,
+ new_line_text: "\n",
+ },
+ ))
+}
+
+#[derive(Parser)]
+struct Opts {
+ /// Treat input as code, reformat it instead of reading file.
+ #[clap(long, short = 'e')]
+ exec: bool,
+ /// Path to be reformatted if `--exec` if unset, otherwise code itself.
+ input: String,
+ /// Replace code with formatted in-place, instead of printing it to stdout.
+ /// Only applicable if `--exec` is unset.
+ #[clap(long, short = 'i')]
+ in_place: bool,
+
+ /// Exit with error if formatted does not match input
+ #[arg(long)]
+ test: bool,
+ /// Number of spaces to indent with
+ ///
+ /// 0 for guess from input (default), and use hard tabs if unable to guess.
+ #[arg(long, default_value = "0")]
+ indent: u8,
+ /// Force hard tab for indentation
+ #[arg(long)]
+ hard_tabs: bool,
+
+ /// Debug option: how many times to call reformatting in case of unstable dprint output resolution.
+ ///
+ /// 0 for not retrying to reformat.
+ #[arg(long, default_value = "0")]
+ conv_limit: usize,
+}
+
+#[derive(thiserror::Error, Debug)]
+enum Error {
+ #[error("--in-place is incompatible with --exec")]
+ InPlaceExec,
+ #[error("io: {0}")]
+ Io(#[from] io::Error),
+ #[error("persist: {0}")]
+ Persist(#[from] tempfile::PersistError),
+ #[error("parsing failed, refusing to reformat corrupted input")]
+ ParseError,
+}
+
+fn main_result() -> Result<(), Error> {
+ eprintln!("jrsonnet-fmt is a prototype of a jsonnet code formatter, do not expect it to produce meaningful results right now.");
+ eprintln!("It is not expected for its output to match other implementations, it will be completly separate implementation with maybe different name.");
+ let mut opts = Opts::parse();
+ let input = if opts.exec {
+ if opts.in_place {
+ return Err(Error::InPlaceExec);
+ }
+ opts.input.clone()
+ } else {
+ fs::read_to_string(&opts.input)?
+ };
+
+ if opts.indent == 0 {
+ // Sane default.
+ // TODO: Implement actual guessing.
+ opts.hard_tabs = true;
+ }
+
+ let mut iteration = 0;
+ let mut formatted = input.clone();
+ let mut tmp;
+ // https://github.com/dprint/dprint/pull/423
+ loop {
+ let Some(reformatted) = format(
+ &formatted,
+ &FormatOptions {
+ indent: if opts.indent == 0 || opts.hard_tabs {
+ 0
+ } else {
+ opts.indent
+ },
+ },
+ ) else {
+ return Err(Error::ParseError);
+ };
+ tmp = reformatted.trim().to_owned();
+ if formatted == tmp {
+ break;
+ }
+ formatted = tmp;
+ if opts.conv_limit == 0 {
+ break;
+ }
+ iteration += 1;
+ if iteration > opts.conv_limit {
+ panic!("formatting not converged");
+ }
+ }
+ formatted.push('\n');
+ if opts.test && formatted != input {
+ process::exit(1);
+ }
+ if opts.in_place {
+ let path = PathBuf::from(opts.input);
+ let mut temp = tempfile::NamedTempFile::new_in(path.parent().expect(
+ "not failed during read, this path is not a directory, and there is a parent",
+ ))?;
+ temp.write_all(formatted.as_bytes())?;
+ temp.flush()?;
+ temp.persist(&path)?;
+ } else {
+ print!("{formatted}")
+ }
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = main_result() {
+ eprintln!("{e}");
+ process::exit(1);
+ }
+}
cmds/jrsonnet-fmt/src/snapshots/jrsonnet_fmt__tests__complex_comments_snapshot.snapdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/src/snapshots/jrsonnet_fmt__tests__complex_comments_snapshot.snap
@@ -0,0 +1,53 @@
+---
+source: cmds/jrsonnet-fmt/src/tests.rs
+expression: "reformat(indoc!(\"{\n\t\t comments: {\n\t\t\t_: '',\n\t\t\t// Plain comment\n\t\t\ta: '',\n\n\t\t\t# Plain comment with empty line before\n\t\t\tb: '',\n\t\t\t/*Single-line multiline comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Single-line multiline doc comment\n\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/**Multiline doc\n\t\t\tComment\n\t\t\t*/\n\t\t\tc: '',\n\n\t\t\t/*\n\n\tMulti-line\n\n\tcomment\n\t\t\t*/\n\t\t\td: '',\n\n\t\t\te: '', // Inline comment\n\n\t\t\tk: '',\n\n\t\t\t// Text after everything\n\t\t },\n\t\t comments2: {\n\t\t\tk: '',\n\t\t\t// Text after everything, but no newline above\n\t\t },\n spacing: {\n a: '',\n\n b: '',\n },\n noSpacing: {\n a: '',\n b: '',\n },\n }\"))"
+---
+{
+ comments: {
+ _: '',
+ // Plain comment
+ a: '',
+
+ # Plain comment with empty line before
+ b: '',
+ /* Single-line multiline comment */
+ c: '',
+
+ /**
+ * Single-line multiline doc comment
+ */
+ c: '',
+
+ /**
+ * Multiline doc
+ * Comment
+ */
+ c: '',
+
+ /*
+ Multi-line
+
+ comment
+ */
+ d: '',
+
+ e: '', // Inline comment
+
+ k: '',
+
+ // Text after everything
+ },
+ comments2: {
+ k: '',
+ // Text after everything, but no newline above
+ },
+ spacing: {
+ a: '',
+
+ b: '',
+ },
+ noSpacing: {
+ a: '',
+ b: '',
+ },
+}
cmds/jrsonnet-fmt/src/tests.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-fmt/src/tests.rs
@@ -0,0 +1,124 @@
+use dprint_core::formatting::PrintOptions;
+use indoc::indoc;
+
+use crate::Printable;
+
+fn reformat(input: &str) -> String {
+ let (source, _) = jrsonnet_rowan_parser::parse(input);
+
+ dprint_core::formatting::format(
+ || source.print(),
+ PrintOptions {
+ indent_width: 2,
+ max_width: 100,
+ use_tabs: false,
+ new_line_text: "\n",
+ },
+ )
+}
+
+macro_rules! assert_formatted {
+ ($input:literal, $output:literal) => {
+ let formatted = reformat(indoc!($input));
+ let mut expected = indoc!($output).to_owned();
+ expected.push('\n');
+ if formatted != expected {
+ panic!(
+ "bad formatting, expected\n```\n{formatted}\n```\nto be equal to\n```\n{expected}\n```",
+ )
+ }
+ };
+}
+
+#[test]
+fn padding_stripped_for_multiline_comment() {
+ assert_formatted!(
+ "{
+ /*
+ Hello
+ World
+ */
+ _: null,
+ }",
+ "{
+ /*
+ Hello
+ World
+ */
+ _: null,
+ }"
+ );
+}
+
+#[test]
+fn last_comment_respects_spacing_with_inline_comment_above() {
+ assert_formatted!(
+ "{
+ a: '', // Inline
+
+ // Comment
+ }",
+ "{
+ a: '', // Inline
+
+ // Comment
+ }"
+ );
+}
+
+#[test]
+fn complex_comments_snapshot() {
+ insta::assert_display_snapshot!(reformat(indoc!(
+ "{
+ comments: {
+ _: '',
+ // Plain comment
+ a: '',
+
+ # Plain comment with empty line before
+ b: '',
+ /*Single-line multiline comment
+
+ */
+ c: '',
+
+ /**Single-line multiline doc comment
+
+ */
+ c: '',
+
+ /**Multiline doc
+ Comment
+ */
+ c: '',
+
+ /*
+
+ Multi-line
+
+ comment
+ */
+ d: '',
+
+ e: '', // Inline comment
+
+ k: '',
+
+ // Text after everything
+ },
+ comments2: {
+ k: '',
+ // Text after everything, but no newline above
+ },
+ spacing: {
+ a: '',
+
+ b: '',
+ },
+ noSpacing: {
+ a: '',
+ b: '',
+ },
+ }"
+ )))
+}
cmds/jrsonnet-lsp/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-lsp/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "jrsonnet-lsp"
+version.workspace = true
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.48"
+jrsonnet-evaluator.workspace = true
+jrsonnet-rowan-parser.workspace = true
+lsp-server = "0.6.0"
+lsp-types = "0.93.0"
+serde = "1.0.130"
+serde_json = "1.0.71"
cmds/jrsonnet-lsp/src/main.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/jrsonnet-lsp/src/main.rs
@@ -0,0 +1,188 @@
+use std::{fs::File, io::Write, path::PathBuf, str::FromStr};
+
+use lsp_server::{Connection, ErrorCode, Message, Request, RequestId, Response};
+use lsp_types::{
+ notification::{DidChangeTextDocument, DidOpenTextDocument, Notification},
+ request::{DocumentLinkRequest, HoverRequest},
+ CompletionOptions, DidChangeTextDocumentParams, DidOpenTextDocumentParams, DocumentLink,
+ DocumentLinkOptions, ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
+ TextDocumentSyncOptions, Url, WorkDoneProgressOptions,
+};
+
+fn main() {
+ let mut log = File::create("test").unwrap();
+ writeln!(log, "start").unwrap();
+ let (connection, io_threads) = Connection::stdio();
+ let capabilities = serde_json::to_value(&ServerCapabilities {
+ completion_provider: Some(CompletionOptions::default()),
+ definition_provider: Some(lsp_types::OneOf::Left(true)),
+ document_link_provider: Some(DocumentLinkOptions {
+ resolve_provider: Some(false),
+ work_done_progress_options: WorkDoneProgressOptions::default(),
+ }),
+ hover_provider: Some(lsp_types::HoverProviderCapability::Simple(true)),
+ text_document_sync: Some(TextDocumentSyncCapability::Options(
+ TextDocumentSyncOptions {
+ change: Some(TextDocumentSyncKind::FULL),
+ open_close: Some(true),
+ ..TextDocumentSyncOptions::default()
+ },
+ )),
+ ..ServerCapabilities::default()
+ })
+ .expect("failed to convert capabilities to json");
+
+ connection
+ .initialize(capabilities)
+ .expect("failed to initialize connection");
+
+ writeln!(log, "initialized").unwrap();
+
+ main_loop(&mut log, &connection).expect("main loop failed");
+
+ io_threads.join().expect("failed to join io_threads");
+}
+fn main_loop(log: &mut File, connection: &Connection) -> anyhow::Result<()> {
+ // let mut es = EvaluationState::default();
+ // es.set_import_resolver(Box::new(FileImportResolver::default()));
+
+ let reply = |response: Response| {
+ connection
+ .sender
+ .send(Message::Response(response))
+ .expect("failed to respond");
+ };
+
+ for msg in &connection.receiver {
+ match msg {
+ Message::Response(_) => (),
+ Message::Request(req) => {
+ if connection.handle_shutdown(&req)? {
+ return Ok(());
+ }
+ if let Some((id, params)) = cast::<DocumentLinkRequest>(&req) {
+ reply(Response::new_ok(id, <Vec<DocumentLink>>::new()));
+ } else if let Some((id, params)) = cast::<HoverRequest>(&req) {
+ let pos = params
+ .text_document_position_params
+ .text_document
+ .uri
+ .path();
+ let buf = PathBuf::from_str(pos).unwrap();
+ // let pos = es
+ // .map_from_source_location(
+ // &buf,
+ // params.text_document_position_params.position.line as usize + 1,
+ // params.text_document_position_params.position.character as usize + 1,
+ // )
+ // .unwrap();
+ // let el = ExprLocation(buf.clone().into(), pos as usize, pos as usize);
+ // let es2 = es.clone();
+ // reply(Response::new_ok(
+ // id,
+ // Some(Hover {
+ // range: None,
+ // contents: HoverContents::Markup(MarkupContent {
+ // kind: MarkupKind::Markdown,
+ // value: es
+ // .run_in_state_with_breakpoint(el, move || {
+ // es2.reset_evaluation_state(&buf);
+ // es2.import_file(&PathBuf::new(), &buf)?
+ // .to_string()
+ // .map(|_| ())
+ // })
+ // .unwrap()
+ // .unwrap_or_else(|| Val::Null)
+ // .value_type()
+ // .to_string(),
+ // }),
+ // }),
+ // ));
+ } else {
+ reply(Response::new_err(
+ req.id,
+ ErrorCode::MethodNotFound as i32,
+ format!("unrecognized request {}", req.method),
+ ))
+ }
+ /*
+ if let Some((id, params)) = cast::<DocumentLinkRequest>(&req) {
+ let links = handle_links(&files, params).unwrap_or_default();
+ reply(Response::new_ok(id, links));
+ } else if let Some((id, params)) = cast::<GotoDefinition>(&req) {
+ if let Some(loc) = handle_goto(&files, params) {
+ reply(Response::new_ok(id, loc))
+ } else {
+ reply(Response::new_ok(id, ()))
+ }
+ } else if let Some((id, params)) = cast::<HoverRequest>(&req) {
+ match handle_hover(&files, params) {
+ Some((range, markdown)) => {
+ reply(Response::new_ok(
+ id,
+ Hover {
+ contents: HoverContents::Markup(MarkupContent {
+ kind: MarkupKind::Markdown,
+ value: markdown,
+ }),
+ range,
+ },
+ ));
+ }
+ None => {
+ reply(Response::new_ok(id, ()));
+ }
+ }
+ } else if let Some((id, params)) = cast::<Completion>(&req) {
+ let completions = handle_completion(&files, params.text_document_position)
+ .unwrap_or_default();
+ reply(Response::new_ok(id, completions));
+ } else
+ */
+ }
+ Message::Notification(req) => {
+ let mut handle = |text: String, uri: Url| {
+ writeln!(log, "updated file: {:?}", uri).unwrap();
+ let path = match PathBuf::from_str(uri.path()) {
+ Ok(x) => x,
+ Err(_) => return,
+ };
+ let (ast, errors) = jrsonnet_rowan_parser::parse(&text);
+ // es.add_parsed_file(path.into(), text.into(), parsed)
+ // .unwrap();
+ writeln!(log, "parsed: {:?}", uri).unwrap();
+ };
+
+ match &*req.method {
+ DidOpenTextDocument::METHOD => {
+ let params: DidOpenTextDocumentParams =
+ match serde_json::from_value(req.params) {
+ Ok(x) => x,
+ Err(_) => continue,
+ };
+ handle(params.text_document.text, params.text_document.uri);
+ }
+ DidChangeTextDocument::METHOD => {
+ let params: DidChangeTextDocumentParams =
+ match serde_json::from_value(req.params) {
+ Ok(x) => x,
+ Err(_) => continue,
+ };
+ for change in params.content_changes.into_iter() {
+ handle(change.text, params.text_document.uri.clone());
+ }
+ }
+ _ => continue,
+ }
+ }
+ }
+ }
+ Ok(())
+}
+fn cast<R>(req: &Request) -> Option<(RequestId, R::Params)>
+where
+ R: lsp_types::request::Request,
+ R::Params: serde::de::DeserializeOwned,
+{
+ req.clone().extract(R::METHOD).ok()
+}
cmds/jrsonnet/Cargo.tomldiffbeforeafterboth--- a/cmds/jrsonnet/Cargo.toml
+++ b/cmds/jrsonnet/Cargo.toml
@@ -12,10 +12,7 @@
# Use mimalloc as allocator
mimalloc = ["mimallocator"]
# Experimental feature, which allows to preserve order of object fields
-exp-preserve-order = [
- "jrsonnet-evaluator/exp-preserve-order",
- "jrsonnet-cli/exp-preserve-order",
-]
+exp-preserve-order = ["jrsonnet-evaluator/exp-preserve-order", "jrsonnet-cli/exp-preserve-order"]
# Destructuring of locals
exp-destruct = ["jrsonnet-evaluator/exp-destruct"]
# Iteration over objects yields [key, value] elements
@@ -44,3 +41,4 @@
clap_complete = { version = "4.1" }
serde_json = "1.0.104"
serde = { workspace = true, features = ["derive"] }
+ass-stroke = { git = "https://github.com/CertainLach/ass-stroke", version = "0.1.0" }
cmds/jrsonnet/src/main.rsdiffbeforeafterboth--- a/cmds/jrsonnet/src/main.rs
+++ b/cmds/jrsonnet/src/main.rs
@@ -37,15 +37,15 @@
#[derive(Parser)]
#[clap(next_help_heading = "INPUT")]
struct InputOpts {
- /// Treat input as code, evaluate them instead of reading file
+ /// Treat input as code, evaluate it instead of reading file.
#[clap(long, short = 'e')]
pub exec: bool,
- /// Path to the file to be compiled if `--evaluate` is unset, otherwise code itself
+ /// Path to the file to be compiled if `--exec` is unset, otherwise code itself.
pub input: Option<String>,
/// After executing input, apply specified code.
- /// Output of the initial input will be accessible using `$`
+ /// Output of the initial input will be accessible using `_`.
#[cfg(feature = "exp-apply")]
#[clap(long)]
pub exp_apply: Vec<String>,
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -41,6 +41,10 @@
clippy::missing_const_for_fn,
// too many false-positives with .expect() calls
clippy::missing_panics_doc,
+ // false positive for IStr type. There is an configuration option for
+ // such cases, but it doesn't work:
+ // https://github.com/rust-lang/rust-clippy/issues/9801
+ clippy::mutable_key_type,
)]
// For jrsonnet-macros
crates/jrsonnet-rowan-parser/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "jrsonnet-rowan-parser"
+version.workspace = true
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0"
+backtrace = "0.3.63"
+drop_bomb = "0.1.5"
+indoc = "1.0"
+logos = "0.12"
+miette = { version = "5.5.0", features = ["fancy"] }
+rowan = "0.15"
+text-size = "1.1"
+thiserror = "1.0"
+
+[dev-dependencies]
+backtrace = "0.3.63"
+indoc = "1.0"
+insta = "1.15"
+anyhow = "1.0"
crates/jrsonnet-rowan-parser/jsonnet.ungramdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/jsonnet.ungram
@@ -0,0 +1,355 @@
+// This file describes structure of jsonnet source code
+// It is also used to generate files in src/generated
+
+// Token names ending with `!` are considered meta, and handled specifically
+
+SourceFile = Expr
+
+SuffixIndex =
+ '?'?
+ '.'
+ index:Name
+SuffixIndexExpr =
+ ('?' '.')?
+ '['
+ index:Expr
+ ']'
+SuffixSlice =
+ SliceDesc
+SuffixApply =
+ ArgsDesc
+ 'tailstrict'?
+Suffix =
+ SuffixIndex
+| SuffixIndexExpr
+| SuffixSlice
+| SuffixApply
+
+StmtLocal =
+ 'local'
+ (Bind (',' Bind)* ','?)
+ ';'
+StmtAssert =
+ Assertion
+ ';'
+Stmt =
+ StmtLocal
+| StmtAssert
+
+ExprBinary =
+ lhs:Expr
+ BinaryOperator
+ rhs:Expr
+ExprUnary =
+ UnaryOperator
+ rhs:Expr
+ExprObjExtend =
+ Expr
+ Expr
+ExprParened =
+ '('
+ Expr
+ ')'
+
+ExprLiteral =
+ Literal
+ExprString =
+ Text
+ExprNumber =
+ Number
+ExprArray =
+ '['
+ (Expr (',' Expr)* ','?)?
+ ']'
+ExprObject =
+ ObjBody
+ExprArrayComp =
+ '['
+ Expr
+ ','?
+ CompSpec*
+ ']'
+
+ExprImport =
+ ImportKind Text
+
+ImportKind =
+ 'importstr'
+| 'importbin'
+| 'import'
+
+ExprVar =
+ name:Name
+
+ExprIfThenElse =
+ 'if'
+ cond:Expr
+ 'then'
+ then:TrueExpr
+ ('else' else_:FalseExpr)?
+
+ExprFunction =
+ 'function'
+ '('
+ ParamsDesc
+ ')'
+ Expr
+ExprError =
+ 'error'
+ Expr
+
+Expr =
+ Stmt*
+ ExprBase
+ Suffix*
+
+ExprBase =
+ ExprBinary
+| ExprUnary
+| ExprObjExtend
+| ExprParened
+| ExprString
+| ExprNumber
+| ExprLiteral
+| ExprArray
+| ExprObject
+| ExprArrayComp
+| ExprImport
+| ExprVar
+| ExprIfThenElse
+| ExprFunction
+| ExprError
+
+BinaryOperator =
+ '||' | '??' | '&&'
+| '|' | '^' | '&'
+| '==' | '!=' | '<' | '>' | '<=' | '>=' | 'in'
+| '<<' | '>>'
+| '+' | '-'
+| '*' | '/' | '%'
+| 'META_OBJECT_APPLY!'
+| 'ERROR_NO_OPERATOR!'
+
+UnaryOperator =
+ '-' | '!' | '~'
+
+SliceDescEnd=Expr
+SliceDescStep=Expr
+SliceDesc =
+ '['
+ from:Expr?
+ ':'
+ (
+ end:SliceDescEnd?
+ (
+ ':'
+ step:SliceDescStep?
+ )?
+ )?
+ ']'
+
+Name =
+ 'LIT_IDENT!'
+
+ArgsDesc =
+ '('
+ (Arg (',' Arg)* ','?)?
+ ')'
+Arg =
+ (name:Name '=')? Expr
+
+ObjBodyComp =
+ '{'
+ (MemberComp (',' MemberComp)* ','?)?
+ CompSpec*
+ '}'
+ObjBodyMemberList =
+ '{'
+ (Member (',' Member)* ','?)?
+ '}'
+ObjBody =
+ ObjBodyComp
+| ObjBodyMemberList
+
+MemberBindStmt = ObjLocal
+MemberAssertStmt = Assertion
+MemberFieldNormal =
+ FieldName
+ '+'?
+ Visibility
+ Expr
+MemberFieldMethod =
+ FieldName
+ ParamsDesc
+ Visibility
+ Expr
+MemberComp =
+ MemberBindStmt
+| MemberFieldNormal
+| MemberFieldMethod
+Member =
+ MemberBindStmt
+| MemberAssertStmt
+| MemberFieldNormal
+| MemberFieldMethod
+
+ObjLocal =
+ 'local'
+ Bind
+
+FieldNameFixed =
+ id:Name
+| Text
+FieldNameDynamic =
+ '['
+ Expr
+ ']'
+FieldName =
+ FieldNameFixed
+| FieldNameDynamic
+
+Visibility =
+ ':::'
+| '::'
+| ':'
+
+Literal =
+ 'null'
+| 'true'
+| 'false'
+| 'self'
+| '$'
+| 'super'
+
+Text =
+ 'LIT_STRING_DOUBLE!'
+| 'ERROR_STRING_DOUBLE_UNTERMINATED!'
+| 'LIT_STRING_SINGLE!'
+| 'ERROR_STRING_SINGLE_UNTERMINATED!'
+| 'LIT_STRING_DOUBLE_VERBATIM!'
+| 'ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED!'
+| 'LIT_STRING_SINGLE_VERBATIM!'
+| 'ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED!'
+| 'ERROR_STRING_VERBATIM_MISSING_QUOTES!'
+| 'LIT_STRING_BLOCK!'
+| 'ERROR_STRING_BLOCK_UNEXPECTED_END!'
+| 'ERROR_STRING_BLOCK_MISSING_NEW_LINE!'
+| 'ERROR_STRING_BLOCK_MISSING_TERMINATION!'
+| 'ERROR_STRING_BLOCK_MISSING_INDENT!'
+
+Number =
+ 'LIT_FLOAT!'
+| 'ERROR_FLOAT_JUNK_AFTER_POINT!'
+| 'ERROR_FLOAT_JUNK_AFTER_EXPONENT!'
+| 'ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN!'
+
+ForSpec =
+ 'for'
+ bind:Destruct
+ 'in'
+ Expr
+IfSpec =
+ 'if'
+ Expr
+CompSpec =
+ ForSpec
+| IfSpec
+
+BindDestruct =
+ into:Destruct
+ '='
+ value:Expr
+BindFunction =
+ name:Name
+ params:ParamsDesc
+ '='
+ value:Expr
+Bind =
+ BindDestruct
+| BindFunction
+
+ParamsDesc =
+ '('
+ (Param (',' Param)* ','?)?
+ ')'
+Param =
+ Destruct
+ (
+ '='
+ Expr
+ )?
+
+Assertion =
+ 'assert'
+ condition:Expr
+ (
+ ':'
+ message:Expr
+ )?
+
+DestructFull =
+ Name
+DestructSkip =
+ '?'
+DestructArray =
+ '['
+ (
+ DestructArrayPart
+ (',' DestructArrayPart)*
+ ','?
+ )?
+ ']'
+DestructObject =
+ '{'
+ (
+ DestructObjectField
+ (',' DestructObjectField)*
+ ','?
+ )?
+ DestructRest?
+ ','?
+ '}'
+Destruct =
+ DestructFull
+| DestructSkip
+| DestructArray
+| DestructObject
+
+DestructArrayElement =
+ Destruct
+DestructArrayPart =
+ DestructArrayElement
+| DestructRest
+
+DestructRest =
+ '...'
+ into:Name?
+
+DestructObjectField =
+ field:Name
+ (
+ ':'
+ Destruct
+ )?
+ (
+ '='
+ Expr
+ )?
+
+// Aliases used to resolve node type conflicts
+TrueExpr=Expr
+FalseExpr=Expr
+
+// Trivia - tokens which will be implicitly skipped for parser
+Trivia =
+ 'LIT_WHITESPACE!'
+| 'LIT_MULTI_LINE_COMMENT!'
+| 'ERROR_COMMENT_TOO_SHORT!'
+| 'ERROR_COMMENT_UNTERMINATED!'
+| 'LIT_SINGLE_LINE_HASH_COMMENT!'
+| 'LIT_SINGLE_LINE_SLASH_COMMENT!'
+
+CustomError =
+ 'ERROR_MISSING_TOKEN!'
+| 'ERROR_UNEXPECTED_TOKEN!'
+| 'ERROR_CUSTOM!'
crates/jrsonnet-rowan-parser/src/ast.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/ast.rs
@@ -0,0 +1,95 @@
+use std::marker::PhantomData;
+
+use crate::{SyntaxKind, SyntaxNode, SyntaxNodeChildren, SyntaxToken};
+
+/// The main trait to go from untyped `SyntaxNode` to a typed ast. The
+/// conversion itself has zero runtime cost: ast and syntax nodes have exactly
+/// the same representation: a pointer to the tree root and a pointer to the
+/// node itself.
+pub trait AstNode {
+ fn can_cast(kind: SyntaxKind) -> bool
+ where
+ Self: Sized;
+
+ fn cast(syntax: SyntaxNode) -> Option<Self>
+ where
+ Self: Sized;
+
+ fn syntax(&self) -> &SyntaxNode;
+ fn clone_for_update(&self) -> Self
+ where
+ Self: Sized,
+ {
+ Self::cast(self.syntax().clone_for_update()).unwrap()
+ }
+ fn clone_subtree(&self) -> Self
+ where
+ Self: Sized,
+ {
+ Self::cast(self.syntax().clone_subtree()).unwrap()
+ }
+}
+
+/// Like `AstNode`, but wraps tokens rather than interior nodes.
+pub trait AstToken {
+ fn can_cast(token: SyntaxKind) -> bool
+ where
+ Self: Sized;
+
+ fn cast(syntax: SyntaxToken) -> Option<Self>
+ where
+ Self: Sized;
+
+ fn syntax(&self) -> &SyntaxToken;
+
+ fn text(&self) -> &str {
+ self.syntax().text()
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct AstChildren<N> {
+ inner: SyntaxNodeChildren,
+ ph: PhantomData<N>,
+}
+
+impl<N> AstChildren<N> {
+ fn new(parent: &SyntaxNode) -> Self {
+ AstChildren {
+ inner: parent.children(),
+ ph: PhantomData,
+ }
+ }
+}
+
+impl<N: AstNode> Iterator for AstChildren<N> {
+ type Item = N;
+ fn next(&mut self) -> Option<N> {
+ self.inner.find_map(N::cast)
+ }
+}
+
+pub mod support {
+ use super::{AstChildren, AstNode, AstToken, SyntaxKind, SyntaxNode, SyntaxToken};
+
+ pub fn child<N: AstNode>(parent: &SyntaxNode) -> Option<N> {
+ parent.children().find_map(N::cast)
+ }
+ pub fn token_child<N: AstToken>(parent: &SyntaxNode) -> Option<N> {
+ parent.children_with_tokens().find_map(|n| match n {
+ rowan::NodeOrToken::Node(_) => None,
+ rowan::NodeOrToken::Token(t) => N::cast(t),
+ })
+ }
+
+ pub fn children<N: AstNode>(parent: &SyntaxNode) -> AstChildren<N> {
+ AstChildren::new(parent)
+ }
+
+ pub fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken> {
+ parent
+ .children_with_tokens()
+ .filter_map(|it| it.into_token())
+ .find(|it| it.kind() == kind)
+ }
+}
crates/jrsonnet-rowan-parser/src/event.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/event.rs
@@ -0,0 +1,204 @@
+use std::{mem, num::NonZeroUsize};
+
+use rowan::{GreenNodeBuilder, Language, TextRange, TextSize};
+
+use crate::{
+ lex::Lexeme,
+ nodes::Trivia,
+ parser::{LocatedSyntaxError, Parse, SyntaxError},
+ AstToken, JsonnetLanguage, SyntaxKind,
+};
+
+#[derive(Clone, Debug)]
+pub enum Event {
+ /// Used for unfinished markers
+ Pending,
+ /// After marker is completed, Pending event is replaced with Start
+ Start {
+ kind: SyntaxKind,
+ /// If marker is preceded or wrapped - instead of reordering events, we
+ /// insert start event in the end of events Vec instead, and store relative offset to this event here
+ forward_parent: Option<NonZeroUsize>,
+ },
+ /// Eat token
+ Token { kind: SyntaxKind },
+ /// Push token, but do not eat anything,
+ VirtualToken { kind: SyntaxKind },
+ /// Position of finished node
+ Finish {
+ /// Same as forward_parent of Start, but for wrapping
+ wrapper: Option<NonZeroUsize>,
+ error: Option<Box<SyntaxError>>,
+ },
+ /// Used for dropped markers and other things
+ Noop,
+}
+
+pub(super) struct Sink<'i> {
+ pub builder: GreenNodeBuilder<'static>,
+ lexemes: &'i [Lexeme<'i>],
+ offset: usize,
+ events: Vec<Event>,
+ pub errors: Vec<LocatedSyntaxError>,
+}
+
+impl<'i> Sink<'i> {
+ pub(super) fn new(events: Vec<Event>, lexemes: &'i [Lexeme<'i>]) -> Self {
+ Self {
+ builder: GreenNodeBuilder::new(),
+ lexemes,
+ offset: 0,
+ events,
+ errors: vec![],
+ }
+ }
+
+ fn text_offset(&self) -> TextSize {
+ if self.offset == 0 {
+ return 0.into();
+ };
+ if let Some(lex) = self.lexemes.get(self.offset) {
+ lex.range.start()
+ } else if let Some(lex) = self.lexemes.get(self.offset - 1) {
+ lex.range.end()
+ } else {
+ panic!("hard oob")
+ }
+ }
+
+ pub(super) fn finish(mut self) -> Parse {
+ let mut eat_start_whitespace = false;
+ let mut depth = 0;
+ let mut error_starts_at = Vec::new();
+ for idx in 0..self.events.len() {
+ match mem::replace(&mut self.events[idx], Event::Noop) {
+ Event::Start {
+ kind,
+ forward_parent,
+ } => {
+ if depth != 0 {
+ self.skip_whitespace();
+ }
+ let mut kinds = vec![kind];
+
+ let mut idx = idx;
+ let mut forward_parent = forward_parent;
+
+ // Walk through the forward parent of the forward parent, and the forward parent
+ // of that, and of that, etc. until we reach a StartNode event without a forward
+ // parent.
+ while let Some(fp) = forward_parent {
+ idx += fp.get();
+
+ forward_parent = if let Event::Start {
+ kind,
+ forward_parent,
+ } = mem::replace(&mut self.events[idx], Event::Noop)
+ {
+ kinds.push(kind);
+ forward_parent
+ } else {
+ unreachable!()
+ };
+ }
+
+ for kind in kinds.into_iter().rev() {
+ self.builder.start_node(JsonnetLanguage::kind_to_raw(kind));
+ depth += 1;
+ if depth == 1 {
+ self.skip_whitespace();
+ }
+ error_starts_at.push(self.text_offset());
+ }
+
+ eat_start_whitespace = false;
+ }
+ Event::Token { kind } => {
+ if eat_start_whitespace {
+ self.skip_whitespace();
+ }
+ self.token(kind);
+ eat_start_whitespace = true;
+ }
+ Event::VirtualToken { kind } => {
+ if eat_start_whitespace {
+ self.skip_whitespace();
+ }
+ self.virtual_token(kind);
+ eat_start_whitespace = false;
+ }
+ Event::Finish { wrapper, error } => {
+ if depth == 1 {
+ self.skip_whitespace();
+ }
+ let range = (
+ error_starts_at.pop().expect("starts == finishes"),
+ self.text_offset(),
+ );
+ if let Some(error) = error {
+ self.errors.push(LocatedSyntaxError {
+ error: *error,
+ range: TextRange::new(range.0, range.1),
+ })
+ }
+ self.builder.finish_node();
+ depth -= 1;
+ let mut idx = idx;
+ let mut wrapper = wrapper;
+ while let Some(w) = wrapper {
+ idx += w.get();
+ wrapper = if let Event::Finish { wrapper, error } =
+ mem::replace(&mut self.events[idx], Event::Noop)
+ {
+ let range = (
+ error_starts_at.pop().expect("starts == finishes"),
+ self.text_offset(),
+ );
+ if let Some(error) = error {
+ self.errors.push(LocatedSyntaxError {
+ error: *error,
+ range: TextRange::new(range.0, range.1),
+ })
+ }
+
+ if depth == 1 {
+ self.skip_whitespace();
+ }
+ self.builder.finish_node();
+ depth -= 1;
+ wrapper
+ } else {
+ unreachable!()
+ }
+ }
+ eat_start_whitespace = true;
+ }
+ Event::Pending => panic!("pending event should not appear in finished events"),
+ Event::Noop => {}
+ }
+ }
+
+ Parse {
+ green_node: self.builder.finish(),
+ errors: self.errors,
+ }
+ }
+ fn virtual_token(&mut self, kind: SyntaxKind) {
+ self.builder.token(JsonnetLanguage::kind_to_raw(kind), "")
+ }
+ fn token(&mut self, kind: SyntaxKind) {
+ let lexeme = self.lexemes[self.offset];
+ self.builder
+ .token(JsonnetLanguage::kind_to_raw(kind), lexeme.text);
+ self.offset += 1;
+ }
+ fn skip_whitespace(&mut self) {
+ while let Some(lexeme) = self.lexemes.get(self.offset) {
+ if !Trivia::can_cast(lexeme.kind) {
+ break;
+ }
+
+ self.token(lexeme.kind);
+ }
+ }
+}
crates/jrsonnet-rowan-parser/src/generated/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/mod.rs
@@ -0,0 +1,2 @@
+pub mod nodes;
+pub mod syntax_kinds;
crates/jrsonnet-rowan-parser/src/generated/nodes.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/nodes.rs
@@ -0,0 +1,3092 @@
+//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.
+
+#![allow(non_snake_case, clippy::match_like_matches_macro)]
+use crate::{
+ ast::{support, AstChildren, AstNode, AstToken},
+ SyntaxKind::{self, *},
+ SyntaxNode, SyntaxToken, T,
+};
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SourceFile {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SourceFile {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Expr {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Expr {
+ pub fn stmts(&self) -> AstChildren<Stmt> {
+ support::children(&self.syntax)
+ }
+ pub fn expr_base(&self) -> Option<ExprBase> {
+ support::child(&self.syntax)
+ }
+ pub fn suffixs(&self) -> AstChildren<Suffix> {
+ support::children(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SuffixIndex {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SuffixIndex {
+ pub fn question_mark_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![?])
+ }
+ pub fn dot_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![.])
+ }
+ pub fn index(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Name {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Name {
+ pub fn ident_lit(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, IDENT)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SuffixIndexExpr {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SuffixIndexExpr {
+ pub fn question_mark_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![?])
+ }
+ pub fn dot_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![.])
+ }
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn index(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SuffixSlice {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SuffixSlice {
+ pub fn slice_desc(&self) -> Option<SliceDesc> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SliceDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SliceDesc {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn from(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn colon_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![:])
+ }
+ pub fn end(&self) -> Option<SliceDescEnd> {
+ support::child(&self.syntax)
+ }
+ pub fn step(&self) -> Option<SliceDescStep> {
+ support::child(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SuffixApply {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SuffixApply {
+ pub fn args_desc(&self) -> Option<ArgsDesc> {
+ support::child(&self.syntax)
+ }
+ pub fn tailstrict_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![tailstrict])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ArgsDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ArgsDesc {
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['('])
+ }
+ pub fn args(&self) -> AstChildren<Arg> {
+ support::children(&self.syntax)
+ }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![')'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct StmtLocal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl StmtLocal {
+ pub fn local_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![local])
+ }
+ pub fn binds(&self) -> AstChildren<Bind> {
+ support::children(&self.syntax)
+ }
+ pub fn semi_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![;])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct StmtAssert {
+ pub(crate) syntax: SyntaxNode,
+}
+impl StmtAssert {
+ pub fn assertion(&self) -> Option<Assertion> {
+ support::child(&self.syntax)
+ }
+ pub fn semi_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![;])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Assertion {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Assertion {
+ pub fn assert_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![assert])
+ }
+ pub fn condition(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn colon_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![:])
+ }
+ pub fn message(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprBinary {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprBinary {
+ pub fn lhs(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn binary_operator(&self) -> Option<BinaryOperator> {
+ support::token_child(&self.syntax)
+ }
+ pub fn rhs(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprUnary {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprUnary {
+ pub fn unary_operator(&self) -> Option<UnaryOperator> {
+ support::token_child(&self.syntax)
+ }
+ pub fn rhs(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprObjExtend {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprObjExtend {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprParened {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprParened {
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['('])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![')'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprLiteral {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprLiteral {
+ pub fn literal(&self) -> Option<Literal> {
+ support::token_child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprString {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprString {
+ pub fn text(&self) -> Option<Text> {
+ support::token_child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprNumber {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprNumber {
+ pub fn number(&self) -> Option<Number> {
+ support::token_child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprArray {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprArray {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn exprs(&self) -> AstChildren<Expr> {
+ support::children(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprObject {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprObject {
+ pub fn obj_body(&self) -> Option<ObjBody> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprArrayComp {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprArrayComp {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn comma_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![,])
+ }
+ pub fn comp_specs(&self) -> AstChildren<CompSpec> {
+ support::children(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprImport {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprImport {
+ pub fn import_kind(&self) -> Option<ImportKind> {
+ support::token_child(&self.syntax)
+ }
+ pub fn text(&self) -> Option<Text> {
+ support::token_child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprVar {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprVar {
+ pub fn name(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprIfThenElse {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprIfThenElse {
+ pub fn if_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![if])
+ }
+ pub fn cond(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn then_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![then])
+ }
+ pub fn then(&self) -> Option<TrueExpr> {
+ support::child(&self.syntax)
+ }
+ pub fn else_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![else])
+ }
+ pub fn else_(&self) -> Option<FalseExpr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct TrueExpr {
+ pub(crate) syntax: SyntaxNode,
+}
+impl TrueExpr {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FalseExpr {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FalseExpr {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprFunction {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprFunction {
+ pub fn function_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![function])
+ }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['('])
+ }
+ pub fn params_desc(&self) -> Option<ParamsDesc> {
+ support::child(&self.syntax)
+ }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![')'])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ParamsDesc {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ParamsDesc {
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['('])
+ }
+ pub fn params(&self) -> AstChildren<Param> {
+ support::children(&self.syntax)
+ }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![')'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ExprError {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ExprError {
+ pub fn error_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![error])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SliceDescEnd {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SliceDescEnd {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct SliceDescStep {
+ pub(crate) syntax: SyntaxNode,
+}
+impl SliceDescStep {
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Arg {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Arg {
+ pub fn name(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+ pub fn assign_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![=])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjBodyComp {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjBodyComp {
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['{'])
+ }
+ pub fn member_comps(&self) -> AstChildren<MemberComp> {
+ support::children(&self.syntax)
+ }
+ pub fn comp_specs(&self) -> AstChildren<CompSpec> {
+ support::children(&self.syntax)
+ }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['}'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjBodyMemberList {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjBodyMemberList {
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['{'])
+ }
+ pub fn members(&self) -> AstChildren<Member> {
+ support::children(&self.syntax)
+ }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['}'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberBindStmt {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberBindStmt {
+ pub fn obj_local(&self) -> Option<ObjLocal> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ObjLocal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ObjLocal {
+ pub fn local_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![local])
+ }
+ pub fn bind(&self) -> Option<Bind> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberAssertStmt {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberAssertStmt {
+ pub fn assertion(&self) -> Option<Assertion> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberFieldNormal {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberFieldNormal {
+ pub fn field_name(&self) -> Option<FieldName> {
+ support::child(&self.syntax)
+ }
+ pub fn plus_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![+])
+ }
+ pub fn visibility(&self) -> Option<Visibility> {
+ support::token_child(&self.syntax)
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct MemberFieldMethod {
+ pub(crate) syntax: SyntaxNode,
+}
+impl MemberFieldMethod {
+ pub fn field_name(&self) -> Option<FieldName> {
+ support::child(&self.syntax)
+ }
+ pub fn params_desc(&self) -> Option<ParamsDesc> {
+ support::child(&self.syntax)
+ }
+ pub fn visibility(&self) -> Option<Visibility> {
+ support::token_child(&self.syntax)
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldNameFixed {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldNameFixed {
+ pub fn id(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+ pub fn text(&self) -> Option<Text> {
+ support::token_child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct FieldNameDynamic {
+ pub(crate) syntax: SyntaxNode,
+}
+impl FieldNameDynamic {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ForSpec {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ForSpec {
+ pub fn for_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![for])
+ }
+ pub fn bind(&self) -> Option<Destruct> {
+ support::child(&self.syntax)
+ }
+ pub fn in_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![in])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct IfSpec {
+ pub(crate) syntax: SyntaxNode,
+}
+impl IfSpec {
+ pub fn if_kw_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![if])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BindDestruct {
+ pub(crate) syntax: SyntaxNode,
+}
+impl BindDestruct {
+ pub fn into(&self) -> Option<Destruct> {
+ support::child(&self.syntax)
+ }
+ pub fn assign_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![=])
+ }
+ pub fn value(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BindFunction {
+ pub(crate) syntax: SyntaxNode,
+}
+impl BindFunction {
+ pub fn name(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+ pub fn params(&self) -> Option<ParamsDesc> {
+ support::child(&self.syntax)
+ }
+ pub fn assign_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![=])
+ }
+ pub fn value(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Param {
+ pub(crate) syntax: SyntaxNode,
+}
+impl Param {
+ pub fn destruct(&self) -> Option<Destruct> {
+ support::child(&self.syntax)
+ }
+ pub fn assign_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![=])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructFull {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructFull {
+ pub fn name(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructSkip {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructSkip {
+ pub fn question_mark_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![?])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructArray {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructArray {
+ pub fn l_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['['])
+ }
+ pub fn destruct_array_parts(&self) -> AstChildren<DestructArrayPart> {
+ support::children(&self.syntax)
+ }
+ pub fn r_brack_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![']'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructObject {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructObject {
+ pub fn l_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['{'])
+ }
+ pub fn destruct_object_fields(&self) -> AstChildren<DestructObjectField> {
+ support::children(&self.syntax)
+ }
+ pub fn destruct_rest(&self) -> Option<DestructRest> {
+ support::child(&self.syntax)
+ }
+ pub fn comma_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![,])
+ }
+ pub fn r_brace_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T!['}'])
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructObjectField {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructObjectField {
+ pub fn field(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+ pub fn colon_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![:])
+ }
+ pub fn destruct(&self) -> Option<Destruct> {
+ support::child(&self.syntax)
+ }
+ pub fn assign_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![=])
+ }
+ pub fn expr(&self) -> Option<Expr> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructRest {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructRest {
+ pub fn dotdotdot_token(&self) -> Option<SyntaxToken> {
+ support::token(&self.syntax, T![...])
+ }
+ pub fn into(&self) -> Option<Name> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct DestructArrayElement {
+ pub(crate) syntax: SyntaxNode,
+}
+impl DestructArrayElement {
+ pub fn destruct(&self) -> Option<Destruct> {
+ support::child(&self.syntax)
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Suffix {
+ SuffixIndex(SuffixIndex),
+ SuffixIndexExpr(SuffixIndexExpr),
+ SuffixSlice(SuffixSlice),
+ SuffixApply(SuffixApply),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Bind {
+ BindDestruct(BindDestruct),
+ BindFunction(BindFunction),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Stmt {
+ StmtLocal(StmtLocal),
+ StmtAssert(StmtAssert),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum ObjBody {
+ ObjBodyComp(ObjBodyComp),
+ ObjBodyMemberList(ObjBodyMemberList),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum CompSpec {
+ ForSpec(ForSpec),
+ IfSpec(IfSpec),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum ExprBase {
+ ExprBinary(ExprBinary),
+ ExprUnary(ExprUnary),
+ ExprObjExtend(ExprObjExtend),
+ ExprParened(ExprParened),
+ ExprString(ExprString),
+ ExprNumber(ExprNumber),
+ ExprLiteral(ExprLiteral),
+ ExprArray(ExprArray),
+ ExprObject(ExprObject),
+ ExprArrayComp(ExprArrayComp),
+ ExprImport(ExprImport),
+ ExprVar(ExprVar),
+ ExprIfThenElse(ExprIfThenElse),
+ ExprFunction(ExprFunction),
+ ExprError(ExprError),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum MemberComp {
+ MemberBindStmt(MemberBindStmt),
+ MemberFieldNormal(MemberFieldNormal),
+ MemberFieldMethod(MemberFieldMethod),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Member {
+ MemberBindStmt(MemberBindStmt),
+ MemberAssertStmt(MemberAssertStmt),
+ MemberFieldNormal(MemberFieldNormal),
+ MemberFieldMethod(MemberFieldMethod),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum FieldName {
+ FieldNameFixed(FieldNameFixed),
+ FieldNameDynamic(FieldNameDynamic),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Destruct {
+ DestructFull(DestructFull),
+ DestructSkip(DestructSkip),
+ DestructArray(DestructArray),
+ DestructObject(DestructObject),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum DestructArrayPart {
+ DestructArrayElement(DestructArrayElement),
+ DestructRest(DestructRest),
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct BinaryOperator {
+ syntax: SyntaxToken,
+ kind: BinaryOperatorKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum BinaryOperatorKind {
+ Or,
+ NullCoaelse,
+ And,
+ BitOr,
+ BitXor,
+ BitAnd,
+ Eq,
+ Ne,
+ Lt,
+ Gt,
+ Le,
+ Ge,
+ InKw,
+ Lhs,
+ Rhs,
+ Plus,
+ Minus,
+ Mul,
+ Div,
+ Modulo,
+ MetaObjectApply,
+ ErrorNoOperator,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct UnaryOperator {
+ syntax: SyntaxToken,
+ kind: UnaryOperatorKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum UnaryOperatorKind {
+ Minus,
+ Not,
+ BitNot,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Literal {
+ syntax: SyntaxToken,
+ kind: LiteralKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum LiteralKind {
+ NullKw,
+ TrueKw,
+ FalseKw,
+ SelfKw,
+ Dollar,
+ SuperKw,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Text {
+ syntax: SyntaxToken,
+ kind: TextKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum TextKind {
+ StringDouble,
+ ErrorStringDoubleUnterminated,
+ StringSingle,
+ ErrorStringSingleUnterminated,
+ StringDoubleVerbatim,
+ ErrorStringDoubleVerbatimUnterminated,
+ StringSingleVerbatim,
+ ErrorStringSingleVerbatimUnterminated,
+ ErrorStringVerbatimMissingQuotes,
+ StringBlock,
+ ErrorStringBlockUnexpectedEnd,
+ ErrorStringBlockMissingNewLine,
+ ErrorStringBlockMissingTermination,
+ ErrorStringBlockMissingIndent,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Number {
+ syntax: SyntaxToken,
+ kind: NumberKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum NumberKind {
+ Float,
+ ErrorFloatJunkAfterPoint,
+ ErrorFloatJunkAfterExponent,
+ ErrorFloatJunkAfterExponentSign,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ImportKind {
+ syntax: SyntaxToken,
+ kind: ImportKindKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ImportKindKind {
+ ImportstrKw,
+ ImportbinKw,
+ ImportKw,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Visibility {
+ syntax: SyntaxToken,
+ kind: VisibilityKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum VisibilityKind {
+ Coloncoloncolon,
+ Coloncolon,
+ Colon,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Trivia {
+ syntax: SyntaxToken,
+ kind: TriviaKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum TriviaKind {
+ Whitespace,
+ MultiLineComment,
+ ErrorCommentTooShort,
+ ErrorCommentUnterminated,
+ SingleLineHashComment,
+ SingleLineSlashComment,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CustomError {
+ syntax: SyntaxToken,
+ kind: CustomErrorKind,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum CustomErrorKind {
+ ErrorMissingToken,
+ ErrorUnexpectedToken,
+ ErrorCustom,
+}
+impl AstNode for SourceFile {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SOURCE_FILE
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for Expr {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SuffixIndex {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SUFFIX_INDEX
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for Name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == NAME
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SuffixIndexExpr {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SUFFIX_INDEX_EXPR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SuffixSlice {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SUFFIX_SLICE
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SliceDesc {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SLICE_DESC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SuffixApply {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SUFFIX_APPLY
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ArgsDesc {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == ARGS_DESC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for StmtLocal {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == STMT_LOCAL
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for StmtAssert {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == STMT_ASSERT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for Assertion {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == ASSERTION
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprBinary {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_BINARY
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprUnary {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_UNARY
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprObjExtend {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_OBJ_EXTEND
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprParened {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_PARENED
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprLiteral {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_LITERAL
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprString {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_STRING
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprNumber {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_NUMBER
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprArray {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_ARRAY
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprObject {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_OBJECT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprArrayComp {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_ARRAY_COMP
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprImport {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_IMPORT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprVar {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_VAR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprIfThenElse {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_IF_THEN_ELSE
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for TrueExpr {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == TRUE_EXPR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for FalseExpr {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == FALSE_EXPR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprFunction {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_FUNCTION
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ParamsDesc {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == PARAMS_DESC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ExprError {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == EXPR_ERROR
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SliceDescEnd {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SLICE_DESC_END
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for SliceDescStep {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == SLICE_DESC_STEP
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for Arg {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == ARG
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ObjBodyComp {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == OBJ_BODY_COMP
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ObjBodyMemberList {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == OBJ_BODY_MEMBER_LIST
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for MemberBindStmt {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == MEMBER_BIND_STMT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ObjLocal {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == OBJ_LOCAL
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for MemberAssertStmt {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == MEMBER_ASSERT_STMT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for MemberFieldNormal {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == MEMBER_FIELD_NORMAL
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for MemberFieldMethod {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == MEMBER_FIELD_METHOD
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for FieldNameFixed {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == FIELD_NAME_FIXED
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for FieldNameDynamic {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == FIELD_NAME_DYNAMIC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for ForSpec {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == FOR_SPEC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for IfSpec {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == IF_SPEC
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for BindDestruct {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == BIND_DESTRUCT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for BindFunction {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == BIND_FUNCTION
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for Param {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == PARAM
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructFull {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_FULL
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructSkip {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_SKIP
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructArray {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_ARRAY
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructObject {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_OBJECT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructObjectField {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_OBJECT_FIELD
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructRest {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_REST
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl AstNode for DestructArrayElement {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == DESTRUCT_ARRAY_ELEMENT
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+}
+impl From<SuffixIndex> for Suffix {
+ fn from(node: SuffixIndex) -> Suffix {
+ Suffix::SuffixIndex(node)
+ }
+}
+impl From<SuffixIndexExpr> for Suffix {
+ fn from(node: SuffixIndexExpr) -> Suffix {
+ Suffix::SuffixIndexExpr(node)
+ }
+}
+impl From<SuffixSlice> for Suffix {
+ fn from(node: SuffixSlice) -> Suffix {
+ Suffix::SuffixSlice(node)
+ }
+}
+impl From<SuffixApply> for Suffix {
+ fn from(node: SuffixApply) -> Suffix {
+ Suffix::SuffixApply(node)
+ }
+}
+impl AstNode for Suffix {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ SUFFIX_INDEX | SUFFIX_INDEX_EXPR | SUFFIX_SLICE | SUFFIX_APPLY => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ SUFFIX_INDEX => Suffix::SuffixIndex(SuffixIndex { syntax }),
+ SUFFIX_INDEX_EXPR => Suffix::SuffixIndexExpr(SuffixIndexExpr { syntax }),
+ SUFFIX_SLICE => Suffix::SuffixSlice(SuffixSlice { syntax }),
+ SUFFIX_APPLY => Suffix::SuffixApply(SuffixApply { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Suffix::SuffixIndex(it) => &it.syntax,
+ Suffix::SuffixIndexExpr(it) => &it.syntax,
+ Suffix::SuffixSlice(it) => &it.syntax,
+ Suffix::SuffixApply(it) => &it.syntax,
+ }
+ }
+}
+impl From<BindDestruct> for Bind {
+ fn from(node: BindDestruct) -> Bind {
+ Bind::BindDestruct(node)
+ }
+}
+impl From<BindFunction> for Bind {
+ fn from(node: BindFunction) -> Bind {
+ Bind::BindFunction(node)
+ }
+}
+impl AstNode for Bind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ BIND_DESTRUCT | BIND_FUNCTION => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ BIND_DESTRUCT => Bind::BindDestruct(BindDestruct { syntax }),
+ BIND_FUNCTION => Bind::BindFunction(BindFunction { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Bind::BindDestruct(it) => &it.syntax,
+ Bind::BindFunction(it) => &it.syntax,
+ }
+ }
+}
+impl From<StmtLocal> for Stmt {
+ fn from(node: StmtLocal) -> Stmt {
+ Stmt::StmtLocal(node)
+ }
+}
+impl From<StmtAssert> for Stmt {
+ fn from(node: StmtAssert) -> Stmt {
+ Stmt::StmtAssert(node)
+ }
+}
+impl AstNode for Stmt {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ STMT_LOCAL | STMT_ASSERT => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ STMT_LOCAL => Stmt::StmtLocal(StmtLocal { syntax }),
+ STMT_ASSERT => Stmt::StmtAssert(StmtAssert { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Stmt::StmtLocal(it) => &it.syntax,
+ Stmt::StmtAssert(it) => &it.syntax,
+ }
+ }
+}
+impl From<ObjBodyComp> for ObjBody {
+ fn from(node: ObjBodyComp) -> ObjBody {
+ ObjBody::ObjBodyComp(node)
+ }
+}
+impl From<ObjBodyMemberList> for ObjBody {
+ fn from(node: ObjBodyMemberList) -> ObjBody {
+ ObjBody::ObjBodyMemberList(node)
+ }
+}
+impl AstNode for ObjBody {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ OBJ_BODY_COMP | OBJ_BODY_MEMBER_LIST => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ OBJ_BODY_COMP => ObjBody::ObjBodyComp(ObjBodyComp { syntax }),
+ OBJ_BODY_MEMBER_LIST => ObjBody::ObjBodyMemberList(ObjBodyMemberList { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ ObjBody::ObjBodyComp(it) => &it.syntax,
+ ObjBody::ObjBodyMemberList(it) => &it.syntax,
+ }
+ }
+}
+impl From<ForSpec> for CompSpec {
+ fn from(node: ForSpec) -> CompSpec {
+ CompSpec::ForSpec(node)
+ }
+}
+impl From<IfSpec> for CompSpec {
+ fn from(node: IfSpec) -> CompSpec {
+ CompSpec::IfSpec(node)
+ }
+}
+impl AstNode for CompSpec {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FOR_SPEC | IF_SPEC => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ FOR_SPEC => CompSpec::ForSpec(ForSpec { syntax }),
+ IF_SPEC => CompSpec::IfSpec(IfSpec { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ CompSpec::ForSpec(it) => &it.syntax,
+ CompSpec::IfSpec(it) => &it.syntax,
+ }
+ }
+}
+impl From<ExprBinary> for ExprBase {
+ fn from(node: ExprBinary) -> ExprBase {
+ ExprBase::ExprBinary(node)
+ }
+}
+impl From<ExprUnary> for ExprBase {
+ fn from(node: ExprUnary) -> ExprBase {
+ ExprBase::ExprUnary(node)
+ }
+}
+impl From<ExprObjExtend> for ExprBase {
+ fn from(node: ExprObjExtend) -> ExprBase {
+ ExprBase::ExprObjExtend(node)
+ }
+}
+impl From<ExprParened> for ExprBase {
+ fn from(node: ExprParened) -> ExprBase {
+ ExprBase::ExprParened(node)
+ }
+}
+impl From<ExprString> for ExprBase {
+ fn from(node: ExprString) -> ExprBase {
+ ExprBase::ExprString(node)
+ }
+}
+impl From<ExprNumber> for ExprBase {
+ fn from(node: ExprNumber) -> ExprBase {
+ ExprBase::ExprNumber(node)
+ }
+}
+impl From<ExprLiteral> for ExprBase {
+ fn from(node: ExprLiteral) -> ExprBase {
+ ExprBase::ExprLiteral(node)
+ }
+}
+impl From<ExprArray> for ExprBase {
+ fn from(node: ExprArray) -> ExprBase {
+ ExprBase::ExprArray(node)
+ }
+}
+impl From<ExprObject> for ExprBase {
+ fn from(node: ExprObject) -> ExprBase {
+ ExprBase::ExprObject(node)
+ }
+}
+impl From<ExprArrayComp> for ExprBase {
+ fn from(node: ExprArrayComp) -> ExprBase {
+ ExprBase::ExprArrayComp(node)
+ }
+}
+impl From<ExprImport> for ExprBase {
+ fn from(node: ExprImport) -> ExprBase {
+ ExprBase::ExprImport(node)
+ }
+}
+impl From<ExprVar> for ExprBase {
+ fn from(node: ExprVar) -> ExprBase {
+ ExprBase::ExprVar(node)
+ }
+}
+impl From<ExprIfThenElse> for ExprBase {
+ fn from(node: ExprIfThenElse) -> ExprBase {
+ ExprBase::ExprIfThenElse(node)
+ }
+}
+impl From<ExprFunction> for ExprBase {
+ fn from(node: ExprFunction) -> ExprBase {
+ ExprBase::ExprFunction(node)
+ }
+}
+impl From<ExprError> for ExprBase {
+ fn from(node: ExprError) -> ExprBase {
+ ExprBase::ExprError(node)
+ }
+}
+impl AstNode for ExprBase {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ EXPR_BINARY | EXPR_UNARY | EXPR_OBJ_EXTEND | EXPR_PARENED | EXPR_STRING
+ | EXPR_NUMBER | EXPR_LITERAL | EXPR_ARRAY | EXPR_OBJECT | EXPR_ARRAY_COMP
+ | EXPR_IMPORT | EXPR_VAR | EXPR_IF_THEN_ELSE | EXPR_FUNCTION | EXPR_ERROR => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ EXPR_BINARY => ExprBase::ExprBinary(ExprBinary { syntax }),
+ EXPR_UNARY => ExprBase::ExprUnary(ExprUnary { syntax }),
+ EXPR_OBJ_EXTEND => ExprBase::ExprObjExtend(ExprObjExtend { syntax }),
+ EXPR_PARENED => ExprBase::ExprParened(ExprParened { syntax }),
+ EXPR_STRING => ExprBase::ExprString(ExprString { syntax }),
+ EXPR_NUMBER => ExprBase::ExprNumber(ExprNumber { syntax }),
+ EXPR_LITERAL => ExprBase::ExprLiteral(ExprLiteral { syntax }),
+ EXPR_ARRAY => ExprBase::ExprArray(ExprArray { syntax }),
+ EXPR_OBJECT => ExprBase::ExprObject(ExprObject { syntax }),
+ EXPR_ARRAY_COMP => ExprBase::ExprArrayComp(ExprArrayComp { syntax }),
+ EXPR_IMPORT => ExprBase::ExprImport(ExprImport { syntax }),
+ EXPR_VAR => ExprBase::ExprVar(ExprVar { syntax }),
+ EXPR_IF_THEN_ELSE => ExprBase::ExprIfThenElse(ExprIfThenElse { syntax }),
+ EXPR_FUNCTION => ExprBase::ExprFunction(ExprFunction { syntax }),
+ EXPR_ERROR => ExprBase::ExprError(ExprError { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ ExprBase::ExprBinary(it) => &it.syntax,
+ ExprBase::ExprUnary(it) => &it.syntax,
+ ExprBase::ExprObjExtend(it) => &it.syntax,
+ ExprBase::ExprParened(it) => &it.syntax,
+ ExprBase::ExprString(it) => &it.syntax,
+ ExprBase::ExprNumber(it) => &it.syntax,
+ ExprBase::ExprLiteral(it) => &it.syntax,
+ ExprBase::ExprArray(it) => &it.syntax,
+ ExprBase::ExprObject(it) => &it.syntax,
+ ExprBase::ExprArrayComp(it) => &it.syntax,
+ ExprBase::ExprImport(it) => &it.syntax,
+ ExprBase::ExprVar(it) => &it.syntax,
+ ExprBase::ExprIfThenElse(it) => &it.syntax,
+ ExprBase::ExprFunction(it) => &it.syntax,
+ ExprBase::ExprError(it) => &it.syntax,
+ }
+ }
+}
+impl From<MemberBindStmt> for MemberComp {
+ fn from(node: MemberBindStmt) -> MemberComp {
+ MemberComp::MemberBindStmt(node)
+ }
+}
+impl From<MemberFieldNormal> for MemberComp {
+ fn from(node: MemberFieldNormal) -> MemberComp {
+ MemberComp::MemberFieldNormal(node)
+ }
+}
+impl From<MemberFieldMethod> for MemberComp {
+ fn from(node: MemberFieldMethod) -> MemberComp {
+ MemberComp::MemberFieldMethod(node)
+ }
+}
+impl AstNode for MemberComp {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ MEMBER_BIND_STMT | MEMBER_FIELD_NORMAL | MEMBER_FIELD_METHOD => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ MEMBER_BIND_STMT => MemberComp::MemberBindStmt(MemberBindStmt { syntax }),
+ MEMBER_FIELD_NORMAL => MemberComp::MemberFieldNormal(MemberFieldNormal { syntax }),
+ MEMBER_FIELD_METHOD => MemberComp::MemberFieldMethod(MemberFieldMethod { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ MemberComp::MemberBindStmt(it) => &it.syntax,
+ MemberComp::MemberFieldNormal(it) => &it.syntax,
+ MemberComp::MemberFieldMethod(it) => &it.syntax,
+ }
+ }
+}
+impl From<MemberBindStmt> for Member {
+ fn from(node: MemberBindStmt) -> Member {
+ Member::MemberBindStmt(node)
+ }
+}
+impl From<MemberAssertStmt> for Member {
+ fn from(node: MemberAssertStmt) -> Member {
+ Member::MemberAssertStmt(node)
+ }
+}
+impl From<MemberFieldNormal> for Member {
+ fn from(node: MemberFieldNormal) -> Member {
+ Member::MemberFieldNormal(node)
+ }
+}
+impl From<MemberFieldMethod> for Member {
+ fn from(node: MemberFieldMethod) -> Member {
+ Member::MemberFieldMethod(node)
+ }
+}
+impl AstNode for Member {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ MEMBER_BIND_STMT | MEMBER_ASSERT_STMT | MEMBER_FIELD_NORMAL | MEMBER_FIELD_METHOD => {
+ true
+ }
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ MEMBER_BIND_STMT => Member::MemberBindStmt(MemberBindStmt { syntax }),
+ MEMBER_ASSERT_STMT => Member::MemberAssertStmt(MemberAssertStmt { syntax }),
+ MEMBER_FIELD_NORMAL => Member::MemberFieldNormal(MemberFieldNormal { syntax }),
+ MEMBER_FIELD_METHOD => Member::MemberFieldMethod(MemberFieldMethod { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Member::MemberBindStmt(it) => &it.syntax,
+ Member::MemberAssertStmt(it) => &it.syntax,
+ Member::MemberFieldNormal(it) => &it.syntax,
+ Member::MemberFieldMethod(it) => &it.syntax,
+ }
+ }
+}
+impl From<FieldNameFixed> for FieldName {
+ fn from(node: FieldNameFixed) -> FieldName {
+ FieldName::FieldNameFixed(node)
+ }
+}
+impl From<FieldNameDynamic> for FieldName {
+ fn from(node: FieldNameDynamic) -> FieldName {
+ FieldName::FieldNameDynamic(node)
+ }
+}
+impl AstNode for FieldName {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FIELD_NAME_FIXED | FIELD_NAME_DYNAMIC => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ FIELD_NAME_FIXED => FieldName::FieldNameFixed(FieldNameFixed { syntax }),
+ FIELD_NAME_DYNAMIC => FieldName::FieldNameDynamic(FieldNameDynamic { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ FieldName::FieldNameFixed(it) => &it.syntax,
+ FieldName::FieldNameDynamic(it) => &it.syntax,
+ }
+ }
+}
+impl From<DestructFull> for Destruct {
+ fn from(node: DestructFull) -> Destruct {
+ Destruct::DestructFull(node)
+ }
+}
+impl From<DestructSkip> for Destruct {
+ fn from(node: DestructSkip) -> Destruct {
+ Destruct::DestructSkip(node)
+ }
+}
+impl From<DestructArray> for Destruct {
+ fn from(node: DestructArray) -> Destruct {
+ Destruct::DestructArray(node)
+ }
+}
+impl From<DestructObject> for Destruct {
+ fn from(node: DestructObject) -> Destruct {
+ Destruct::DestructObject(node)
+ }
+}
+impl AstNode for Destruct {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ DESTRUCT_FULL | DESTRUCT_SKIP | DESTRUCT_ARRAY | DESTRUCT_OBJECT => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ DESTRUCT_FULL => Destruct::DestructFull(DestructFull { syntax }),
+ DESTRUCT_SKIP => Destruct::DestructSkip(DestructSkip { syntax }),
+ DESTRUCT_ARRAY => Destruct::DestructArray(DestructArray { syntax }),
+ DESTRUCT_OBJECT => Destruct::DestructObject(DestructObject { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ Destruct::DestructFull(it) => &it.syntax,
+ Destruct::DestructSkip(it) => &it.syntax,
+ Destruct::DestructArray(it) => &it.syntax,
+ Destruct::DestructObject(it) => &it.syntax,
+ }
+ }
+}
+impl From<DestructArrayElement> for DestructArrayPart {
+ fn from(node: DestructArrayElement) -> DestructArrayPart {
+ DestructArrayPart::DestructArrayElement(node)
+ }
+}
+impl From<DestructRest> for DestructArrayPart {
+ fn from(node: DestructRest) -> DestructArrayPart {
+ DestructArrayPart::DestructRest(node)
+ }
+}
+impl AstNode for DestructArrayPart {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ DESTRUCT_ARRAY_ELEMENT | DESTRUCT_REST => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ DESTRUCT_ARRAY_ELEMENT => {
+ DestructArrayPart::DestructArrayElement(DestructArrayElement { syntax })
+ }
+ DESTRUCT_REST => DestructArrayPart::DestructRest(DestructRest { syntax }),
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ DestructArrayPart::DestructArrayElement(it) => &it.syntax,
+ DestructArrayPart::DestructRest(it) => &it.syntax,
+ }
+ }
+}
+impl AstToken for BinaryOperator {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ BinaryOperatorKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = BinaryOperatorKind::cast(syntax.kind())?;
+ Some(BinaryOperator { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl BinaryOperatorKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ OR | NULL_COAELSE | AND | BIT_OR | BIT_XOR | BIT_AND | EQ | NE | LT | GT | LE | GE
+ | IN_KW | LHS | RHS | PLUS | MINUS | MUL | DIV | MODULO | META_OBJECT_APPLY
+ | ERROR_NO_OPERATOR => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ OR => Self::Or,
+ NULL_COAELSE => Self::NullCoaelse,
+ AND => Self::And,
+ BIT_OR => Self::BitOr,
+ BIT_XOR => Self::BitXor,
+ BIT_AND => Self::BitAnd,
+ EQ => Self::Eq,
+ NE => Self::Ne,
+ LT => Self::Lt,
+ GT => Self::Gt,
+ LE => Self::Le,
+ GE => Self::Ge,
+ IN_KW => Self::InKw,
+ LHS => Self::Lhs,
+ RHS => Self::Rhs,
+ PLUS => Self::Plus,
+ MINUS => Self::Minus,
+ MUL => Self::Mul,
+ DIV => Self::Div,
+ MODULO => Self::Modulo,
+ META_OBJECT_APPLY => Self::MetaObjectApply,
+ ERROR_NO_OPERATOR => Self::ErrorNoOperator,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl BinaryOperator {
+ pub fn kind(&self) -> BinaryOperatorKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for BinaryOperator {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for UnaryOperator {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ UnaryOperatorKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = UnaryOperatorKind::cast(syntax.kind())?;
+ Some(UnaryOperator { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl UnaryOperatorKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ MINUS | NOT | BIT_NOT => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ MINUS => Self::Minus,
+ NOT => Self::Not,
+ BIT_NOT => Self::BitNot,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl UnaryOperator {
+ pub fn kind(&self) -> UnaryOperatorKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for UnaryOperator {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for Literal {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ LiteralKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = LiteralKind::cast(syntax.kind())?;
+ Some(Literal { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl LiteralKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ NULL_KW | TRUE_KW | FALSE_KW | SELF_KW | DOLLAR | SUPER_KW => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ NULL_KW => Self::NullKw,
+ TRUE_KW => Self::TrueKw,
+ FALSE_KW => Self::FalseKw,
+ SELF_KW => Self::SelfKw,
+ DOLLAR => Self::Dollar,
+ SUPER_KW => Self::SuperKw,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl Literal {
+ pub fn kind(&self) -> LiteralKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for Literal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for Text {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ TextKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = TextKind::cast(syntax.kind())?;
+ Some(Text { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl TextKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ STRING_DOUBLE
+ | ERROR_STRING_DOUBLE_UNTERMINATED
+ | STRING_SINGLE
+ | ERROR_STRING_SINGLE_UNTERMINATED
+ | STRING_DOUBLE_VERBATIM
+ | ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED
+ | STRING_SINGLE_VERBATIM
+ | ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED
+ | ERROR_STRING_VERBATIM_MISSING_QUOTES
+ | STRING_BLOCK
+ | ERROR_STRING_BLOCK_UNEXPECTED_END
+ | ERROR_STRING_BLOCK_MISSING_NEW_LINE
+ | ERROR_STRING_BLOCK_MISSING_TERMINATION
+ | ERROR_STRING_BLOCK_MISSING_INDENT => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ STRING_DOUBLE => Self::StringDouble,
+ ERROR_STRING_DOUBLE_UNTERMINATED => Self::ErrorStringDoubleUnterminated,
+ STRING_SINGLE => Self::StringSingle,
+ ERROR_STRING_SINGLE_UNTERMINATED => Self::ErrorStringSingleUnterminated,
+ STRING_DOUBLE_VERBATIM => Self::StringDoubleVerbatim,
+ ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED => {
+ Self::ErrorStringDoubleVerbatimUnterminated
+ }
+ STRING_SINGLE_VERBATIM => Self::StringSingleVerbatim,
+ ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED => {
+ Self::ErrorStringSingleVerbatimUnterminated
+ }
+ ERROR_STRING_VERBATIM_MISSING_QUOTES => Self::ErrorStringVerbatimMissingQuotes,
+ STRING_BLOCK => Self::StringBlock,
+ ERROR_STRING_BLOCK_UNEXPECTED_END => Self::ErrorStringBlockUnexpectedEnd,
+ ERROR_STRING_BLOCK_MISSING_NEW_LINE => Self::ErrorStringBlockMissingNewLine,
+ ERROR_STRING_BLOCK_MISSING_TERMINATION => Self::ErrorStringBlockMissingTermination,
+ ERROR_STRING_BLOCK_MISSING_INDENT => Self::ErrorStringBlockMissingIndent,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl Text {
+ pub fn kind(&self) -> TextKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for Text {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for Number {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ NumberKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = NumberKind::cast(syntax.kind())?;
+ Some(Number { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl NumberKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ FLOAT
+ | ERROR_FLOAT_JUNK_AFTER_POINT
+ | ERROR_FLOAT_JUNK_AFTER_EXPONENT
+ | ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ FLOAT => Self::Float,
+ ERROR_FLOAT_JUNK_AFTER_POINT => Self::ErrorFloatJunkAfterPoint,
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT => Self::ErrorFloatJunkAfterExponent,
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN => Self::ErrorFloatJunkAfterExponentSign,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl Number {
+ pub fn kind(&self) -> NumberKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for Number {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for ImportKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ ImportKindKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = ImportKindKind::cast(syntax.kind())?;
+ Some(ImportKind { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl ImportKindKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ IMPORTSTR_KW | IMPORTBIN_KW | IMPORT_KW => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ IMPORTSTR_KW => Self::ImportstrKw,
+ IMPORTBIN_KW => Self::ImportbinKw,
+ IMPORT_KW => Self::ImportKw,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl ImportKind {
+ pub fn kind(&self) -> ImportKindKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for ImportKind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for Visibility {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ VisibilityKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = VisibilityKind::cast(syntax.kind())?;
+ Some(Visibility { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl VisibilityKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ COLONCOLONCOLON | COLONCOLON | COLON => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ COLONCOLONCOLON => Self::Coloncoloncolon,
+ COLONCOLON => Self::Coloncolon,
+ COLON => Self::Colon,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl Visibility {
+ pub fn kind(&self) -> VisibilityKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for Visibility {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for Trivia {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ TriviaKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = TriviaKind::cast(syntax.kind())?;
+ Some(Trivia { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl TriviaKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ WHITESPACE
+ | MULTI_LINE_COMMENT
+ | ERROR_COMMENT_TOO_SHORT
+ | ERROR_COMMENT_UNTERMINATED
+ | SINGLE_LINE_HASH_COMMENT
+ | SINGLE_LINE_SLASH_COMMENT => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ WHITESPACE => Self::Whitespace,
+ MULTI_LINE_COMMENT => Self::MultiLineComment,
+ ERROR_COMMENT_TOO_SHORT => Self::ErrorCommentTooShort,
+ ERROR_COMMENT_UNTERMINATED => Self::ErrorCommentUnterminated,
+ SINGLE_LINE_HASH_COMMENT => Self::SingleLineHashComment,
+ SINGLE_LINE_SLASH_COMMENT => Self::SingleLineSlashComment,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl Trivia {
+ pub fn kind(&self) -> TriviaKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for Trivia {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl AstToken for CustomError {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ CustomErrorKind::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = CustomErrorKind::cast(syntax.kind())?;
+ Some(CustomError { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+}
+impl CustomErrorKind {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ ERROR_MISSING_TOKEN | ERROR_UNEXPECTED_TOKEN | ERROR_CUSTOM => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ ERROR_MISSING_TOKEN => Self::ErrorMissingToken,
+ ERROR_UNEXPECTED_TOKEN => Self::ErrorUnexpectedToken,
+ ERROR_CUSTOM => Self::ErrorCustom,
+ _ => return None,
+ };
+ Some(res)
+ }
+}
+impl CustomError {
+ pub fn kind(&self) -> CustomErrorKind {
+ self.kind
+ }
+}
+impl std::fmt::Display for CustomError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Suffix {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Bind {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Stmt {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBody {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for CompSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprBase {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberComp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Member {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldName {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Destruct {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructArrayPart {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SourceFile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Expr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SuffixIndex {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SuffixIndexExpr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SuffixSlice {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SliceDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SuffixApply {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ArgsDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for StmtLocal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for StmtAssert {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Assertion {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprBinary {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprUnary {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprObjExtend {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprParened {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprLiteral {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprString {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprNumber {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprArray {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprObject {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprArrayComp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprImport {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprVar {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprIfThenElse {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for TrueExpr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FalseExpr {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprFunction {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ParamsDesc {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ExprError {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SliceDescEnd {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for SliceDescStep {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Arg {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBodyComp {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjBodyMemberList {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberBindStmt {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ObjLocal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberAssertStmt {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberFieldNormal {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for MemberFieldMethod {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldNameFixed {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for FieldNameDynamic {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for ForSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for IfSpec {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for BindDestruct {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for BindFunction {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for Param {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructFull {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructSkip {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructArray {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructObject {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructObjectField {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructRest {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
+impl std::fmt::Display for DestructArrayElement {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs
@@ -0,0 +1,293 @@
+//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.
+
+#![allow(
+ bad_style,
+ missing_docs,
+ unreachable_pub,
+ clippy::manual_non_exhaustive,
+ clippy::match_like_matches_macro
+)]
+use logos::Logos;
+#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]
+#[repr(u16)]
+pub enum SyntaxKind {
+ #[doc(hidden)]
+ TOMBSTONE,
+ #[doc(hidden)]
+ EOF,
+ #[token("||")]
+ OR,
+ #[token("??")]
+ NULL_COAELSE,
+ #[token("&&")]
+ AND,
+ #[token("|")]
+ BIT_OR,
+ #[token("^")]
+ BIT_XOR,
+ #[token("&")]
+ BIT_AND,
+ #[token("==")]
+ EQ,
+ #[token("!=")]
+ NE,
+ #[token("<")]
+ LT,
+ #[token(">")]
+ GT,
+ #[token("<=")]
+ LE,
+ #[token(">=")]
+ GE,
+ #[token("<<")]
+ LHS,
+ #[token(">>")]
+ RHS,
+ #[token("+")]
+ PLUS,
+ #[token("-")]
+ MINUS,
+ #[token("*")]
+ MUL,
+ #[token("/")]
+ DIV,
+ #[token("%")]
+ MODULO,
+ #[token("!")]
+ NOT,
+ #[token("~")]
+ BIT_NOT,
+ #[token("[")]
+ L_BRACK,
+ #[token("]")]
+ R_BRACK,
+ #[token("(")]
+ L_PAREN,
+ #[token(")")]
+ R_PAREN,
+ #[token("{")]
+ L_BRACE,
+ #[token("}")]
+ R_BRACE,
+ #[token(":")]
+ COLON,
+ #[token("::")]
+ COLONCOLON,
+ #[token(":::")]
+ COLONCOLONCOLON,
+ #[token(";")]
+ SEMI,
+ #[token(".")]
+ DOT,
+ #[token("...")]
+ DOTDOTDOT,
+ #[token(",")]
+ COMMA,
+ #[token("$")]
+ DOLLAR,
+ #[token("=")]
+ ASSIGN,
+ #[token("?")]
+ QUESTION_MARK,
+ #[regex("(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?")]
+ FLOAT,
+ #[regex("(?:0|[1-9][0-9]*)\\.[^0-9]")]
+ ERROR_FLOAT_JUNK_AFTER_POINT,
+ #[regex("(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?[eE][^+\\-0-9]")]
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT,
+ #[regex("(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?[eE][+-][^0-9]")]
+ ERROR_FLOAT_JUNK_AFTER_EXPONENT_SIGN,
+ #[regex("\"(?s:[^\"\\\\]|\\\\.)*\"")]
+ STRING_DOUBLE,
+ #[regex("\"(?s:[^\"\\\\]|\\\\.)*")]
+ ERROR_STRING_DOUBLE_UNTERMINATED,
+ #[regex("'(?s:[^'\\\\]|\\\\.)*'")]
+ STRING_SINGLE,
+ #[regex("'(?s:[^'\\\\]|\\\\.)*")]
+ ERROR_STRING_SINGLE_UNTERMINATED,
+ #[regex("@\"(?:[^\"]|\"\")*\"")]
+ STRING_DOUBLE_VERBATIM,
+ #[regex("@\"(?:[^\"]|\"\")*")]
+ ERROR_STRING_DOUBLE_VERBATIM_UNTERMINATED,
+ #[regex("@'(?:[^']|'')*'")]
+ STRING_SINGLE_VERBATIM,
+ #[regex("@'(?:[^']|'')*")]
+ ERROR_STRING_SINGLE_VERBATIM_UNTERMINATED,
+ #[regex("@[^\"'\\s]\\S+")]
+ ERROR_STRING_VERBATIM_MISSING_QUOTES,
+ #[regex("\\|\\|\\|", crate::string_block::lex_str_block_test)]
+ STRING_BLOCK,
+ ERROR_STRING_BLOCK_UNEXPECTED_END,
+ ERROR_STRING_BLOCK_MISSING_NEW_LINE,
+ ERROR_STRING_BLOCK_MISSING_TERMINATION,
+ ERROR_STRING_BLOCK_MISSING_INDENT,
+ #[regex("[_a-zA-Z][_a-zA-Z0-9]*")]
+ IDENT,
+ #[regex("[ \\t\\n\\r]+")]
+ WHITESPACE,
+ #[regex("//[^\\r\\n]*(\\r\\n|\\n)?")]
+ SINGLE_LINE_SLASH_COMMENT,
+ #[regex("#[^\\r\\n]*(\\r\\n|\\n)?")]
+ SINGLE_LINE_HASH_COMMENT,
+ #[regex("/\\*([^*]|\\*[^/])*\\*/")]
+ MULTI_LINE_COMMENT,
+ #[regex("/\\*/")]
+ ERROR_COMMENT_TOO_SHORT,
+ #[regex("/\\*([^*]|\\*[^/])+")]
+ ERROR_COMMENT_UNTERMINATED,
+ #[token("tailstrict")]
+ TAILSTRICT_KW,
+ #[token("local")]
+ LOCAL_KW,
+ #[token("importstr")]
+ IMPORTSTR_KW,
+ #[token("importbin")]
+ IMPORTBIN_KW,
+ #[token("import")]
+ IMPORT_KW,
+ #[token("if")]
+ IF_KW,
+ #[token("then")]
+ THEN_KW,
+ #[token("else")]
+ ELSE_KW,
+ #[token("function")]
+ FUNCTION_KW,
+ #[token("error")]
+ ERROR_KW,
+ #[token("in")]
+ IN_KW,
+ META_OBJECT_APPLY,
+ ERROR_NO_OPERATOR,
+ #[token("null")]
+ NULL_KW,
+ #[token("true")]
+ TRUE_KW,
+ #[token("false")]
+ FALSE_KW,
+ #[token("self")]
+ SELF_KW,
+ #[token("super")]
+ SUPER_KW,
+ #[token("for")]
+ FOR_KW,
+ #[token("assert")]
+ ASSERT_KW,
+ ERROR_MISSING_TOKEN,
+ ERROR_UNEXPECTED_TOKEN,
+ ERROR_CUSTOM,
+ #[doc = r" Also acts as __LAST_TOKEN"]
+ #[error]
+ LEXING_ERROR,
+ SOURCE_FILE,
+ EXPR,
+ SUFFIX_INDEX,
+ NAME,
+ SUFFIX_INDEX_EXPR,
+ SUFFIX_SLICE,
+ SLICE_DESC,
+ SUFFIX_APPLY,
+ ARGS_DESC,
+ STMT_LOCAL,
+ STMT_ASSERT,
+ ASSERTION,
+ EXPR_BINARY,
+ EXPR_UNARY,
+ EXPR_OBJ_EXTEND,
+ EXPR_PARENED,
+ EXPR_LITERAL,
+ EXPR_STRING,
+ EXPR_NUMBER,
+ EXPR_ARRAY,
+ EXPR_OBJECT,
+ EXPR_ARRAY_COMP,
+ EXPR_IMPORT,
+ EXPR_VAR,
+ EXPR_IF_THEN_ELSE,
+ TRUE_EXPR,
+ FALSE_EXPR,
+ EXPR_FUNCTION,
+ PARAMS_DESC,
+ EXPR_ERROR,
+ SLICE_DESC_END,
+ SLICE_DESC_STEP,
+ ARG,
+ OBJ_BODY_COMP,
+ OBJ_BODY_MEMBER_LIST,
+ MEMBER_BIND_STMT,
+ OBJ_LOCAL,
+ MEMBER_ASSERT_STMT,
+ MEMBER_FIELD_NORMAL,
+ MEMBER_FIELD_METHOD,
+ FIELD_NAME_FIXED,
+ FIELD_NAME_DYNAMIC,
+ FOR_SPEC,
+ IF_SPEC,
+ BIND_DESTRUCT,
+ BIND_FUNCTION,
+ PARAM,
+ DESTRUCT_FULL,
+ DESTRUCT_SKIP,
+ DESTRUCT_ARRAY,
+ DESTRUCT_OBJECT,
+ DESTRUCT_OBJECT_FIELD,
+ DESTRUCT_REST,
+ DESTRUCT_ARRAY_ELEMENT,
+ SUFFIX,
+ BIND,
+ STMT,
+ OBJ_BODY,
+ COMP_SPEC,
+ EXPR_BASE,
+ MEMBER_COMP,
+ MEMBER,
+ FIELD_NAME,
+ DESTRUCT,
+ DESTRUCT_ARRAY_PART,
+ BINARY_OPERATOR,
+ UNARY_OPERATOR,
+ LITERAL,
+ TEXT,
+ NUMBER,
+ IMPORT_KIND,
+ VISIBILITY,
+ TRIVIA,
+ CUSTOM_ERROR,
+ #[doc(hidden)]
+ __LAST,
+}
+use self::SyntaxKind::*;
+impl SyntaxKind {
+ pub fn is_keyword(self) -> bool {
+ match self {
+ OR | NULL_COAELSE | AND | BIT_OR | BIT_XOR | BIT_AND | EQ | NE | LT | GT | LE | GE
+ | LHS | RHS | PLUS | MINUS | MUL | DIV | MODULO | NOT | BIT_NOT | L_BRACK | R_BRACK
+ | L_PAREN | R_PAREN | L_BRACE | R_BRACE | COLON | COLONCOLON | COLONCOLONCOLON
+ | SEMI | DOT | DOTDOTDOT | COMMA | DOLLAR | ASSIGN | QUESTION_MARK | TAILSTRICT_KW
+ | LOCAL_KW | IMPORTSTR_KW | IMPORTBIN_KW | IMPORT_KW | IF_KW | THEN_KW | ELSE_KW
+ | FUNCTION_KW | ERROR_KW | IN_KW | NULL_KW | TRUE_KW | FALSE_KW | SELF_KW
+ | SUPER_KW | FOR_KW | ASSERT_KW => true,
+ _ => false,
+ }
+ }
+ pub fn is_enum(self) -> bool {
+ match self {
+ SUFFIX | BIND | STMT | OBJ_BODY | COMP_SPEC | EXPR_BASE | MEMBER_COMP | MEMBER
+ | FIELD_NAME | DESTRUCT | DESTRUCT_ARRAY_PART | BINARY_OPERATOR | UNARY_OPERATOR
+ | LITERAL | TEXT | NUMBER | IMPORT_KIND | VISIBILITY | TRIVIA | CUSTOM_ERROR => true,
+ _ => false,
+ }
+ }
+ pub fn from_raw(r: u16) -> Self {
+ assert!(r < Self::__LAST as u16);
+ unsafe { std::mem::transmute(r) }
+ }
+ pub fn into_raw(self) -> u16 {
+ self as u16
+ }
+}
+#[macro_export]
+macro_rules ! T { [||] => { $ crate :: SyntaxKind :: OR } ; [??] => { $ crate :: SyntaxKind :: NULL_COAELSE } ; [&&] => { $ crate :: SyntaxKind :: AND } ; [|] => { $ crate :: SyntaxKind :: BIT_OR } ; [^] => { $ crate :: SyntaxKind :: BIT_XOR } ; [&] => { $ crate :: SyntaxKind :: BIT_AND } ; [==] => { $ crate :: SyntaxKind :: EQ } ; [!=] => { $ crate :: SyntaxKind :: NE } ; [<] => { $ crate :: SyntaxKind :: LT } ; [>] => { $ crate :: SyntaxKind :: GT } ; [<=] => { $ crate :: SyntaxKind :: LE } ; [>=] => { $ crate :: SyntaxKind :: GE } ; [<<] => { $ crate :: SyntaxKind :: LHS } ; [>>] => { $ crate :: SyntaxKind :: RHS } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [*] => { $ crate :: SyntaxKind :: MUL } ; [/] => { $ crate :: SyntaxKind :: DIV } ; [%] => { $ crate :: SyntaxKind :: MODULO } ; [!] => { $ crate :: SyntaxKind :: NOT } ; [~] => { $ crate :: SyntaxKind :: BIT_NOT } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_BRACE } ; ['}'] => { $ crate :: SyntaxKind :: R_BRACE } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLONCOLON } ; [:::] => { $ crate :: SyntaxKind :: COLONCOLONCOLON } ; [;] => { $ crate :: SyntaxKind :: SEMI } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [...] => { $ crate :: SyntaxKind :: DOTDOTDOT } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['$'] => { $ crate :: SyntaxKind :: DOLLAR } ; [=] => { $ crate :: SyntaxKind :: ASSIGN } ; [?] => { $ crate :: SyntaxKind :: QUESTION_MARK } ; [tailstrict] => { $ crate :: SyntaxKind :: TAILSTRICT_KW } ; [local] => { $ crate :: SyntaxKind :: LOCAL_KW } ; [importstr] => { $ crate :: SyntaxKind :: IMPORTSTR_KW } ; [importbin] => { $ crate :: SyntaxKind :: IMPORTBIN_KW } ; [import] => { $ crate :: SyntaxKind :: IMPORT_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [then] => { $ crate :: SyntaxKind :: THEN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [function] => { $ crate :: SyntaxKind :: FUNCTION_KW } ; [error] => { $ crate :: SyntaxKind :: ERROR_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [null] => { $ crate :: SyntaxKind :: NULL_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [assert] => { $ crate :: SyntaxKind :: ASSERT_KW } }
+pub use T;
crates/jrsonnet-rowan-parser/src/language.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/language.rs
@@ -0,0 +1,24 @@
+use rowan::Language;
+
+use crate::SyntaxKind;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum JsonnetLanguage {}
+impl Language for JsonnetLanguage {
+ type Kind = SyntaxKind;
+
+ fn kind_from_raw(raw: rowan::SyntaxKind) -> SyntaxKind {
+ SyntaxKind::from_raw(raw.0)
+ }
+
+ fn kind_to_raw(kind: SyntaxKind) -> rowan::SyntaxKind {
+ rowan::SyntaxKind(kind.into_raw())
+ }
+}
+
+pub type SyntaxNode = rowan::SyntaxNode<JsonnetLanguage>;
+pub type SyntaxToken = rowan::SyntaxToken<JsonnetLanguage>;
+pub type SyntaxElement = rowan::SyntaxElement<JsonnetLanguage>;
+pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<JsonnetLanguage>;
+pub type SyntaxElementChildren = rowan::SyntaxElementChildren<JsonnetLanguage>;
+pub type PreorderWithTokens = rowan::api::PreorderWithTokens<JsonnetLanguage>;
crates/jrsonnet-rowan-parser/src/lex.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/lex.rs
@@ -0,0 +1,80 @@
+use core::ops::Range;
+use std::convert::TryFrom;
+
+use logos::Logos;
+use rowan::{TextRange, TextSize};
+
+use crate::{
+ string_block::{lex_str_block, StringBlockError},
+ SyntaxKind,
+};
+
+pub struct Lexer<'a> {
+ inner: logos::Lexer<'a, SyntaxKind>,
+}
+
+impl<'a> Lexer<'a> {
+ pub fn new(input: &'a str) -> Self {
+ Self {
+ inner: SyntaxKind::lexer(input),
+ }
+ }
+}
+
+impl<'a> Iterator for Lexer<'a> {
+ type Item = Lexeme<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ use SyntaxKind::*;
+
+ let mut kind = self.inner.next()?;
+ let text = self.inner.slice();
+
+ if kind == STRING_BLOCK {
+ // We use custom lexer, which skips enough bytes, but not returns error
+ // Instead we should call lexer again to verify if there is something wrong with string block
+ let mut lexer = logos::Lexer::<SyntaxKind>::new(text);
+ // In kinds, string blocks is parsed at least as `|||`
+ lexer.bump(3);
+ let res = lex_str_block(&mut lexer);
+ debug_assert!(lexer.next().is_none(), "str_block is lexed");
+ match res {
+ Ok(_) => {}
+ Err(e) => {
+ kind = match e {
+ StringBlockError::UnexpectedEnd => ERROR_STRING_BLOCK_UNEXPECTED_END,
+ StringBlockError::MissingNewLine => ERROR_STRING_BLOCK_MISSING_NEW_LINE,
+ StringBlockError::MissingTermination => {
+ ERROR_STRING_BLOCK_MISSING_TERMINATION
+ }
+ StringBlockError::MissingIndent => ERROR_STRING_BLOCK_MISSING_INDENT,
+ }
+ }
+ }
+ }
+
+ Some(Self::Item {
+ kind,
+ text,
+ range: {
+ let Range { start, end } = self.inner.span();
+
+ TextRange::new(
+ TextSize::try_from(start).unwrap(),
+ TextSize::try_from(end).unwrap(),
+ )
+ },
+ })
+ }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct Lexeme<'i> {
+ pub kind: SyntaxKind,
+ pub text: &'i str,
+ pub range: TextRange,
+}
+
+pub fn lex(input: &str) -> Vec<Lexeme<'_>> {
+ Lexer::new(input).collect()
+}
crates/jrsonnet-rowan-parser/src/lib.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/lib.rs
@@ -0,0 +1,71 @@
+#![deny(unused_must_use)]
+
+use event::Sink;
+use generated::nodes::{SourceFile, Trivia};
+use lex::lex;
+use parser::{LocatedSyntaxError, Parser};
+pub use rowan;
+
+mod ast;
+mod event;
+mod generated;
+mod language;
+mod lex;
+mod marker;
+mod parser;
+mod precedence;
+mod string_block;
+mod tests;
+mod token_set;
+
+pub use ast::{AstChildren, AstNode, AstToken};
+pub use generated::{nodes, syntax_kinds::SyntaxKind};
+pub use language::*;
+pub use token_set::SyntaxKindSet;
+
+use self::{
+ ast::support,
+ generated::nodes::{Expr, ExprBinary, ExprObjExtend},
+};
+
+pub fn parse(input: &str) -> (SourceFile, Vec<LocatedSyntaxError>) {
+ let lexemes = lex(input);
+ let kinds = lexemes
+ .iter()
+ .map(|l| l.kind)
+ .filter(|k| !Trivia::can_cast(*k))
+ .collect();
+ let parser = Parser::new(kinds);
+ let events = parser.parse();
+ let sink = Sink::new(events, &lexemes);
+
+ let parse = sink.finish();
+ (
+ SourceFile {
+ syntax: parse.syntax(),
+ },
+ parse.errors,
+ )
+}
+impl ExprBinary {
+ pub fn lhs_work(&self) -> Option<Expr> {
+ support::child(self.syntax())
+ }
+ pub fn rhs_work(&self) -> Option<Expr> {
+ let mut children = support::children(self.syntax());
+ // skip lhs
+ children.next()?;
+ children.next()
+ }
+}
+impl ExprObjExtend {
+ pub fn lhs_work(&self) -> Option<Expr> {
+ support::child(self.syntax())
+ }
+ pub fn rhs_work(&self) -> Option<Expr> {
+ let mut children = support::children(self.syntax());
+ // skip lhs
+ children.next()?;
+ children.next()
+ }
+}
crates/jrsonnet-rowan-parser/src/marker.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/marker.rs
@@ -0,0 +1,187 @@
+use std::num::NonZeroUsize;
+
+use drop_bomb::DropBomb;
+
+use crate::{
+ event::Event,
+ parser::{ExpectedSyntax, Parser, SyntaxError},
+ SyntaxKind,
+};
+
+pub struct Ranger {
+ pub pos: usize,
+}
+impl Ranger {
+ pub fn finish(self, p: &Parser) -> FinishedRanger {
+ FinishedRanger {
+ start_token: self.pos,
+ end_token: self.pos.max(p.offset.saturating_sub(1)),
+ }
+ }
+}
+
+pub struct FinishedRanger {
+ pub start_token: usize,
+ pub end_token: usize,
+}
+impl FinishedRanger {
+ #[allow(dead_code)]
+ pub fn had_error_since(&self, p: &Parser) -> bool {
+ p.last_error_token >= self.start_token
+ }
+}
+
+#[must_use]
+pub struct Marker {
+ pub start_event_idx: usize,
+ bomb: DropBomb,
+}
+impl Marker {
+ pub fn new(pos: usize) -> Self {
+ Self {
+ start_event_idx: pos,
+ bomb: DropBomb::new("marked dropped while not completed"),
+ }
+ }
+ fn complete_raw(
+ mut self,
+ p: &mut Parser,
+ kind: SyntaxKind,
+ error: Option<SyntaxError>,
+ ) -> CompletedMarker {
+ self.bomb.defuse();
+ assert!(
+ !kind.is_enum(),
+ "{kind:?} is a enum kind, you should use variant kinds instead"
+ );
+ // TODO: is_lexer should return true if enum variant has #[regex]/#[token] over it, or it is defined as lexer error explicitly
+ // debug_assert!(
+ // !kind.is_lexer(),
+ // "{kind:?} should be only emitted by lexer, not used directly"
+ // );
+ let event_at_pos = &mut p.events[self.start_event_idx];
+ assert!(matches!(event_at_pos, Event::Pending));
+
+ *event_at_pos = Event::Start {
+ kind,
+ forward_parent: None,
+ };
+
+ let finish_event_idx = p.events.len();
+ p.events.push(Event::Finish {
+ wrapper: None,
+ error: error.map(Box::new),
+ });
+ p.entered -= 1;
+ p.clear_outdated_hints();
+ CompletedMarker {
+ start_event_idx: self.start_event_idx,
+ finish_event_idx,
+ }
+ }
+ pub fn complete(mut self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
+ self.complete_raw(p, kind, None)
+ }
+ pub fn complete_error(mut self, p: &mut Parser, msg: impl AsRef<str>) -> CompletedMarker {
+ self.complete_raw(
+ p,
+ SyntaxKind::ERROR_CUSTOM,
+ Some(SyntaxError::Custom {
+ error: msg.as_ref().to_owned(),
+ }),
+ )
+ }
+ pub fn complete_missing(mut self, p: &mut Parser, expected: ExpectedSyntax) -> CompletedMarker {
+ self.complete_raw(
+ p,
+ SyntaxKind::ERROR_MISSING_TOKEN,
+ Some(SyntaxError::Missing { expected }),
+ )
+ }
+ pub fn complete_unexpected(
+ mut self,
+ p: &mut Parser,
+ expected: ExpectedSyntax,
+ found: SyntaxKind,
+ ) -> CompletedMarker {
+ self.complete_raw(
+ p,
+ SyntaxKind::ERROR_UNEXPECTED_TOKEN,
+ Some(SyntaxError::Unexpected { expected, found }),
+ )
+ }
+
+ pub fn forget(mut self, p: &mut Parser) {
+ self.bomb.defuse();
+ let event_at_pos = &mut p.events[self.start_event_idx];
+ assert!(matches!(event_at_pos, Event::Pending));
+
+ *event_at_pos = Event::Noop;
+ p.entered -= 1;
+ p.clear_outdated_hints();
+ }
+}
+pub struct CompletedMarker {
+ start_event_idx: usize,
+ finish_event_idx: usize,
+}
+impl CompletedMarker {
+ pub(super) fn precede(self, p: &mut Parser) -> Marker {
+ let new_m = p.start();
+ match &mut p.events[self.start_event_idx] {
+ Event::Start { forward_parent, .. } => {
+ *forward_parent = Some(
+ NonZeroUsize::new(new_m.start_event_idx - self.start_event_idx).expect("!= 0"),
+ );
+ }
+ _ => unreachable!(),
+ }
+
+ new_m
+ }
+ /// Create new node around existing marker, not counting anything that comes after it
+ fn wrap_raw(
+ self,
+ p: &mut Parser,
+ kind: SyntaxKind,
+ error: Option<SyntaxError>,
+ ) -> CompletedMarker {
+ let new_m = p.start();
+ match &mut p.events[self.start_event_idx] {
+ Event::Start { forward_parent, .. } => {
+ *forward_parent = Some(
+ NonZeroUsize::new(new_m.start_event_idx - self.start_event_idx).expect("!= 0"),
+ );
+ }
+ _ => unreachable!(),
+ }
+
+ let completed = new_m.complete_raw(p, kind, error);
+
+ match &mut p.events[self.finish_event_idx] {
+ Event::Finish {
+ wrapper,
+ error: _error,
+ } => {
+ *wrapper = Some(
+ NonZeroUsize::new(completed.finish_event_idx - self.finish_event_idx)
+ .expect("!= 0"),
+ );
+ }
+ _ => unreachable!(),
+ }
+ completed
+ }
+ pub fn wrap(self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
+ self.wrap_raw(p, kind, None)
+ }
+ pub fn wrap_error(self, p: &mut Parser, msg: impl AsRef<str>) -> CompletedMarker {
+ self.wrap_raw(
+ p,
+ SyntaxKind::ERROR_CUSTOM,
+ Some(SyntaxError::Custom {
+ error: msg.as_ref().to_owned(),
+ }),
+ )
+ }
+}
crates/jrsonnet-rowan-parser/src/parser.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/parser.rs
@@ -0,0 +1,940 @@
+use std::{cell::Cell, fmt, rc::Rc};
+
+use miette::{LabeledSpan, SourceOffset, SourceSpan};
+use rowan::{GreenNode, TextRange};
+
+use crate::{
+ event::Event,
+ marker::{CompletedMarker, Marker, Ranger},
+ nodes::{BinaryOperatorKind, Literal, Number, Text, UnaryOperatorKind},
+ token_set::SyntaxKindSet,
+ AstToken, SyntaxKind,
+ SyntaxKind::*,
+ SyntaxNode, T, TS,
+};
+
+pub struct Parse {
+ pub green_node: GreenNode,
+ pub errors: Vec<LocatedSyntaxError>,
+}
+
+pub struct Parser {
+ // TODO: remove all trivia before feeding to parser?
+ kinds: Vec<SyntaxKind>,
+ pub offset: usize,
+ pub events: Vec<Event>,
+ pub entered: u32,
+ pub hints: Vec<(u32, TextRange, String)>,
+ pub last_error_token: usize,
+ expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,
+ steps: Cell<u64>,
+}
+
+#[derive(Clone, Debug)]
+pub enum SyntaxError {
+ Unexpected {
+ expected: ExpectedSyntax,
+ found: SyntaxKind,
+ },
+ Missing {
+ expected: ExpectedSyntax,
+ },
+ Custom {
+ error: String,
+ },
+ Hint {
+ error: String,
+ },
+}
+
+#[derive(Debug)]
+pub struct LocatedSyntaxError {
+ pub error: SyntaxError,
+ pub range: TextRange,
+}
+
+impl From<LocatedSyntaxError> for LabeledSpan {
+ fn from(val: LocatedSyntaxError) -> Self {
+ let span = SourceSpan::new(
+ SourceOffset::from(usize::from(val.range.start())),
+ SourceOffset::from(usize::from(val.range.end() - val.range.start())),
+ );
+ dbg!(&val);
+ match val.error {
+ SyntaxError::Unexpected { expected, found } => LabeledSpan::new_with_span(
+ Some(format!("expected {expected}, found {found:?}")),
+ span,
+ ),
+ SyntaxError::Missing { expected } => {
+ LabeledSpan::new_with_span(Some(format!("missing {expected}")), span)
+ }
+ SyntaxError::Custom { error } | SyntaxError::Hint { error } => {
+ LabeledSpan::new_with_span(Some(error), span)
+ }
+ }
+ }
+}
+
+impl Parser {
+ pub fn new(kinds: Vec<SyntaxKind>) -> Self {
+ Self {
+ kinds,
+ offset: 0,
+ events: vec![],
+ entered: 0,
+ last_error_token: 0,
+ hints: vec![],
+ expected_syntax_tracking_state: Rc::new(Cell::new(ExpectedSyntax::Unnamed(TS![]))),
+ steps: Cell::new(0),
+ }
+ }
+ pub fn clear_outdated_hints(&mut self) {
+ let amount = self
+ .hints
+ .iter()
+ .rev()
+ .take_while(|h| h.0 > self.entered)
+ .count();
+ self.hints.truncate(self.hints.len() - amount)
+ }
+ fn clear_expected_syntaxes(&mut self) {
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Unnamed(TS![]));
+ }
+ pub fn start(&mut self) -> Marker {
+ let start_event_idx = self.events.len();
+ self.events.push(Event::Pending);
+ self.entered += 1;
+ Marker::new(start_event_idx)
+ }
+ pub fn start_ranger(&mut self) -> Ranger {
+ let pos = self.offset;
+ Ranger { pos }
+ }
+ pub fn parse(mut self) -> Vec<Event> {
+ let m = self.start();
+ expr(&mut self);
+ if !self.at(EOF) {
+ let m = self.start();
+ while !self.at(EOF) {
+ self.bump();
+ }
+ m.complete_error(&mut self, "unexpected tokens after end");
+ }
+ m.complete(&mut self, SOURCE_FILE);
+
+ self.events
+ }
+
+ pub(crate) fn expect(&mut self, kind: SyntaxKind) {
+ self.expect_with_recovery_set(kind, TS![])
+ }
+
+ pub(crate) fn expect_with_recovery_set(
+ &mut self,
+ kind: SyntaxKind,
+ recovery_set: SyntaxKindSet,
+ ) {
+ if self.at(kind) {
+ if kind != EOF {
+ self.bump();
+ }
+ } else {
+ self.error_with_recovery_set(recovery_set);
+ }
+ }
+
+ pub(crate) fn expect_with_no_skip(&mut self, kind: SyntaxKind) {
+ if self.at(kind) {
+ self.bump();
+ } else {
+ self.error_with_no_skip();
+ }
+ }
+ pub fn error_with_no_skip(&mut self) -> CompletedMarker {
+ self.error_with_recovery_set(SyntaxKindSet::ALL)
+ }
+
+ pub fn error_with_recovery_set(&mut self, recovery_set: SyntaxKindSet) -> CompletedMarker {
+ let expected = self.expected_syntax_tracking_state.get();
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Unnamed(TS![]));
+
+ if self.at_end() || self.at_ts(recovery_set) {
+ let m = self.start();
+ return m.complete_missing(self, expected);
+ }
+
+ let current_token = self.current();
+
+ self.last_error_token = self.offset;
+
+ let m = self.start();
+ self.bump();
+ let m = m.complete_unexpected(self, expected, current_token);
+ self.clear_expected_syntaxes();
+ m
+ }
+ fn bump_assert(&mut self, kind: SyntaxKind) {
+ assert!(self.at(kind), "expected {:?}", kind);
+ self.bump_remap(self.current());
+ }
+ fn bump(&mut self) {
+ self.bump_remap(self.current());
+ }
+ fn bump_remap(&mut self, kind: SyntaxKind) {
+ assert_ne!(self.offset, self.kinds.len(), "already at end");
+ self.events.push(Event::Token { kind });
+ self.offset += 1;
+ self.clear_expected_syntaxes();
+ }
+ fn step(&self) {
+ use std::fmt::Write;
+ let steps = self.steps.get();
+ if steps >= 15000000 {
+ let mut out = "seems like parsing is stuck".to_owned();
+ {
+ let last = 20;
+ write!(out, "\n\nLast {} events:", last).unwrap();
+ for (i, event) in self
+ .events
+ .iter()
+ .skip(self.events.len().saturating_sub(last))
+ .enumerate()
+ {
+ write!(out, "\n{i}. {event:?}").unwrap();
+ }
+ }
+ {
+ let next = 20;
+ write!(out, "\n\nNext {next} tokens:").unwrap();
+ for (i, tok) in self.kinds.iter().skip(self.offset).take(next).enumerate() {
+ write!(out, "\n{i}. {tok:?}").unwrap();
+ }
+ }
+ panic!("{out}")
+ }
+ self.steps.set(steps + 1);
+ }
+ fn nth(&self, i: usize) -> SyntaxKind {
+ self.step();
+ let mut offset = self.offset;
+ for _ in 0..i {
+ offset += 1;
+ }
+ self.kinds.get(offset).copied().unwrap_or(EOF)
+ }
+ fn current(&self) -> SyntaxKind {
+ self.nth(0)
+ }
+ #[must_use]
+ pub(crate) fn expected_syntax_name(&mut self, name: &'static str) -> ExpectedSyntaxGuard {
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Named(name));
+
+ ExpectedSyntaxGuard::new(Rc::clone(&self.expected_syntax_tracking_state))
+ }
+ pub fn at(&mut self, kind: SyntaxKind) -> bool {
+ self.nth_at(0, kind)
+ }
+ pub fn nth_at(&mut self, n: usize, kind: SyntaxKind) -> bool {
+ if n == 0 {
+ if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {
+ let kinds = kinds.with(kind);
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Unnamed(kinds))
+ }
+ }
+ self.nth(n) == kind
+ }
+ pub fn at_ts(&mut self, set: SyntaxKindSet) -> bool {
+ if let ExpectedSyntax::Unnamed(kinds) = self.expected_syntax_tracking_state.get() {
+ let kinds = kinds.union(set);
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Unnamed(kinds))
+ }
+ set.contains(self.current())
+ }
+ pub fn at_end(&mut self) -> bool {
+ self.at(EOF)
+ }
+}
+pub(crate) struct ExpectedSyntaxGuard {
+ expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>,
+}
+
+impl ExpectedSyntaxGuard {
+ fn new(expected_syntax_tracking_state: Rc<Cell<ExpectedSyntax>>) -> Self {
+ Self {
+ expected_syntax_tracking_state,
+ }
+ }
+}
+
+impl Drop for ExpectedSyntaxGuard {
+ fn drop(&mut self) {
+ self.expected_syntax_tracking_state
+ .set(ExpectedSyntax::Unnamed(TS![]));
+ }
+}
+
+#[derive(Clone, Debug, Copy)]
+pub enum ExpectedSyntax {
+ Named(&'static str),
+ Unnamed(SyntaxKindSet),
+}
+impl fmt::Display for ExpectedSyntax {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ExpectedSyntax::Named(name) => write!(f, "{name}"),
+ ExpectedSyntax::Unnamed(set) => write!(f, "{set}"),
+ }
+ }
+}
+
+fn expr(p: &mut Parser) -> CompletedMarker {
+ let m = p.start();
+ while p.at(T![local]) || p.at(T![assert]) {
+ let m = p.start();
+
+ if p.at(T![local]) {
+ p.bump();
+ loop {
+ if p.at(T![;]) {
+ p.bump();
+ break;
+ }
+ bind(p);
+
+ if p.at(T![,]) {
+ p.bump();
+ continue;
+ }
+ p.expect(T![;]);
+ break;
+ }
+ m.complete(p, STMT_LOCAL);
+ } else {
+ assertion(p);
+ p.expect(T![;]);
+ m.complete(p, STMT_ASSERT);
+ }
+ }
+ match expr_binding_power(p, 0) {
+ Ok(m) => m,
+ Err(m) => m,
+ };
+ m.complete(p, EXPR)
+}
+fn expr_binding_power(
+ p: &mut Parser,
+ minimum_binding_power: u8,
+) -> Result<CompletedMarker, CompletedMarker> {
+ let mut lhs = lhs(p)?;
+
+ while let Some(op) = BinaryOperatorKind::cast(p.current())
+ .or_else(|| p.at(T!['{']).then_some(BinaryOperatorKind::MetaObjectApply))
+ {
+ let (left_binding_power, right_binding_power) = op.binding_power();
+ if left_binding_power < minimum_binding_power {
+ break;
+ }
+
+ // Object apply is not a real operator, we dont have something to bump
+ if op != BinaryOperatorKind::MetaObjectApply {
+ p.bump();
+ }
+
+ let m = lhs.wrap(p, EXPR).precede(p);
+ let parsed_rhs = expr_binding_power(p, right_binding_power)
+ .map(|v| v.precede(p).complete(p, EXPR))
+ .is_ok();
+ lhs = m.complete(
+ p,
+ if op == BinaryOperatorKind::MetaObjectApply {
+ EXPR_OBJ_EXTEND
+ } else {
+ EXPR_BINARY
+ },
+ );
+
+ if !parsed_rhs {
+ break;
+ }
+ }
+ Ok(lhs)
+}
+
+const COMPSPEC: SyntaxKindSet = TS![for if];
+fn compspec(p: &mut Parser) -> CompletedMarker {
+ assert!(p.at_ts(COMPSPEC));
+ if p.at(T![for]) {
+ let m = p.start();
+ p.bump();
+ destruct(p);
+ p.expect(T![in]);
+ expr(p);
+ m.complete(p, FOR_SPEC)
+ } else if p.at(T![if]) {
+ let m = p.start();
+ p.bump();
+ expr(p);
+ m.complete(p, IF_SPEC)
+ } else {
+ unreachable!()
+ }
+}
+
+fn comma(p: &mut Parser) -> bool {
+ comma_with_alternatives(p, TS![])
+}
+fn comma_with_alternatives(p: &mut Parser, set: SyntaxKindSet) -> bool {
+ if p.at(T![,]) {
+ p.bump();
+ true
+ } else if p.at_ts(set) {
+ let _ex = p.expected_syntax_name("comma");
+ p.expect_with_recovery_set(T![,], TS![]);
+ true
+ } else {
+ false
+ }
+}
+
+fn field_name(p: &mut Parser) {
+ let _e = p.expected_syntax_name("field name");
+ let m = p.start();
+ if p.at(T!['[']) {
+ p.bump();
+ expr(p);
+ p.expect(T![']']);
+ m.complete(p, FIELD_NAME_DYNAMIC);
+ } else if p.at(IDENT) {
+ name(p);
+ m.complete(p, FIELD_NAME_FIXED);
+ } else if Text::can_cast(p.current()) {
+ text(p);
+ m.complete(p, FIELD_NAME_FIXED);
+ } else {
+ m.forget(p);
+ p.error_with_recovery_set(TS![; : :: ::: '(']);
+ }
+}
+fn visibility(p: &mut Parser) {
+ if p.at_ts(TS![: :: :::]) {
+ p.bump()
+ } else {
+ p.error_with_recovery_set(TS![=]);
+ }
+}
+fn assertion(p: &mut Parser) {
+ let m = p.start();
+ p.bump_assert(T![assert]);
+ expr(p);
+ if p.at(T![:]) {
+ p.bump();
+ expr(p);
+ }
+ m.complete(p, ASSERTION);
+}
+fn object(p: &mut Parser) -> CompletedMarker {
+ let m_t = p.start();
+ let m = p.start();
+ p.bump_assert(T!['{']);
+
+ let mut elems = 0;
+ let mut compspecs = Vec::new();
+ let mut asserts = Vec::new();
+ loop {
+ if p.at(T!['}']) {
+ p.bump();
+ break;
+ }
+ if p.at_ts(COMPSPEC) {
+ if elems == 0 {
+ let m = p.start();
+ m.complete_missing(p, ExpectedSyntax::Named("field definition"));
+ }
+ while p.at_ts(COMPSPEC) {
+ compspecs.push(compspec(p));
+ }
+ if comma_with_alternatives(p, TS![;]) {
+ continue;
+ }
+ p.expect(R_BRACE);
+ break;
+ }
+ let m = p.start();
+ if p.at(T![local]) {
+ obj_local(p);
+ m.complete(p, MEMBER_BIND_STMT);
+ } else if p.at(T![assert]) {
+ assertion(p);
+ asserts.push(m.complete(p, MEMBER_ASSERT_STMT));
+ } else {
+ field_name(p);
+ if p.at(T![+]) {
+ p.bump();
+ }
+ let params = if p.at(T!['(']) {
+ params_desc(p);
+ visibility(p);
+ expr(p);
+ true
+ } else if p.at_ts(TS![: :: :::]) && p.nth_at(1, T![function]) {
+ visibility(p);
+ p.bump_assert(T![function]);
+ params_desc(p);
+ expr(p);
+ true
+ } else {
+ visibility(p);
+ expr(p);
+ false
+ };
+ elems += 1;
+
+ if params {
+ m.complete(p, MEMBER_FIELD_METHOD)
+ } else {
+ m.complete(p, MEMBER_FIELD_NORMAL)
+ };
+ };
+ while p.at_ts(COMPSPEC) {
+ compspecs.push(compspec(p));
+ }
+ if comma_with_alternatives(p, TS![;]) {
+ continue;
+ }
+ p.expect(R_BRACE);
+ break;
+ }
+
+ if elems > 1 && !compspecs.is_empty() {
+ for errored in compspecs {
+ errored.wrap_error(
+ p,
+ "compspec may only be used if there is only one object element",
+ );
+ }
+ m.complete(p, OBJ_BODY_MEMBER_LIST);
+ } else if !compspecs.is_empty() {
+ for errored in asserts {
+ errored.wrap_error(p, "asserts can't be used in object comprehensions");
+ }
+ m.complete(p, OBJ_BODY_COMP);
+ } else {
+ m.complete(p, OBJ_BODY_MEMBER_LIST);
+ }
+ m_t.complete(p, EXPR_OBJECT)
+}
+fn param(p: &mut Parser) {
+ let m = p.start();
+ destruct(p);
+ if p.at(T![=]) {
+ p.bump();
+ expr(p);
+ }
+ m.complete(p, PARAM);
+}
+fn params_desc(p: &mut Parser) -> CompletedMarker {
+ let m = p.start();
+ p.bump_assert(T!['(']);
+
+ loop {
+ if p.at(T![')']) {
+ p.bump();
+ break;
+ }
+ param(p);
+ if comma(p) {
+ continue;
+ }
+ p.expect(T![')']);
+ break;
+ }
+
+ m.complete(p, PARAMS_DESC)
+}
+fn args_desc(p: &mut Parser) {
+ let m = p.start();
+ p.bump_assert(T!['(']);
+
+ let started_named = Cell::new(false);
+ let mut unnamed_after_named = Vec::new();
+
+ loop {
+ if p.at(T![')']) {
+ break;
+ }
+
+ let m = p.start();
+ if p.at(IDENT) && p.nth_at(1, T![=]) {
+ name(p);
+ p.bump();
+ expr(p);
+ m.complete(p, ARG);
+ started_named.set(true);
+ } else {
+ expr(p);
+ let arg = m.complete(p, ARG);
+ if started_named.get() {
+ unnamed_after_named.push(arg)
+ }
+ }
+ if comma(p) {
+ continue;
+ }
+ break;
+ }
+ p.expect(T![')']);
+ if p.at(T![tailstrict]) {
+ p.bump()
+ }
+
+ for errored in unnamed_after_named {
+ errored.wrap_error(p, "can't use positional arguments after named");
+ }
+
+ m.complete(p, ARGS_DESC);
+}
+
+fn array(p: &mut Parser) -> CompletedMarker {
+ // Start the list node
+ let m = p.start();
+ p.bump_assert(T!['[']);
+
+ let mut compspecs = Vec::new();
+ let mut elems = 0;
+
+ loop {
+ if p.at(T![']']) {
+ p.bump();
+ break;
+ }
+ if elems != 0 && p.at_ts(COMPSPEC) {
+ while p.at_ts(COMPSPEC) {
+ compspecs.push(compspec(p));
+ }
+ if comma(p) {
+ continue;
+ }
+ p.expect(T![']']);
+ break;
+ }
+ expr(p);
+ elems += 1;
+ while p.at_ts(COMPSPEC) {
+ compspecs.push(compspec(p));
+ }
+ if comma(p) {
+ continue;
+ }
+ p.expect(T![']']);
+ break;
+ }
+
+ if elems > 1 && !compspecs.is_empty() {
+ for spec in compspecs {
+ spec.wrap_error(
+ p,
+ "compspec may only be used if there is only one array element",
+ );
+ }
+
+ m.complete(p, EXPR_ARRAY)
+ } else if !compspecs.is_empty() {
+ m.complete(p, EXPR_ARRAY_COMP)
+ } else {
+ m.complete(p, EXPR_ARRAY)
+ }
+}
+/// Returns true if it was slice, false if just index
+#[must_use]
+fn slice_desc_or_index(p: &mut Parser) -> bool {
+ let m = p.start();
+ p.bump();
+ // TODO: do not treat :, ::, ::: as full tokens?
+ // Start
+ if !p.at(T![:]) && !p.at(T![::]) {
+ expr(p);
+ }
+ if p.at(T![:]) {
+ p.bump();
+ // End
+ if !p.at(T![']']) {
+ expr(p).wrap(p, SLICE_DESC_END);
+ }
+ if p.at(T![:]) {
+ p.bump();
+ // Step
+ if !p.at(T![']']) {
+ expr(p).wrap(p, SLICE_DESC_STEP);
+ }
+ }
+ } else if p.at(T![::]) {
+ p.bump();
+ // End
+ if !p.at(T![']']) {
+ expr(p).wrap(p, SLICE_DESC_END);
+ }
+ } else {
+ // It was not a slice
+ p.expect(T![']']);
+ m.forget(p);
+ return false;
+ }
+ p.expect(T![']']);
+ m.complete(p, SLICE_DESC);
+ true
+}
+
+fn suffix(p: &mut Parser) {
+ loop {
+ let start = p.start();
+ let _marker: CompletedMarker = if p.at(T![?]) {
+ p.bump();
+ p.expect(T![.]);
+ if p.at(IDENT) {
+ name(p);
+ start.complete(p, SUFFIX_INDEX)
+ } else if p.at(T!['[']) {
+ p.bump();
+ expr(p);
+ p.expect(T![']']);
+ start.complete(p, SUFFIX_INDEX_EXPR)
+ } else {
+ start.complete_missing(p, ExpectedSyntax::Named("index"))
+ }
+ } else if p.at(T![.]) {
+ p.bump();
+ name(p);
+ start.complete(p, SUFFIX_INDEX)
+ } else if p.at(T!['[']) {
+ if slice_desc_or_index(p) {
+ start.complete(p, SUFFIX_SLICE)
+ } else {
+ start.complete(p, SUFFIX_INDEX_EXPR)
+ }
+ } else if p.at(T!['(']) {
+ args_desc(p);
+ start.complete(p, SUFFIX_APPLY)
+ } else {
+ start.forget(p);
+ break;
+ };
+ }
+}
+
+fn lhs(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {
+ let lhs = lhs_basic(p)?;
+
+ suffix(p);
+
+ Ok(lhs)
+}
+fn name(p: &mut Parser) {
+ let m = p.start();
+ p.expect(IDENT);
+ m.complete(p, NAME);
+}
+fn destruct_rest(p: &mut Parser) {
+ let m = p.start();
+ p.bump_assert(T![...]);
+ if p.at(IDENT) {
+ p.bump()
+ }
+ m.complete(p, DESTRUCT_REST);
+}
+fn destruct_object_field(p: &mut Parser) {
+ let m = p.start();
+ name(p);
+ if p.at(T![:]) {
+ p.bump();
+ destruct(p);
+ };
+ if p.at(T![=]) {
+ p.bump();
+ expr(p);
+ }
+ m.complete(p, DESTRUCT_OBJECT_FIELD);
+}
+fn obj_local(p: &mut Parser) {
+ let m = p.start();
+ p.bump_assert(T![local]);
+ bind(p);
+ m.complete(p, OBJ_LOCAL);
+}
+fn destruct(p: &mut Parser) -> CompletedMarker {
+ let m = p.start();
+ let _ex = p.expected_syntax_name("destruction specifier");
+ if p.at(T![?]) {
+ p.bump();
+ m.complete(p, DESTRUCT_SKIP)
+ } else if p.at(T!['[']) {
+ p.bump();
+ let mut had_rest = false;
+ loop {
+ if p.at(T![']']) {
+ p.bump();
+ break;
+ } else if p.at(T![...]) {
+ let m_err = p.start_ranger();
+ destruct_rest(p);
+ // if had_rest {
+ // p.custom_error(m_err.finish(p), "only one rest can be present in array");
+ // }
+ had_rest = true;
+ } else {
+ destruct(p);
+ }
+ if p.at(T![,]) {
+ p.bump();
+ continue;
+ }
+ p.expect(T![']']);
+ break;
+ }
+ m.complete(p, DESTRUCT_ARRAY)
+ } else if p.at(T!['{']) {
+ p.bump();
+ let mut had_rest = false;
+ loop {
+ if p.at(T!['}']) {
+ p.bump();
+ break;
+ } else if p.at(T![...]) {
+ let m_err = p.start_ranger();
+ destruct_rest(p);
+ // if had_rest {
+ // p.custom_error(m_err.finish(p), "only one rest can be present in object");
+ // }
+ had_rest = true;
+ } else {
+ if had_rest {
+ p.error_with_recovery_set(TS![]);
+ }
+ destruct_object_field(p);
+ }
+ if p.at(T![,]) {
+ p.bump();
+ continue;
+ }
+ p.expect(T!['}']);
+ break;
+ }
+ m.complete(p, DESTRUCT_OBJECT)
+ } else if p.at(IDENT) {
+ name(p);
+ m.complete(p, DESTRUCT_FULL)
+ } else {
+ m.forget(p);
+ p.error_with_recovery_set(TS![; , '}', '(', :])
+ }
+}
+fn bind(p: &mut Parser) {
+ let m = p.start();
+ if p.at(IDENT) && p.nth_at(1, T!['(']) {
+ name(p);
+ params_desc(p);
+ p.expect(T![=]);
+ expr(p);
+ m.complete(p, BIND_FUNCTION)
+ } else if p.at(IDENT) && p.nth_at(1, T![=]) && p.nth_at(2, T![function]) {
+ name(p);
+ p.expect(T![=]);
+ p.expect(T![function]);
+ params_desc(p);
+ expr(p);
+ m.complete(p, BIND_FUNCTION)
+ } else {
+ destruct(p);
+ p.expect(T![=]);
+ expr(p);
+ m.complete(p, BIND_DESTRUCT)
+ };
+}
+fn text(p: &mut Parser) {
+ assert!(Text::can_cast(p.current()));
+ p.bump();
+}
+fn number(p: &mut Parser) {
+ assert!(Number::can_cast(p.current()));
+ p.bump();
+}
+fn literal(p: &mut Parser) {
+ assert!(Literal::can_cast(p.current()));
+ p.bump();
+}
+fn lhs_basic(p: &mut Parser) -> Result<CompletedMarker, CompletedMarker> {
+ let _e = p.expected_syntax_name("expression");
+ Ok(if Literal::can_cast(p.current()) {
+ let m = p.start();
+ literal(p);
+ m.complete(p, EXPR_LITERAL)
+ } else if Text::can_cast(p.current()) {
+ let m = p.start();
+ text(p);
+ m.complete(p, EXPR_STRING)
+ } else if Number::can_cast(p.current()) {
+ let m = p.start();
+ number(p);
+ m.complete(p, EXPR_NUMBER)
+ } else if p.at(IDENT) {
+ let m = p.start();
+ name(p);
+ m.complete(p, EXPR_VAR)
+ } else if p.at(T![if]) {
+ let m = p.start();
+ p.bump();
+ expr(p);
+ p.expect(T![then]);
+ expr(p).wrap(p, TRUE_EXPR);
+ if p.at(T![else]) {
+ p.bump();
+ expr(p).wrap(p, FALSE_EXPR);
+ }
+ m.complete(p, EXPR_IF_THEN_ELSE)
+ } else if p.at(T!['[']) {
+ array(p)
+ } else if p.at(T!['{']) {
+ object(p)
+ } else if p.at(T![function]) {
+ let m = p.start();
+ p.bump();
+ params_desc(p);
+ expr(p);
+ m.complete(p, EXPR_FUNCTION)
+ } else if p.at(T![error]) {
+ let m = p.start();
+ p.bump();
+ expr(p);
+ m.complete(p, EXPR_ERROR)
+ } else if p.at(T![import]) || p.at(T![importstr]) || p.at(T![importbin]) {
+ let m = p.start();
+ p.bump();
+ text(p);
+ m.complete(p, EXPR_IMPORT)
+ } else if let Some(op) = UnaryOperatorKind::cast(p.current()) {
+ let ((), right_binding_power) = op.binding_power();
+
+ let m = p.start();
+ p.bump();
+ let _ = expr_binding_power(p, right_binding_power);
+ m.complete(p, EXPR_UNARY)
+ } else if p.at(T!['(']) {
+ let m = p.start();
+ p.bump();
+ expr(p);
+ p.expect(T![')']);
+ m.complete(p, EXPR_PARENED)
+ } else {
+ return Err(p.error_with_no_skip());
+ })
+}
+
+impl Parse {
+ pub fn syntax(&self) -> SyntaxNode {
+ SyntaxNode::new_root(self.green_node.clone())
+ }
+}
crates/jrsonnet-rowan-parser/src/precedence.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/precedence.rs
@@ -0,0 +1,31 @@
+use crate::nodes::{BinaryOperatorKind, UnaryOperatorKind};
+
+impl BinaryOperatorKind {
+ pub fn binding_power(&self) -> (u8, u8) {
+ match self {
+ Self::MetaObjectApply => (22, 23),
+ Self::Mul | Self::Div | Self::Modulo => (20, 21),
+ Self::Plus | Self::Minus => (18, 19),
+ Self::Lhs | Self::Rhs => (16, 17),
+ Self::Lt | Self::Gt | Self::Le | Self::Ge | Self::InKw => (14, 15),
+ Self::Eq | Self::Ne => (12, 13),
+ Self::BitAnd => (10, 11),
+ Self::BitXor => (8, 9),
+ Self::BitOr => (6, 7),
+ Self::And => (4, 5),
+ Self::NullCoaelse => (2, 3),
+ Self::Or => (2, 3),
+ Self::ErrorNoOperator => (0, 1),
+ }
+ }
+}
+
+impl UnaryOperatorKind {
+ pub fn binding_power(&self) -> ((), u8) {
+ match self {
+ Self::Minus => ((), 20),
+ Self::Not => ((), 20),
+ Self::BitNot => ((), 20),
+ }
+ }
+}
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec.snap
@@ -0,0 +1,41 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a for a in [1, 2, 3]]\n"
+---
+SOURCE_FILE@0..23
+ EXPR@0..22
+ EXPR_ARRAY_COMP@0..22
+ L_BRACK@0..1 "["
+ EXPR@1..2
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ WHITESPACE@2..3 " "
+ FOR_SPEC@3..21
+ FOR_KW@3..6 "for"
+ WHITESPACE@6..7 " "
+ DESTRUCT_FULL@7..8
+ NAME@7..8
+ IDENT@7..8 "a"
+ WHITESPACE@8..9 " "
+ IN_KW@9..11 "in"
+ WHITESPACE@11..12 " "
+ EXPR@12..21
+ EXPR_ARRAY@12..21
+ L_BRACK@12..13 "["
+ EXPR@13..14
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "1"
+ COMMA@14..15 ","
+ WHITESPACE@15..16 " "
+ EXPR@16..17
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "2"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ EXPR@19..20
+ EXPR_NUMBER@19..20
+ FLOAT@19..20 "3"
+ R_BRACK@20..21 "]"
+ R_BRACK@21..22 "]"
+ WHITESPACE@22..23 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_comma.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_comma.snap
@@ -0,0 +1,42 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a, for a in [1, 2, 3]]\n"
+---
+SOURCE_FILE@0..24
+ EXPR@0..23
+ EXPR_ARRAY_COMP@0..23
+ L_BRACK@0..1 "["
+ EXPR@1..2
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COMMA@2..3 ","
+ WHITESPACE@3..4 " "
+ FOR_SPEC@4..22
+ FOR_KW@4..7 "for"
+ WHITESPACE@7..8 " "
+ DESTRUCT_FULL@8..9
+ NAME@8..9
+ IDENT@8..9 "a"
+ WHITESPACE@9..10 " "
+ IN_KW@10..12 "in"
+ WHITESPACE@12..13 " "
+ EXPR@13..22
+ EXPR_ARRAY@13..22
+ L_BRACK@13..14 "["
+ EXPR@14..15
+ EXPR_NUMBER@14..15
+ FLOAT@14..15 "1"
+ COMMA@15..16 ","
+ WHITESPACE@16..17 " "
+ EXPR@17..18
+ EXPR_NUMBER@17..18
+ FLOAT@17..18 "2"
+ COMMA@18..19 ","
+ WHITESPACE@19..20 " "
+ EXPR@20..21
+ EXPR_NUMBER@20..21
+ FLOAT@20..21 "3"
+ R_BRACK@21..22 "]"
+ R_BRACK@22..23 "]"
+ WHITESPACE@23..24 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems.snap
@@ -0,0 +1,57 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a for a in [1, 2, 3], b]\n"
+---
+SOURCE_FILE@0..26
+ EXPR@0..25
+ EXPR_ARRAY@0..25
+ L_BRACK@0..1 "["
+ EXPR@1..2
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ WHITESPACE@2..3 " "
+ ERROR_CUSTOM@3..21
+ FOR_SPEC@3..21
+ FOR_KW@3..6 "for"
+ WHITESPACE@6..7 " "
+ DESTRUCT_FULL@7..8
+ NAME@7..8
+ IDENT@7..8 "a"
+ WHITESPACE@8..9 " "
+ IN_KW@9..11 "in"
+ WHITESPACE@11..12 " "
+ EXPR@12..21
+ EXPR_ARRAY@12..21
+ L_BRACK@12..13 "["
+ EXPR@13..14
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "1"
+ COMMA@14..15 ","
+ WHITESPACE@15..16 " "
+ EXPR@16..17
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "2"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ EXPR@19..20
+ EXPR_NUMBER@19..20
+ FLOAT@19..20 "3"
+ R_BRACK@20..21 "]"
+ COMMA@21..22 ","
+ WHITESPACE@22..23 " "
+ EXPR@23..24
+ EXPR_VAR@23..24
+ NAME@23..24
+ IDENT@23..24 "b"
+ R_BRACK@24..25 "]"
+ WHITESPACE@25..26 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 3..21 }
+===
+ x syntax error
+ ,----
+ 1 | [a for a in [1, 2, 3], b]
+ : ^^^^^^^^^|^^^^^^^^
+ : `-- compspec may only be used if there is only one array element
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_incompatible_with_multiple_elems_w.snap
@@ -0,0 +1,64 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a, b, for a in [1, 2, 3], c]\n"
+---
+SOURCE_FILE@0..30
+ EXPR@0..29
+ EXPR_ARRAY@0..29
+ L_BRACK@0..1 "["
+ EXPR@1..2
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COMMA@2..3 ","
+ WHITESPACE@3..4 " "
+ EXPR@4..5
+ EXPR_VAR@4..5
+ NAME@4..5
+ IDENT@4..5 "b"
+ COMMA@5..6 ","
+ WHITESPACE@6..7 " "
+ ERROR_CUSTOM@7..25
+ FOR_SPEC@7..25
+ FOR_KW@7..10 "for"
+ WHITESPACE@10..11 " "
+ DESTRUCT_FULL@11..12
+ NAME@11..12
+ IDENT@11..12 "a"
+ WHITESPACE@12..13 " "
+ IN_KW@13..15 "in"
+ WHITESPACE@15..16 " "
+ EXPR@16..25
+ EXPR_ARRAY@16..25
+ L_BRACK@16..17 "["
+ EXPR@17..18
+ EXPR_NUMBER@17..18
+ FLOAT@17..18 "1"
+ COMMA@18..19 ","
+ WHITESPACE@19..20 " "
+ EXPR@20..21
+ EXPR_NUMBER@20..21
+ FLOAT@20..21 "2"
+ COMMA@21..22 ","
+ WHITESPACE@22..23 " "
+ EXPR@23..24
+ EXPR_NUMBER@23..24
+ FLOAT@23..24 "3"
+ R_BRACK@24..25 "]"
+ COMMA@25..26 ","
+ WHITESPACE@26..27 " "
+ EXPR@27..28
+ EXPR_VAR@27..28
+ NAME@27..28
+ IDENT@27..28 "c"
+ R_BRACK@28..29 "]"
+ WHITESPACE@29..30 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one array element" }, range: 7..25 }
+===
+ x syntax error
+ ,----
+ 1 | [a, b, for a in [1, 2, 3], c]
+ : ^^^^^^^^^|^^^^^^^^
+ : `-- compspec may only be used if there is only one array element
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__arr_compspec_no_elems.snap
@@ -0,0 +1,47 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[for a in [1, 2, 3]]\n"
+---
+SOURCE_FILE@0..21
+ EXPR@0..20
+ EXPR_ARRAY_COMP@0..20
+ L_BRACK@0..1 "["
+ EXPR@1..1
+ ERROR_MISSING_TOKEN@1..1
+ FOR_SPEC@1..19
+ FOR_KW@1..4 "for"
+ WHITESPACE@4..5 " "
+ DESTRUCT_FULL@5..6
+ NAME@5..6
+ IDENT@5..6 "a"
+ WHITESPACE@6..7 " "
+ IN_KW@7..9 "in"
+ WHITESPACE@9..10 " "
+ EXPR@10..19
+ EXPR_ARRAY@10..19
+ L_BRACK@10..11 "["
+ EXPR@11..12
+ EXPR_NUMBER@11..12
+ FLOAT@11..12 "1"
+ COMMA@12..13 ","
+ WHITESPACE@13..14 " "
+ EXPR@14..15
+ EXPR_NUMBER@14..15
+ FLOAT@14..15 "2"
+ COMMA@15..16 ","
+ WHITESPACE@16..17 " "
+ EXPR@17..18
+ EXPR_NUMBER@17..18
+ FLOAT@17..18 "3"
+ R_BRACK@18..19 "]"
+ R_BRACK@19..20 "]"
+ WHITESPACE@20..21 "\n"
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
+===
+ x syntax error
+ ,----
+ 1 | [for a in [1, 2, 3]]
+ : ^
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__array_comp.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__array_comp.snap
@@ -0,0 +1,35 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a for a in [1, 2, 3]]\n"
+---
+SOURCE_FILE@0..23
+ EXPR_ARRAY_COMP@0..22
+ L_BRACK@0..1 "["
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ WHITESPACE@2..3 " "
+ FOR_SPEC@3..21
+ FOR_KW@3..6 "for"
+ WHITESPACE@6..7 " "
+ NAME@7..8
+ IDENT@7..8 "a"
+ WHITESPACE@8..9 " "
+ IN_KW@9..11 "in"
+ WHITESPACE@11..12 " "
+ EXPR_ARRAY@12..21
+ L_BRACK@12..13 "["
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "1"
+ COMMA@14..15 ","
+ WHITESPACE@15..16 " "
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "2"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ EXPR_NUMBER@19..20
+ FLOAT@19..20 "3"
+ R_BRACK@20..21 "]"
+ R_BRACK@21..22 "]"
+ WHITESPACE@22..23 "\n"
+
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__array_comp_incompatible_with_multiple_elems.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__array_comp_incompatible_with_multiple_elems.snap
@@ -0,0 +1,48 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "[a for a in [1, 2, 3], b]\n"
+---
+SOURCE_FILE@0..25
+ EXPR_ARRAY@0..25
+ L_BRACK@0..1 "["
+ EXPR_VAR@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ WHITESPACE@2..3 " "
+ FOR_SPEC@3..21
+ FOR_KW@3..6 "for"
+ WHITESPACE@6..7 " "
+ NAME@7..8
+ IDENT@7..8 "a"
+ WHITESPACE@8..9 " "
+ IN_KW@9..11 "in"
+ WHITESPACE@11..12 " "
+ EXPR_ARRAY@12..21
+ L_BRACK@12..13 "["
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "1"
+ COMMA@14..15 ","
+ WHITESPACE@15..16 " "
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "2"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ EXPR_NUMBER@19..20
+ FLOAT@19..20 "3"
+ R_BRACK@20..21 "]"
+ COMMA@21..22 ","
+ WHITESPACE@22..23 " "
+ EXPR_VAR@23..24
+ NAME@23..24
+ IDENT@23..24 "b"
+ R_BRACK@24..25 "]"
+===
+Custom { error: "compspec may only be used if there is only one array element", range: 3..21 }
+===
+ x syntax error
+ ,----
+ 1 | [a for a in [1, 2, 3], b]
+ : ^^^^^^^^^|^^^^^^^^
+ : `-- compspec may only be used if there is only one array element
+ `----
+
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__continue_after_total_failure.snap
@@ -0,0 +1,77 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local intr = $intrinsic(test);\n\nlocal a = 1, b = 2, c = a + b;\n\n[c]\n"
+---
+SOURCE_FILE@0..68
+ EXPR@0..29
+ STMT_LOCAL@0..23
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..14
+ DESTRUCT_FULL@6..10
+ NAME@6..10
+ IDENT@6..10 "intr"
+ WHITESPACE@10..11 " "
+ ASSIGN@11..12 "="
+ WHITESPACE@12..13 " "
+ EXPR@13..14
+ EXPR_LITERAL@13..14
+ DOLLAR@13..14 "$"
+ ERROR_UNEXPECTED_TOKEN@14..23
+ IDENT@14..23 "intrinsic"
+ EXPR_PARENED@23..29
+ L_PAREN@23..24 "("
+ EXPR@24..28
+ EXPR_VAR@24..28
+ NAME@24..28
+ IDENT@24..28 "test"
+ R_PAREN@28..29 ")"
+ ERROR_CUSTOM@29..67
+ SEMI@29..30 ";"
+ WHITESPACE@30..32 "\n\n"
+ LOCAL_KW@32..37 "local"
+ WHITESPACE@37..38 " "
+ IDENT@38..39 "a"
+ WHITESPACE@39..40 " "
+ ASSIGN@40..41 "="
+ WHITESPACE@41..42 " "
+ FLOAT@42..43 "1"
+ COMMA@43..44 ","
+ WHITESPACE@44..45 " "
+ IDENT@45..46 "b"
+ WHITESPACE@46..47 " "
+ ASSIGN@47..48 "="
+ WHITESPACE@48..49 " "
+ FLOAT@49..50 "2"
+ COMMA@50..51 ","
+ WHITESPACE@51..52 " "
+ IDENT@52..53 "c"
+ WHITESPACE@53..54 " "
+ ASSIGN@54..55 "="
+ WHITESPACE@55..56 " "
+ IDENT@56..57 "a"
+ WHITESPACE@57..58 " "
+ PLUS@58..59 "+"
+ WHITESPACE@59..60 " "
+ IDENT@60..61 "b"
+ SEMI@61..62 ";"
+ WHITESPACE@62..64 "\n\n"
+ L_BRACK@64..65 "["
+ IDENT@65..66 "c"
+ R_BRACK@66..67 "]"
+ WHITESPACE@67..68 "\n"
+===
+LocatedSyntaxError { error: Unexpected { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])), found: IDENT }, range: 14..23 }
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 29..67 }
+===
+ x syntax error
+ ,-[1:1]
+ 1 | ,-> local intr = $intrinsic(test);
+ : || ^^^^|^^^^
+ : || `-- expected L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK, found IDENT
+ 2 | |
+ 3 | | local a = 1, b = 2, c = a + b;
+ 4 | |
+ 5 | |-> [c]
+ : `---- unexpected tokens after end
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__destruct.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__destruct.snap
@@ -0,0 +1,265 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local [a, b, c] = arr;\nlocal [a, ...] = arr_rest;\nlocal [..., a] = rest_arr;\nlocal [...] = rest_in_arr;\nlocal [a, ...n] = arr_rest_n;\nlocal [...n, a] = rest_arr_n;\nlocal [...n] = rest_in_arr_n;\n\nlocal {a, b, c} = obj;\nlocal {a, b, c, ...} = obj_rest;\nlocal {a, b, c, ...n} = obj_rest_n;\n\nnull\n"
+---
+SOURCE_FILE@0..293
+ EXPR@0..292
+ STMT_LOCAL@0..22
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..21
+ DESTRUCT_ARRAY@6..15
+ L_BRACK@6..7 "["
+ DESTRUCT_FULL@7..8
+ NAME@7..8
+ IDENT@7..8 "a"
+ COMMA@8..9 ","
+ WHITESPACE@9..10 " "
+ DESTRUCT_FULL@10..11
+ NAME@10..11
+ IDENT@10..11 "b"
+ COMMA@11..12 ","
+ WHITESPACE@12..13 " "
+ DESTRUCT_FULL@13..14
+ NAME@13..14
+ IDENT@13..14 "c"
+ R_BRACK@14..15 "]"
+ WHITESPACE@15..16 " "
+ ASSIGN@16..17 "="
+ WHITESPACE@17..18 " "
+ EXPR@18..21
+ EXPR_VAR@18..21
+ NAME@18..21
+ IDENT@18..21 "arr"
+ SEMI@21..22 ";"
+ WHITESPACE@22..23 "\n"
+ STMT_LOCAL@23..49
+ LOCAL_KW@23..28 "local"
+ WHITESPACE@28..29 " "
+ BIND_DESTRUCT@29..48
+ DESTRUCT_ARRAY@29..37
+ L_BRACK@29..30 "["
+ DESTRUCT_FULL@30..31
+ NAME@30..31
+ IDENT@30..31 "a"
+ COMMA@31..32 ","
+ WHITESPACE@32..33 " "
+ DESTRUCT_REST@33..36
+ DOTDOTDOT@33..36 "..."
+ R_BRACK@36..37 "]"
+ WHITESPACE@37..38 " "
+ ASSIGN@38..39 "="
+ WHITESPACE@39..40 " "
+ EXPR@40..48
+ EXPR_VAR@40..48
+ NAME@40..48
+ IDENT@40..48 "arr_rest"
+ SEMI@48..49 ";"
+ WHITESPACE@49..50 "\n"
+ STMT_LOCAL@50..76
+ LOCAL_KW@50..55 "local"
+ WHITESPACE@55..56 " "
+ BIND_DESTRUCT@56..75
+ DESTRUCT_ARRAY@56..64
+ L_BRACK@56..57 "["
+ DESTRUCT_REST@57..60
+ DOTDOTDOT@57..60 "..."
+ COMMA@60..61 ","
+ WHITESPACE@61..62 " "
+ DESTRUCT_FULL@62..63
+ NAME@62..63
+ IDENT@62..63 "a"
+ R_BRACK@63..64 "]"
+ WHITESPACE@64..65 " "
+ ASSIGN@65..66 "="
+ WHITESPACE@66..67 " "
+ EXPR@67..75
+ EXPR_VAR@67..75
+ NAME@67..75
+ IDENT@67..75 "rest_arr"
+ SEMI@75..76 ";"
+ WHITESPACE@76..77 "\n"
+ STMT_LOCAL@77..103
+ LOCAL_KW@77..82 "local"
+ WHITESPACE@82..83 " "
+ BIND_DESTRUCT@83..102
+ DESTRUCT_ARRAY@83..88
+ L_BRACK@83..84 "["
+ DESTRUCT_REST@84..87
+ DOTDOTDOT@84..87 "..."
+ R_BRACK@87..88 "]"
+ WHITESPACE@88..89 " "
+ ASSIGN@89..90 "="
+ WHITESPACE@90..91 " "
+ EXPR@91..102
+ EXPR_VAR@91..102
+ NAME@91..102
+ IDENT@91..102 "rest_in_arr"
+ SEMI@102..103 ";"
+ WHITESPACE@103..104 "\n"
+ STMT_LOCAL@104..133
+ LOCAL_KW@104..109 "local"
+ WHITESPACE@109..110 " "
+ BIND_DESTRUCT@110..132
+ DESTRUCT_ARRAY@110..119
+ L_BRACK@110..111 "["
+ DESTRUCT_FULL@111..112
+ NAME@111..112
+ IDENT@111..112 "a"
+ COMMA@112..113 ","
+ WHITESPACE@113..114 " "
+ DESTRUCT_REST@114..118
+ DOTDOTDOT@114..117 "..."
+ IDENT@117..118 "n"
+ R_BRACK@118..119 "]"
+ WHITESPACE@119..120 " "
+ ASSIGN@120..121 "="
+ WHITESPACE@121..122 " "
+ EXPR@122..132
+ EXPR_VAR@122..132
+ NAME@122..132
+ IDENT@122..132 "arr_rest_n"
+ SEMI@132..133 ";"
+ WHITESPACE@133..134 "\n"
+ STMT_LOCAL@134..163
+ LOCAL_KW@134..139 "local"
+ WHITESPACE@139..140 " "
+ BIND_DESTRUCT@140..162
+ DESTRUCT_ARRAY@140..149
+ L_BRACK@140..141 "["
+ DESTRUCT_REST@141..145
+ DOTDOTDOT@141..144 "..."
+ IDENT@144..145 "n"
+ COMMA@145..146 ","
+ WHITESPACE@146..147 " "
+ DESTRUCT_FULL@147..148
+ NAME@147..148
+ IDENT@147..148 "a"
+ R_BRACK@148..149 "]"
+ WHITESPACE@149..150 " "
+ ASSIGN@150..151 "="
+ WHITESPACE@151..152 " "
+ EXPR@152..162
+ EXPR_VAR@152..162
+ NAME@152..162
+ IDENT@152..162 "rest_arr_n"
+ SEMI@162..163 ";"
+ WHITESPACE@163..164 "\n"
+ STMT_LOCAL@164..193
+ LOCAL_KW@164..169 "local"
+ WHITESPACE@169..170 " "
+ BIND_DESTRUCT@170..192
+ DESTRUCT_ARRAY@170..176
+ L_BRACK@170..171 "["
+ DESTRUCT_REST@171..175
+ DOTDOTDOT@171..174 "..."
+ IDENT@174..175 "n"
+ R_BRACK@175..176 "]"
+ WHITESPACE@176..177 " "
+ ASSIGN@177..178 "="
+ WHITESPACE@178..179 " "
+ EXPR@179..192
+ EXPR_VAR@179..192
+ NAME@179..192
+ IDENT@179..192 "rest_in_arr_n"
+ SEMI@192..193 ";"
+ WHITESPACE@193..195 "\n\n"
+ STMT_LOCAL@195..217
+ LOCAL_KW@195..200 "local"
+ WHITESPACE@200..201 " "
+ BIND_DESTRUCT@201..216
+ DESTRUCT_OBJECT@201..210
+ L_BRACE@201..202 "{"
+ DESTRUCT_OBJECT_FIELD@202..203
+ NAME@202..203
+ IDENT@202..203 "a"
+ COMMA@203..204 ","
+ WHITESPACE@204..205 " "
+ DESTRUCT_OBJECT_FIELD@205..206
+ NAME@205..206
+ IDENT@205..206 "b"
+ COMMA@206..207 ","
+ WHITESPACE@207..208 " "
+ DESTRUCT_OBJECT_FIELD@208..209
+ NAME@208..209
+ IDENT@208..209 "c"
+ R_BRACE@209..210 "}"
+ WHITESPACE@210..211 " "
+ ASSIGN@211..212 "="
+ WHITESPACE@212..213 " "
+ EXPR@213..216
+ EXPR_VAR@213..216
+ NAME@213..216
+ IDENT@213..216 "obj"
+ SEMI@216..217 ";"
+ WHITESPACE@217..218 "\n"
+ STMT_LOCAL@218..250
+ LOCAL_KW@218..223 "local"
+ WHITESPACE@223..224 " "
+ BIND_DESTRUCT@224..249
+ DESTRUCT_OBJECT@224..238
+ L_BRACE@224..225 "{"
+ DESTRUCT_OBJECT_FIELD@225..226
+ NAME@225..226
+ IDENT@225..226 "a"
+ COMMA@226..227 ","
+ WHITESPACE@227..228 " "
+ DESTRUCT_OBJECT_FIELD@228..229
+ NAME@228..229
+ IDENT@228..229 "b"
+ COMMA@229..230 ","
+ WHITESPACE@230..231 " "
+ DESTRUCT_OBJECT_FIELD@231..232
+ NAME@231..232
+ IDENT@231..232 "c"
+ COMMA@232..233 ","
+ WHITESPACE@233..234 " "
+ DESTRUCT_REST@234..237
+ DOTDOTDOT@234..237 "..."
+ R_BRACE@237..238 "}"
+ WHITESPACE@238..239 " "
+ ASSIGN@239..240 "="
+ WHITESPACE@240..241 " "
+ EXPR@241..249
+ EXPR_VAR@241..249
+ NAME@241..249
+ IDENT@241..249 "obj_rest"
+ SEMI@249..250 ";"
+ WHITESPACE@250..251 "\n"
+ STMT_LOCAL@251..286
+ LOCAL_KW@251..256 "local"
+ WHITESPACE@256..257 " "
+ BIND_DESTRUCT@257..285
+ DESTRUCT_OBJECT@257..272
+ L_BRACE@257..258 "{"
+ DESTRUCT_OBJECT_FIELD@258..259
+ NAME@258..259
+ IDENT@258..259 "a"
+ COMMA@259..260 ","
+ WHITESPACE@260..261 " "
+ DESTRUCT_OBJECT_FIELD@261..262
+ NAME@261..262
+ IDENT@261..262 "b"
+ COMMA@262..263 ","
+ WHITESPACE@263..264 " "
+ DESTRUCT_OBJECT_FIELD@264..265
+ NAME@264..265
+ IDENT@264..265 "c"
+ COMMA@265..266 ","
+ WHITESPACE@266..267 " "
+ DESTRUCT_REST@267..271
+ DOTDOTDOT@267..270 "..."
+ IDENT@270..271 "n"
+ R_BRACE@271..272 "}"
+ WHITESPACE@272..273 " "
+ ASSIGN@273..274 "="
+ WHITESPACE@274..275 " "
+ EXPR@275..285
+ EXPR_VAR@275..285
+ NAME@275..285
+ IDENT@275..285 "obj_rest_n"
+ SEMI@285..286 ";"
+ WHITESPACE@286..288 "\n\n"
+ EXPR_LITERAL@288..292
+ NULL_KW@288..292 "null"
+ WHITESPACE@292..293 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__empty.snap
@@ -0,0 +1,17 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: " "
+---
+SOURCE_FILE@0..1
+ WHITESPACE@0..1 " "
+ EXPR@1..1
+ ERROR_MISSING_TOKEN@1..1
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 1..1 }
+===
+ x syntax error
+ ,----
+ 1 |
+ : ^
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function.snap
@@ -0,0 +1,42 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "function(a, b = 1) a + b\n"
+---
+SOURCE_FILE@0..25
+ EXPR@0..24
+ EXPR_FUNCTION@0..24
+ FUNCTION_KW@0..8 "function"
+ PARAMS_DESC@8..18
+ L_PAREN@8..9 "("
+ PARAM@9..10
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ COMMA@10..11 ","
+ WHITESPACE@11..12 " "
+ PARAM@12..17
+ DESTRUCT_FULL@12..13
+ NAME@12..13
+ IDENT@12..13 "b"
+ WHITESPACE@13..14 " "
+ ASSIGN@14..15 "="
+ WHITESPACE@15..16 " "
+ EXPR@16..17
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "1"
+ R_PAREN@17..18 ")"
+ WHITESPACE@18..19 " "
+ EXPR@19..24
+ EXPR_BINARY@19..24
+ EXPR@19..20
+ EXPR_VAR@19..20
+ NAME@19..20
+ IDENT@19..20 "a"
+ WHITESPACE@20..21 " "
+ PLUS@21..22 "+"
+ WHITESPACE@22..23 " "
+ EXPR@23..24
+ EXPR_VAR@23..24
+ NAME@23..24
+ IDENT@23..24 "b"
+ WHITESPACE@24..25 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_body.snap
@@ -0,0 +1,33 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "function(a, b)\n"
+---
+SOURCE_FILE@0..15
+ EXPR@0..15
+ EXPR_FUNCTION@0..15
+ FUNCTION_KW@0..8 "function"
+ PARAMS_DESC@8..14
+ L_PAREN@8..9 "("
+ PARAM@9..10
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ COMMA@10..11 ","
+ WHITESPACE@11..12 " "
+ PARAM@12..13
+ DESTRUCT_FULL@12..13
+ NAME@12..13
+ IDENT@12..13 "b"
+ R_PAREN@13..14 ")"
+ WHITESPACE@14..15 "\n"
+ EXPR@15..15
+ ERROR_MISSING_TOKEN@15..15
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 15..15 }
+===
+ x syntax error
+ ,----
+ 1 | function(a, b)
+ : ^
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_no_value.snap
@@ -0,0 +1,50 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "function(a, b = ) a + b\n"
+---
+SOURCE_FILE@0..24
+ EXPR@0..23
+ EXPR_FUNCTION@0..23
+ FUNCTION_KW@0..8 "function"
+ PARAMS_DESC@8..17
+ L_PAREN@8..9 "("
+ PARAM@9..10
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ COMMA@10..11 ","
+ WHITESPACE@11..12 " "
+ PARAM@12..16
+ DESTRUCT_FULL@12..13
+ NAME@12..13
+ IDENT@12..13 "b"
+ WHITESPACE@13..14 " "
+ ASSIGN@14..15 "="
+ WHITESPACE@15..16 " "
+ EXPR@16..16
+ ERROR_MISSING_TOKEN@16..16
+ R_PAREN@16..17 ")"
+ WHITESPACE@17..18 " "
+ EXPR@18..23
+ EXPR_BINARY@18..23
+ EXPR@18..19
+ EXPR_VAR@18..19
+ NAME@18..19
+ IDENT@18..19 "a"
+ WHITESPACE@19..20 " "
+ PLUS@20..21 "+"
+ WHITESPACE@21..22 " "
+ EXPR@22..23
+ EXPR_VAR@22..23
+ NAME@22..23
+ IDENT@22..23 "b"
+ WHITESPACE@23..24 "\n"
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 16..16 }
+===
+ x syntax error
+ ,----
+ 1 | function(a, b = ) a + b
+ : ^
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__function_error_rparen.snap
@@ -0,0 +1,35 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "function(a, b\n"
+---
+SOURCE_FILE@0..14
+ EXPR@0..14
+ EXPR_FUNCTION@0..14
+ FUNCTION_KW@0..8 "function"
+ PARAMS_DESC@8..14
+ L_PAREN@8..9 "("
+ PARAM@9..10
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ COMMA@10..11 ","
+ WHITESPACE@11..12 " "
+ PARAM@12..13
+ DESTRUCT_FULL@12..13
+ NAME@12..13
+ IDENT@12..13 "b"
+ WHITESPACE@13..14 "\n"
+ ERROR_MISSING_TOKEN@14..14
+ EXPR@14..14
+ ERROR_MISSING_TOKEN@14..14
+===
+LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([R_PAREN, COMMA, ASSIGN])) }, range: 14..14 }
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 14..14 }
+===
+ x syntax error
+ ,----
+ 1 | function(a, b
+ : ^^
+ : |`-- missing expression
+ : `-- missing R_PAREN, COMMA or ASSIGN
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_method.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_method.snap
@@ -0,0 +1,55 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local\n\ta(x) = x,\n\ta = function(x) x,\n; c\n"
+---
+SOURCE_FILE@0..41
+ EXPR@0..40
+ STMT_LOCAL@0..38
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..7 "\n\t"
+ BIND_FUNCTION@7..15
+ NAME@7..8
+ IDENT@7..8 "a"
+ PARAMS_DESC@8..11
+ L_PAREN@8..9 "("
+ PARAM@9..10
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "x"
+ R_PAREN@10..11 ")"
+ WHITESPACE@11..12 " "
+ ASSIGN@12..13 "="
+ WHITESPACE@13..14 " "
+ EXPR@14..15
+ EXPR_VAR@14..15
+ NAME@14..15
+ IDENT@14..15 "x"
+ COMMA@15..16 ","
+ WHITESPACE@16..18 "\n\t"
+ BIND_FUNCTION@18..35
+ NAME@18..19
+ IDENT@18..19 "a"
+ WHITESPACE@19..20 " "
+ ASSIGN@20..21 "="
+ WHITESPACE@21..22 " "
+ FUNCTION_KW@22..30 "function"
+ PARAMS_DESC@30..33
+ L_PAREN@30..31 "("
+ PARAM@31..32
+ DESTRUCT_FULL@31..32
+ NAME@31..32
+ IDENT@31..32 "x"
+ R_PAREN@32..33 ")"
+ WHITESPACE@33..34 " "
+ EXPR@34..35
+ EXPR_VAR@34..35
+ NAME@34..35
+ IDENT@34..35 "x"
+ COMMA@35..36 ","
+ WHITESPACE@36..37 "\n"
+ SEMI@37..38 ";"
+ WHITESPACE@38..39 " "
+ EXPR_VAR@39..40
+ NAME@39..40
+ IDENT@39..40 "c"
+ WHITESPACE@40..41 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_no_value_recovery.snap
@@ -0,0 +1,49 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local a =\nlocal b = 3;\n1\n"
+---
+SOURCE_FILE@0..25
+ EXPR@0..25
+ STMT_LOCAL@0..25
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..24
+ DESTRUCT_FULL@6..7
+ NAME@6..7
+ IDENT@6..7 "a"
+ WHITESPACE@7..8 " "
+ ASSIGN@8..9 "="
+ WHITESPACE@9..10 "\n"
+ EXPR@10..24
+ STMT_LOCAL@10..22
+ LOCAL_KW@10..15 "local"
+ WHITESPACE@15..16 " "
+ BIND_DESTRUCT@16..21
+ DESTRUCT_FULL@16..17
+ NAME@16..17
+ IDENT@16..17 "b"
+ WHITESPACE@17..18 " "
+ ASSIGN@18..19 "="
+ WHITESPACE@19..20 " "
+ EXPR@20..21
+ EXPR_NUMBER@20..21
+ FLOAT@20..21 "3"
+ SEMI@21..22 ";"
+ WHITESPACE@22..23 "\n"
+ EXPR_NUMBER@23..24
+ FLOAT@23..24 "1"
+ WHITESPACE@24..25 "\n"
+ ERROR_MISSING_TOKEN@25..25
+ ERROR_MISSING_TOKEN@25..25
+===
+LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA, QUESTION_MARK])) }, range: 25..25 }
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 25..25 }
+===
+ x syntax error
+ ,-[2:1]
+ 2 | local b = 3;
+ 3 | 1
+ : ^^
+ : |`-- missing expression
+ : `-- missing L_BRACK, L_PAREN, L_BRACE, SEMI, DOT, COMMA or QUESTION_MARK
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__local_novalue.snap
@@ -0,0 +1,33 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local a =\n"
+---
+SOURCE_FILE@0..10
+ EXPR@0..10
+ STMT_LOCAL@0..10
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..10
+ DESTRUCT_FULL@6..7
+ NAME@6..7
+ IDENT@6..7 "a"
+ WHITESPACE@7..8 " "
+ ASSIGN@8..9 "="
+ WHITESPACE@9..10 "\n"
+ EXPR@10..10
+ ERROR_MISSING_TOKEN@10..10
+ ERROR_MISSING_TOKEN@10..10
+ ERROR_MISSING_TOKEN@10..10
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 10..10 }
+LocatedSyntaxError { error: Missing { expected: Unnamed(SyntaxKindSet([SEMI, COMMA])) }, range: 10..10 }
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 10..10 }
+===
+ x syntax error
+ ,----
+ 1 | local a =
+ : ^^^
+ : `-- missing expression
+ : |`-- missing SEMI or COMMA
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__named_before_positional.snap
@@ -0,0 +1,78 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "a(1, 2, b=4, 3, 5, k = 12, 6)\n"
+---
+SOURCE_FILE@0..30
+ EXPR@0..29
+ EXPR_VAR@0..1
+ NAME@0..1
+ IDENT@0..1 "a"
+ SUFFIX_APPLY@1..29
+ ARGS_DESC@1..29
+ L_PAREN@1..2 "("
+ ARG@2..3
+ EXPR@2..3
+ EXPR_NUMBER@2..3
+ FLOAT@2..3 "1"
+ COMMA@3..4 ","
+ WHITESPACE@4..5 " "
+ ARG@5..6
+ EXPR@5..6
+ EXPR_NUMBER@5..6
+ FLOAT@5..6 "2"
+ COMMA@6..7 ","
+ WHITESPACE@7..8 " "
+ ARG@8..11
+ NAME@8..9
+ IDENT@8..9 "b"
+ ASSIGN@9..10 "="
+ EXPR@10..11
+ EXPR_NUMBER@10..11
+ FLOAT@10..11 "4"
+ COMMA@11..12 ","
+ WHITESPACE@12..13 " "
+ ERROR_CUSTOM@13..14
+ ARG@13..14
+ EXPR@13..14
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "3"
+ COMMA@14..15 ","
+ WHITESPACE@15..16 " "
+ ERROR_CUSTOM@16..17
+ ARG@16..17
+ EXPR@16..17
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "5"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ ARG@19..25
+ NAME@19..20
+ IDENT@19..20 "k"
+ WHITESPACE@20..21 " "
+ ASSIGN@21..22 "="
+ WHITESPACE@22..23 " "
+ EXPR@23..25
+ EXPR_NUMBER@23..25
+ FLOAT@23..25 "12"
+ COMMA@25..26 ","
+ WHITESPACE@26..27 " "
+ ERROR_CUSTOM@27..28
+ ARG@27..28
+ EXPR@27..28
+ EXPR_NUMBER@27..28
+ FLOAT@27..28 "6"
+ R_PAREN@28..29 ")"
+ WHITESPACE@29..30 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 13..14 }
+LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 16..17 }
+LocatedSyntaxError { error: Custom { error: "can't use positional arguments after named" }, range: 27..28 }
+===
+ x syntax error
+ ,----
+ 1 | a(1, 2, b=4, 3, 5, k = 12, 6)
+ : | | |
+ : | | `-- can't use positional arguments after named
+ : | `-- can't use positional arguments after named
+ : `-- can't use positional arguments after named
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_lhs.snap
@@ -0,0 +1,23 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "+ 2\n"
+---
+SOURCE_FILE@0..4
+ EXPR@0..0
+ ERROR_MISSING_TOKEN@0..0
+ ERROR_CUSTOM@0..3
+ PLUS@0..1 "+"
+ WHITESPACE@1..2 " "
+ FLOAT@2..3 "2"
+ WHITESPACE@3..4 "\n"
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 0..0 }
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 0..3 }
+===
+ x syntax error
+ ,----
+ 1 | + 2
+ : ^^|
+ : | `-- unexpected tokens after end
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_operator.snap
@@ -0,0 +1,21 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "2 2\n"
+---
+SOURCE_FILE@0..4
+ EXPR@0..1
+ EXPR_NUMBER@0..1
+ FLOAT@0..1 "2"
+ WHITESPACE@1..2 " "
+ ERROR_CUSTOM@2..3
+ FLOAT@2..3 "2"
+ WHITESPACE@3..4 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "unexpected tokens after end" }, range: 2..3 }
+===
+ x syntax error
+ ,----
+ 1 | 2 2
+ : |
+ : `-- unexpected tokens after end
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__no_rhs.snap
@@ -0,0 +1,24 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "a +\n"
+---
+SOURCE_FILE@0..4
+ EXPR@0..4
+ EXPR_BINARY@0..4
+ EXPR@0..1
+ EXPR_VAR@0..1
+ NAME@0..1
+ IDENT@0..1 "a"
+ WHITESPACE@1..2 " "
+ PLUS@2..3 "+"
+ WHITESPACE@3..4 "\n"
+ ERROR_MISSING_TOKEN@4..4
+===
+LocatedSyntaxError { error: Missing { expected: Named("expression") }, range: 4..4 }
+===
+ x syntax error
+ ,----
+ 1 | a +
+ : ^
+ : `-- missing expression
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec.snap
@@ -0,0 +1,46 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{a:1 for a in [1, 2, 3]}\n"
+---
+SOURCE_FILE@0..25
+ EXPR@0..24
+ EXPR_OBJECT@0..24
+ OBJ_BODY_COMP@0..24
+ L_BRACE@0..1 "{"
+ MEMBER_FIELD_NORMAL@1..4
+ FIELD_NAME_FIXED@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COLON@2..3 ":"
+ EXPR@3..4
+ EXPR_NUMBER@3..4
+ FLOAT@3..4 "1"
+ WHITESPACE@4..5 " "
+ FOR_SPEC@5..23
+ FOR_KW@5..8 "for"
+ WHITESPACE@8..9 " "
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ WHITESPACE@10..11 " "
+ IN_KW@11..13 "in"
+ WHITESPACE@13..14 " "
+ EXPR@14..23
+ EXPR_ARRAY@14..23
+ L_BRACK@14..15 "["
+ EXPR@15..16
+ EXPR_NUMBER@15..16
+ FLOAT@15..16 "1"
+ COMMA@16..17 ","
+ WHITESPACE@17..18 " "
+ EXPR@18..19
+ EXPR_NUMBER@18..19
+ FLOAT@18..19 "2"
+ COMMA@19..20 ","
+ WHITESPACE@20..21 " "
+ EXPR@21..22
+ EXPR_NUMBER@21..22
+ FLOAT@21..22 "3"
+ R_BRACK@22..23 "]"
+ R_BRACE@23..24 "}"
+ WHITESPACE@24..25 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_comma.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_comma.snap
@@ -0,0 +1,47 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{a:1, for a in [1, 2, 3]}\n"
+---
+SOURCE_FILE@0..26
+ EXPR@0..25
+ EXPR_OBJECT@0..25
+ OBJ_BODY_COMP@0..25
+ L_BRACE@0..1 "{"
+ MEMBER_FIELD_NORMAL@1..4
+ FIELD_NAME_FIXED@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COLON@2..3 ":"
+ EXPR@3..4
+ EXPR_NUMBER@3..4
+ FLOAT@3..4 "1"
+ COMMA@4..5 ","
+ WHITESPACE@5..6 " "
+ FOR_SPEC@6..24
+ FOR_KW@6..9 "for"
+ WHITESPACE@9..10 " "
+ DESTRUCT_FULL@10..11
+ NAME@10..11
+ IDENT@10..11 "a"
+ WHITESPACE@11..12 " "
+ IN_KW@12..14 "in"
+ WHITESPACE@14..15 " "
+ EXPR@15..24
+ EXPR_ARRAY@15..24
+ L_BRACK@15..16 "["
+ EXPR@16..17
+ EXPR_NUMBER@16..17
+ FLOAT@16..17 "1"
+ COMMA@17..18 ","
+ WHITESPACE@18..19 " "
+ EXPR@19..20
+ EXPR_NUMBER@19..20
+ FLOAT@19..20 "2"
+ COMMA@20..21 ","
+ WHITESPACE@21..22 " "
+ EXPR@22..23
+ EXPR_NUMBER@22..23
+ FLOAT@22..23 "3"
+ R_BRACK@23..24 "]"
+ R_BRACE@24..25 "}"
+ WHITESPACE@25..26 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_asserts.snap
@@ -0,0 +1,64 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{assert 1, a: 1 for a in [1,2,3]}\n"
+---
+SOURCE_FILE@0..34
+ EXPR@0..33
+ EXPR_OBJECT@0..33
+ OBJ_BODY_COMP@0..33
+ L_BRACE@0..1 "{"
+ ERROR_CUSTOM@1..9
+ MEMBER_ASSERT_STMT@1..9
+ ASSERTION@1..9
+ ASSERT_KW@1..7 "assert"
+ WHITESPACE@7..8 " "
+ EXPR@8..9
+ EXPR_NUMBER@8..9
+ FLOAT@8..9 "1"
+ COMMA@9..10 ","
+ WHITESPACE@10..11 " "
+ MEMBER_FIELD_NORMAL@11..15
+ FIELD_NAME_FIXED@11..12
+ NAME@11..12
+ IDENT@11..12 "a"
+ COLON@12..13 ":"
+ WHITESPACE@13..14 " "
+ EXPR@14..15
+ EXPR_NUMBER@14..15
+ FLOAT@14..15 "1"
+ WHITESPACE@15..16 " "
+ FOR_SPEC@16..32
+ FOR_KW@16..19 "for"
+ WHITESPACE@19..20 " "
+ DESTRUCT_FULL@20..21
+ NAME@20..21
+ IDENT@20..21 "a"
+ WHITESPACE@21..22 " "
+ IN_KW@22..24 "in"
+ WHITESPACE@24..25 " "
+ EXPR@25..32
+ EXPR_ARRAY@25..32
+ L_BRACK@25..26 "["
+ EXPR@26..27
+ EXPR_NUMBER@26..27
+ FLOAT@26..27 "1"
+ COMMA@27..28 ","
+ EXPR@28..29
+ EXPR_NUMBER@28..29
+ FLOAT@28..29 "2"
+ COMMA@29..30 ","
+ EXPR@30..31
+ EXPR_NUMBER@30..31
+ FLOAT@30..31 "3"
+ R_BRACK@31..32 "]"
+ R_BRACE@32..33 "}"
+ WHITESPACE@33..34 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "asserts can't be used in object comprehensions" }, range: 1..9 }
+===
+ x syntax error
+ ,----
+ 1 | {assert 1, a: 1 for a in [1,2,3]}
+ : ^^^^|^^^
+ : `-- asserts can't be used in object comprehensions
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems.snap
@@ -0,0 +1,66 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{a:1 for a in [1, 2, 3], b:1}\n"
+---
+SOURCE_FILE@0..30
+ EXPR@0..29
+ EXPR_OBJECT@0..29
+ OBJ_BODY_MEMBER_LIST@0..29
+ L_BRACE@0..1 "{"
+ MEMBER_FIELD_NORMAL@1..4
+ FIELD_NAME_FIXED@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COLON@2..3 ":"
+ EXPR@3..4
+ EXPR_NUMBER@3..4
+ FLOAT@3..4 "1"
+ WHITESPACE@4..5 " "
+ ERROR_CUSTOM@5..23
+ FOR_SPEC@5..23
+ FOR_KW@5..8 "for"
+ WHITESPACE@8..9 " "
+ DESTRUCT_FULL@9..10
+ NAME@9..10
+ IDENT@9..10 "a"
+ WHITESPACE@10..11 " "
+ IN_KW@11..13 "in"
+ WHITESPACE@13..14 " "
+ EXPR@14..23
+ EXPR_ARRAY@14..23
+ L_BRACK@14..15 "["
+ EXPR@15..16
+ EXPR_NUMBER@15..16
+ FLOAT@15..16 "1"
+ COMMA@16..17 ","
+ WHITESPACE@17..18 " "
+ EXPR@18..19
+ EXPR_NUMBER@18..19
+ FLOAT@18..19 "2"
+ COMMA@19..20 ","
+ WHITESPACE@20..21 " "
+ EXPR@21..22
+ EXPR_NUMBER@21..22
+ FLOAT@21..22 "3"
+ R_BRACK@22..23 "]"
+ COMMA@23..24 ","
+ WHITESPACE@24..25 " "
+ MEMBER_FIELD_NORMAL@25..28
+ FIELD_NAME_FIXED@25..26
+ NAME@25..26
+ IDENT@25..26 "b"
+ COLON@26..27 ":"
+ EXPR@27..28
+ EXPR_NUMBER@27..28
+ FLOAT@27..28 "1"
+ R_BRACE@28..29 "}"
+ WHITESPACE@29..30 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 5..23 }
+===
+ x syntax error
+ ,----
+ 1 | {a:1 for a in [1, 2, 3], b:1}
+ : ^^^^^^^^^|^^^^^^^^
+ : `-- compspec may only be used if there is only one object element
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_incompatible_with_multiple_elems_w.snap
@@ -0,0 +1,77 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{a:1, b:1, for a in [1, 2, 3], c:1}\n"
+---
+SOURCE_FILE@0..36
+ EXPR@0..35
+ EXPR_OBJECT@0..35
+ OBJ_BODY_MEMBER_LIST@0..35
+ L_BRACE@0..1 "{"
+ MEMBER_FIELD_NORMAL@1..4
+ FIELD_NAME_FIXED@1..2
+ NAME@1..2
+ IDENT@1..2 "a"
+ COLON@2..3 ":"
+ EXPR@3..4
+ EXPR_NUMBER@3..4
+ FLOAT@3..4 "1"
+ COMMA@4..5 ","
+ WHITESPACE@5..6 " "
+ MEMBER_FIELD_NORMAL@6..9
+ FIELD_NAME_FIXED@6..7
+ NAME@6..7
+ IDENT@6..7 "b"
+ COLON@7..8 ":"
+ EXPR@8..9
+ EXPR_NUMBER@8..9
+ FLOAT@8..9 "1"
+ COMMA@9..10 ","
+ WHITESPACE@10..11 " "
+ ERROR_CUSTOM@11..29
+ FOR_SPEC@11..29
+ FOR_KW@11..14 "for"
+ WHITESPACE@14..15 " "
+ DESTRUCT_FULL@15..16
+ NAME@15..16
+ IDENT@15..16 "a"
+ WHITESPACE@16..17 " "
+ IN_KW@17..19 "in"
+ WHITESPACE@19..20 " "
+ EXPR@20..29
+ EXPR_ARRAY@20..29
+ L_BRACK@20..21 "["
+ EXPR@21..22
+ EXPR_NUMBER@21..22
+ FLOAT@21..22 "1"
+ COMMA@22..23 ","
+ WHITESPACE@23..24 " "
+ EXPR@24..25
+ EXPR_NUMBER@24..25
+ FLOAT@24..25 "2"
+ COMMA@25..26 ","
+ WHITESPACE@26..27 " "
+ EXPR@27..28
+ EXPR_NUMBER@27..28
+ FLOAT@27..28 "3"
+ R_BRACK@28..29 "]"
+ COMMA@29..30 ","
+ WHITESPACE@30..31 " "
+ MEMBER_FIELD_NORMAL@31..34
+ FIELD_NAME_FIXED@31..32
+ NAME@31..32
+ IDENT@31..32 "c"
+ COLON@32..33 ":"
+ EXPR@33..34
+ EXPR_NUMBER@33..34
+ FLOAT@33..34 "1"
+ R_BRACE@34..35 "}"
+ WHITESPACE@35..36 "\n"
+===
+LocatedSyntaxError { error: Custom { error: "compspec may only be used if there is only one object element" }, range: 11..29 }
+===
+ x syntax error
+ ,----
+ 1 | {a:1, b:1, for a in [1, 2, 3], c:1}
+ : ^^^^^^^^^|^^^^^^^^
+ : `-- compspec may only be used if there is only one object element
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_compspec_no_elems.snap
@@ -0,0 +1,47 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{for a in [1, 2, 3]}\n"
+---
+SOURCE_FILE@0..21
+ EXPR@0..20
+ EXPR_OBJECT@0..20
+ OBJ_BODY_COMP@0..20
+ L_BRACE@0..1 "{"
+ ERROR_MISSING_TOKEN@1..1
+ FOR_SPEC@1..19
+ FOR_KW@1..4 "for"
+ WHITESPACE@4..5 " "
+ DESTRUCT_FULL@5..6
+ NAME@5..6
+ IDENT@5..6 "a"
+ WHITESPACE@6..7 " "
+ IN_KW@7..9 "in"
+ WHITESPACE@9..10 " "
+ EXPR@10..19
+ EXPR_ARRAY@10..19
+ L_BRACK@10..11 "["
+ EXPR@11..12
+ EXPR_NUMBER@11..12
+ FLOAT@11..12 "1"
+ COMMA@12..13 ","
+ WHITESPACE@13..14 " "
+ EXPR@14..15
+ EXPR_NUMBER@14..15
+ FLOAT@14..15 "2"
+ COMMA@15..16 ","
+ WHITESPACE@16..17 " "
+ EXPR@17..18
+ EXPR_NUMBER@17..18
+ FLOAT@17..18 "3"
+ R_BRACK@18..19 "]"
+ R_BRACE@19..20 "}"
+ WHITESPACE@20..21 "\n"
+===
+LocatedSyntaxError { error: Missing { expected: Named("field definition") }, range: 1..1 }
+===
+ x syntax error
+ ,----
+ 1 | {for a in [1, 2, 3]}
+ : ^
+ : `-- missing field definition
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_method.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__obj_method.snap
@@ -0,0 +1,52 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{\n\ta(x): x,\n\ta: function(x) x,\n}\n"
+---
+SOURCE_FILE@0..33
+ EXPR@0..32
+ EXPR_OBJECT@0..32
+ OBJ_BODY_MEMBER_LIST@0..32
+ L_BRACE@0..1 "{"
+ WHITESPACE@1..3 "\n\t"
+ MEMBER_FIELD_METHOD@3..10
+ FIELD_NAME_FIXED@3..4
+ NAME@3..4
+ IDENT@3..4 "a"
+ PARAMS_DESC@4..7
+ L_PAREN@4..5 "("
+ PARAM@5..6
+ DESTRUCT_FULL@5..6
+ NAME@5..6
+ IDENT@5..6 "x"
+ R_PAREN@6..7 ")"
+ COLON@7..8 ":"
+ WHITESPACE@8..9 " "
+ EXPR@9..10
+ EXPR_VAR@9..10
+ NAME@9..10
+ IDENT@9..10 "x"
+ COMMA@10..11 ","
+ WHITESPACE@11..13 "\n\t"
+ MEMBER_FIELD_METHOD@13..29
+ FIELD_NAME_FIXED@13..14
+ NAME@13..14
+ IDENT@13..14 "a"
+ COLON@14..15 ":"
+ WHITESPACE@15..16 " "
+ FUNCTION_KW@16..24 "function"
+ PARAMS_DESC@24..27
+ L_PAREN@24..25 "("
+ PARAM@25..26
+ DESTRUCT_FULL@25..26
+ NAME@25..26
+ IDENT@25..26 "x"
+ R_PAREN@26..27 ")"
+ WHITESPACE@27..28 " "
+ EXPR@28..29
+ EXPR_VAR@28..29
+ NAME@28..29
+ IDENT@28..29 "x"
+ COMMA@29..30 ","
+ WHITESPACE@30..31 "\n"
+ R_BRACE@31..32 "}"
+ WHITESPACE@32..33 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__plain_call.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__plain_call.snap
@@ -0,0 +1,58 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "std.substr(a, 0, std.length(b)) == b\n"
+---
+SOURCE_FILE@0..37
+ EXPR@0..36
+ EXPR_BINARY@0..36
+ EXPR@0..3
+ EXPR_VAR@0..3
+ NAME@0..3
+ IDENT@0..3 "std"
+ SUFFIX_INDEX@3..10
+ DOT@3..4 "."
+ NAME@4..10
+ IDENT@4..10 "substr"
+ SUFFIX_APPLY@10..31
+ ARGS_DESC@10..31
+ L_PAREN@10..11 "("
+ ARG@11..12
+ EXPR@11..12
+ EXPR_VAR@11..12
+ NAME@11..12
+ IDENT@11..12 "a"
+ COMMA@12..13 ","
+ WHITESPACE@13..14 " "
+ ARG@14..15
+ EXPR@14..15
+ EXPR_NUMBER@14..15
+ FLOAT@14..15 "0"
+ COMMA@15..16 ","
+ WHITESPACE@16..17 " "
+ ARG@17..30
+ EXPR@17..30
+ EXPR_VAR@17..20
+ NAME@17..20
+ IDENT@17..20 "std"
+ SUFFIX_INDEX@20..27
+ DOT@20..21 "."
+ NAME@21..27
+ IDENT@21..27 "length"
+ SUFFIX_APPLY@27..30
+ ARGS_DESC@27..30
+ L_PAREN@27..28 "("
+ ARG@28..29
+ EXPR@28..29
+ EXPR_VAR@28..29
+ NAME@28..29
+ IDENT@28..29 "b"
+ R_PAREN@29..30 ")"
+ R_PAREN@30..31 ")"
+ WHITESPACE@31..32 " "
+ EQ@32..34 "=="
+ WHITESPACE@34..35 " "
+ EXPR@35..36
+ EXPR_VAR@35..36
+ NAME@35..36
+ IDENT@35..36 "b"
+ WHITESPACE@36..37 "\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__stdlib.snapdiffbeforeafterboth1---2source: crates/jrsonnet-rowan-parser/src/tests.rs3expression: "{\n local std = self,\n local id = std.id,\n\n thisFile:: error 'std.thisFile is deprecated, to enable its support in jrsonnet - recompile it with \"legacy-this-file\" support.\\nThis will slow down stdlib caching a bit, though',\n\n lstripChars(str, chars)::\n if std.length(str) > 0 && std.member(chars, str[0]) then\n std.lstripChars(str[1:], chars)\n else\n str,\n\n rstripChars(str, chars)::\n local len = std.length(str);\n if len > 0 && std.member(chars, str[len - 1]) then\n std.rstripChars(str[:len - 1], chars)\n else\n str,\n\n stripChars(str, chars)::\n std.lstripChars(std.rstripChars(str, chars), chars),\n\n splitLimitR(str, c, maxsplits)::\n if maxsplits == -1 then\n std.splitLimit(str, c, -1)\n else\n local revStr(str) = std.join('', std.reverse(std.stringChars(str)));\n std.map(function(e) revStr(e), std.reverse(std.splitLimit(revStr(str), revStr(c), maxsplits))),\n\n split(str, c):: std.splitLimit(str, c, -1),\n\n mapWithIndex(func, arr)::\n if !std.isFunction(func) then\n error ('std.mapWithIndex first param must be function, got ' + std.type(func))\n else if !std.isArray(arr) && !std.isString(arr) then\n error ('std.mapWithIndex second param must be array, got ' + std.type(arr))\n else\n std.makeArray(std.length(arr), function(i) func(i, arr[i])),\n\n mapWithKey(func, obj)::\n if !std.isFunction(func) then\n error ('std.mapWithKey first param must be function, got ' + std.type(func))\n else if !std.isObject(obj) then\n error ('std.mapWithKey second param must be object, got ' + std.type(obj))\n else\n { [k]: func(k, obj[k]) for k in std.objectFields(obj) },\n\n lines(arr)::\n std.join('\\n', arr + ['']),\n\n deepJoin(arr)::\n if std.isString(arr) then\n arr\n else if std.isArray(arr) then\n std.join('', [std.deepJoin(x) for x in arr])\n else\n error 'Expected string or array, got %s' % std.type(arr),\n\n assertEqual(a, b)::\n if a == b then\n true\n else\n error 'Assertion failed. ' + a + ' != ' + b,\n\n clamp(x, minVal, maxVal)::\n if x < minVal then minVal\n else if x > maxVal then maxVal\n else x,\n\n manifestIni(ini)::\n local body_lines(body) =\n std.join([], [\n local value_or_values = body[k];\n if std.isArray(value_or_values) then\n ['%s = %s' % [k, value] for value in value_or_values]\n else\n ['%s = %s' % [k, value_or_values]]\n\n for k in std.objectFields(body)\n ]);\n\n local section_lines(sname, sbody) = ['[%s]' % [sname]] + body_lines(sbody),\n main_body = if std.objectHas(ini, 'main') then body_lines(ini.main) else [],\n all_sections = [\n section_lines(k, ini.sections[k])\n for k in std.objectFields(ini.sections)\n ];\n std.join('\\n', main_body + std.flattenArrays(all_sections) + ['']),\n\n manifestToml(value):: std.manifestTomlEx(value, ' '),\n\n escapeStringPython(str)::\n std.escapeStringJson(str),\n\n escapeStringBash(str_)::\n local str = std.toString(str_);\n local trans(ch) =\n if ch == \"'\" then\n \"'\\\"'\\\"'\"\n else\n ch;\n \"'%s'\" % std.join('', [trans(ch) for ch in std.stringChars(str)]),\n\n escapeStringDollars(str_)::\n local str = std.toString(str_);\n local trans(ch) =\n if ch == '$' then\n '$$'\n else\n ch;\n std.foldl(function(a, b) a + trans(b), std.stringChars(str), ''),\n\n local xml_escapes = {\n '<': '<',\n '>': '>',\n '&': '&',\n '\"': '"',\n \"'\": ''',\n },\n\n escapeStringXML(str_)::\n local str = std.toString(str_);\n std.join('', [std.get(xml_escapes, ch, ch) for ch in std.stringChars(str)]),\n\n manifestJson(value):: std.manifestJsonEx(value, ' ') tailstrict,\n\n manifestJsonMinified(value):: std.manifestJsonEx(value, '', '', ':'),\n\n manifestYamlStream(value, indent_array_in_object=false, c_document_end=true, quote_keys=true)::\n if !std.isArray(value) then\n error 'manifestYamlStream only takes arrays, got ' + std.type(value)\n else\n '---\\n' + std.join(\n '\\n---\\n', [std.manifestYamlDoc(e, indent_array_in_object, quote_keys) for e in value]\n ) + if c_document_end then '\\n...\\n' else '\\n',\n\n manifestPython(v)::\n if std.isObject(v) then\n local fields = [\n '%s: %s' % [std.escapeStringPython(k), std.manifestPython(v[k])]\n for k in std.objectFields(v)\n ];\n '{%s}' % [std.join(', ', fields)]\n else if std.isArray(v) then\n '[%s]' % [std.join(', ', [std.manifestPython(v2) for v2 in v])]\n else if std.isString(v) then\n '%s' % [std.escapeStringPython(v)]\n else if std.isFunction(v) then\n error 'cannot manifest function'\n else if std.isNumber(v) then\n std.toString(v)\n else if v == true then\n 'True'\n else if v == false then\n 'False'\n else if v == null then\n 'None',\n\n manifestPythonVars(conf)::\n local vars = ['%s = %s' % [k, std.manifestPython(conf[k])] for k in std.objectFields(conf)];\n std.join('\\n', vars + ['']),\n\n manifestXmlJsonml(value)::\n if !std.isArray(value) then\n error 'Expected a JSONML value (an array), got %s' % std.type(value)\n else\n local aux(v) =\n if std.isString(v) then\n v\n else\n local tag = v[0];\n local has_attrs = std.length(v) > 1 && std.isObject(v[1]);\n local attrs = if has_attrs then v[1] else {};\n local children = if has_attrs then v[2:] else v[1:];\n local attrs_str =\n std.join('', [' %s=\"%s\"' % [k, attrs[k]] for k in std.objectFields(attrs)]);\n std.deepJoin(['<', tag, attrs_str, '>', [aux(x) for x in children], '</', tag, '>']);\n\n aux(value),\n\n mergePatch(target, patch)::\n if std.isObject(patch) then\n local target_object =\n if std.isObject(target) then target else {};\n\n local target_fields =\n if std.isObject(target_object) then std.objectFields(target_object) else [];\n\n local null_fields = [k for k in std.objectFields(patch) if patch[k] == null];\n local both_fields = std.setUnion(target_fields, std.objectFields(patch));\n\n {\n [k]:\n if !std.objectHas(patch, k) then\n target_object[k]\n else if !std.objectHas(target_object, k) then\n std.mergePatch(null, patch[k]) tailstrict\n else\n std.mergePatch(target_object[k], patch[k]) tailstrict\n for k in std.setDiff(both_fields, null_fields)\n }\n else\n patch,\n\n get(o, f, default=null, inc_hidden=true)::\n if std.objectHasEx(o, f, inc_hidden) then o[f] else default,\n\n resolvePath(f, r)::\n local arr = std.split(f, '/');\n std.join('/', std.makeArray(std.length(arr) - 1, function(i) arr[i]) + [r]),\n\n prune(a)::\n local isContent(b) =\n if b == null then\n false\n else if std.isArray(b) then\n std.length(b) > 0\n else if std.isObject(b) then\n std.length(b) > 0\n else\n true;\n if std.isArray(a) then\n [std.prune(x) for x in a if isContent($.prune(x))]\n else if std.isObject(a) then {\n [x]: $.prune(a[x])\n for x in std.objectFields(a)\n if isContent(std.prune(a[x]))\n } else\n a,\n\n find(value, arr)::\n if !std.isArray(arr) then\n error 'find second parameter should be an array, got ' + std.type(arr)\n else\n std.filter(function(i) arr[i] == value, std.range(0, std.length(arr) - 1)),\n\n // Compat\n __compare_array(arr1, arr2)::\n assert std.isArray(arr1) && std.isArray(arr2);\n std.__compare(arr1, arr2),\n __array_less(arr1, arr2):: std.__compare_array(arr1, arr2) == -1,\n __array_greater(arr1, arr2):: std.__compare_array(arr1, arr2) == 1,\n __array_less_or_equal(arr1, arr2):: std.__compare_array(arr1, arr2) <= 0,\n __array_greater_or_equal(arr1, arr2):: std.__compare_array(arr1, arr2) >= 0,\n}\n"4---5SOURCE_FILE@0..78356 EXPR@0..78347 EXPR_OBJECT@0..78348 OBJ_BODY_MEMBER_LIST@0..78349 L_BRACE@0..1 "{"10 WHITESPACE@1..4 "\n "11 MEMBER_BIND_STMT@4..2012 OBJ_LOCAL@4..2013 LOCAL_KW@4..9 "local"14 WHITESPACE@9..10 " "15 BIND_DESTRUCT@10..2016 DESTRUCT_FULL@10..1317 NAME@10..1318 IDENT@10..13 "std"19 WHITESPACE@13..14 " "20 ASSIGN@14..15 "="21 WHITESPACE@15..16 " "22 EXPR@16..2023 EXPR_LITERAL@16..2024 SELF_KW@16..20 "self"25 COMMA@20..21 ","26 WHITESPACE@21..24 "\n "27 MEMBER_BIND_STMT@24..4128 OBJ_LOCAL@24..4129 LOCAL_KW@24..29 "local"30 WHITESPACE@29..30 " "31 BIND_DESTRUCT@30..4132 DESTRUCT_FULL@30..3233 NAME@30..3234 IDENT@30..32 "id"35 WHITESPACE@32..33 " "36 ASSIGN@33..34 "="37 WHITESPACE@34..35 " "38 EXPR@35..4139 EXPR_VAR@35..3840 NAME@35..3841 IDENT@35..38 "std"42 SUFFIX_INDEX@38..4143 DOT@38..39 "."44 NAME@39..4145 IDENT@39..41 "id"46 COMMA@41..42 ","47 WHITESPACE@42..46 "\n\n "48 MEMBER_FIELD_NORMAL@46..22449 FIELD_NAME_FIXED@46..5450 NAME@46..5451 IDENT@46..54 "thisFile"52 COLONCOLON@54..56 "::"53 WHITESPACE@56..57 " "54 EXPR@57..22455 EXPR_ERROR@57..22456 ERROR_KW@57..62 "error"57 WHITESPACE@62..63 " "58 EXPR@63..22459 EXPR_STRING@63..22460 STRING_SINGLE@63..224 "'std.thisFile is depr ..."61 COMMA@224..225 ","62 WHITESPACE@225..229 "\n\n "63 MEMBER_FIELD_METHOD@229..37264 FIELD_NAME_FIXED@229..24065 NAME@229..24066 IDENT@229..240 "lstripChars"67 PARAMS_DESC@240..25268 L_PAREN@240..241 "("69 PARAM@241..24470 DESTRUCT_FULL@241..24471 NAME@241..24472 IDENT@241..244 "str"73 COMMA@244..245 ","74 WHITESPACE@245..246 " "75 PARAM@246..25176 DESTRUCT_FULL@246..25177 NAME@246..25178 IDENT@246..251 "chars"79 R_PAREN@251..252 ")"80 COLONCOLON@252..254 "::"81 WHITESPACE@254..259 "\n "82 EXPR@259..37283 EXPR_IF_THEN_ELSE@259..37284 IF_KW@259..261 "if"85 WHITESPACE@261..262 " "86 EXPR@262..31087 EXPR_BINARY@262..31088 EXPR@262..28189 EXPR_BINARY@262..28190 EXPR@262..26591 EXPR_VAR@262..26592 NAME@262..26593 IDENT@262..265 "std"94 SUFFIX_INDEX@265..27295 DOT@265..266 "."96 NAME@266..27297 IDENT@266..272 "length"98 SUFFIX_APPLY@272..27799 ARGS_DESC@272..277100 L_PAREN@272..273 "("101 ARG@273..276102 EXPR@273..276103 EXPR_VAR@273..276104 NAME@273..276105 IDENT@273..276 "str"106 R_PAREN@276..277 ")"107 WHITESPACE@277..278 " "108 GT@278..279 ">"109 WHITESPACE@279..280 " "110 EXPR@280..281111 EXPR_NUMBER@280..281112 FLOAT@280..281 "0"113 WHITESPACE@281..282 " "114 AND@282..284 "&&"115 WHITESPACE@284..285 " "116 EXPR@285..310117 EXPR_VAR@285..288118 NAME@285..288119 IDENT@285..288 "std"120 SUFFIX_INDEX@288..295121 DOT@288..289 "."122 NAME@289..295123 IDENT@289..295 "member"124 SUFFIX_APPLY@295..310125 ARGS_DESC@295..310126 L_PAREN@295..296 "("127 ARG@296..301128 EXPR@296..301129 EXPR_VAR@296..301130 NAME@296..301131 IDENT@296..301 "chars"132 COMMA@301..302 ","133 WHITESPACE@302..303 " "134 ARG@303..309135 EXPR@303..309136 EXPR_VAR@303..306137 NAME@303..306138 IDENT@303..306 "str"139 SUFFIX_INDEX_EXPR@306..309140 L_BRACK@306..307 "["141 EXPR@307..308142 EXPR_NUMBER@307..308143 FLOAT@307..308 "0"144 R_BRACK@308..309 "]"145 R_PAREN@309..310 ")"146 WHITESPACE@310..311 " "147 THEN_KW@311..315 "then"148 WHITESPACE@315..322 "\n "149 TRUE_EXPR@322..353150 EXPR@322..353151 EXPR_VAR@322..325152 NAME@322..325153 IDENT@322..325 "std"154 SUFFIX_INDEX@325..337155 DOT@325..326 "."156 NAME@326..337157 IDENT@326..337 "lstripChars"158 SUFFIX_APPLY@337..353159 ARGS_DESC@337..353160 L_PAREN@337..338 "("161 ARG@338..345162 EXPR@338..345163 EXPR_VAR@338..341164 NAME@338..341165 IDENT@338..341 "str"166 SUFFIX_SLICE@341..345167 SLICE_DESC@341..345168 L_BRACK@341..342 "["169 EXPR@342..343170 EXPR_NUMBER@342..343171 FLOAT@342..343 "1"172 COLON@343..344 ":"173 R_BRACK@344..345 "]"174 COMMA@345..346 ","175 WHITESPACE@346..347 " "176 ARG@347..352177 EXPR@347..352178 EXPR_VAR@347..352179 NAME@347..352180 IDENT@347..352 "chars"181 R_PAREN@352..353 ")"182 WHITESPACE@353..358 "\n "183 ELSE_KW@358..362 "else"184 WHITESPACE@362..369 "\n "185 FALSE_EXPR@369..372186 EXPR@369..372187 EXPR_VAR@369..372188 NAME@369..372189 IDENT@369..372 "str"190 COMMA@372..373 ","191 WHITESPACE@373..377 "\n\n "192 MEMBER_FIELD_METHOD@377..553193 FIELD_NAME_FIXED@377..388194 NAME@377..388195 IDENT@377..388 "rstripChars"196 PARAMS_DESC@388..400197 L_PAREN@388..389 "("198 PARAM@389..392199 DESTRUCT_FULL@389..392200 NAME@389..392201 IDENT@389..392 "str"202 COMMA@392..393 ","203 WHITESPACE@393..394 " "204 PARAM@394..399205 DESTRUCT_FULL@394..399206 NAME@394..399207 IDENT@394..399 "chars"208 R_PAREN@399..400 ")"209 COLONCOLON@400..402 "::"210 WHITESPACE@402..407 "\n "211 EXPR@407..553212 STMT_LOCAL@407..435213 LOCAL_KW@407..412 "local"214 WHITESPACE@412..413 " "215 BIND_DESTRUCT@413..434216 DESTRUCT_FULL@413..416217 NAME@413..416218 IDENT@413..416 "len"219 WHITESPACE@416..417 " "220 ASSIGN@417..418 "="221 WHITESPACE@418..419 " "222 EXPR@419..434223 EXPR_VAR@419..422224 NAME@419..422225 IDENT@419..422 "std"226 SUFFIX_INDEX@422..429227 DOT@422..423 "."228 NAME@423..429229 IDENT@423..429 "length"230 SUFFIX_APPLY@429..434231 ARGS_DESC@429..434232 L_PAREN@429..430 "("233 ARG@430..433234 EXPR@430..433235 EXPR_VAR@430..433236 NAME@430..433237 IDENT@430..433 "str"238 R_PAREN@433..434 ")"239 SEMI@434..435 ";"240 WHITESPACE@435..440 "\n "241 EXPR_IF_THEN_ELSE@440..553242 IF_KW@440..442 "if"243 WHITESPACE@442..443 " "244 EXPR@443..485245 EXPR_BINARY@443..485246 EXPR@443..450247 EXPR_BINARY@443..450248 EXPR@443..446249 EXPR_VAR@443..446250 NAME@443..446251 IDENT@443..446 "len"252 WHITESPACE@446..447 " "253 GT@447..448 ">"254 WHITESPACE@448..449 " "255 EXPR@449..450256 EXPR_NUMBER@449..450257 FLOAT@449..450 "0"258 WHITESPACE@450..451 " "259 AND@451..453 "&&"260 WHITESPACE@453..454 " "261 EXPR@454..485262 EXPR_VAR@454..457263 NAME@454..457264 IDENT@454..457 "std"265 SUFFIX_INDEX@457..464266 DOT@457..458 "."267 NAME@458..464268 IDENT@458..464 "member"269 SUFFIX_APPLY@464..485270 ARGS_DESC@464..485271 L_PAREN@464..465 "("272 ARG@465..470273 EXPR@465..470274 EXPR_VAR@465..470275 NAME@465..470276 IDENT@465..470 "chars"277 COMMA@470..471 ","278 WHITESPACE@471..472 " "279 ARG@472..484280 EXPR@472..484281 EXPR_VAR@472..475282 NAME@472..475283 IDENT@472..475 "str"284 SUFFIX_INDEX_EXPR@475..484285 L_BRACK@475..476 "["286 EXPR@476..483287 EXPR_BINARY@476..483288 EXPR@476..479289 EXPR_VAR@476..479290 NAME@476..479291 IDENT@476..479 "len"292 WHITESPACE@479..480 " "293 MINUS@480..481 "-"294 WHITESPACE@481..482 " "295 EXPR@482..483296 EXPR_NUMBER@482..483297 FLOAT@482..483 "1"298 R_BRACK@483..484 "]"299 R_PAREN@484..485 ")"300 WHITESPACE@485..486 " "301 THEN_KW@486..490 "then"302 WHITESPACE@490..497 "\n "303 TRUE_EXPR@497..534304 EXPR@497..534305 EXPR_VAR@497..500306 NAME@497..500307 IDENT@497..500 "std"308 SUFFIX_INDEX@500..512309 DOT@500..501 "."310 NAME@501..512311 IDENT@501..512 "rstripChars"312 SUFFIX_APPLY@512..534313 ARGS_DESC@512..534314 L_PAREN@512..513 "("315 ARG@513..526316 EXPR@513..526317 EXPR_VAR@513..516318 NAME@513..516319 IDENT@513..516 "str"320 SUFFIX_SLICE@516..526321 SLICE_DESC@516..526322 L_BRACK@516..517 "["323 COLON@517..518 ":"324 SLICE_DESC_END@518..525325 EXPR@518..525326 EXPR_BINARY@518..525327 EXPR@518..521328 EXPR_VAR@518..521329 NAME@518..521330 IDENT@518..521 "len"331 WHITESPACE@521..522 " "332 MINUS@522..523 "-"333 WHITESPACE@523..524 " "334 EXPR@524..525335 EXPR_NUMBER@524..525336 FLOAT@524..525 "1"337 R_BRACK@525..526 "]"338 COMMA@526..527 ","339 WHITESPACE@527..528 " "340 ARG@528..533341 EXPR@528..533342 EXPR_VAR@528..533343 NAME@528..533344 IDENT@528..533 "chars"345 R_PAREN@533..534 ")"346 WHITESPACE@534..539 "\n "347 ELSE_KW@539..543 "else"348 WHITESPACE@543..550 "\n "349 FALSE_EXPR@550..553350 EXPR@550..553351 EXPR_VAR@550..553352 NAME@550..553353 IDENT@550..553 "str"354 COMMA@553..554 ","355 WHITESPACE@554..558 "\n\n "356 MEMBER_FIELD_METHOD@558..638357 FIELD_NAME_FIXED@558..568358 NAME@558..568359 IDENT@558..568 "stripChars"360 PARAMS_DESC@568..580361 L_PAREN@568..569 "("362 PARAM@569..572363 DESTRUCT_FULL@569..572364 NAME@569..572365 IDENT@569..572 "str"366 COMMA@572..573 ","367 WHITESPACE@573..574 " "368 PARAM@574..579369 DESTRUCT_FULL@574..579370 NAME@574..579371 IDENT@574..579 "chars"372 R_PAREN@579..580 ")"373 COLONCOLON@580..582 "::"374 WHITESPACE@582..587 "\n "375 EXPR@587..638376 EXPR_VAR@587..590377 NAME@587..590378 IDENT@587..590 "std"379 SUFFIX_INDEX@590..602380 DOT@590..591 "."381 NAME@591..602382 IDENT@591..602 "lstripChars"383 SUFFIX_APPLY@602..638384 ARGS_DESC@602..638385 L_PAREN@602..603 "("386 ARG@603..630387 EXPR@603..630388 EXPR_VAR@603..606389 NAME@603..606390 IDENT@603..606 "std"391 SUFFIX_INDEX@606..618392 DOT@606..607 "."393 NAME@607..618394 IDENT@607..618 "rstripChars"395 SUFFIX_APPLY@618..630396 ARGS_DESC@618..630397 L_PAREN@618..619 "("398 ARG@619..622399 EXPR@619..622400 EXPR_VAR@619..622401 NAME@619..622402 IDENT@619..622 "str"403 COMMA@622..623 ","404 WHITESPACE@623..624 " "405 ARG@624..629406 EXPR@624..629407 EXPR_VAR@624..629408 NAME@624..629409 IDENT@624..629 "chars"410 R_PAREN@629..630 ")"411 COMMA@630..631 ","412 WHITESPACE@631..632 " "413 ARG@632..637414 EXPR@632..637415 EXPR_VAR@632..637416 NAME@632..637417 IDENT@632..637 "chars"418 R_PAREN@637..638 ")"419 COMMA@638..639 ","420 WHITESPACE@639..643 "\n\n "421 MEMBER_FIELD_METHOD@643..921422 FIELD_NAME_FIXED@643..654423 NAME@643..654424 IDENT@643..654 "splitLimitR"425 PARAMS_DESC@654..673426 L_PAREN@654..655 "("427 PARAM@655..658428 DESTRUCT_FULL@655..658429 NAME@655..658430 IDENT@655..658 "str"431 COMMA@658..659 ","432 WHITESPACE@659..660 " "433 PARAM@660..661434 DESTRUCT_FULL@660..661435 NAME@660..661436 IDENT@660..661 "c"437 COMMA@661..662 ","438 WHITESPACE@662..663 " "439 PARAM@663..672440 DESTRUCT_FULL@663..672441 NAME@663..672442 IDENT@663..672 "maxsplits"443 R_PAREN@672..673 ")"444 COLONCOLON@673..675 "::"445 WHITESPACE@675..680 "\n "446 EXPR@680..921447 EXPR_IF_THEN_ELSE@680..921448 IF_KW@680..682 "if"449 WHITESPACE@682..683 " "450 EXPR@683..698451 EXPR_BINARY@683..698452 EXPR@683..692453 EXPR_VAR@683..692454 NAME@683..692455 IDENT@683..692 "maxsplits"456 WHITESPACE@692..693 " "457 EQ@693..695 "=="458 WHITESPACE@695..696 " "459 EXPR@696..698460 EXPR_UNARY@696..698461 MINUS@696..697 "-"462 EXPR_NUMBER@697..698463 FLOAT@697..698 "1"464 WHITESPACE@698..699 " "465 THEN_KW@699..703 "then"466 WHITESPACE@703..710 "\n "467 TRUE_EXPR@710..736468 EXPR@710..736469 EXPR_VAR@710..713470 NAME@710..713471 IDENT@710..713 "std"472 SUFFIX_INDEX@713..724473 DOT@713..714 "."474 NAME@714..724475 IDENT@714..724 "splitLimit"476 SUFFIX_APPLY@724..736477 ARGS_DESC@724..736478 L_PAREN@724..725 "("479 ARG@725..728480 EXPR@725..728481 EXPR_VAR@725..728482 NAME@725..728483 IDENT@725..728 "str"484 COMMA@728..729 ","485 WHITESPACE@729..730 " "486 ARG@730..731487 EXPR@730..731488 EXPR_VAR@730..731489 NAME@730..731490 IDENT@730..731 "c"491 COMMA@731..732 ","492 WHITESPACE@732..733 " "493 ARG@733..735494 EXPR@733..735495 EXPR_UNARY@733..735496 MINUS@733..734 "-"497 EXPR_NUMBER@734..735498 FLOAT@734..735 "1"499 R_PAREN@735..736 ")"500 WHITESPACE@736..741 "\n "501 ELSE_KW@741..745 "else"502 WHITESPACE@745..752 "\n "503 FALSE_EXPR@752..921504 EXPR@752..921505 STMT_LOCAL@752..820506 LOCAL_KW@752..757 "local"507 WHITESPACE@757..758 " "508 BIND_FUNCTION@758..819509 NAME@758..764510 IDENT@758..764 "revStr"511 PARAMS_DESC@764..769512 L_PAREN@764..765 "("513 PARAM@765..768514 DESTRUCT_FULL@765..768515 NAME@765..768516 IDENT@765..768 "str"517 R_PAREN@768..769 ")"518 WHITESPACE@769..770 " "519 ASSIGN@770..771 "="520 WHITESPACE@771..772 " "521 EXPR@772..819522 EXPR_VAR@772..775523 NAME@772..775524 IDENT@772..775 "std"525 SUFFIX_INDEX@775..780526 DOT@775..776 "."527 NAME@776..780528 IDENT@776..780 "join"529 SUFFIX_APPLY@780..819530 ARGS_DESC@780..819531 L_PAREN@780..781 "("532 ARG@781..783533 EXPR@781..783534 EXPR_STRING@781..783535 STRING_SINGLE@781..783 "''"536 COMMA@783..784 ","537 WHITESPACE@784..785 " "538 ARG@785..818539 EXPR@785..818540 EXPR_VAR@785..788541 NAME@785..788542 IDENT@785..788 "std"543 SUFFIX_INDEX@788..796544 DOT@788..789 "."545 NAME@789..796546 IDENT@789..796 "reverse"547 SUFFIX_APPLY@796..818548 ARGS_DESC@796..818549 L_PAREN@796..797 "("550 ARG@797..817551 EXPR@797..817552 EXPR_VAR@797..800553 NAME@797..800554 IDENT@797..800 "std"555 SUFFIX_INDEX@800..812556 DOT@800..801 "."557 NAME@801..812558 IDENT@801..812 "stringChars"559 SUFFIX_APPLY@812..817560 ARGS_DESC@812..817561 L_PAREN@812..813 "("562 ARG@813..816563 EXPR@813..816564 EXPR_VAR@813..816565 NAME@813..816566 IDENT@813..816 "str"567 R_PAREN@816..817 ")"568 R_PAREN@817..818 ")"569 R_PAREN@818..819 ")"570 SEMI@819..820 ";"571 WHITESPACE@820..827 "\n "572 EXPR_VAR@827..830573 NAME@827..830574 IDENT@827..830 "std"575 SUFFIX_INDEX@830..834576 DOT@830..831 "."577 NAME@831..834578 IDENT@831..834 "map"579 SUFFIX_APPLY@834..921580 ARGS_DESC@834..921581 L_PAREN@834..835 "("582 ARG@835..856583 EXPR@835..856584 EXPR_FUNCTION@835..856585 FUNCTION_KW@835..843 "function"586 PARAMS_DESC@843..846587 L_PAREN@843..844 "("588 PARAM@844..845589 DESTRUCT_FULL@844..845590 NAME@844..845591 IDENT@844..845 "e"592 R_PAREN@845..846 ")"593 WHITESPACE@846..847 " "594 EXPR@847..856595 EXPR_VAR@847..853596 NAME@847..853597 IDENT@847..853 "revStr"598 SUFFIX_APPLY@853..856599 ARGS_DESC@853..856600 L_PAREN@853..854 "("601 ARG@854..855602 EXPR@854..855603 EXPR_VAR@854..855604 NAME@854..855605 IDENT@854..855 "e"606 R_PAREN@855..856 ")"607 COMMA@856..857 ","608 WHITESPACE@857..858 " "609 ARG@858..920610 EXPR@858..920611 EXPR_VAR@858..861612 NAME@858..861613 IDENT@858..861 "std"614 SUFFIX_INDEX@861..869615 DOT@861..862 "."616 NAME@862..869617 IDENT@862..869 "reverse"618 SUFFIX_APPLY@869..920619 ARGS_DESC@869..920620 L_PAREN@869..870 "("621 ARG@870..919622 EXPR@870..919623 EXPR_VAR@870..873624 NAME@870..873625 IDENT@870..873 "std"626 SUFFIX_INDEX@873..884627 DOT@873..874 "."628 NAME@874..884629 IDENT@874..884 "splitLimit"630 SUFFIX_APPLY@884..919631 ARGS_DESC@884..919632 L_PAREN@884..885 "("633 ARG@885..896634 EXPR@885..896635 EXPR_VAR@885..891636 NAME@885..891637 IDENT@885..891 "revStr"638 SUFFIX_APPLY@891..896639 ARGS_DESC@891..896640 L_PAREN@891..892 "("641 ARG@892..895642 EXPR@892..895643 EXPR_VAR@892..895644 NAME@892..895645 IDENT@892..895 "str"646 R_PAREN@895..896 ")"647 COMMA@896..897 ","648 WHITESPACE@897..898 " "649 ARG@898..907650 EXPR@898..907651 EXPR_VAR@898..904652 NAME@898..904653 IDENT@898..904 "revStr"654 SUFFIX_APPLY@904..907655 ARGS_DESC@904..907656 L_PAREN@904..905 "("657 ARG@905..906658 EXPR@905..906659 EXPR_VAR@905..906660 NAME@905..906661 IDENT@905..906 "c"662 R_PAREN@906..907 ")"663 COMMA@907..908 ","664 WHITESPACE@908..909 " "665 ARG@909..918666 EXPR@909..918667 EXPR_VAR@909..918668 NAME@909..918669 IDENT@909..918 "maxsplits"670 R_PAREN@918..919 ")"671 R_PAREN@919..920 ")"672 R_PAREN@920..921 ")"673 COMMA@921..922 ","674 WHITESPACE@922..926 "\n\n "675 MEMBER_FIELD_METHOD@926..968676 FIELD_NAME_FIXED@926..931677 NAME@926..931678 IDENT@926..931 "split"679 PARAMS_DESC@931..939680 L_PAREN@931..932 "("681 PARAM@932..935682 DESTRUCT_FULL@932..935683 NAME@932..935684 IDENT@932..935 "str"685 COMMA@935..936 ","686 WHITESPACE@936..937 " "687 PARAM@937..938688 DESTRUCT_FULL@937..938689 NAME@937..938690 IDENT@937..938 "c"691 R_PAREN@938..939 ")"692 COLONCOLON@939..941 "::"693 WHITESPACE@941..942 " "694 EXPR@942..968695 EXPR_VAR@942..945696 NAME@942..945697 IDENT@942..945 "std"698 SUFFIX_INDEX@945..956699 DOT@945..946 "."700 NAME@946..956701 IDENT@946..956 "splitLimit"702 SUFFIX_APPLY@956..968703 ARGS_DESC@956..968704 L_PAREN@956..957 "("705 ARG@957..960706 EXPR@957..960707 EXPR_VAR@957..960708 NAME@957..960709 IDENT@957..960 "str"710 COMMA@960..961 ","711 WHITESPACE@961..962 " "712 ARG@962..963713 EXPR@962..963714 EXPR_VAR@962..963715 NAME@962..963716 IDENT@962..963 "c"717 COMMA@963..964 ","718 WHITESPACE@964..965 " "719 ARG@965..967720 EXPR@965..967721 EXPR_UNARY@965..967722 MINUS@965..966 "-"723 EXPR_NUMBER@966..967724 FLOAT@966..967 "1"725 R_PAREN@967..968 ")"726 COMMA@968..969 ","727 WHITESPACE@969..973 "\n\n "728 MEMBER_FIELD_METHOD@973..1331729 FIELD_NAME_FIXED@973..985730 NAME@973..985731 IDENT@973..985 "mapWithIndex"732 PARAMS_DESC@985..996733 L_PAREN@985..986 "("734 PARAM@986..990735 DESTRUCT_FULL@986..990736 NAME@986..990737 IDENT@986..990 "func"738 COMMA@990..991 ","739 WHITESPACE@991..992 " "740 PARAM@992..995741 DESTRUCT_FULL@992..995742 NAME@992..995743 IDENT@992..995 "arr"744 R_PAREN@995..996 ")"745 COLONCOLON@996..998 "::"746 WHITESPACE@998..1003 "\n "747 EXPR@1003..1331748 EXPR_IF_THEN_ELSE@1003..1331749 IF_KW@1003..1005 "if"750 WHITESPACE@1005..1006 " "751 EXPR@1006..1027752 EXPR_UNARY@1006..1027753 NOT@1006..1007 "!"754 EXPR_VAR@1007..1010755 NAME@1007..1010756 IDENT@1007..1010 "std"757 SUFFIX_INDEX@1010..1021758 DOT@1010..1011 "."759 NAME@1011..1021760 IDENT@1011..1021 "isFunction"761 SUFFIX_APPLY@1021..1027762 ARGS_DESC@1021..1027763 L_PAREN@1021..1022 "("764 ARG@1022..1026765 EXPR@1022..1026766 EXPR_VAR@1022..1026767 NAME@1022..1026768 IDENT@1022..1026 "func"769 R_PAREN@1026..1027 ")"770 WHITESPACE@1027..1028 " "771 THEN_KW@1028..1032 "then"772 WHITESPACE@1032..1039 "\n "773 TRUE_EXPR@1039..1117774 EXPR@1039..1117775 EXPR_ERROR@1039..1117776 ERROR_KW@1039..1044 "error"777 WHITESPACE@1044..1045 " "778 EXPR@1045..1117779 EXPR_PARENED@1045..1117780 L_PAREN@1045..1046 "("781 EXPR@1046..1116782 EXPR_BINARY@1046..1116783 EXPR@1046..1099784 EXPR_STRING@1046..1099785 STRING_SINGLE@1046..1099 "'std.mapWithIndex fir ..."786 WHITESPACE@1099..1100 " "787 PLUS@1100..1101 "+"788 WHITESPACE@1101..1102 " "789 EXPR@1102..1116790 EXPR_VAR@1102..1105791 NAME@1102..1105792 IDENT@1102..1105 "std"793 SUFFIX_INDEX@1105..1110794 DOT@1105..1106 "."795 NAME@1106..1110796 IDENT@1106..1110 "type"797 SUFFIX_APPLY@1110..1116798 ARGS_DESC@1110..1116799 L_PAREN@1110..1111 "("800 ARG@1111..1115801 EXPR@1111..1115802 EXPR_VAR@1111..1115803 NAME@1111..1115804 IDENT@1111..1115 "func"805 R_PAREN@1115..1116 ")"806 R_PAREN@1116..1117 ")"807 WHITESPACE@1117..1122 "\n "808 ELSE_KW@1122..1126 "else"809 WHITESPACE@1126..1127 " "810 FALSE_EXPR@1127..1331811 EXPR@1127..1331812 EXPR_IF_THEN_ELSE@1127..1331813 IF_KW@1127..1129 "if"814 WHITESPACE@1129..1130 " "815 EXPR@1130..1169816 EXPR_BINARY@1130..1169817 EXPR@1130..1147818 EXPR_UNARY@1130..1147819 NOT@1130..1131 "!"820 EXPR_VAR@1131..1134821 NAME@1131..1134822 IDENT@1131..1134 "std"823 SUFFIX_INDEX@1134..1142824 DOT@1134..1135 "."825 NAME@1135..1142826 IDENT@1135..1142 "isArray"827 SUFFIX_APPLY@1142..1147828 ARGS_DESC@1142..1147829 L_PAREN@1142..1143 "("830 ARG@1143..1146831 EXPR@1143..1146832 EXPR_VAR@1143..1146833 NAME@1143..1146834 IDENT@1143..1146 "arr"835 R_PAREN@1146..1147 ")"836 WHITESPACE@1147..1148 " "837 AND@1148..1150 "&&"838 WHITESPACE@1150..1151 " "839 EXPR@1151..1169840 EXPR_UNARY@1151..1169841 NOT@1151..1152 "!"842 EXPR_VAR@1152..1155843 NAME@1152..1155844 IDENT@1152..1155 "std"845 SUFFIX_INDEX@1155..1164846 DOT@1155..1156 "."847 NAME@1156..1164848 IDENT@1156..1164 "isString"849 SUFFIX_APPLY@1164..1169850 ARGS_DESC@1164..1169851 L_PAREN@1164..1165 "("852 ARG@1165..1168853 EXPR@1165..1168854 EXPR_VAR@1165..1168855 NAME@1165..1168856 IDENT@1165..1168 "arr"857 R_PAREN@1168..1169 ")"858 WHITESPACE@1169..1170 " "859 THEN_KW@1170..1174 "then"860 WHITESPACE@1174..1181 "\n "861 TRUE_EXPR@1181..1256862 EXPR@1181..1256863 EXPR_ERROR@1181..1256864 ERROR_KW@1181..1186 "error"865 WHITESPACE@1186..1187 " "866 EXPR@1187..1256867 EXPR_PARENED@1187..1256868 L_PAREN@1187..1188 "("869 EXPR@1188..1255870 EXPR_BINARY@1188..1255871 EXPR@1188..1239872 EXPR_STRING@1188..1239873 STRING_SINGLE@1188..1239 "'std.mapWithIndex sec ..."874 WHITESPACE@1239..1240 " "875 PLUS@1240..1241 "+"876 WHITESPACE@1241..1242 " "877 EXPR@1242..1255878 EXPR_VAR@1242..1245879 NAME@1242..1245880 IDENT@1242..1245 "std"881 SUFFIX_INDEX@1245..1250882 DOT@1245..1246 "."883 NAME@1246..1250884 IDENT@1246..1250 "type"885 SUFFIX_APPLY@1250..1255886 ARGS_DESC@1250..1255887 L_PAREN@1250..1251 "("888 ARG@1251..1254889 EXPR@1251..1254890 EXPR_VAR@1251..1254891 NAME@1251..1254892 IDENT@1251..1254 "arr"893 R_PAREN@1254..1255 ")"894 R_PAREN@1255..1256 ")"895 WHITESPACE@1256..1261 "\n "896 ELSE_KW@1261..1265 "else"897 WHITESPACE@1265..1272 "\n "898 FALSE_EXPR@1272..1331899 EXPR@1272..1331900 EXPR_VAR@1272..1275901 NAME@1272..1275902 IDENT@1272..1275 "std"903 SUFFIX_INDEX@1275..1285904 DOT@1275..1276 "."905 NAME@1276..1285906 IDENT@1276..1285 "makeArray"907 SUFFIX_APPLY@1285..1331908 ARGS_DESC@1285..1331909 L_PAREN@1285..1286 "("910 ARG@1286..1301911 EXPR@1286..1301912 EXPR_VAR@1286..1289913 NAME@1286..1289914 IDENT@1286..1289 "std"915 SUFFIX_INDEX@1289..1296916 DOT@1289..1290 "."917 NAME@1290..1296918 IDENT@1290..1296 "length"919 SUFFIX_APPLY@1296..1301920 ARGS_DESC@1296..1301921 L_PAREN@1296..1297 "("922 ARG@1297..1300923 EXPR@1297..1300924 EXPR_VAR@1297..1300925 NAME@1297..1300926 IDENT@1297..1300 "arr"927 R_PAREN@1300..1301 ")"928 COMMA@1301..1302 ","929 WHITESPACE@1302..1303 " "930 ARG@1303..1330931 EXPR@1303..1330932 EXPR_FUNCTION@1303..1330933 FUNCTION_KW@1303..1311 "function"934 PARAMS_DESC@1311..1314935 L_PAREN@1311..1312 "("936 PARAM@1312..1313937 DESTRUCT_FULL@1312..1313938 NAME@1312..1313939 IDENT@1312..1313 "i"940 R_PAREN@1313..1314 ")"941 WHITESPACE@1314..1315 " "942 EXPR@1315..1330943 EXPR_VAR@1315..1319944 NAME@1315..1319945 IDENT@1315..1319 "func"946 SUFFIX_APPLY@1319..1330947 ARGS_DESC@1319..1330948 L_PAREN@1319..1320 "("949 ARG@1320..1321950 EXPR@1320..1321951 EXPR_VAR@1320..1321952 NAME@1320..1321953 IDENT@1320..1321 "i"954 COMMA@1321..1322 ","955 WHITESPACE@1322..1323 " "956 ARG@1323..1329957 EXPR@1323..1329958 EXPR_VAR@1323..1326959 NAME@1323..1326960 IDENT@1323..1326 "arr"961 SUFFIX_INDEX_EXPR@1326..1329962 L_BRACK@1326..1327 "["963 EXPR@1327..1328964 EXPR_VAR@1327..1328965 NAME@1327..1328966 IDENT@1327..1328 "i"967 R_BRACK@1328..1329 "]"968 R_PAREN@1329..1330 ")"969 R_PAREN@1330..1331 ")"970 COMMA@1331..1332 ","971 WHITESPACE@1332..1336 "\n\n "972 MEMBER_FIELD_METHOD@1336..1664973 FIELD_NAME_FIXED@1336..1346974 NAME@1336..1346975 IDENT@1336..1346 "mapWithKey"976 PARAMS_DESC@1346..1357977 L_PAREN@1346..1347 "("978 PARAM@1347..1351979 DESTRUCT_FULL@1347..1351980 NAME@1347..1351981 IDENT@1347..1351 "func"982 COMMA@1351..1352 ","983 WHITESPACE@1352..1353 " "984 PARAM@1353..1356985 DESTRUCT_FULL@1353..1356986 NAME@1353..1356987 IDENT@1353..1356 "obj"988 R_PAREN@1356..1357 ")"989 COLONCOLON@1357..1359 "::"990 WHITESPACE@1359..1364 "\n "991 EXPR@1364..1664992 EXPR_IF_THEN_ELSE@1364..1664993 IF_KW@1364..1366 "if"994 WHITESPACE@1366..1367 " "995 EXPR@1367..1388996 EXPR_UNARY@1367..1388997 NOT@1367..1368 "!"998 EXPR_VAR@1368..1371999 NAME@1368..13711000 IDENT@1368..1371 "std"1001 SUFFIX_INDEX@1371..13821002 DOT@1371..1372 "."1003 NAME@1372..13821004 IDENT@1372..1382 "isFunction"1005 SUFFIX_APPLY@1382..13881006 ARGS_DESC@1382..13881007 L_PAREN@1382..1383 "("1008 ARG@1383..13871009 EXPR@1383..13871010 EXPR_VAR@1383..13871011 NAME@1383..13871012 IDENT@1383..1387 "func"1013 R_PAREN@1387..1388 ")"1014 WHITESPACE@1388..1389 " "1015 THEN_KW@1389..1393 "then"1016 WHITESPACE@1393..1400 "\n "1017 TRUE_EXPR@1400..14761018 EXPR@1400..14761019 EXPR_ERROR@1400..14761020 ERROR_KW@1400..1405 "error"1021 WHITESPACE@1405..1406 " "1022 EXPR@1406..14761023 EXPR_PARENED@1406..14761024 L_PAREN@1406..1407 "("1025 EXPR@1407..14751026 EXPR_BINARY@1407..14751027 EXPR@1407..14581028 EXPR_STRING@1407..14581029 STRING_SINGLE@1407..1458 "'std.mapWithKey first ..."1030 WHITESPACE@1458..1459 " "1031 PLUS@1459..1460 "+"1032 WHITESPACE@1460..1461 " "1033 EXPR@1461..14751034 EXPR_VAR@1461..14641035 NAME@1461..14641036 IDENT@1461..1464 "std"1037 SUFFIX_INDEX@1464..14691038 DOT@1464..1465 "."1039 NAME@1465..14691040 IDENT@1465..1469 "type"1041 SUFFIX_APPLY@1469..14751042 ARGS_DESC@1469..14751043 L_PAREN@1469..1470 "("1044 ARG@1470..14741045 EXPR@1470..14741046 EXPR_VAR@1470..14741047 NAME@1470..14741048 IDENT@1470..1474 "func"1049 R_PAREN@1474..1475 ")"1050 R_PAREN@1475..1476 ")"1051 WHITESPACE@1476..1481 "\n "1052 ELSE_KW@1481..1485 "else"1053 WHITESPACE@1485..1486 " "1054 FALSE_EXPR@1486..16641055 EXPR@1486..16641056 EXPR_IF_THEN_ELSE@1486..16641057 IF_KW@1486..1488 "if"1058 WHITESPACE@1488..1489 " "1059 EXPR@1489..15071060 EXPR_UNARY@1489..15071061 NOT@1489..1490 "!"1062 EXPR_VAR@1490..14931063 NAME@1490..14931064 IDENT@1490..1493 "std"1065 SUFFIX_INDEX@1493..15021066 DOT@1493..1494 "."1067 NAME@1494..15021068 IDENT@1494..1502 "isObject"1069 SUFFIX_APPLY@1502..15071070 ARGS_DESC@1502..15071071 L_PAREN@1502..1503 "("1072 ARG@1503..15061073 EXPR@1503..15061074 EXPR_VAR@1503..15061075 NAME@1503..15061076 IDENT@1503..1506 "obj"1077 R_PAREN@1506..1507 ")"1078 WHITESPACE@1507..1508 " "1079 THEN_KW@1508..1512 "then"1080 WHITESPACE@1512..1519 "\n "1081 TRUE_EXPR@1519..15931082 EXPR@1519..15931083 EXPR_ERROR@1519..15931084 ERROR_KW@1519..1524 "error"1085 WHITESPACE@1524..1525 " "1086 EXPR@1525..15931087 EXPR_PARENED@1525..15931088 L_PAREN@1525..1526 "("1089 EXPR@1526..15921090 EXPR_BINARY@1526..15921091 EXPR@1526..15761092 EXPR_STRING@1526..15761093 STRING_SINGLE@1526..1576 "'std.mapWithKey secon ..."1094 WHITESPACE@1576..1577 " "1095 PLUS@1577..1578 "+"1096 WHITESPACE@1578..1579 " "1097 EXPR@1579..15921098 EXPR_VAR@1579..15821099 NAME@1579..15821100 IDENT@1579..1582 "std"1101 SUFFIX_INDEX@1582..15871102 DOT@1582..1583 "."1103 NAME@1583..15871104 IDENT@1583..1587 "type"1105 SUFFIX_APPLY@1587..15921106 ARGS_DESC@1587..15921107 L_PAREN@1587..1588 "("1108 ARG@1588..15911109 EXPR@1588..15911110 EXPR_VAR@1588..15911111 NAME@1588..15911112 IDENT@1588..1591 "obj"1113 R_PAREN@1591..1592 ")"1114 R_PAREN@1592..1593 ")"1115 WHITESPACE@1593..1598 "\n "1116 ELSE_KW@1598..1602 "else"1117 WHITESPACE@1602..1609 "\n "1118 FALSE_EXPR@1609..16641119 EXPR@1609..16641120 EXPR_OBJECT@1609..16641121 OBJ_BODY_COMP@1609..16641122 L_BRACE@1609..1610 "{"1123 WHITESPACE@1610..1611 " "1124 MEMBER_FIELD_NORMAL@1611..16311125 FIELD_NAME_DYNAMIC@1611..16141126 L_BRACK@1611..1612 "["1127 EXPR@1612..16131128 EXPR_VAR@1612..16131129 NAME@1612..16131130 IDENT@1612..1613 "k"1131 R_BRACK@1613..1614 "]"1132 COLON@1614..1615 ":"1133 WHITESPACE@1615..1616 " "1134 EXPR@1616..16311135 EXPR_VAR@1616..16201136 NAME@1616..16201137 IDENT@1616..1620 "func"1138 SUFFIX_APPLY@1620..16311139 ARGS_DESC@1620..16311140 L_PAREN@1620..1621 "("1141 ARG@1621..16221142 EXPR@1621..16221143 EXPR_VAR@1621..16221144 NAME@1621..16221145 IDENT@1621..1622 "k"1146 COMMA@1622..1623 ","1147 WHITESPACE@1623..1624 " "1148 ARG@1624..16301149 EXPR@1624..16301150 EXPR_VAR@1624..16271151 NAME@1624..16271152 IDENT@1624..1627 "obj"1153 SUFFIX_INDEX_EXPR@1627..16301154 L_BRACK@1627..1628 "["1155 EXPR@1628..16291156 EXPR_VAR@1628..16291157 NAME@1628..16291158 IDENT@1628..1629 "k"1159 R_BRACK@1629..1630 "]"1160 R_PAREN@1630..1631 ")"1161 WHITESPACE@1631..1632 " "1162 FOR_SPEC@1632..16621163 FOR_KW@1632..1635 "for"1164 WHITESPACE@1635..1636 " "1165 DESTRUCT_FULL@1636..16371166 NAME@1636..16371167 IDENT@1636..1637 "k"1168 WHITESPACE@1637..1638 " "1169 IN_KW@1638..1640 "in"1170 WHITESPACE@1640..1641 " "1171 EXPR@1641..16621172 EXPR_VAR@1641..16441173 NAME@1641..16441174 IDENT@1641..1644 "std"1175 SUFFIX_INDEX@1644..16571176 DOT@1644..1645 "."1177 NAME@1645..16571178 IDENT@1645..1657 "objectFields"1179 SUFFIX_APPLY@1657..16621180 ARGS_DESC@1657..16621181 L_PAREN@1657..1658 "("1182 ARG@1658..16611183 EXPR@1658..16611184 EXPR_VAR@1658..16611185 NAME@1658..16611186 IDENT@1658..1661 "obj"1187 R_PAREN@1661..1662 ")"1188 WHITESPACE@1662..1663 " "1189 R_BRACE@1663..1664 "}"1190 COMMA@1664..1665 ","1191 WHITESPACE@1665..1669 "\n\n "1192 MEMBER_FIELD_METHOD@1669..17121193 FIELD_NAME_FIXED@1669..16741194 NAME@1669..16741195 IDENT@1669..1674 "lines"1196 PARAMS_DESC@1674..16791197 L_PAREN@1674..1675 "("1198 PARAM@1675..16781199 DESTRUCT_FULL@1675..16781200 NAME@1675..16781201 IDENT@1675..1678 "arr"1202 R_PAREN@1678..1679 ")"1203 COLONCOLON@1679..1681 "::"1204 WHITESPACE@1681..1686 "\n "1205 EXPR@1686..17121206 EXPR_VAR@1686..16891207 NAME@1686..16891208 IDENT@1686..1689 "std"1209 SUFFIX_INDEX@1689..16941210 DOT@1689..1690 "."1211 NAME@1690..16941212 IDENT@1690..1694 "join"1213 SUFFIX_APPLY@1694..17121214 ARGS_DESC@1694..17121215 L_PAREN@1694..1695 "("1216 ARG@1695..16991217 EXPR@1695..16991218 EXPR_STRING@1695..16991219 STRING_SINGLE@1695..1699 "'\\n'"1220 COMMA@1699..1700 ","1221 WHITESPACE@1700..1701 " "1222 ARG@1701..17111223 EXPR@1701..17111224 EXPR_BINARY@1701..17111225 EXPR@1701..17041226 EXPR_VAR@1701..17041227 NAME@1701..17041228 IDENT@1701..1704 "arr"1229 WHITESPACE@1704..1705 " "1230 PLUS@1705..1706 "+"1231 WHITESPACE@1706..1707 " "1232 EXPR@1707..17111233 EXPR_ARRAY@1707..17111234 L_BRACK@1707..1708 "["1235 EXPR@1708..17101236 EXPR_STRING@1708..17101237 STRING_SINGLE@1708..1710 "''"1238 R_BRACK@1710..1711 "]"1239 R_PAREN@1711..1712 ")"1240 COMMA@1712..1713 ","1241 WHITESPACE@1713..1717 "\n\n "1242 MEMBER_FIELD_METHOD@1717..19291243 FIELD_NAME_FIXED@1717..17251244 NAME@1717..17251245 IDENT@1717..1725 "deepJoin"1246 PARAMS_DESC@1725..17301247 L_PAREN@1725..1726 "("1248 PARAM@1726..17291249 DESTRUCT_FULL@1726..17291250 NAME@1726..17291251 IDENT@1726..1729 "arr"1252 R_PAREN@1729..1730 ")"1253 COLONCOLON@1730..1732 "::"1254 WHITESPACE@1732..1737 "\n "1255 EXPR@1737..19291256 EXPR_IF_THEN_ELSE@1737..19291257 IF_KW@1737..1739 "if"1258 WHITESPACE@1739..1740 " "1259 EXPR@1740..17571260 EXPR_VAR@1740..17431261 NAME@1740..17431262 IDENT@1740..1743 "std"1263 SUFFIX_INDEX@1743..17521264 DOT@1743..1744 "."1265 NAME@1744..17521266 IDENT@1744..1752 "isString"1267 SUFFIX_APPLY@1752..17571268 ARGS_DESC@1752..17571269 L_PAREN@1752..1753 "("1270 ARG@1753..17561271 EXPR@1753..17561272 EXPR_VAR@1753..17561273 NAME@1753..17561274 IDENT@1753..1756 "arr"1275 R_PAREN@1756..1757 ")"1276 WHITESPACE@1757..1758 " "1277 THEN_KW@1758..1762 "then"1278 WHITESPACE@1762..1769 "\n "1279 TRUE_EXPR@1769..17721280 EXPR@1769..17721281 EXPR_VAR@1769..17721282 NAME@1769..17721283 IDENT@1769..1772 "arr"1284 WHITESPACE@1772..1777 "\n "1285 ELSE_KW@1777..1781 "else"1286 WHITESPACE@1781..1782 " "1287 FALSE_EXPR@1782..19291288 EXPR@1782..19291289 EXPR_IF_THEN_ELSE@1782..19291290 IF_KW@1782..1784 "if"1291 WHITESPACE@1784..1785 " "1292 EXPR@1785..18011293 EXPR_VAR@1785..17881294 NAME@1785..17881295 IDENT@1785..1788 "std"1296 SUFFIX_INDEX@1788..17961297 DOT@1788..1789 "."1298 NAME@1789..17961299 IDENT@1789..1796 "isArray"1300 SUFFIX_APPLY@1796..18011301 ARGS_DESC@1796..18011302 L_PAREN@1796..1797 "("1303 ARG@1797..18001304 EXPR@1797..18001305 EXPR_VAR@1797..18001306 NAME@1797..18001307 IDENT@1797..1800 "arr"1308 R_PAREN@1800..1801 ")"1309 WHITESPACE@1801..1802 " "1310 THEN_KW@1802..1806 "then"1311 WHITESPACE@1806..1813 "\n "1312 TRUE_EXPR@1813..18571313 EXPR@1813..18571314 EXPR_VAR@1813..18161315 NAME@1813..18161316 IDENT@1813..1816 "std"1317 SUFFIX_INDEX@1816..18211318 DOT@1816..1817 "."1319 NAME@1817..18211320 IDENT@1817..1821 "join"1321 SUFFIX_APPLY@1821..18571322 ARGS_DESC@1821..18571323 L_PAREN@1821..1822 "("1324 ARG@1822..18241325 EXPR@1822..18241326 EXPR_STRING@1822..18241327 STRING_SINGLE@1822..1824 "''"1328 COMMA@1824..1825 ","1329 WHITESPACE@1825..1826 " "1330 ARG@1826..18561331 EXPR@1826..18561332 EXPR_ARRAY_COMP@1826..18561333 L_BRACK@1826..1827 "["1334 EXPR@1827..18421335 EXPR_VAR@1827..18301336 NAME@1827..18301337 IDENT@1827..1830 "std"1338 SUFFIX_INDEX@1830..18391339 DOT@1830..1831 "."1340 NAME@1831..18391341 IDENT@1831..1839 "deepJoin"1342 SUFFIX_APPLY@1839..18421343 ARGS_DESC@1839..18421344 L_PAREN@1839..1840 "("1345 ARG@1840..18411346 EXPR@1840..18411347 EXPR_VAR@1840..18411348 NAME@1840..18411349 IDENT@1840..1841 "x"1350 R_PAREN@1841..1842 ")"1351 WHITESPACE@1842..1843 " "1352 FOR_SPEC@1843..18551353 FOR_KW@1843..1846 "for"1354 WHITESPACE@1846..1847 " "1355 DESTRUCT_FULL@1847..18481356 NAME@1847..18481357 IDENT@1847..1848 "x"1358 WHITESPACE@1848..1849 " "1359 IN_KW@1849..1851 "in"1360 WHITESPACE@1851..1852 " "1361 EXPR@1852..18551362 EXPR_VAR@1852..18551363 NAME@1852..18551364 IDENT@1852..1855 "arr"1365 R_BRACK@1855..1856 "]"1366 R_PAREN@1856..1857 ")"1367 WHITESPACE@1857..1862 "\n "1368 ELSE_KW@1862..1866 "else"1369 WHITESPACE@1866..1873 "\n "1370 FALSE_EXPR@1873..19291371 EXPR@1873..19291372 EXPR_ERROR@1873..19291373 ERROR_KW@1873..1878 "error"1374 WHITESPACE@1878..1879 " "1375 EXPR@1879..19291376 EXPR_BINARY@1879..19291377 EXPR@1879..19131378 EXPR_STRING@1879..19131379 STRING_SINGLE@1879..1913 "'Expected string or a ..."1380 WHITESPACE@1913..1914 " "1381 MODULO@1914..1915 "%"1382 WHITESPACE@1915..1916 " "1383 EXPR@1916..19291384 EXPR_VAR@1916..19191385 NAME@1916..19191386 IDENT@1916..1919 "std"1387 SUFFIX_INDEX@1919..19241388 DOT@1919..1920 "."1389 NAME@1920..19241390 IDENT@1920..1924 "type"1391 SUFFIX_APPLY@1924..19291392 ARGS_DESC@1924..19291393 L_PAREN@1924..1925 "("1394 ARG@1925..19281395 EXPR@1925..19281396 EXPR_VAR@1925..19281397 NAME@1925..19281398 IDENT@1925..1928 "arr"1399 R_PAREN@1928..1929 ")"1400 COMMA@1929..1930 ","1401 WHITESPACE@1930..1934 "\n\n "1402 MEMBER_FIELD_METHOD@1934..20421403 FIELD_NAME_FIXED@1934..19451404 NAME@1934..19451405 IDENT@1934..1945 "assertEqual"1406 PARAMS_DESC@1945..19511407 L_PAREN@1945..1946 "("1408 PARAM@1946..19471409 DESTRUCT_FULL@1946..19471410 NAME@1946..19471411 IDENT@1946..1947 "a"1412 COMMA@1947..1948 ","1413 WHITESPACE@1948..1949 " "1414 PARAM@1949..19501415 DESTRUCT_FULL@1949..19501416 NAME@1949..19501417 IDENT@1949..1950 "b"1418 R_PAREN@1950..1951 ")"1419 COLONCOLON@1951..1953 "::"1420 WHITESPACE@1953..1958 "\n "1421 EXPR@1958..20421422 EXPR_IF_THEN_ELSE@1958..20421423 IF_KW@1958..1960 "if"1424 WHITESPACE@1960..1961 " "1425 EXPR@1961..19671426 EXPR_BINARY@1961..19671427 EXPR@1961..19621428 EXPR_VAR@1961..19621429 NAME@1961..19621430 IDENT@1961..1962 "a"1431 WHITESPACE@1962..1963 " "1432 EQ@1963..1965 "=="1433 WHITESPACE@1965..1966 " "1434 EXPR@1966..19671435 EXPR_VAR@1966..19671436 NAME@1966..19671437 IDENT@1966..1967 "b"1438 WHITESPACE@1967..1968 " "1439 THEN_KW@1968..1972 "then"1440 WHITESPACE@1972..1979 "\n "1441 TRUE_EXPR@1979..19831442 EXPR@1979..19831443 EXPR_LITERAL@1979..19831444 TRUE_KW@1979..1983 "true"1445 WHITESPACE@1983..1988 "\n "1446 ELSE_KW@1988..1992 "else"1447 WHITESPACE@1992..1999 "\n "1448 FALSE_EXPR@1999..20421449 EXPR@1999..20421450 EXPR_ERROR@1999..20421451 ERROR_KW@1999..2004 "error"1452 WHITESPACE@2004..2005 " "1453 EXPR@2005..20421454 EXPR_BINARY@2005..20421455 EXPR@2005..20381456 EXPR_BINARY@2005..20381457 EXPR@2005..20291458 EXPR_BINARY@2005..20291459 EXPR@2005..20251460 EXPR_STRING@2005..20251461 STRING_SINGLE@2005..2025 "'Assertion failed. '"1462 WHITESPACE@2025..2026 " "1463 PLUS@2026..2027 "+"1464 WHITESPACE@2027..2028 " "1465 EXPR@2028..20291466 EXPR_VAR@2028..20291467 NAME@2028..20291468 IDENT@2028..2029 "a"1469 WHITESPACE@2029..2030 " "1470 PLUS@2030..2031 "+"1471 WHITESPACE@2031..2032 " "1472 EXPR@2032..20381473 EXPR_STRING@2032..20381474 STRING_SINGLE@2032..2038 "' != '"1475 WHITESPACE@2038..2039 " "1476 PLUS@2039..2040 "+"1477 WHITESPACE@2040..2041 " "1478 EXPR@2041..20421479 EXPR_VAR@2041..20421480 NAME@2041..20421481 IDENT@2041..2042 "b"1482 COMMA@2042..2043 ","1483 WHITESPACE@2043..2047 "\n\n "1484 MEMBER_FIELD_METHOD@2047..21491485 FIELD_NAME_FIXED@2047..20521486 NAME@2047..20521487 IDENT@2047..2052 "clamp"1488 PARAMS_DESC@2052..20711489 L_PAREN@2052..2053 "("1490 PARAM@2053..20541491 DESTRUCT_FULL@2053..20541492 NAME@2053..20541493 IDENT@2053..2054 "x"1494 COMMA@2054..2055 ","1495 WHITESPACE@2055..2056 " "1496 PARAM@2056..20621497 DESTRUCT_FULL@2056..20621498 NAME@2056..20621499 IDENT@2056..2062 "minVal"1500 COMMA@2062..2063 ","1501 WHITESPACE@2063..2064 " "1502 PARAM@2064..20701503 DESTRUCT_FULL@2064..20701504 NAME@2064..20701505 IDENT@2064..2070 "maxVal"1506 R_PAREN@2070..2071 ")"1507 COLONCOLON@2071..2073 "::"1508 WHITESPACE@2073..2078 "\n "1509 EXPR@2078..21491510 EXPR_IF_THEN_ELSE@2078..21491511 IF_KW@2078..2080 "if"1512 WHITESPACE@2080..2081 " "1513 EXPR@2081..20911514 EXPR_BINARY@2081..20911515 EXPR@2081..20821516 EXPR_VAR@2081..20821517 NAME@2081..20821518 IDENT@2081..2082 "x"1519 WHITESPACE@2082..2083 " "1520 LT@2083..2084 "<"1521 WHITESPACE@2084..2085 " "1522 EXPR@2085..20911523 EXPR_VAR@2085..20911524 NAME@2085..20911525 IDENT@2085..2091 "minVal"1526 WHITESPACE@2091..2092 " "1527 THEN_KW@2092..2096 "then"1528 WHITESPACE@2096..2097 " "1529 TRUE_EXPR@2097..21031530 EXPR@2097..21031531 EXPR_VAR@2097..21031532 NAME@2097..21031533 IDENT@2097..2103 "minVal"1534 WHITESPACE@2103..2108 "\n "1535 ELSE_KW@2108..2112 "else"1536 WHITESPACE@2112..2113 " "1537 FALSE_EXPR@2113..21491538 EXPR@2113..21491539 EXPR_IF_THEN_ELSE@2113..21491540 IF_KW@2113..2115 "if"1541 WHITESPACE@2115..2116 " "1542 EXPR@2116..21261543 EXPR_BINARY@2116..21261544 EXPR@2116..21171545 EXPR_VAR@2116..21171546 NAME@2116..21171547 IDENT@2116..2117 "x"1548 WHITESPACE@2117..2118 " "1549 GT@2118..2119 ">"1550 WHITESPACE@2119..2120 " "1551 EXPR@2120..21261552 EXPR_VAR@2120..21261553 NAME@2120..21261554 IDENT@2120..2126 "maxVal"1555 WHITESPACE@2126..2127 " "1556 THEN_KW@2127..2131 "then"1557 WHITESPACE@2131..2132 " "1558 TRUE_EXPR@2132..21381559 EXPR@2132..21381560 EXPR_VAR@2132..21381561 NAME@2132..21381562 IDENT@2132..2138 "maxVal"1563 WHITESPACE@2138..2143 "\n "1564 ELSE_KW@2143..2147 "else"1565 WHITESPACE@2147..2148 " "1566 FALSE_EXPR@2148..21491567 EXPR@2148..21491568 EXPR_VAR@2148..21491569 NAME@2148..21491570 IDENT@2148..2149 "x"1571 COMMA@2149..2150 ","1572 WHITESPACE@2150..2154 "\n\n "1573 MEMBER_FIELD_METHOD@2154..28401574 FIELD_NAME_FIXED@2154..21651575 NAME@2154..21651576 IDENT@2154..2165 "manifestIni"1577 PARAMS_DESC@2165..21701578 L_PAREN@2165..2166 "("1579 PARAM@2166..21691580 DESTRUCT_FULL@2166..21691581 NAME@2166..21691582 IDENT@2166..2169 "ini"1583 R_PAREN@2169..2170 ")"1584 COLONCOLON@2170..2172 "::"1585 WHITESPACE@2172..2177 "\n "1586 EXPR@2177..28401587 STMT_LOCAL@2177..24811588 LOCAL_KW@2177..2182 "local"1589 WHITESPACE@2182..2183 " "1590 BIND_FUNCTION@2183..24801591 NAME@2183..21931592 IDENT@2183..2193 "body_lines"1593 PARAMS_DESC@2193..21991594 L_PAREN@2193..2194 "("1595 PARAM@2194..21981596 DESTRUCT_FULL@2194..21981597 NAME@2194..21981598 IDENT@2194..2198 "body"1599 R_PAREN@2198..2199 ")"1600 WHITESPACE@2199..2200 " "1601 ASSIGN@2200..2201 "="1602 WHITESPACE@2201..2208 "\n "1603 EXPR@2208..24801604 EXPR_VAR@2208..22111605 NAME@2208..22111606 IDENT@2208..2211 "std"1607 SUFFIX_INDEX@2211..22161608 DOT@2211..2212 "."1609 NAME@2212..22161610 IDENT@2212..2216 "join"1611 SUFFIX_APPLY@2216..24801612 ARGS_DESC@2216..24801613 L_PAREN@2216..2217 "("1614 ARG@2217..22191615 EXPR@2217..22191616 EXPR_ARRAY@2217..22191617 L_BRACK@2217..2218 "["1618 R_BRACK@2218..2219 "]"1619 COMMA@2219..2220 ","1620 WHITESPACE@2220..2221 " "1621 ARG@2221..24791622 EXPR@2221..24791623 EXPR_ARRAY_COMP@2221..24791624 L_BRACK@2221..2222 "["1625 WHITESPACE@2222..2231 "\n "1626 EXPR@2231..24301627 STMT_LOCAL@2231..22631628 LOCAL_KW@2231..2236 "local"1629 WHITESPACE@2236..2237 " "1630 BIND_DESTRUCT@2237..22621631 DESTRUCT_FULL@2237..22521632 NAME@2237..22521633 IDENT@2237..2252 "value_or_values"1634 WHITESPACE@2252..2253 " "1635 ASSIGN@2253..2254 "="1636 WHITESPACE@2254..2255 " "1637 EXPR@2255..22621638 EXPR_VAR@2255..22591639 NAME@2255..22591640 IDENT@2255..2259 "body"1641 SUFFIX_INDEX_EXPR@2259..22621642 L_BRACK@2259..2260 "["1643 EXPR@2260..22611644 EXPR_VAR@2260..22611645 NAME@2260..22611646 IDENT@2260..2261 "k"1647 R_BRACK@2261..2262 "]"1648 SEMI@2262..2263 ";"1649 WHITESPACE@2263..2272 "\n "1650 EXPR_IF_THEN_ELSE@2272..24301651 IF_KW@2272..2274 "if"1652 WHITESPACE@2274..2275 " "1653 EXPR@2275..23031654 EXPR_VAR@2275..22781655 NAME@2275..22781656 IDENT@2275..2278 "std"1657 SUFFIX_INDEX@2278..22861658 DOT@2278..2279 "."1659 NAME@2279..22861660 IDENT@2279..2286 "isArray"1661 SUFFIX_APPLY@2286..23031662 ARGS_DESC@2286..23031663 L_PAREN@2286..2287 "("1664 ARG@2287..23021665 EXPR@2287..23021666 EXPR_VAR@2287..23021667 NAME@2287..23021668 IDENT@2287..2302 "value_or_values"1669 R_PAREN@2302..2303 ")"1670 WHITESPACE@2303..2304 " "1671 THEN_KW@2304..2308 "then"1672 WHITESPACE@2308..2319 "\n "1673 TRUE_EXPR@2319..23721674 EXPR@2319..23721675 EXPR_ARRAY_COMP@2319..23721676 L_BRACK@2319..2320 "["1677 EXPR@2320..23421678 EXPR_BINARY@2320..23421679 EXPR@2320..23291680 EXPR_STRING@2320..23291681 STRING_SINGLE@2320..2329 "'%s = %s'"1682 WHITESPACE@2329..2330 " "1683 MODULO@2330..2331 "%"1684 WHITESPACE@2331..2332 " "1685 EXPR@2332..23421686 EXPR_ARRAY@2332..23421687 L_BRACK@2332..2333 "["1688 EXPR@2333..23341689 EXPR_VAR@2333..23341690 NAME@2333..23341691 IDENT@2333..2334 "k"1692 COMMA@2334..2335 ","1693 WHITESPACE@2335..2336 " "1694 EXPR@2336..23411695 EXPR_VAR@2336..23411696 NAME@2336..23411697 IDENT@2336..2341 "value"1698 R_BRACK@2341..2342 "]"1699 WHITESPACE@2342..2343 " "1700 FOR_SPEC@2343..23711701 FOR_KW@2343..2346 "for"1702 WHITESPACE@2346..2347 " "1703 DESTRUCT_FULL@2347..23521704 NAME@2347..23521705 IDENT@2347..2352 "value"1706 WHITESPACE@2352..2353 " "1707 IN_KW@2353..2355 "in"1708 WHITESPACE@2355..2356 " "1709 EXPR@2356..23711710 EXPR_VAR@2356..23711711 NAME@2356..23711712 IDENT@2356..2371 "value_or_values"1713 R_BRACK@2371..2372 "]"1714 WHITESPACE@2372..2381 "\n "1715 ELSE_KW@2381..2385 "else"1716 WHITESPACE@2385..2396 "\n "1717 FALSE_EXPR@2396..24301718 EXPR@2396..24301719 EXPR_ARRAY@2396..24301720 L_BRACK@2396..2397 "["1721 EXPR@2397..24291722 EXPR_BINARY@2397..24291723 EXPR@2397..24061724 EXPR_STRING@2397..24061725 STRING_SINGLE@2397..2406 "'%s = %s'"1726 WHITESPACE@2406..2407 " "1727 MODULO@2407..2408 "%"1728 WHITESPACE@2408..2409 " "1729 EXPR@2409..24291730 EXPR_ARRAY@2409..24291731 L_BRACK@2409..2410 "["1732 EXPR@2410..24111733 EXPR_VAR@2410..24111734 NAME@2410..24111735 IDENT@2410..2411 "k"1736 COMMA@2411..2412 ","1737 WHITESPACE@2412..2413 " "1738 EXPR@2413..24281739 EXPR_VAR@2413..24281740 NAME@2413..24281741 IDENT@2413..2428 "value_or_values"1742 R_BRACK@2428..2429 "]"1743 R_BRACK@2429..2430 "]"1744 WHITESPACE@2430..2440 "\n\n "1745 FOR_SPEC@2440..24711746 FOR_KW@2440..2443 "for"1747 WHITESPACE@2443..2444 " "1748 DESTRUCT_FULL@2444..24451749 NAME@2444..24451750 IDENT@2444..2445 "k"1751 WHITESPACE@2445..2446 " "1752 IN_KW@2446..2448 "in"1753 WHITESPACE@2448..2449 " "1754 EXPR@2449..24711755 EXPR_VAR@2449..24521756 NAME@2449..24521757 IDENT@2449..2452 "std"1758 SUFFIX_INDEX@2452..24651759 DOT@2452..2453 "."1760 NAME@2453..24651761 IDENT@2453..2465 "objectFields"1762 SUFFIX_APPLY@2465..24711763 ARGS_DESC@2465..24711764 L_PAREN@2465..2466 "("1765 ARG@2466..24701766 EXPR@2466..24701767 EXPR_VAR@2466..24701768 NAME@2466..24701769 IDENT@2466..2470 "body"1770 R_PAREN@2470..2471 ")"1771 WHITESPACE@2471..2478 "\n "1772 R_BRACK@2478..2479 "]"1773 R_PAREN@2479..2480 ")"1774 SEMI@2480..2481 ";"1775 WHITESPACE@2481..2487 "\n\n "1776 STMT_LOCAL@2487..27691777 LOCAL_KW@2487..2492 "local"1778 WHITESPACE@2492..2493 " "1779 BIND_FUNCTION@2493..25611780 NAME@2493..25061781 IDENT@2493..2506 "section_lines"1782 PARAMS_DESC@2506..25201783 L_PAREN@2506..2507 "("1784 PARAM@2507..25121785 DESTRUCT_FULL@2507..25121786 NAME@2507..25121787 IDENT@2507..2512 "sname"1788 COMMA@2512..2513 ","1789 WHITESPACE@2513..2514 " "1790 PARAM@2514..25191791 DESTRUCT_FULL@2514..25191792 NAME@2514..25191793 IDENT@2514..2519 "sbody"1794 R_PAREN@2519..2520 ")"1795 WHITESPACE@2520..2521 " "1796 ASSIGN@2521..2522 "="1797 WHITESPACE@2522..2523 " "1798 EXPR@2523..25611799 EXPR_BINARY@2523..25611800 EXPR@2523..25411801 EXPR_ARRAY@2523..25411802 L_BRACK@2523..2524 "["1803 EXPR@2524..25401804 EXPR_BINARY@2524..25401805 EXPR@2524..25301806 EXPR_STRING@2524..25301807 STRING_SINGLE@2524..2530 "'[%s]'"1808 WHITESPACE@2530..2531 " "1809 MODULO@2531..2532 "%"1810 WHITESPACE@2532..2533 " "1811 EXPR@2533..25401812 EXPR_ARRAY@2533..25401813 L_BRACK@2533..2534 "["1814 EXPR@2534..25391815 EXPR_VAR@2534..25391816 NAME@2534..25391817 IDENT@2534..2539 "sname"1818 R_BRACK@2539..2540 "]"1819 R_BRACK@2540..2541 "]"1820 WHITESPACE@2541..2542 " "1821 PLUS@2542..2543 "+"1822 WHITESPACE@2543..2544 " "1823 EXPR@2544..25611824 EXPR_VAR@2544..25541825 NAME@2544..25541826 IDENT@2544..2554 "body_lines"1827 SUFFIX_APPLY@2554..25611828 ARGS_DESC@2554..25611829 L_PAREN@2554..2555 "("1830 ARG@2555..25601831 EXPR@2555..25601832 EXPR_VAR@2555..25601833 NAME@2555..25601834 IDENT@2555..2560 "sbody"1835 R_PAREN@2560..2561 ")"1836 COMMA@2561..2562 ","1837 WHITESPACE@2562..2573 "\n "1838 BIND_DESTRUCT@2573..26481839 DESTRUCT_FULL@2573..25821840 NAME@2573..25821841 IDENT@2573..2582 "main_body"1842 WHITESPACE@2582..2583 " "1843 ASSIGN@2583..2584 "="1844 WHITESPACE@2584..2585 " "1845 EXPR@2585..26481846 EXPR_IF_THEN_ELSE@2585..26481847 IF_KW@2585..2587 "if"1848 WHITESPACE@2587..2588 " "1849 EXPR@2588..26141850 EXPR_VAR@2588..25911851 NAME@2588..25911852 IDENT@2588..2591 "std"1853 SUFFIX_INDEX@2591..26011854 DOT@2591..2592 "."1855 NAME@2592..26011856 IDENT@2592..2601 "objectHas"1857 SUFFIX_APPLY@2601..26141858 ARGS_DESC@2601..26141859 L_PAREN@2601..2602 "("1860 ARG@2602..26051861 EXPR@2602..26051862 EXPR_VAR@2602..26051863 NAME@2602..26051864 IDENT@2602..2605 "ini"1865 COMMA@2605..2606 ","1866 WHITESPACE@2606..2607 " "1867 ARG@2607..26131868 EXPR@2607..26131869 EXPR_STRING@2607..26131870 STRING_SINGLE@2607..2613 "'main'"1871 R_PAREN@2613..2614 ")"1872 WHITESPACE@2614..2615 " "1873 THEN_KW@2615..2619 "then"1874 WHITESPACE@2619..2620 " "1875 TRUE_EXPR@2620..26401876 EXPR@2620..26401877 EXPR_VAR@2620..26301878 NAME@2620..26301879 IDENT@2620..2630 "body_lines"1880 SUFFIX_APPLY@2630..26401881 ARGS_DESC@2630..26401882 L_PAREN@2630..2631 "("1883 ARG@2631..26391884 EXPR@2631..26391885 EXPR_VAR@2631..26341886 NAME@2631..26341887 IDENT@2631..2634 "ini"1888 SUFFIX_INDEX@2634..26391889 DOT@2634..2635 "."1890 NAME@2635..26391891 IDENT@2635..2639 "main"1892 R_PAREN@2639..2640 ")"1893 WHITESPACE@2640..2641 " "1894 ELSE_KW@2641..2645 "else"1895 WHITESPACE@2645..2646 " "1896 FALSE_EXPR@2646..26481897 EXPR@2646..26481898 EXPR_ARRAY@2646..26481899 L_BRACK@2646..2647 "["1900 R_BRACK@2647..2648 "]"1901 COMMA@2648..2649 ","1902 WHITESPACE@2649..2660 "\n "1903 BIND_DESTRUCT@2660..27681904 DESTRUCT_FULL@2660..26721905 NAME@2660..26721906 IDENT@2660..2672 "all_sections"1907 WHITESPACE@2672..2673 " "1908 ASSIGN@2673..2674 "="1909 WHITESPACE@2674..2675 " "1910 EXPR@2675..27681911 EXPR_ARRAY_COMP@2675..27681912 L_BRACK@2675..2676 "["1913 WHITESPACE@2676..2683 "\n "1914 EXPR@2683..27161915 EXPR_VAR@2683..26961916 NAME@2683..26961917 IDENT@2683..2696 "section_lines"1918 SUFFIX_APPLY@2696..27161919 ARGS_DESC@2696..27161920 L_PAREN@2696..2697 "("1921 ARG@2697..26981922 EXPR@2697..26981923 EXPR_VAR@2697..26981924 NAME@2697..26981925 IDENT@2697..2698 "k"1926 COMMA@2698..2699 ","1927 WHITESPACE@2699..2700 " "1928 ARG@2700..27151929 EXPR@2700..27151930 EXPR_VAR@2700..27031931 NAME@2700..27031932 IDENT@2700..2703 "ini"1933 SUFFIX_INDEX@2703..27121934 DOT@2703..2704 "."1935 NAME@2704..27121936 IDENT@2704..2712 "sections"1937 SUFFIX_INDEX_EXPR@2712..27151938 L_BRACK@2712..2713 "["1939 EXPR@2713..27141940 EXPR_VAR@2713..27141941 NAME@2713..27141942 IDENT@2713..2714 "k"1943 R_BRACK@2714..2715 "]"1944 R_PAREN@2715..2716 ")"1945 WHITESPACE@2716..2723 "\n "1946 FOR_SPEC@2723..27621947 FOR_KW@2723..2726 "for"1948 WHITESPACE@2726..2727 " "1949 DESTRUCT_FULL@2727..27281950 NAME@2727..27281951 IDENT@2727..2728 "k"1952 WHITESPACE@2728..2729 " "1953 IN_KW@2729..2731 "in"1954 WHITESPACE@2731..2732 " "1955 EXPR@2732..27621956 EXPR_VAR@2732..27351957 NAME@2732..27351958 IDENT@2732..2735 "std"1959 SUFFIX_INDEX@2735..27481960 DOT@2735..2736 "."1961 NAME@2736..27481962 IDENT@2736..2748 "objectFields"1963 SUFFIX_APPLY@2748..27621964 ARGS_DESC@2748..27621965 L_PAREN@2748..2749 "("1966 ARG@2749..27611967 EXPR@2749..27611968 EXPR_VAR@2749..27521969 NAME@2749..27521970 IDENT@2749..2752 "ini"1971 SUFFIX_INDEX@2752..27611972 DOT@2752..2753 "."1973 NAME@2753..27611974 IDENT@2753..2761 "sections"1975 R_PAREN@2761..2762 ")"1976 WHITESPACE@2762..2767 "\n "1977 R_BRACK@2767..2768 "]"1978 SEMI@2768..2769 ";"1979 WHITESPACE@2769..2774 "\n "1980 EXPR_VAR@2774..27771981 NAME@2774..27771982 IDENT@2774..2777 "std"1983 SUFFIX_INDEX@2777..27821984 DOT@2777..2778 "."1985 NAME@2778..27821986 IDENT@2778..2782 "join"1987 SUFFIX_APPLY@2782..28401988 ARGS_DESC@2782..28401989 L_PAREN@2782..2783 "("1990 ARG@2783..27871991 EXPR@2783..27871992 EXPR_STRING@2783..27871993 STRING_SINGLE@2783..2787 "'\\n'"1994 COMMA@2787..2788 ","1995 WHITESPACE@2788..2789 " "1996 ARG@2789..28391997 EXPR@2789..28391998 EXPR_BINARY@2789..28391999 EXPR@2789..28322000 EXPR_BINARY@2789..28322001 EXPR@2789..27982002 EXPR_VAR@2789..27982003 NAME@2789..27982004 IDENT@2789..2798 "main_body"2005 WHITESPACE@2798..2799 " "2006 PLUS@2799..2800 "+"2007 WHITESPACE@2800..2801 " "2008 EXPR@2801..28322009 EXPR_VAR@2801..28042010 NAME@2801..28042011 IDENT@2801..2804 "std"2012 SUFFIX_INDEX@2804..28182013 DOT@2804..2805 "."2014 NAME@2805..28182015 IDENT@2805..2818 "flattenArrays"2016 SUFFIX_APPLY@2818..28322017 ARGS_DESC@2818..28322018 L_PAREN@2818..2819 "("2019 ARG@2819..28312020 EXPR@2819..28312021 EXPR_VAR@2819..28312022 NAME@2819..28312023 IDENT@2819..2831 "all_sections"2024 R_PAREN@2831..2832 ")"2025 WHITESPACE@2832..2833 " "2026 PLUS@2833..2834 "+"2027 WHITESPACE@2834..2835 " "2028 EXPR@2835..28392029 EXPR_ARRAY@2835..28392030 L_BRACK@2835..2836 "["2031 EXPR@2836..28382032 EXPR_STRING@2836..28382033 STRING_SINGLE@2836..2838 "''"2034 R_BRACK@2838..2839 "]"2035 R_PAREN@2839..2840 ")"2036 COMMA@2840..2841 ","2037 WHITESPACE@2841..2845 "\n\n "2038 MEMBER_FIELD_METHOD@2845..28982039 FIELD_NAME_FIXED@2845..28572040 NAME@2845..28572041 IDENT@2845..2857 "manifestToml"2042 PARAMS_DESC@2857..28642043 L_PAREN@2857..2858 "("2044 PARAM@2858..28632045 DESTRUCT_FULL@2858..28632046 NAME@2858..28632047 IDENT@2858..2863 "value"2048 R_PAREN@2863..2864 ")"2049 COLONCOLON@2864..2866 "::"2050 WHITESPACE@2866..2867 " "2051 EXPR@2867..28982052 EXPR_VAR@2867..28702053 NAME@2867..28702054 IDENT@2867..2870 "std"2055 SUFFIX_INDEX@2870..28852056 DOT@2870..2871 "."2057 NAME@2871..28852058 IDENT@2871..2885 "manifestTomlEx"2059 SUFFIX_APPLY@2885..28982060 ARGS_DESC@2885..28982061 L_PAREN@2885..2886 "("2062 ARG@2886..28912063 EXPR@2886..28912064 EXPR_VAR@2886..28912065 NAME@2886..28912066 IDENT@2886..2891 "value"2067 COMMA@2891..2892 ","2068 WHITESPACE@2892..2893 " "2069 ARG@2893..28972070 EXPR@2893..28972071 EXPR_STRING@2893..28972072 STRING_SINGLE@2893..2897 "' '"2073 R_PAREN@2897..2898 ")"2074 COMMA@2898..2899 ","2075 WHITESPACE@2899..2903 "\n\n "2076 MEMBER_FIELD_METHOD@2903..29582077 FIELD_NAME_FIXED@2903..29212078 NAME@2903..29212079 IDENT@2903..2921 "escapeStringPython"2080 PARAMS_DESC@2921..29262081 L_PAREN@2921..2922 "("2082 PARAM@2922..29252083 DESTRUCT_FULL@2922..29252084 NAME@2922..29252085 IDENT@2922..2925 "str"2086 R_PAREN@2925..2926 ")"2087 COLONCOLON@2926..2928 "::"2088 WHITESPACE@2928..2933 "\n "2089 EXPR@2933..29582090 EXPR_VAR@2933..29362091 NAME@2933..29362092 IDENT@2933..2936 "std"2093 SUFFIX_INDEX@2936..29532094 DOT@2936..2937 "."2095 NAME@2937..29532096 IDENT@2937..2953 "escapeStringJson"2097 SUFFIX_APPLY@2953..29582098 ARGS_DESC@2953..29582099 L_PAREN@2953..2954 "("2100 ARG@2954..29572101 EXPR@2954..29572102 EXPR_VAR@2954..29572103 NAME@2954..29572104 IDENT@2954..2957 "str"2105 R_PAREN@2957..2958 ")"2106 COMMA@2958..2959 ","2107 WHITESPACE@2959..2963 "\n\n "2108 MEMBER_FIELD_METHOD@2963..31802109 FIELD_NAME_FIXED@2963..29792110 NAME@2963..29792111 IDENT@2963..2979 "escapeStringBash"2112 PARAMS_DESC@2979..29852113 L_PAREN@2979..2980 "("2114 PARAM@2980..29842115 DESTRUCT_FULL@2980..29842116 NAME@2980..29842117 IDENT@2980..2984 "str_"2118 R_PAREN@2984..2985 ")"2119 COLONCOLON@2985..2987 "::"2120 WHITESPACE@2987..2992 "\n "2121 EXPR@2992..31802122 STMT_LOCAL@2992..30232123 LOCAL_KW@2992..2997 "local"2124 WHITESPACE@2997..2998 " "2125 BIND_DESTRUCT@2998..30222126 DESTRUCT_FULL@2998..30012127 NAME@2998..30012128 IDENT@2998..3001 "str"2129 WHITESPACE@3001..3002 " "2130 ASSIGN@3002..3003 "="2131 WHITESPACE@3003..3004 " "2132 EXPR@3004..30222133 EXPR_VAR@3004..30072134 NAME@3004..30072135 IDENT@3004..3007 "std"2136 SUFFIX_INDEX@3007..30162137 DOT@3007..3008 "."2138 NAME@3008..30162139 IDENT@3008..3016 "toString"2140 SUFFIX_APPLY@3016..30222141 ARGS_DESC@3016..30222142 L_PAREN@3016..3017 "("2143 ARG@3017..30212144 EXPR@3017..30212145 EXPR_VAR@3017..30212146 NAME@3017..30212147 IDENT@3017..3021 "str_"2148 R_PAREN@3021..3022 ")"2149 SEMI@3022..3023 ";"2150 WHITESPACE@3023..3028 "\n "2151 STMT_LOCAL@3028..31102152 LOCAL_KW@3028..3033 "local"2153 WHITESPACE@3033..3034 " "2154 BIND_FUNCTION@3034..31092155 NAME@3034..30392156 IDENT@3034..3039 "trans"2157 PARAMS_DESC@3039..30432158 L_PAREN@3039..3040 "("2159 PARAM@3040..30422160 DESTRUCT_FULL@3040..30422161 NAME@3040..30422162 IDENT@3040..3042 "ch"2163 R_PAREN@3042..3043 ")"2164 WHITESPACE@3043..3044 " "2165 ASSIGN@3044..3045 "="2166 WHITESPACE@3045..3052 "\n "2167 EXPR@3052..31092168 EXPR_IF_THEN_ELSE@3052..31092169 IF_KW@3052..3054 "if"2170 WHITESPACE@3054..3055 " "2171 EXPR@3055..30642172 EXPR_BINARY@3055..30642173 EXPR@3055..30572174 EXPR_VAR@3055..30572175 NAME@3055..30572176 IDENT@3055..3057 "ch"2177 WHITESPACE@3057..3058 " "2178 EQ@3058..3060 "=="2179 WHITESPACE@3060..3061 " "2180 EXPR@3061..30642181 EXPR_STRING@3061..30642182 STRING_DOUBLE@3061..3064 "\"'\""2183 WHITESPACE@3064..3065 " "2184 THEN_KW@3065..3069 "then"2185 WHITESPACE@3069..3078 "\n "2186 TRUE_EXPR@3078..30872187 EXPR@3078..30872188 EXPR_STRING@3078..30872189 STRING_DOUBLE@3078..3087 "\"'\\\"'\\\"'\""2190 WHITESPACE@3087..3094 "\n "2191 ELSE_KW@3094..3098 "else"2192 WHITESPACE@3098..3107 "\n "2193 FALSE_EXPR@3107..31092194 EXPR@3107..31092195 EXPR_VAR@3107..31092196 NAME@3107..31092197 IDENT@3107..3109 "ch"2198 SEMI@3109..3110 ";"2199 WHITESPACE@3110..3115 "\n "2200 EXPR_BINARY@3115..31802201 EXPR@3115..31212202 EXPR_STRING@3115..31212203 STRING_DOUBLE@3115..3121 "\"'%s'\""2204 WHITESPACE@3121..3122 " "2205 MODULO@3122..3123 "%"2206 WHITESPACE@3123..3124 " "2207 EXPR@3124..31802208 EXPR_VAR@3124..31272209 NAME@3124..31272210 IDENT@3124..3127 "std"2211 SUFFIX_INDEX@3127..31322212 DOT@3127..3128 "."2213 NAME@3128..31322214 IDENT@3128..3132 "join"2215 SUFFIX_APPLY@3132..31802216 ARGS_DESC@3132..31802217 L_PAREN@3132..3133 "("2218 ARG@3133..31352219 EXPR@3133..31352220 EXPR_STRING@3133..31352221 STRING_SINGLE@3133..3135 "''"2222 COMMA@3135..3136 ","2223 WHITESPACE@3136..3137 " "2224 ARG@3137..31792225 EXPR@3137..31792226 EXPR_ARRAY_COMP@3137..31792227 L_BRACK@3137..3138 "["2228 EXPR@3138..31472229 EXPR_VAR@3138..31432230 NAME@3138..31432231 IDENT@3138..3143 "trans"2232 SUFFIX_APPLY@3143..31472233 ARGS_DESC@3143..31472234 L_PAREN@3143..3144 "("2235 ARG@3144..31462236 EXPR@3144..31462237 EXPR_VAR@3144..31462238 NAME@3144..31462239 IDENT@3144..3146 "ch"2240 R_PAREN@3146..3147 ")"2241 WHITESPACE@3147..3148 " "2242 FOR_SPEC@3148..31782243 FOR_KW@3148..3151 "for"2244 WHITESPACE@3151..3152 " "2245 DESTRUCT_FULL@3152..31542246 NAME@3152..31542247 IDENT@3152..3154 "ch"2248 WHITESPACE@3154..3155 " "2249 IN_KW@3155..3157 "in"2250 WHITESPACE@3157..3158 " "2251 EXPR@3158..31782252 EXPR_VAR@3158..31612253 NAME@3158..31612254 IDENT@3158..3161 "std"2255 SUFFIX_INDEX@3161..31732256 DOT@3161..3162 "."2257 NAME@3162..31732258 IDENT@3162..3173 "stringChars"2259 SUFFIX_APPLY@3173..31782260 ARGS_DESC@3173..31782261 L_PAREN@3173..3174 "("2262 ARG@3174..31772263 EXPR@3174..31772264 EXPR_VAR@3174..31772265 NAME@3174..31772266 IDENT@3174..3177 "str"2267 R_PAREN@3177..3178 ")"2268 R_BRACK@3178..3179 "]"2269 R_PAREN@3179..3180 ")"2270 COMMA@3180..3181 ","2271 WHITESPACE@3181..3185 "\n\n "2272 MEMBER_FIELD_METHOD@3185..33992273 FIELD_NAME_FIXED@3185..32042274 NAME@3185..32042275 IDENT@3185..3204 "escapeStringDollars"2276 PARAMS_DESC@3204..32102277 L_PAREN@3204..3205 "("2278 PARAM@3205..32092279 DESTRUCT_FULL@3205..32092280 NAME@3205..32092281 IDENT@3205..3209 "str_"2282 R_PAREN@3209..3210 ")"2283 COLONCOLON@3210..3212 "::"2284 WHITESPACE@3212..3217 "\n "2285 EXPR@3217..33992286 STMT_LOCAL@3217..32482287 LOCAL_KW@3217..3222 "local"2288 WHITESPACE@3222..3223 " "2289 BIND_DESTRUCT@3223..32472290 DESTRUCT_FULL@3223..32262291 NAME@3223..32262292 IDENT@3223..3226 "str"2293 WHITESPACE@3226..3227 " "2294 ASSIGN@3227..3228 "="2295 WHITESPACE@3228..3229 " "2296 EXPR@3229..32472297 EXPR_VAR@3229..32322298 NAME@3229..32322299 IDENT@3229..3232 "std"2300 SUFFIX_INDEX@3232..32412301 DOT@3232..3233 "."2302 NAME@3233..32412303 IDENT@3233..3241 "toString"2304 SUFFIX_APPLY@3241..32472305 ARGS_DESC@3241..32472306 L_PAREN@3241..3242 "("2307 ARG@3242..32462308 EXPR@3242..32462309 EXPR_VAR@3242..32462310 NAME@3242..32462311 IDENT@3242..3246 "str_"2312 R_PAREN@3246..3247 ")"2313 SEMI@3247..3248 ";"2314 WHITESPACE@3248..3253 "\n "2315 STMT_LOCAL@3253..33302316 LOCAL_KW@3253..3258 "local"2317 WHITESPACE@3258..3259 " "2318 BIND_FUNCTION@3259..33292319 NAME@3259..32642320 IDENT@3259..3264 "trans"2321 PARAMS_DESC@3264..32682322 L_PAREN@3264..3265 "("2323 PARAM@3265..32672324 DESTRUCT_FULL@3265..32672325 NAME@3265..32672326 IDENT@3265..3267 "ch"2327 R_PAREN@3267..3268 ")"2328 WHITESPACE@3268..3269 " "2329 ASSIGN@3269..3270 "="2330 WHITESPACE@3270..3277 "\n "2331 EXPR@3277..33292332 EXPR_IF_THEN_ELSE@3277..33292333 IF_KW@3277..3279 "if"2334 WHITESPACE@3279..3280 " "2335 EXPR@3280..32892336 EXPR_BINARY@3280..32892337 EXPR@3280..32822338 EXPR_VAR@3280..32822339 NAME@3280..32822340 IDENT@3280..3282 "ch"2341 WHITESPACE@3282..3283 " "2342 EQ@3283..3285 "=="2343 WHITESPACE@3285..3286 " "2344 EXPR@3286..32892345 EXPR_STRING@3286..32892346 STRING_SINGLE@3286..3289 "'$'"2347 WHITESPACE@3289..3290 " "2348 THEN_KW@3290..3294 "then"2349 WHITESPACE@3294..3303 "\n "2350 TRUE_EXPR@3303..33072351 EXPR@3303..33072352 EXPR_STRING@3303..33072353 STRING_SINGLE@3303..3307 "'$$'"2354 WHITESPACE@3307..3314 "\n "2355 ELSE_KW@3314..3318 "else"2356 WHITESPACE@3318..3327 "\n "2357 FALSE_EXPR@3327..33292358 EXPR@3327..33292359 EXPR_VAR@3327..33292360 NAME@3327..33292361 IDENT@3327..3329 "ch"2362 SEMI@3329..3330 ";"2363 WHITESPACE@3330..3335 "\n "2364 EXPR_VAR@3335..33382365 NAME@3335..33382366 IDENT@3335..3338 "std"2367 SUFFIX_INDEX@3338..33442368 DOT@3338..3339 "."2369 NAME@3339..33442370 IDENT@3339..3344 "foldl"2371 SUFFIX_APPLY@3344..33992372 ARGS_DESC@3344..33992373 L_PAREN@3344..3345 "("2374 ARG@3345..33722375 EXPR@3345..33722376 EXPR_FUNCTION@3345..33722377 FUNCTION_KW@3345..3353 "function"2378 PARAMS_DESC@3353..33592379 L_PAREN@3353..3354 "("2380 PARAM@3354..33552381 DESTRUCT_FULL@3354..33552382 NAME@3354..33552383 IDENT@3354..3355 "a"2384 COMMA@3355..3356 ","2385 WHITESPACE@3356..3357 " "2386 PARAM@3357..33582387 DESTRUCT_FULL@3357..33582388 NAME@3357..33582389 IDENT@3357..3358 "b"2390 R_PAREN@3358..3359 ")"2391 WHITESPACE@3359..3360 " "2392 EXPR@3360..33722393 EXPR_BINARY@3360..33722394 EXPR@3360..33612395 EXPR_VAR@3360..33612396 NAME@3360..33612397 IDENT@3360..3361 "a"2398 WHITESPACE@3361..3362 " "2399 PLUS@3362..3363 "+"2400 WHITESPACE@3363..3364 " "2401 EXPR@3364..33722402 EXPR_VAR@3364..33692403 NAME@3364..33692404 IDENT@3364..3369 "trans"2405 SUFFIX_APPLY@3369..33722406 ARGS_DESC@3369..33722407 L_PAREN@3369..3370 "("2408 ARG@3370..33712409 EXPR@3370..33712410 EXPR_VAR@3370..33712411 NAME@3370..33712412 IDENT@3370..3371 "b"2413 R_PAREN@3371..3372 ")"2414 COMMA@3372..3373 ","2415 WHITESPACE@3373..3374 " "2416 ARG@3374..33942417 EXPR@3374..33942418 EXPR_VAR@3374..33772419 NAME@3374..33772420 IDENT@3374..3377 "std"2421 SUFFIX_INDEX@3377..33892422 DOT@3377..3378 "."2423 NAME@3378..33892424 IDENT@3378..3389 "stringChars"2425 SUFFIX_APPLY@3389..33942426 ARGS_DESC@3389..33942427 L_PAREN@3389..3390 "("2428 ARG@3390..33932429 EXPR@3390..33932430 EXPR_VAR@3390..33932431 NAME@3390..33932432 IDENT@3390..3393 "str"2433 R_PAREN@3393..3394 ")"2434 COMMA@3394..3395 ","2435 WHITESPACE@3395..3396 " "2436 ARG@3396..33982437 EXPR@3396..33982438 EXPR_STRING@3396..33982439 STRING_SINGLE@3396..3398 "''"2440 R_PAREN@3398..3399 ")"2441 COMMA@3399..3400 ","2442 WHITESPACE@3400..3404 "\n\n "2443 MEMBER_BIND_STMT@3404..35192444 OBJ_LOCAL@3404..35192445 LOCAL_KW@3404..3409 "local"2446 WHITESPACE@3409..3410 " "2447 BIND_DESTRUCT@3410..35192448 DESTRUCT_FULL@3410..34212449 NAME@3410..34212450 IDENT@3410..3421 "xml_escapes"2451 WHITESPACE@3421..3422 " "2452 ASSIGN@3422..3423 "="2453 WHITESPACE@3423..3424 " "2454 EXPR@3424..35192455 EXPR_OBJECT@3424..35192456 OBJ_BODY_MEMBER_LIST@3424..35192457 L_BRACE@3424..3425 "{"2458 WHITESPACE@3425..3430 "\n "2459 MEMBER_FIELD_NORMAL@3430..34412460 FIELD_NAME_FIXED@3430..34332461 STRING_SINGLE@3430..3433 "'<'"2462 COLON@3433..3434 ":"2463 WHITESPACE@3434..3435 " "2464 EXPR@3435..34412465 EXPR_STRING@3435..34412466 STRING_SINGLE@3435..3441 "'<'"2467 COMMA@3441..3442 ","2468 WHITESPACE@3442..3447 "\n "2469 MEMBER_FIELD_NORMAL@3447..34582470 FIELD_NAME_FIXED@3447..34502471 STRING_SINGLE@3447..3450 "'>'"2472 COLON@3450..3451 ":"2473 WHITESPACE@3451..3452 " "2474 EXPR@3452..34582475 EXPR_STRING@3452..34582476 STRING_SINGLE@3452..3458 "'>'"2477 COMMA@3458..3459 ","2478 WHITESPACE@3459..3464 "\n "2479 MEMBER_FIELD_NORMAL@3464..34762480 FIELD_NAME_FIXED@3464..34672481 STRING_SINGLE@3464..3467 "'&'"2482 COLON@3467..3468 ":"2483 WHITESPACE@3468..3469 " "2484 EXPR@3469..34762485 EXPR_STRING@3469..34762486 STRING_SINGLE@3469..3476 "'&'"2487 COMMA@3476..3477 ","2488 WHITESPACE@3477..3482 "\n "2489 MEMBER_FIELD_NORMAL@3482..34952490 FIELD_NAME_FIXED@3482..34852491 STRING_SINGLE@3482..3485 "'\"'"2492 COLON@3485..3486 ":"2493 WHITESPACE@3486..3487 " "2494 EXPR@3487..34952495 EXPR_STRING@3487..34952496 STRING_SINGLE@3487..3495 "'"'"2497 COMMA@3495..3496 ","2498 WHITESPACE@3496..3501 "\n "2499 MEMBER_FIELD_NORMAL@3501..35142500 FIELD_NAME_FIXED@3501..35042501 STRING_DOUBLE@3501..3504 "\"'\""2502 COLON@3504..3505 ":"2503 WHITESPACE@3505..3506 " "2504 EXPR@3506..35142505 EXPR_STRING@3506..35142506 STRING_SINGLE@3506..3514 "'''"2507 COMMA@3514..3515 ","2508 WHITESPACE@3515..3518 "\n "2509 R_BRACE@3518..3519 "}"2510 COMMA@3519..3520 ","2511 WHITESPACE@3520..3524 "\n\n "2512 MEMBER_FIELD_METHOD@3524..36632513 FIELD_NAME_FIXED@3524..35392514 NAME@3524..35392515 IDENT@3524..3539 "escapeStringXML"2516 PARAMS_DESC@3539..35452517 L_PAREN@3539..3540 "("2518 PARAM@3540..35442519 DESTRUCT_FULL@3540..35442520 NAME@3540..35442521 IDENT@3540..3544 "str_"2522 R_PAREN@3544..3545 ")"2523 COLONCOLON@3545..3547 "::"2524 WHITESPACE@3547..3552 "\n "2525 EXPR@3552..36632526 STMT_LOCAL@3552..35832527 LOCAL_KW@3552..3557 "local"2528 WHITESPACE@3557..3558 " "2529 BIND_DESTRUCT@3558..35822530 DESTRUCT_FULL@3558..35612531 NAME@3558..35612532 IDENT@3558..3561 "str"2533 WHITESPACE@3561..3562 " "2534 ASSIGN@3562..3563 "="2535 WHITESPACE@3563..3564 " "2536 EXPR@3564..35822537 EXPR_VAR@3564..35672538 NAME@3564..35672539 IDENT@3564..3567 "std"2540 SUFFIX_INDEX@3567..35762541 DOT@3567..3568 "."2542 NAME@3568..35762543 IDENT@3568..3576 "toString"2544 SUFFIX_APPLY@3576..35822545 ARGS_DESC@3576..35822546 L_PAREN@3576..3577 "("2547 ARG@3577..35812548 EXPR@3577..35812549 EXPR_VAR@3577..35812550 NAME@3577..35812551 IDENT@3577..3581 "str_"2552 R_PAREN@3581..3582 ")"2553 SEMI@3582..3583 ";"2554 WHITESPACE@3583..3588 "\n "2555 EXPR_VAR@3588..35912556 NAME@3588..35912557 IDENT@3588..3591 "std"2558 SUFFIX_INDEX@3591..35962559 DOT@3591..3592 "."2560 NAME@3592..35962561 IDENT@3592..3596 "join"2562 SUFFIX_APPLY@3596..36632563 ARGS_DESC@3596..36632564 L_PAREN@3596..3597 "("2565 ARG@3597..35992566 EXPR@3597..35992567 EXPR_STRING@3597..35992568 STRING_SINGLE@3597..3599 "''"2569 COMMA@3599..3600 ","2570 WHITESPACE@3600..3601 " "2571 ARG@3601..36622572 EXPR@3601..36622573 EXPR_ARRAY_COMP@3601..36622574 L_BRACK@3601..3602 "["2575 EXPR@3602..36302576 EXPR_VAR@3602..36052577 NAME@3602..36052578 IDENT@3602..3605 "std"2579 SUFFIX_INDEX@3605..36092580 DOT@3605..3606 "."2581 NAME@3606..36092582 IDENT@3606..3609 "get"2583 SUFFIX_APPLY@3609..36302584 ARGS_DESC@3609..36302585 L_PAREN@3609..3610 "("2586 ARG@3610..36212587 EXPR@3610..36212588 EXPR_VAR@3610..36212589 NAME@3610..36212590 IDENT@3610..3621 "xml_escapes"2591 COMMA@3621..3622 ","2592 WHITESPACE@3622..3623 " "2593 ARG@3623..36252594 EXPR@3623..36252595 EXPR_VAR@3623..36252596 NAME@3623..36252597 IDENT@3623..3625 "ch"2598 COMMA@3625..3626 ","2599 WHITESPACE@3626..3627 " "2600 ARG@3627..36292601 EXPR@3627..36292602 EXPR_VAR@3627..36292603 NAME@3627..36292604 IDENT@3627..3629 "ch"2605 R_PAREN@3629..3630 ")"2606 WHITESPACE@3630..3631 " "2607 FOR_SPEC@3631..36612608 FOR_KW@3631..3634 "for"2609 WHITESPACE@3634..3635 " "2610 DESTRUCT_FULL@3635..36372611 NAME@3635..36372612 IDENT@3635..3637 "ch"2613 WHITESPACE@3637..3638 " "2614 IN_KW@3638..3640 "in"2615 WHITESPACE@3640..3641 " "2616 EXPR@3641..36612617 EXPR_VAR@3641..36442618 NAME@3641..36442619 IDENT@3641..3644 "std"2620 SUFFIX_INDEX@3644..36562621 DOT@3644..3645 "."2622 NAME@3645..36562623 IDENT@3645..3656 "stringChars"2624 SUFFIX_APPLY@3656..36612625 ARGS_DESC@3656..36612626 L_PAREN@3656..3657 "("2627 ARG@3657..36602628 EXPR@3657..36602629 EXPR_VAR@3657..36602630 NAME@3657..36602631 IDENT@3657..3660 "str"2632 R_PAREN@3660..3661 ")"2633 R_BRACK@3661..3662 "]"2634 R_PAREN@3662..3663 ")"2635 COMMA@3663..3664 ","2636 WHITESPACE@3664..3668 "\n\n "2637 MEMBER_FIELD_METHOD@3668..37342638 FIELD_NAME_FIXED@3668..36802639 NAME@3668..36802640 IDENT@3668..3680 "manifestJson"2641 PARAMS_DESC@3680..36872642 L_PAREN@3680..3681 "("2643 PARAM@3681..36862644 DESTRUCT_FULL@3681..36862645 NAME@3681..36862646 IDENT@3681..3686 "value"2647 R_PAREN@3686..3687 ")"2648 COLONCOLON@3687..3689 "::"2649 WHITESPACE@3689..3690 " "2650 EXPR@3690..37342651 EXPR_VAR@3690..36932652 NAME@3690..36932653 IDENT@3690..3693 "std"2654 SUFFIX_INDEX@3693..37082655 DOT@3693..3694 "."2656 NAME@3694..37082657 IDENT@3694..3708 "manifestJsonEx"2658 SUFFIX_APPLY@3708..37342659 ARGS_DESC@3708..37342660 L_PAREN@3708..3709 "("2661 ARG@3709..37142662 EXPR@3709..37142663 EXPR_VAR@3709..37142664 NAME@3709..37142665 IDENT@3709..3714 "value"2666 COMMA@3714..3715 ","2667 WHITESPACE@3715..3716 " "2668 ARG@3716..37222669 EXPR@3716..37222670 EXPR_STRING@3716..37222671 STRING_SINGLE@3716..3722 "' '"2672 R_PAREN@3722..3723 ")"2673 WHITESPACE@3723..3724 " "2674 TAILSTRICT_KW@3724..3734 "tailstrict"2675 COMMA@3734..3735 ","2676 WHITESPACE@3735..3739 "\n\n "2677 MEMBER_FIELD_METHOD@3739..38072678 FIELD_NAME_FIXED@3739..37592679 NAME@3739..37592680 IDENT@3739..3759 "manifestJsonMinified"2681 PARAMS_DESC@3759..37662682 L_PAREN@3759..3760 "("2683 PARAM@3760..37652684 DESTRUCT_FULL@3760..37652685 NAME@3760..37652686 IDENT@3760..3765 "value"2687 R_PAREN@3765..3766 ")"2688 COLONCOLON@3766..3768 "::"2689 WHITESPACE@3768..3769 " "2690 EXPR@3769..38072691 EXPR_VAR@3769..37722692 NAME@3769..37722693 IDENT@3769..3772 "std"2694 SUFFIX_INDEX@3772..37872695 DOT@3772..3773 "."2696 NAME@3773..37872697 IDENT@3773..3787 "manifestJsonEx"2698 SUFFIX_APPLY@3787..38072699 ARGS_DESC@3787..38072700 L_PAREN@3787..3788 "("2701 ARG@3788..37932702 EXPR@3788..37932703 EXPR_VAR@3788..37932704 NAME@3788..37932705 IDENT@3788..3793 "value"2706 COMMA@3793..3794 ","2707 WHITESPACE@3794..3795 " "2708 ARG@3795..37972709 EXPR@3795..37972710 EXPR_STRING@3795..37972711 STRING_SINGLE@3795..3797 "''"2712 COMMA@3797..3798 ","2713 WHITESPACE@3798..3799 " "2714 ARG@3799..38012715 EXPR@3799..38012716 EXPR_STRING@3799..38012717 STRING_SINGLE@3799..3801 "''"2718 COMMA@3801..3802 ","2719 WHITESPACE@3802..3803 " "2720 ARG@3803..38062721 EXPR@3803..38062722 EXPR_STRING@3803..38062723 STRING_SINGLE@3803..3806 "':'"2724 R_PAREN@3806..3807 ")"2725 COMMA@3807..3808 ","2726 WHITESPACE@3808..3812 "\n\n "2727 MEMBER_FIELD_METHOD@3812..41972728 FIELD_NAME_FIXED@3812..38302729 NAME@3812..38302730 IDENT@3812..3830 "manifestYamlStream"2731 PARAMS_DESC@3830..39052732 L_PAREN@3830..3831 "("2733 PARAM@3831..38362734 DESTRUCT_FULL@3831..38362735 NAME@3831..38362736 IDENT@3831..3836 "value"2737 COMMA@3836..3837 ","2738 WHITESPACE@3837..3838 " "2739 PARAM@3838..38662740 DESTRUCT_FULL@3838..38602741 NAME@3838..38602742 IDENT@3838..3860 "indent_array_in_object"2743 ASSIGN@3860..3861 "="2744 EXPR@3861..38662745 EXPR_LITERAL@3861..38662746 FALSE_KW@3861..3866 "false"2747 COMMA@3866..3867 ","2748 WHITESPACE@3867..3868 " "2749 PARAM@3868..38872750 DESTRUCT_FULL@3868..38822751 NAME@3868..38822752 IDENT@3868..3882 "c_document_end"2753 ASSIGN@3882..3883 "="2754 EXPR@3883..38872755 EXPR_LITERAL@3883..38872756 TRUE_KW@3883..3887 "true"2757 COMMA@3887..3888 ","2758 WHITESPACE@3888..3889 " "2759 PARAM@3889..39042760 DESTRUCT_FULL@3889..38992761 NAME@3889..38992762 IDENT@3889..3899 "quote_keys"2763 ASSIGN@3899..3900 "="2764 EXPR@3900..39042765 EXPR_LITERAL@3900..39042766 TRUE_KW@3900..3904 "true"2767 R_PAREN@3904..3905 ")"2768 COLONCOLON@3905..3907 "::"2769 WHITESPACE@3907..3912 "\n "2770 EXPR@3912..41972771 EXPR_IF_THEN_ELSE@3912..41972772 IF_KW@3912..3914 "if"2773 WHITESPACE@3914..3915 " "2774 EXPR@3915..39342775 EXPR_UNARY@3915..39342776 NOT@3915..3916 "!"2777 EXPR_VAR@3916..39192778 NAME@3916..39192779 IDENT@3916..3919 "std"2780 SUFFIX_INDEX@3919..39272781 DOT@3919..3920 "."2782 NAME@3920..39272783 IDENT@3920..3927 "isArray"2784 SUFFIX_APPLY@3927..39342785 ARGS_DESC@3927..39342786 L_PAREN@3927..3928 "("2787 ARG@3928..39332788 EXPR@3928..39332789 EXPR_VAR@3928..39332790 NAME@3928..39332791 IDENT@3928..3933 "value"2792 R_PAREN@3933..3934 ")"2793 WHITESPACE@3934..3935 " "2794 THEN_KW@3935..3939 "then"2795 WHITESPACE@3939..3946 "\n "2796 TRUE_EXPR@3946..40142797 EXPR@3946..40142798 EXPR_ERROR@3946..40142799 ERROR_KW@3946..3951 "error"2800 WHITESPACE@3951..3952 " "2801 EXPR@3952..40142802 EXPR_BINARY@3952..40142803 EXPR@3952..39962804 EXPR_STRING@3952..39962805 STRING_SINGLE@3952..3996 "'manifestYamlStream o ..."2806 WHITESPACE@3996..3997 " "2807 PLUS@3997..3998 "+"2808 WHITESPACE@3998..3999 " "2809 EXPR@3999..40142810 EXPR_VAR@3999..40022811 NAME@3999..40022812 IDENT@3999..4002 "std"2813 SUFFIX_INDEX@4002..40072814 DOT@4002..4003 "."2815 NAME@4003..40072816 IDENT@4003..4007 "type"2817 SUFFIX_APPLY@4007..40142818 ARGS_DESC@4007..40142819 L_PAREN@4007..4008 "("2820 ARG@4008..40132821 EXPR@4008..40132822 EXPR_VAR@4008..40132823 NAME@4008..40132824 IDENT@4008..4013 "value"2825 R_PAREN@4013..4014 ")"2826 WHITESPACE@4014..4019 "\n "2827 ELSE_KW@4019..4023 "else"2828 WHITESPACE@4023..4030 "\n "2829 FALSE_EXPR@4030..41972830 EXPR@4030..41972831 EXPR_BINARY@4030..41972832 EXPR@4030..41522833 EXPR_BINARY@4030..41522834 EXPR@4030..40372835 EXPR_STRING@4030..40372836 STRING_SINGLE@4030..4037 "'---\\n'"2837 WHITESPACE@4037..4038 " "2838 PLUS@4038..4039 "+"2839 WHITESPACE@4039..4040 " "2840 EXPR@4040..41522841 EXPR_VAR@4040..40432842 NAME@4040..40432843 IDENT@4040..4043 "std"2844 SUFFIX_INDEX@4043..40482845 DOT@4043..4044 "."2846 NAME@4044..40482847 IDENT@4044..4048 "join"2848 SUFFIX_APPLY@4048..41522849 ARGS_DESC@4048..41522850 L_PAREN@4048..4049 "("2851 WHITESPACE@4049..4058 "\n "2852 ARG@4058..40672853 EXPR@4058..40672854 EXPR_STRING@4058..40672855 STRING_SINGLE@4058..4067 "'\\n---\\n'"2856 COMMA@4067..4068 ","2857 WHITESPACE@4068..4069 " "2858 ARG@4069..41442859 EXPR@4069..41442860 EXPR_ARRAY_COMP@4069..41442861 L_BRACK@4069..4070 "["2862 EXPR@4070..41282863 EXPR_VAR@4070..40732864 NAME@4070..40732865 IDENT@4070..4073 "std"2866 SUFFIX_INDEX@4073..40892867 DOT@4073..4074 "."2868 NAME@4074..40892869 IDENT@4074..4089 "manifestYamlDoc"2870 SUFFIX_APPLY@4089..41282871 ARGS_DESC@4089..41282872 L_PAREN@4089..4090 "("2873 ARG@4090..40912874 EXPR@4090..40912875 EXPR_VAR@4090..40912876 NAME@4090..40912877 IDENT@4090..4091 "e"2878 COMMA@4091..4092 ","2879 WHITESPACE@4092..4093 " "2880 ARG@4093..41152881 EXPR@4093..41152882 EXPR_VAR@4093..41152883 NAME@4093..41152884 IDENT@4093..4115 "indent_array_in_object"2885 COMMA@4115..4116 ","2886 WHITESPACE@4116..4117 " "2887 ARG@4117..41272888 EXPR@4117..41272889 EXPR_VAR@4117..41272890 NAME@4117..41272891 IDENT@4117..4127 "quote_keys"2892 R_PAREN@4127..4128 ")"2893 WHITESPACE@4128..4129 " "2894 FOR_SPEC@4129..41432895 FOR_KW@4129..4132 "for"2896 WHITESPACE@4132..4133 " "2897 DESTRUCT_FULL@4133..41342898 NAME@4133..41342899 IDENT@4133..4134 "e"2900 WHITESPACE@4134..4135 " "2901 IN_KW@4135..4137 "in"2902 WHITESPACE@4137..4138 " "2903 EXPR@4138..41432904 EXPR_VAR@4138..41432905 NAME@4138..41432906 IDENT@4138..4143 "value"2907 R_BRACK@4143..4144 "]"2908 WHITESPACE@4144..4151 "\n "2909 R_PAREN@4151..4152 ")"2910 WHITESPACE@4152..4153 " "2911 PLUS@4153..4154 "+"2912 WHITESPACE@4154..4155 " "2913 EXPR@4155..41972914 EXPR_IF_THEN_ELSE@4155..41972915 IF_KW@4155..4157 "if"2916 WHITESPACE@4157..4158 " "2917 EXPR@4158..41722918 EXPR_VAR@4158..41722919 NAME@4158..41722920 IDENT@4158..4172 "c_document_end"2921 WHITESPACE@4172..4173 " "2922 THEN_KW@4173..4177 "then"2923 WHITESPACE@4177..4178 " "2924 TRUE_EXPR@4178..41872925 EXPR@4178..41872926 EXPR_STRING@4178..41872927 STRING_SINGLE@4178..4187 "'\\n...\\n'"2928 WHITESPACE@4187..4188 " "2929 ELSE_KW@4188..4192 "else"2930 WHITESPACE@4192..4193 " "2931 FALSE_EXPR@4193..41972932 EXPR@4193..41972933 EXPR_STRING@4193..41972934 STRING_SINGLE@4193..4197 "'\\n'"2935 COMMA@4197..4198 ","2936 WHITESPACE@4198..4202 "\n\n "2937 MEMBER_FIELD_METHOD@4202..48582938 FIELD_NAME_FIXED@4202..42162939 NAME@4202..42162940 IDENT@4202..4216 "manifestPython"2941 PARAMS_DESC@4216..42192942 L_PAREN@4216..4217 "("2943 PARAM@4217..42182944 DESTRUCT_FULL@4217..42182945 NAME@4217..42182946 IDENT@4217..4218 "v"2947 R_PAREN@4218..4219 ")"2948 COLONCOLON@4219..4221 "::"2949 WHITESPACE@4221..4226 "\n "2950 EXPR@4226..48582951 EXPR_IF_THEN_ELSE@4226..48582952 IF_KW@4226..4228 "if"2953 WHITESPACE@4228..4229 " "2954 EXPR@4229..42442955 EXPR_VAR@4229..42322956 NAME@4229..42322957 IDENT@4229..4232 "std"2958 SUFFIX_INDEX@4232..42412959 DOT@4232..4233 "."2960 NAME@4233..42412961 IDENT@4233..4241 "isObject"2962 SUFFIX_APPLY@4241..42442963 ARGS_DESC@4241..42442964 L_PAREN@4241..4242 "("2965 ARG@4242..42432966 EXPR@4242..42432967 EXPR_VAR@4242..42432968 NAME@4242..42432969 IDENT@4242..4243 "v"2970 R_PAREN@4243..4244 ")"2971 WHITESPACE@4244..4245 " "2972 THEN_KW@4245..4249 "then"2973 WHITESPACE@4249..4256 "\n "2974 TRUE_EXPR@4256..44312975 EXPR@4256..44312976 STMT_LOCAL@4256..43912977 LOCAL_KW@4256..4261 "local"2978 WHITESPACE@4261..4262 " "2979 BIND_DESTRUCT@4262..43902980 DESTRUCT_FULL@4262..42682981 NAME@4262..42682982 IDENT@4262..4268 "fields"2983 WHITESPACE@4268..4269 " "2984 ASSIGN@4269..4270 "="2985 WHITESPACE@4270..4271 " "2986 EXPR@4271..43902987 EXPR_ARRAY_COMP@4271..43902988 L_BRACK@4271..4272 "["2989 WHITESPACE@4272..4281 "\n "2990 EXPR@4281..43452991 EXPR_BINARY@4281..43452992 EXPR@4281..42892993 EXPR_STRING@4281..42892994 STRING_SINGLE@4281..4289 "'%s: %s'"2995 WHITESPACE@4289..4290 " "2996 MODULO@4290..4291 "%"2997 WHITESPACE@4291..4292 " "2998 EXPR@4292..43452999 EXPR_ARRAY@4292..43453000 L_BRACK@4292..4293 "["3001 EXPR@4293..43183002 EXPR_VAR@4293..42963003 NAME@4293..42963004 IDENT@4293..4296 "std"3005 SUFFIX_INDEX@4296..43153006 DOT@4296..4297 "."3007 NAME@4297..43153008 IDENT@4297..4315 "escapeStringPython"3009 SUFFIX_APPLY@4315..43183010 ARGS_DESC@4315..43183011 L_PAREN@4315..4316 "("3012 ARG@4316..43173013 EXPR@4316..43173014 EXPR_VAR@4316..43173015 NAME@4316..43173016 IDENT@4316..4317 "k"3017 R_PAREN@4317..4318 ")"3018 COMMA@4318..4319 ","3019 WHITESPACE@4319..4320 " "3020 EXPR@4320..43443021 EXPR_VAR@4320..43233022 NAME@4320..43233023 IDENT@4320..4323 "std"3024 SUFFIX_INDEX@4323..43383025 DOT@4323..4324 "."3026 NAME@4324..43383027 IDENT@4324..4338 "manifestPython"3028 SUFFIX_APPLY@4338..43443029 ARGS_DESC@4338..43443030 L_PAREN@4338..4339 "("3031 ARG@4339..43433032 EXPR@4339..43433033 EXPR_VAR@4339..43403034 NAME@4339..43403035 IDENT@4339..4340 "v"3036 SUFFIX_INDEX_EXPR@4340..43433037 L_BRACK@4340..4341 "["3038 EXPR@4341..43423039 EXPR_VAR@4341..43423040 NAME@4341..43423041 IDENT@4341..4342 "k"3042 R_BRACK@4342..4343 "]"3043 R_PAREN@4343..4344 ")"3044 R_BRACK@4344..4345 "]"3045 WHITESPACE@4345..4354 "\n "3046 FOR_SPEC@4354..43823047 FOR_KW@4354..4357 "for"3048 WHITESPACE@4357..4358 " "3049 DESTRUCT_FULL@4358..43593050 NAME@4358..43593051 IDENT@4358..4359 "k"3052 WHITESPACE@4359..4360 " "3053 IN_KW@4360..4362 "in"3054 WHITESPACE@4362..4363 " "3055 EXPR@4363..43823056 EXPR_VAR@4363..43663057 NAME@4363..43663058 IDENT@4363..4366 "std"3059 SUFFIX_INDEX@4366..43793060 DOT@4366..4367 "."3061 NAME@4367..43793062 IDENT@4367..4379 "objectFields"3063 SUFFIX_APPLY@4379..43823064 ARGS_DESC@4379..43823065 L_PAREN@4379..4380 "("3066 ARG@4380..43813067 EXPR@4380..43813068 EXPR_VAR@4380..43813069 NAME@4380..43813070 IDENT@4380..4381 "v"3071 R_PAREN@4381..4382 ")"3072 WHITESPACE@4382..4389 "\n "3073 R_BRACK@4389..4390 "]"3074 SEMI@4390..4391 ";"3075 WHITESPACE@4391..4398 "\n "3076 EXPR_BINARY@4398..44313077 EXPR@4398..44043078 EXPR_STRING@4398..44043079 STRING_SINGLE@4398..4404 "'{%s}'"3080 WHITESPACE@4404..4405 " "3081 MODULO@4405..4406 "%"3082 WHITESPACE@4406..4407 " "3083 EXPR@4407..44313084 EXPR_ARRAY@4407..44313085 L_BRACK@4407..4408 "["3086 EXPR@4408..44303087 EXPR_VAR@4408..44113088 NAME@4408..44113089 IDENT@4408..4411 "std"3090 SUFFIX_INDEX@4411..44163091 DOT@4411..4412 "."3092 NAME@4412..44163093 IDENT@4412..4416 "join"3094 SUFFIX_APPLY@4416..44303095 ARGS_DESC@4416..44303096 L_PAREN@4416..4417 "("3097 ARG@4417..44213098 EXPR@4417..44213099 EXPR_STRING@4417..44213100 STRING_SINGLE@4417..4421 "', '"3101 COMMA@4421..4422 ","3102 WHITESPACE@4422..4423 " "3103 ARG@4423..44293104 EXPR@4423..44293105 EXPR_VAR@4423..44293106 NAME@4423..44293107 IDENT@4423..4429 "fields"3108 R_PAREN@4429..4430 ")"3109 R_BRACK@4430..4431 "]"3110 WHITESPACE@4431..4436 "\n "3111 ELSE_KW@4436..4440 "else"3112 WHITESPACE@4440..4441 " "3113 FALSE_EXPR@4441..48583114 EXPR@4441..48583115 EXPR_IF_THEN_ELSE@4441..48583116 IF_KW@4441..4443 "if"3117 WHITESPACE@4443..4444 " "3118 EXPR@4444..44583119 EXPR_VAR@4444..44473120 NAME@4444..44473121 IDENT@4444..4447 "std"3122 SUFFIX_INDEX@4447..44553123 DOT@4447..4448 "."3124 NAME@4448..44553125 IDENT@4448..4455 "isArray"3126 SUFFIX_APPLY@4455..44583127 ARGS_DESC@4455..44583128 L_PAREN@4455..4456 "("3129 ARG@4456..44573130 EXPR@4456..44573131 EXPR_VAR@4456..44573132 NAME@4456..44573133 IDENT@4456..4457 "v"3134 R_PAREN@4457..4458 ")"3135 WHITESPACE@4458..4459 " "3136 THEN_KW@4459..4463 "then"3137 WHITESPACE@4463..4470 "\n "3138 TRUE_EXPR@4470..45333139 EXPR@4470..45333140 EXPR_BINARY@4470..45333141 EXPR@4470..44763142 EXPR_STRING@4470..44763143 STRING_SINGLE@4470..4476 "'[%s]'"3144 WHITESPACE@4476..4477 " "3145 MODULO@4477..4478 "%"3146 WHITESPACE@4478..4479 " "3147 EXPR@4479..45333148 EXPR_ARRAY@4479..45333149 L_BRACK@4479..4480 "["3150 EXPR@4480..45323151 EXPR_VAR@4480..44833152 NAME@4480..44833153 IDENT@4480..4483 "std"3154 SUFFIX_INDEX@4483..44883155 DOT@4483..4484 "."3156 NAME@4484..44883157 IDENT@4484..4488 "join"3158 SUFFIX_APPLY@4488..45323159 ARGS_DESC@4488..45323160 L_PAREN@4488..4489 "("3161 ARG@4489..44933162 EXPR@4489..44933163 EXPR_STRING@4489..44933164 STRING_SINGLE@4489..4493 "', '"3165 COMMA@4493..4494 ","3166 WHITESPACE@4494..4495 " "3167 ARG@4495..45313168 EXPR@4495..45313169 EXPR_ARRAY_COMP@4495..45313170 L_BRACK@4495..4496 "["3171 EXPR@4496..45183172 EXPR_VAR@4496..44993173 NAME@4496..44993174 IDENT@4496..4499 "std"3175 SUFFIX_INDEX@4499..45143176 DOT@4499..4500 "."3177 NAME@4500..45143178 IDENT@4500..4514 "manifestPython"3179 SUFFIX_APPLY@4514..45183180 ARGS_DESC@4514..45183181 L_PAREN@4514..4515 "("3182 ARG@4515..45173183 EXPR@4515..45173184 EXPR_VAR@4515..45173185 NAME@4515..45173186 IDENT@4515..4517 "v2"3187 R_PAREN@4517..4518 ")"3188 WHITESPACE@4518..4519 " "3189 FOR_SPEC@4519..45303190 FOR_KW@4519..4522 "for"3191 WHITESPACE@4522..4523 " "3192 DESTRUCT_FULL@4523..45253193 NAME@4523..45253194 IDENT@4523..4525 "v2"3195 WHITESPACE@4525..4526 " "3196 IN_KW@4526..4528 "in"3197 WHITESPACE@4528..4529 " "3198 EXPR@4529..45303199 EXPR_VAR@4529..45303200 NAME@4529..45303201 IDENT@4529..4530 "v"3202 R_BRACK@4530..4531 "]"3203 R_PAREN@4531..4532 ")"3204 R_BRACK@4532..4533 "]"3205 WHITESPACE@4533..4538 "\n "3206 ELSE_KW@4538..4542 "else"3207 WHITESPACE@4542..4543 " "3208 FALSE_EXPR@4543..48583209 EXPR@4543..48583210 EXPR_IF_THEN_ELSE@4543..48583211 IF_KW@4543..4545 "if"3212 WHITESPACE@4545..4546 " "3213 EXPR@4546..45613214 EXPR_VAR@4546..45493215 NAME@4546..45493216 IDENT@4546..4549 "std"3217 SUFFIX_INDEX@4549..45583218 DOT@4549..4550 "."3219 NAME@4550..45583220 IDENT@4550..4558 "isString"3221 SUFFIX_APPLY@4558..45613222 ARGS_DESC@4558..45613223 L_PAREN@4558..4559 "("3224 ARG@4559..45603225 EXPR@4559..45603226 EXPR_VAR@4559..45603227 NAME@4559..45603228 IDENT@4559..4560 "v"3229 R_PAREN@4560..4561 ")"3230 WHITESPACE@4561..4562 " "3231 THEN_KW@4562..4566 "then"3232 WHITESPACE@4566..4573 "\n "3233 TRUE_EXPR@4573..46073234 EXPR@4573..46073235 EXPR_BINARY@4573..46073236 EXPR@4573..45773237 EXPR_STRING@4573..45773238 STRING_SINGLE@4573..4577 "'%s'"3239 WHITESPACE@4577..4578 " "3240 MODULO@4578..4579 "%"3241 WHITESPACE@4579..4580 " "3242 EXPR@4580..46073243 EXPR_ARRAY@4580..46073244 L_BRACK@4580..4581 "["3245 EXPR@4581..46063246 EXPR_VAR@4581..45843247 NAME@4581..45843248 IDENT@4581..4584 "std"3249 SUFFIX_INDEX@4584..46033250 DOT@4584..4585 "."3251 NAME@4585..46033252 IDENT@4585..4603 "escapeStringPython"3253 SUFFIX_APPLY@4603..46063254 ARGS_DESC@4603..46063255 L_PAREN@4603..4604 "("3256 ARG@4604..46053257 EXPR@4604..46053258 EXPR_VAR@4604..46053259 NAME@4604..46053260 IDENT@4604..4605 "v"3261 R_PAREN@4605..4606 ")"3262 R_BRACK@4606..4607 "]"3263 WHITESPACE@4607..4612 "\n "3264 ELSE_KW@4612..4616 "else"3265 WHITESPACE@4616..4617 " "3266 FALSE_EXPR@4617..48583267 EXPR@4617..48583268 EXPR_IF_THEN_ELSE@4617..48583269 IF_KW@4617..4619 "if"3270 WHITESPACE@4619..4620 " "3271 EXPR@4620..46373272 EXPR_VAR@4620..46233273 NAME@4620..46233274 IDENT@4620..4623 "std"3275 SUFFIX_INDEX@4623..46343276 DOT@4623..4624 "."3277 NAME@4624..46343278 IDENT@4624..4634 "isFunction"3279 SUFFIX_APPLY@4634..46373280 ARGS_DESC@4634..46373281 L_PAREN@4634..4635 "("3282 ARG@4635..46363283 EXPR@4635..46363284 EXPR_VAR@4635..46363285 NAME@4635..46363286 IDENT@4635..4636 "v"3287 R_PAREN@4636..4637 ")"3288 WHITESPACE@4637..4638 " "3289 THEN_KW@4638..4642 "then"3290 WHITESPACE@4642..4649 "\n "3291 TRUE_EXPR@4649..46813292 EXPR@4649..46813293 EXPR_ERROR@4649..46813294 ERROR_KW@4649..4654 "error"3295 WHITESPACE@4654..4655 " "3296 EXPR@4655..46813297 EXPR_STRING@4655..46813298 STRING_SINGLE@4655..4681 "'cannot manifest func ..."3299 WHITESPACE@4681..4686 "\n "3300 ELSE_KW@4686..4690 "else"3301 WHITESPACE@4690..4691 " "3302 FALSE_EXPR@4691..48583303 EXPR@4691..48583304 EXPR_IF_THEN_ELSE@4691..48583305 IF_KW@4691..4693 "if"3306 WHITESPACE@4693..4694 " "3307 EXPR@4694..47093308 EXPR_VAR@4694..46973309 NAME@4694..46973310 IDENT@4694..4697 "std"3311 SUFFIX_INDEX@4697..47063312 DOT@4697..4698 "."3313 NAME@4698..47063314 IDENT@4698..4706 "isNumber"3315 SUFFIX_APPLY@4706..47093316 ARGS_DESC@4706..47093317 L_PAREN@4706..4707 "("3318 ARG@4707..47083319 EXPR@4707..47083320 EXPR_VAR@4707..47083321 NAME@4707..47083322 IDENT@4707..4708 "v"3323 R_PAREN@4708..4709 ")"3324 WHITESPACE@4709..4710 " "3325 THEN_KW@4710..4714 "then"3326 WHITESPACE@4714..4721 "\n "3327 TRUE_EXPR@4721..47363328 EXPR@4721..47363329 EXPR_VAR@4721..47243330 NAME@4721..47243331 IDENT@4721..4724 "std"3332 SUFFIX_INDEX@4724..47333333 DOT@4724..4725 "."3334 NAME@4725..47333335 IDENT@4725..4733 "toString"3336 SUFFIX_APPLY@4733..47363337 ARGS_DESC@4733..47363338 L_PAREN@4733..4734 "("3339 ARG@4734..47353340 EXPR@4734..47353341 EXPR_VAR@4734..47353342 NAME@4734..47353343 IDENT@4734..4735 "v"3344 R_PAREN@4735..4736 ")"3345 WHITESPACE@4736..4741 "\n "3346 ELSE_KW@4741..4745 "else"3347 WHITESPACE@4745..4746 " "3348 FALSE_EXPR@4746..48583349 EXPR@4746..48583350 EXPR_IF_THEN_ELSE@4746..48583351 IF_KW@4746..4748 "if"3352 WHITESPACE@4748..4749 " "3353 EXPR@4749..47583354 EXPR_BINARY@4749..47583355 EXPR@4749..47503356 EXPR_VAR@4749..47503357 NAME@4749..47503358 IDENT@4749..4750 "v"3359 WHITESPACE@4750..4751 " "3360 EQ@4751..4753 "=="3361 WHITESPACE@4753..4754 " "3362 EXPR@4754..47583363 EXPR_LITERAL@4754..47583364 TRUE_KW@4754..4758 "true"3365 WHITESPACE@4758..4759 " "3366 THEN_KW@4759..4763 "then"3367 WHITESPACE@4763..4770 "\n "3368 TRUE_EXPR@4770..47763369 EXPR@4770..47763370 EXPR_STRING@4770..47763371 STRING_SINGLE@4770..4776 "'True'"3372 WHITESPACE@4776..4781 "\n "3373 ELSE_KW@4781..4785 "else"3374 WHITESPACE@4785..4786 " "3375 FALSE_EXPR@4786..48583376 EXPR@4786..48583377 EXPR_IF_THEN_ELSE@4786..48583378 IF_KW@4786..4788 "if"3379 WHITESPACE@4788..4789 " "3380 EXPR@4789..47993381 EXPR_BINARY@4789..47993382 EXPR@4789..47903383 EXPR_VAR@4789..47903384 NAME@4789..47903385 IDENT@4789..4790 "v"3386 WHITESPACE@4790..4791 " "3387 EQ@4791..4793 "=="3388 WHITESPACE@4793..4794 " "3389 EXPR@4794..47993390 EXPR_LITERAL@4794..47993391 FALSE_KW@4794..4799 "false"3392 WHITESPACE@4799..4800 " "3393 THEN_KW@4800..4804 "then"3394 WHITESPACE@4804..4811 "\n "3395 TRUE_EXPR@4811..48183396 EXPR@4811..48183397 EXPR_STRING@4811..48183398 STRING_SINGLE@4811..4818 "'False'"3399 WHITESPACE@4818..4823 "\n "3400 ELSE_KW@4823..4827 "else"3401 WHITESPACE@4827..4828 " "3402 FALSE_EXPR@4828..48583403 EXPR@4828..48583404 EXPR_IF_THEN_ELSE@4828..48583405 IF_KW@4828..4830 "if"3406 WHITESPACE@4830..4831 " "3407 EXPR@4831..48403408 EXPR_BINARY@4831..48403409 EXPR@4831..48323410 EXPR_VAR@4831..48323411 NAME@4831..48323412 IDENT@4831..4832 "v"3413 WHITESPACE@4832..4833 " "3414 EQ@4833..4835 "=="3415 WHITESPACE@4835..4836 " "3416 EXPR@4836..48403417 EXPR_LITERAL@4836..48403418 NULL_KW@4836..4840 "null"3419 WHITESPACE@4840..4841 " "3420 THEN_KW@4841..4845 "then"3421 WHITESPACE@4845..4852 "\n "3422 TRUE_EXPR@4852..48583423 EXPR@4852..48583424 EXPR_STRING@4852..48583425 STRING_SINGLE@4852..4858 "'None'"3426 COMMA@4858..4859 ","3427 WHITESPACE@4859..4863 "\n\n "3428 MEMBER_FIELD_METHOD@4863..50183429 FIELD_NAME_FIXED@4863..48813430 NAME@4863..48813431 IDENT@4863..4881 "manifestPythonVars"3432 PARAMS_DESC@4881..48873433 L_PAREN@4881..4882 "("3434 PARAM@4882..48863435 DESTRUCT_FULL@4882..48863436 NAME@4882..48863437 IDENT@4882..4886 "conf"3438 R_PAREN@4886..4887 ")"3439 COLONCOLON@4887..4889 "::"3440 WHITESPACE@4889..4894 "\n "3441 EXPR@4894..50183442 STMT_LOCAL@4894..49863443 LOCAL_KW@4894..4899 "local"3444 WHITESPACE@4899..4900 " "3445 BIND_DESTRUCT@4900..49853446 DESTRUCT_FULL@4900..49043447 NAME@4900..49043448 IDENT@4900..4904 "vars"3449 WHITESPACE@4904..4905 " "3450 ASSIGN@4905..4906 "="3451 WHITESPACE@4906..4907 " "3452 EXPR@4907..49853453 EXPR_ARRAY_COMP@4907..49853454 L_BRACK@4907..4908 "["3455 EXPR@4908..49523456 EXPR_BINARY@4908..49523457 EXPR@4908..49173458 EXPR_STRING@4908..49173459 STRING_SINGLE@4908..4917 "'%s = %s'"3460 WHITESPACE@4917..4918 " "3461 MODULO@4918..4919 "%"3462 WHITESPACE@4919..4920 " "3463 EXPR@4920..49523464 EXPR_ARRAY@4920..49523465 L_BRACK@4920..4921 "["3466 EXPR@4921..49223467 EXPR_VAR@4921..49223468 NAME@4921..49223469 IDENT@4921..4922 "k"3470 COMMA@4922..4923 ","3471 WHITESPACE@4923..4924 " "3472 EXPR@4924..49513473 EXPR_VAR@4924..49273474 NAME@4924..49273475 IDENT@4924..4927 "std"3476 SUFFIX_INDEX@4927..49423477 DOT@4927..4928 "."3478 NAME@4928..49423479 IDENT@4928..4942 "manifestPython"3480 SUFFIX_APPLY@4942..49513481 ARGS_DESC@4942..49513482 L_PAREN@4942..4943 "("3483 ARG@4943..49503484 EXPR@4943..49503485 EXPR_VAR@4943..49473486 NAME@4943..49473487 IDENT@4943..4947 "conf"3488 SUFFIX_INDEX_EXPR@4947..49503489 L_BRACK@4947..4948 "["3490 EXPR@4948..49493491 EXPR_VAR@4948..49493492 NAME@4948..49493493 IDENT@4948..4949 "k"3494 R_BRACK@4949..4950 "]"3495 R_PAREN@4950..4951 ")"3496 R_BRACK@4951..4952 "]"3497 WHITESPACE@4952..4953 " "3498 FOR_SPEC@4953..49843499 FOR_KW@4953..4956 "for"3500 WHITESPACE@4956..4957 " "3501 DESTRUCT_FULL@4957..49583502 NAME@4957..49583503 IDENT@4957..4958 "k"3504 WHITESPACE@4958..4959 " "3505 IN_KW@4959..4961 "in"3506 WHITESPACE@4961..4962 " "3507 EXPR@4962..49843508 EXPR_VAR@4962..49653509 NAME@4962..49653510 IDENT@4962..4965 "std"3511 SUFFIX_INDEX@4965..49783512 DOT@4965..4966 "."3513 NAME@4966..49783514 IDENT@4966..4978 "objectFields"3515 SUFFIX_APPLY@4978..49843516 ARGS_DESC@4978..49843517 L_PAREN@4978..4979 "("3518 ARG@4979..49833519 EXPR@4979..49833520 EXPR_VAR@4979..49833521 NAME@4979..49833522 IDENT@4979..4983 "conf"3523 R_PAREN@4983..4984 ")"3524 R_BRACK@4984..4985 "]"3525 SEMI@4985..4986 ";"3526 WHITESPACE@4986..4991 "\n "3527 EXPR_VAR@4991..49943528 NAME@4991..49943529 IDENT@4991..4994 "std"3530 SUFFIX_INDEX@4994..49993531 DOT@4994..4995 "."3532 NAME@4995..49993533 IDENT@4995..4999 "join"3534 SUFFIX_APPLY@4999..50183535 ARGS_DESC@4999..50183536 L_PAREN@4999..5000 "("3537 ARG@5000..50043538 EXPR@5000..50043539 EXPR_STRING@5000..50043540 STRING_SINGLE@5000..5004 "'\\n'"3541 COMMA@5004..5005 ","3542 WHITESPACE@5005..5006 " "3543 ARG@5006..50173544 EXPR@5006..50173545 EXPR_BINARY@5006..50173546 EXPR@5006..50103547 EXPR_VAR@5006..50103548 NAME@5006..50103549 IDENT@5006..5010 "vars"3550 WHITESPACE@5010..5011 " "3551 PLUS@5011..5012 "+"3552 WHITESPACE@5012..5013 " "3553 EXPR@5013..50173554 EXPR_ARRAY@5013..50173555 L_BRACK@5013..5014 "["3556 EXPR@5014..50163557 EXPR_STRING@5014..50163558 STRING_SINGLE@5014..5016 "''"3559 R_BRACK@5016..5017 "]"3560 R_PAREN@5017..5018 ")"3561 COMMA@5018..5019 ","3562 WHITESPACE@5019..5023 "\n\n "3563 MEMBER_FIELD_METHOD@5023..56903564 FIELD_NAME_FIXED@5023..50403565 NAME@5023..50403566 IDENT@5023..5040 "manifestXmlJsonml"3567 PARAMS_DESC@5040..50473568 L_PAREN@5040..5041 "("3569 PARAM@5041..50463570 DESTRUCT_FULL@5041..50463571 NAME@5041..50463572 IDENT@5041..5046 "value"3573 R_PAREN@5046..5047 ")"3574 COLONCOLON@5047..5049 "::"3575 WHITESPACE@5049..5054 "\n "3576 EXPR@5054..56903577 EXPR_IF_THEN_ELSE@5054..56903578 IF_KW@5054..5056 "if"3579 WHITESPACE@5056..5057 " "3580 EXPR@5057..50763581 EXPR_UNARY@5057..50763582 NOT@5057..5058 "!"3583 EXPR_VAR@5058..50613584 NAME@5058..50613585 IDENT@5058..5061 "std"3586 SUFFIX_INDEX@5061..50693587 DOT@5061..5062 "."3588 NAME@5062..50693589 IDENT@5062..5069 "isArray"3590 SUFFIX_APPLY@5069..50763591 ARGS_DESC@5069..50763592 L_PAREN@5069..5070 "("3593 ARG@5070..50753594 EXPR@5070..50753595 EXPR_VAR@5070..50753596 NAME@5070..50753597 IDENT@5070..5075 "value"3598 R_PAREN@5075..5076 ")"3599 WHITESPACE@5076..5077 " "3600 THEN_KW@5077..5081 "then"3601 WHITESPACE@5081..5088 "\n "3602 TRUE_EXPR@5088..51563603 EXPR@5088..51563604 EXPR_ERROR@5088..51563605 ERROR_KW@5088..5093 "error"3606 WHITESPACE@5093..5094 " "3607 EXPR@5094..51563608 EXPR_BINARY@5094..51563609 EXPR@5094..51383610 EXPR_STRING@5094..51383611 STRING_SINGLE@5094..5138 "'Expected a JSONML va ..."3612 WHITESPACE@5138..5139 " "3613 MODULO@5139..5140 "%"3614 WHITESPACE@5140..5141 " "3615 EXPR@5141..51563616 EXPR_VAR@5141..51443617 NAME@5141..51443618 IDENT@5141..5144 "std"3619 SUFFIX_INDEX@5144..51493620 DOT@5144..5145 "."3621 NAME@5145..51493622 IDENT@5145..5149 "type"3623 SUFFIX_APPLY@5149..51563624 ARGS_DESC@5149..51563625 L_PAREN@5149..5150 "("3626 ARG@5150..51553627 EXPR@5150..51553628 EXPR_VAR@5150..51553629 NAME@5150..51553630 IDENT@5150..5155 "value"3631 R_PAREN@5155..5156 ")"3632 WHITESPACE@5156..5161 "\n "3633 ELSE_KW@5161..5165 "else"3634 WHITESPACE@5165..5172 "\n "3635 FALSE_EXPR@5172..56903636 EXPR@5172..56903637 STMT_LOCAL@5172..56723638 LOCAL_KW@5172..5177 "local"3639 WHITESPACE@5177..5178 " "3640 BIND_FUNCTION@5178..56713641 NAME@5178..51813642 IDENT@5178..5181 "aux"3643 PARAMS_DESC@5181..51843644 L_PAREN@5181..5182 "("3645 PARAM@5182..51833646 DESTRUCT_FULL@5182..51833647 NAME@5182..51833648 IDENT@5182..5183 "v"3649 R_PAREN@5183..5184 ")"3650 WHITESPACE@5184..5185 " "3651 ASSIGN@5185..5186 "="3652 WHITESPACE@5186..5195 "\n "3653 EXPR@5195..56713654 EXPR_IF_THEN_ELSE@5195..56713655 IF_KW@5195..5197 "if"3656 WHITESPACE@5197..5198 " "3657 EXPR@5198..52133658 EXPR_VAR@5198..52013659 NAME@5198..52013660 IDENT@5198..5201 "std"3661 SUFFIX_INDEX@5201..52103662 DOT@5201..5202 "."3663 NAME@5202..52103664 IDENT@5202..5210 "isString"3665 SUFFIX_APPLY@5210..52133666 ARGS_DESC@5210..52133667 L_PAREN@5210..5211 "("3668 ARG@5211..52123669 EXPR@5211..52123670 EXPR_VAR@5211..52123671 NAME@5211..52123672 IDENT@5211..5212 "v"3673 R_PAREN@5212..5213 ")"3674 WHITESPACE@5213..5214 " "3675 THEN_KW@5214..5218 "then"3676 WHITESPACE@5218..5229 "\n "3677 TRUE_EXPR@5229..52303678 EXPR@5229..52303679 EXPR_VAR@5229..52303680 NAME@5229..52303681 IDENT@5229..5230 "v"3682 WHITESPACE@5230..5239 "\n "3683 ELSE_KW@5239..5243 "else"3684 WHITESPACE@5243..5254 "\n "3685 FALSE_EXPR@5254..56713686 EXPR@5254..56713687 STMT_LOCAL@5254..52713688 LOCAL_KW@5254..5259 "local"3689 WHITESPACE@5259..5260 " "3690 BIND_DESTRUCT@5260..52703691 DESTRUCT_FULL@5260..52633692 NAME@5260..52633693 IDENT@5260..5263 "tag"3694 WHITESPACE@5263..5264 " "3695 ASSIGN@5264..5265 "="3696 WHITESPACE@5265..5266 " "3697 EXPR@5266..52703698 EXPR_VAR@5266..52673699 NAME@5266..52673700 IDENT@5266..5267 "v"3701 SUFFIX_INDEX_EXPR@5267..52703702 L_BRACK@5267..5268 "["3703 EXPR@5268..52693704 EXPR_NUMBER@5268..52693705 FLOAT@5268..5269 "0"3706 R_BRACK@5269..5270 "]"3707 SEMI@5270..5271 ";"3708 WHITESPACE@5271..5282 "\n "3709 STMT_LOCAL@5282..53403710 LOCAL_KW@5282..5287 "local"3711 WHITESPACE@5287..5288 " "3712 BIND_DESTRUCT@5288..53393713 DESTRUCT_FULL@5288..52973714 NAME@5288..52973715 IDENT@5288..5297 "has_attrs"3716 WHITESPACE@5297..5298 " "3717 ASSIGN@5298..5299 "="3718 WHITESPACE@5299..5300 " "3719 EXPR@5300..53393720 EXPR_BINARY@5300..53393721 EXPR@5300..53173722 EXPR_BINARY@5300..53173723 EXPR@5300..53033724 EXPR_VAR@5300..53033725 NAME@5300..53033726 IDENT@5300..5303 "std"3727 SUFFIX_INDEX@5303..53103728 DOT@5303..5304 "."3729 NAME@5304..53103730 IDENT@5304..5310 "length"3731 SUFFIX_APPLY@5310..53133732 ARGS_DESC@5310..53133733 L_PAREN@5310..5311 "("3734 ARG@5311..53123735 EXPR@5311..53123736 EXPR_VAR@5311..53123737 NAME@5311..53123738 IDENT@5311..5312 "v"3739 R_PAREN@5312..5313 ")"3740 WHITESPACE@5313..5314 " "3741 GT@5314..5315 ">"3742 WHITESPACE@5315..5316 " "3743 EXPR@5316..53173744 EXPR_NUMBER@5316..53173745 FLOAT@5316..5317 "1"3746 WHITESPACE@5317..5318 " "3747 AND@5318..5320 "&&"3748 WHITESPACE@5320..5321 " "3749 EXPR@5321..53393750 EXPR_VAR@5321..53243751 NAME@5321..53243752 IDENT@5321..5324 "std"3753 SUFFIX_INDEX@5324..53333754 DOT@5324..5325 "."3755 NAME@5325..53333756 IDENT@5325..5333 "isObject"3757 SUFFIX_APPLY@5333..53393758 ARGS_DESC@5333..53393759 L_PAREN@5333..5334 "("3760 ARG@5334..53383761 EXPR@5334..53383762 EXPR_VAR@5334..53353763 NAME@5334..53353764 IDENT@5334..5335 "v"3765 SUFFIX_INDEX_EXPR@5335..53383766 L_BRACK@5335..5336 "["3767 EXPR@5336..53373768 EXPR_NUMBER@5336..53373769 FLOAT@5336..5337 "1"3770 R_BRACK@5337..5338 "]"3771 R_PAREN@5338..5339 ")"3772 SEMI@5339..5340 ";"3773 WHITESPACE@5340..5351 "\n "3774 STMT_LOCAL@5351..53963775 LOCAL_KW@5351..5356 "local"3776 WHITESPACE@5356..5357 " "3777 BIND_DESTRUCT@5357..53953778 DESTRUCT_FULL@5357..53623779 NAME@5357..53623780 IDENT@5357..5362 "attrs"3781 WHITESPACE@5362..5363 " "3782 ASSIGN@5363..5364 "="3783 WHITESPACE@5364..5365 " "3784 EXPR@5365..53953785 EXPR_IF_THEN_ELSE@5365..53953786 IF_KW@5365..5367 "if"3787 WHITESPACE@5367..5368 " "3788 EXPR@5368..53773789 EXPR_VAR@5368..53773790 NAME@5368..53773791 IDENT@5368..5377 "has_attrs"3792 WHITESPACE@5377..5378 " "3793 THEN_KW@5378..5382 "then"3794 WHITESPACE@5382..5383 " "3795 TRUE_EXPR@5383..53873796 EXPR@5383..53873797 EXPR_VAR@5383..53843798 NAME@5383..53843799 IDENT@5383..5384 "v"3800 SUFFIX_INDEX_EXPR@5384..53873801 L_BRACK@5384..5385 "["3802 EXPR@5385..53863803 EXPR_NUMBER@5385..53863804 FLOAT@5385..5386 "1"3805 R_BRACK@5386..5387 "]"3806 WHITESPACE@5387..5388 " "3807 ELSE_KW@5388..5392 "else"3808 WHITESPACE@5392..5393 " "3809 FALSE_EXPR@5393..53953810 EXPR@5393..53953811 EXPR_OBJECT@5393..53953812 OBJ_BODY_MEMBER_LIST@5393..53953813 L_BRACE@5393..5394 "{"3814 R_BRACE@5394..5395 "}"3815 SEMI@5395..5396 ";"3816 WHITESPACE@5396..5407 "\n "3817 STMT_LOCAL@5407..54593818 LOCAL_KW@5407..5412 "local"3819 WHITESPACE@5412..5413 " "3820 BIND_DESTRUCT@5413..54583821 DESTRUCT_FULL@5413..54213822 NAME@5413..54213823 IDENT@5413..5421 "children"3824 WHITESPACE@5421..5422 " "3825 ASSIGN@5422..5423 "="3826 WHITESPACE@5423..5424 " "3827 EXPR@5424..54583828 EXPR_IF_THEN_ELSE@5424..54583829 IF_KW@5424..5426 "if"3830 WHITESPACE@5426..5427 " "3831 EXPR@5427..54363832 EXPR_VAR@5427..54363833 NAME@5427..54363834 IDENT@5427..5436 "has_attrs"3835 WHITESPACE@5436..5437 " "3836 THEN_KW@5437..5441 "then"3837 WHITESPACE@5441..5442 " "3838 TRUE_EXPR@5442..54473839 EXPR@5442..54473840 EXPR_VAR@5442..54433841 NAME@5442..54433842 IDENT@5442..5443 "v"3843 SUFFIX_SLICE@5443..54473844 SLICE_DESC@5443..54473845 L_BRACK@5443..5444 "["3846 EXPR@5444..54453847 EXPR_NUMBER@5444..54453848 FLOAT@5444..5445 "2"3849 COLON@5445..5446 ":"3850 R_BRACK@5446..5447 "]"3851 WHITESPACE@5447..5448 " "3852 ELSE_KW@5448..5452 "else"3853 WHITESPACE@5452..5453 " "3854 FALSE_EXPR@5453..54583855 EXPR@5453..54583856 EXPR_VAR@5453..54543857 NAME@5453..54543858 IDENT@5453..5454 "v"3859 SUFFIX_SLICE@5454..54583860 SLICE_DESC@5454..54583861 L_BRACK@5454..5455 "["3862 EXPR@5455..54563863 EXPR_NUMBER@5455..54563864 FLOAT@5455..5456 "1"3865 COLON@5456..5457 ":"3866 R_BRACK@5457..5458 "]"3867 SEMI@5458..5459 ";"3868 WHITESPACE@5459..5470 "\n "3869 STMT_LOCAL@5470..55763870 LOCAL_KW@5470..5475 "local"3871 WHITESPACE@5475..5476 " "3872 BIND_DESTRUCT@5476..55753873 DESTRUCT_FULL@5476..54853874 NAME@5476..54853875 IDENT@5476..5485 "attrs_str"3876 WHITESPACE@5485..5486 " "3877 ASSIGN@5486..5487 "="3878 WHITESPACE@5487..5500 "\n "3879 EXPR@5500..55753880 EXPR_VAR@5500..55033881 NAME@5500..55033882 IDENT@5500..5503 "std"3883 SUFFIX_INDEX@5503..55083884 DOT@5503..5504 "."3885 NAME@5504..55083886 IDENT@5504..5508 "join"3887 SUFFIX_APPLY@5508..55753888 ARGS_DESC@5508..55753889 L_PAREN@5508..5509 "("3890 ARG@5509..55113891 EXPR@5509..55113892 EXPR_STRING@5509..55113893 STRING_SINGLE@5509..5511 "''"3894 COMMA@5511..5512 ","3895 WHITESPACE@5512..5513 " "3896 ARG@5513..55743897 EXPR@5513..55743898 EXPR_ARRAY_COMP@5513..55743899 L_BRACK@5513..5514 "["3900 EXPR@5514..55403901 EXPR_BINARY@5514..55403902 EXPR@5514..55243903 EXPR_STRING@5514..55243904 STRING_SINGLE@5514..5524 "' %s=\"%s\"'"3905 WHITESPACE@5524..5525 " "3906 MODULO@5525..5526 "%"3907 WHITESPACE@5526..5527 " "3908 EXPR@5527..55403909 EXPR_ARRAY@5527..55403910 L_BRACK@5527..5528 "["3911 EXPR@5528..55293912 EXPR_VAR@5528..55293913 NAME@5528..55293914 IDENT@5528..5529 "k"3915 COMMA@5529..5530 ","3916 WHITESPACE@5530..5531 " "3917 EXPR@5531..55393918 EXPR_VAR@5531..55363919 NAME@5531..55363920 IDENT@5531..5536 "attrs"3921 SUFFIX_INDEX_EXPR@5536..55393922 L_BRACK@5536..5537 "["3923 EXPR@5537..55383924 EXPR_VAR@5537..55383925 NAME@5537..55383926 IDENT@5537..5538 "k"3927 R_BRACK@5538..5539 "]"3928 R_BRACK@5539..5540 "]"3929 WHITESPACE@5540..5541 " "3930 FOR_SPEC@5541..55733931 FOR_KW@5541..5544 "for"3932 WHITESPACE@5544..5545 " "3933 DESTRUCT_FULL@5545..55463934 NAME@5545..55463935 IDENT@5545..5546 "k"3936 WHITESPACE@5546..5547 " "3937 IN_KW@5547..5549 "in"3938 WHITESPACE@5549..5550 " "3939 EXPR@5550..55733940 EXPR_VAR@5550..55533941 NAME@5550..55533942 IDENT@5550..5553 "std"3943 SUFFIX_INDEX@5553..55663944 DOT@5553..5554 "."3945 NAME@5554..55663946 IDENT@5554..5566 "objectFields"3947 SUFFIX_APPLY@5566..55733948 ARGS_DESC@5566..55733949 L_PAREN@5566..5567 "("3950 ARG@5567..55723951 EXPR@5567..55723952 EXPR_VAR@5567..55723953 NAME@5567..55723954 IDENT@5567..5572 "attrs"3955 R_PAREN@5572..5573 ")"3956 R_BRACK@5573..5574 "]"3957 R_PAREN@5574..5575 ")"3958 SEMI@5575..5576 ";"3959 WHITESPACE@5576..5587 "\n "3960 EXPR_VAR@5587..55903961 NAME@5587..55903962 IDENT@5587..5590 "std"3963 SUFFIX_INDEX@5590..55993964 DOT@5590..5591 "."3965 NAME@5591..55993966 IDENT@5591..5599 "deepJoin"3967 SUFFIX_APPLY@5599..56713968 ARGS_DESC@5599..56713969 L_PAREN@5599..5600 "("3970 ARG@5600..56703971 EXPR@5600..56703972 EXPR_ARRAY@5600..56703973 L_BRACK@5600..5601 "["3974 EXPR@5601..56043975 EXPR_STRING@5601..56043976 STRING_SINGLE@5601..5604 "'<'"3977 COMMA@5604..5605 ","3978 WHITESPACE@5605..5606 " "3979 EXPR@5606..56093980 EXPR_VAR@5606..56093981 NAME@5606..56093982 IDENT@5606..5609 "tag"3983 COMMA@5609..5610 ","3984 WHITESPACE@5610..5611 " "3985 EXPR@5611..56203986 EXPR_VAR@5611..56203987 NAME@5611..56203988 IDENT@5611..5620 "attrs_str"3989 COMMA@5620..5621 ","3990 WHITESPACE@5621..5622 " "3991 EXPR@5622..56253992 EXPR_STRING@5622..56253993 STRING_SINGLE@5622..5625 "'>'"3994 COMMA@5625..5626 ","3995 WHITESPACE@5626..5627 " "3996 EXPR@5627..56533997 EXPR_ARRAY_COMP@5627..56533998 L_BRACK@5627..5628 "["3999 EXPR@5628..56344000 EXPR_VAR@5628..56314001 NAME@5628..56314002 IDENT@5628..5631 "aux"4003 SUFFIX_APPLY@5631..56344004 ARGS_DESC@5631..56344005 L_PAREN@5631..5632 "("4006 ARG@5632..56334007 EXPR@5632..56334008 EXPR_VAR@5632..56334009 NAME@5632..56334010 IDENT@5632..5633 "x"4011 R_PAREN@5633..5634 ")"4012 WHITESPACE@5634..5635 " "4013 FOR_SPEC@5635..56524014 FOR_KW@5635..5638 "for"4015 WHITESPACE@5638..5639 " "4016 DESTRUCT_FULL@5639..56404017 NAME@5639..56404018 IDENT@5639..5640 "x"4019 WHITESPACE@5640..5641 " "4020 IN_KW@5641..5643 "in"4021 WHITESPACE@5643..5644 " "4022 EXPR@5644..56524023 EXPR_VAR@5644..56524024 NAME@5644..56524025 IDENT@5644..5652 "children"4026 R_BRACK@5652..5653 "]"4027 COMMA@5653..5654 ","4028 WHITESPACE@5654..5655 " "4029 EXPR@5655..56594030 EXPR_STRING@5655..56594031 STRING_SINGLE@5655..5659 "'</'"4032 COMMA@5659..5660 ","4033 WHITESPACE@5660..5661 " "4034 EXPR@5661..56644035 EXPR_VAR@5661..56644036 NAME@5661..56644037 IDENT@5661..5664 "tag"4038 COMMA@5664..5665 ","4039 WHITESPACE@5665..5666 " "4040 EXPR@5666..56694041 EXPR_STRING@5666..56694042 STRING_SINGLE@5666..5669 "'>'"4043 R_BRACK@5669..5670 "]"4044 R_PAREN@5670..5671 ")"4045 SEMI@5671..5672 ";"4046 WHITESPACE@5672..5680 "\n\n "4047 EXPR_VAR@5680..56834048 NAME@5680..56834049 IDENT@5680..5683 "aux"4050 SUFFIX_APPLY@5683..56904051 ARGS_DESC@5683..56904052 L_PAREN@5683..5684 "("4053 ARG@5684..56894054 EXPR@5684..56894055 EXPR_VAR@5684..56894056 NAME@5684..56894057 IDENT@5684..5689 "value"4058 R_PAREN@5689..5690 ")"4059 COMMA@5690..5691 ","4060 WHITESPACE@5691..5695 "\n\n "4061 MEMBER_FIELD_METHOD@5695..64834062 FIELD_NAME_FIXED@5695..57054063 NAME@5695..57054064 IDENT@5695..5705 "mergePatch"4065 PARAMS_DESC@5705..57204066 L_PAREN@5705..5706 "("4067 PARAM@5706..57124068 DESTRUCT_FULL@5706..57124069 NAME@5706..57124070 IDENT@5706..5712 "target"4071 COMMA@5712..5713 ","4072 WHITESPACE@5713..5714 " "4073 PARAM@5714..57194074 DESTRUCT_FULL@5714..57194075 NAME@5714..57194076 IDENT@5714..5719 "patch"4077 R_PAREN@5719..5720 ")"4078 COLONCOLON@5720..5722 "::"4079 WHITESPACE@5722..5727 "\n "4080 EXPR@5727..64834081 EXPR_IF_THEN_ELSE@5727..64834082 IF_KW@5727..5729 "if"4083 WHITESPACE@5729..5730 " "4084 EXPR@5730..57494085 EXPR_VAR@5730..57334086 NAME@5730..57334087 IDENT@5730..5733 "std"4088 SUFFIX_INDEX@5733..57424089 DOT@5733..5734 "."4090 NAME@5734..57424091 IDENT@5734..5742 "isObject"4092 SUFFIX_APPLY@5742..57494093 ARGS_DESC@5742..57494094 L_PAREN@5742..5743 "("4095 ARG@5743..57484096 EXPR@5743..57484097 EXPR_VAR@5743..57484098 NAME@5743..57484099 IDENT@5743..5748 "patch"4100 R_PAREN@5748..5749 ")"4101 WHITESPACE@5749..5750 " "4102 THEN_KW@5750..5754 "then"4103 WHITESPACE@5754..5761 "\n "4104 TRUE_EXPR@5761..64624105 EXPR@5761..64624106 STMT_LOCAL@5761..58354107 LOCAL_KW@5761..5766 "local"4108 WHITESPACE@5766..5767 " "4109 BIND_DESTRUCT@5767..58344110 DESTRUCT_FULL@5767..57804111 NAME@5767..57804112 IDENT@5767..5780 "target_object"4113 WHITESPACE@5780..5781 " "4114 ASSIGN@5781..5782 "="4115 WHITESPACE@5782..5791 "\n "4116 EXPR@5791..58344117 EXPR_IF_THEN_ELSE@5791..58344118 IF_KW@5791..5793 "if"4119 WHITESPACE@5793..5794 " "4120 EXPR@5794..58144121 EXPR_VAR@5794..57974122 NAME@5794..57974123 IDENT@5794..5797 "std"4124 SUFFIX_INDEX@5797..58064125 DOT@5797..5798 "."4126 NAME@5798..58064127 IDENT@5798..5806 "isObject"4128 SUFFIX_APPLY@5806..58144129 ARGS_DESC@5806..58144130 L_PAREN@5806..5807 "("4131 ARG@5807..58134132 EXPR@5807..58134133 EXPR_VAR@5807..58134134 NAME@5807..58134135 IDENT@5807..5813 "target"4136 R_PAREN@5813..5814 ")"4137 WHITESPACE@5814..5815 " "4138 THEN_KW@5815..5819 "then"4139 WHITESPACE@5819..5820 " "4140 TRUE_EXPR@5820..58264141 EXPR@5820..58264142 EXPR_VAR@5820..58264143 NAME@5820..58264144 IDENT@5820..5826 "target"4145 WHITESPACE@5826..5827 " "4146 ELSE_KW@5827..5831 "else"4147 WHITESPACE@5831..5832 " "4148 FALSE_EXPR@5832..58344149 EXPR@5832..58344150 EXPR_OBJECT@5832..58344151 OBJ_BODY_MEMBER_LIST@5832..58344152 L_BRACE@5832..5833 "{"4153 R_BRACE@5833..5834 "}"4154 SEMI@5834..5835 ";"4155 WHITESPACE@5835..5843 "\n\n "4156 STMT_LOCAL@5843..59494157 LOCAL_KW@5843..5848 "local"4158 WHITESPACE@5848..5849 " "4159 BIND_DESTRUCT@5849..59484160 DESTRUCT_FULL@5849..58624161 NAME@5849..58624162 IDENT@5849..5862 "target_fields"4163 WHITESPACE@5862..5863 " "4164 ASSIGN@5863..5864 "="4165 WHITESPACE@5864..5873 "\n "4166 EXPR@5873..59484167 EXPR_IF_THEN_ELSE@5873..59484168 IF_KW@5873..5875 "if"4169 WHITESPACE@5875..5876 " "4170 EXPR@5876..59034171 EXPR_VAR@5876..58794172 NAME@5876..58794173 IDENT@5876..5879 "std"4174 SUFFIX_INDEX@5879..58884175 DOT@5879..5880 "."4176 NAME@5880..58884177 IDENT@5880..5888 "isObject"4178 SUFFIX_APPLY@5888..59034179 ARGS_DESC@5888..59034180 L_PAREN@5888..5889 "("4181 ARG@5889..59024182 EXPR@5889..59024183 EXPR_VAR@5889..59024184 NAME@5889..59024185 IDENT@5889..5902 "target_object"4186 R_PAREN@5902..5903 ")"4187 WHITESPACE@5903..5904 " "4188 THEN_KW@5904..5908 "then"4189 WHITESPACE@5908..5909 " "4190 TRUE_EXPR@5909..59404191 EXPR@5909..59404192 EXPR_VAR@5909..59124193 NAME@5909..59124194 IDENT@5909..5912 "std"4195 SUFFIX_INDEX@5912..59254196 DOT@5912..5913 "."4197 NAME@5913..59254198 IDENT@5913..5925 "objectFields"4199 SUFFIX_APPLY@5925..59404200 ARGS_DESC@5925..59404201 L_PAREN@5925..5926 "("4202 ARG@5926..59394203 EXPR@5926..59394204 EXPR_VAR@5926..59394205 NAME@5926..59394206 IDENT@5926..5939 "target_object"4207 R_PAREN@5939..5940 ")"4208 WHITESPACE@5940..5941 " "4209 ELSE_KW@5941..5945 "else"4210 WHITESPACE@5945..5946 " "4211 FALSE_EXPR@5946..59484212 EXPR@5946..59484213 EXPR_ARRAY@5946..59484214 L_BRACK@5946..5947 "["4215 R_BRACK@5947..5948 "]"4216 SEMI@5948..5949 ";"4217 WHITESPACE@5949..5957 "\n\n "4218 STMT_LOCAL@5957..60344219 LOCAL_KW@5957..5962 "local"4220 WHITESPACE@5962..5963 " "4221 BIND_DESTRUCT@5963..60334222 DESTRUCT_FULL@5963..59744223 NAME@5963..59744224 IDENT@5963..5974 "null_fields"4225 WHITESPACE@5974..5975 " "4226 ASSIGN@5975..5976 "="4227 WHITESPACE@5976..5977 " "4228 EXPR@5977..60334229 EXPR_ARRAY_COMP@5977..60334230 L_BRACK@5977..5978 "["4231 EXPR@5978..59794232 EXPR_VAR@5978..59794233 NAME@5978..59794234 IDENT@5978..5979 "k"4235 WHITESPACE@5979..5980 " "4236 FOR_SPEC@5980..60124237 FOR_KW@5980..5983 "for"4238 WHITESPACE@5983..5984 " "4239 DESTRUCT_FULL@5984..59854240 NAME@5984..59854241 IDENT@5984..5985 "k"4242 WHITESPACE@5985..5986 " "4243 IN_KW@5986..5988 "in"4244 WHITESPACE@5988..5989 " "4245 EXPR@5989..60124246 EXPR_VAR@5989..59924247 NAME@5989..59924248 IDENT@5989..5992 "std"4249 SUFFIX_INDEX@5992..60054250 DOT@5992..5993 "."4251 NAME@5993..60054252 IDENT@5993..6005 "objectFields"4253 SUFFIX_APPLY@6005..60124254 ARGS_DESC@6005..60124255 L_PAREN@6005..6006 "("4256 ARG@6006..60114257 EXPR@6006..60114258 EXPR_VAR@6006..60114259 NAME@6006..60114260 IDENT@6006..6011 "patch"4261 R_PAREN@6011..6012 ")"4262 WHITESPACE@6012..6013 " "4263 IF_SPEC@6013..60324264 IF_KW@6013..6015 "if"4265 WHITESPACE@6015..6016 " "4266 EXPR@6016..60324267 EXPR_BINARY@6016..60324268 EXPR@6016..60214269 EXPR_VAR@6016..60214270 NAME@6016..60214271 IDENT@6016..6021 "patch"4272 SUFFIX_INDEX_EXPR@6021..60244273 L_BRACK@6021..6022 "["4274 EXPR@6022..60234275 EXPR_VAR@6022..60234276 NAME@6022..60234277 IDENT@6022..6023 "k"4278 R_BRACK@6023..6024 "]"4279 WHITESPACE@6024..6025 " "4280 EQ@6025..6027 "=="4281 WHITESPACE@6027..6028 " "4282 EXPR@6028..60324283 EXPR_LITERAL@6028..60324284 NULL_KW@6028..6032 "null"4285 R_BRACK@6032..6033 "]"4286 SEMI@6033..6034 ";"4287 WHITESPACE@6034..6041 "\n "4288 STMT_LOCAL@6041..61144289 LOCAL_KW@6041..6046 "local"4290 WHITESPACE@6046..6047 " "4291 BIND_DESTRUCT@6047..61134292 DESTRUCT_FULL@6047..60584293 NAME@6047..60584294 IDENT@6047..6058 "both_fields"4295 WHITESPACE@6058..6059 " "4296 ASSIGN@6059..6060 "="4297 WHITESPACE@6060..6061 " "4298 EXPR@6061..61134299 EXPR_VAR@6061..60644300 NAME@6061..60644301 IDENT@6061..6064 "std"4302 SUFFIX_INDEX@6064..60734303 DOT@6064..6065 "."4304 NAME@6065..60734305 IDENT@6065..6073 "setUnion"4306 SUFFIX_APPLY@6073..61134307 ARGS_DESC@6073..61134308 L_PAREN@6073..6074 "("4309 ARG@6074..60874310 EXPR@6074..60874311 EXPR_VAR@6074..60874312 NAME@6074..60874313 IDENT@6074..6087 "target_fields"4314 COMMA@6087..6088 ","4315 WHITESPACE@6088..6089 " "4316 ARG@6089..61124317 EXPR@6089..61124318 EXPR_VAR@6089..60924319 NAME@6089..60924320 IDENT@6089..6092 "std"4321 SUFFIX_INDEX@6092..61054322 DOT@6092..6093 "."4323 NAME@6093..61054324 IDENT@6093..6105 "objectFields"4325 SUFFIX_APPLY@6105..61124326 ARGS_DESC@6105..61124327 L_PAREN@6105..6106 "("4328 ARG@6106..61114329 EXPR@6106..61114330 EXPR_VAR@6106..61114331 NAME@6106..61114332 IDENT@6106..6111 "patch"4333 R_PAREN@6111..6112 ")"4334 R_PAREN@6112..6113 ")"4335 SEMI@6113..6114 ";"4336 WHITESPACE@6114..6122 "\n\n "4337 EXPR_OBJECT@6122..64624338 OBJ_BODY_COMP@6122..64624339 L_BRACE@6122..6123 "{"4340 WHITESPACE@6123..6132 "\n "4341 MEMBER_FIELD_NORMAL@6132..63994342 FIELD_NAME_DYNAMIC@6132..61354343 L_BRACK@6132..6133 "["4344 EXPR@6133..61344345 EXPR_VAR@6133..61344346 NAME@6133..61344347 IDENT@6133..6134 "k"4348 R_BRACK@6134..6135 "]"4349 COLON@6135..6136 ":"4350 WHITESPACE@6136..6147 "\n "4351 EXPR@6147..63994352 EXPR_IF_THEN_ELSE@6147..63994353 IF_KW@6147..6149 "if"4354 WHITESPACE@6149..6150 " "4355 EXPR@6150..61744356 EXPR_UNARY@6150..61744357 NOT@6150..6151 "!"4358 EXPR_VAR@6151..61544359 NAME@6151..61544360 IDENT@6151..6154 "std"4361 SUFFIX_INDEX@6154..61644362 DOT@6154..6155 "."4363 NAME@6155..61644364 IDENT@6155..6164 "objectHas"4365 SUFFIX_APPLY@6164..61744366 ARGS_DESC@6164..61744367 L_PAREN@6164..6165 "("4368 ARG@6165..61704369 EXPR@6165..61704370 EXPR_VAR@6165..61704371 NAME@6165..61704372 IDENT@6165..6170 "patch"4373 COMMA@6170..6171 ","4374 WHITESPACE@6171..6172 " "4375 ARG@6172..61734376 EXPR@6172..61734377 EXPR_VAR@6172..61734378 NAME@6172..61734379 IDENT@6172..6173 "k"4380 R_PAREN@6173..6174 ")"4381 WHITESPACE@6174..6175 " "4382 THEN_KW@6175..6179 "then"4383 WHITESPACE@6179..6192 "\n "4384 TRUE_EXPR@6192..62084385 EXPR@6192..62084386 EXPR_VAR@6192..62054387 NAME@6192..62054388 IDENT@6192..6205 "target_object"4389 SUFFIX_INDEX_EXPR@6205..62084390 L_BRACK@6205..6206 "["4391 EXPR@6206..62074392 EXPR_VAR@6206..62074393 NAME@6206..62074394 IDENT@6206..6207 "k"4395 R_BRACK@6207..6208 "]"4396 WHITESPACE@6208..6219 "\n "4397 ELSE_KW@6219..6223 "else"4398 WHITESPACE@6223..6224 " "4399 FALSE_EXPR@6224..63994400 EXPR@6224..63994401 EXPR_IF_THEN_ELSE@6224..63994402 IF_KW@6224..6226 "if"4403 WHITESPACE@6226..6227 " "4404 EXPR@6227..62594405 EXPR_UNARY@6227..62594406 NOT@6227..6228 "!"4407 EXPR_VAR@6228..62314408 NAME@6228..62314409 IDENT@6228..6231 "std"4410 SUFFIX_INDEX@6231..62414411 DOT@6231..6232 "."4412 NAME@6232..62414413 IDENT@6232..6241 "objectHas"4414 SUFFIX_APPLY@6241..62594415 ARGS_DESC@6241..62594416 L_PAREN@6241..6242 "("4417 ARG@6242..62554418 EXPR@6242..62554419 EXPR_VAR@6242..62554420 NAME@6242..62554421 IDENT@6242..6255 "target_object"4422 COMMA@6255..6256 ","4423 WHITESPACE@6256..6257 " "4424 ARG@6257..62584425 EXPR@6257..62584426 EXPR_VAR@6257..62584427 NAME@6257..62584428 IDENT@6257..6258 "k"4429 R_PAREN@6258..6259 ")"4430 WHITESPACE@6259..6260 " "4431 THEN_KW@6260..6264 "then"4432 WHITESPACE@6264..6277 "\n "4433 TRUE_EXPR@6277..63184434 EXPR@6277..63184435 EXPR_VAR@6277..62804436 NAME@6277..62804437 IDENT@6277..6280 "std"4438 SUFFIX_INDEX@6280..62914439 DOT@6280..6281 "."4440 NAME@6281..62914441 IDENT@6281..6291 "mergePatch"4442 SUFFIX_APPLY@6291..63184443 ARGS_DESC@6291..63184444 L_PAREN@6291..6292 "("4445 ARG@6292..62964446 EXPR@6292..62964447 EXPR_LITERAL@6292..62964448 NULL_KW@6292..6296 "null"4449 COMMA@6296..6297 ","4450 WHITESPACE@6297..6298 " "4451 ARG@6298..63064452 EXPR@6298..63064453 EXPR_VAR@6298..63034454 NAME@6298..63034455 IDENT@6298..6303 "patch"4456 SUFFIX_INDEX_EXPR@6303..63064457 L_BRACK@6303..6304 "["4458 EXPR@6304..63054459 EXPR_VAR@6304..63054460 NAME@6304..63054461 IDENT@6304..6305 "k"4462 R_BRACK@6305..6306 "]"4463 R_PAREN@6306..6307 ")"4464 WHITESPACE@6307..6308 " "4465 TAILSTRICT_KW@6308..6318 "tailstrict"4466 WHITESPACE@6318..6329 "\n "4467 ELSE_KW@6329..6333 "else"4468 WHITESPACE@6333..6346 "\n "4469 FALSE_EXPR@6346..63994470 EXPR@6346..63994471 EXPR_VAR@6346..63494472 NAME@6346..63494473 IDENT@6346..6349 "std"4474 SUFFIX_INDEX@6349..63604475 DOT@6349..6350 "."4476 NAME@6350..63604477 IDENT@6350..6360 "mergePatch"4478 SUFFIX_APPLY@6360..63994479 ARGS_DESC@6360..63994480 L_PAREN@6360..6361 "("4481 ARG@6361..63774482 EXPR@6361..63774483 EXPR_VAR@6361..63744484 NAME@6361..63744485 IDENT@6361..6374 "target_object"4486 SUFFIX_INDEX_EXPR@6374..63774487 L_BRACK@6374..6375 "["4488 EXPR@6375..63764489 EXPR_VAR@6375..63764490 NAME@6375..63764491 IDENT@6375..6376 "k"4492 R_BRACK@6376..6377 "]"4493 COMMA@6377..6378 ","4494 WHITESPACE@6378..6379 " "4495 ARG@6379..63874496 EXPR@6379..63874497 EXPR_VAR@6379..63844498 NAME@6379..63844499 IDENT@6379..6384 "patch"4500 SUFFIX_INDEX_EXPR@6384..63874501 L_BRACK@6384..6385 "["4502 EXPR@6385..63864503 EXPR_VAR@6385..63864504 NAME@6385..63864505 IDENT@6385..6386 "k"4506 R_BRACK@6386..6387 "]"4507 R_PAREN@6387..6388 ")"4508 WHITESPACE@6388..6389 " "4509 TAILSTRICT_KW@6389..6399 "tailstrict"4510 WHITESPACE@6399..6408 "\n "4511 FOR_SPEC@6408..64544512 FOR_KW@6408..6411 "for"4513 WHITESPACE@6411..6412 " "4514 DESTRUCT_FULL@6412..64134515 NAME@6412..64134516 IDENT@6412..6413 "k"4517 WHITESPACE@6413..6414 " "4518 IN_KW@6414..6416 "in"4519 WHITESPACE@6416..6417 " "4520 EXPR@6417..64544521 EXPR_VAR@6417..64204522 NAME@6417..64204523 IDENT@6417..6420 "std"4524 SUFFIX_INDEX@6420..64284525 DOT@6420..6421 "."4526 NAME@6421..64284527 IDENT@6421..6428 "setDiff"4528 SUFFIX_APPLY@6428..64544529 ARGS_DESC@6428..64544530 L_PAREN@6428..6429 "("4531 ARG@6429..64404532 EXPR@6429..64404533 EXPR_VAR@6429..64404534 NAME@6429..64404535 IDENT@6429..6440 "both_fields"4536 COMMA@6440..6441 ","4537 WHITESPACE@6441..6442 " "4538 ARG@6442..64534539 EXPR@6442..64534540 EXPR_VAR@6442..64534541 NAME@6442..64534542 IDENT@6442..6453 "null_fields"4543 R_PAREN@6453..6454 ")"4544 WHITESPACE@6454..6461 "\n "4545 R_BRACE@6461..6462 "}"4546 WHITESPACE@6462..6467 "\n "4547 ELSE_KW@6467..6471 "else"4548 WHITESPACE@6471..6478 "\n "4549 FALSE_EXPR@6478..64834550 EXPR@6478..64834551 EXPR_VAR@6478..64834552 NAME@6478..64834553 IDENT@6478..6483 "patch"4554 COMMA@6483..6484 ","4555 WHITESPACE@6484..6488 "\n\n "4556 MEMBER_FIELD_METHOD@6488..65944557 FIELD_NAME_FIXED@6488..64914558 NAME@6488..64914559 IDENT@6488..6491 "get"4560 PARAMS_DESC@6491..65284561 L_PAREN@6491..6492 "("4562 PARAM@6492..64934563 DESTRUCT_FULL@6492..64934564 NAME@6492..64934565 IDENT@6492..6493 "o"4566 COMMA@6493..6494 ","4567 WHITESPACE@6494..6495 " "4568 PARAM@6495..64964569 DESTRUCT_FULL@6495..64964570 NAME@6495..64964571 IDENT@6495..6496 "f"4572 COMMA@6496..6497 ","4573 WHITESPACE@6497..6498 " "4574 PARAM@6498..65104575 DESTRUCT_FULL@6498..65054576 NAME@6498..65054577 IDENT@6498..6505 "default"4578 ASSIGN@6505..6506 "="4579 EXPR@6506..65104580 EXPR_LITERAL@6506..65104581 NULL_KW@6506..6510 "null"4582 COMMA@6510..6511 ","4583 WHITESPACE@6511..6512 " "4584 PARAM@6512..65274585 DESTRUCT_FULL@6512..65224586 NAME@6512..65224587 IDENT@6512..6522 "inc_hidden"4588 ASSIGN@6522..6523 "="4589 EXPR@6523..65274590 EXPR_LITERAL@6523..65274591 TRUE_KW@6523..6527 "true"4592 R_PAREN@6527..6528 ")"4593 COLONCOLON@6528..6530 "::"4594 WHITESPACE@6530..6535 "\n "4595 EXPR@6535..65944596 EXPR_IF_THEN_ELSE@6535..65944597 IF_KW@6535..6537 "if"4598 WHITESPACE@6537..6538 " "4599 EXPR@6538..65714600 EXPR_VAR@6538..65414601 NAME@6538..65414602 IDENT@6538..6541 "std"4603 SUFFIX_INDEX@6541..65534604 DOT@6541..6542 "."4605 NAME@6542..65534606 IDENT@6542..6553 "objectHasEx"4607 SUFFIX_APPLY@6553..65714608 ARGS_DESC@6553..65714609 L_PAREN@6553..6554 "("4610 ARG@6554..65554611 EXPR@6554..65554612 EXPR_VAR@6554..65554613 NAME@6554..65554614 IDENT@6554..6555 "o"4615 COMMA@6555..6556 ","4616 WHITESPACE@6556..6557 " "4617 ARG@6557..65584618 EXPR@6557..65584619 EXPR_VAR@6557..65584620 NAME@6557..65584621 IDENT@6557..6558 "f"4622 COMMA@6558..6559 ","4623 WHITESPACE@6559..6560 " "4624 ARG@6560..65704625 EXPR@6560..65704626 EXPR_VAR@6560..65704627 NAME@6560..65704628 IDENT@6560..6570 "inc_hidden"4629 R_PAREN@6570..6571 ")"4630 WHITESPACE@6571..6572 " "4631 THEN_KW@6572..6576 "then"4632 WHITESPACE@6576..6577 " "4633 TRUE_EXPR@6577..65814634 EXPR@6577..65814635 EXPR_VAR@6577..65784636 NAME@6577..65784637 IDENT@6577..6578 "o"4638 SUFFIX_INDEX_EXPR@6578..65814639 L_BRACK@6578..6579 "["4640 EXPR@6579..65804641 EXPR_VAR@6579..65804642 NAME@6579..65804643 IDENT@6579..6580 "f"4644 R_BRACK@6580..6581 "]"4645 WHITESPACE@6581..6582 " "4646 ELSE_KW@6582..6586 "else"4647 WHITESPACE@6586..6587 " "4648 FALSE_EXPR@6587..65944649 EXPR@6587..65944650 EXPR_VAR@6587..65944651 NAME@6587..65944652 IDENT@6587..6594 "default"4653 COMMA@6594..6595 ","4654 WHITESPACE@6595..6599 "\n\n "4655 MEMBER_FIELD_METHOD@6599..67334656 FIELD_NAME_FIXED@6599..66104657 NAME@6599..66104658 IDENT@6599..6610 "resolvePath"4659 PARAMS_DESC@6610..66164660 L_PAREN@6610..6611 "("4661 PARAM@6611..66124662 DESTRUCT_FULL@6611..66124663 NAME@6611..66124664 IDENT@6611..6612 "f"4665 COMMA@6612..6613 ","4666 WHITESPACE@6613..6614 " "4667 PARAM@6614..66154668 DESTRUCT_FULL@6614..66154669 NAME@6614..66154670 IDENT@6614..6615 "r"4671 R_PAREN@6615..6616 ")"4672 COLONCOLON@6616..6618 "::"4673 WHITESPACE@6618..6623 "\n "4674 EXPR@6623..67334675 STMT_LOCAL@6623..66534676 LOCAL_KW@6623..6628 "local"4677 WHITESPACE@6628..6629 " "4678 BIND_DESTRUCT@6629..66524679 DESTRUCT_FULL@6629..66324680 NAME@6629..66324681 IDENT@6629..6632 "arr"4682 WHITESPACE@6632..6633 " "4683 ASSIGN@6633..6634 "="4684 WHITESPACE@6634..6635 " "4685 EXPR@6635..66524686 EXPR_VAR@6635..66384687 NAME@6635..66384688 IDENT@6635..6638 "std"4689 SUFFIX_INDEX@6638..66444690 DOT@6638..6639 "."4691 NAME@6639..66444692 IDENT@6639..6644 "split"4693 SUFFIX_APPLY@6644..66524694 ARGS_DESC@6644..66524695 L_PAREN@6644..6645 "("4696 ARG@6645..66464697 EXPR@6645..66464698 EXPR_VAR@6645..66464699 NAME@6645..66464700 IDENT@6645..6646 "f"4701 COMMA@6646..6647 ","4702 WHITESPACE@6647..6648 " "4703 ARG@6648..66514704 EXPR@6648..66514705 EXPR_STRING@6648..66514706 STRING_SINGLE@6648..6651 "'/'"4707 R_PAREN@6651..6652 ")"4708 SEMI@6652..6653 ";"4709 WHITESPACE@6653..6658 "\n "4710 EXPR_VAR@6658..66614711 NAME@6658..66614712 IDENT@6658..6661 "std"4713 SUFFIX_INDEX@6661..66664714 DOT@6661..6662 "."4715 NAME@6662..66664716 IDENT@6662..6666 "join"4717 SUFFIX_APPLY@6666..67334718 ARGS_DESC@6666..67334719 L_PAREN@6666..6667 "("4720 ARG@6667..66704721 EXPR@6667..66704722 EXPR_STRING@6667..66704723 STRING_SINGLE@6667..6670 "'/'"4724 COMMA@6670..6671 ","4725 WHITESPACE@6671..6672 " "4726 ARG@6672..67324727 EXPR@6672..67324728 EXPR_BINARY@6672..67324729 EXPR@6672..66754730 EXPR_VAR@6672..66754731 NAME@6672..66754732 IDENT@6672..6675 "std"4733 SUFFIX_INDEX@6675..66854734 DOT@6675..6676 "."4735 NAME@6676..66854736 IDENT@6676..6685 "makeArray"4737 SUFFIX_APPLY@6685..67264738 ARGS_DESC@6685..67264739 L_PAREN@6685..6686 "("4740 ARG@6686..67054741 EXPR@6686..67054742 EXPR_BINARY@6686..67054743 EXPR@6686..66894744 EXPR_VAR@6686..66894745 NAME@6686..66894746 IDENT@6686..6689 "std"4747 SUFFIX_INDEX@6689..66964748 DOT@6689..6690 "."4749 NAME@6690..66964750 IDENT@6690..6696 "length"4751 SUFFIX_APPLY@6696..67014752 ARGS_DESC@6696..67014753 L_PAREN@6696..6697 "("4754 ARG@6697..67004755 EXPR@6697..67004756 EXPR_VAR@6697..67004757 NAME@6697..67004758 IDENT@6697..6700 "arr"4759 R_PAREN@6700..6701 ")"4760 WHITESPACE@6701..6702 " "4761 MINUS@6702..6703 "-"4762 WHITESPACE@6703..6704 " "4763 EXPR@6704..67054764 EXPR_NUMBER@6704..67054765 FLOAT@6704..6705 "1"4766 COMMA@6705..6706 ","4767 WHITESPACE@6706..6707 " "4768 ARG@6707..67254769 EXPR@6707..67254770 EXPR_FUNCTION@6707..67254771 FUNCTION_KW@6707..6715 "function"4772 PARAMS_DESC@6715..67184773 L_PAREN@6715..6716 "("4774 PARAM@6716..67174775 DESTRUCT_FULL@6716..67174776 NAME@6716..67174777 IDENT@6716..6717 "i"4778 R_PAREN@6717..6718 ")"4779 WHITESPACE@6718..6719 " "4780 EXPR@6719..67254781 EXPR_VAR@6719..67224782 NAME@6719..67224783 IDENT@6719..6722 "arr"4784 SUFFIX_INDEX_EXPR@6722..67254785 L_BRACK@6722..6723 "["4786 EXPR@6723..67244787 EXPR_VAR@6723..67244788 NAME@6723..67244789 IDENT@6723..6724 "i"4790 R_BRACK@6724..6725 "]"4791 R_PAREN@6725..6726 ")"4792 WHITESPACE@6726..6727 " "4793 PLUS@6727..6728 "+"4794 WHITESPACE@6728..6729 " "4795 EXPR@6729..67324796 EXPR_ARRAY@6729..67324797 L_BRACK@6729..6730 "["4798 EXPR@6730..67314799 EXPR_VAR@6730..67314800 NAME@6730..67314801 IDENT@6730..6731 "r"4802 R_BRACK@6731..6732 "]"4803 R_PAREN@6732..6733 ")"4804 COMMA@6733..6734 ","4805 WHITESPACE@6734..6738 "\n\n "4806 MEMBER_FIELD_METHOD@6738..71914807 FIELD_NAME_FIXED@6738..67434808 NAME@6738..67434809 IDENT@6738..6743 "prune"4810 PARAMS_DESC@6743..67464811 L_PAREN@6743..6744 "("4812 PARAM@6744..67454813 DESTRUCT_FULL@6744..67454814 NAME@6744..67454815 IDENT@6744..6745 "a"4816 R_PAREN@6745..6746 ")"4817 COLONCOLON@6746..6748 "::"4818 WHITESPACE@6748..6753 "\n "4819 EXPR@6753..71914820 STMT_LOCAL@6753..69574821 LOCAL_KW@6753..6758 "local"4822 WHITESPACE@6758..6759 " "4823 BIND_FUNCTION@6759..69564824 NAME@6759..67684825 IDENT@6759..6768 "isContent"4826 PARAMS_DESC@6768..67714827 L_PAREN@6768..6769 "("4828 PARAM@6769..67704829 DESTRUCT_FULL@6769..67704830 NAME@6769..67704831 IDENT@6769..6770 "b"4832 R_PAREN@6770..6771 ")"4833 WHITESPACE@6771..6772 " "4834 ASSIGN@6772..6773 "="4835 WHITESPACE@6773..6780 "\n "4836 EXPR@6780..69564837 EXPR_IF_THEN_ELSE@6780..69564838 IF_KW@6780..6782 "if"4839 WHITESPACE@6782..6783 " "4840 EXPR@6783..67924841 EXPR_BINARY@6783..67924842 EXPR@6783..67844843 EXPR_VAR@6783..67844844 NAME@6783..67844845 IDENT@6783..6784 "b"4846 WHITESPACE@6784..6785 " "4847 EQ@6785..6787 "=="4848 WHITESPACE@6787..6788 " "4849 EXPR@6788..67924850 EXPR_LITERAL@6788..67924851 NULL_KW@6788..6792 "null"4852 WHITESPACE@6792..6793 " "4853 THEN_KW@6793..6797 "then"4854 WHITESPACE@6797..6806 "\n "4855 TRUE_EXPR@6806..68114856 EXPR@6806..68114857 EXPR_LITERAL@6806..68114858 FALSE_KW@6806..6811 "false"4859 WHITESPACE@6811..6818 "\n "4860 ELSE_KW@6818..6822 "else"4861 WHITESPACE@6822..6823 " "4862 FALSE_EXPR@6823..69564863 EXPR@6823..69564864 EXPR_IF_THEN_ELSE@6823..69564865 IF_KW@6823..6825 "if"4866 WHITESPACE@6825..6826 " "4867 EXPR@6826..68404868 EXPR_VAR@6826..68294869 NAME@6826..68294870 IDENT@6826..6829 "std"4871 SUFFIX_INDEX@6829..68374872 DOT@6829..6830 "."4873 NAME@6830..68374874 IDENT@6830..6837 "isArray"4875 SUFFIX_APPLY@6837..68404876 ARGS_DESC@6837..68404877 L_PAREN@6837..6838 "("4878 ARG@6838..68394879 EXPR@6838..68394880 EXPR_VAR@6838..68394881 NAME@6838..68394882 IDENT@6838..6839 "b"4883 R_PAREN@6839..6840 ")"4884 WHITESPACE@6840..6841 " "4885 THEN_KW@6841..6845 "then"4886 WHITESPACE@6845..6854 "\n "4887 TRUE_EXPR@6854..68714888 EXPR@6854..68714889 EXPR_BINARY@6854..68714890 EXPR@6854..68574891 EXPR_VAR@6854..68574892 NAME@6854..68574893 IDENT@6854..6857 "std"4894 SUFFIX_INDEX@6857..68644895 DOT@6857..6858 "."4896 NAME@6858..68644897 IDENT@6858..6864 "length"4898 SUFFIX_APPLY@6864..68674899 ARGS_DESC@6864..68674900 L_PAREN@6864..6865 "("4901 ARG@6865..68664902 EXPR@6865..68664903 EXPR_VAR@6865..68664904 NAME@6865..68664905 IDENT@6865..6866 "b"4906 R_PAREN@6866..6867 ")"4907 WHITESPACE@6867..6868 " "4908 GT@6868..6869 ">"4909 WHITESPACE@6869..6870 " "4910 EXPR@6870..68714911 EXPR_NUMBER@6870..68714912 FLOAT@6870..6871 "0"4913 WHITESPACE@6871..6878 "\n "4914 ELSE_KW@6878..6882 "else"4915 WHITESPACE@6882..6883 " "4916 FALSE_EXPR@6883..69564917 EXPR@6883..69564918 EXPR_IF_THEN_ELSE@6883..69564919 IF_KW@6883..6885 "if"4920 WHITESPACE@6885..6886 " "4921 EXPR@6886..69014922 EXPR_VAR@6886..68894923 NAME@6886..68894924 IDENT@6886..6889 "std"4925 SUFFIX_INDEX@6889..68984926 DOT@6889..6890 "."4927 NAME@6890..68984928 IDENT@6890..6898 "isObject"4929 SUFFIX_APPLY@6898..69014930 ARGS_DESC@6898..69014931 L_PAREN@6898..6899 "("4932 ARG@6899..69004933 EXPR@6899..69004934 EXPR_VAR@6899..69004935 NAME@6899..69004936 IDENT@6899..6900 "b"4937 R_PAREN@6900..6901 ")"4938 WHITESPACE@6901..6902 " "4939 THEN_KW@6902..6906 "then"4940 WHITESPACE@6906..6915 "\n "4941 TRUE_EXPR@6915..69324942 EXPR@6915..69324943 EXPR_BINARY@6915..69324944 EXPR@6915..69184945 EXPR_VAR@6915..69184946 NAME@6915..69184947 IDENT@6915..6918 "std"4948 SUFFIX_INDEX@6918..69254949 DOT@6918..6919 "."4950 NAME@6919..69254951 IDENT@6919..6925 "length"4952 SUFFIX_APPLY@6925..69284953 ARGS_DESC@6925..69284954 L_PAREN@6925..6926 "("4955 ARG@6926..69274956 EXPR@6926..69274957 EXPR_VAR@6926..69274958 NAME@6926..69274959 IDENT@6926..6927 "b"4960 R_PAREN@6927..6928 ")"4961 WHITESPACE@6928..6929 " "4962 GT@6929..6930 ">"4963 WHITESPACE@6930..6931 " "4964 EXPR@6931..69324965 EXPR_NUMBER@6931..69324966 FLOAT@6931..6932 "0"4967 WHITESPACE@6932..6939 "\n "4968 ELSE_KW@6939..6943 "else"4969 WHITESPACE@6943..6952 "\n "4970 FALSE_EXPR@6952..69564971 EXPR@6952..69564972 EXPR_LITERAL@6952..69564973 TRUE_KW@6952..6956 "true"4974 SEMI@6956..6957 ";"4975 WHITESPACE@6957..6962 "\n "4976 EXPR_IF_THEN_ELSE@6962..71914977 IF_KW@6962..6964 "if"4978 WHITESPACE@6964..6965 " "4979 EXPR@6965..69794980 EXPR_VAR@6965..69684981 NAME@6965..69684982 IDENT@6965..6968 "std"4983 SUFFIX_INDEX@6968..69764984 DOT@6968..6969 "."4985 NAME@6969..69764986 IDENT@6969..6976 "isArray"4987 SUFFIX_APPLY@6976..69794988 ARGS_DESC@6976..69794989 L_PAREN@6976..6977 "("4990 ARG@6977..69784991 EXPR@6977..69784992 EXPR_VAR@6977..69784993 NAME@6977..69784994 IDENT@6977..6978 "a"4995 R_PAREN@6978..6979 ")"4996 WHITESPACE@6979..6980 " "4997 THEN_KW@6980..6984 "then"4998 WHITESPACE@6984..6991 "\n "4999 TRUE_EXPR@6991..70415000 EXPR@6991..70415001 EXPR_ARRAY_COMP@6991..70415002 L_BRACK@6991..6992 "["5003 EXPR@6992..70045004 EXPR_VAR@6992..69955005 NAME@6992..69955006 IDENT@6992..6995 "std"5007 SUFFIX_INDEX@6995..70015008 DOT@6995..6996 "."5009 NAME@6996..70015010 IDENT@6996..7001 "prune"5011 SUFFIX_APPLY@7001..70045012 ARGS_DESC@7001..70045013 L_PAREN@7001..7002 "("5014 ARG@7002..70035015 EXPR@7002..70035016 EXPR_VAR@7002..70035017 NAME@7002..70035018 IDENT@7002..7003 "x"5019 R_PAREN@7003..7004 ")"5020 WHITESPACE@7004..7005 " "5021 FOR_SPEC@7005..70155022 FOR_KW@7005..7008 "for"5023 WHITESPACE@7008..7009 " "5024 DESTRUCT_FULL@7009..70105025 NAME@7009..70105026 IDENT@7009..7010 "x"5027 WHITESPACE@7010..7011 " "5028 IN_KW@7011..7013 "in"5029 WHITESPACE@7013..7014 " "5030 EXPR@7014..70155031 EXPR_VAR@7014..70155032 NAME@7014..70155033 IDENT@7014..7015 "a"5034 WHITESPACE@7015..7016 " "5035 IF_SPEC@7016..70405036 IF_KW@7016..7018 "if"5037 WHITESPACE@7018..7019 " "5038 EXPR@7019..70405039 EXPR_VAR@7019..70285040 NAME@7019..70285041 IDENT@7019..7028 "isContent"5042 SUFFIX_APPLY@7028..70405043 ARGS_DESC@7028..70405044 L_PAREN@7028..7029 "("5045 ARG@7029..70395046 EXPR@7029..70395047 EXPR_LITERAL@7029..70305048 DOLLAR@7029..7030 "$"5049 SUFFIX_INDEX@7030..70365050 DOT@7030..7031 "."5051 NAME@7031..70365052 IDENT@7031..7036 "prune"5053 SUFFIX_APPLY@7036..70395054 ARGS_DESC@7036..70395055 L_PAREN@7036..7037 "("5056 ARG@7037..70385057 EXPR@7037..70385058 EXPR_VAR@7037..70385059 NAME@7037..70385060 IDENT@7037..7038 "x"5061 R_PAREN@7038..7039 ")"5062 R_PAREN@7039..7040 ")"5063 R_BRACK@7040..7041 "]"5064 WHITESPACE@7041..7046 "\n "5065 ELSE_KW@7046..7050 "else"5066 WHITESPACE@7050..7051 " "5067 FALSE_EXPR@7051..71915068 EXPR@7051..71915069 EXPR_IF_THEN_ELSE@7051..71915070 IF_KW@7051..7053 "if"5071 WHITESPACE@7053..7054 " "5072 EXPR@7054..70695073 EXPR_VAR@7054..70575074 NAME@7054..70575075 IDENT@7054..7057 "std"5076 SUFFIX_INDEX@7057..70665077 DOT@7057..7058 "."5078 NAME@7058..70665079 IDENT@7058..7066 "isObject"5080 SUFFIX_APPLY@7066..70695081 ARGS_DESC@7066..70695082 L_PAREN@7066..7067 "("5083 ARG@7067..70685084 EXPR@7067..70685085 EXPR_VAR@7067..70685086 NAME@7067..70685087 IDENT@7067..7068 "a"5088 R_PAREN@7068..7069 ")"5089 WHITESPACE@7069..7070 " "5090 THEN_KW@7070..7074 "then"5091 WHITESPACE@7074..7075 " "5092 TRUE_EXPR@7075..71785093 EXPR@7075..71785094 EXPR_OBJECT@7075..71785095 OBJ_BODY_COMP@7075..71785096 L_BRACE@7075..7076 "{"5097 WHITESPACE@7076..7083 "\n "5098 MEMBER_FIELD_NORMAL@7083..71015099 FIELD_NAME_DYNAMIC@7083..70865100 L_BRACK@7083..7084 "["5101 EXPR@7084..70855102 EXPR_VAR@7084..70855103 NAME@7084..70855104 IDENT@7084..7085 "x"5105 R_BRACK@7085..7086 "]"5106 COLON@7086..7087 ":"5107 WHITESPACE@7087..7088 " "5108 EXPR@7088..71015109 EXPR_LITERAL@7088..70895110 DOLLAR@7088..7089 "$"5111 SUFFIX_INDEX@7089..70955112 DOT@7089..7090 "."5113 NAME@7090..70955114 IDENT@7090..7095 "prune"5115 SUFFIX_APPLY@7095..71015116 ARGS_DESC@7095..71015117 L_PAREN@7095..7096 "("5118 ARG@7096..71005119 EXPR@7096..71005120 EXPR_VAR@7096..70975121 NAME@7096..70975122 IDENT@7096..7097 "a"5123 SUFFIX_INDEX_EXPR@7097..71005124 L_BRACK@7097..7098 "["5125 EXPR@7098..70995126 EXPR_VAR@7098..70995127 NAME@7098..70995128 IDENT@7098..7099 "x"5129 R_BRACK@7099..7100 "]"5130 R_PAREN@7100..7101 ")"5131 WHITESPACE@7101..7108 "\n "5132 FOR_SPEC@7108..71365133 FOR_KW@7108..7111 "for"5134 WHITESPACE@7111..7112 " "5135 DESTRUCT_FULL@7112..71135136 NAME@7112..71135137 IDENT@7112..7113 "x"5138 WHITESPACE@7113..7114 " "5139 IN_KW@7114..7116 "in"5140 WHITESPACE@7116..7117 " "5141 EXPR@7117..71365142 EXPR_VAR@7117..71205143 NAME@7117..71205144 IDENT@7117..7120 "std"5145 SUFFIX_INDEX@7120..71335146 DOT@7120..7121 "."5147 NAME@7121..71335148 IDENT@7121..7133 "objectFields"5149 SUFFIX_APPLY@7133..71365150 ARGS_DESC@7133..71365151 L_PAREN@7133..7134 "("5152 ARG@7134..71355153 EXPR@7134..71355154 EXPR_VAR@7134..71355155 NAME@7134..71355156 IDENT@7134..7135 "a"5157 R_PAREN@7135..7136 ")"5158 WHITESPACE@7136..7143 "\n "5159 IF_SPEC@7143..71725160 IF_KW@7143..7145 "if"5161 WHITESPACE@7145..7146 " "5162 EXPR@7146..71725163 EXPR_VAR@7146..71555164 NAME@7146..71555165 IDENT@7146..7155 "isContent"5166 SUFFIX_APPLY@7155..71725167 ARGS_DESC@7155..71725168 L_PAREN@7155..7156 "("5169 ARG@7156..71715170 EXPR@7156..71715171 EXPR_VAR@7156..71595172 NAME@7156..71595173 IDENT@7156..7159 "std"5174 SUFFIX_INDEX@7159..71655175 DOT@7159..7160 "."5176 NAME@7160..71655177 IDENT@7160..7165 "prune"5178 SUFFIX_APPLY@7165..71715179 ARGS_DESC@7165..71715180 L_PAREN@7165..7166 "("5181 ARG@7166..71705182 EXPR@7166..71705183 EXPR_VAR@7166..71675184 NAME@7166..71675185 IDENT@7166..7167 "a"5186 SUFFIX_INDEX_EXPR@7167..71705187 L_BRACK@7167..7168 "["5188 EXPR@7168..71695189 EXPR_VAR@7168..71695190 NAME@7168..71695191 IDENT@7168..7169 "x"5192 R_BRACK@7169..7170 "]"5193 R_PAREN@7170..7171 ")"5194 R_PAREN@7171..7172 ")"5195 WHITESPACE@7172..7177 "\n "5196 R_BRACE@7177..7178 "}"5197 WHITESPACE@7178..7179 " "5198 ELSE_KW@7179..7183 "else"5199 WHITESPACE@7183..7190 "\n "5200 FALSE_EXPR@7190..71915201 EXPR@7190..71915202 EXPR_VAR@7190..71915203 NAME@7190..71915204 IDENT@7190..7191 "a"5205 COMMA@7191..7192 ","5206 WHITESPACE@7192..7196 "\n\n "5207 MEMBER_FIELD_METHOD@7196..74115208 FIELD_NAME_FIXED@7196..72005209 NAME@7196..72005210 IDENT@7196..7200 "find"5211 PARAMS_DESC@7200..72125212 L_PAREN@7200..7201 "("5213 PARAM@7201..72065214 DESTRUCT_FULL@7201..72065215 NAME@7201..72065216 IDENT@7201..7206 "value"5217 COMMA@7206..7207 ","5218 WHITESPACE@7207..7208 " "5219 PARAM@7208..72115220 DESTRUCT_FULL@7208..72115221 NAME@7208..72115222 IDENT@7208..7211 "arr"5223 R_PAREN@7211..7212 ")"5224 COLONCOLON@7212..7214 "::"5225 WHITESPACE@7214..7219 "\n "5226 EXPR@7219..74115227 EXPR_IF_THEN_ELSE@7219..74115228 IF_KW@7219..7221 "if"5229 WHITESPACE@7221..7222 " "5230 EXPR@7222..72395231 EXPR_UNARY@7222..72395232 NOT@7222..7223 "!"5233 EXPR_VAR@7223..72265234 NAME@7223..72265235 IDENT@7223..7226 "std"5236 SUFFIX_INDEX@7226..72345237 DOT@7226..7227 "."5238 NAME@7227..72345239 IDENT@7227..7234 "isArray"5240 SUFFIX_APPLY@7234..72395241 ARGS_DESC@7234..72395242 L_PAREN@7234..7235 "("5243 ARG@7235..72385244 EXPR@7235..72385245 EXPR_VAR@7235..72385246 NAME@7235..72385247 IDENT@7235..7238 "arr"5248 R_PAREN@7238..7239 ")"5249 WHITESPACE@7239..7240 " "5250 THEN_KW@7240..7244 "then"5251 WHITESPACE@7244..7251 "\n "5252 TRUE_EXPR@7251..73215253 EXPR@7251..73215254 EXPR_ERROR@7251..73215255 ERROR_KW@7251..7256 "error"5256 WHITESPACE@7256..7257 " "5257 EXPR@7257..73215258 EXPR_BINARY@7257..73215259 EXPR@7257..73055260 EXPR_STRING@7257..73055261 STRING_SINGLE@7257..7305 "'find second paramete ..."5262 WHITESPACE@7305..7306 " "5263 PLUS@7306..7307 "+"5264 WHITESPACE@7307..7308 " "5265 EXPR@7308..73215266 EXPR_VAR@7308..73115267 NAME@7308..73115268 IDENT@7308..7311 "std"5269 SUFFIX_INDEX@7311..73165270 DOT@7311..7312 "."5271 NAME@7312..73165272 IDENT@7312..7316 "type"5273 SUFFIX_APPLY@7316..73215274 ARGS_DESC@7316..73215275 L_PAREN@7316..7317 "("5276 ARG@7317..73205277 EXPR@7317..73205278 EXPR_VAR@7317..73205279 NAME@7317..73205280 IDENT@7317..7320 "arr"5281 R_PAREN@7320..7321 ")"5282 WHITESPACE@7321..7326 "\n "5283 ELSE_KW@7326..7330 "else"5284 WHITESPACE@7330..7337 "\n "5285 FALSE_EXPR@7337..74115286 EXPR@7337..74115287 EXPR_VAR@7337..73405288 NAME@7337..73405289 IDENT@7337..7340 "std"5290 SUFFIX_INDEX@7340..73475291 DOT@7340..7341 "."5292 NAME@7341..73475293 IDENT@7341..7347 "filter"5294 SUFFIX_APPLY@7347..74115295 ARGS_DESC@7347..74115296 L_PAREN@7347..7348 "("5297 ARG@7348..73755298 EXPR@7348..73755299 EXPR_FUNCTION@7348..73755300 FUNCTION_KW@7348..7356 "function"5301 PARAMS_DESC@7356..73595302 L_PAREN@7356..7357 "("5303 PARAM@7357..73585304 DESTRUCT_FULL@7357..73585305 NAME@7357..73585306 IDENT@7357..7358 "i"5307 R_PAREN@7358..7359 ")"5308 WHITESPACE@7359..7360 " "5309 EXPR@7360..73755310 EXPR_BINARY@7360..73755311 EXPR@7360..73635312 EXPR_VAR@7360..73635313 NAME@7360..73635314 IDENT@7360..7363 "arr"5315 SUFFIX_INDEX_EXPR@7363..73665316 L_BRACK@7363..7364 "["5317 EXPR@7364..73655318 EXPR_VAR@7364..73655319 NAME@7364..73655320 IDENT@7364..7365 "i"5321 R_BRACK@7365..7366 "]"5322 WHITESPACE@7366..7367 " "5323 EQ@7367..7369 "=="5324 WHITESPACE@7369..7370 " "5325 EXPR@7370..73755326 EXPR_VAR@7370..73755327 NAME@7370..73755328 IDENT@7370..7375 "value"5329 COMMA@7375..7376 ","5330 WHITESPACE@7376..7377 " "5331 ARG@7377..74105332 EXPR@7377..74105333 EXPR_VAR@7377..73805334 NAME@7377..73805335 IDENT@7377..7380 "std"5336 SUFFIX_INDEX@7380..73865337 DOT@7380..7381 "."5338 NAME@7381..73865339 IDENT@7381..7386 "range"5340 SUFFIX_APPLY@7386..74105341 ARGS_DESC@7386..74105342 L_PAREN@7386..7387 "("5343 ARG@7387..73885344 EXPR@7387..73885345 EXPR_NUMBER@7387..73885346 FLOAT@7387..7388 "0"5347 COMMA@7388..7389 ","5348 WHITESPACE@7389..7390 " "5349 ARG@7390..74095350 EXPR@7390..74095351 EXPR_BINARY@7390..74095352 EXPR@7390..73935353 EXPR_VAR@7390..73935354 NAME@7390..73935355 IDENT@7390..7393 "std"5356 SUFFIX_INDEX@7393..74005357 DOT@7393..7394 "."5358 NAME@7394..74005359 IDENT@7394..7400 "length"5360 SUFFIX_APPLY@7400..74055361 ARGS_DESC@7400..74055362 L_PAREN@7400..7401 "("5363 ARG@7401..74045364 EXPR@7401..74045365 EXPR_VAR@7401..74045366 NAME@7401..74045367 IDENT@7401..7404 "arr"5368 R_PAREN@7404..7405 ")"5369 WHITESPACE@7405..7406 " "5370 MINUS@7406..7407 "-"5371 WHITESPACE@7407..7408 " "5372 EXPR@7408..74095373 EXPR_NUMBER@7408..74095374 FLOAT@7408..7409 "1"5375 R_PAREN@7409..7410 ")"5376 R_PAREN@7410..7411 ")"5377 COMMA@7411..7412 ","5378 WHITESPACE@7412..7416 "\n\n "5379 SINGLE_LINE_SLASH_COMMENT@7416..7426 "// Compat\n"5380 WHITESPACE@7426..7428 " "5381 MEMBER_FIELD_METHOD@7428..75385382 FIELD_NAME_FIXED@7428..74435383 NAME@7428..74435384 IDENT@7428..7443 "__compare_array"5385 PARAMS_DESC@7443..74555386 L_PAREN@7443..7444 "("5387 PARAM@7444..74485388 DESTRUCT_FULL@7444..74485389 NAME@7444..74485390 IDENT@7444..7448 "arr1"5391 COMMA@7448..7449 ","5392 WHITESPACE@7449..7450 " "5393 PARAM@7450..74545394 DESTRUCT_FULL@7450..74545395 NAME@7450..74545396 IDENT@7450..7454 "arr2"5397 R_PAREN@7454..7455 ")"5398 COLONCOLON@7455..7457 "::"5399 WHITESPACE@7457..7462 "\n "5400 EXPR@7462..75385401 STMT_ASSERT@7462..75085402 ASSERTION@7462..75075403 ASSERT_KW@7462..7468 "assert"5404 WHITESPACE@7468..7469 " "5405 EXPR@7469..75075406 EXPR_BINARY@7469..75075407 EXPR@7469..74725408 EXPR_VAR@7469..74725409 NAME@7469..74725410 IDENT@7469..7472 "std"5411 SUFFIX_INDEX@7472..74805412 DOT@7472..7473 "."5413 NAME@7473..74805414 IDENT@7473..7480 "isArray"5415 SUFFIX_APPLY@7480..74865416 ARGS_DESC@7480..74865417 L_PAREN@7480..7481 "("5418 ARG@7481..74855419 EXPR@7481..74855420 EXPR_VAR@7481..74855421 NAME@7481..74855422 IDENT@7481..7485 "arr1"5423 R_PAREN@7485..7486 ")"5424 WHITESPACE@7486..7487 " "5425 AND@7487..7489 "&&"5426 WHITESPACE@7489..7490 " "5427 EXPR@7490..75075428 EXPR_VAR@7490..74935429 NAME@7490..74935430 IDENT@7490..7493 "std"5431 SUFFIX_INDEX@7493..75015432 DOT@7493..7494 "."5433 NAME@7494..75015434 IDENT@7494..7501 "isArray"5435 SUFFIX_APPLY@7501..75075436 ARGS_DESC@7501..75075437 L_PAREN@7501..7502 "("5438 ARG@7502..75065439 EXPR@7502..75065440 EXPR_VAR@7502..75065441 NAME@7502..75065442 IDENT@7502..7506 "arr2"5443 R_PAREN@7506..7507 ")"5444 SEMI@7507..7508 ";"5445 WHITESPACE@7508..7513 "\n "5446 EXPR_VAR@7513..75165447 NAME@7513..75165448 IDENT@7513..7516 "std"5449 SUFFIX_INDEX@7516..75265450 DOT@7516..7517 "."5451 NAME@7517..75265452 IDENT@7517..7526 "__compare"5453 SUFFIX_APPLY@7526..75385454 ARGS_DESC@7526..75385455 L_PAREN@7526..7527 "("5456 ARG@7527..75315457 EXPR@7527..75315458 EXPR_VAR@7527..75315459 NAME@7527..75315460 IDENT@7527..7531 "arr1"5461 COMMA@7531..7532 ","5462 WHITESPACE@7532..7533 " "5463 ARG@7533..75375464 EXPR@7533..75375465 EXPR_VAR@7533..75375466 NAME@7533..75375467 IDENT@7533..7537 "arr2"5468 R_PAREN@7537..7538 ")"5469 COMMA@7538..7539 ","5470 WHITESPACE@7539..7542 "\n "5471 MEMBER_FIELD_METHOD@7542..76065472 FIELD_NAME_FIXED@7542..75545473 NAME@7542..75545474 IDENT@7542..7554 "__array_less"5475 PARAMS_DESC@7554..75665476 L_PAREN@7554..7555 "("5477 PARAM@7555..75595478 DESTRUCT_FULL@7555..75595479 NAME@7555..75595480 IDENT@7555..7559 "arr1"5481 COMMA@7559..7560 ","5482 WHITESPACE@7560..7561 " "5483 PARAM@7561..75655484 DESTRUCT_FULL@7561..75655485 NAME@7561..75655486 IDENT@7561..7565 "arr2"5487 R_PAREN@7565..7566 ")"5488 COLONCOLON@7566..7568 "::"5489 WHITESPACE@7568..7569 " "5490 EXPR@7569..76065491 EXPR_BINARY@7569..76065492 EXPR@7569..75725493 EXPR_VAR@7569..75725494 NAME@7569..75725495 IDENT@7569..7572 "std"5496 SUFFIX_INDEX@7572..75885497 DOT@7572..7573 "."5498 NAME@7573..75885499 IDENT@7573..7588 "__compare_array"5500 SUFFIX_APPLY@7588..76005501 ARGS_DESC@7588..76005502 L_PAREN@7588..7589 "("5503 ARG@7589..75935504 EXPR@7589..75935505 EXPR_VAR@7589..75935506 NAME@7589..75935507 IDENT@7589..7593 "arr1"5508 COMMA@7593..7594 ","5509 WHITESPACE@7594..7595 " "5510 ARG@7595..75995511 EXPR@7595..75995512 EXPR_VAR@7595..75995513 NAME@7595..75995514 IDENT@7595..7599 "arr2"5515 R_PAREN@7599..7600 ")"5516 WHITESPACE@7600..7601 " "5517 EQ@7601..7603 "=="5518 WHITESPACE@7603..7604 " "5519 EXPR@7604..76065520 EXPR_UNARY@7604..76065521 MINUS@7604..7605 "-"5522 EXPR_NUMBER@7605..76065523 FLOAT@7605..7606 "1"5524 COMMA@7606..7607 ","5525 WHITESPACE@7607..7610 "\n "5526 MEMBER_FIELD_METHOD@7610..76765527 FIELD_NAME_FIXED@7610..76255528 NAME@7610..76255529 IDENT@7610..7625 "__array_greater"5530 PARAMS_DESC@7625..76375531 L_PAREN@7625..7626 "("5532 PARAM@7626..76305533 DESTRUCT_FULL@7626..76305534 NAME@7626..76305535 IDENT@7626..7630 "arr1"5536 COMMA@7630..7631 ","5537 WHITESPACE@7631..7632 " "5538 PARAM@7632..76365539 DESTRUCT_FULL@7632..76365540 NAME@7632..76365541 IDENT@7632..7636 "arr2"5542 R_PAREN@7636..7637 ")"5543 COLONCOLON@7637..7639 "::"5544 WHITESPACE@7639..7640 " "5545 EXPR@7640..76765546 EXPR_BINARY@7640..76765547 EXPR@7640..76435548 EXPR_VAR@7640..76435549 NAME@7640..76435550 IDENT@7640..7643 "std"5551 SUFFIX_INDEX@7643..76595552 DOT@7643..7644 "."5553 NAME@7644..76595554 IDENT@7644..7659 "__compare_array"5555 SUFFIX_APPLY@7659..76715556 ARGS_DESC@7659..76715557 L_PAREN@7659..7660 "("5558 ARG@7660..76645559 EXPR@7660..76645560 EXPR_VAR@7660..76645561 NAME@7660..76645562 IDENT@7660..7664 "arr1"5563 COMMA@7664..7665 ","5564 WHITESPACE@7665..7666 " "5565 ARG@7666..76705566 EXPR@7666..76705567 EXPR_VAR@7666..76705568 NAME@7666..76705569 IDENT@7666..7670 "arr2"5570 R_PAREN@7670..7671 ")"5571 WHITESPACE@7671..7672 " "5572 EQ@7672..7674 "=="5573 WHITESPACE@7674..7675 " "5574 EXPR@7675..76765575 EXPR_NUMBER@7675..76765576 FLOAT@7675..7676 "1"5577 COMMA@7676..7677 ","5578 WHITESPACE@7677..7680 "\n "5579 MEMBER_FIELD_METHOD@7680..77525580 FIELD_NAME_FIXED@7680..77015581 NAME@7680..77015582 IDENT@7680..7701 "__array_less_or_equal"5583 PARAMS_DESC@7701..77135584 L_PAREN@7701..7702 "("5585 PARAM@7702..77065586 DESTRUCT_FULL@7702..77065587 NAME@7702..77065588 IDENT@7702..7706 "arr1"5589 COMMA@7706..7707 ","5590 WHITESPACE@7707..7708 " "5591 PARAM@7708..77125592 DESTRUCT_FULL@7708..77125593 NAME@7708..77125594 IDENT@7708..7712 "arr2"5595 R_PAREN@7712..7713 ")"5596 COLONCOLON@7713..7715 "::"5597 WHITESPACE@7715..7716 " "5598 EXPR@7716..77525599 EXPR_BINARY@7716..77525600 EXPR@7716..77195601 EXPR_VAR@7716..77195602 NAME@7716..77195603 IDENT@7716..7719 "std"5604 SUFFIX_INDEX@7719..77355605 DOT@7719..7720 "."5606 NAME@7720..77355607 IDENT@7720..7735 "__compare_array"5608 SUFFIX_APPLY@7735..77475609 ARGS_DESC@7735..77475610 L_PAREN@7735..7736 "("5611 ARG@7736..77405612 EXPR@7736..77405613 EXPR_VAR@7736..77405614 NAME@7736..77405615 IDENT@7736..7740 "arr1"5616 COMMA@7740..7741 ","5617 WHITESPACE@7741..7742 " "5618 ARG@7742..77465619 EXPR@7742..77465620 EXPR_VAR@7742..77465621 NAME@7742..77465622 IDENT@7742..7746 "arr2"5623 R_PAREN@7746..7747 ")"5624 WHITESPACE@7747..7748 " "5625 LE@7748..7750 "<="5626 WHITESPACE@7750..7751 " "5627 EXPR@7751..77525628 EXPR_NUMBER@7751..77525629 FLOAT@7751..7752 "0"5630 COMMA@7752..7753 ","5631 WHITESPACE@7753..7756 "\n "5632 MEMBER_FIELD_METHOD@7756..78315633 FIELD_NAME_FIXED@7756..77805634 NAME@7756..77805635 IDENT@7756..7780 "__array_greater_or_equal"5636 PARAMS_DESC@7780..77925637 L_PAREN@7780..7781 "("5638 PARAM@7781..77855639 DESTRUCT_FULL@7781..77855640 NAME@7781..77855641 IDENT@7781..7785 "arr1"5642 COMMA@7785..7786 ","5643 WHITESPACE@7786..7787 " "5644 PARAM@7787..77915645 DESTRUCT_FULL@7787..77915646 NAME@7787..77915647 IDENT@7787..7791 "arr2"5648 R_PAREN@7791..7792 ")"5649 COLONCOLON@7792..7794 "::"5650 WHITESPACE@7794..7795 " "5651 EXPR@7795..78315652 EXPR_BINARY@7795..78315653 EXPR@7795..77985654 EXPR_VAR@7795..77985655 NAME@7795..77985656 IDENT@7795..7798 "std"5657 SUFFIX_INDEX@7798..78145658 DOT@7798..7799 "."5659 NAME@7799..78145660 IDENT@7799..7814 "__compare_array"5661 SUFFIX_APPLY@7814..78265662 ARGS_DESC@7814..78265663 L_PAREN@7814..7815 "("5664 ARG@7815..78195665 EXPR@7815..78195666 EXPR_VAR@7815..78195667 NAME@7815..78195668 IDENT@7815..7819 "arr1"5669 COMMA@7819..7820 ","5670 WHITESPACE@7820..7821 " "5671 ARG@7821..78255672 EXPR@7821..78255673 EXPR_VAR@7821..78255674 NAME@7821..78255675 IDENT@7821..7825 "arr2"5676 R_PAREN@7825..7826 ")"5677 WHITESPACE@7826..7827 " "5678 GE@7827..7829 ">="5679 WHITESPACE@7829..7830 " "5680 EXPR@7830..78315681 EXPR_NUMBER@7830..78315682 FLOAT@7830..7831 "0"5683 COMMA@7831..7832 ","5684 WHITESPACE@7832..7833 "\n"5685 R_BRACE@7833..7834 "}"5686 WHITESPACE@7834..7835 "\n"crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_indent.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_indent.snap
@@ -0,0 +1,8 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "|||\n"
+---
+SOURCE_FILE@0..4
+ EXPR@0..4
+ EXPR_STRING@0..4
+ ERROR_STRING_BLOCK_MISSING_INDENT@0..4 "|||\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_indent_text.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_indent_text.snap
@@ -0,0 +1,8 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "|||\nhello\n"
+---
+SOURCE_FILE@0..10
+ EXPR@0..10
+ EXPR_STRING@0..10
+ ERROR_STRING_BLOCK_MISSING_INDENT@0..10 "|||\nhello\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_newline.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_newline.snap
@@ -0,0 +1,8 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "|||hello\n"
+---
+SOURCE_FILE@0..9
+ EXPR@0..9
+ EXPR_STRING@0..9
+ ERROR_STRING_BLOCK_MISSING_NEW_LINE@0..9 "|||hello\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_termination.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__str_block_missing_termination.snap
@@ -0,0 +1,8 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "|||\n\thello\n"
+---
+SOURCE_FILE@0..11
+ EXPR@0..11
+ EXPR_STRING@0..11
+ ERROR_STRING_BLOCK_UNEXPECTED_END@0..11 "|||\n\thello\n"
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__unexpected_destruct.snap
@@ -0,0 +1,34 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "local * = 1;\na\n"
+---
+SOURCE_FILE@0..15
+ EXPR@0..14
+ STMT_LOCAL@0..12
+ LOCAL_KW@0..5 "local"
+ WHITESPACE@5..6 " "
+ BIND_DESTRUCT@6..11
+ ERROR_UNEXPECTED_TOKEN@6..7
+ MUL@6..7 "*"
+ WHITESPACE@7..8 " "
+ ASSIGN@8..9 "="
+ WHITESPACE@9..10 " "
+ EXPR@10..11
+ EXPR_NUMBER@10..11
+ FLOAT@10..11 "1"
+ SEMI@11..12 ";"
+ WHITESPACE@12..13 "\n"
+ EXPR_VAR@13..14
+ NAME@13..14
+ IDENT@13..14 "a"
+ WHITESPACE@14..15 "\n"
+===
+LocatedSyntaxError { error: Unexpected { expected: Named("destruction specifier"), found: MUL }, range: 6..7 }
+===
+ x syntax error
+ ,-[1:1]
+ 1 | local * = 1;
+ : |
+ : `-- expected destruction specifier, found MUL
+ 2 | a
+ `----
crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snapdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/snapshots/jrsonnet_rowan_parser__tests__wrong_field_end.snap
@@ -0,0 +1,51 @@
+---
+source: crates/jrsonnet-rowan-parser/src/tests.rs
+expression: "{\n\ta: 1;\n\tb: 2;\n}\n"
+---
+SOURCE_FILE@0..18
+ EXPR@0..17
+ EXPR_OBJECT@0..17
+ OBJ_BODY_MEMBER_LIST@0..17
+ L_BRACE@0..1 "{"
+ WHITESPACE@1..3 "\n\t"
+ MEMBER_FIELD_NORMAL@3..7
+ FIELD_NAME_FIXED@3..4
+ NAME@3..4
+ IDENT@3..4 "a"
+ COLON@4..5 ":"
+ WHITESPACE@5..6 " "
+ EXPR@6..7
+ EXPR_NUMBER@6..7
+ FLOAT@6..7 "1"
+ ERROR_UNEXPECTED_TOKEN@7..8
+ SEMI@7..8 ";"
+ WHITESPACE@8..10 "\n\t"
+ MEMBER_FIELD_NORMAL@10..14
+ FIELD_NAME_FIXED@10..11
+ NAME@10..11
+ IDENT@10..11 "b"
+ COLON@11..12 ":"
+ WHITESPACE@12..13 " "
+ EXPR@13..14
+ EXPR_NUMBER@13..14
+ FLOAT@13..14 "2"
+ ERROR_UNEXPECTED_TOKEN@14..15
+ SEMI@14..15 ";"
+ WHITESPACE@15..16 "\n"
+ R_BRACE@16..17 "}"
+ WHITESPACE@17..18 "\n"
+===
+LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 7..8 }
+LocatedSyntaxError { error: Unexpected { expected: Named("comma"), found: SEMI }, range: 14..15 }
+===
+ x syntax error
+ ,-[1:1]
+ 1 | {
+ 2 | a: 1;
+ : |
+ : `-- expected comma, found SEMI
+ 3 | b: 2;
+ : |
+ : `-- expected comma, found SEMI
+ 4 | }
+ `----
crates/jrsonnet-rowan-parser/src/string_block.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/string_block.rs
@@ -0,0 +1,216 @@
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum StringBlockError {
+ UnexpectedEnd,
+ MissingNewLine,
+ MissingTermination,
+ MissingIndent,
+}
+
+use std::ops::Range;
+
+use logos::Lexer;
+use StringBlockError::*;
+
+use crate::SyntaxKind;
+
+pub fn lex_str_block_test(lex: &mut Lexer<SyntaxKind>) {
+ let _ = lex_str_block(lex);
+}
+
+pub fn lex_str_block(lex: &mut Lexer<SyntaxKind>) -> Result<(), StringBlockError> {
+ struct Context<'a> {
+ source: &'a str,
+ index: usize,
+ offset: usize,
+ }
+
+ impl<'a> Context<'a> {
+ fn rest(&self) -> &'a str {
+ &self.source[self.index..]
+ }
+
+ fn next(&mut self) -> Option<char> {
+ if self.index == self.source.len() {
+ return None;
+ }
+
+ match self.rest().chars().next() {
+ None => None,
+ Some(c) => {
+ self.index += c.len_utf8();
+ Some(c)
+ }
+ }
+ }
+
+ fn peek(&self) -> Option<char> {
+ if self.index == self.source.len() {
+ return None;
+ }
+
+ self.rest().chars().next()
+ }
+
+ fn eat_while(&mut self, f: impl Fn(char) -> bool) -> usize {
+ if self.index == self.source.len() {
+ return 0;
+ }
+
+ let next_char = self.rest().char_indices().find(|(_, c)| !f(*c));
+
+ match next_char {
+ None => {
+ let diff = self.source.len() - self.index;
+ self.index = self.source.len();
+ diff
+ }
+ Some((idx, _)) => {
+ self.index += idx;
+ idx
+ }
+ }
+ }
+
+ fn skip(&mut self, len: usize) {
+ self.index = match self.index + len {
+ n if n > self.source.len() => self.source.len(),
+ n => n,
+ };
+ }
+
+ fn pos(&self) -> Range<usize> {
+ if self.index == self.source.len() {
+ self.offset + self.index..self.offset + self.index
+ } else {
+ // TODO: char size
+ self.offset + self.index..self.offset + self.index + 1
+ }
+ }
+ }
+
+ // Check that b has at least the same whitespace prefix as a and returns the
+ // amount of this whitespace, otherwise returns 0. If a has no whitespace
+ // prefix than return 0.
+ fn check_whitespace(a: &str, b: &str) -> usize {
+ let a = a.as_bytes();
+ let b = b.as_bytes();
+
+ for i in 0..a.len() {
+ if a[i] != b' ' && a[i] != b'\t' {
+ // a has run out of whitespace and b matched up to this point. Return result.
+ return i;
+ }
+
+ if i >= b.len() {
+ // We ran off the edge of b while a still has whitespace. Return 0 as failure.
+ return 0;
+ }
+
+ if a[i] != b[i] {
+ // a has whitespace but b does not. Return 0 as failure.
+ return 0;
+ }
+ }
+
+ // We ran off the end of a and b kept up
+ a.len()
+ }
+
+ fn guess_token_end_and_bump<'a>(lex: &mut Lexer<'a, SyntaxKind>, ctx: &Context<'a>) {
+ let end_index = ctx
+ .rest()
+ .find("|||")
+ .map(|v| v + 3)
+ .unwrap_or_else(|| ctx.rest().len());
+ lex.bump(ctx.index + end_index);
+ }
+
+ debug_assert_eq!(lex.slice(), "|||");
+ let mut ctx = Context {
+ source: lex.remainder(),
+ index: 0,
+ offset: lex.span().end,
+ };
+
+ // Skip whitespaces
+ ctx.eat_while(|r| r == ' ' || r == '\t' || r == '\r');
+
+ // Skip \n
+ match ctx.next() {
+ Some('\n') => (),
+ None => {
+ guess_token_end_and_bump(lex, &ctx);
+ return Err(UnexpectedEnd);
+ }
+ // Text block requires new line after |||.
+ Some(_) => {
+ guess_token_end_and_bump(lex, &ctx);
+ return Err(MissingNewLine);
+ }
+ }
+
+ // Process leading blank lines before calculating string block indent
+ while let Some('\n') = ctx.peek() {
+ ctx.next();
+ }
+
+ let mut num_whitespace = check_whitespace(ctx.rest(), ctx.rest());
+ let str_block_indent = &ctx.rest()[..num_whitespace];
+
+ if num_whitespace == 0 {
+ // Text block's first line must start with whitespace
+ guess_token_end_and_bump(lex, &ctx);
+ return Err(MissingIndent);
+ }
+
+ loop {
+ debug_assert_ne!(num_whitespace, 0, "Unexpected value for num_whitespace");
+ ctx.skip(num_whitespace);
+
+ loop {
+ match ctx.next() {
+ None => {
+ guess_token_end_and_bump(lex, &ctx);
+ return Err(UnexpectedEnd);
+ }
+ Some('\n') => break,
+ Some(_) => (),
+ }
+ }
+
+ // Skip any blank lines
+ while let Some('\n') = ctx.peek() {
+ ctx.next();
+ }
+
+ // Look at the next line
+ num_whitespace = check_whitespace(str_block_indent, ctx.rest());
+ if num_whitespace == 0 {
+ // End of the text block
+ let mut term_indent = String::with_capacity(num_whitespace);
+ while let Some(' ' | '\t') = ctx.peek() {
+ term_indent.push(ctx.next().unwrap());
+ }
+
+ if !ctx.rest().starts_with("|||") {
+ // Text block not terminated with |||
+ let pos = ctx.pos();
+ if pos.is_empty() {
+ // eof
+ lex.bump(ctx.index);
+ return Err(UnexpectedEnd);
+ }
+
+ guess_token_end_and_bump(lex, &ctx);
+ return Err(MissingTermination);
+ }
+
+ // Skip '|||'
+ ctx.skip(3);
+ break;
+ }
+ }
+
+ lex.bump(ctx.index);
+ Ok(())
+}
crates/jrsonnet-rowan-parser/src/tests.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/tests.rs
@@ -0,0 +1,253 @@
+#![cfg(test)]
+
+use miette::{
+ Diagnostic, GraphicalReportHandler, GraphicalTheme, LabeledSpan, ThemeCharacters, ThemeStyles,
+};
+use thiserror::Error;
+
+use crate::{parse, AstNode};
+
+#[derive(Debug, Error)]
+#[error("syntax error")]
+struct MyDiagnostic {
+ code: String,
+ spans: Vec<LabeledSpan>,
+}
+impl Diagnostic for MyDiagnostic {
+ fn code<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn severity(&self) -> Option<miette::Severity> {
+ None
+ }
+
+ fn help<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn url<'a>(&'a self) -> Option<Box<dyn std::fmt::Display + 'a>> {
+ None
+ }
+
+ fn source_code(&self) -> Option<&dyn miette::SourceCode> {
+ Some(&self.code)
+ }
+
+ fn labels(&self) -> Option<Box<dyn Iterator<Item = miette::LabeledSpan> + '_>> {
+ Some(Box::new(self.spans.clone().into_iter()))
+ }
+
+ fn related<'a>(&'a self) -> Option<Box<dyn Iterator<Item = &'a dyn Diagnostic> + 'a>> {
+ None
+ }
+}
+
+fn process(text: &str) -> String {
+ use std::fmt::Write;
+ let mut out = String::new();
+ let (node, errors) = parse(text);
+ write!(out, "{:#?}", node.syntax()).unwrap();
+ if !errors.is_empty() && !text.is_empty() {
+ writeln!(out, "===").unwrap();
+ for err in &errors {
+ writeln!(out, "{:?}", err).unwrap();
+ }
+ let mut code = text.to_string();
+
+ // Prettier errors at EOF position
+ if code.ends_with('\n') {
+ code.truncate(code.len() - 1);
+ code += " ";
+ }
+ code += " ";
+
+ let diag = MyDiagnostic {
+ code,
+ spans: errors.into_iter().map(|e| e.into()).collect(),
+ };
+
+ let handler = GraphicalReportHandler::new_themed(GraphicalTheme {
+ characters: ThemeCharacters::ascii(),
+ styles: ThemeStyles::none(),
+ });
+
+ writeln!(out, "===").unwrap();
+ handler
+ .render_report(&mut out, &diag)
+ .expect("fmt error?..");
+ }
+ out.split('\n')
+ .map(|s| s.trim_end().to_string())
+ .collect::<Vec<String>>()
+ .join("\n")
+ .trim_end()
+ .to_string()
+}
+macro_rules! mk_test {
+ ($($name:ident => $test:expr)+) => {$(
+ #[test]
+ fn $name() {
+ let src = indoc::indoc!($test);
+ let result = process(&src);
+ insta::assert_snapshot!(stringify!($name), result, src);
+
+ }
+ )+};
+ }
+mk_test!(
+ empty => r#" "#
+ function => r#"
+ function(a, b = 1) a + b
+ "#
+ function_error_no_value => r#"
+ function(a, b = ) a + b
+ "#
+ function_error_rparen => r#"
+ function(a, b
+ "#
+ function_error_body => r#"
+ function(a, b)
+ "#
+ local_novalue => r#"
+ local a =
+ "#
+ local_no_value_recovery => r#"
+ local a =
+ local b = 3;
+ 1
+ "#
+
+
+ no_rhs => r#"
+ a +
+ "#
+ no_lhs => r#"
+ + 2
+ "#
+ no_operator => "
+ 2 2
+ "
+
+ named_before_positional => "
+ a(1, 2, b=4, 3, 5, k = 12, 6)
+ "
+
+ wrong_field_end => "
+ {
+ a: 1;
+ b: 2;
+ }
+ "
+
+
+ plain_call => "
+ std.substr(a, 0, std.length(b)) == b
+ "
+
+ destruct => "
+ local [a, b, c] = arr;
+ local [a, ...] = arr_rest;
+ local [..., a] = rest_arr;
+ local [...] = rest_in_arr;
+ local [a, ...n] = arr_rest_n;
+ local [...n, a] = rest_arr_n;
+ local [...n] = rest_in_arr_n;
+
+ local {a, b, c} = obj;
+ local {a, b, c, ...} = obj_rest;
+ local {a, b, c, ...n} = obj_rest_n;
+
+ null
+ "
+
+ str_block_missing_indent => "
+ |||
+ "
+ str_block_missing_termination => "
+ |||
+ hello
+ "
+ str_block_missing_newline => "
+ |||hello
+ "
+ str_block_missing_indent_text => "
+ |||
+ hello
+ "
+
+ unexpected_destruct => "
+ local * = 1;
+ a
+ "
+ arr_compspec => r#"
+ [a for a in [1, 2, 3]]
+ "#
+ arr_compspec_comma => "
+ [a, for a in [1, 2, 3]]
+ "
+ arr_compspec_no_elems => "
+ [for a in [1, 2, 3]]
+ "
+ arr_compspec_incompatible_with_multiple_elems => r#"
+ [a for a in [1, 2, 3], b]
+ "#
+ arr_compspec_incompatible_with_multiple_elems_w => r#"
+ [a, b, for a in [1, 2, 3], c]
+ "#
+
+ obj_compspec => r#"
+ {a:1 for a in [1, 2, 3]}
+ "#
+ obj_compspec_comma => "
+ {a:1, for a in [1, 2, 3]}
+ "
+ obj_compspec_no_elems => "
+ {for a in [1, 2, 3]}
+ "
+ obj_compspec_incompatible_with_multiple_elems => r#"
+ {a:1 for a in [1, 2, 3], b:1}
+ "#
+ obj_compspec_incompatible_with_multiple_elems_w => r#"
+ {a:1, b:1, for a in [1, 2, 3], c:1}
+ "#
+
+ obj_compspec_incompatible_with_asserts => r#"
+ {assert 1, a: 1 for a in [1,2,3]}
+ "#
+
+ local_method => r#"
+ local
+ a(x) = x,
+ a = function(x) x,
+ ; c
+ "#
+ obj_method => r#"
+ {
+ a(x): x,
+ a: function(x) x,
+ }
+ "#
+
+ continue_after_total_failure => r#"
+ local intr = $intrinsic(test);
+
+ local a = 1, b = 2, c = a + b;
+
+ [c]
+ "#
+);
+
+#[test]
+fn stdlib() {
+ let src = include_str!("../../jrsonnet-stdlib/src/std.jsonnet");
+ let result = process(src);
+ insta::assert_snapshot!("stdlib", result, src);
+}
+#[test]
+fn eval_simple() {
+ let src = "local a = 1, b = 2; a + local c = 1; c";
+ let (node, errors) = parse(src);
+
+ dbg!(node);
+}
crates/jrsonnet-rowan-parser/src/token_set.rsdiffbeforeafterboth--- /dev/null
+++ b/crates/jrsonnet-rowan-parser/src/token_set.rs
@@ -0,0 +1,106 @@
+use std::fmt;
+
+use crate::SyntaxKind;
+
+#[derive(Clone, Copy, Default)]
+pub struct SyntaxKindSet(u128);
+
+impl SyntaxKindSet {
+ #[allow(dead_code)]
+ pub const EMPTY: Self = Self(0);
+ pub const ALL: Self = Self(u128::MAX);
+
+ pub const fn new(kinds: &[SyntaxKind]) -> SyntaxKindSet {
+ let mut res = 0u128;
+ let mut i = 0;
+ while i < kinds.len() {
+ res |= mask(kinds[i]);
+ i += 1
+ }
+ SyntaxKindSet(res)
+ }
+
+ pub const fn union(self, other: SyntaxKindSet) -> SyntaxKindSet {
+ SyntaxKindSet(self.0 | other.0)
+ }
+ pub const fn with(self, kind: SyntaxKind) -> SyntaxKindSet {
+ SyntaxKindSet(self.0 | mask(kind))
+ }
+
+ pub fn contains(&self, kind: SyntaxKind) -> bool {
+ if !is_token(kind) {
+ return false;
+ }
+ self.0 & mask(kind) != 0
+ }
+}
+impl fmt::Display for SyntaxKindSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut v = self.0;
+ let mut variants = <Vec<SyntaxKind>>::new();
+ for i in 0..128 {
+ if v & 1 == 1 {
+ variants.push(SyntaxKind::from_raw(i))
+ }
+ v >>= 1;
+ if v == 0 {
+ break;
+ }
+ }
+ for (i, v) in variants.iter().enumerate() {
+ if i == 0 {
+ } else if i == variants.len() - 1 {
+ write!(f, " or ")?;
+ } else {
+ write!(f, ", ")?;
+ }
+ write!(f, "{v:?}")?;
+ }
+ Ok(())
+ }
+}
+impl fmt::Debug for SyntaxKindSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut v = self.0;
+ let mut variants = <Vec<SyntaxKind>>::new();
+ for i in 0..128 {
+ if v & 1 == 1 {
+ variants.push(SyntaxKind::from_raw(i))
+ }
+ v >>= 1;
+ if v == 0 {
+ break;
+ }
+ }
+ f.debug_tuple("SyntaxKindSet").field(&variants).finish()
+ }
+}
+
+const fn mask(kind: SyntaxKind) -> u128 {
+ if kind as u32 > 128 {
+ panic!("mask for not a token kind")
+ }
+ 1u128 << (kind as u128)
+}
+
+#[macro_export]
+macro_rules! TS {
+ ($($tt:tt)*) => {
+ $crate::SyntaxKindSet::new(&[
+ $(
+ $crate::T![$tt]
+ ),*
+ ])
+ };
+}
+
+#[test]
+fn sanity() {
+ assert!(
+ (SyntaxKind::LEXING_ERROR as u32) < 127,
+ "can't keep KindSet as bitset"
+ );
+}
+fn is_token(kind: SyntaxKind) -> bool {
+ (kind as u32) < 127
+}
crates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/strings.rs
+++ b/crates/jrsonnet-stdlib/src/strings.rs
@@ -161,7 +161,11 @@
use jrsonnet_evaluator::runtime_error;
use Either2::*;
Ok(match v {
- A(a) => Val::BigInt(Box::new((a as i64).into())),
+ A(a) => {
+ Val::BigInt(Box::new(a.to_string().parse().map_err(|e| {
+ runtime_error!("number is not convertible to bigint: {e}")
+ })?))
+ }
B(b) => Val::BigInt(Box::new(
b.as_str()
.parse()
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -131,6 +131,8 @@
cargo-edit
cargo-asm
cargo-outdated
+ cargo-watch
+ cargo-insta
lld
hyperfine
graphviz
xtask/Cargo.tomldiffbeforeafterboth--- /dev/null
+++ b/xtask/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "xtask"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+anyhow = "1.0.57"
+indexmap = "1.9.0"
+itertools = "0.10.3"
+proc-macro2 = "1.0.39"
+quote = "1.0.18"
+ungrammar = "1.16.1"
+xshell = "0.2.2"
xtask/src/main.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/main.rs
@@ -0,0 +1,7 @@
+use anyhow::Result;
+
+mod sourcegen;
+
+fn main() -> Result<()> {
+ sourcegen::generate_ungrammar()
+}
xtask/src/sourcegen/ast.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/ast.rs
@@ -0,0 +1,399 @@
+use std::collections::{BTreeSet, HashMap};
+
+use proc_macro2::TokenStream;
+use quote::format_ident;
+use ungrammar::{Grammar, Rule};
+
+use super::{
+ util::{pluralize, to_lower_snake_case},
+ KindsSrc,
+};
+
+impl AstNodeSrc {
+ pub fn remove_field(&mut self, to_remove: Vec<usize>) {
+ to_remove.into_iter().rev().for_each(|idx| {
+ self.fields.remove(idx);
+ });
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Default, Debug)]
+pub struct AstSrc {
+ pub nodes: Vec<AstNodeSrc>,
+ pub enums: Vec<AstEnumSrc>,
+ pub token_enums: Vec<AstTokenEnumSrc>,
+}
+#[derive(Debug)]
+pub struct AstNodeSrc {
+ pub doc: Vec<String>,
+ pub name: String,
+ pub traits: Vec<String>,
+ pub fields: Vec<Field>,
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum Field {
+ Token(String),
+ Node {
+ name: String,
+ ty: String,
+ cardinality: Cardinality,
+ },
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum Cardinality {
+ /// This field may not exist in code
+ Optional,
+ /// This field should exist in correctly parsed code
+ Required,
+ /// There may be multiple field values of this kind
+ Many,
+}
+
+#[derive(Debug, Clone)]
+pub struct AstEnumSrc {
+ pub doc: Vec<String>,
+ pub name: String,
+ pub traits: Vec<String>,
+ pub variants: Vec<String>,
+}
+
+#[derive(Debug, Clone)]
+pub struct AstTokenEnumSrc {
+ pub doc: Vec<String>,
+ pub name: String,
+ pub variants: Vec<String>,
+}
+
+impl Field {
+ pub fn is_many(&self) -> bool {
+ matches!(
+ self,
+ Field::Node {
+ cardinality: Cardinality::Many,
+ ..
+ }
+ )
+ }
+
+ pub fn token_name(&self) -> Option<String> {
+ match self {
+ Field::Token(token) => Some(token.clone()),
+ _ => None,
+ }
+ }
+ pub fn token_kind(&self, kinds: &KindsSrc) -> Option<TokenStream> {
+ match self {
+ Field::Token(token) => Some(kinds.token(token).expect("token exists").reference()),
+ _ => None,
+ }
+ }
+ pub fn is_token_enum(&self, grammar: &AstSrc) -> bool {
+ match self {
+ Field::Node { ty, .. } => grammar.token_enums.iter().any(|e| &e.name == ty),
+ _ => false,
+ }
+ }
+
+ pub fn method_name(&self, kinds: &KindsSrc) -> proc_macro2::Ident {
+ match self {
+ Field::Token(name) => kinds.token(name).expect("token exists").method_name(),
+ Field::Node { name, .. } => {
+ format_ident!("{}", name)
+ }
+ }
+ }
+ pub fn ty(&self) -> proc_macro2::Ident {
+ match self {
+ Field::Token(_) => format_ident!("SyntaxToken"),
+ Field::Node { ty, .. } => format_ident!("{}", ty),
+ }
+ }
+}
+
+pub fn lower(kinds: &KindsSrc, grammar: &Grammar) -> AstSrc {
+ let mut res = AstSrc {
+ // tokens,
+ ..Default::default()
+ };
+
+ let nodes = grammar.iter().collect::<Vec<_>>();
+
+ for &node in &nodes {
+ let name = grammar[node].name.clone();
+ let rule = &grammar[node].rule;
+ match lower_enum(grammar, rule) {
+ Some(variants) => {
+ let enum_src = AstEnumSrc {
+ doc: Vec::new(),
+ name,
+ traits: Vec::new(),
+ variants,
+ };
+ res.enums.push(enum_src);
+ }
+ None => match lower_token_enum(grammar, rule) {
+ Some(variants) => {
+ let tokens_enum_src = AstTokenEnumSrc {
+ doc: Vec::new(),
+ name,
+ variants,
+ };
+ res.token_enums.push(tokens_enum_src);
+ }
+ None => {
+ let mut fields = Vec::new();
+ lower_rule(&mut fields, grammar, None, rule, false);
+ let mut types = HashMap::new();
+ for field in fields.iter().filter(|f| f.token_name().is_none()) {
+ if let Some(old) = types.insert(field.ty(), field.method_name(kinds)) {
+ // panic!("{name}.{} has same type as {name}.{}, resolve conflict by wrapping one field: {}", old, field.method_name(kinds), field.ty());
+ }
+ // TODO: check for assignable field types, i.e you can have
+ // ```
+ // SomeEnum =
+ // SomeItem
+ // | SomeOtherItem
+ // ```
+ // And check above will fail to detect conflict in
+ // ```
+ // SomeStruct =
+ // SomeEnum
+ // SomeItem
+ // ```
+ // Despite generating getters, which will both return SomeEnum
+ }
+ res.nodes.push(AstNodeSrc {
+ doc: Vec::new(),
+ name,
+ traits: Vec::new(),
+ fields,
+ });
+ }
+ },
+ }
+ }
+
+ deduplicate_fields(&mut res);
+ extract_struct_traits(kinds, &mut res);
+ extract_enum_traits(&mut res);
+ res
+}
+
+fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
+ let alternatives = match rule {
+ Rule::Alt(it) => it,
+ _ => return None,
+ };
+ let mut variants = Vec::new();
+ for alternative in alternatives {
+ match alternative {
+ Rule::Node(it) => variants.push(grammar[*it].name.clone()),
+ Rule::Token(it) if grammar[*it].name == ";" => (),
+ _ => return None,
+ }
+ }
+ Some(variants)
+}
+fn lower_token_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
+ let alternatives = match rule {
+ Rule::Alt(it) => it,
+ _ => return None,
+ };
+ let mut variants = Vec::new();
+ for alternative in alternatives {
+ match alternative {
+ Rule::Token(it) => variants.push(grammar[*it].name.clone()),
+ _ => return None,
+ }
+ }
+ Some(variants)
+}
+
+fn lower_rule(
+ acc: &mut Vec<Field>,
+ grammar: &Grammar,
+ label: Option<&String>,
+ rule: &Rule,
+ in_optional: bool,
+) {
+ if lower_comma_list(acc, grammar, label, rule) {
+ return;
+ }
+
+ match rule {
+ Rule::Node(node) => {
+ let ty = grammar[*node].name.clone();
+ let name = label.cloned().unwrap_or_else(|| to_lower_snake_case(&ty));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: if in_optional {
+ Cardinality::Optional
+ } else {
+ Cardinality::Required
+ },
+ };
+ acc.push(field);
+ }
+ Rule::Token(token) => {
+ assert!(label.is_none(), "uexpected label: {:?}", label);
+ let name = grammar[*token].name.clone();
+ let field = Field::Token(name);
+ acc.push(field);
+ }
+ Rule::Rep(inner) => {
+ if let Rule::Node(node) = &**inner {
+ let ty = grammar[*node].name.clone();
+ let name = label
+ .cloned()
+ .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Many,
+ };
+ acc.push(field);
+ return;
+ }
+ todo!("unsupported repitition: {:?}", rule)
+ }
+ Rule::Labeled { label: l, rule } => {
+ assert!(label.is_none());
+ lower_rule(acc, grammar, Some(l), rule, in_optional);
+ }
+ Rule::Seq(rules) | Rule::Alt(rules) => {
+ for rule in rules {
+ lower_rule(acc, grammar, label, rule, in_optional)
+ }
+ }
+ Rule::Opt(rule) => lower_rule(acc, grammar, label, rule, true),
+ }
+}
+
+// (T (',' T)* ','?)
+fn lower_comma_list(
+ acc: &mut Vec<Field>,
+ grammar: &Grammar,
+ label: Option<&String>,
+ rule: &Rule,
+) -> bool {
+ let rule = match rule {
+ Rule::Seq(it) => it,
+ _ => return false,
+ };
+ let (node, repeat, trailing_comma) = match rule.as_slice() {
+ [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
+ (node, repeat, trailing_comma)
+ }
+ _ => return false,
+ };
+ let repeat = match &**repeat {
+ Rule::Seq(it) => it,
+ _ => return false,
+ };
+ match repeat.as_slice() {
+ [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
+ _ => return false,
+ }
+ let ty = grammar[*node].name.clone();
+ let name = label
+ .cloned()
+ .unwrap_or_else(|| pluralize(&to_lower_snake_case(&ty)));
+ let field = Field::Node {
+ name,
+ ty,
+ cardinality: Cardinality::Many,
+ };
+ acc.push(field);
+ true
+}
+
+fn deduplicate_fields(ast: &mut AstSrc) {
+ for node in &mut ast.nodes {
+ let mut i = 0;
+ 'outer: while i < node.fields.len() {
+ for j in 0..i {
+ let f1 = &node.fields[i];
+ let f2 = &node.fields[j];
+ if f1 == f2 {
+ node.fields.remove(i);
+ continue 'outer;
+ }
+ }
+ i += 1;
+ }
+ }
+}
+
+fn extract_struct_traits(kinds: &KindsSrc, ast: &mut AstSrc) {
+ // TODO: add common accessor traits here.
+ let traits: &[(&str, &[&str])] = &[];
+
+ for node in &mut ast.nodes {
+ for (name, methods) in traits {
+ extract_struct_trait(kinds, node, name, methods);
+ }
+ }
+}
+
+fn extract_struct_trait(
+ kinds: &KindsSrc,
+ node: &mut AstNodeSrc,
+ trait_name: &str,
+ methods: &[&str],
+) {
+ let mut to_remove = Vec::new();
+ for (i, field) in node.fields.iter().enumerate() {
+ let method_name = field.method_name(kinds).to_string();
+ if methods.iter().any(|&it| it == method_name) {
+ to_remove.push(i);
+ }
+ }
+ if to_remove.len() == methods.len() {
+ node.traits.push(trait_name.to_string());
+ node.remove_field(to_remove);
+ }
+}
+
+fn extract_enum_traits(ast: &mut AstSrc) {
+ let enums = ast.enums.clone();
+ for enm in &mut ast.enums {
+ let nodes = &ast.nodes;
+
+ let mut variant_traits = enm.variants.iter().map(|var| {
+ nodes
+ .iter()
+ .find_map(|node| {
+ if &node.name != var {
+ return None;
+ }
+ Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())
+ })
+ .unwrap_or_else(|| {
+ enums
+ .iter()
+ .find_map(|node| {
+ if &node.name != var {
+ return None;
+ }
+ Some(node.traits.iter().cloned().collect::<BTreeSet<_>>())
+ })
+ .unwrap_or_else(|| {
+ panic!("could not find struct {var} for enum {}::{var}", enm.name)
+ })
+ })
+ });
+
+ let mut enum_traits = match variant_traits.next() {
+ Some(it) => it,
+ None => continue,
+ };
+ for traits in variant_traits {
+ enum_traits = enum_traits.intersection(&traits).cloned().collect();
+ }
+ enm.traits = enum_traits.into_iter().collect();
+ }
+}
xtask/src/sourcegen/kinds.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/kinds.rs
@@ -0,0 +1,279 @@
+#[derive(Debug)]
+pub struct KindsSrc {
+ /// Key - how this token appears in ungrammar
+ defined_tokens: IndexMap<String, TokenKind>,
+ defined_node_names: HashSet<String>,
+ pub nodes: Vec<String>,
+}
+
+#[derive(Debug, Clone)]
+pub enum TokenKind {
+ /// May exist in token tree, but never in source code
+ Meta { grammar_name: String, name: String },
+ /// Specific parsing/lexing errors may be emitted as this type of kind
+ Error {
+ grammar_name: String,
+ name: String,
+ /// Is this error returned by lexer directly, or from lex.rs
+ is_lexer_error: bool,
+ regex: Option<String>,
+ priority: Option<u32>,
+ },
+ /// Keyword - literal match of token
+ Keyword {
+ /// How this keyword appears in grammar/code, should be same as Kinds key
+ code: String,
+ name: String,
+ },
+ /// Literal - something defined by user, i.e strings, identifiers, smth
+ Literal {
+ /// How this keyword appears in grammar, should be same as Kinds key
+ grammar_name: String,
+ name: String,
+ /// Regex for Logos lexer
+ regex: String,
+ /// Path to custom lexer
+ lexer: Option<String>,
+ },
+}
+
+impl TokenKind {
+ pub fn grammar_name(&self) -> &str {
+ match self {
+ TokenKind::Keyword { code, .. } => code,
+ TokenKind::Literal { grammar_name, .. } => grammar_name,
+ TokenKind::Meta { grammar_name, .. } => grammar_name,
+ TokenKind::Error { grammar_name, .. } => grammar_name,
+ }
+ }
+ /// How this keyword should appear in kinds enum, screaming snake cased
+ pub fn name(&self) -> &str {
+ match self {
+ TokenKind::Keyword { name, .. } => name,
+ TokenKind::Literal { name, .. } => name,
+ TokenKind::Meta { name, .. } => name,
+ TokenKind::Error { name, .. } => name,
+ }
+ }
+ pub fn expand_kind(&self) -> TokenStream {
+ let name = format_ident!("{}", self.name());
+ let attr = match self {
+ TokenKind::Keyword { code, .. } => quote! {#[token(#code)]},
+ TokenKind::Literal { regex, lexer, .. } => {
+ let lexer = lexer
+ .as_deref()
+ .map(TokenStream::from_str)
+ .map(|r| r.expect("path is correct"));
+ quote! {#[regex(#regex, #lexer)]}
+ }
+ TokenKind::Error {
+ regex, priority, ..
+ } if regex.is_some() => {
+ let priority = priority.map(|p| quote! {, priority = #p});
+ quote! {#[regex(#regex #priority)]}
+ }
+ _ => quote! {},
+ };
+ quote! {
+ #attr
+ #name
+ }
+ }
+ pub fn expand_t_macros(&self) -> Option<TokenStream> {
+ match self {
+ TokenKind::Keyword { code, name } => {
+ let code = escape_token_macro(code);
+ let name = format_ident!("{name}");
+ Some(quote! {
+ [#code] => {$crate::SyntaxKind::#name}
+ })
+ }
+ // Meta items should not appear in T![_]
+ _ => None,
+ }
+ }
+
+ /// How this token should be referenced in code
+ /// Keywords are referenced with `T![_]` macro,
+ /// and literals are referenced directly by name
+ pub fn reference(&self) -> TokenStream {
+ match self {
+ TokenKind::Keyword { code, .. } => {
+ let code = escape_token_macro(code);
+ quote! {T![#code]}
+ }
+ _ => {
+ let name = self.name();
+ let ident = format_ident!("{name}");
+ quote! {#ident}
+ }
+ }
+ }
+
+ pub fn method_name(&self) -> Ident {
+ match self {
+ TokenKind::Keyword { name, .. } => {
+ format_ident!("{}_token", name.to_lowercase())
+ }
+ TokenKind::Literal { name, .. } => {
+ format_ident!("{}_lit", name.to_lowercase())
+ }
+ TokenKind::Meta { name, .. } => format_ident!("{}_meta", name.to_lowercase()),
+ TokenKind::Error { name, .. } => format_ident!("{}_error", name.to_lowercase()),
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! define_kinds {
+ ($into:ident = lit($name:literal) => $regex:literal $(, $lexer:literal)? $(; $($rest:tt)*)?) => {{
+ $into.define_token(TokenKind::Literal {
+ grammar_name: format!("LIT_{}!", $name),
+ name: $name.to_owned(),
+ regex: $regex.to_owned(),
+ lexer: None $(.or_else(|| Some($lexer.to_string())))?,
+ });
+ $(define_kinds!($into = $($rest)*))?
+ }};
+ ($into:ident = error($name:literal$(, priority = $priority:literal)? $(, lexer = $lexer:literal)?) $(=> $regex:literal)? $(; $($rest:tt)*)?) => {{
+ {
+ let regex = None$(.or(Some($regex.to_owned())))?;
+ let priority = None$(.or(Some($priority)))?;
+ $into.define_token(TokenKind::Error {
+ grammar_name: format!("ERROR_{}!", $name),
+ name: format!("ERROR_{}", $name),
+ is_lexer_error: false $(|| $lexer)? || regex.is_some() || priority.is_some(),
+ regex,
+ priority,
+ });
+ }
+ $(define_kinds!($into = $($rest)*))?
+ }};
+ ($into:ident = $tok:literal => $name:literal $(; $($rest:tt)*)?) => {{
+ $into.define_token(TokenKind::Keyword {
+ code: format!("{}", $tok),
+ name: $name.to_owned(),
+ });
+ $(define_kinds!($into = $($rest)*))?
+ }};
+ ($into:ident =) => {{}}
+}
+use std::{collections::HashSet, str::FromStr};
+
+pub use define_kinds;
+use indexmap::IndexMap;
+use proc_macro2::{Ident, TokenStream};
+use quote::{format_ident, quote};
+
+use super::escape_token_macro;
+
+impl KindsSrc {
+ pub fn new() -> Self {
+ Self {
+ defined_tokens: IndexMap::new(),
+ defined_node_names: HashSet::new(),
+ nodes: Vec::new(),
+ }
+ }
+ pub fn define_token(&mut self, token: TokenKind) {
+ assert!(
+ self.defined_node_names.insert(token.name().to_owned()),
+ "node name already defined: {}",
+ token.name()
+ );
+ assert!(
+ self.defined_tokens
+ .insert(token.grammar_name().to_owned(), token.clone())
+ .is_none(),
+ "token already defined: {}",
+ token.grammar_name()
+ )
+ }
+ pub fn define_node(&mut self, node: &str) {
+ assert!(
+ self.defined_node_names.insert(node.to_owned()),
+ "node name already defined: {}",
+ node
+ );
+ self.nodes.push(node.to_string())
+ }
+ pub fn token(&self, tok: &str) -> Option<&TokenKind> {
+ self.defined_tokens.get(tok)
+ }
+ pub fn is_token(&self, tok: &str) -> bool {
+ self.defined_tokens.contains_key(tok)
+ }
+ pub fn tokens(&self) -> impl Iterator<Item = &TokenKind> {
+ self.defined_tokens.iter().map(|(_, v)| v)
+ }
+}
+
+pub fn jsonnet_kinds() -> KindsSrc {
+ let mut kinds = KindsSrc::new();
+ define_kinds![kinds =
+ "||" => "OR";
+ "??" => "NULL_COAELSE";
+ "&&" => "AND";
+ "|" => "BIT_OR";
+ "^" => "BIT_XOR";
+ "&" => "BIT_AND";
+ "==" => "EQ";
+ "!=" => "NE";
+ "<" => "LT";
+ ">" => "GT";
+ "<=" => "LE";
+ ">=" => "GE";
+ "<<" => "LHS";
+ ">>" => "RHS";
+ "+" => "PLUS";
+ "-" => "MINUS";
+ "*" => "MUL";
+ "/" => "DIV";
+ "%" => "MODULO";
+ "!" => "NOT";
+ "~" => "BIT_NOT";
+ "[" => "L_BRACK";
+ "]" => "R_BRACK";
+ "(" => "L_PAREN";
+ ")" => "R_PAREN";
+ "{" => "L_BRACE";
+ "}" => "R_BRACE";
+ ":" => "COLON";
+ "::" => "COLONCOLON";
+ ":::" => "COLONCOLONCOLON";
+ ";" => "SEMI";
+ "." => "DOT";
+ "..." => "DOTDOTDOT";
+ "," => "COMMA";
+ "$" => "DOLLAR";
+ "=" => "ASSIGN";
+ "?" => "QUESTION_MARK";
+ // Literals
+ lit("FLOAT") => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?";
+ error("FLOAT_JUNK_AFTER_POINT") => r"(?:0|[1-9][0-9]*)\.[^0-9]";
+ error("FLOAT_JUNK_AFTER_EXPONENT") => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?[eE][^+\-0-9]";
+ error("FLOAT_JUNK_AFTER_EXPONENT_SIGN") => r"(?:0|[1-9][0-9]*)(?:\.[0-9]+)?[eE][+-][^0-9]";
+ lit("STRING_DOUBLE") => "\"(?s:[^\"\\\\]|\\\\.)*\"";
+ error("STRING_DOUBLE_UNTERMINATED") => "\"(?s:[^\"\\\\]|\\\\.)*";
+ lit("STRING_SINGLE") => "'(?s:[^'\\\\]|\\\\.)*'";
+ error("STRING_SINGLE_UNTERMINATED") => "'(?s:[^'\\\\]|\\\\.)*";
+ lit("STRING_DOUBLE_VERBATIM") => "@\"(?:[^\"]|\"\")*\"";
+ error("STRING_DOUBLE_VERBATIM_UNTERMINATED") => "@\"(?:[^\"]|\"\")*";
+ lit("STRING_SINGLE_VERBATIM") => "@'(?:[^']|'')*'";
+ error("STRING_SINGLE_VERBATIM_UNTERMINATED") => "@'(?:[^']|'')*";
+ error("STRING_VERBATIM_MISSING_QUOTES") => "@[^\"'\\s]\\S+";
+ lit("STRING_BLOCK") => r"\|\|\|", "crate::string_block::lex_str_block_test";
+ error("STRING_BLOCK_UNEXPECTED_END", lexer = true);
+ error("STRING_BLOCK_MISSING_NEW_LINE", lexer = true);
+ error("STRING_BLOCK_MISSING_TERMINATION", lexer = true);
+ error("STRING_BLOCK_MISSING_INDENT", lexer = true);
+ lit("IDENT") => r"[_a-zA-Z][_a-zA-Z0-9]*";
+ lit("WHITESPACE") => r"[ \t\n\r]+";
+ lit("SINGLE_LINE_SLASH_COMMENT") => r"//[^\r\n]*(\r\n|\n)?";
+ lit("SINGLE_LINE_HASH_COMMENT") => r"#[^\r\n]*(\r\n|\n)?";
+ lit("MULTI_LINE_COMMENT") => r"/\*([^*]|\*[^/])*\*/";
+ error("COMMENT_TOO_SHORT") => r"/\*/";
+ error("COMMENT_UNTERMINATED") => r"/\*([^*]|\*[^/])+";
+ ];
+ kinds
+}
xtask/src/sourcegen/mod.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/mod.rs
@@ -0,0 +1,541 @@
+use std::path::PathBuf;
+
+use anyhow::Result;
+use ast::{lower, AstSrc};
+use itertools::Itertools;
+use kinds::{KindsSrc, TokenKind};
+use proc_macro2::{Punct, Spacing, TokenStream};
+use quote::{format_ident, quote};
+use ungrammar::Grammar;
+use util::{ensure_file_contents, reformat, to_pascal_case, to_upper_snake_case};
+
+mod ast;
+mod kinds;
+mod util;
+
+enum SpecialName {
+ Literal,
+ Meta,
+ Error,
+}
+fn classify_special(name: &str) -> Option<(SpecialName, &str)> {
+ let name = name.strip_suffix('!')?;
+ Some(if let Some(name) = name.strip_prefix("LIT_") {
+ (SpecialName::Literal, name)
+ } else if let Some(name) = name.strip_prefix("META_") {
+ (SpecialName::Meta, name)
+ } else if let Some(name) = name.strip_prefix("ERROR_") {
+ (SpecialName::Error, name)
+ } else {
+ return None;
+ })
+}
+
+pub fn generate_ungrammar() -> Result<()> {
+ let grammar: Grammar = include_str!(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/jsonnet.ungram"
+ ))
+ .parse()?;
+
+ let mut kinds = kinds::jsonnet_kinds();
+ let ast = lower(&kinds, &grammar);
+
+ for token in grammar.tokens() {
+ let token = &grammar[token];
+ let token = &token.name.clone();
+ if !kinds.is_token(token) {
+ if let Some((special, name)) = classify_special(token) {
+ match special {
+ SpecialName::Literal => panic!("literal is not defined: {name}"),
+ SpecialName::Meta => {
+ eprintln!("implicit meta: {}", name);
+ kinds.define_token(TokenKind::Meta {
+ grammar_name: token.to_owned(),
+ name: format!("META_{}", name),
+ })
+ }
+ SpecialName::Error => {
+ eprintln!("implicit error: {}", name);
+ kinds.define_token(TokenKind::Error {
+ grammar_name: token.to_owned(),
+ name: format!("ERROR_{}", name),
+ regex: None,
+ priority: None,
+ is_lexer_error: true,
+ })
+ }
+ };
+ continue;
+ };
+ let name = to_upper_snake_case(token);
+ eprintln!("implicit kw: {}", token);
+ kinds.define_token(TokenKind::Keyword {
+ code: token.to_owned(),
+ name: format!("{name}_KW"),
+ });
+ }
+ }
+ for node in &ast.nodes {
+ let name = to_upper_snake_case(&node.name);
+ kinds.define_node(&name);
+ }
+ for enum_ in &ast.enums {
+ let name = to_upper_snake_case(&enum_.name);
+ kinds.define_node(&name);
+ }
+ for token_enum in &ast.token_enums {
+ let name = to_upper_snake_case(&token_enum.name);
+ kinds.define_node(&name);
+ }
+
+ let syntax_kinds = generate_syntax_kinds(&kinds, &ast)?;
+
+ let nodes = generate_nodes(&kinds, &ast)?;
+ ensure_file_contents(
+ &PathBuf::from(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/src/generated/syntax_kinds.rs",
+ )),
+ &syntax_kinds,
+ )?;
+ ensure_file_contents(
+ &PathBuf::from(concat!(
+ env!("CARGO_MANIFEST_DIR"),
+ "/../crates/jrsonnet-rowan-parser/src/generated/nodes.rs",
+ )),
+ &nodes,
+ )?;
+ Ok(())
+}
+
+fn generate_syntax_kinds(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {
+ let t_macros = kinds.tokens().filter_map(TokenKind::expand_t_macros);
+ let token_kinds = kinds.tokens().map(TokenKind::expand_kind);
+
+ let keywords = kinds
+ .tokens()
+ .filter(|k| matches!(k, TokenKind::Keyword { .. }))
+ .map(TokenKind::name)
+ .map(|n| format_ident!("{n}"));
+
+ let nodes = kinds
+ .nodes
+ .iter()
+ .map(|name| format_ident!("{}", name))
+ .collect::<Vec<_>>();
+
+ let enums = grammar
+ .enums
+ .iter()
+ .map(|e| format_ident!("{}", to_upper_snake_case(&e.name)))
+ .chain(
+ grammar
+ .token_enums
+ .iter()
+ .map(|e| format_ident!("{}", to_upper_snake_case(&e.name))),
+ );
+
+ let ast = quote! {
+ #![allow(bad_style, missing_docs, unreachable_pub, clippy::manual_non_exhaustive, clippy::match_like_matches_macro)]
+ use logos::Logos;
+
+ /// The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`.
+ #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Logos)]
+ #[repr(u16)]
+ pub enum SyntaxKind {
+ #[doc(hidden)]
+ TOMBSTONE,
+ #[doc(hidden)]
+ EOF,
+ #(#token_kinds,)*
+ /// Also acts as __LAST_TOKEN
+ #[error]
+ LEXING_ERROR,
+ #(#nodes,)*
+ #[doc(hidden)]
+ __LAST,
+ }
+ use self::SyntaxKind::*;
+
+ impl SyntaxKind {
+ pub fn is_keyword(self) -> bool {
+ match self {
+ #(#keywords)|* => true,
+ _ => false,
+ }
+ }
+ pub fn is_enum(self) -> bool {
+ match self {
+ #(#enums)|* => true,
+ _ => false,
+ }
+ }
+
+ pub fn from_raw(r: u16) -> Self {
+ assert!(r < Self::__LAST as u16);
+ unsafe { std::mem::transmute(r) }
+ }
+ pub fn into_raw(self) -> u16 {
+ self as u16
+ }
+ }
+
+ #[macro_export]
+ macro_rules! T {#(#t_macros);*}
+ pub use T;
+ };
+
+ reformat(&ast.to_string())
+}
+
+fn generate_nodes(kinds: &KindsSrc, grammar: &AstSrc) -> Result<String> {
+ let (node_defs, node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .nodes
+ .iter()
+ .map(|node| {
+ let name = format_ident!("{}", node.name);
+ let kind = format_ident!("{}", to_upper_snake_case(&node.name));
+ let traits = node.traits.iter().map(|trait_name| {
+ let trait_name = format_ident!("{}", trait_name);
+ quote!(impl ast::#trait_name for #name {})
+ });
+
+ let methods = node.fields.iter().map(|field| {
+ let method_name = field.method_name(kinds);
+ let ty = field.ty();
+
+ if field.is_many() {
+ quote! {
+ pub fn #method_name(&self) -> AstChildren<#ty> {
+ support::children(&self.syntax)
+ }
+ }
+ } else if let Some(token_kind) = field.token_kind(kinds) {
+ quote! {
+ pub fn #method_name(&self) -> Option<#ty> {
+ support::token(&self.syntax, #token_kind)
+ }
+ }
+ } else if field.is_token_enum(grammar) {
+ quote! {
+ pub fn #method_name(&self) -> Option<#ty> {
+ support::token_child(&self.syntax)
+ }
+ }
+ } else {
+ quote! {
+ pub fn #method_name(&self) -> Option<#ty> {
+ support::child(&self.syntax)
+ }
+ }
+ }
+ });
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name {
+ pub(crate) syntax: SyntaxNode,
+ }
+
+ #(#traits)*
+
+ impl #name {
+ #(#methods)*
+ }
+ },
+ quote! {
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ kind == #kind
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+ }
+ },
+ )
+ })
+ .unzip();
+
+ let (enum_defs, enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .enums
+ .iter()
+ .map(|en| {
+ let variants: Vec<_> = en
+ .variants
+ .iter()
+ .map(|var| format_ident!("{}", var))
+ .collect();
+ let name = format_ident!("{}", en.name);
+ let kinds: Vec<_> = variants
+ .iter()
+ .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
+ .collect();
+ let traits = en.traits.iter().map(|trait_name| {
+ let trait_name = format_ident!("{}", trait_name);
+ quote!(impl ast::#trait_name for #name {})
+ });
+
+ let ast_node = quote! {
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ #(#kinds)|* => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ let res = match syntax.kind() {
+ #(
+ #kinds => #name::#variants(#variants { syntax }),
+ )*
+ _ => return None,
+ };
+ Some(res)
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ match self {
+ #(
+ #name::#variants(it) => &it.syntax,
+ )*
+ }
+ }
+ }
+ };
+
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub enum #name {
+ #(#variants(#variants),)*
+ }
+
+ #(#traits)*
+ },
+ quote! {
+ #(
+ impl From<#variants> for #name {
+ fn from(node: #variants) -> #name {
+ #name::#variants(node)
+ }
+ }
+ )*
+ #ast_node
+ },
+ )
+ })
+ .unzip();
+
+ let (token_enum_defs, token_enum_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .token_enums
+ .iter()
+ .map(|en| {
+ let variants: Vec<_> = en
+ .variants
+ .iter()
+ .map(|token| {
+ format_ident!(
+ "{}",
+ to_pascal_case(kinds.token(token).expect("token exists").name())
+ )
+ })
+ .collect();
+ let name = format_ident!("{}", en.name);
+ let kind_name = format_ident!("{}Kind", en.name);
+ let kinds: Vec<_> = variants
+ .iter()
+ .map(|name| format_ident!("{}", to_upper_snake_case(&name.to_string())))
+ .collect();
+
+ let ast_node = quote! {
+ impl AstToken for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ #kind_name::can_cast(kind)
+ }
+ fn cast(syntax: SyntaxToken) -> Option<Self> {
+ let kind = #kind_name::cast(syntax.kind())?;
+ Some(#name { syntax, kind })
+ }
+ fn syntax(&self) -> &SyntaxToken {
+ &self.syntax
+ }
+ }
+
+ impl #kind_name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ #(#kinds)|* => true,
+ _ => false,
+ }
+ }
+ pub fn cast(kind: SyntaxKind) -> Option<Self> {
+ let res = match kind {
+ #(#kinds => Self::#variants,)*
+ _ => return None,
+ };
+ Some(res)
+ }
+ }
+ };
+
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name { syntax: SyntaxToken, kind: #kind_name }
+
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+ pub enum #kind_name {
+ #(#variants,)*
+ }
+ },
+ quote! {
+ #ast_node
+
+ impl #name {
+ pub fn kind(&self) -> #kind_name {
+ self.kind
+ }
+ }
+
+ impl std::fmt::Display for #name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+ }
+ },
+ )
+ })
+ .unzip();
+
+ let (any_node_defs, any_node_boilerplate_impls): (Vec<_>, Vec<_>) = grammar
+ .nodes
+ .iter()
+ .flat_map(|node| node.traits.iter().map(move |t| (t, node)))
+ .into_group_map()
+ .into_iter()
+ .sorted_by_key(|(k, _)| *k)
+ .map(|(trait_name, nodes)| {
+ let name = format_ident!("Any{}", trait_name);
+ let trait_name = format_ident!("{}", trait_name);
+ let kinds: Vec<_> = nodes
+ .iter()
+ .map(|name| format_ident!("{}", to_upper_snake_case(&name.name.to_string())))
+ .collect();
+
+ (
+ quote! {
+ #[pretty_doc_comment_placeholder_workaround]
+ #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+ pub struct #name {
+ pub(crate) syntax: SyntaxNode,
+ }
+ impl ast::#trait_name for #name {}
+ },
+ quote! {
+ impl #name {
+ #[inline]
+ pub fn new<T: ast::#trait_name>(node: T) -> #name {
+ #name {
+ syntax: node.syntax().clone()
+ }
+ }
+ }
+ impl AstNode for #name {
+ fn can_cast(kind: SyntaxKind) -> bool {
+ match kind {
+ #(#kinds)|* => true,
+ _ => false,
+ }
+ }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ Self::can_cast(syntax.kind()).then(|| #name { syntax })
+ }
+ fn syntax(&self) -> &SyntaxNode {
+ &self.syntax
+ }
+ }
+ },
+ )
+ })
+ .unzip();
+
+ let enum_names = grammar.enums.iter().map(|it| &it.name);
+ let node_names = grammar.nodes.iter().map(|it| &it.name);
+
+ let display_impls = enum_names
+ .chain(node_names.clone())
+ .map(|it| format_ident!("{}", it))
+ .map(|name| {
+ quote! {
+ impl std::fmt::Display for #name {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+ }
+ }
+ });
+
+ let ast = quote! {
+ #![allow(non_snake_case, clippy::match_like_matches_macro)]
+
+ use crate::{
+ SyntaxNode, SyntaxToken, SyntaxKind::{self, *},
+ ast::{AstNode, AstToken, AstChildren, support},
+ T,
+ };
+
+ #(#node_defs)*
+ #(#enum_defs)*
+ #(#token_enum_defs)*
+ #(#any_node_defs)*
+ #(#node_boilerplate_impls)*
+ #(#enum_boilerplate_impls)*
+ #(#token_enum_boilerplate_impls)*
+ #(#any_node_boilerplate_impls)*
+ #(#display_impls)*
+ };
+
+ let ast = ast.to_string().replace("T ! [", "T![");
+
+ let mut res = String::with_capacity(ast.len() * 2);
+
+ let mut docs = grammar
+ .nodes
+ .iter()
+ .map(|it| &it.doc)
+ .chain(grammar.enums.iter().map(|it| &it.doc));
+
+ for chunk in ast.split("# [pretty_doc_comment_placeholder_workaround] ") {
+ res.push_str(chunk);
+ if let Some(doc) = docs.next() {
+ write_doc_comment(doc, &mut res);
+ }
+ }
+
+ let res = reformat(&res)?;
+ Ok(res.replace("#[derive", "\n#[derive"))
+}
+
+fn write_doc_comment(contents: &[String], dest: &mut String) {
+ use std::fmt::Write;
+ for line in contents {
+ writeln!(dest, "///{}", line).unwrap();
+ }
+}
+
+pub fn escape_token_macro(token: &str) -> TokenStream {
+ if "{}[]()$".contains(token) {
+ let c = token.chars().next().unwrap();
+ quote! { #c }
+ } else if token.contains('$') {
+ quote! { #token }
+ } else {
+ let cs = token.chars().map(|c| Punct::new(c, Spacing::Joint));
+ quote! { #(#cs)* }
+ }
+}
xtask/src/sourcegen/util.rsdiffbeforeafterboth--- /dev/null
+++ b/xtask/src/sourcegen/util.rs
@@ -0,0 +1,87 @@
+use std::{fs, path::Path};
+
+use anyhow::Result;
+use xshell::{cmd, Shell};
+
+/// Checks that the `file` has the specified `contents`. If that is not the
+/// case, updates the file and then fails the test.
+pub fn ensure_file_contents(file: &Path, contents: &str) -> Result<()> {
+ if let Ok(old_contents) = fs::read_to_string(file) {
+ if normalize_newlines(&old_contents) == normalize_newlines(contents) {
+ // File is already up to date.
+ return Ok(());
+ }
+ }
+
+ eprintln!("{} was not up-to-date, updating", file.display());
+ if let Some(parent) = file.parent() {
+ let _ = fs::create_dir_all(parent);
+ }
+ fs::write(file, contents).unwrap();
+ Ok(())
+}
+
+// Eww, someone configured git to use crlf?
+fn normalize_newlines(s: &str) -> String {
+ s.replace("\r\n", "\n")
+}
+
+pub(crate) fn pluralize(s: &str) -> String {
+ format!("{}s", s)
+}
+
+pub fn to_upper_snake_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev = false;
+ for c in s.chars() {
+ if c.is_ascii_uppercase() && prev {
+ buf.push('_')
+ }
+ prev = true;
+
+ buf.push(c.to_ascii_uppercase());
+ }
+ buf
+}
+pub fn to_lower_snake_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev = false;
+ for c in s.chars() {
+ if c.is_ascii_uppercase() && prev {
+ buf.push('_')
+ }
+ prev = true;
+
+ buf.push(c.to_ascii_lowercase());
+ }
+ buf
+}
+
+pub fn to_pascal_case(s: &str) -> String {
+ let mut buf = String::with_capacity(s.len());
+ let mut prev_is_underscore = true;
+ for c in s.chars() {
+ if c == '_' {
+ prev_is_underscore = true;
+ } else if prev_is_underscore {
+ buf.push(c.to_ascii_uppercase());
+ prev_is_underscore = false;
+ } else {
+ buf.push(c.to_ascii_lowercase());
+ }
+ }
+ buf
+}
+
+pub fn reformat(text: &str) -> Result<String> {
+ // let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
+ // rustfmt()?;
+ let sh = Shell::new()?;
+ let stdout = cmd!(sh, "rustfmt").stdin(text).read()?;
+ Ok(format!(
+ "{}\n\n{}\n",
+ "//! This is a generated file, please do not edit manually. Changes can be
+//! made in codegeneration that lives in `xtask` top-level dir.",
+ stdout
+ ))
+}