mirror of
https://github.com/HigherOrderCO/Bend.git
synced 2024-09-11 11:56:54 +03:00
Initial commit of hvm-lang with basic parser
This commit is contained in:
commit
c2eaa8502d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
12
.rustfmt.toml
Normal file
12
.rustfmt.toml
Normal file
@ -0,0 +1,12 @@
|
||||
edition = "2021"
|
||||
version = "Two"
|
||||
max_width = 110
|
||||
# won't add \r\n on windows machines, better on diffs
|
||||
newline_style = "Unix"
|
||||
use_small_heuristics = "Max"
|
||||
tab_spaces = 2
|
||||
imports_granularity = "Crate"
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
spaces_around_ranges = true
|
||||
overflow_delimited_expr = true
|
459
Cargo.lock
generated
Normal file
459
Cargo.lock
generated
Normal file
@ -0,0 +1,459 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "ariadne"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72fe02fc62033df9ba41cba57ee19acf5e742511a140c7dbc3a873e19a19a1bd"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.83"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chumsky"
|
||||
version = "1.0.0-alpha.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc3172a80699de358070dd99f80ea8badc6cdf8ac2417cb5a96e6d81bf5fe06d"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"stacker",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hvm-lang"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"ariadne",
|
||||
"chumsky",
|
||||
"clap",
|
||||
"logos",
|
||||
"shrinkwraprs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "logos"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1"
|
||||
dependencies = [
|
||||
"logos-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-codegen"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68"
|
||||
dependencies = [
|
||||
"beef",
|
||||
"fnv",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex-syntax",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-derive"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e"
|
||||
dependencies = [
|
||||
"logos-codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psm"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "shrinkwraprs"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63e6744142336dfb606fe2b068afa2e1cca1ee6a5d8377277a92945d81fa331"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"psm",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
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",
|
||||
]
|
||||
|
||||
[[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.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[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.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "hvm-lang"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.72"
|
||||
ariadne = "0.3.0"
|
||||
chumsky = "1.0.0-alpha.4"
|
||||
clap = {version = "4.4.1", features = ["derive"]}
|
||||
logos = "0.13.0"
|
||||
shrinkwraprs = "0.3.0"
|
34
justfile
Normal file
34
justfile
Normal file
@ -0,0 +1,34 @@
|
||||
# To use this, first run `cargo install just`
|
||||
# Then run the install subcommand: `just install`
|
||||
# Running `just` is equivalent to running `just all` because it's the first command
|
||||
|
||||
export CARGO_TERM_COLOR := "always"
|
||||
|
||||
all: rustup-show test clippy fmt sort audit
|
||||
|
||||
rustup-show:
|
||||
rustup show
|
||||
|
||||
test:
|
||||
cargo test --workspace
|
||||
|
||||
clippy:
|
||||
cargo clippy
|
||||
|
||||
fmt:
|
||||
cargo fmt --all -- --check
|
||||
|
||||
sort:
|
||||
cargo sort --check --workspace
|
||||
|
||||
audit:
|
||||
cargo audit
|
||||
|
||||
install:
|
||||
cargo install --locked cargo-sort cargo-audit
|
||||
|
||||
llcheck:
|
||||
cargo watch -x llcheck
|
||||
|
||||
extras:
|
||||
cargo install --locked cargo-watch cargo-limit amber
|
4
rust-toolchain.toml
Normal file
4
rust-toolchain.toml
Normal file
@ -0,0 +1,4 @@
|
||||
[toolchain]
|
||||
profile = "minimal"
|
||||
channel = "nightly-2023-07-10"
|
||||
components = ["rustfmt", "clippy"]
|
72
src/ast/mod.rs
Normal file
72
src/ast/mod.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use shrinkwraprs::Shrinkwrap;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct DefinitionBook {
|
||||
pub definitions: HashMap<Name, Definition>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Definition {
|
||||
pub name: Name,
|
||||
pub rules: Vec<Rule>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Rule {
|
||||
pub name: Name,
|
||||
pub pats: Vec<Pattern>,
|
||||
pub body: Term,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Pattern {
|
||||
Ctr(Name, Vec<Pattern>),
|
||||
Num(Number),
|
||||
Var(Name),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Term {
|
||||
Lam { name: Name, body: Box<Term> },
|
||||
Var { name: Name },
|
||||
App { func: Box<Term>, arg: Box<Term> },
|
||||
Dup { fst: Name, snd: Name, val: Box<Term>, next: Box<Term> },
|
||||
Def { name: Name },
|
||||
Num { val: Number },
|
||||
NumOp { op: NumOper, fst: Box<Term>, snd: Box<Term> },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Shrinkwrap, Hash)]
|
||||
pub struct Name(pub String);
|
||||
|
||||
// TODO: Accept other number types
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Shrinkwrap)]
|
||||
pub struct Number(pub u16);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum NumOper {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Mod,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Shl,
|
||||
Shr,
|
||||
Ltn,
|
||||
Lte,
|
||||
Gtn,
|
||||
Gte,
|
||||
Eql,
|
||||
Neq,
|
||||
}
|
||||
|
||||
impl DefinitionBook {
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
25
src/loader/mod.rs
Normal file
25
src/loader/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use crate::{ast::DefinitionBook, parser::parse_definition_book};
|
||||
use ariadne::{Color, Label, Report, ReportKind, Source};
|
||||
use std::path::Path;
|
||||
|
||||
/// Reads a file and parses to a definition book.
|
||||
pub fn load_file_to_book(path: &Path) -> anyhow::Result<DefinitionBook> {
|
||||
let code = std::fs::read_to_string(path)?;
|
||||
match parse_definition_book(&code) {
|
||||
Ok(book) => Ok(book),
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
Report::build(ReportKind::Error, (), err.span().start)
|
||||
.with_code(3)
|
||||
.with_message(err.to_string())
|
||||
.with_label(
|
||||
Label::new(err.span().into_range()).with_message(err.reason().to_string()).with_color(Color::Red),
|
||||
)
|
||||
.finish()
|
||||
.eprint(Source::from(code.clone()))
|
||||
.unwrap();
|
||||
}
|
||||
Err(anyhow::anyhow!("Parsing error"))
|
||||
}
|
||||
}
|
||||
}
|
22
src/main.rs
Normal file
22
src/main.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
mod ast;
|
||||
mod loader;
|
||||
mod parser;
|
||||
mod to_core;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Args {
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = Args::parse();
|
||||
let book = loader::load_file_to_book(&args.path)?;
|
||||
println!("{book:?}");
|
||||
// let compiled = to_core::book_to_hvm_core(book)?;
|
||||
// println!("{compiled}");
|
||||
Ok(())
|
||||
}
|
182
src/parser/lexer.rs
Normal file
182
src/parser/lexer.rs
Normal file
@ -0,0 +1,182 @@
|
||||
use logos::{FilterResult, Lexer, Logos};
|
||||
use std::fmt;
|
||||
|
||||
use crate::ast::Number;
|
||||
|
||||
#[derive(Logos, Debug, PartialEq, Clone)]
|
||||
#[logos(error=LexingError)]
|
||||
pub enum Token {
|
||||
#[regex("[_a-zA-Z][_a-zA-Z0-9]*", |lex| lex.slice().parse().ok())]
|
||||
Name(String),
|
||||
|
||||
#[regex(r"\\|λ")]
|
||||
Lambda,
|
||||
|
||||
#[token("let")]
|
||||
Let,
|
||||
|
||||
#[token("dup")]
|
||||
Dup,
|
||||
|
||||
#[token("=")]
|
||||
Equals,
|
||||
|
||||
#[regex("[0-9]+", |lex| lex.slice().parse().map(|x| Number(x)).ok())]
|
||||
Number(Number),
|
||||
|
||||
#[token("+")]
|
||||
Add,
|
||||
|
||||
#[token("-")]
|
||||
Sub,
|
||||
|
||||
#[token("*")]
|
||||
Mul,
|
||||
|
||||
#[token("/")]
|
||||
Div,
|
||||
|
||||
#[token("%")]
|
||||
Mod,
|
||||
|
||||
#[token("&")]
|
||||
And,
|
||||
|
||||
#[token("|")]
|
||||
Or,
|
||||
|
||||
#[token("^")]
|
||||
Xor,
|
||||
|
||||
#[token("<<")]
|
||||
Shl,
|
||||
|
||||
#[token(">>")]
|
||||
Shr,
|
||||
|
||||
#[token("<")]
|
||||
Ltn,
|
||||
|
||||
#[token("<=")]
|
||||
Lte,
|
||||
|
||||
#[token(">")]
|
||||
Gtn,
|
||||
|
||||
#[token(">=")]
|
||||
Gte,
|
||||
|
||||
#[token("==")]
|
||||
EqualsEquals,
|
||||
|
||||
#[token("!=")]
|
||||
NotEquals,
|
||||
|
||||
#[token(";")]
|
||||
Semicolon,
|
||||
|
||||
#[token("(")]
|
||||
LParen,
|
||||
|
||||
#[token(")")]
|
||||
RParen,
|
||||
|
||||
#[token("\n")]
|
||||
NewLine,
|
||||
|
||||
#[regex("//.*", logos::skip)]
|
||||
SingleLineComment,
|
||||
|
||||
#[token("/*", comment)]
|
||||
MultiLineComment,
|
||||
|
||||
#[regex(r"[ \t\f\r]+", logos::skip)]
|
||||
Whitespace,
|
||||
|
||||
Error(LexingError),
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Clone)]
|
||||
pub enum LexingError {
|
||||
UnclosedComment,
|
||||
|
||||
#[default]
|
||||
InvalidCharacter,
|
||||
}
|
||||
|
||||
// Lexer for nested multi-line comments
|
||||
#[derive(Logos)]
|
||||
pub enum MultiLineComment {
|
||||
#[token("/*")]
|
||||
Open,
|
||||
|
||||
#[token("*/")]
|
||||
Close,
|
||||
|
||||
#[regex("(?s).")]
|
||||
Other,
|
||||
}
|
||||
|
||||
fn comment(lexer: &mut Lexer<'_, Token>) -> FilterResult<(), LexingError> {
|
||||
let start = lexer.remainder();
|
||||
let mut comment = MultiLineComment::lexer(start);
|
||||
let mut depth = 1; // Already matched an Open token, so count it
|
||||
loop {
|
||||
if let Some(token) = comment.next() {
|
||||
match token {
|
||||
Ok(MultiLineComment::Open) => depth += 1,
|
||||
Ok(MultiLineComment::Close) => depth -= 1,
|
||||
Ok(MultiLineComment::Other) => {}
|
||||
Err(()) => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
// Unclosed comment
|
||||
return FilterResult::Error(LexingError::UnclosedComment);
|
||||
}
|
||||
if depth <= 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let end = comment.remainder();
|
||||
let span = (end as *const str as *const () as usize) - (start as *const str as *const () as usize);
|
||||
lexer.bump(span);
|
||||
FilterResult::Skip
|
||||
}
|
||||
|
||||
impl fmt::Display for Token {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Name(s) => write!(f, "{}", s),
|
||||
Self::Lambda => write!(f, r"λ"),
|
||||
Self::Let => write!(f, "let"),
|
||||
Self::Dup => write!(f, "dup"),
|
||||
Self::Equals => write!(f, "="),
|
||||
Self::Number(num) => write!(f, "{}", num.as_ref()),
|
||||
Self::Add => write!(f, "+"),
|
||||
Self::Sub => write!(f, "-"),
|
||||
Self::Mul => write!(f, "*"),
|
||||
Self::Div => write!(f, "/"),
|
||||
Self::Mod => write!(f, "%"),
|
||||
Self::And => write!(f, "&"),
|
||||
Self::Or => write!(f, "|"),
|
||||
Self::Xor => write!(f, "^"),
|
||||
Self::Shl => write!(f, "<<"),
|
||||
Self::Shr => write!(f, ">>"),
|
||||
Self::Ltn => write!(f, "<"),
|
||||
Self::Lte => write!(f, "<="),
|
||||
Self::Gtn => write!(f, ">"),
|
||||
Self::Gte => write!(f, ">="),
|
||||
Self::NotEquals => write!(f, "!="),
|
||||
Self::EqualsEquals => write!(f, "=="),
|
||||
Self::Semicolon => write!(f, ";"),
|
||||
Self::LParen => write!(f, "("),
|
||||
Self::RParen => write!(f, ")"),
|
||||
Self::NewLine => write!(f, "<NewLine>"),
|
||||
Self::SingleLineComment => write!(f, "<SingleLineComment>"),
|
||||
Self::MultiLineComment => write!(f, "<MultiLineComment>"),
|
||||
Self::Whitespace => write!(f, "<Whitespace>"),
|
||||
Self::Error(LexingError::InvalidCharacter) => write!(f, "<InvalidCharacter>"),
|
||||
Self::Error(LexingError::UnclosedComment) => write!(f, "<UnclosedComment>"),
|
||||
}
|
||||
}
|
||||
}
|
4
src/parser/mod.rs
Normal file
4
src/parser/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod lexer;
|
||||
mod parser;
|
||||
|
||||
pub use parser::parse_definition_book;
|
170
src/parser/parser.rs
Normal file
170
src/parser/parser.rs
Normal file
@ -0,0 +1,170 @@
|
||||
use crate::{
|
||||
ast::{Definition, DefinitionBook, Name, NumOper, Rule, Term},
|
||||
parser::lexer::Token,
|
||||
};
|
||||
use chumsky::{
|
||||
extra,
|
||||
input::{Emitter, Stream, ValueInput},
|
||||
prelude::{Input, Rich},
|
||||
primitive::{choice, just},
|
||||
recursive::recursive,
|
||||
select,
|
||||
span::SimpleSpan,
|
||||
IterParser, Parser,
|
||||
};
|
||||
use logos::Logos;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn parse_definition_book(code: &str) -> Result<DefinitionBook, Vec<Rich<Token>>> {
|
||||
let token_iter = Token::lexer(code).spanned().map(|(token, span)| match token {
|
||||
Ok(t) => (t, SimpleSpan::from(span).into()),
|
||||
Err(e) => (Token::Error(e), SimpleSpan::from(span).into()),
|
||||
});
|
||||
let token_stream = Stream::from_iter(token_iter).spanned(SimpleSpan::from(code.len() .. code.len()).into());
|
||||
book_parser().parse(token_stream).into_result()
|
||||
}
|
||||
|
||||
// TODO: Pattern matching on rules
|
||||
// TODO: Other types of numbers
|
||||
/// <Name> ::= <name_token> // [_a-zA-Z][_a-zA-Z0-9]*
|
||||
/// <Number> ::= <number_token> // [0-9]+
|
||||
/// <Var> ::= <Name>
|
||||
/// <Nested> ::= "(" <newline_token>* <Term> <newline_token>* ")"
|
||||
/// <Item> ::= <Var> | <Number> | <Nested>
|
||||
/// <App> ::= <Item> <Item>+
|
||||
/// <Lam> ::= ("λ"|"\") <Name> <Term>
|
||||
/// <Dup> ::= "dup" <Name> <Name> "=" <Term> ";" <Term>
|
||||
/// <Let> ::= "let" <Name> "=" <Term> ";" <Term>
|
||||
/// <NumOp> ::= <numop_token> <Item> <Item>
|
||||
/// <Term> ::= <Lam> | <App> | <Dup> | <Let> | <NumOp> | <Item>
|
||||
/// <Rule> ::= "(" <Name> ")" "=" <newline_token>* <Term> <newline_token>*
|
||||
/// <Def> ::= (<Rule> <NewLine>)+
|
||||
/// <Book> ::= <Def>+
|
||||
|
||||
fn rule_parser<'a, I>() -> impl Parser<'a, I, Rule, extra::Err<Rich<'a, Token>>>
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
let new_line = just(Token::NewLine).repeated();
|
||||
let name = select!(Token::Name(name) => Name(name.to_string()));
|
||||
let number = select!(Token::Number(num) => Term::Num{val: num});
|
||||
|
||||
let num_oper = select! {
|
||||
Token::Add => NumOper::Add,
|
||||
Token::Sub => NumOper::Sub,
|
||||
Token::Mul => NumOper::Mul,
|
||||
Token::Div => NumOper::Div,
|
||||
Token::Mod => NumOper::Mod,
|
||||
Token::And => NumOper::And,
|
||||
Token::Or => NumOper::Or,
|
||||
Token::Xor => NumOper::Xor,
|
||||
Token::Shl => NumOper::Shl,
|
||||
Token::Shr => NumOper::Shr,
|
||||
Token::Lte => NumOper::Lte,
|
||||
Token::Ltn => NumOper::Ltn,
|
||||
Token::Gte => NumOper::Gte,
|
||||
Token::Gtn => NumOper::Gtn,
|
||||
Token::EqualsEquals => NumOper::Eql,
|
||||
Token::NotEquals => NumOper::Neq,
|
||||
};
|
||||
|
||||
let var = name.map(|name| Term::Var { name });
|
||||
|
||||
let term = recursive(|term| {
|
||||
let nested = term
|
||||
.clone()
|
||||
.delimited_by(just(Token::LParen).then(new_line.clone()), just(Token::RParen).then(new_line.clone()));
|
||||
|
||||
let item = choice((var, number, nested));
|
||||
|
||||
let app = item
|
||||
.clone()
|
||||
.foldl(item.clone().repeated(), |fun, arg| Term::App { func: Box::new(fun), arg: Box::new(arg) });
|
||||
|
||||
let lam = just(Token::Lambda)
|
||||
.ignore_then(name)
|
||||
.then(term.clone())
|
||||
.map(|(name, body)| Term::Lam { name, body: Box::new(body) });
|
||||
|
||||
let dup = just(Token::Dup)
|
||||
.ignore_then(name)
|
||||
.then(name)
|
||||
.then_ignore(just(Token::Equals))
|
||||
.then(term.clone())
|
||||
.then_ignore(just(Token::Semicolon))
|
||||
.then(term.clone())
|
||||
.map(|(((fst, snd), val), next)| Term::Dup { fst, snd, val: Box::new(val), next: Box::new(next) });
|
||||
|
||||
let let_ = just(Token::Let)
|
||||
.ignore_then(name)
|
||||
.then_ignore(just(Token::Equals))
|
||||
.then(term.clone())
|
||||
.then_ignore(just(Token::Semicolon))
|
||||
.then(term.clone())
|
||||
.map(|((name, body), next)| Term::App {
|
||||
func: Box::new(Term::Lam { name, body: next.into() }),
|
||||
arg: Box::new(body),
|
||||
});
|
||||
|
||||
let num_op = num_oper.then(item.clone()).then(item.clone()).map(|((op, fst), snd)| Term::NumOp {
|
||||
op,
|
||||
fst: Box::new(fst),
|
||||
snd: Box::new(snd),
|
||||
});
|
||||
|
||||
choice((lam, app, dup, let_, num_op, item))
|
||||
});
|
||||
|
||||
just(Token::LParen)
|
||||
.ignore_then(name)
|
||||
.then_ignore(just(Token::RParen))
|
||||
.then_ignore(just(Token::Equals))
|
||||
.then(term.delimited_by(new_line.clone(), new_line.clone()))
|
||||
.map(|(name, body)| Rule { name, pats: vec![], body })
|
||||
}
|
||||
|
||||
fn book_parser<'a, I>() -> impl Parser<'a, I, DefinitionBook, extra::Err<Rich<'a, Token>>>
|
||||
where
|
||||
I: ValueInput<'a, Token = Token, Span = SimpleSpan>,
|
||||
{
|
||||
fn rules_to_book(
|
||||
rules: Vec<(Rule, SimpleSpan)>,
|
||||
_span: SimpleSpan,
|
||||
emitter: &mut Emitter<Rich<Token>>,
|
||||
) -> DefinitionBook {
|
||||
let mut book = DefinitionBook::new();
|
||||
let mut crnt_def: Option<(Definition, SimpleSpan)> = None;
|
||||
// Check for repeated defs (could be rules out of order or actually repeated names)
|
||||
for (rule, rule_span) in rules {
|
||||
if let Some((crnt_def, def_span)) = crnt_def.as_mut() {
|
||||
if rule.name == crnt_def.name {
|
||||
crnt_def.rules.push(rule);
|
||||
def_span.end = rule_span.end;
|
||||
} else {
|
||||
let def = std::mem::replace(crnt_def, Definition { name: rule.name, rules: vec![] });
|
||||
add_to_def_book(&mut book, def, *def_span, emitter);
|
||||
}
|
||||
} else {
|
||||
crnt_def = Some((Definition { name: rule.name, rules: vec![] }, rule_span));
|
||||
}
|
||||
}
|
||||
if let Some((def, span)) = crnt_def {
|
||||
add_to_def_book(&mut book, def, span, emitter);
|
||||
}
|
||||
book
|
||||
}
|
||||
|
||||
fn add_to_def_book(book: &mut DefinitionBook, def: Definition, span: SimpleSpan, emitter: &mut Emitter<Rich<Token>>) {
|
||||
if book.definitions.contains_key(&def.name) {
|
||||
emitter.emit(Rich::custom(span, format!("Repeated definition '{}'", def.name.as_ref())));
|
||||
} else {
|
||||
book.definitions.insert(def.name.clone(), def);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let parsed_rules =
|
||||
rule_parser().map_with_span(|rule, span| (rule, span)).repeated().collect::<Vec<(Rule, SimpleSpan)>>();
|
||||
|
||||
parsed_rules.validate(move |rules, span, emitter| rules_to_book(rules, span, emitter))
|
||||
}
|
5
src/to_core/mod.rs
Normal file
5
src/to_core/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use crate::ast::DefinitionBook;
|
||||
|
||||
pub fn book_to_hvm_core(book: DefinitionBook) -> anyhow::Result<String> {
|
||||
todo!()
|
||||
}
|
Loading…
Reference in New Issue
Block a user