diff --git a/Cargo.lock b/Cargo.lock index a80b059..6f6a4ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,36 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.16", + "once_cell", + "version_check", + "zerocopy 0.7.35", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ariadne" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f5e3dca4e09a6f340a61a0e9c7b61e030c69fc27bf29d73218f7e5e3b7638f" +dependencies = [ + "concolor", + "unicode-width", + "yansi", +] + [[package]] name = "autocfg" version = "1.5.0" @@ -12,8 +42,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" name = "bang" version = "0.1.0" dependencies = [ - "codespan", - "codespan-reporting", + "ariadne", + "internment", + "memmap2", "proptest", "proptest-derive", "thiserror", @@ -34,6 +65,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.9.4" @@ -47,26 +84,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] -name = "codespan" -version = "0.12.0" +name = "concolor" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4b418d52c9206820a56fc1aa28db73d67e346ba8ba6aa90987e8d6becef7e4" +checksum = "0b946244a988c390a94667ae0e3958411fa40cc46ea496a929b263d883f5f9c3" dependencies = [ - "codespan-reporting", - "serde", + "bitflags 1.3.2", + "concolor-query", + "is-terminal", ] [[package]] -name = "codespan-reporting" -version = "0.12.0" +name = "concolor-query" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" dependencies = [ - "serde", - "termcolor", - "unicode-width", + "windows-sys 0.45.0", ] +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -74,7 +129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] @@ -89,6 +144,23 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -98,7 +170,53 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "internment" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636d4b0f6a39fd684effe2a73f5310df16a3fa7954c26d36833e98f44d1977a2" +dependencies = [ + "ahash", + "dashmap", + "hashbrown 0.15.5", + "once_cell", +] + +[[package]] +name = "is-terminal" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.59.0", ] [[package]] @@ -119,6 +237,25 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memmap2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843a98750cd611cc2965a8213b53b43e715f13c37a9e096c6408e69990961db7" +dependencies = [ + "libc", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -134,13 +271,26 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "ppv-lite86" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.27", ] [[package]] @@ -160,7 +310,7 @@ checksum = "2bb0be07becd10686a0bb407298fb425360a5c44a663774406340c59a22de4ce" dependencies = [ "bit-set", "bit-vec", - "bitflags", + "bitflags 2.9.4", "lazy_static", "num-traits", "rand", @@ -191,9 +341,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -230,7 +380,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom", + "getrandom 0.3.3", ] [[package]] @@ -242,6 +392,15 @@ dependencies = [ "rand_core", ] +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags 2.9.4", +] + [[package]] name = "regex-syntax" version = "0.8.6" @@ -254,18 +413,18 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.61.2", ] [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -274,34 +433,16 @@ dependencies = [ ] [[package]] -name = "serde" -version = "1.0.227" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" -dependencies = [ - "serde_core", - "serde_derive", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "serde_core" -version = "1.0.227" +name = "smallvec" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.227" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "syn" @@ -321,35 +462,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom", + "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys", -] - -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", + "windows-sys 0.61.2", ] [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -370,9 +502,15 @@ checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-width" -version = "0.2.1" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" @@ -383,6 +521,12 @@ dependencies = [ "libc", ] +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + [[package]] name = "wasi" version = "0.14.7+wasi-0.2.4" @@ -401,43 +545,199 @@ dependencies = [ "wit-bindgen", ] -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys", -] - [[package]] name = "windows-link" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.61.1" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive 0.7.35", +] + [[package]] name = "zerocopy" version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ - "zerocopy-derive", + "zerocopy-derive 0.8.27", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e994877..364d469 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,9 @@ version = "0.1.0" edition = "2024" [dependencies] -codespan = "0.12.0" -codespan-reporting = "0.12.0" +ariadne = { version = "0.5.1", features = ["auto-color"] } +internment = { version = "0.8.6", features = ["arc", "arena"] } +memmap2 = "0.9.8" proptest = "1.7.0" proptest-derive = "0.6.0" thiserror = "2.0.12" diff --git a/src/syntax.rs b/src/syntax.rs index 35ae376..4476080 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -6,11 +6,61 @@ mod parse; mod parser_tests; pub mod tokens; +pub use crate::syntax::error::ParserError; +use crate::syntax::parse::Parser; +use crate::syntax::tokens::Lexer; +use internment::ArcIntern; pub use location::{Located, Location}; +use memmap2::Mmap; pub use name::Name; use proptest_derive::Arbitrary; +use std::collections::HashMap; use std::fmt::Debug; use std::ops::Range; +use std::path::{Path, PathBuf}; + +pub struct Universe { + pub files: HashMap, + pub modules: HashMap, +} + +impl Default for Universe { + fn default() -> Self { + Universe { + files: HashMap::new(), + modules: HashMap::new(), + } + } +} + +impl Universe { + pub fn add_file>(&mut self, file: P) -> Result<(), ParserError> { + let filename = file.as_ref().to_string_lossy().into_owned(); + + let file_handle = std::fs::File::open(&file) + .map_err(|e| ParserError::OpenError { + file: filename.clone(), + error: e, + })?; + let contents = unsafe { Mmap::map(&file_handle) } + .map_err(|e| ParserError::ReadError { + file: filename.clone(), + error: e, + })?; + let string_contents = std::str::from_utf8(&contents) + .map_err(|e| ParserError::Utf8Error { + file: filename.clone(), + error: e, + })?; + + let lexer = Lexer::from(string_contents); + let mut parser = Parser::new(&file, lexer); + let module = parser.parse_module()?; + self.modules.insert(file.as_ref().to_path_buf(), module); + + Ok(()) + } +} #[derive(Debug)] pub struct Module { diff --git a/src/syntax/error.rs b/src/syntax/error.rs index 35924b9..7700cb1 100644 --- a/src/syntax/error.rs +++ b/src/syntax/error.rs @@ -1,23 +1,34 @@ //use codespan_reporting::diagnostic::{Diagnostic, Label}; use crate::syntax::tokens::Token; use std::ops::Range; +use std::path::PathBuf; +use internment::ArcIntern; use thiserror::Error; #[derive(Debug, Error)] pub enum ParserError { - #[error("Lexer error at {file_id}: {error}")] - LexerError { file_id: usize, error: LexerError }, + #[error("Lexer error at {file}: {error}")] + LexerError { file: ArcIntern, error: LexerError }, - #[error("Unacceptable end of file at {file_id} while {place}")] - UnacceptableEof { file_id: usize, place: &'static str }, + #[error("Unacceptable end of file at {file} while {place}")] + UnacceptableEof { file: ArcIntern, place: &'static str }, - #[error("Unexpected token at {file_id}: expected {expected}, saw {token}")] + #[error("Unexpected token at {file}: expected {expected}, saw {token}")] UnexpectedToken { - file_id: usize, + file: ArcIntern, span: Range, token: Token, expected: &'static str, }, + + #[error("Unexpected problem opening file {file}: {error}")] + OpenError { file: String, error: std::io::Error }, + + #[error("Unexpected problem reading file {file}: {error}")] + ReadError { file: String, error: std::io::Error }, + + #[error("UTF-8 problem reading file {file}: {error}")] + Utf8Error { file: String, error: std::str::Utf8Error }, } #[derive(Clone, Debug, Error, PartialEq)] diff --git a/src/syntax/location.rs b/src/syntax/location.rs index fe4a352..104d6d8 100644 --- a/src/syntax/location.rs +++ b/src/syntax/location.rs @@ -1,6 +1,8 @@ -use codespan_reporting::diagnostic::Label; +use ariadne::Span; +use internment::ArcIntern; use std::cmp::{max, min}; use std::ops::Range; +use std::path::PathBuf; pub trait Located { fn location(&self) -> Location; @@ -8,19 +10,35 @@ pub trait Located { #[derive(Clone, Debug, Eq, PartialEq)] pub struct Location { - file_id: usize, + file: ArcIntern, span: Range, } +impl Span for Location { + type SourceId = ArcIntern; + + fn source(&self) -> &Self::SourceId { + &self.file + } + + fn start(&self) -> usize { + self.span.start + } + + fn end(&self) -> usize { + self.span.end + } +} + impl Location { - pub fn new(file_id: usize, span: Range) -> Self { - Location { file_id, span } + pub fn new(file: &ArcIntern, span: Range) -> Self { + Location { file: file.clone(), span } } pub fn extend_to(&self, other: &Location) -> Location { - assert_eq!(self.file_id, other.file_id); + assert_eq!(self.file, other.file); Location { - file_id: self.file_id, + file: self.file.clone(), span: min(self.span.start, other.span.start)..max(self.span.end, other.span.end), } } @@ -30,19 +48,11 @@ impl Location { self } - pub fn file_id(&self) -> usize { - self.file_id + pub fn file(&self) -> &str { + self.file.to_str().unwrap_or("") } pub fn span(&self) -> Range { self.span.clone() } - - pub fn primary_label(&self) -> Label { - Label::primary(self.file_id, self.span.clone()) - } - - pub fn secondary_label(&self) -> Label { - Label::secondary(self.file_id, self.span.clone()) - } } diff --git a/src/syntax/parse.rs b/src/syntax/parse.rs index ddb7c2e..d6c0d80 100644 --- a/src/syntax/parse.rs +++ b/src/syntax/parse.rs @@ -1,11 +1,12 @@ use crate::syntax::error::ParserError; use crate::syntax::tokens::{Lexer, LocatedToken, Token}; use crate::syntax::*; +use internment::ArcIntern; use std::collections::HashMap; -pub struct Parser<'a> { - file_id: usize, - lexer: Lexer<'a>, +pub struct Parser<'lexer> { + file: ArcIntern, + lexer: Lexer<'lexer>, known_tokens: Vec, prefix_precedence_table: HashMap, infix_precedence_table: HashMap, @@ -18,16 +19,19 @@ pub enum Associativity { None, } -impl<'a> Parser<'a> { +impl<'lexer> Parser<'lexer> { /// Create a new parser from the given file index and lexer. /// /// The file index will be used for annotating locations and for /// error messages. If you don't care about either, you can use /// 0 with no loss of functionality. (Obviously, it will be harder /// to create quality error messages, but you already knew that.) - pub fn new(file_id: usize, lexer: Lexer<'a>) -> Parser<'a> { + pub fn new>( + file: P, + lexer: Lexer<'lexer> + ) -> Parser<'lexer> { Parser { - file_id, + file: ArcIntern::new(file.as_ref().to_path_buf()), lexer, known_tokens: vec![], prefix_precedence_table: HashMap::new(), @@ -82,7 +86,7 @@ impl<'a> Parser<'a> { .next() .transpose() .map_err(|error| ParserError::LexerError { - file_id: self.file_id, + file: self.file.clone(), error, }) } @@ -94,13 +98,13 @@ impl<'a> Parser<'a> { fn bad_eof(&mut self, place: &'static str) -> ParserError { ParserError::UnacceptableEof { - file_id: self.file_id, + file: self.file.clone(), place, } } fn to_location(&self, span: Range) -> Location { - Location::new(self.file_id, span) + Location::new(&self.file, span) } pub fn parse_module(&mut self) -> Result { @@ -161,7 +165,7 @@ impl<'a> Parser<'a> { if !matches!(maybe_paren.token, Token::OpenParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_paren.span, token: maybe_paren.token, expected: "open parenthesis, following the restrict keyword", @@ -179,7 +183,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("Looking for open paren after restrict"))?; if !matches!(maybe_paren.token, Token::CloseParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_paren.span, token: maybe_paren.token, expected: "close parenthesis following type restrictions", @@ -212,7 +216,7 @@ impl<'a> Parser<'a> { weird => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_constructor.span, token: weird, expected: "Constructor name, comma, or close parenthesis in type restriction", @@ -261,7 +265,7 @@ impl<'a> Parser<'a> { } Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "'structure', 'enumeration', or a value identifier", @@ -274,7 +278,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("looking for definition"))?; if !matches!(structure_token.token, Token::ValueName(ref s) if s == "structure") { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: structure_token.span, token: structure_token.token, expected: "the 'structure' keyword", @@ -288,7 +292,7 @@ impl<'a> Parser<'a> { Token::TypeName(str) => str, _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: name.span, token: name.token, expected: "a structure name", @@ -301,7 +305,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("the open brace after a structure name"))?; if !matches!(brace.token, Token::OpenBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: brace.span, token: brace.token, expected: "the brace after a structure name", @@ -319,7 +323,7 @@ impl<'a> Parser<'a> { })?; if !matches!(brace.token, Token::CloseBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: brace.span, token: brace.token, expected: "the brace at the end of a structure definition", @@ -355,7 +359,7 @@ impl<'a> Parser<'a> { })?; if !matches!(maybe_colon.token, Token::Colon) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_colon.span, token: maybe_colon.token, expected: "colon after field name in constructor", @@ -388,7 +392,7 @@ impl<'a> Parser<'a> { return Ok(None); } else { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_name.span, token: maybe_name.token, expected: "a field name", @@ -412,7 +416,7 @@ impl<'a> Parser<'a> { _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_colon.span, token: maybe_colon.token, expected: "colon, comma, or close brace after field name", @@ -432,7 +436,7 @@ impl<'a> Parser<'a> { } _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: end_token.span, token: end_token.token, expected: "looking for comma or close brace after field definition", @@ -459,7 +463,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("looking for definition"))?; if !matches!(enumeration_token.token, Token::ValueName(ref e) if e == "enumeration") { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: enumeration_token.span, token: enumeration_token.token, expected: "the 'enumeration' keyword", @@ -473,7 +477,7 @@ impl<'a> Parser<'a> { Token::TypeName(str) => str, _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: name.span, token: name.token, expected: "an enumeration name", @@ -486,7 +490,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("the open brace after an enumeration name"))?; if !matches!(brace.token, Token::OpenBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: brace.span, token: brace.token, expected: "the brace after an enumeration name", @@ -504,7 +508,7 @@ impl<'a> Parser<'a> { })?; if !matches!(brace.token, Token::CloseBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: brace.span, token: brace.token, expected: "the brace at the end of an enumeration definition", @@ -535,7 +539,7 @@ impl<'a> Parser<'a> { _ => { self.save(maybe_name.clone()); return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_name.span, token: maybe_name.token, expected: "variant name (identifier starting with a capital)", @@ -555,7 +559,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("trying to parse a enumeration variant's type"))?; if !matches!(maybe_close.token, Token::CloseParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_close.span, token: maybe_close.token, expected: "close paren to end an enumeration variant's type argument", @@ -581,7 +585,7 @@ impl<'a> Parser<'a> { _ => { self.save(ender.clone()); return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: ender.span, token: ender.token, expected: "comma or close brace after enumeration variant", @@ -598,7 +602,7 @@ impl<'a> Parser<'a> { })) } - pub fn parse_function_or_value(&mut self) -> Result { + fn parse_function_or_value(&mut self) -> Result { unimplemented!() } @@ -617,17 +621,17 @@ impl<'a> Parser<'a> { } } - pub fn parse_match_expression(&mut self) -> Result { + fn parse_match_expression(&mut self) -> Result { unimplemented!() } - pub fn parse_if_expression(&mut self) -> Result { + fn parse_if_expression(&mut self) -> Result { let next = self .next()? .ok_or_else(|| self.bad_eof("looking for an 'if' to start conditional"))?; if !matches!(next.token, Token::ValueName(ref x) if x == "if") { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "an 'if' to start a conditional", @@ -677,7 +681,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("looking for open brace to start block"))?; if !matches!(next.token, Token::OpenBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "an open brace to start a block", @@ -701,7 +705,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("looking for statement or block close"))?; if !matches!(next.token, Token::CloseBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "a close brace to end a block", @@ -762,7 +766,7 @@ impl<'a> Parser<'a> { if !matches!(next.token, Token::ValueName(ref n) if n == "let") { self.save(next.clone()); return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "a 'let' to open a binding statement", @@ -785,7 +789,7 @@ impl<'a> Parser<'a> { Token::ValueName(v) => Name::new(self.to_location(next.span), v), _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "a variable name for the let binding", @@ -798,7 +802,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("an '=' after a variable name in a binding"))?; if !matches!(next.token, Token::OperatorName(ref x) if x == "=") { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "an '=' after the variable name in a let binding", @@ -812,7 +816,7 @@ impl<'a> Parser<'a> { .ok_or_else(|| self.bad_eof("looking for terminal semicolon for let statement"))?; if !matches!(next.token, Token::Semi) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "a semicolon to finish a let statement", @@ -839,7 +843,7 @@ impl<'a> Parser<'a> { if *pre_prec < level { self.save(next.clone()); return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "a base expression of a tighter-binding prefix operator", @@ -918,7 +922,7 @@ impl<'a> Parser<'a> { if !matches!(next.token, Token::OpenParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "open paren for call arguments", @@ -948,7 +952,7 @@ impl<'a> Parser<'a> { Token::CloseParen => break, _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "comma or close paren in function arguments", @@ -985,7 +989,7 @@ impl<'a> Parser<'a> { } else { self.save(hopefully_close.clone()); Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: hopefully_close.span, token: hopefully_close.token, expected: "close paren after expression", @@ -1012,7 +1016,7 @@ impl<'a> Parser<'a> { })?; if !matches!(closer.token, Token::CloseBrace) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: closer.span, token: closer.token, expected: "close brace or comma after field value", @@ -1028,7 +1032,7 @@ impl<'a> Parser<'a> { })?; if !matches!(second_colon.token, Token::Colon) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: second_colon.span, token: second_colon.token, expected: "second colon in enumeration value", @@ -1047,7 +1051,7 @@ impl<'a> Parser<'a> { _ => { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: vname.span, token: vname.token, expected: "enumeration value name", @@ -1063,7 +1067,7 @@ impl<'a> Parser<'a> { })?; if !matches!(tok.token, Token::CloseParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: tok.span, token: tok.token, expected: "close paren after enum value argument", @@ -1079,7 +1083,7 @@ impl<'a> Parser<'a> { } _ => Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: after_type_name.span, token: after_type_name.token, expected: "colon, open brace, or open paren in constructor", @@ -1096,7 +1100,7 @@ impl<'a> Parser<'a> { _ => { self.save(next.clone()); Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: next.span, token: next.token, expected: "some base expression or an open brace", @@ -1120,7 +1124,7 @@ impl<'a> Parser<'a> { match args.pop() { None => { return Err(ParserError::UnacceptableEof { - file_id: self.file_id, + file: self.file.clone(), place: "parsing function type or type", }); } @@ -1129,7 +1133,7 @@ impl<'a> Parser<'a> { Some(_) => { return Err(ParserError::UnacceptableEof { - file_id: self.file_id, + file: self.file.clone(), place: "looking for '->' in function type", }); } @@ -1147,7 +1151,7 @@ impl<'a> Parser<'a> { let LocatedToken { token, span } = maybe_arrow; Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span, token, expected: "'->' in function type", @@ -1193,7 +1197,7 @@ impl<'a> Parser<'a> { if !matches!(closer.token, Token::CloseParen) { return Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: closer.span, token: closer.token, expected: "close parenthesis to finish a type", @@ -1209,7 +1213,7 @@ impl<'a> Parser<'a> { }); Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span, token, expected: "type constructor, type variable, or primitive type", @@ -1239,7 +1243,7 @@ impl<'a> Parser<'a> { _ => { self.save(maybe_constant.clone()); Err(ParserError::UnexpectedToken { - file_id: self.file_id, + file: self.file.clone(), span: maybe_constant.span, token: maybe_constant.token, expected: "constant value", diff --git a/src/syntax/parser_tests.rs b/src/syntax/parser_tests.rs index 5960671..0e1bbd5 100644 --- a/src/syntax/parser_tests.rs +++ b/src/syntax/parser_tests.rs @@ -7,7 +7,7 @@ use crate::syntax::*; fn constants() { let parse_constant = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_constant() }; @@ -65,7 +65,7 @@ fn constants() { fn types() { let parse_type = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_type() }; @@ -123,7 +123,7 @@ fn types() { fn type_restrictions() { let parse_tr = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_type_restrictions() }; @@ -195,7 +195,7 @@ fn type_restrictions() { fn field_definition() { let parse_fd = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_field_definition() }; @@ -249,7 +249,7 @@ fn field_definition() { fn structures() { let parse_st = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_structure() }; @@ -325,7 +325,7 @@ fn structures() { fn enum_variant() { let parse_ev = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_enum_variant() }; @@ -382,7 +382,7 @@ fn enum_variant() { fn enumerations() { let parse_en = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_enumeration() }; @@ -418,7 +418,7 @@ fn enumerations() { fn expressions() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() }; @@ -451,7 +451,7 @@ fn expressions() { fn enumeration_values() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() }; @@ -472,7 +472,7 @@ fn enumeration_values() { fn structure_value() { let parse_st = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() }; @@ -521,7 +521,7 @@ fn structure_value() { fn infix_and_precedence() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.add_infix_precedence("+", parse::Associativity::Left, 6); result.add_infix_precedence("*", parse::Associativity::Right, 7); result.parse_expression() @@ -625,7 +625,7 @@ fn infix_and_precedence() { fn calls() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.add_infix_precedence("+", parse::Associativity::Left, 6); result.add_infix_precedence("*", parse::Associativity::Right, 7); result.parse_expression() @@ -766,7 +766,7 @@ fn calls() { fn prefix_and_postfix() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.add_infix_precedence("+", parse::Associativity::Left, 4); result.add_infix_precedence("*", parse::Associativity::Left, 8); result.add_prefix_precedence("++", 6); @@ -840,7 +840,7 @@ fn prefix_and_postfix() { fn blocks() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() }; @@ -879,7 +879,7 @@ fn blocks() { fn bindings() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() }; @@ -896,7 +896,7 @@ fn bindings() { fn conditionals() { let parse_ex = |str| { let lexer = Lexer::from(str); - let mut result = Parser::new(0, lexer); + let mut result = Parser::new("test", lexer); result.parse_expression() };