v2
This commit is contained in:
parent
2d374d5d9d
commit
ca14802a21
26
.github/workflows/rust.yml
vendored
26
.github/workflows/rust.yml
vendored
|
@ -1,26 +0,0 @@
|
||||||
name: Rust
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Build
|
|
||||||
run: cargo build --release --verbose
|
|
||||||
- name: Run cargo tests
|
|
||||||
run: cargo test --release --verbose
|
|
||||||
- name: Run lang tests
|
|
||||||
run: ./target/release/mcl_test_dev -m test
|
|
||||||
- name: Check formatting with clippy
|
|
||||||
run: cargo clippy -- -W clippy::pedantic -A clippy::struct-excessive-bools -A clippy::too_many_lines -A clippy::similar_names
|
|
15
.gitignore
vendored
15
.gitignore
vendored
|
@ -1,6 +1,9 @@
|
||||||
/target
|
/*
|
||||||
/a
|
!/.vscode
|
||||||
|
!/.gitignore
|
||||||
test
|
!/.gitkeep
|
||||||
test.nasm
|
!/src
|
||||||
test.o
|
!/include
|
||||||
|
!/Cargo*
|
||||||
|
!/REF.md
|
||||||
|
!/*.mcl
|
11
.vscode/extensions.json
vendored
Normal file
11
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"aaron-bond.better-comments",
|
||||||
|
"usernamehw.errorlens",
|
||||||
|
"tamasfe.even-better-toml",
|
||||||
|
"platformio.platformio-ide",
|
||||||
|
"1YiB.rust-bundle",
|
||||||
|
"tamasfe.even-better-toml",
|
||||||
|
"ms-vscode.cpptools"
|
||||||
|
]
|
||||||
|
}
|
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug executable 'mclangc-v2'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=mclangc-v2",
|
||||||
|
"--package=mclangc-v2"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "mclangc-v2",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": ["-o", "test", "test.mcl", "-r"],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug unit tests in executable 'mclangc-v2'",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"test",
|
||||||
|
"--no-run",
|
||||||
|
"--bin=mclangc-v2",
|
||||||
|
"--package=mclangc-v2"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "mclangc-v2",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"*.s": "platformio-debug.asm"
|
||||||
|
}
|
||||||
|
}
|
490
Cargo.lock
generated
490
Cargo.lock
generated
|
@ -3,76 +3,106 @@
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "anstream"
|
||||||
version = "0.19.0"
|
version = "0.6.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gimli",
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "anstyle"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "anstyle-wincon"
|
||||||
version = "0.3.67"
|
version = "3.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"anstyle",
|
||||||
"cc",
|
"windows-sys",
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anyhow"
|
||||||
|
version = "1.0.80"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "2.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "camino"
|
||||||
version = "1.0.79"
|
version = "1.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.1.8"
|
version = "4.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
|
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
"is-terminal",
|
|
||||||
"once_cell",
|
|
||||||
"strsim",
|
"strsim",
|
||||||
"termcolor",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.1.8"
|
version = "4.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
|
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn",
|
"syn",
|
||||||
|
@ -80,76 +110,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.3.2"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
|
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
dependencies = [
|
|
||||||
"os_str_bytes",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "color-eyre"
|
name = "colorchoice"
|
||||||
version = "0.6.2"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"color-spantrace",
|
|
||||||
"eyre",
|
|
||||||
"indenter",
|
|
||||||
"once_cell",
|
|
||||||
"owo-colors",
|
|
||||||
"tracing-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "color-spantrace"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"owo-colors",
|
|
||||||
"tracing-core",
|
|
||||||
"tracing-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "eyre"
|
|
||||||
version = "0.6.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
|
||||||
dependencies = [
|
|
||||||
"indenter",
|
|
||||||
"once_cell",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.27.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
@ -157,40 +126,6 @@ version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indenter"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "io-lifetimes"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cfa919a82ea574332e2de6e74b4c36e74d41982b335080fa59d4ef31be20fdf3"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is-terminal"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"io-lifetimes",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -198,156 +133,83 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "map-macro"
|
||||||
version = "0.2.140"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
|
checksum = "fb950a42259642e5a3483115aca87eebed2a64886993463af9c9739c205b8d3a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "mclangc"
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mclang"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bitflags",
|
||||||
|
"camino",
|
||||||
"clap",
|
"clap",
|
||||||
"color-eyre",
|
"clap_derive",
|
||||||
"eyre",
|
"lazy_static",
|
||||||
|
"map-macro",
|
||||||
|
"parse_int",
|
||||||
|
"snailquote",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "num-traits"
|
||||||
version = "2.5.0"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "parse_int"
|
||||||
version = "0.30.3"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
|
checksum = "2d695b79916a2c08bcff7be7647ab60d1402885265005a6658ffe6d763553c5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"num-traits",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "once_cell"
|
|
||||||
version = "1.17.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_str_bytes"
|
|
||||||
version = "6.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "owo-colors"
|
|
||||||
version = "3.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pin-project-lite"
|
|
||||||
version = "0.2.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro-error-attr",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"version_check",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "proc-macro-error-attr"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"version_check",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.51"
|
version = "1.0.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.23"
|
version = "1.0.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "snailquote"
|
||||||
version = "0.1.21"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
checksum = "ec62a949bda7f15800481a711909f946e1204f2460f89210eaf7f57730f88f86"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.36.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fd5c6ff11fecd55b40746d1995a02f2eb375bf8c00d192d521ee09f42bef37bc"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"thiserror",
|
||||||
"errno",
|
"unicode_categories",
|
||||||
"io-lifetimes",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sharded-slab"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.10.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "2.0.52"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -355,129 +217,57 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "thiserror"
|
||||||
version = "1.2.0"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thiserror-impl"
|
||||||
version = "1.1.7"
|
version = "1.0.58"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"proc-macro2",
|
||||||
"once_cell",
|
"quote",
|
||||||
]
|
"syn",
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing"
|
|
||||||
version = "0.1.37"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-core"
|
|
||||||
version = "0.1.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"valuable",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-error"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
|
||||||
dependencies = [
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tracing-subscriber"
|
|
||||||
version = "0.3.16"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
|
||||||
dependencies = [
|
|
||||||
"sharded-slab",
|
|
||||||
"thread_local",
|
|
||||||
"tracing-core",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.8"
|
version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "unicode_categories"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "utf8parse"
|
||||||
version = "0.9.4"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[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-util"
|
|
||||||
version = "0.1.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[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]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc",
|
||||||
|
@ -490,42 +280,42 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.1"
|
version = "0.52.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||||
|
|
15
Cargo.toml
15
Cargo.toml
|
@ -2,9 +2,18 @@
|
||||||
name = "mclangc"
|
name = "mclangc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.1.8", features = ["derive"] }
|
anyhow = "1.0.80"
|
||||||
color-eyre = "0.6.2"
|
bitflags = "2.4.2"
|
||||||
eyre = "0.6.8"
|
camino = "1.1.6"
|
||||||
|
clap = { version = "4.5.2", features = ["derive"] }
|
||||||
|
clap_derive = "4.5.0"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
map-macro = "0.3.0"
|
||||||
|
parse_int = "0.6.0"
|
||||||
|
# serde = { version = "1.0.197", features = ["derive"] }
|
||||||
|
# regex = "1.10.3"
|
||||||
|
snailquote = "0.3.1"
|
||||||
|
|
23
README.md
23
README.md
|
@ -1,23 +0,0 @@
|
||||||
# mclang rev2
|
|
||||||
|
|
||||||
This is the second revision of [MCLang](https://github.com/mc-lang/mclang) now written in rust!
|
|
||||||
|
|
||||||
## Goals
|
|
||||||
|
|
||||||
✅ - relatevely usable by normal programmers
|
|
||||||
✅ - speed comparable to unoptimised C (sometimes)
|
|
||||||
✅ - static typing
|
|
||||||
❌ - self hosted (maybe better if not? Since rust is fast asf)
|
|
||||||
❌ - multiplatform (~~windows~~, linux and mac)
|
|
||||||
✅ - interop with other languages
|
|
||||||
❌ - package manager
|
|
||||||
❌ - installer
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
The docs are currently are just made in MarkDown.
|
|
||||||
You can find the docs [here](/docs/index.md)
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
[MCotange](https://github.com/MCorange99) - The one and only me, the creator and current maintainer or mclang rev1 and rev2
|
|
53
REF.md
Normal file
53
REF.md
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
# Reference
|
||||||
|
|
||||||
|
```mclang
|
||||||
|
typedef str do int ptr end // [int, ptr]
|
||||||
|
|
||||||
|
include "std.mcl"
|
||||||
|
|
||||||
|
const sizeof(u8) 1 end
|
||||||
|
const sizeof(u16) 2 end
|
||||||
|
const sizeof(u32) 4 end
|
||||||
|
const sizeof(u64) 8 end
|
||||||
|
|
||||||
|
structdef Foo do
|
||||||
|
buz do sizeof(u64) end
|
||||||
|
baz do sizeof(u64) end
|
||||||
|
done
|
||||||
|
|
||||||
|
memory s_foo Foo end
|
||||||
|
|
||||||
|
//? Comments :3
|
||||||
|
|
||||||
|
extern fn a with void returns void then done
|
||||||
|
inline fn b with void returns void then done
|
||||||
|
export fn c with void returns void then done
|
||||||
|
|
||||||
|
fn puts with str returns void then drop drop done
|
||||||
|
// fn putd with int returns void then drop done
|
||||||
|
|
||||||
|
fn main with int ptr returns int then
|
||||||
|
// 1 2 add
|
||||||
|
69 _dbg_print
|
||||||
|
"Hewo" puts
|
||||||
|
|
||||||
|
if 3 4 eq do
|
||||||
|
"omg what impossible!\n"
|
||||||
|
else if 1 1 eq do
|
||||||
|
"whaaaaaaaaa\n"
|
||||||
|
else
|
||||||
|
"finally, some good soup\n"
|
||||||
|
done
|
||||||
|
puts
|
||||||
|
|
||||||
|
10
|
||||||
|
while dup 0 gt do
|
||||||
|
"uwu" puts
|
||||||
|
dup _dbg_print
|
||||||
|
1
|
||||||
|
done
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
```
|
2
editor/vscode/.gitignore
vendored
2
editor/vscode/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
**/*.log
|
|
||||||
**/node_modules/
|
|
17
editor/vscode/.vscode/launch.json
vendored
17
editor/vscode/.vscode/launch.json
vendored
|
@ -1,17 +0,0 @@
|
||||||
// A launch configuration that launches the extension inside a new window
|
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
{
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"name": "Extension",
|
|
||||||
"type": "extensionHost",
|
|
||||||
"request": "launch",
|
|
||||||
"args": [
|
|
||||||
"--extensionDevelopmentPath=${workspaceFolder}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
.vscode/**
|
|
||||||
.vscode-test/**
|
|
||||||
.gitignore
|
|
||||||
vsc-extension-quickstart.md
|
|
|
@ -1,9 +0,0 @@
|
||||||
# Change Log
|
|
||||||
|
|
||||||
All notable changes to the "mclang" extension will be documented in this file.
|
|
||||||
|
|
||||||
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
|
|
||||||
|
|
||||||
## [Unreleased]
|
|
||||||
|
|
||||||
- Initial release
|
|
|
@ -1,17 +0,0 @@
|
||||||
# mclang README
|
|
||||||
|
|
||||||
Code highlghting for mclang 1 and 2
|
|
||||||
|
|
||||||
## Known Issues
|
|
||||||
|
|
||||||
None
|
|
||||||
|
|
||||||
## Release Notes
|
|
||||||
|
|
||||||
Users appreciate release notes as you update your extension.
|
|
||||||
|
|
||||||
### 1.0.0
|
|
||||||
|
|
||||||
Initial release of mclang
|
|
||||||
|
|
||||||
**Enjoy!**
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"comments": {
|
|
||||||
// symbol used for single line comment. Remove this entry if your language does not support line comments
|
|
||||||
"lineComment": "//",
|
|
||||||
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
|
|
||||||
"blockComment": [ "/*", "*/" ]
|
|
||||||
},
|
|
||||||
// symbols used as brackets
|
|
||||||
"brackets": [
|
|
||||||
["{", "}"],
|
|
||||||
["[", "]"],
|
|
||||||
["(", ")"]
|
|
||||||
],
|
|
||||||
// symbols that are auto closed when typing
|
|
||||||
"autoClosingPairs": [
|
|
||||||
["{", "}"],
|
|
||||||
["[", "]"],
|
|
||||||
["(", ")"],
|
|
||||||
["\"", "\""],
|
|
||||||
["'", "'"]
|
|
||||||
],
|
|
||||||
// symbols that can be used to surround a selection
|
|
||||||
"surroundingPairs": [
|
|
||||||
["{", "}"],
|
|
||||||
["[", "]"],
|
|
||||||
["(", ")"],
|
|
||||||
["\"", "\""],
|
|
||||||
["'", "'"]
|
|
||||||
]
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,42 +0,0 @@
|
||||||
{
|
|
||||||
"name": "mclang",
|
|
||||||
"displayName": "mclang",
|
|
||||||
"description": "Code highlighting for mclang",
|
|
||||||
"version": "0.0.3",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git@github.com:mc-lang/mclang2.git"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"vscode": "^1.54.0"
|
|
||||||
},
|
|
||||||
"categories": [
|
|
||||||
"Programming Languages"
|
|
||||||
],
|
|
||||||
"contributes": {
|
|
||||||
"languages": [
|
|
||||||
{
|
|
||||||
"id": "mclang",
|
|
||||||
"aliases": [
|
|
||||||
"MCLang",
|
|
||||||
"mclang"
|
|
||||||
],
|
|
||||||
"extensions": [
|
|
||||||
".mcl"
|
|
||||||
],
|
|
||||||
"configuration": "./language-configuration.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"grammars": [
|
|
||||||
{
|
|
||||||
"language": "mclang",
|
|
||||||
"scopeName": "source.mcl",
|
|
||||||
"path": "./syntaxes/mclang.tmLanguage.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"generator-code": "^1.7.4",
|
|
||||||
"@vscode/vsce": "^2.15.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,147 +0,0 @@
|
||||||
{
|
|
||||||
"name": "MCLang",
|
|
||||||
"fileTypes": [
|
|
||||||
"mcl"
|
|
||||||
],
|
|
||||||
"scopeName": "source.mcl",
|
|
||||||
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"include": "#errors"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#keywords"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#definitions"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#placeholders"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#strings"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#comments"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#intrinsics"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"include": "#constants-and-special-vars"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"repository": {
|
|
||||||
"errors": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "invalid.illegal",
|
|
||||||
"match": "(?<=^|\\s)(?:const|memory)\\s+(end)(?:$|\\s)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "invalid.illegal",
|
|
||||||
"match": "(?<=^|\\s)(?:fn)\\s+(done)(?:$|\\s)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "invalid.illegal",
|
|
||||||
"match": "(?<=^|\\s)(memory|const)\\s+\\S*(\\s+|$)end(?:\n|\\s)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "invalid.illegal",
|
|
||||||
"match": "(?<=^|\\s)(inline)\\s+(?!fn(\\s|$))"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"keywords": {
|
|
||||||
"patterns": [
|
|
||||||
|
|
||||||
{
|
|
||||||
"name": "keyword.declaration.mclang",
|
|
||||||
"match": "(?<=\\s|^)(macro|memory|fn|const|in|inline|include|assert|offset|addr-of|call-like|reset|let|peek|with|returns)(?:\\s|$)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "keyword.control.mclang",
|
|
||||||
"match": "(?<=\\s|^)(if|else|elif|end|done|then|while|do|if\\*)(?:\\s|$)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"definitions": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "support.class.mclang",
|
|
||||||
"match": "(?<=(macro|memory|fn|const)\\s+)(\\S*)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "support.class.mclang",
|
|
||||||
"match": "(?<=(let|peek)\\s+)\\S+.*(?=\\s+(in))"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"placeholders": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "markup.italic.mclang",
|
|
||||||
"match": "(?<=(\\s|^))_[\\S]*_(?:(\\s|$))"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"strings": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "string.quoted.double.mclang",
|
|
||||||
"begin": "\"",
|
|
||||||
"end": "\"",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "constant.character.escape.mclang",
|
|
||||||
"match": "\\\\."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "string.quoted.single.mclang",
|
|
||||||
"begin": "'",
|
|
||||||
"end": "'",
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "constant.character.escape.mclang",
|
|
||||||
"match": "\\\\."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"comments": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "constant.other.character-class.regexp",
|
|
||||||
"match": "(?://\\s*)(TODO(O*)|FIXME).*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "comment.line.double-slash.mclang",
|
|
||||||
"match": "(//(?!\\s?(TODO(O*)|FIXME)(\\s|:|$)).*|//\\s*)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"intrinsics": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "variable.name.source.mclang",
|
|
||||||
"match": "(?<=^|\\s)(\\+|-|\\*|int|ptr|bool|addr|any|void|max|divmod|_dbg_print|=|>|<|>=|<=|!=|>>|<<|\\||&|not|dup|swap|drop|over|rot|argc|argv|here|syscall0|syscall1|syscall2|syscall3|syscall4|syscall5|syscall6|\\?\\?\\?)(?=>$|\\s)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"constants-and-special-vars": {
|
|
||||||
"patterns": [
|
|
||||||
{
|
|
||||||
"name": "constant.numeric.mclang",
|
|
||||||
"match": "\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)\\b(?!\\$)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "entity.name.function.mclang",
|
|
||||||
"match": "(?<=^|\\s)(NULL|true|false|cast(ptr)|cast(int)|cast(bool)|sizeof\\(u64\\)|sizeof\\(u32\\)|sizeof\\(ptr\\)|sizeof\\(bool\\)|sizeof\\(int\\)|sizeof\\(addr\\)|STDIN|STDOUT|STDERR|@ptr|@@ptr|@bool|@int|@addr|!bool|!ptr|!int|!addr|AT_FDCWD|O_RDONLY|O_WRONLY|O_RDWR|O_CREAT|O_TRUNC|O_NONBLOCK|F_SETFL|F_GETFL|EAGAIN|CLOCK_MONOTONIC|TIMER_ABSTIME|MAP_PRIVATE|MAP_ANONYMOUS|PROT_READ|PROT_WRITE|SIGQUIT|timespec\\.tv_sec|timespec\\.tv_nsec|sizeof\\(timespec\\)|ptr\\+|ptr-|ptr!=|ptr=|ptr<|\\+ptr|ptr-diff|sizeof\\(stat\\)|stat\\.st_dev|stat\\.st_ino|stat\\.st_mode|stat\\.st_nlink|stat\\.st_uid|stat\\.st_gid|stat\\.st_rdev|stat\\.st_size|@stat\\.st_size|stat\\.st_blksize|stat\\.st_blocks|stat\\.st_atim|stat\\.st_mtim|stat\\.st_ctim|sizeof\\(stat\\.st_dev\\)|sizeof\\(stat\\.st_ino\\)|sizeof\\(stat\\.st_mode\\)|sizeof\\(stat\\.st_nlink\\)|sizeof\\(stat\\.st_uid\\)|sizeof\\(stat\\.st_gid\\)|sizeof\\(stat\\.st_rdev\\)|sizeof\\(stat\\.st_size\\)|sizeof\\(stat\\.st_blksize\\)|sizeof\\(stat\\.st_blocks\\)|sizeof\\(stat\\.st_atim\\)|sizeof\\(stat\\.st_mtim\\)|sizeof\\(stat\\.st_ctim\\)|write|read|openat|fstat|stat|close|exit|mmap|clock_nanosleep|clock_gettime|fork|getpid|execve|wait4|rename|fcntl|kill|dup2|/|%|mod|div|imod|idiv|emod|nth_argv|lnot|land|lor|inc64-by|inc64|dec64|inc32|dec32|inc8|dec8|swap64|cstrlen|cstreq|cstr-to-str|fputs|puts|eputs|WIFSTOPPED|WIFCONTINUED|WIFSIGNALED|WTERMSIG|WIFEXITED|WEXITSTATUS|offsetof\\(Str\\.count\\)|offsetof\\(Str\\.data\\)|sizeof\\(Str\\)|Str\\.count|Str\\.data|@Str\\.count|@Str\\.data|!Str\\.count|!Str\\.data|@Str|!Str|str-chop-one-left|str-chop-one-right|\\?space|str-trim-left|str-chop-by-predicate|str-chop-by-delim|str-starts-with|\\?str-empty|streq|\\?digit|isdigit|\\?alpha|isalpha|\\?alnum|isalnum|try-parse-int|PUTU_BUFFER_CAP|fputu|fput0u|putu|put0u|eputu|memcpy|memset|srand|RAND_A|RAND_C|rand|getenv|TMP_CAP|tmp-clean|tmp-end|tmp-rewind|tmp-alloc|tmp-str-to-cstr|tmp-append|tmp-append-ptr|execvp|append-item|tmp-utos|map-file|\\?file-exist|\\?shell-safe-char|\\?shell-safe-str|shell-escape|timeit/from-here|1e9|timeit/to-here|str-rfind|dirname|putch|remove-ext|cmd-echoed)(?:\\s|$)"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Welcome to your VS Code Extension
|
|
||||||
|
|
||||||
## What's in the folder
|
|
||||||
|
|
||||||
* This folder contains all of the files necessary for your extension.
|
|
||||||
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
|
|
||||||
* `syntaxes/mclang.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
|
|
||||||
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
|
|
||||||
|
|
||||||
## Get up and running straight away
|
|
||||||
|
|
||||||
* Make sure the language configuration settings in `language-configuration.json` are accurate.
|
|
||||||
* Press `F5` to open a new window with your extension loaded.
|
|
||||||
* Create a new file with a file name suffix matching your language.
|
|
||||||
* Verify that syntax highlighting works and that the language configuration settings are working.
|
|
||||||
|
|
||||||
## Make changes
|
|
||||||
|
|
||||||
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
|
|
||||||
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
|
|
||||||
|
|
||||||
## Add more language features
|
|
||||||
|
|
||||||
* To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
|
|
||||||
|
|
||||||
## Install your extension
|
|
||||||
|
|
||||||
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
|
|
||||||
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +0,0 @@
|
||||||
include "std.mcl"
|
|
||||||
|
|
||||||
"Henlo World! :3\n" puts
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
include "std.mcl"
|
|
||||||
|
|
||||||
macro BOARD_SIZE 100 end
|
|
||||||
|
|
||||||
mem BOARD_SIZE 2 - + 1 @8
|
|
||||||
|
|
||||||
0 while dup BOARD_SIZE 2 - < do
|
|
||||||
0 while dup BOARD_SIZE < do
|
|
||||||
dup mem + !8 if
|
|
||||||
dup mem + BOARD_SIZE + '*' @8
|
|
||||||
else
|
|
||||||
dup mem + BOARD_SIZE + ' ' @8
|
|
||||||
end
|
|
||||||
1 +
|
|
||||||
end
|
|
||||||
|
|
||||||
mem + BOARD_SIZE + '\n' @8
|
|
||||||
|
|
||||||
BOARD_SIZE 1 + mem BOARD_SIZE + puts
|
|
||||||
|
|
||||||
// pattern
|
|
||||||
mem !8 1 shl
|
|
||||||
mem 1 + !8
|
|
||||||
bor
|
|
||||||
|
|
||||||
1 while dup BOARD_SIZE 2 - < do
|
|
||||||
swap 1 shl 7 band
|
|
||||||
over mem + 1 + !8 bor
|
|
||||||
2dup 110 swap shr 1 band
|
|
||||||
swap mem + swap @8
|
|
||||||
swap
|
|
||||||
|
|
||||||
1 +
|
|
||||||
end
|
|
||||||
drop drop
|
|
||||||
|
|
||||||
1 +
|
|
||||||
end
|
|
||||||
drop
|
|
|
@ -1,5 +0,0 @@
|
||||||
|
|
||||||
0 while dup 100 < do
|
|
||||||
dup print
|
|
||||||
1 +
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
// todo: add some sort of macrow
|
|
|
@ -1,18 +0,0 @@
|
||||||
const FS_O_APPEND 1024 end // append to existing file
|
|
||||||
const FS_O_ASYNC 8192 end // use signal-driven IO
|
|
||||||
const FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions)
|
|
||||||
const FS_O_CREAT 64 end // create file if it doesn’t exist
|
|
||||||
const FS_O_DIRECT 16384 end // bypass cache (slower)
|
|
||||||
const FS_O_DIRECTORY 65536 end // fail if pathname isn’t a directory
|
|
||||||
const FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return
|
|
||||||
const FS_O_EXCL 128 end // ensure creation of file
|
|
||||||
const FS_O_LARGEFILE 0 end // allows use of file sizes represented by off64_t
|
|
||||||
const FS_O_NOATIME 262144 end // do not increment access time upon open
|
|
||||||
const FS_O_NOCTTY 256 end // if pathname is a terminal device, don’t become controlling terminal
|
|
||||||
const FS_O_NOFOLLOW 131072 end // fail if pathname is symbolic link
|
|
||||||
const FS_O_NONBLOCK 2048 end // if possible, open file with non-blocking IO
|
|
||||||
const FS_O_NDELAY 2048 end // same as O_NONBLOCK
|
|
||||||
const FS_O_PATH 2097152 end // open descriptor for obtaining permissions and status of a file but does not allow read/write operations
|
|
||||||
const FS_O_SYNC 1052672 end // wait for IO to complete before returning
|
|
||||||
const FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file
|
|
||||||
const FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!)
|
|
|
@ -1,15 +0,0 @@
|
||||||
const NULL 0 end
|
|
||||||
const false 0 end
|
|
||||||
const true 1 end
|
|
||||||
|
|
||||||
inline fn div with int int returns int then divmod drop done
|
|
||||||
inline fn mod with int int returns int then divmod swap drop done
|
|
||||||
|
|
||||||
|
|
||||||
inline fn dup2 with any any returns any any any any then over over done
|
|
||||||
inline fn drop2 with any any returns void then drop drop done
|
|
||||||
|
|
||||||
const sizeof(u64) 8 end
|
|
||||||
const sizeof(u32) 4 end
|
|
||||||
const sizeof(u16) 2 end
|
|
||||||
const sizeof(u8) 1 end
|
|
|
@ -1,50 +0,0 @@
|
||||||
|
|
||||||
// Write to a file descriptor using the SYS_write syscall
|
|
||||||
// args: [buff_size, buff_ptr, fd]
|
|
||||||
// @arg buff_size: Int - number of bytes to write
|
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
|
||||||
// @arg fd: Int - file descriptor
|
|
||||||
// @ret Int
|
|
||||||
inline fn write with int ptr int returns int then
|
|
||||||
SYS_write syscall3
|
|
||||||
done
|
|
||||||
|
|
||||||
// Write to a file descriptor using the SYS_write syscall
|
|
||||||
// args: [buff_size, buff_ptr, fd]
|
|
||||||
// @arg buff_size: Int - number of bytes to write
|
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
|
||||||
// @arg fd: Int - file descriptor
|
|
||||||
// @ret Int
|
|
||||||
inline fn read with int ptr int returns int then
|
|
||||||
SYS_read syscall3
|
|
||||||
done
|
|
||||||
|
|
||||||
|
|
||||||
// Print a string to STDOUT
|
|
||||||
// args: [str_size, str_ptr]
|
|
||||||
// @arg buff_size: Int - number of bytes to write
|
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
|
||||||
// @ret NULL
|
|
||||||
inline fn puts with int ptr returns void then
|
|
||||||
STDOUT write drop
|
|
||||||
done
|
|
||||||
|
|
||||||
// Print a string to STDERR
|
|
||||||
// args: [str_size, str_ptr]
|
|
||||||
// @arg buff_size: Int - number of bytes to write
|
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
|
||||||
// @ret NULL
|
|
||||||
inline fn eputs with int ptr returns void then
|
|
||||||
STDOUT write drop
|
|
||||||
done
|
|
||||||
|
|
||||||
// TODO: make putc and eputc after we make local mem
|
|
||||||
|
|
||||||
// Exit the program with exit_code
|
|
||||||
// args: [exit_code]
|
|
||||||
// @arg exit_code: Int
|
|
||||||
// @ret NULL/NEVER
|
|
||||||
inline fn exit with int returns void then
|
|
||||||
SYS_exit syscall1 drop
|
|
||||||
done
|
|
||||||
|
|
|
@ -1,322 +0,0 @@
|
||||||
|
|
||||||
// file descriptors
|
|
||||||
const STDIN 0 end
|
|
||||||
const STDOUT 1 end
|
|
||||||
const STDERR 2 end
|
|
||||||
|
|
||||||
|
|
||||||
// syscalls
|
|
||||||
const SYS_read 0 end
|
|
||||||
const SYS_write 1 end
|
|
||||||
const SYS_open 2 end
|
|
||||||
const SYS_close 3 end
|
|
||||||
const SYS_stat 4 end
|
|
||||||
const SYS_fstat 5 end
|
|
||||||
const SYS_lstat 6 end
|
|
||||||
const SYS_poll 7 end
|
|
||||||
const SYS_lseek 8 end
|
|
||||||
const SYS_mmap 9 end
|
|
||||||
const SYS_mprotect 10 end
|
|
||||||
const SYS_munmap 11 end
|
|
||||||
const SYS_brk 12 end
|
|
||||||
const SYS_rt_sigaction 13 end
|
|
||||||
const SYS_rt_sigprocmask 14 end
|
|
||||||
const SYS_rt_sigreturn 15 end
|
|
||||||
const SYS_ioctl 16 end
|
|
||||||
const SYS_pread64 17 end
|
|
||||||
const SYS_pwrite64 18 end
|
|
||||||
const SYS_readv 19 end
|
|
||||||
const SYS_writev 20 end
|
|
||||||
const SYS_access 21 end
|
|
||||||
const SYS_pipe 22 end
|
|
||||||
const SYS_select 23 end
|
|
||||||
const SYS_sched_yield 24 end
|
|
||||||
const SYS_mremap 25 end
|
|
||||||
const SYS_msync 26 end
|
|
||||||
const SYS_mincore 27 end
|
|
||||||
const SYS_madvise 28 end
|
|
||||||
const SYS_shmget 29 end
|
|
||||||
const SYS_shmat 30 end
|
|
||||||
const SYS_shmctl 31 end
|
|
||||||
const SYS_dup 32 end
|
|
||||||
const SYS_dup2 33 end
|
|
||||||
const SYS_pause 34 end
|
|
||||||
const SYS_nanosleep 35 end
|
|
||||||
const SYS_getitimer 36 end
|
|
||||||
const SYS_alarm 37 end
|
|
||||||
const SYS_setitimer 38 end
|
|
||||||
const SYS_getpid 39 end
|
|
||||||
const SYS_sendfile 40 end
|
|
||||||
const SYS_socket 41 end
|
|
||||||
const SYS_connect 42 end
|
|
||||||
const SYS_accept 43 end
|
|
||||||
const SYS_sendto 44 end
|
|
||||||
const SYS_recvfrom 45 end
|
|
||||||
const SYS_sendmsg 46 end
|
|
||||||
const SYS_recvmsg 47 end
|
|
||||||
const SYS_shutdown 48 end
|
|
||||||
const SYS_bind 49 end
|
|
||||||
const SYS_listen 50 end
|
|
||||||
const SYS_getsockname 51 end
|
|
||||||
const SYS_getpeername 52 end
|
|
||||||
const SYS_socketpair 53 end
|
|
||||||
const SYS_setsockopt 54 end
|
|
||||||
const SYS_getsockopt 55 end
|
|
||||||
const SYS_clone 56 end
|
|
||||||
const SYS_fork 57 end
|
|
||||||
const SYS_vfork 58 end
|
|
||||||
const SYS_execve 59 end
|
|
||||||
const SYS_exit 60 end
|
|
||||||
const SYS_wait4 61 end
|
|
||||||
const SYS_kill 62 end
|
|
||||||
const SYS_uname 63 end
|
|
||||||
const SYS_semget 64 end
|
|
||||||
const SYS_semop 65 end
|
|
||||||
const SYS_semctl 66 end
|
|
||||||
const SYS_shmdt 67 end
|
|
||||||
const SYS_msgget 68 end
|
|
||||||
const SYS_msgsnd 69 end
|
|
||||||
const SYS_msgrcv 70 end
|
|
||||||
const SYS_msgctl 71 end
|
|
||||||
const SYS_fcntl 72 end
|
|
||||||
const SYS_flock 73 end
|
|
||||||
const SYS_fsync 74 end
|
|
||||||
const SYS_fdatasync 75 end
|
|
||||||
const SYS_truncate 76 end
|
|
||||||
const SYS_ftruncate 77 end
|
|
||||||
const SYS_getdents 78 end
|
|
||||||
const SYS_getcwd 79 end
|
|
||||||
const SYS_chdir 80 end
|
|
||||||
const SYS_fchdir 81 end
|
|
||||||
const SYS_rename 82 end
|
|
||||||
const SYS_mkdir 83 end
|
|
||||||
const SYS_rmdir 84 end
|
|
||||||
const SYS_creat 85 end
|
|
||||||
const SYS_link 86 end
|
|
||||||
const SYS_unlink 87 end
|
|
||||||
const SYS_symlink 88 end
|
|
||||||
const SYS_readlink 89 end
|
|
||||||
const SYS_chmod 90 end
|
|
||||||
const SYS_fchmod 91 end
|
|
||||||
const SYS_chown 92 end
|
|
||||||
const SYS_fchown 93 end
|
|
||||||
const SYS_lchown 94 end
|
|
||||||
const SYS_umask 95 end
|
|
||||||
const SYS_gettimeofday 96 end
|
|
||||||
const SYS_getrlimit 97 end
|
|
||||||
const SYS_getrusage 98 end
|
|
||||||
const SYS_sysinfo 99 end
|
|
||||||
const SYS_times 100 end
|
|
||||||
const SYS_ptrace 101 end
|
|
||||||
const SYS_getuid 102 end
|
|
||||||
const SYS_syslog 103 end
|
|
||||||
const SYS_getgid 104 end
|
|
||||||
const SYS_setuid 105 end
|
|
||||||
const SYS_setgid 106 end
|
|
||||||
const SYS_geteuid 107 end
|
|
||||||
const SYS_getegid 108 end
|
|
||||||
const SYS_setpgid 109 end
|
|
||||||
const SYS_getppid 110 end
|
|
||||||
const SYS_getpgrp 111 end
|
|
||||||
const SYS_setsid 112 end
|
|
||||||
const SYS_setreuid 113 end
|
|
||||||
const SYS_setregid 114 end
|
|
||||||
const SYS_getgroups 115 end
|
|
||||||
const SYS_setgroups 116 end
|
|
||||||
const SYS_setresuid 117 end
|
|
||||||
const SYS_getresuid 118 end
|
|
||||||
const SYS_setresgid 119 end
|
|
||||||
const SYS_getresgid 120 end
|
|
||||||
const SYS_getpgid 121 end
|
|
||||||
const SYS_setfsuid 122 end
|
|
||||||
const SYS_setfsgid 123 end
|
|
||||||
const SYS_getsid 124 end
|
|
||||||
const SYS_capget 125 end
|
|
||||||
const SYS_capset 126 end
|
|
||||||
const SYS_rt_sigpending 127 end
|
|
||||||
const SYS_rt_sigtimedwait 128 end
|
|
||||||
const SYS_rt_sigqueueinfo 129 end
|
|
||||||
const SYS_rt_sigsuspend 130 end
|
|
||||||
const SYS_sigaltstack 131 end
|
|
||||||
const SYS_utime 132 end
|
|
||||||
const SYS_mknod 133 end
|
|
||||||
const SYS_uselib 134 end
|
|
||||||
const SYS_personality 135 end
|
|
||||||
const SYS_ustat 136 end
|
|
||||||
const SYS_statfs 137 end
|
|
||||||
const SYS_fstatfs 138 end
|
|
||||||
const SYS_sysfs 139 end
|
|
||||||
const SYS_getpriority 140 end
|
|
||||||
const SYS_setpriority 141 end
|
|
||||||
const SYS_sched_setparam 142 end
|
|
||||||
const SYS_sched_getparam 143 end
|
|
||||||
const SYS_sched_setscheduler 144 end
|
|
||||||
const SYS_sched_getscheduler 145 end
|
|
||||||
const SYS_sched_get_priority_max 146 end
|
|
||||||
const SYS_sched_get_priority_min 147 end
|
|
||||||
const SYS_sched_rr_get_interval 148 end
|
|
||||||
const SYS_mlock 149 end
|
|
||||||
const SYS_munlock 150 end
|
|
||||||
const SYS_mlockall 151 end
|
|
||||||
const SYS_munlockall 152 end
|
|
||||||
const SYS_vhangup 153 end
|
|
||||||
const SYS_modify_ldt 154 end
|
|
||||||
const SYS_pivot_root 155 end
|
|
||||||
const SYS__sysctl 156 end
|
|
||||||
const SYS_prctl 157 end
|
|
||||||
const SYS_arch_prctl 158 end
|
|
||||||
const SYS_adjtimex 159 end
|
|
||||||
const SYS_setrlimit 160 end
|
|
||||||
const SYS_chroot 161 end
|
|
||||||
const SYS_sync 162 end
|
|
||||||
const SYS_acct 163 end
|
|
||||||
const SYS_settimeofday 164 end
|
|
||||||
const SYS_mount 165 end
|
|
||||||
const SYS_umount2 166 end
|
|
||||||
const SYS_swapon 167 end
|
|
||||||
const SYS_swapoff 168 end
|
|
||||||
const SYS_reboot 169 end
|
|
||||||
const SYS_sethostname 170 end
|
|
||||||
const SYS_setdomainname 171 end
|
|
||||||
const SYS_iopl 172 end
|
|
||||||
const SYS_ioperm 173 end
|
|
||||||
const SYS_create_module 174 end
|
|
||||||
const SYS_init_module 175 end
|
|
||||||
const SYS_delete_module 176 end
|
|
||||||
const SYS_get_kernel_syms 177 end
|
|
||||||
const SYS_query_module 178 end
|
|
||||||
const SYS_quotactl 179 end
|
|
||||||
const SYS_nfsservctl 180 end
|
|
||||||
const SYS_getpmsg 181 end
|
|
||||||
const SYS_putpmsg 182 end
|
|
||||||
const SYS_afs_syscall 183 end
|
|
||||||
const SYS_tuxcall 184 end
|
|
||||||
const SYS_security 185 end
|
|
||||||
const SYS_gettid 186 end
|
|
||||||
const SYS_readahead 187 end
|
|
||||||
const SYS_setxattr 188 end
|
|
||||||
const SYS_lsetxattr 189 end
|
|
||||||
const SYS_fsetxattr 190 end
|
|
||||||
const SYS_getxattr 191 end
|
|
||||||
const SYS_lgetxattr 192 end
|
|
||||||
const SYS_fgetxattr 193 end
|
|
||||||
const SYS_listxattr 194 end
|
|
||||||
const SYS_llistxattr 195 end
|
|
||||||
const SYS_flistxattr 196 end
|
|
||||||
const SYS_removexattr 197 end
|
|
||||||
const SYS_lremovexattr 198 end
|
|
||||||
const SYS_fremovexattr 199 end
|
|
||||||
const SYS_tkill 200 end
|
|
||||||
const SYS_time 201 end
|
|
||||||
const SYS_futex 202 end
|
|
||||||
const SYS_sched_setaffinity 203 end
|
|
||||||
const SYS_sched_getaffinity 204 end
|
|
||||||
const SYS_set_thread_area 205 end
|
|
||||||
const SYS_io_setup 206 end
|
|
||||||
const SYS_io_destroy 207 end
|
|
||||||
const SYS_io_getevents 208 end
|
|
||||||
const SYS_io_submit 209 end
|
|
||||||
const SYS_io_cancel 210 end
|
|
||||||
const SYS_get_thread_area 211 end
|
|
||||||
const SYS_lookup_dcookie 212 end
|
|
||||||
const SYS_epoll_create 213 end
|
|
||||||
const SYS_epoll_ctl_old 214 end
|
|
||||||
const SYS_epoll_wait_old 215 end
|
|
||||||
const SYS_remap_file_pages 216 end
|
|
||||||
const SYS_getdents64 217 end
|
|
||||||
const SYS_set_tid_address 218 end
|
|
||||||
const SYS_restart_syscall 219 end
|
|
||||||
const SYS_semtimedop 220 end
|
|
||||||
const SYS_fadvise64 221 end
|
|
||||||
const SYS_timer_create 222 end
|
|
||||||
const SYS_timer_settime 223 end
|
|
||||||
const SYS_timer_gettime 224 end
|
|
||||||
const SYS_timer_getoverrun 225 end
|
|
||||||
const SYS_timer_delete 226 end
|
|
||||||
const SYS_clock_settime 227 end
|
|
||||||
const SYS_clock_gettime 228 end
|
|
||||||
const SYS_clock_getres 229 end
|
|
||||||
const SYS_clock_nanosleep 230 end
|
|
||||||
const SYS_exit_group 231 end
|
|
||||||
const SYS_epoll_wait 232 end
|
|
||||||
const SYS_epoll_ctl 233 end
|
|
||||||
const SYS_tgkill 234 end
|
|
||||||
const SYS_utimes 235 end
|
|
||||||
const SYS_vserver 236 end
|
|
||||||
const SYS_mbind 237 end
|
|
||||||
const SYS_set_mempolicy 238 end
|
|
||||||
const SYS_get_mempolicy 239 end
|
|
||||||
const SYS_mq_open 240 end
|
|
||||||
const SYS_mq_unlink 241 end
|
|
||||||
const SYS_mq_timedsend 242 end
|
|
||||||
const SYS_mq_timedreceive 243 end
|
|
||||||
const SYS_mq_notify 244 end
|
|
||||||
const SYS_mq_getsetattr 245 end
|
|
||||||
const SYS_kexec_load 246 end
|
|
||||||
const SYS_waitid 247 end
|
|
||||||
const SYS_add_key 248 end
|
|
||||||
const SYS_request_key 249 end
|
|
||||||
const SYS_keyctl 250 end
|
|
||||||
const SYS_ioprio_set 251 end
|
|
||||||
const SYS_ioprio_get 252 end
|
|
||||||
const SYS_inotify_init 253 end
|
|
||||||
const SYS_inotify_add_watch 254 end
|
|
||||||
const SYS_inotify_rm_watch 255 end
|
|
||||||
const SYS_migrate_pages 256 end
|
|
||||||
const SYS_openat 257 end
|
|
||||||
const SYS_mkdirat 258 end
|
|
||||||
const SYS_mknodat 259 end
|
|
||||||
const SYS_fchownat 260 end
|
|
||||||
const SYS_futimesat 261 end
|
|
||||||
const SYS_newfstatat 262 end
|
|
||||||
const SYS_unlinkat 263 end
|
|
||||||
const SYS_renameat 264 end
|
|
||||||
const SYS_linkat 265 end
|
|
||||||
const SYS_symlinkat 266 end
|
|
||||||
const SYS_readlinkat 267 end
|
|
||||||
const SYS_fchmodat 268 end
|
|
||||||
const SYS_faccessat 269 end
|
|
||||||
const SYS_pselect6 270 end
|
|
||||||
const SYS_ppoll 271 end
|
|
||||||
const SYS_unshare 272 end
|
|
||||||
const SYS_set_robust_list 273 end
|
|
||||||
const SYS_get_robust_list 274 end
|
|
||||||
const SYS_splice 275 end
|
|
||||||
const SYS_tee 276 end
|
|
||||||
const SYS_sync_file_range 277 end
|
|
||||||
const SYS_vmsplice 278 end
|
|
||||||
const SYS_move_pages 279 end
|
|
||||||
const SYS_utimensat 280 end
|
|
||||||
const SYS_epoll_pwait 281 end
|
|
||||||
const SYS_signalfd 282 end
|
|
||||||
const SYS_timerfd_create 283 end
|
|
||||||
const SYS_eventfd 284 end
|
|
||||||
const SYS_fallocate 285 end
|
|
||||||
const SYS_timerfd_settime 286 end
|
|
||||||
const SYS_timerfd_gettime 287 end
|
|
||||||
const SYS_accept4 288 end
|
|
||||||
const SYS_signalfd4 289 end
|
|
||||||
const SYS_eventfd2 290 end
|
|
||||||
const SYS_epoll_create1 291 end
|
|
||||||
const SYS_dup3 292 end
|
|
||||||
const SYS_pipe2 293 end
|
|
||||||
const SYS_inotify_init1 294 end
|
|
||||||
const SYS_preadv 295 end
|
|
||||||
const SYS_pwritev 296 end
|
|
||||||
const SYS_rt_tgsigqueueinfo 297 end
|
|
||||||
const SYS_perf_event_open 298 end
|
|
||||||
const SYS_recvmmsg 299 end
|
|
||||||
const SYS_fanotify_init 300 end
|
|
||||||
const SYS_fanotify_mark 301 end
|
|
||||||
const SYS_prlimit64 302 end
|
|
||||||
const SYS_name_to_handle_at 303 end
|
|
||||||
const SYS_open_by_handle_at 304 end
|
|
||||||
const SYS_clock_adjtime 305 end
|
|
||||||
const SYS_syncfs 306 end
|
|
||||||
const SYS_sendmmsg 307 end
|
|
||||||
const SYS_setns 308 end
|
|
||||||
const SYS_getcpu 309 end
|
|
||||||
const SYS_process_vm_readv 310 end
|
|
||||||
const SYS_process_vm_writev 311 end
|
|
||||||
const SYS_kcmp 312 end
|
|
||||||
const SYS_finit_module 313 end
|
|
14
include/linux/io.mcl
Normal file
14
include/linux/io.mcl
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
|
||||||
|
fn fwrite with u64 ptr u64 returns u64 then
|
||||||
|
SYS_write syscall3
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fn puts with u64 ptr u64 returns u64 then
|
||||||
|
STDOUT fwrite drop
|
||||||
|
done
|
||||||
|
|
||||||
|
fn eputs with u64 ptr u64 returns u64 then
|
||||||
|
STDERR fwrite drop
|
||||||
|
done
|
2
include/linux/linux.mcl
Normal file
2
include/linux/linux.mcl
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
include "linux/syscalls.mcl"
|
||||||
|
include "linux/io.mcl"
|
322
include/linux/syscalls.mcl
Normal file
322
include/linux/syscalls.mcl
Normal file
|
@ -0,0 +1,322 @@
|
||||||
|
|
||||||
|
// file descriptors
|
||||||
|
const STDIN 0 end
|
||||||
|
const STDOUT 1 end
|
||||||
|
const STDERR 2 end
|
||||||
|
|
||||||
|
|
||||||
|
// syscalls
|
||||||
|
// const SYS_read 0 end
|
||||||
|
const SYS_write 1 end
|
||||||
|
// const SYS_open 2 end
|
||||||
|
// const SYS_close 3 end
|
||||||
|
// const SYS_stat 4 end
|
||||||
|
// const SYS_fstat 5 end
|
||||||
|
// const SYS_lstat 6 end
|
||||||
|
// const SYS_poll 7 end
|
||||||
|
// const SYS_lseek 8 end
|
||||||
|
// const SYS_mmap 9 end
|
||||||
|
// const SYS_mprotect 10 end
|
||||||
|
// const SYS_munmap 11 end
|
||||||
|
// const SYS_brk 12 end
|
||||||
|
// const SYS_rt_sigaction 13 end
|
||||||
|
// const SYS_rt_sigprocmask 14 end
|
||||||
|
// const SYS_rt_sigreturn 15 end
|
||||||
|
// const SYS_ioctl 16 end
|
||||||
|
// const SYS_pread64 17 end
|
||||||
|
// const SYS_pwrite64 18 end
|
||||||
|
// const SYS_readv 19 end
|
||||||
|
// const SYS_writev 20 end
|
||||||
|
// const SYS_access 21 end
|
||||||
|
// const SYS_pipe 22 end
|
||||||
|
// const SYS_select 23 end
|
||||||
|
// const SYS_sched_yield 24 end
|
||||||
|
// const SYS_mremap 25 end
|
||||||
|
// const SYS_msync 26 end
|
||||||
|
// const SYS_mincore 27 end
|
||||||
|
// const SYS_madvise 28 end
|
||||||
|
// const SYS_shmget 29 end
|
||||||
|
// const SYS_shmat 30 end
|
||||||
|
// const SYS_shmctl 31 end
|
||||||
|
// const SYS_dup 32 end
|
||||||
|
// const SYS_dup2 33 end
|
||||||
|
// const SYS_pause 34 end
|
||||||
|
// const SYS_nanosleep 35 end
|
||||||
|
// const SYS_getitimer 36 end
|
||||||
|
// const SYS_alarm 37 end
|
||||||
|
// const SYS_setitimer 38 end
|
||||||
|
// const SYS_getpid 39 end
|
||||||
|
// const SYS_sendfile 40 end
|
||||||
|
// const SYS_socket 41 end
|
||||||
|
// const SYS_connect 42 end
|
||||||
|
// const SYS_accept 43 end
|
||||||
|
// const SYS_sendto 44 end
|
||||||
|
// const SYS_recvfrom 45 end
|
||||||
|
// const SYS_sendmsg 46 end
|
||||||
|
// const SYS_recvmsg 47 end
|
||||||
|
// const SYS_shutdown 48 end
|
||||||
|
// const SYS_bind 49 end
|
||||||
|
// const SYS_listen 50 end
|
||||||
|
// const SYS_getsockname 51 end
|
||||||
|
// const SYS_getpeername 52 end
|
||||||
|
// const SYS_socketpair 53 end
|
||||||
|
// const SYS_setsockopt 54 end
|
||||||
|
// const SYS_getsockopt 55 end
|
||||||
|
// const SYS_clone 56 end
|
||||||
|
// const SYS_fork 57 end
|
||||||
|
// const SYS_vfork 58 end
|
||||||
|
// const SYS_execve 59 end
|
||||||
|
const SYS_exit 60 end
|
||||||
|
// const SYS_wait4 61 end
|
||||||
|
// const SYS_kill 62 end
|
||||||
|
// const SYS_uname 63 end
|
||||||
|
// const SYS_semget 64 end
|
||||||
|
// const SYS_semop 65 end
|
||||||
|
// const SYS_semctl 66 end
|
||||||
|
// const SYS_shmdt 67 end
|
||||||
|
// const SYS_msgget 68 end
|
||||||
|
// const SYS_msgsnd 69 end
|
||||||
|
// const SYS_msgrcv 70 end
|
||||||
|
// const SYS_msgctl 71 end
|
||||||
|
// const SYS_fcntl 72 end
|
||||||
|
// const SYS_flock 73 end
|
||||||
|
// const SYS_fsync 74 end
|
||||||
|
// const SYS_fdatasync 75 end
|
||||||
|
// const SYS_truncate 76 end
|
||||||
|
// const SYS_ftruncate 77 end
|
||||||
|
// const SYS_getdents 78 end
|
||||||
|
// const SYS_getcwd 79 end
|
||||||
|
// const SYS_chdir 80 end
|
||||||
|
// const SYS_fchdir 81 end
|
||||||
|
// const SYS_rename 82 end
|
||||||
|
// const SYS_mkdir 83 end
|
||||||
|
// const SYS_rmdir 84 end
|
||||||
|
// const SYS_creat 85 end
|
||||||
|
// const SYS_link 86 end
|
||||||
|
// const SYS_unlink 87 end
|
||||||
|
// const SYS_symlink 88 end
|
||||||
|
// const SYS_readlink 89 end
|
||||||
|
// const SYS_chmod 90 end
|
||||||
|
// const SYS_fchmod 91 end
|
||||||
|
// const SYS_chown 92 end
|
||||||
|
// const SYS_fchown 93 end
|
||||||
|
// const SYS_lchown 94 end
|
||||||
|
// const SYS_umask 95 end
|
||||||
|
// const SYS_gettimeofday 96 end
|
||||||
|
// const SYS_getrlimit 97 end
|
||||||
|
// const SYS_getrusage 98 end
|
||||||
|
// const SYS_sysinfo 99 end
|
||||||
|
// const SYS_times 100 end
|
||||||
|
// const SYS_ptrace 101 end
|
||||||
|
// const SYS_getuid 102 end
|
||||||
|
// const SYS_syslog 103 end
|
||||||
|
// const SYS_getgid 104 end
|
||||||
|
// const SYS_setuid 105 end
|
||||||
|
// const SYS_setgid 106 end
|
||||||
|
// const SYS_geteuid 107 end
|
||||||
|
// const SYS_getegid 108 end
|
||||||
|
// const SYS_setpgid 109 end
|
||||||
|
// const SYS_getppid 110 end
|
||||||
|
// const SYS_getpgrp 111 end
|
||||||
|
// const SYS_setsid 112 end
|
||||||
|
// const SYS_setreuid 113 end
|
||||||
|
// const SYS_setregid 114 end
|
||||||
|
// const SYS_getgroups 115 end
|
||||||
|
// const SYS_setgroups 116 end
|
||||||
|
// const SYS_setresuid 117 end
|
||||||
|
// const SYS_getresuid 118 end
|
||||||
|
// const SYS_setresgid 119 end
|
||||||
|
// const SYS_getresgid 120 end
|
||||||
|
// const SYS_getpgid 121 end
|
||||||
|
// const SYS_setfsuid 122 end
|
||||||
|
// const SYS_setfsgid 123 end
|
||||||
|
// const SYS_getsid 124 end
|
||||||
|
// const SYS_capget 125 end
|
||||||
|
// const SYS_capset 126 end
|
||||||
|
// const SYS_rt_sigpending 127 end
|
||||||
|
// const SYS_rt_sigtimedwait 128 end
|
||||||
|
// const SYS_rt_sigqueueinfo 129 end
|
||||||
|
// const SYS_rt_sigsuspend 130 end
|
||||||
|
// const SYS_sigaltstack 131 end
|
||||||
|
// const SYS_utime 132 end
|
||||||
|
// const SYS_mknod 133 end
|
||||||
|
// const SYS_uselib 134 end
|
||||||
|
// const SYS_personality 135 end
|
||||||
|
// const SYS_ustat 136 end
|
||||||
|
// const SYS_statfs 137 end
|
||||||
|
// const SYS_fstatfs 138 end
|
||||||
|
// const SYS_sysfs 139 end
|
||||||
|
// const SYS_getpriority 140 end
|
||||||
|
// const SYS_setpriority 141 end
|
||||||
|
// const SYS_sched_setparam 142 end
|
||||||
|
// const SYS_sched_getparam 143 end
|
||||||
|
// const SYS_sched_setscheduler 144 end
|
||||||
|
// const SYS_sched_getscheduler 145 end
|
||||||
|
// const SYS_sched_get_priority_max 146 end
|
||||||
|
// const SYS_sched_get_priority_min 147 end
|
||||||
|
// const SYS_sched_rr_get_interval 148 end
|
||||||
|
// const SYS_mlock 149 end
|
||||||
|
// const SYS_munlock 150 end
|
||||||
|
// const SYS_mlockall 151 end
|
||||||
|
// const SYS_munlockall 152 end
|
||||||
|
// const SYS_vhangup 153 end
|
||||||
|
// const SYS_modify_ldt 154 end
|
||||||
|
// const SYS_pivot_root 155 end
|
||||||
|
// const SYS__sysctl 156 end
|
||||||
|
// const SYS_prctl 157 end
|
||||||
|
// const SYS_arch_prctl 158 end
|
||||||
|
// const SYS_adjtimex 159 end
|
||||||
|
// const SYS_setrlimit 160 end
|
||||||
|
// const SYS_chroot 161 end
|
||||||
|
// const SYS_sync 162 end
|
||||||
|
// const SYS_acct 163 end
|
||||||
|
// const SYS_settimeofday 164 end
|
||||||
|
// const SYS_mount 165 end
|
||||||
|
// const SYS_umount2 166 end
|
||||||
|
// const SYS_swapon 167 end
|
||||||
|
// const SYS_swapoff 168 end
|
||||||
|
// const SYS_reboot 169 end
|
||||||
|
// const SYS_sethostname 170 end
|
||||||
|
// const SYS_setdomainname 171 end
|
||||||
|
// const SYS_iopl 172 end
|
||||||
|
// const SYS_ioperm 173 end
|
||||||
|
// const SYS_create_module 174 end
|
||||||
|
// const SYS_init_module 175 end
|
||||||
|
// const SYS_delete_module 176 end
|
||||||
|
// const SYS_get_kernel_syms 177 end
|
||||||
|
// const SYS_query_module 178 end
|
||||||
|
// const SYS_quotactl 179 end
|
||||||
|
// const SYS_nfsservctl 180 end
|
||||||
|
// const SYS_getpmsg 181 end
|
||||||
|
// const SYS_putpmsg 182 end
|
||||||
|
// const SYS_afs_syscall 183 end
|
||||||
|
// const SYS_tuxcall 184 end
|
||||||
|
// const SYS_security 185 end
|
||||||
|
// const SYS_gettid 186 end
|
||||||
|
// const SYS_readahead 187 end
|
||||||
|
// const SYS_setxattr 188 end
|
||||||
|
// const SYS_lsetxattr 189 end
|
||||||
|
// const SYS_fsetxattr 190 end
|
||||||
|
// const SYS_getxattr 191 end
|
||||||
|
// const SYS_lgetxattr 192 end
|
||||||
|
// const SYS_fgetxattr 193 end
|
||||||
|
// const SYS_listxattr 194 end
|
||||||
|
// const SYS_llistxattr 195 end
|
||||||
|
// const SYS_flistxattr 196 end
|
||||||
|
// const SYS_removexattr 197 end
|
||||||
|
// const SYS_lremovexattr 198 end
|
||||||
|
// const SYS_fremovexattr 199 end
|
||||||
|
// const SYS_tkill 200 end
|
||||||
|
// const SYS_time 201 end
|
||||||
|
// const SYS_futex 202 end
|
||||||
|
// const SYS_sched_setaffinity 203 end
|
||||||
|
// const SYS_sched_getaffinity 204 end
|
||||||
|
// const SYS_set_thread_area 205 end
|
||||||
|
// const SYS_io_setup 206 end
|
||||||
|
// const SYS_io_destroy 207 end
|
||||||
|
// const SYS_io_getevents 208 end
|
||||||
|
// const SYS_io_submit 209 end
|
||||||
|
// const SYS_io_cancel 210 end
|
||||||
|
// const SYS_get_thread_area 211 end
|
||||||
|
// const SYS_lookup_dcookie 212 end
|
||||||
|
// const SYS_epoll_create 213 end
|
||||||
|
// const SYS_epoll_ctl_old 214 end
|
||||||
|
// const SYS_epoll_wait_old 215 end
|
||||||
|
// const SYS_remap_file_pages 216 end
|
||||||
|
// const SYS_getdents64 217 end
|
||||||
|
// const SYS_set_tid_address 218 end
|
||||||
|
// const SYS_restart_syscall 219 end
|
||||||
|
// const SYS_semtimedop 220 end
|
||||||
|
// const SYS_fadvise64 221 end
|
||||||
|
// const SYS_timer_create 222 end
|
||||||
|
// const SYS_timer_settime 223 end
|
||||||
|
// const SYS_timer_gettime 224 end
|
||||||
|
// const SYS_timer_getoverrun 225 end
|
||||||
|
// const SYS_timer_delete 226 end
|
||||||
|
// const SYS_clock_settime 227 end
|
||||||
|
// const SYS_clock_gettime 228 end
|
||||||
|
// const SYS_clock_getres 229 end
|
||||||
|
// const SYS_clock_nanosleep 230 end
|
||||||
|
// const SYS_exit_group 231 end
|
||||||
|
// const SYS_epoll_wait 232 end
|
||||||
|
// const SYS_epoll_ctl 233 end
|
||||||
|
// const SYS_tgkill 234 end
|
||||||
|
// const SYS_utimes 235 end
|
||||||
|
// const SYS_vserver 236 end
|
||||||
|
// const SYS_mbind 237 end
|
||||||
|
// const SYS_set_mempolicy 238 end
|
||||||
|
// const SYS_get_mempolicy 239 end
|
||||||
|
// const SYS_mq_open 240 end
|
||||||
|
// const SYS_mq_unlink 241 end
|
||||||
|
// const SYS_mq_timedsend 242 end
|
||||||
|
// const SYS_mq_timedreceive 243 end
|
||||||
|
// const SYS_mq_notify 244 end
|
||||||
|
// const SYS_mq_getsetattr 245 end
|
||||||
|
// const SYS_kexec_load 246 end
|
||||||
|
// const SYS_waitid 247 end
|
||||||
|
// const SYS_add_key 248 end
|
||||||
|
// const SYS_request_key 249 end
|
||||||
|
// const SYS_keyctl 250 end
|
||||||
|
// const SYS_ioprio_set 251 end
|
||||||
|
// const SYS_ioprio_get 252 end
|
||||||
|
// const SYS_inotify_init 253 end
|
||||||
|
// const SYS_inotify_add_watch 254 end
|
||||||
|
// const SYS_inotify_rm_watch 255 end
|
||||||
|
// const SYS_migrate_pages 256 end
|
||||||
|
// const SYS_openat 257 end
|
||||||
|
// const SYS_mkdirat 258 end
|
||||||
|
// const SYS_mknodat 259 end
|
||||||
|
// const SYS_fchownat 260 end
|
||||||
|
// const SYS_futimesat 261 end
|
||||||
|
// const SYS_newfstatat 262 end
|
||||||
|
// const SYS_unlinkat 263 end
|
||||||
|
// const SYS_renameat 264 end
|
||||||
|
// const SYS_linkat 265 end
|
||||||
|
// const SYS_symlinkat 266 end
|
||||||
|
// const SYS_readlinkat 267 end
|
||||||
|
// const SYS_fchmodat 268 end
|
||||||
|
// const SYS_faccessat 269 end
|
||||||
|
// const SYS_pselect6 270 end
|
||||||
|
// const SYS_ppoll 271 end
|
||||||
|
// const SYS_unshare 272 end
|
||||||
|
// const SYS_set_robust_list 273 end
|
||||||
|
// const SYS_get_robust_list 274 end
|
||||||
|
// const SYS_splice 275 end
|
||||||
|
// const SYS_tee 276 end
|
||||||
|
// const SYS_sync_file_range 277 end
|
||||||
|
// const SYS_vmsplice 278 end
|
||||||
|
// const SYS_move_pages 279 end
|
||||||
|
// const SYS_utimensat 280 end
|
||||||
|
// const SYS_epoll_pwait 281 end
|
||||||
|
// const SYS_signalfd 282 end
|
||||||
|
// const SYS_timerfd_create 283 end
|
||||||
|
// const SYS_eventfd 284 end
|
||||||
|
// const SYS_fallocate 285 end
|
||||||
|
// const SYS_timerfd_settime 286 end
|
||||||
|
// const SYS_timerfd_gettime 287 end
|
||||||
|
// const SYS_accept4 288 end
|
||||||
|
// const SYS_signalfd4 289 end
|
||||||
|
// const SYS_eventfd2 290 end
|
||||||
|
// const SYS_epoll_create1 291 end
|
||||||
|
// const SYS_dup3 292 end
|
||||||
|
// const SYS_pipe2 293 end
|
||||||
|
// const SYS_inotify_init1 294 end
|
||||||
|
// const SYS_preadv 295 end
|
||||||
|
// const SYS_pwritev 296 end
|
||||||
|
// const SYS_rt_tgsigqueueinfo 297 end
|
||||||
|
// const SYS_perf_event_open 298 end
|
||||||
|
// const SYS_recvmmsg 299 end
|
||||||
|
// const SYS_fanotify_init 300 end
|
||||||
|
// const SYS_fanotify_mark 301 end
|
||||||
|
// const SYS_prlimit64 302 end
|
||||||
|
// const SYS_name_to_handle_at 303 end
|
||||||
|
// const SYS_open_by_handle_at 304 end
|
||||||
|
// const SYS_clock_adjtime 305 end
|
||||||
|
// const SYS_syncfs 306 end
|
||||||
|
// const SYS_sendmmsg 307 end
|
||||||
|
// const SYS_setns 308 end
|
||||||
|
// const SYS_getcpu 309 end
|
||||||
|
// const SYS_process_vm_readv 310 end
|
||||||
|
// const SYS_process_vm_writev 311 end
|
||||||
|
// const SYS_kcmp 312 end
|
||||||
|
// const SYS_finit_module 313 end
|
|
@ -1,6 +1,2 @@
|
||||||
include "linux.mcl"
|
include "linux/linux.mcl"
|
||||||
include "io.mcl"
|
include "types.mcl"
|
||||||
include "util.mcl"
|
|
||||||
include "int.mcl"
|
|
||||||
include "fs.mcl"
|
|
||||||
include "compat.mcl"
|
|
4
include/types.mcl
Normal file
4
include/types.mcl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const sizeof(u8) 1 end
|
||||||
|
const sizeof(u16) 2 end
|
||||||
|
const sizeof(u32) 4 end
|
||||||
|
const sizeof(u64) 8 end
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
// Assert implementation
|
|
||||||
// args: [condition, str_len, str_ptr]
|
|
||||||
// @arg condition: Bool
|
|
||||||
// @arg str_len: Int
|
|
||||||
// @arg str_ptr: Ptr
|
|
||||||
// @ret NULL/NEVER
|
|
||||||
fn assert with bool int ptr returns void then
|
|
||||||
rot
|
|
||||||
if else
|
|
||||||
"Assert failed: \"" eputs eputs
|
|
||||||
"\". Exiting!\n" eputs
|
|
||||||
1 exit
|
|
||||||
end
|
|
||||||
done
|
|
|
@ -1,172 +0,0 @@
|
||||||
|
|
||||||
use std::path::{PathBuf, Path};
|
|
||||||
use std::process::Stdio;
|
|
||||||
use std::{process, fs};
|
|
||||||
use clap::Parser;
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
pub mod color {
|
|
||||||
#![allow(dead_code)]
|
|
||||||
pub const NONE: &str = "\x1b[0m";
|
|
||||||
pub const RESET: &str = "\x1b[0m";
|
|
||||||
pub const BRIGHT: &str = "\x1b[1m";
|
|
||||||
pub const DIM: &str = "\x1b[2m";
|
|
||||||
pub const UNDERSCORE: &str = "\x1b[4m";
|
|
||||||
pub const BLINK: &str = "\x1b[5m";
|
|
||||||
pub const REVERSE: &str = "\x1b[7m";
|
|
||||||
pub const HIDDEN: &str = "\x1b[8m";
|
|
||||||
pub const FG_BLACK: &str = "\x1b[30m";
|
|
||||||
pub const FG_RED: &str = "\x1b[31m";
|
|
||||||
pub const FG_GREEN: &str = "\x1b[32m";
|
|
||||||
pub const FG_YELLOW: &str = "\x1b[33m";
|
|
||||||
pub const FG_BLUE: &str = "\x1b[34m";
|
|
||||||
pub const FG_MAGENTA: &str = "\x1b[35m";
|
|
||||||
pub const FG_CYAN: &str = "\x1b[36m";
|
|
||||||
pub const FG_WHITE: &str = "\x1b[37m";
|
|
||||||
pub const BG_BLACK: &str = "\x1b[40m";
|
|
||||||
pub const BG_RED: &str = "\x1b[41m";
|
|
||||||
pub const BG_GREEN: &str = "\x1b[42m";
|
|
||||||
pub const BG_YELLOW: &str = "\x1b[43m";
|
|
||||||
pub const BG_BLUE: &str = "\x1b[44m";
|
|
||||||
pub const BG_MAGENTA: &str = "\x1b[45m";
|
|
||||||
pub const BG_CYAN: &str = "\x1b[46m";
|
|
||||||
pub const BG_WHITE: &str = "\x1b[47m";
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct TestOutput {
|
|
||||||
stdout: String,
|
|
||||||
stderr: String,
|
|
||||||
stdin: String,
|
|
||||||
status: i32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_test<P: Into<PathBuf> + std::convert::AsRef<std::ffi::OsStr>>(f_in: PathBuf, f_out: &PathBuf, compiler: P, compile_mode: bool, stdin: String) -> Result<TestOutput> {
|
|
||||||
let mut command = process::Command::new(compiler);
|
|
||||||
command.stdout(Stdio::piped());
|
|
||||||
command.stderr(Stdio::piped());
|
|
||||||
if compile_mode {
|
|
||||||
command.arg("-cqr");
|
|
||||||
} else {
|
|
||||||
command.arg("-sq");
|
|
||||||
}
|
|
||||||
|
|
||||||
command.arg("-i");
|
|
||||||
command.arg(f_in);
|
|
||||||
command.arg("-o");
|
|
||||||
command.arg(f_out);
|
|
||||||
|
|
||||||
let child = command.spawn()?;
|
|
||||||
|
|
||||||
let out = child.wait_with_output()?;
|
|
||||||
|
|
||||||
let stdout = out.stdout.iter().map(|c| {
|
|
||||||
char::from_u32(u32::from(*c)).expect("Failed to parse stdout char").to_string()
|
|
||||||
}).collect::<String>();
|
|
||||||
|
|
||||||
let stderr = out.stderr.iter().map(|c| {
|
|
||||||
char::from_u32(u32::from(*c)).expect("Failed to parse stderr char").to_string()
|
|
||||||
}).collect::<String>();
|
|
||||||
|
|
||||||
|
|
||||||
Ok(TestOutput {
|
|
||||||
stdout,
|
|
||||||
stderr,
|
|
||||||
stdin,
|
|
||||||
status: out.status.code().unwrap()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_tests(args: Args) -> Result<()>{
|
|
||||||
|
|
||||||
let files = fs::read_dir(args.input)?;
|
|
||||||
|
|
||||||
for file in files {
|
|
||||||
let file = file?;
|
|
||||||
let f_name = file.file_name().to_string_lossy().to_string();
|
|
||||||
let f_out = PathBuf::from(&args.output).join(f_name);
|
|
||||||
|
|
||||||
|
|
||||||
let intp = run_test(file.path(), &f_out, &args.compiler_path, false, String::new())?;
|
|
||||||
let comp = run_test(file.path(), &f_out, &args.compiler_path, true, String::new())?;
|
|
||||||
compare_results(&intp, &comp, &file.path())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn compare_results(intp: &TestOutput, comp: &TestOutput, f_in: &Path) -> Result<()> {
|
|
||||||
|
|
||||||
if intp.stdout != comp.stdout {
|
|
||||||
println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
|
||||||
println!("compiled:\n{}", comp.stdout);
|
|
||||||
println!("interpreted:\n{}", intp.stdout);
|
|
||||||
return Err(eyre!("Testing failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if intp.stderr != comp.stderr {
|
|
||||||
println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stderr versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
|
||||||
println!("compiled:\n{}", comp.stderr);
|
|
||||||
println!("interpreted:\n{}", intp.stderr);
|
|
||||||
return Err(eyre!("Testing failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if intp.status != comp.status {
|
|
||||||
println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted status codes differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
|
||||||
println!("compiled:\n{}", comp.status);
|
|
||||||
println!("interpreted:\n{}", intp.status);
|
|
||||||
return Err(eyre!("Testing failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("{b}[ {g}OK{rs}{b} ]{rs} {f} ", g=color::FG_GREEN, rs=color::RESET, b=color::BRIGHT, f=f_in.display());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
|
||||||
#[command(author, version, about, long_about = None)]
|
|
||||||
struct Args {
|
|
||||||
|
|
||||||
/// Mode, allowed modes: test, record
|
|
||||||
#[arg(long, short)]
|
|
||||||
mode: String,
|
|
||||||
|
|
||||||
/// Use compile mode
|
|
||||||
#[arg(long, short)]
|
|
||||||
compile: bool,
|
|
||||||
|
|
||||||
/// Use interpret mode
|
|
||||||
#[arg(long, short='s')]
|
|
||||||
interpret: bool,
|
|
||||||
|
|
||||||
/// Output folder
|
|
||||||
#[arg(long, short, default_value_t=String::from("./target/mcl_test_dev"))]
|
|
||||||
output: String,
|
|
||||||
|
|
||||||
/// Input folder
|
|
||||||
#[arg(long, short, default_value_t=String::from("./tests"))]
|
|
||||||
input: String,
|
|
||||||
|
|
||||||
/// Compiler path
|
|
||||||
#[arg(long, short, default_value_t=String::from("./target/release/mclangc"))]
|
|
||||||
compiler_path: String
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
|
||||||
let args = Args::parse();
|
|
||||||
fs::create_dir_all(&args.output)?;
|
|
||||||
match args.mode.as_str() {
|
|
||||||
"test" => run_tests(args),
|
|
||||||
"record" => todo!("Implement test result recording"),
|
|
||||||
s => {
|
|
||||||
eprintln!("Unknown mode '{s}'");
|
|
||||||
return Err(eyre!("Bad subcommand"));
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
129
src/cli.rs
Normal file
129
src/cli.rs
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
use clap::{builder::PossibleValue, Parser, ValueEnum};
|
||||||
|
use camino::Utf8PathBuf;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref DEFAULT_INCLUDE_PATHS: Vec<Utf8PathBuf> = vec![
|
||||||
|
Utf8PathBuf::from("./"),
|
||||||
|
Utf8PathBuf::from("./include"),
|
||||||
|
Utf8PathBuf::from("~/.mclang/include"),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
pub struct CliArgs {
|
||||||
|
/// Only compile, dont link
|
||||||
|
#[arg(long, short)]
|
||||||
|
pub compile: bool,
|
||||||
|
|
||||||
|
/// Verosity
|
||||||
|
/// -1 - Nothing
|
||||||
|
/// 0 - Only errors
|
||||||
|
/// 1 - Normal
|
||||||
|
/// 2 - Verbose
|
||||||
|
/// 3 - Tracing
|
||||||
|
#[arg(long, short, default_value_t=1)]
|
||||||
|
pub verbose: i8,
|
||||||
|
|
||||||
|
/// Runt the program after compilation
|
||||||
|
#[arg(long, short)]
|
||||||
|
pub run: bool,
|
||||||
|
|
||||||
|
/// Output execuable file path
|
||||||
|
#[arg(long, short, default_value="./a.out")]
|
||||||
|
pub output: Utf8PathBuf,
|
||||||
|
|
||||||
|
/// Paths to search for libraries
|
||||||
|
#[arg(long="include", short='I', default_values_t=DEFAULT_INCLUDE_PATHS.clone().into_iter())]
|
||||||
|
pub include_path: Vec<Utf8PathBuf>,
|
||||||
|
|
||||||
|
/// Target to compile to
|
||||||
|
#[arg(long, short='T', default_value_t=CompilationTarget::X86_64_linux_nasm)]
|
||||||
|
pub target: CompilationTarget,
|
||||||
|
|
||||||
|
/// Input code files
|
||||||
|
#[arg(required=true, num_args=1..)]
|
||||||
|
pub input: Vec<Utf8PathBuf>,
|
||||||
|
|
||||||
|
#[clap(skip)]
|
||||||
|
pub passthrough: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl CliArgs {
|
||||||
|
pub fn parse_with_passthrough() -> Self {
|
||||||
|
let mut clap_args = Vec::new();
|
||||||
|
let mut pt_args = Vec::new();
|
||||||
|
let mut switch = false;
|
||||||
|
for arg in std::env::args() {
|
||||||
|
if arg == String::from("--") {
|
||||||
|
switch = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !switch {
|
||||||
|
//clap args
|
||||||
|
clap_args.push(arg);
|
||||||
|
} else {
|
||||||
|
// passwthrough
|
||||||
|
pt_args.push(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cargs = Self::parse_from(clap_args);
|
||||||
|
cargs.passthrough = pt_args;
|
||||||
|
|
||||||
|
cargs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum CompilationTarget {
|
||||||
|
X86_64_linux_nasm
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ValueEnum for CompilationTarget {
|
||||||
|
fn value_variants<'a>() -> &'a [Self] {
|
||||||
|
&[
|
||||||
|
Self::X86_64_linux_nasm
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
|
||||||
|
match self {
|
||||||
|
CompilationTarget::X86_64_linux_nasm => Some(PossibleValue::new("x86_64-linux-nasm")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CompilationTarget {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
let r = match self {
|
||||||
|
CompilationTarget::X86_64_linux_nasm => "x86_64-linux-nasm",
|
||||||
|
};
|
||||||
|
write!(f, "{}", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl From<CompilationTarget> for clap::builder::OsStr {
|
||||||
|
// fn from(value: CompilationTarget) -> Self {
|
||||||
|
// match value {
|
||||||
|
// CompilationTarget::X86_64_linux_nasm => "X86_64_linux_nasm".into()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl TryFrom<&str> for CompilationTarget {
|
||||||
|
// type Error = anyhow::Error;
|
||||||
|
// fn try_from(value: &str) -> Result<Self, Error> {
|
||||||
|
// match value {
|
||||||
|
// "X86_64_linux_nasm" => Ok(CompilationTarget::X86_64_linux_nasm)
|
||||||
|
// _ => bail!("Unknown compilation target {value}")
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
use std::path::{PathBuf, Path};
|
|
||||||
use std::process::{Command, Stdio};
|
|
||||||
use color_eyre::Result;
|
|
||||||
use crate::info;
|
|
||||||
|
|
||||||
pub fn linux_x86_64_compile_and_link(of_a: &Path, of_o: &Path, of_c: &Path, quiet: bool) -> Result<()> {
|
|
||||||
|
|
||||||
let nasm_args = [
|
|
||||||
"-felf64",
|
|
||||||
of_a.to_str().unwrap(),
|
|
||||||
"-o",
|
|
||||||
of_o.to_str().unwrap()
|
|
||||||
];
|
|
||||||
|
|
||||||
let ld_args = [
|
|
||||||
of_o.to_str().unwrap(),
|
|
||||||
"-o",
|
|
||||||
of_c.to_str().unwrap()
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
let mut proc = if cfg!(target_os = "windows") {
|
|
||||||
return Ok(());
|
|
||||||
} else {
|
|
||||||
Command::new("nasm")
|
|
||||||
.args(nasm_args)
|
|
||||||
.stdout(Stdio::inherit())
|
|
||||||
.stderr(Stdio::inherit())
|
|
||||||
.spawn()?
|
|
||||||
};
|
|
||||||
if !quiet {
|
|
||||||
info!("running 'nasm {}'", nasm_args.join(" "));
|
|
||||||
}
|
|
||||||
let exit = proc.wait()?;
|
|
||||||
|
|
||||||
if !quiet {
|
|
||||||
info!("nasm process exited with code {}", exit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let mut proc2 = if cfg!(target_os = "windows") {
|
|
||||||
return Ok(());
|
|
||||||
} else {
|
|
||||||
Command::new("ld")
|
|
||||||
.args(ld_args)
|
|
||||||
.stdout(Stdio::inherit())
|
|
||||||
.stderr(Stdio::inherit())
|
|
||||||
.spawn()?
|
|
||||||
};
|
|
||||||
if !quiet {
|
|
||||||
info!("running 'ld {}'", ld_args.join(" "));
|
|
||||||
}
|
|
||||||
let exit2 = proc2.wait()?;
|
|
||||||
if !quiet {
|
|
||||||
info!("ld process exited with code {}", exit2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn linux_x86_64_run(bin: &Path, args: &[String], quiet: bool) -> Result<i32> {
|
|
||||||
|
|
||||||
let bin = PathBuf::from(
|
|
||||||
format!("./{}", bin.to_string_lossy())
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut proc = if cfg!(target_os = "windows") {
|
|
||||||
return Ok(0);
|
|
||||||
} else {
|
|
||||||
Command::new(bin.clone())
|
|
||||||
.args(args)
|
|
||||||
.stdout(Stdio::inherit())
|
|
||||||
.stderr(Stdio::inherit())
|
|
||||||
.spawn()?
|
|
||||||
};
|
|
||||||
// println!("{}", quiet);
|
|
||||||
if !quiet {
|
|
||||||
info!("running {} {}", bin.to_string_lossy(), args.join(" "));
|
|
||||||
}
|
|
||||||
let exit = proc.wait()?;
|
|
||||||
if !quiet {
|
|
||||||
info!("{} process exited with code {}", bin.to_string_lossy(), exit);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(exit.code().unwrap_or(0))
|
|
||||||
}
|
|
|
@ -1,661 +0,0 @@
|
||||||
use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap};
|
|
||||||
use crate::{constants::{Operator, OpType, KeywordType}, Args, warn, lerror};
|
|
||||||
use color_eyre::Result;
|
|
||||||
use crate::compile::commands::linux_x86_64_compile_and_link;
|
|
||||||
use crate::constants::InstructionType;
|
|
||||||
use super::{commands::linux_x86_64_run, Constant, Memory, Function};
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
|
|
||||||
pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|
||||||
let debug = args.get_opt_level()? < 1;
|
|
||||||
|
|
||||||
let mut of_c = PathBuf::from(&args.out_file);
|
|
||||||
let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE {
|
|
||||||
let of_o = PathBuf::from("/tmp/mclang_comp.o");
|
|
||||||
let of_a = PathBuf::from("/tmp/mclang_comp.nasm");
|
|
||||||
(of_o, of_a)
|
|
||||||
} else {
|
|
||||||
let of_o = PathBuf::from(&args.out_file);
|
|
||||||
let of_a = PathBuf::from(&args.out_file);
|
|
||||||
(of_o, of_a)
|
|
||||||
};
|
|
||||||
|
|
||||||
of_c.set_extension("");
|
|
||||||
of_o.set_extension("o");
|
|
||||||
of_a.set_extension("nasm");
|
|
||||||
|
|
||||||
let mut should_push_ret = false;
|
|
||||||
|
|
||||||
let file = fs::File::create(&of_a)?;
|
|
||||||
let mut writer = BufWriter::new(&file);
|
|
||||||
let mut memories: Vec<Memory> = Vec::new();
|
|
||||||
let mut constants: HashMap<String, Constant> = HashMap::new();
|
|
||||||
let mut functions: Vec<Function> = Vec::new();
|
|
||||||
// println!("{}", tokens.len());
|
|
||||||
let mut strings: Vec<String> = Vec::new();
|
|
||||||
|
|
||||||
writeln!(writer, "BITS 64")?;
|
|
||||||
writeln!(writer, "segment .text")?;
|
|
||||||
|
|
||||||
writeln!(writer, "_dbg_print:")?;
|
|
||||||
writeln!(writer, " mov r9, -3689348814741910323")?;
|
|
||||||
writeln!(writer, " sub rsp, 40")?;
|
|
||||||
writeln!(writer, " mov BYTE [rsp+31], 10")?;
|
|
||||||
writeln!(writer, " lea rcx, [rsp+30]")?;
|
|
||||||
writeln!(writer, ".L2:")?;
|
|
||||||
writeln!(writer, " mov rax, rdi")?;
|
|
||||||
writeln!(writer, " lea r8, [rsp+32]")?;
|
|
||||||
writeln!(writer, " mul r9")?;
|
|
||||||
writeln!(writer, " mov rax, rdi")?;
|
|
||||||
writeln!(writer, " sub r8, rcx")?;
|
|
||||||
writeln!(writer, " shr rdx, 3")?;
|
|
||||||
writeln!(writer, " lea rsi, [rdx+rdx*4]")?;
|
|
||||||
writeln!(writer, " add rsi, rsi")?;
|
|
||||||
writeln!(writer, " sub rax, rsi")?;
|
|
||||||
writeln!(writer, " add eax, 48")?;
|
|
||||||
writeln!(writer, " mov BYTE [rcx], al")?;
|
|
||||||
writeln!(writer, " mov rax, rdi")?;
|
|
||||||
writeln!(writer, " mov rdi, rdx")?;
|
|
||||||
writeln!(writer, " mov rdx, rcx")?;
|
|
||||||
writeln!(writer, " sub rcx, 1")?;
|
|
||||||
writeln!(writer, " cmp rax, 9")?;
|
|
||||||
writeln!(writer, " ja .L2")?;
|
|
||||||
writeln!(writer, " lea rax, [rsp+32]")?;
|
|
||||||
writeln!(writer, " mov edi, 1")?;
|
|
||||||
writeln!(writer, " sub rdx, rax")?;
|
|
||||||
writeln!(writer, " xor eax, eax")?;
|
|
||||||
writeln!(writer, " lea rsi, [rsp+32+rdx]")?;
|
|
||||||
writeln!(writer, " mov rdx, r8")?;
|
|
||||||
writeln!(writer, " mov rax, 1")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " add rsp, 40")?;
|
|
||||||
writeln!(writer, " ret")?;
|
|
||||||
|
|
||||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
|
||||||
writeln!(writer, "global _start")?;
|
|
||||||
writeln!(writer, "_start:")?;
|
|
||||||
writeln!(writer, " lea rbp, [rel ret_stack]")?;
|
|
||||||
writeln!(writer, " call main")?;
|
|
||||||
writeln!(writer, " jmp end")?;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let mut ti = 0;
|
|
||||||
while ti < tokens.len() {
|
|
||||||
let token = &tokens[ti];
|
|
||||||
// println!("{:?}", token);
|
|
||||||
if debug {
|
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
|
||||||
if token.typ == OpType::Instruction(InstructionType::PushInt) {
|
|
||||||
writeln!(writer, " ;; -- {:?} {}", token.typ, token.value)?;
|
|
||||||
} else if token.typ == OpType::Instruction(InstructionType::PushStr) {
|
|
||||||
writeln!(writer, " ;; -- {:?} {}", token.typ, token.text.escape_debug())?;
|
|
||||||
} else {
|
|
||||||
writeln!(writer, " ;; -- {:?}", token.typ)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ti > 0 {
|
|
||||||
if tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) ||
|
|
||||||
tokens[ti-1].typ == OpType::Keyword(KeywordType::End){
|
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) {
|
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let OpType::Keyword(keyword) = &token.typ {
|
|
||||||
match keyword {
|
|
||||||
&KeywordType::End |
|
|
||||||
&KeywordType::While => {
|
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
match token.typ.clone() {
|
|
||||||
// stack
|
|
||||||
|
|
||||||
OpType::Instruction(instruction) => {
|
|
||||||
match instruction {
|
|
||||||
InstructionType::PushInt => {
|
|
||||||
writeln!(writer, " mov rax, {}", token.value)?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::PushStr => {
|
|
||||||
writeln!(writer, " mov rax, {}", token.text.len())?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " mov rax, str_{}", strings.len())?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
strings.push(token.text.clone());
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Drop => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Print => {
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " call _dbg_print")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Dup => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Rot => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rcx")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Swap => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Over => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Load8 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " xor rbx, rbx")?;
|
|
||||||
writeln!(writer, " mov bl, byte [rax]")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Store8 => {
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " mov byte [rax], bl")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Load32 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " xor rbx, rbx")?;
|
|
||||||
writeln!(writer, " mov bl, dword [rax]")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Store32 => {
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " mov dword[rax], bl")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Load64 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " xor rbx, rbx")?;
|
|
||||||
writeln!(writer, " mov bl, qword [rax]")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Store64 => {
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " mov qword [rax], bl")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// math
|
|
||||||
InstructionType::Plus => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " add rax, rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Minus => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " sub rbx, rax")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Equals => {
|
|
||||||
writeln!(writer, " mov rcx, 0")?;
|
|
||||||
writeln!(writer, " mov rdx, 1")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmove rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Lt => {
|
|
||||||
writeln!(writer, " mov rcx, 0")?;
|
|
||||||
writeln!(writer, " mov rdx, 1")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmovl rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Gt => {
|
|
||||||
writeln!(writer, " mov rcx, 0")?;
|
|
||||||
writeln!(writer, " mov rdx, 1")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmovg rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::NotEquals => {
|
|
||||||
writeln!(writer, " mov rcx, 1")?;
|
|
||||||
writeln!(writer, " mov rdx, 0")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmove rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Le => {
|
|
||||||
writeln!(writer, " mov rcx, 0")?;
|
|
||||||
writeln!(writer, " mov rdx, 1")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmovle rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Ge => {
|
|
||||||
writeln!(writer, " mov rcx, 0")?;
|
|
||||||
writeln!(writer, " mov rdx, 1")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " cmp rax, rbx")?;
|
|
||||||
writeln!(writer, " cmovge rcx, rdx")?;
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Band => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " and rbx, rax")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Bor => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " or rbx, rax")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Shr => {
|
|
||||||
writeln!(writer, " pop rcx")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " shr rbx, cl")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Shl => {
|
|
||||||
writeln!(writer, " pop rcx")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " shl rbx, cl")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::DivMod => {
|
|
||||||
writeln!(writer, " xor rdx, rdx")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " div rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
writeln!(writer, " push rdx")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Mul => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " mul rbx")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall0 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall1 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall2 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " pop rsi")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall3 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " pop rsi")?;
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall4 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " pop rsi")?;
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
writeln!(writer, " pop r10")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall5 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " pop rsi")?;
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
writeln!(writer, " pop r10")?;
|
|
||||||
writeln!(writer, " pop r8")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall6 => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " pop rdi")?;
|
|
||||||
writeln!(writer, " pop rsi")?;
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
writeln!(writer, " pop r10")?;
|
|
||||||
writeln!(writer, " pop r8")?;
|
|
||||||
writeln!(writer, " pop r9")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::MemUse => {
|
|
||||||
writeln!(writer, " push mem_{}", token.addr.unwrap())?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::None => {
|
|
||||||
println!("{token:?}");
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
InstructionType::FnCall => {
|
|
||||||
writeln!(writer, " call {}", token.text)?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Return => {
|
|
||||||
|
|
||||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret {
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
should_push_ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(writer, " sub rbp, 8")?;
|
|
||||||
writeln!(writer, " mov rbx, qword [rbp]")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
writeln!(writer, " ret")?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::CastBool |
|
|
||||||
InstructionType::CastPtr |
|
|
||||||
InstructionType::CastInt |
|
|
||||||
InstructionType::CastVoid |
|
|
||||||
InstructionType::TypeBool |
|
|
||||||
InstructionType::TypePtr |
|
|
||||||
InstructionType::TypeInt |
|
|
||||||
InstructionType::TypeVoid |
|
|
||||||
InstructionType::TypeAny |
|
|
||||||
InstructionType::Returns |
|
|
||||||
InstructionType::With => {
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
InstructionType::ConstUse => {
|
|
||||||
writeln!(writer, " mov rax, qword [const_{}]", token.text)?;
|
|
||||||
writeln!(writer, " push rax")?;
|
|
||||||
|
|
||||||
let mut c = constants.get(&token.text).unwrap().clone();
|
|
||||||
c.used = true;
|
|
||||||
constants.remove(&token.text);
|
|
||||||
constants.insert(token.text.clone(), c);
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
OpType::Keyword(keyword) => {
|
|
||||||
match keyword {
|
|
||||||
|
|
||||||
// block
|
|
||||||
KeywordType::If |
|
|
||||||
KeywordType::Do => {
|
|
||||||
writeln!(writer, " pop rax")?;
|
|
||||||
writeln!(writer, " test rax, rax")?;
|
|
||||||
writeln!(writer, " jz addr_{}", token.jmp)?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
KeywordType::Else => {
|
|
||||||
writeln!(writer, " jmp addr_{}", token.jmp)?;
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
KeywordType::While => {
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
KeywordType::End => {
|
|
||||||
if ti + 1 != token.jmp {
|
|
||||||
// writeln!(writer, " jmp addr_{}", token.jmp)?;
|
|
||||||
}
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
KeywordType::Memory => {
|
|
||||||
memories.push(Memory { size: token.value, loc: token.loc.clone(), id: token.addr.unwrap() });
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
KeywordType::ConstantDef => {
|
|
||||||
// TODO: after we add c style strings add supoort for them in constants
|
|
||||||
let a = args.get_opt_level()? < 1;
|
|
||||||
let c = Constant{
|
|
||||||
loc: token.loc.clone(),
|
|
||||||
name: token.text.clone(),
|
|
||||||
value_i: Some(token.value),
|
|
||||||
value_s: None,
|
|
||||||
used: a,
|
|
||||||
};
|
|
||||||
|
|
||||||
constants.insert(token.text.clone(), c);
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
KeywordType::FunctionDef => {
|
|
||||||
writeln!(writer, "{}:", token.text)?;
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " mov qword [rbp], rbx")?;
|
|
||||||
writeln!(writer, " add rbp, 8")?;
|
|
||||||
functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false});
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
KeywordType::FunctionDone => {
|
|
||||||
|
|
||||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret {
|
|
||||||
writeln!(writer, " pop rdx")?;
|
|
||||||
should_push_ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(writer, " sub rbp, 8")?;
|
|
||||||
writeln!(writer, " mov rbx, qword [rbp]")?;
|
|
||||||
writeln!(writer, " push rbx")?;
|
|
||||||
writeln!(writer, " ret")?;
|
|
||||||
ti += 1;
|
|
||||||
}
|
|
||||||
KeywordType::FunctionThen => ti += 1,
|
|
||||||
KeywordType::Function |
|
|
||||||
KeywordType::Include |
|
|
||||||
KeywordType::Inline |
|
|
||||||
KeywordType::Export |
|
|
||||||
KeywordType::Constant => unreachable!(),
|
|
||||||
KeywordType::FunctionDefExported => {
|
|
||||||
|
|
||||||
if !crate::config::ENABLE_EXPORTED_FUNCTIONS {
|
|
||||||
lerror!(&token.loc, "Experimental feature 'exported functions' is not enabled");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
writeln!(writer, "global {}", token.text)?;
|
|
||||||
writeln!(writer, "{}:", token.text)?;
|
|
||||||
|
|
||||||
writeln!(writer, " pop rbx")?;
|
|
||||||
writeln!(writer, " mov qword [rbp], rbx")?;
|
|
||||||
writeln!(writer, " add rbp, 8")?;
|
|
||||||
warn!("External functions are highly experimental and should be treated as such");
|
|
||||||
if token.types.0 == 0 {
|
|
||||||
writeln!(writer, " ; no arguments")?;
|
|
||||||
} else {
|
|
||||||
if token.types.0 >= 1 {
|
|
||||||
writeln!(writer, " push rdi")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 2 {
|
|
||||||
writeln!(writer, " push rsi")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 3 {
|
|
||||||
writeln!(writer, " push rdx")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 4 {
|
|
||||||
writeln!(writer, " push rcx")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 5 {
|
|
||||||
writeln!(writer, " push r8")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 6 {
|
|
||||||
writeln!(writer, " push r9")?;
|
|
||||||
}
|
|
||||||
if token.types.0 >= 7 {
|
|
||||||
lerror!(&token.loc, "More than 6 arguments in an external function is not supported");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if token.types.1 == 1 {
|
|
||||||
should_push_ret = true;
|
|
||||||
} else if token.types.1 > 1 {
|
|
||||||
lerror!(&token.loc, "More than 1 return arguments in an external function is not supported");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false});
|
|
||||||
ti += 1;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
|
||||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
|
||||||
writeln!(writer, "end:")?;
|
|
||||||
writeln!(writer, " mov rax, 60")?;
|
|
||||||
writeln!(writer, " mov rdi, 0")?;
|
|
||||||
writeln!(writer, " syscall")?;
|
|
||||||
}
|
|
||||||
writeln!(writer, "segment .data")?;
|
|
||||||
for (i, s) in strings.iter().enumerate() {
|
|
||||||
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
|
||||||
let s_list = s_chars.join(",");
|
|
||||||
writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (_, c) in constants {
|
|
||||||
if !c.used {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(v) = &c.value_i {
|
|
||||||
writeln!(writer, " const_{}: dq {}", c.name, v)?;
|
|
||||||
} else if let Some(_v) = &c.value_s {
|
|
||||||
todo!();
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
writeln!(writer, "segment .bss")?;
|
|
||||||
for s in memories {
|
|
||||||
writeln!(writer, " mem_{}: resb {}", s.id, s.size)?;
|
|
||||||
}
|
|
||||||
writeln!(writer, " ret_stack: resq 256")?;
|
|
||||||
|
|
||||||
// for t in tokens {
|
|
||||||
// println!("{t:?}");
|
|
||||||
// }
|
|
||||||
|
|
||||||
writer.flush()?;
|
|
||||||
|
|
||||||
|
|
||||||
pre_compile_steps(
|
|
||||||
String::from_utf8_lossy(writer.buffer()).to_string().as_str(),
|
|
||||||
functions
|
|
||||||
)?;
|
|
||||||
|
|
||||||
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
|
|
||||||
if args.run {
|
|
||||||
let c = linux_x86_64_run(&of_c, &[], args.quiet)?;
|
|
||||||
return Ok(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn pre_compile_steps(_code: &str, functions: Vec<Function>) -> Result<()> {
|
|
||||||
let mut has_main = false;
|
|
||||||
|
|
||||||
for func in functions {
|
|
||||||
if func.name == "main" {
|
|
||||||
has_main = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if !has_main {
|
|
||||||
crate::errors::missing_main_fn();
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
use crate::constants::Loc;
|
|
||||||
|
|
||||||
pub mod linux_x86_64;
|
|
||||||
pub mod commands;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Constant {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String,
|
|
||||||
pub value_i: Option<usize>,
|
|
||||||
pub value_s: Option<String>,
|
|
||||||
pub used: bool
|
|
||||||
// extern: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Memory {
|
|
||||||
pub size: usize,
|
|
||||||
pub loc: Loc,
|
|
||||||
pub id: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String,
|
|
||||||
pub exter: bool,
|
|
||||||
}
|
|
104
src/compiler/mod.rs
Normal file
104
src/compiler/mod.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
mod x86_64_linux_nasm;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
|
use crate::{cli::{CliArgs, CompilationTarget}, types::ast::Program};
|
||||||
|
use std::{collections::HashMap, fs::File, io::{BufWriter, Write}, path::{Path, PathBuf}, process::Command};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub trait Compiler {
|
||||||
|
fn new() -> Self;
|
||||||
|
fn generate_asm(&mut self, prog: &Program, fd: &mut BufWriter<File>) -> anyhow::Result<()>;
|
||||||
|
fn compile(&mut self, asm_fp: &Path, obj: &Path) -> anyhow::Result<()>;
|
||||||
|
fn link(&mut self, obj_files: Vec<PathBuf>, bin_fp: &Path) -> anyhow::Result<()>;
|
||||||
|
/// Return programs that are needed
|
||||||
|
fn needed_dependencies(&mut self) -> Vec<&str>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//NOTE: No bsd cause im not about to create 3 or 4 diffrent compilation targets
|
||||||
|
|
||||||
|
pub fn compile_program(cli_args: &CliArgs, prog_map: HashMap<&Path, Program>) -> anyhow::Result<()> {
|
||||||
|
let mut compiler = match cli_args.target {
|
||||||
|
CompilationTarget::X86_64_linux_nasm => x86_64_linux_nasm::X86_64LinuxNasmCompiler::new(),
|
||||||
|
};
|
||||||
|
let bin_p = cli_args.output.as_std_path();
|
||||||
|
let mut objs = Vec::new();
|
||||||
|
for (k, v) in prog_map {
|
||||||
|
let mut asm_p = k.to_path_buf();
|
||||||
|
let mut obj_p = k.to_path_buf();
|
||||||
|
|
||||||
|
asm_p.set_extension("s");
|
||||||
|
obj_p.set_extension("o");
|
||||||
|
|
||||||
|
|
||||||
|
if let Err(_) = compile_file(&mut compiler, cli_args, asm_p.as_path(), obj_p.as_path(), &v) {
|
||||||
|
error!("Failed to compile file {k:?}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
objs.push(obj_p.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = compiler.link(objs, bin_p) {
|
||||||
|
error!("Failed to link program: {e}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Finished building program");
|
||||||
|
|
||||||
|
if cli_args.run {
|
||||||
|
// run_cmd(format!("./{}", bin_p.to_string_lossy()), cli_args.passthrough.clone())?;
|
||||||
|
let bin = bin_p.to_string_lossy().to_string();
|
||||||
|
let mut cmd = Command::new(format!("./{}", bin.clone()));
|
||||||
|
let cmd = cmd.args(cli_args.passthrough.clone());
|
||||||
|
|
||||||
|
let child = match cmd.spawn() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Unable to run {cmd:?}: {e}");
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ret = child.wait_with_output().expect("fuck i know");
|
||||||
|
|
||||||
|
|
||||||
|
if !ret.status.success() {
|
||||||
|
error!("Process running {bin:?} exited abnormaly, run with -v 2 for more output");
|
||||||
|
bail!("")
|
||||||
|
} else {
|
||||||
|
info!("Process exited successfully")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile_file<C: Compiler>(compiler: &mut C, _: &CliArgs, asm_file: &Path, obj_file: &Path, prog: &Program) -> anyhow::Result<()> {
|
||||||
|
|
||||||
|
let asm_fd = std::fs::File::options()
|
||||||
|
.write(true)
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.truncate(true)
|
||||||
|
.append(false)
|
||||||
|
.open(asm_file);
|
||||||
|
|
||||||
|
let asm_fd = match asm_fd {
|
||||||
|
Ok(fd) => fd,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to open file {asm_file:?}: {e}");
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buf_asm_fd = BufWriter::new(asm_fd);
|
||||||
|
|
||||||
|
compiler.generate_asm(prog, &mut buf_asm_fd)?;
|
||||||
|
buf_asm_fd.flush()?;
|
||||||
|
|
||||||
|
compiler.compile(asm_file, obj_file)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
36
src/compiler/utils.rs
Normal file
36
src/compiler/utils.rs
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
use std::{fmt::Debug, process::{Command, Stdio}};
|
||||||
|
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn run_cmd<'a, S: Into<String> + Debug + Clone>(bin: S, args: Vec<String>) -> anyhow::Result<()> {
|
||||||
|
let debug = unsafe {
|
||||||
|
crate::logger::LOGGER.enabled(crate::logger::Level::Debug)
|
||||||
|
};
|
||||||
|
let mut cmd = Command::new(bin.clone().into());
|
||||||
|
let cmd = cmd.args(args);
|
||||||
|
let cmd = if debug {
|
||||||
|
cmd.stdout(Stdio::inherit())
|
||||||
|
} else {
|
||||||
|
cmd.stdout(Stdio::null())
|
||||||
|
};
|
||||||
|
let cmd = cmd.stderr(Stdio::inherit());
|
||||||
|
|
||||||
|
let child = match cmd.spawn() {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Unable to run {cmd:?}: {e}");
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ret = child.wait_with_output().expect("fuck i know");
|
||||||
|
|
||||||
|
|
||||||
|
if !ret.status.success() {
|
||||||
|
error!("Process running {bin:?} exited abnormaly, run with -v 2 for more output");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
521
src/compiler/x86_64_linux_nasm/mod.rs
Normal file
521
src/compiler/x86_64_linux_nasm/mod.rs
Normal file
|
@ -0,0 +1,521 @@
|
||||||
|
mod utils;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs::File, io::BufWriter, path::Path};
|
||||||
|
use std::io::Write;
|
||||||
|
use crate::types::ast::{AstNode, EscIdent, Function, MemSize, Module, Program};
|
||||||
|
use crate::types::token::{InstructionType, Token, TokenType};
|
||||||
|
|
||||||
|
use super::utils::run_cmd;
|
||||||
|
use super::Compiler;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct X86_64LinuxNasmCompiler {
|
||||||
|
strings: Vec<String>,
|
||||||
|
// func_mem_i: Vec<usize>,
|
||||||
|
// func_mem_list: HashMap<String, usize>,
|
||||||
|
if_i: usize,
|
||||||
|
while_i: usize,
|
||||||
|
used_consts: Vec<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl X86_64LinuxNasmCompiler {
|
||||||
|
fn handle_token(&mut self, fd: &mut BufWriter<File>, _: &Program, token: &Token) -> anyhow::Result<()> {
|
||||||
|
match &token.typ {
|
||||||
|
TokenType::Instruction(it) => {
|
||||||
|
match it {
|
||||||
|
InstructionType::PushInt(i) => {
|
||||||
|
writeln!(fd, " mov rax, {i} ; PUSHINT({i})")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::PushStr(s) => {
|
||||||
|
writeln!(fd, " push {}", s.len())?;
|
||||||
|
writeln!(fd, " push str_{}; PUSHSTR({})", self.strings.len(), s.escape_debug())?;
|
||||||
|
self.strings.push(s.clone());
|
||||||
|
},
|
||||||
|
InstructionType::PushCStr(s) => {
|
||||||
|
writeln!(fd, " push str_{}; PUSHCSTR({})", self.strings.len(), s.escape_debug())?;
|
||||||
|
self.strings.push(s.clone());
|
||||||
|
},
|
||||||
|
InstructionType::PushChar(c) => {
|
||||||
|
writeln!(fd, " push {}; PUSHCHAR({})", *c as u8, c.escape_debug())?;
|
||||||
|
},
|
||||||
|
InstructionType::Drop => {
|
||||||
|
writeln!(fd, " pop rax ; DROP")?;
|
||||||
|
},
|
||||||
|
InstructionType::Print => {
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " call _dbg_print ; _DBG_PRINT")?;
|
||||||
|
},
|
||||||
|
InstructionType::Dup => {
|
||||||
|
writeln!(fd, " pop rax ; DUP")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Rot => {
|
||||||
|
writeln!(fd, " pop rax ; ROT")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rcx")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Over => {
|
||||||
|
writeln!(fd, " pop rax ; OVER")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Swap => {
|
||||||
|
writeln!(fd, " pop rax ; SWAP")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
}
|
||||||
|
InstructionType::Minus => {
|
||||||
|
writeln!(fd, " pop rax ; SUB")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " sub rbx, rax")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Plus => {
|
||||||
|
writeln!(fd, " pop rax ; ADD")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " add rax, rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Equals => {
|
||||||
|
writeln!(fd, " mov rcx, 0 ; EQ")?;
|
||||||
|
writeln!(fd, " mov rdx, 1")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmove rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Gt => {
|
||||||
|
writeln!(fd, " mov rcx, 0 ; GT")?;
|
||||||
|
writeln!(fd, " mov rdx, 1")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmovg rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Lt => {
|
||||||
|
writeln!(fd, " mov rcx, 0 ; LT")?;
|
||||||
|
writeln!(fd, " mov rdx, 1")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmovl rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Ge => {
|
||||||
|
writeln!(fd, " mov rcx, 0 ; GE")?;
|
||||||
|
writeln!(fd, " mov rdx, 1")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmovge rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Le => {
|
||||||
|
writeln!(fd, " mov rcx, 0 ; LE")?;
|
||||||
|
writeln!(fd, " mov rdx, 1")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmovle rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::NotEquals => {
|
||||||
|
writeln!(fd, " mov rdx, 1 ; NEQ")?;
|
||||||
|
writeln!(fd, " mov rcx, 0")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " cmp rax, rbx")?;
|
||||||
|
writeln!(fd, " cmove rcx, rdx")?;
|
||||||
|
writeln!(fd, " push rcx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Band => {
|
||||||
|
writeln!(fd, " pop rax ; BAND")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " and rbx, rax")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Bor => {
|
||||||
|
writeln!(fd, " pop rax ; BOR")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " or rbx, rax")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
}
|
||||||
|
InstructionType::Shr => {
|
||||||
|
writeln!(fd, " pop rcx")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " shr rbx, cl")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Shl => {
|
||||||
|
writeln!(fd, " pop rcx")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " shl rbx, cl")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::DivMod => {
|
||||||
|
writeln!(fd, " xor rdx, rdx")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " div rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
writeln!(fd, " push rdx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Mul => {
|
||||||
|
writeln!(fd, " pop rax ; MUL")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " mul rbx")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Read8 => {
|
||||||
|
writeln!(fd, " pop rax ; READ8")?;
|
||||||
|
writeln!(fd, " xor rbx, rbx")?;
|
||||||
|
writeln!(fd, " mov bl, byte [rax]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
}
|
||||||
|
InstructionType::Write8 => {
|
||||||
|
writeln!(fd, " pop rax ; WRITE 8")?;
|
||||||
|
writeln!(fd, " xor rbx, rbx")?;
|
||||||
|
writeln!(fd, " mov ebx, dword [rax]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Read32 => {
|
||||||
|
writeln!(fd, " pop rax ; READ 32")?;
|
||||||
|
writeln!(fd, " xor rbx, rbx")?;
|
||||||
|
writeln!(fd, " mov ebx, dword [rax]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Write32 => {
|
||||||
|
writeln!(fd, " pop rbx ; WRITE 32")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " mov dword[rax], ebx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Read64 => {
|
||||||
|
writeln!(fd, " pop rax ; READ 32")?;
|
||||||
|
writeln!(fd, " xor rbx, rbx")?;
|
||||||
|
writeln!(fd, " mov rbx, qword [rax]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Write64 => {
|
||||||
|
writeln!(fd, " pop rbx ; WRITE 64")?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " mov qword[rax], rbx")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall0 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall1 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall2 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " pop rsi")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall3 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " pop rsi")?;
|
||||||
|
writeln!(fd, " pop rdx")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall4 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " pop rsi")?;
|
||||||
|
writeln!(fd, " pop rdx")?;
|
||||||
|
writeln!(fd, " pop r10")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall5 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " pop rsi")?;
|
||||||
|
writeln!(fd, " pop rdx")?;
|
||||||
|
writeln!(fd, " pop r10")?;
|
||||||
|
writeln!(fd, " pop r8")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::Syscall6 => {
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " pop rdi")?;
|
||||||
|
writeln!(fd, " pop rsi")?;
|
||||||
|
writeln!(fd, " pop rdx")?;
|
||||||
|
writeln!(fd, " pop r10")?;
|
||||||
|
writeln!(fd, " pop r8")?;
|
||||||
|
writeln!(fd, " pop r9")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
InstructionType::CastBool |
|
||||||
|
InstructionType::CastPtr |
|
||||||
|
InstructionType::CastInt |
|
||||||
|
InstructionType::CastVoid => (), //? Possibly have a use for this
|
||||||
|
InstructionType::FnCall |
|
||||||
|
InstructionType::MemUse |
|
||||||
|
InstructionType::StructPath(_) |
|
||||||
|
InstructionType::StructItem(_) |
|
||||||
|
InstructionType::ConstUse => unreachable!(),
|
||||||
|
InstructionType::Return => {
|
||||||
|
writeln!(fd, " sub rbp, 8")?;
|
||||||
|
writeln!(fd, " mov rbx, qword [rbp]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
writeln!(fd, " ret")?;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TokenType::Keyword(_) |
|
||||||
|
TokenType::Type(_) |
|
||||||
|
TokenType::Unknown(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_module(&mut self, fd: &mut BufWriter<File>, prog: &Program, module: &Module) -> anyhow::Result<()> {
|
||||||
|
writeln!(fd, "; {} Module START", module.path.join("::"))?;
|
||||||
|
self.handle_ast_list(fd, prog, module.body.clone())?;
|
||||||
|
writeln!(fd, "; {} Module END", module.path.join("::"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_function(&mut self, fd: &mut BufWriter<File>, prog: &Program, func: &Function) -> anyhow::Result<()> {
|
||||||
|
writeln!(fd, "{f}: ; fn {f}", f=func.get_ident_escaped())?;
|
||||||
|
writeln!(fd, " fn_setup")?;
|
||||||
|
|
||||||
|
self.handle_ast_list(fd, prog, func.body.clone())?;
|
||||||
|
|
||||||
|
writeln!(fd, " fn_cleanup")?;
|
||||||
|
writeln!(fd, " ret")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_ast_list(&mut self, fd: &mut BufWriter<File>, prog: &Program, ast: Vec<AstNode>) -> anyhow::Result<()> {
|
||||||
|
for node in ast {
|
||||||
|
match &node {
|
||||||
|
AstNode::Function(f) => self.handle_function(fd, prog, f)?,
|
||||||
|
AstNode::Constant(_) => (),
|
||||||
|
AstNode::If(i) => {
|
||||||
|
let id = self.if_i;
|
||||||
|
self.if_i += 1;
|
||||||
|
|
||||||
|
writeln!(fd, "; IF({id}) START")?;
|
||||||
|
self.handle_ast_list(fd, prog, i.test.clone())?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " test rax, rax")?;
|
||||||
|
writeln!(fd, " jz if_{id}_else")?;
|
||||||
|
writeln!(fd, "if_{id}_start:")?;
|
||||||
|
self.handle_ast_list(fd, prog, i.body.clone())?;
|
||||||
|
writeln!(fd, " jmp if_{id}_end")?;
|
||||||
|
writeln!(fd, "if_{id}_else:")?;
|
||||||
|
self.handle_ast_list(fd, prog, vec![Box::leak(i.els.clone()).clone()])?;
|
||||||
|
writeln!(fd, "if_{id}_end:")?;
|
||||||
|
writeln!(fd, "; IF({id}) END")?;
|
||||||
|
},
|
||||||
|
AstNode::While(w) => {
|
||||||
|
let id = self.while_i;
|
||||||
|
self.while_i += 1;
|
||||||
|
writeln!(fd, "; WHILE({id}) START")?;
|
||||||
|
writeln!(fd, "while_{id}_test:")?;
|
||||||
|
self.handle_ast_list(fd, prog, w.test.clone())?;
|
||||||
|
writeln!(fd, " pop rax")?;
|
||||||
|
writeln!(fd, " test rax, rax")?;
|
||||||
|
writeln!(fd, " jz while_{id}_exit")?;
|
||||||
|
writeln!(fd, "while_{id}_start:")?;
|
||||||
|
self.handle_ast_list(fd, prog, w.body.clone())?;
|
||||||
|
writeln!(fd, "while_{id}_end:")?;
|
||||||
|
writeln!(fd, " jmp while_{id}_test")?;
|
||||||
|
writeln!(fd, "while_{id}_exit:")?;
|
||||||
|
writeln!(fd, "; WHILE({id}) END")?;
|
||||||
|
},
|
||||||
|
AstNode::Module(m) => self.handle_module(fd, prog, m)?,
|
||||||
|
AstNode::Memory(_) => {
|
||||||
|
//? Possibly allow stack based allocation somehow
|
||||||
|
// if !m.statc {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
AstNode::MemUse(m) => {
|
||||||
|
let tmp = if let Some(disp) = m.disp {
|
||||||
|
format!("+{disp}")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
writeln!(fd, " push m_{}{}", m.get_ident_escaped(), tmp)?;
|
||||||
|
},
|
||||||
|
AstNode::ConstUse(c) => {
|
||||||
|
self.used_consts.push(c.get_ident_escaped());
|
||||||
|
writeln!(fd, " mov rax, qword [c_{}]", c.get_ident_escaped())?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
AstNode::FnCall(f)=> {
|
||||||
|
writeln!(fd, " call {f} ; FUNCTIONCALL({f:?})", f=f.get_ident_escaped())?;
|
||||||
|
},
|
||||||
|
AstNode::Block(b)=> {
|
||||||
|
writeln!(fd, "; BLOCK({}) START", b.comment)?;
|
||||||
|
self.handle_ast_list(fd, prog, b.body.clone())?;
|
||||||
|
writeln!(fd, "; BLOCK({}) END", b.comment)?;
|
||||||
|
},
|
||||||
|
AstNode::Token(t) => self.handle_token(fd, prog, t)?,
|
||||||
|
AstNode::Int(_, _) |
|
||||||
|
AstNode::Str(_, _) |
|
||||||
|
AstNode::CStr(_, _) |
|
||||||
|
AstNode::Char(_, _) => unreachable!(),
|
||||||
|
AstNode::StructDef(_) => (),
|
||||||
|
AstNode::StructDispPush { disp, ident, .. } => {
|
||||||
|
writeln!(fd, " mov rax, {} ; STRUCTDISPPUSH({})", disp, ident)?;
|
||||||
|
writeln!(fd, " push rax")?;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Compiler for X86_64LinuxNasmCompiler {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
strings: Vec::new(),
|
||||||
|
used_consts: Vec::new(),
|
||||||
|
if_i: 0,
|
||||||
|
while_i: 0,
|
||||||
|
// func_mem_i: Vec::new(),
|
||||||
|
// func_mem_list: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_asm(&mut self, prog: &Program, fd: &mut BufWriter<File>) -> anyhow::Result<()> {
|
||||||
|
|
||||||
|
writeln!(fd, "BITS 64")?;
|
||||||
|
writeln!(fd, "segment .text")?;
|
||||||
|
|
||||||
|
writeln!(fd, "%macro fn_setup 0")?;
|
||||||
|
writeln!(fd, " pop rbx")?;
|
||||||
|
writeln!(fd, " mov qword [rbp], rbx")?;
|
||||||
|
writeln!(fd, " add rbp, 8")?;
|
||||||
|
writeln!(fd, "%endmacro")?;
|
||||||
|
writeln!(fd, "%macro fn_cleanup 0")?;
|
||||||
|
writeln!(fd, " sub rbp, 8")?;
|
||||||
|
writeln!(fd, " mov rbx, qword [rbp]")?;
|
||||||
|
writeln!(fd, " push rbx")?;
|
||||||
|
writeln!(fd, "%endmacro")?;
|
||||||
|
|
||||||
|
writeln!(fd, "{}", utils::DBG_PRINT)?;
|
||||||
|
writeln!(fd, "global _start")?;
|
||||||
|
writeln!(fd, "_start:")?;
|
||||||
|
writeln!(fd, " lea rbp, [rel ret_stack]")?;
|
||||||
|
writeln!(fd, " call main")?;
|
||||||
|
writeln!(fd, " jmp __MCL_END__")?;
|
||||||
|
|
||||||
|
match &prog.ast {
|
||||||
|
AstNode::Module(m) => {
|
||||||
|
self.handle_module(fd, prog, m)?;
|
||||||
|
},
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
writeln!(fd, "__MCL_END__:")?;
|
||||||
|
writeln!(fd, " mov rax, 60")?;
|
||||||
|
writeln!(fd, " mov rdi, 0")?;
|
||||||
|
writeln!(fd, " syscall")?;
|
||||||
|
|
||||||
|
writeln!(fd, "segment .data")?;
|
||||||
|
for (_, v) in prog.constants.iter() {
|
||||||
|
|
||||||
|
if !self.used_consts.contains(&v.get_ident_escaped()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match Box::leak(v.value.clone()) {
|
||||||
|
AstNode::Int(_, val) => {
|
||||||
|
writeln!(fd, " c_{}: dq {}", v.get_ident_escaped(), val)?;
|
||||||
|
}
|
||||||
|
AstNode::Str(_, val) |
|
||||||
|
AstNode::CStr(_, val) => {
|
||||||
|
let s_chars = val.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
||||||
|
let s_list = s_chars.join(",");
|
||||||
|
writeln!(fd, " c_{}: db {} ; {}", v.get_ident_escaped(), s_list, val.escape_debug())?;
|
||||||
|
}
|
||||||
|
AstNode::Char(_, val) => {
|
||||||
|
writeln!(fd, " c_{}: db {} ; '{}'", v.get_ident_escaped(), *val as u8, val)?;
|
||||||
|
}
|
||||||
|
c => panic!("{c:?}")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, s) in self.strings.iter().enumerate() {
|
||||||
|
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
||||||
|
let s_list = s_chars.join(",");
|
||||||
|
writeln!(fd, " str_{i}: db {} ; STRDEF({})", s_list, s.escape_debug())?;
|
||||||
|
}
|
||||||
|
writeln!(fd, "segment .bss")?;
|
||||||
|
writeln!(fd, " ret_stack: resq 256")?;
|
||||||
|
|
||||||
|
for (_, v) in &prog.memories {
|
||||||
|
match &v.size {
|
||||||
|
MemSize::Size(s) => {
|
||||||
|
writeln!(fd, " m_{}: resb {}", v.get_ident_escaped(), s)?;
|
||||||
|
},
|
||||||
|
MemSize::Type(tt) => {
|
||||||
|
writeln!(fd, " m_{}: resb {} ; {:?}", v.get_ident_escaped(), tt.get_size(), tt)?;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn compile(&mut self, asm_fp: &Path, obj_fp: &Path) -> anyhow::Result<()> {
|
||||||
|
run_cmd("nasm", vec![
|
||||||
|
String::from("-felf64"),
|
||||||
|
String::from("-o"),
|
||||||
|
obj_fp.to_string_lossy().to_string(),
|
||||||
|
asm_fp.to_string_lossy().to_string()
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link(&mut self, obj_files: Vec<PathBuf>, bin_fp: &Path) -> anyhow::Result<()> {
|
||||||
|
let mut args = vec![
|
||||||
|
String::from("-o"),
|
||||||
|
bin_fp.to_string_lossy().to_string(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for f in obj_files {
|
||||||
|
args.push(f.to_string_lossy().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
run_cmd("ld", args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needed_dependencies(&mut self) -> Vec<&str> {
|
||||||
|
vec![
|
||||||
|
"nasm",
|
||||||
|
"ld"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
37
src/compiler/x86_64_linux_nasm/utils.rs
Normal file
37
src/compiler/x86_64_linux_nasm/utils.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
|
||||||
|
pub const DBG_PRINT: &'static str = "
|
||||||
|
_dbg_print:
|
||||||
|
mov r9, -3689348814741910323
|
||||||
|
sub rsp, 40
|
||||||
|
mov BYTE [rsp+31], 10
|
||||||
|
lea rcx, [rsp+30]
|
||||||
|
.L2:
|
||||||
|
mov rax, rdi
|
||||||
|
lea r8, [rsp+32]
|
||||||
|
mul r9
|
||||||
|
mov rax, rdi
|
||||||
|
sub r8, rcx
|
||||||
|
shr rdx, 3
|
||||||
|
lea rsi, [rdx+rdx*4]
|
||||||
|
add rsi, rsi
|
||||||
|
sub rax, rsi
|
||||||
|
add eax, 48
|
||||||
|
mov BYTE [rcx], al
|
||||||
|
mov rax, rdi
|
||||||
|
mov rdi, rdx
|
||||||
|
mov rdx, rcx
|
||||||
|
sub rcx, 1
|
||||||
|
cmp rax, 9
|
||||||
|
ja .L2
|
||||||
|
lea rax, [rsp+32]
|
||||||
|
mov edi, 1
|
||||||
|
sub rdx, rax
|
||||||
|
xor eax, eax
|
||||||
|
lea rsi, [rsp+32+rdx]
|
||||||
|
mov rdx, r8
|
||||||
|
mov rax, 1
|
||||||
|
syscall
|
||||||
|
add rsp, 40
|
||||||
|
ret
|
||||||
|
";
|
|
@ -1,26 +0,0 @@
|
||||||
/**
|
|
||||||
* Prints out extra information
|
|
||||||
*/
|
|
||||||
pub const DEV_MODE: bool = false;
|
|
||||||
|
|
||||||
pub const DEFAULT_OUT_FILE: &str = "a.out";
|
|
||||||
pub const DEFAULT_INCLUDES: [&str;1] = [
|
|
||||||
"./include",
|
|
||||||
// "~/.mclang/include",
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpreting configs
|
|
||||||
* `MEM_SZ` is the buffer size for memory
|
|
||||||
* `STRING_SZ` is the buffer size for strings
|
|
||||||
* if you have buffer overflow consider increasing these
|
|
||||||
*/
|
|
||||||
pub const MEM_SZ: usize = 640 * 1000; // 4kb
|
|
||||||
pub const STRING_SZ: usize = 640 * 1000; // 4kb
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental options
|
|
||||||
*/
|
|
||||||
pub const ENABLE_EXPORTED_FUNCTIONS: bool = false;
|
|
277
src/constants.rs
277
src/constants.rs
|
@ -1,277 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum InstructionType {
|
|
||||||
|
|
||||||
// stack
|
|
||||||
PushInt,
|
|
||||||
PushStr,
|
|
||||||
Drop,
|
|
||||||
Print,
|
|
||||||
Dup,
|
|
||||||
Rot, // a b c => b c a
|
|
||||||
Over, // a b => a b a
|
|
||||||
Swap, // a b => b a
|
|
||||||
|
|
||||||
// math
|
|
||||||
Minus,
|
|
||||||
Plus,
|
|
||||||
Equals,
|
|
||||||
Gt,
|
|
||||||
Lt,
|
|
||||||
Ge,
|
|
||||||
Le,
|
|
||||||
NotEquals,
|
|
||||||
Band, // &
|
|
||||||
Bor, // |
|
|
||||||
Shr, // >>
|
|
||||||
Shl, // <<
|
|
||||||
DivMod, // /
|
|
||||||
Mul,
|
|
||||||
|
|
||||||
|
|
||||||
// mem
|
|
||||||
Load8,
|
|
||||||
Store8,
|
|
||||||
Load32,
|
|
||||||
Store32,
|
|
||||||
Load64,
|
|
||||||
Store64,
|
|
||||||
|
|
||||||
// syscalls
|
|
||||||
Syscall0,
|
|
||||||
Syscall1,
|
|
||||||
Syscall2,
|
|
||||||
Syscall3,
|
|
||||||
Syscall4,
|
|
||||||
Syscall5,
|
|
||||||
Syscall6,
|
|
||||||
|
|
||||||
CastBool,
|
|
||||||
CastPtr,
|
|
||||||
CastInt,
|
|
||||||
CastVoid,
|
|
||||||
|
|
||||||
// typing
|
|
||||||
TypeBool,
|
|
||||||
TypePtr,
|
|
||||||
TypeInt,
|
|
||||||
TypeVoid,
|
|
||||||
// TypeStr,
|
|
||||||
TypeAny,
|
|
||||||
Returns,
|
|
||||||
With,
|
|
||||||
|
|
||||||
FnCall,
|
|
||||||
MemUse,
|
|
||||||
ConstUse,
|
|
||||||
|
|
||||||
Return,
|
|
||||||
None // Used for macros and any other non built in word definitions
|
|
||||||
|
|
||||||
}
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum KeywordType {
|
|
||||||
If,
|
|
||||||
Else,
|
|
||||||
End,
|
|
||||||
While,
|
|
||||||
Do,
|
|
||||||
Include,
|
|
||||||
Memory,
|
|
||||||
Constant,
|
|
||||||
ConstantDef,
|
|
||||||
Function,
|
|
||||||
FunctionDef,
|
|
||||||
FunctionDefExported,
|
|
||||||
FunctionThen,
|
|
||||||
FunctionDone,
|
|
||||||
Inline,
|
|
||||||
Export
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum OpType {
|
|
||||||
Keyword(KeywordType),
|
|
||||||
Instruction(InstructionType)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Operator{
|
|
||||||
pub typ: OpType,
|
|
||||||
pub tok_typ: TokenType,
|
|
||||||
pub value: usize,
|
|
||||||
pub text: String, //? only used for OpType::PushStr
|
|
||||||
pub addr: Option<usize>, //? only used for OpType::PushStr
|
|
||||||
pub jmp: usize,
|
|
||||||
pub loc: Loc,
|
|
||||||
pub types: (usize, usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Operator {
|
|
||||||
pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
typ,
|
|
||||||
value,
|
|
||||||
jmp: 0,
|
|
||||||
addr: None,
|
|
||||||
text,
|
|
||||||
loc: (file, row, col),
|
|
||||||
tok_typ,
|
|
||||||
types: (0, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn set_addr(&mut self, addr: usize) -> Self {
|
|
||||||
self.addr = Some(addr);
|
|
||||||
(*self).clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub fn set_types(&mut self, args: usize, rets: usize) -> Self {
|
|
||||||
// self.types = (args, rets);
|
|
||||||
// (*self).clone()
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl OpType {
|
|
||||||
pub fn human(&self) -> String {
|
|
||||||
match (*self).clone() {
|
|
||||||
OpType::Instruction(instruction) => {
|
|
||||||
match instruction {
|
|
||||||
|
|
||||||
InstructionType::PushInt => "Number",
|
|
||||||
InstructionType::PushStr => "String",
|
|
||||||
InstructionType::Print => "_dbg_print",
|
|
||||||
InstructionType::Dup => "dup",
|
|
||||||
InstructionType::Drop => "drop",
|
|
||||||
InstructionType::Rot => "rot",
|
|
||||||
InstructionType::Over => "over",
|
|
||||||
InstructionType::Swap => "swap",
|
|
||||||
InstructionType::Plus => "+",
|
|
||||||
InstructionType::Minus => "-",
|
|
||||||
InstructionType::Equals => "=",
|
|
||||||
InstructionType::Gt => ">",
|
|
||||||
InstructionType::Lt => "<",
|
|
||||||
InstructionType::NotEquals => "!=",
|
|
||||||
InstructionType::Le => "<=",
|
|
||||||
InstructionType::Ge => ">=",
|
|
||||||
InstructionType::Band => "band",
|
|
||||||
InstructionType::Bor => "bor",
|
|
||||||
InstructionType::Shr => "shr",
|
|
||||||
InstructionType::Shl => "shl",
|
|
||||||
InstructionType::DivMod => "divmod",
|
|
||||||
InstructionType::Mul => "*",
|
|
||||||
InstructionType::Load8 => "load8",
|
|
||||||
InstructionType::Store8 => "store8",
|
|
||||||
InstructionType::Load32 => "load32",
|
|
||||||
InstructionType::Store32 => "store32",
|
|
||||||
InstructionType::Load64 => "load64",
|
|
||||||
InstructionType::Store64 => "store64",
|
|
||||||
InstructionType::Syscall0 => "syscall0",
|
|
||||||
InstructionType::Syscall1 => "syscall1",
|
|
||||||
InstructionType::Syscall2 => "syscall2",
|
|
||||||
InstructionType::Syscall3 => "syscall3",
|
|
||||||
InstructionType::Syscall4 => "syscall4",
|
|
||||||
InstructionType::Syscall5 => "syscall5",
|
|
||||||
InstructionType::Syscall6 => "syscall6",
|
|
||||||
InstructionType::CastBool => "cast(bool",
|
|
||||||
InstructionType::CastPtr => "cast(ptr)",
|
|
||||||
InstructionType::CastInt => "cast(int)",
|
|
||||||
InstructionType::CastVoid => "cast(void)",
|
|
||||||
InstructionType::None => "None",
|
|
||||||
InstructionType::MemUse => "Memory use (internal)",
|
|
||||||
InstructionType::FnCall => "Function Call (Internal)",
|
|
||||||
InstructionType::ConstUse => "Constant Use (Internal)",
|
|
||||||
InstructionType::Return => "return",
|
|
||||||
InstructionType::TypeBool => "bool",
|
|
||||||
InstructionType::TypePtr => "ptr",
|
|
||||||
InstructionType::TypeInt => "int",
|
|
||||||
InstructionType::TypeVoid => "void",
|
|
||||||
InstructionType::Returns => "returns",
|
|
||||||
InstructionType::With => "with",
|
|
||||||
InstructionType::TypeAny => "any",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpType::Keyword(keyword) => {
|
|
||||||
match keyword {
|
|
||||||
KeywordType::If => "if",
|
|
||||||
KeywordType::Else => "else",
|
|
||||||
KeywordType::End => "end",
|
|
||||||
KeywordType::While => "while",
|
|
||||||
KeywordType::Do => "do",
|
|
||||||
KeywordType::Include => "include",
|
|
||||||
KeywordType::Memory => "memory",
|
|
||||||
KeywordType::Function => "fn",
|
|
||||||
KeywordType::Constant => "const",
|
|
||||||
KeywordType::FunctionThen => "then",
|
|
||||||
KeywordType::FunctionDone => "done",
|
|
||||||
KeywordType::ConstantDef => "constant Definition (internal)",
|
|
||||||
KeywordType::FunctionDef => "function definition (internal)",
|
|
||||||
KeywordType::FunctionDefExported => "extern function definition (internal)",
|
|
||||||
KeywordType::Inline => "inline",
|
|
||||||
KeywordType::Export => "export",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Token {
|
|
||||||
pub file: String,
|
|
||||||
pub line: usize,
|
|
||||||
pub col: usize,
|
|
||||||
pub text: String,
|
|
||||||
pub typ: TokenType,
|
|
||||||
pub value: Option<usize>, //* only used for Memories
|
|
||||||
pub addr: Option<usize>, //* only used for Memories
|
|
||||||
pub op_typ: OpType //* only used for Memories
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
|
||||||
pub enum TokenType {
|
|
||||||
Word,
|
|
||||||
Int,
|
|
||||||
String,
|
|
||||||
Char
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Token {
|
|
||||||
pub fn loc(&self) -> Loc {
|
|
||||||
(
|
|
||||||
self.file.clone(),
|
|
||||||
self.line,
|
|
||||||
self.col
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TokenType {
|
|
||||||
pub fn human(self) -> String {
|
|
||||||
match self {
|
|
||||||
TokenType::Word => "Word",
|
|
||||||
TokenType::Int => "Int",
|
|
||||||
TokenType::String => "String",
|
|
||||||
TokenType::Char => "Char"
|
|
||||||
}.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Loc = (String, usize, usize);
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
|
||||||
pub enum Types {
|
|
||||||
Bool,
|
|
||||||
Ptr,
|
|
||||||
Int,
|
|
||||||
Void,
|
|
||||||
Any
|
|
||||||
// U8,
|
|
||||||
// U16,
|
|
||||||
// U32,
|
|
||||||
// U64,
|
|
||||||
// todo: add signed numbers since we dont have them yet lol
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
use crate::{error, help, code_block};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn missing_main_fn() {
|
|
||||||
error!("Main function not found, please create one lol");
|
|
||||||
help!("Heres a basic main function with code that prints hello world:\n{}",
|
|
||||||
code_block!(
|
|
||||||
concat!(
|
|
||||||
"include \"std.mcl\"\n",
|
|
||||||
"\n",
|
|
||||||
"fn main with void retuns void then\n",
|
|
||||||
" \"Hello world!\\n\" puts\n",
|
|
||||||
"done\n"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,425 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{constants::{OpType, Loc, InstructionType, KeywordType, Operator}, lerror, error};
|
|
||||||
// use crate::util::logger;
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
use super::{Memory, Function, Constant};
|
|
||||||
mod syscalls;
|
|
||||||
|
|
||||||
fn stack_pop(stack: &mut Vec<usize>, pos: &Loc) -> Result<usize> {
|
|
||||||
if let Some(i) = stack.pop() { Ok(i) } else {
|
|
||||||
lerror!(&pos.clone(), "Stack underflow");
|
|
||||||
Err(eyre!("Stack underflow"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|
||||||
let mut stack: Vec<usize> = Vec::new();
|
|
||||||
let mut mem: Vec<u64> = vec![0; crate::MEM_SZ + crate::STRING_SZ];
|
|
||||||
let mut string_idx = 0;
|
|
||||||
|
|
||||||
let prerunned = pre_run(ops);
|
|
||||||
let functions = prerunned.functions;
|
|
||||||
let constants = prerunned.constants;
|
|
||||||
let memories = prerunned.memories;
|
|
||||||
|
|
||||||
let mut ret_stack: Vec<usize> = Vec::new();
|
|
||||||
|
|
||||||
// for token in &tokens {
|
|
||||||
// println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// jump to main func
|
|
||||||
let mut ip = if let Some(i) = functions.get("main") {i.id} else {
|
|
||||||
crate::errors::missing_main_fn();
|
|
||||||
return Err(eyre!(""));
|
|
||||||
};
|
|
||||||
|
|
||||||
while ip < ops.len() {
|
|
||||||
let op = &ops[ip];
|
|
||||||
let pos = op.loc.clone();
|
|
||||||
match op.typ.clone() {
|
|
||||||
OpType::Instruction(instruction) => {
|
|
||||||
match instruction {
|
|
||||||
InstructionType::PushInt => {
|
|
||||||
stack.push(op.value);
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::PushStr => {
|
|
||||||
if op.addr.is_none() {
|
|
||||||
stack.push(op.text.len()); // string len
|
|
||||||
stack.push(string_idx + crate::MEM_SZ);
|
|
||||||
|
|
||||||
for c in op.text.bytes() {
|
|
||||||
mem[crate::MEM_SZ + string_idx] = u64::from(c);
|
|
||||||
string_idx += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stack.push(op.text.len());
|
|
||||||
if let Some(addr) = op.addr {
|
|
||||||
stack.push(addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Drop => {
|
|
||||||
stack.pop();
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Dup => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(a);
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Rot => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
let c = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b);
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(c);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Swap => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Over => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b);
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Print => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
println!("{a}");
|
|
||||||
// let _ = io::stdout().flush();
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
InstructionType::Load8 |
|
|
||||||
InstructionType::Load32 |
|
|
||||||
InstructionType::Load64 => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
if a > crate::MEM_SZ {
|
|
||||||
lerror!(&op.loc, "Invalid memory address {a}");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
let byte = mem[a];
|
|
||||||
stack.push(byte as usize);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
InstructionType::Store8 => {
|
|
||||||
let val = stack_pop(&mut stack, &pos)?;
|
|
||||||
let addr = stack_pop(&mut stack, &pos)?;
|
|
||||||
|
|
||||||
if addr > crate::MEM_SZ {
|
|
||||||
lerror!(&op.loc, "Invalid memory address {addr}");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem[addr] = u64::from(val as u8);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
InstructionType::Store32 => {
|
|
||||||
let val = stack_pop(&mut stack, &pos)?;
|
|
||||||
let addr = stack_pop(&mut stack, &pos)?;
|
|
||||||
|
|
||||||
if addr > crate::MEM_SZ {
|
|
||||||
lerror!(&op.loc, "Invalid memory address {addr}");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem[addr] = u64::from(val as u32);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
InstructionType::Store64 => {
|
|
||||||
let val = stack_pop(&mut stack, &pos)?;
|
|
||||||
let addr = stack_pop(&mut stack, &pos)?;
|
|
||||||
|
|
||||||
if addr > crate::MEM_SZ {
|
|
||||||
lerror!(&op.loc, "Invalid memory address {addr}");
|
|
||||||
return Ok(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem[addr] = val as u64;
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// math
|
|
||||||
InstructionType::Plus => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b + a);
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Minus => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b - a);
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Equals => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b == a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Gt => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b > a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Lt => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b < a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::NotEquals => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b != a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Ge => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b >= a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Le => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(usize::from(b <= a));
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Band => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(a & b);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Bor => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(a | b);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Shr => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b >> a);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Shl => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b << a);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::DivMod => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b / a);
|
|
||||||
stack.push(b % a);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Mul => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
let b = stack_pop(&mut stack, &pos)?;
|
|
||||||
stack.push(b * a);
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
InstructionType::Syscall0 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall1 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall2 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall3 => {
|
|
||||||
let rax = stack_pop(&mut stack, &pos)?;
|
|
||||||
let rdi = stack_pop(&mut stack, &pos)?;
|
|
||||||
let rsi = stack_pop(&mut stack, &pos)?;
|
|
||||||
let rdx = stack_pop(&mut stack, &pos)?;
|
|
||||||
// println!("yes");
|
|
||||||
let ret = match rax {
|
|
||||||
1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem),
|
|
||||||
0 => 0, //? temp, so clippy doesnt complain
|
|
||||||
_ => {
|
|
||||||
error!("Syscall(3) #{} is not implemented", rax);
|
|
||||||
return Err(eyre!("Syscall not implemented"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
stack.push(ret);
|
|
||||||
// println!("{}", stack.len());
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall4 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall5 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall6 => {
|
|
||||||
todo!();
|
|
||||||
// ti += 1;
|
|
||||||
},
|
|
||||||
InstructionType::MemUse => {
|
|
||||||
|
|
||||||
let m = memories.get(&op.addr.unwrap()).unwrap();
|
|
||||||
stack.push(m.id);
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::FnCall => {
|
|
||||||
ret_stack.push(ip);
|
|
||||||
let f = functions.get(&op.text).unwrap();
|
|
||||||
ip = f.id;
|
|
||||||
}
|
|
||||||
InstructionType::Return => {
|
|
||||||
ip = ret_stack.pop().unwrap();
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
InstructionType::ConstUse => {
|
|
||||||
let a = constants.get(&op.text).unwrap();
|
|
||||||
|
|
||||||
if let Some(i) = a.value_i {
|
|
||||||
stack.push(i);
|
|
||||||
} else if let Some(_s) = a.value_s.clone() {
|
|
||||||
unimplemented!();
|
|
||||||
}
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
InstructionType::CastBool |
|
|
||||||
InstructionType::CastPtr |
|
|
||||||
InstructionType::CastInt |
|
|
||||||
InstructionType::CastVoid |
|
|
||||||
InstructionType::TypeBool |
|
|
||||||
InstructionType::TypePtr |
|
|
||||||
InstructionType::TypeInt |
|
|
||||||
InstructionType::TypeVoid |
|
|
||||||
InstructionType::TypeAny |
|
|
||||||
InstructionType::Returns |
|
|
||||||
InstructionType::With => ip += 1,
|
|
||||||
InstructionType::None => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
OpType::Keyword(k) => {
|
|
||||||
match k {
|
|
||||||
// blocks
|
|
||||||
KeywordType::If => {
|
|
||||||
let a = stack_pop(&mut stack, &pos)?;
|
|
||||||
if a == 0 {
|
|
||||||
// println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp);
|
|
||||||
ip = op.jmp;
|
|
||||||
} else {
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
KeywordType::Else | KeywordType::End => {
|
|
||||||
ip = op.jmp;
|
|
||||||
}
|
|
||||||
KeywordType::Do => {
|
|
||||||
let a = stack.pop().unwrap();
|
|
||||||
if a == 0 {
|
|
||||||
ip = op.jmp;
|
|
||||||
} else {
|
|
||||||
ip += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeywordType::While | //* exept this one, this one should just skip over
|
|
||||||
KeywordType::Memory |
|
|
||||||
KeywordType::FunctionDef |
|
|
||||||
KeywordType::FunctionDefExported |
|
|
||||||
KeywordType::ConstantDef => {
|
|
||||||
//? Disabled since we now pre run the whole program
|
|
||||||
// constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
|
|
||||||
ip += 1;
|
|
||||||
},
|
|
||||||
KeywordType::FunctionDone => {
|
|
||||||
if let Some(i) = ret_stack.pop() {
|
|
||||||
ip = i + 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
KeywordType::FunctionThen => ip += 1,
|
|
||||||
KeywordType::Constant |
|
|
||||||
KeywordType::Function |
|
|
||||||
KeywordType::Inline |
|
|
||||||
KeywordType::Export |
|
|
||||||
KeywordType::Include => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Defineds {
|
|
||||||
pub memories: HashMap<usize, Memory>,
|
|
||||||
pub functions: HashMap<String, Function>,
|
|
||||||
pub constants: HashMap<String, Constant>
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pre_run(ops: &[Operator]) -> Defineds {
|
|
||||||
let mut defineds = Defineds{
|
|
||||||
memories: HashMap::new(),
|
|
||||||
functions: HashMap::new(),
|
|
||||||
constants: HashMap::new(),
|
|
||||||
};
|
|
||||||
for (ip, op) in ops.iter().enumerate() {
|
|
||||||
|
|
||||||
match op.typ {
|
|
||||||
OpType::Keyword(KeywordType::Memory) => {
|
|
||||||
defineds.memories.insert(op.addr.unwrap(), Memory { size: op.value, loc: op.loc.clone(), id: op.addr.unwrap() });
|
|
||||||
},
|
|
||||||
OpType::Keyword(KeywordType::FunctionDefExported) => {
|
|
||||||
|
|
||||||
}
|
|
||||||
OpType::Keyword(KeywordType::FunctionDef) => {
|
|
||||||
defineds.functions.insert(op.text.clone(), Function { loc: op.loc.clone(), name: op.text.clone(), id: ip });
|
|
||||||
},
|
|
||||||
OpType::Keyword(KeywordType::ConstantDef) => {
|
|
||||||
defineds.constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
|
|
||||||
},
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
defineds
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
#[allow(clippy::cast_possible_truncation)]
|
|
||||||
pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec<u64> ) -> usize {
|
|
||||||
let mem = (*mem).clone();
|
|
||||||
// println!("{:?}", &mem[buff..(buff + count)]);
|
|
||||||
// return 0 ;
|
|
||||||
let s = &mem[buff..(buff + count)].iter().map(|i| {
|
|
||||||
char::from_u32(u32::from(*i as u8)).unwrap_or('_').to_string()
|
|
||||||
}).collect::<String>();
|
|
||||||
|
|
||||||
match fd {
|
|
||||||
1 => {
|
|
||||||
print!("{s}");
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
eprint!("{s}");
|
|
||||||
},
|
|
||||||
_ => panic!("Unknown file {fd}")
|
|
||||||
};
|
|
||||||
let _ = std::io::Write::flush(&mut std::io::stdout());
|
|
||||||
let _ = std::io::Write::flush(&mut std::io::stderr());
|
|
||||||
sys_n
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
use crate::constants::Loc;
|
|
||||||
|
|
||||||
pub mod linux_x86_64;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Constant {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String,
|
|
||||||
pub value_i: Option<usize>,
|
|
||||||
pub value_s: Option<String>,
|
|
||||||
pub used: bool
|
|
||||||
// extern: bool
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Memory {
|
|
||||||
pub size: usize,
|
|
||||||
pub loc: Loc,
|
|
||||||
pub id: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String,
|
|
||||||
pub id: usize
|
|
||||||
}
|
|
126
src/lexer.rs
126
src/lexer.rs
|
@ -1,126 +0,0 @@
|
||||||
|
|
||||||
use crate::{constants::{Token, TokenType}, Args};
|
|
||||||
|
|
||||||
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
|
|
||||||
match s {
|
|
||||||
s if s.parse::<u64>().is_ok() && tok_type == TokenType::Word => { // negative numbers not yet implemented
|
|
||||||
(TokenType::Int, s)
|
|
||||||
},
|
|
||||||
s if tok_type == TokenType::Word => {
|
|
||||||
(TokenType::Word, s)
|
|
||||||
},
|
|
||||||
s if tok_type == TokenType::String => {
|
|
||||||
(TokenType::String, s)
|
|
||||||
}
|
|
||||||
s if tok_type == TokenType::Char => {
|
|
||||||
(TokenType::Char, s)
|
|
||||||
}
|
|
||||||
_ => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_col<F>(text: &str, mut col: usize, predicate: F) -> usize where F: Fn(char, char) -> bool {
|
|
||||||
let mut last = '\0';
|
|
||||||
while col < text.len() && !predicate(text.chars().nth(col).unwrap(), last) {
|
|
||||||
last = text.chars().nth(col).unwrap();
|
|
||||||
col += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
col
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Implement multiline strings
|
|
||||||
fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
|
|
||||||
let mut tokens: Vec<(usize, String, TokenType)> = Vec::new();
|
|
||||||
|
|
||||||
let mut col = find_col(text, 0, |x, _| !x.is_whitespace());
|
|
||||||
let mut col_end: usize = 0;
|
|
||||||
while col_end < text.to_string().len() {
|
|
||||||
if (text.len() - col) < 1 {
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
if &text[col..=col] == "\"" {
|
|
||||||
col_end = find_col(text, col + 1, |x, x2| x == '"' && x2 != '\\');
|
|
||||||
let t = &text[(col + 1)..col_end];
|
|
||||||
let t = t.replace("\\n", "\n")
|
|
||||||
.replace("\\t", "\t")
|
|
||||||
.replace("\\r", "\r")
|
|
||||||
.replace("\\\'", "\'")
|
|
||||||
.replace("\\\"", "\"")
|
|
||||||
.replace("\\0", "\0");
|
|
||||||
if !t.is_empty() {
|
|
||||||
tokens.push((col, t.to_string(), TokenType::String));
|
|
||||||
}
|
|
||||||
col = find_col(text, col_end + 1, |x, _| !x.is_whitespace());
|
|
||||||
|
|
||||||
} else if &text[col..=col] == "'"{
|
|
||||||
col_end = find_col(text, col + 1, |x, x2| x == '\'' && x2 != '\\');
|
|
||||||
let t = &text[(col + 1)..col_end];
|
|
||||||
let t = t.replace("\\n", "\n")
|
|
||||||
.replace("\\t", "\t")
|
|
||||||
.replace("\\r", "\r")
|
|
||||||
.replace("\\\'", "\'")
|
|
||||||
.replace("\\\"", "\"")
|
|
||||||
.replace("\\0", "\0");
|
|
||||||
|
|
||||||
|
|
||||||
if !t.is_empty() {
|
|
||||||
tokens.push((col, t.to_string(), TokenType::Char));
|
|
||||||
}
|
|
||||||
col = find_col(text, col_end + 1, |x, _| !x.is_whitespace());
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
col_end = find_col(text, col, |x, _| x.is_whitespace());
|
|
||||||
let t = &text[col..col_end];
|
|
||||||
|
|
||||||
if t == "//" {
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !t.is_empty() {
|
|
||||||
tokens.push((col, t.to_string(), TokenType::Word));
|
|
||||||
}
|
|
||||||
col = find_col(text, col_end, |x, _| !x.is_whitespace());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tokens
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lex(code: &str, file: &str, _args: &Args) -> Vec<Token> {
|
|
||||||
let lines: Vec<(usize, &str)> = code
|
|
||||||
.split(['\n', '\r'])
|
|
||||||
.enumerate()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let lines: Vec<(usize, String)> = lines.iter().map(|i| (i.0, i.1.to_string())).collect();
|
|
||||||
|
|
||||||
let mut tokens: Vec<Token> = Vec::new();
|
|
||||||
|
|
||||||
for (row, line) in lines {
|
|
||||||
let lt = lex_line(&line);
|
|
||||||
for (col, tok, tok_type) in lt {
|
|
||||||
let (tok_type, tok) = lex_word(tok, tok_type);
|
|
||||||
let t = Token{
|
|
||||||
file: file.to_string(),
|
|
||||||
line: row + 1,
|
|
||||||
col,
|
|
||||||
text: tok,
|
|
||||||
typ: tok_type,
|
|
||||||
value: None,
|
|
||||||
addr: None,
|
|
||||||
op_typ: crate::constants::OpType::Instruction(crate::constants::InstructionType::None)
|
|
||||||
};
|
|
||||||
tokens.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// println!("{}", tokens.len());
|
|
||||||
|
|
||||||
// for token in tokens.clone() {
|
|
||||||
// println!("tok: {:?}", token.text);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
tokens
|
|
||||||
}
|
|
389
src/lexer/mod.rs
Normal file
389
src/lexer/mod.rs
Normal file
|
@ -0,0 +1,389 @@
|
||||||
|
use std::path::Path;
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
|
use crate::{error, types::{common::Loc, token::{InstructionType, KeywordType, Token, TokenType, TypeType}}};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Lexer {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub tokens: Vec<Token>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Lexer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
loc: Default::default(),
|
||||||
|
tokens: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn lex(&mut self, file: &Path) -> anyhow::Result<&mut Self> {
|
||||||
|
self.reset(file);
|
||||||
|
|
||||||
|
let chars = match std::fs::read_to_string(file) {
|
||||||
|
Ok(c) => c,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to open file {file:?} : {e}");
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
}.chars().collect::<Vec<char>>();
|
||||||
|
|
||||||
|
|
||||||
|
let mut idx = 0;
|
||||||
|
let mut buf = String::new();
|
||||||
|
let mut is_searching = false;
|
||||||
|
|
||||||
|
if let Err(_) = self.go_to_first_char(&chars, &mut idx) {
|
||||||
|
return Ok(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut start_loc = self.loc.clone();
|
||||||
|
while idx < chars.len() {
|
||||||
|
|
||||||
|
match chars[idx] {
|
||||||
|
|
||||||
|
'c' if chars.get(idx + 1) == Some(&'"') => {
|
||||||
|
start_loc = self.loc.clone();
|
||||||
|
is_searching = true;
|
||||||
|
idx += 2; // skip c and "
|
||||||
|
self.loc.col += 2;
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
debug!({loc => self.loc() }, "buffer was not empty, intresting");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if chars[idx] == '"' && chars[idx-1] != '\\' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.push(chars[idx]);
|
||||||
|
if chars[idx] == '\n' {
|
||||||
|
self.loc.inc_line()
|
||||||
|
}
|
||||||
|
self.loc.inc_col();
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push('\0');
|
||||||
|
let str = self.unescape(&&buf);
|
||||||
|
self.loc.inc_col();
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushCStr(str)), self.loc(), buf.clone()));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
'"' => {
|
||||||
|
start_loc = self.loc.clone();
|
||||||
|
is_searching = true;
|
||||||
|
idx += 1; // skip "
|
||||||
|
self.loc.col += 1;
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
debug!({loc => self.loc() }, "buffer was not empty, intresting ({buf:?})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// while chars.get(idx+1) != Some(&'"') && chars[idx] != '\\' && chars.get(idx+1).is_some() {
|
||||||
|
loop {
|
||||||
|
if chars[idx] == '"' && chars[idx-1] != '\\' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.push(chars[idx]);
|
||||||
|
if chars[idx] == '\n' {
|
||||||
|
self.loc.inc_line()
|
||||||
|
}
|
||||||
|
self.loc.inc_col();
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let str = self.unescape(&buf);
|
||||||
|
self.loc.inc_col();
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushStr(str)), start_loc.clone(), buf.clone()));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
'\'' => {
|
||||||
|
start_loc = self.loc.clone();
|
||||||
|
is_searching = true;
|
||||||
|
idx += 1; // skip '
|
||||||
|
self.loc.col += 1;
|
||||||
|
|
||||||
|
if !buf.is_empty() {
|
||||||
|
debug!({loc => self.loc() }, "buffer was not empty, intresting ({buf})");
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if chars[idx] == '"' && chars[idx-1] != '\\' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf.push(chars[idx]);
|
||||||
|
if chars[idx] == '\n' {
|
||||||
|
self.loc.inc_line()
|
||||||
|
}
|
||||||
|
self.loc.inc_col();
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let str = self.unescape(&&&buf);
|
||||||
|
if str.len() > 1 {
|
||||||
|
error!({loc => self.loc()}, "Chars can only have 1 char");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.loc.inc_col();
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushStr(str)), self.loc(), buf.clone()));
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
':' if chars.get(idx + 1) == Some(&':') => {
|
||||||
|
let mut p_buf = vec![buf.clone()];
|
||||||
|
buf.clear();
|
||||||
|
idx += 2; // skip ::
|
||||||
|
self.loc.col += 2;
|
||||||
|
|
||||||
|
while idx < chars.len() {
|
||||||
|
match chars[idx] {
|
||||||
|
' ' | '\n' | '\r' => {
|
||||||
|
if !p_buf.is_empty() {
|
||||||
|
p_buf.push(buf.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::StructPath(p_buf.clone())), start_loc.clone(), p_buf.clone().join("::")));
|
||||||
|
buf.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c @ ('\'' | '"') => {
|
||||||
|
error!({loc => self.loc()}, "Invalid char in struct path token, expected /a-z|A-Z|0-9|_|-/ got {c}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
':' if chars.get(idx + 1) == Some(&':') => {
|
||||||
|
if buf.is_empty() {
|
||||||
|
error!({loc => self.loc()}, "Invalid char in struct path token, expected /a-z|A-Z|0-9|_|-/ got '.'");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
idx += 2; // skip ::
|
||||||
|
self.loc.col += 2;
|
||||||
|
p_buf.push(buf.clone());
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
c => {
|
||||||
|
buf.push(c);
|
||||||
|
idx += 1;
|
||||||
|
self.loc.inc_col();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'.' if !buf.is_empty() => {
|
||||||
|
let mut p_buf = vec![buf.clone()];
|
||||||
|
buf.clear();
|
||||||
|
idx += 1; // skip .
|
||||||
|
self.loc.inc_col();
|
||||||
|
|
||||||
|
while idx < chars.len() {
|
||||||
|
match chars[idx] {
|
||||||
|
' ' | '\n' | '\r' => {
|
||||||
|
if !p_buf.is_empty() {
|
||||||
|
p_buf.push(buf.clone());
|
||||||
|
}
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::StructItem(p_buf.clone())), start_loc.clone(), p_buf.clone().join(".")));
|
||||||
|
buf.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c @ ('\'' | '"') => {
|
||||||
|
error!({loc => self.loc()}, "Invalid char in struct access token, expected /a-z|A-Z|0-9|_|-/ got {c}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
'.' => {
|
||||||
|
if buf.is_empty() {
|
||||||
|
error!({loc => self.loc()}, "Invalid char in struct access token, expected /a-z|A-Z|0-9|_|-/ got '.'");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
idx += 1; // skip .
|
||||||
|
self.loc.col += 1;
|
||||||
|
p_buf.push(buf.clone());
|
||||||
|
buf.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
c => {
|
||||||
|
buf.push(c);
|
||||||
|
idx += 1;
|
||||||
|
self.loc.inc_col();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch @ (' ' | '\n' | '\r') => {
|
||||||
|
if ch == '\n' {
|
||||||
|
self.loc.inc_line();
|
||||||
|
} else {
|
||||||
|
self.loc.inc_col();
|
||||||
|
}
|
||||||
|
if !buf.is_empty() {
|
||||||
|
//TODO: Implement signed ints
|
||||||
|
if let Ok(int) = parse_int::parse::<usize>(&buf) {
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushInt(int)), start_loc.clone(), buf.clone()));
|
||||||
|
} else {
|
||||||
|
let token_type = self.match_token_type(&buf);
|
||||||
|
self.tokens.push(Token::new(token_type, start_loc.clone(), buf.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.clear();
|
||||||
|
is_searching = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'/' if chars.get(idx + 1) == Some(&'/') => {
|
||||||
|
let mut c = chars.get(idx);
|
||||||
|
while c.is_some() && c != Some(&'\n') {
|
||||||
|
self.loc.inc_col();
|
||||||
|
idx += 1;
|
||||||
|
c = chars.get(idx);
|
||||||
|
}
|
||||||
|
self.loc.inc_line();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ch => {
|
||||||
|
if is_searching {
|
||||||
|
is_searching = false;
|
||||||
|
start_loc = self.loc.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.push(ch);
|
||||||
|
self.loc.inc_col();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
//? Add last token
|
||||||
|
//TODO: Implement signed ints
|
||||||
|
if !buf.is_empty() {
|
||||||
|
if let Ok(int) = parse_int::parse::<usize>(&buf) {
|
||||||
|
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushInt(int)), start_loc.clone(), buf.clone()));
|
||||||
|
} else {
|
||||||
|
let token_type = self.match_token_type(&buf);
|
||||||
|
self.tokens.push(Token::new(token_type, start_loc.clone(), buf.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for t in &self.tokens {
|
||||||
|
// debug!({loc => t.loc.clone()}, "token: {:?}", t.typ);
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn go_to_first_char(&mut self, chars: &Vec<char>, idx: &mut usize) -> anyhow::Result<()> {
|
||||||
|
loop {
|
||||||
|
if let Some(c) = chars.get(*idx) {
|
||||||
|
match c {
|
||||||
|
' ' | '\r' => self.loc.inc_col(),
|
||||||
|
'\n' => self.loc.inc_line(),
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
*idx += 1;
|
||||||
|
} else {
|
||||||
|
warn!("Empty program");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn match_token_type(&self, s: &str) -> TokenType {
|
||||||
|
match s {
|
||||||
|
"if" => TokenType::Keyword(KeywordType::If),
|
||||||
|
"else" => TokenType::Keyword(KeywordType::Else),
|
||||||
|
"end" => TokenType::Keyword(KeywordType::End),
|
||||||
|
"while" => TokenType::Keyword(KeywordType::While),
|
||||||
|
"do" => TokenType::Keyword(KeywordType::Do),
|
||||||
|
"include" => TokenType::Keyword(KeywordType::Include),
|
||||||
|
"memory" => TokenType::Keyword(KeywordType::Memory),
|
||||||
|
"const" => TokenType::Keyword(KeywordType::Constant),
|
||||||
|
"fn" => TokenType::Keyword(KeywordType::Function),
|
||||||
|
"then" => TokenType::Keyword(KeywordType::Then),
|
||||||
|
"done" => TokenType::Keyword(KeywordType::Done),
|
||||||
|
"typedef" => TokenType::Keyword(KeywordType::TypeDef),
|
||||||
|
"structdef" => TokenType::Keyword(KeywordType::StructDef),
|
||||||
|
"inline" => TokenType::Keyword(KeywordType::Inline),
|
||||||
|
"export" => TokenType::Keyword(KeywordType::Export),
|
||||||
|
"extern" => TokenType::Keyword(KeywordType::Extern),
|
||||||
|
"returns" => TokenType::Keyword(KeywordType::Returns),
|
||||||
|
"with" => TokenType::Keyword(KeywordType::With),
|
||||||
|
"drop" => TokenType::Instruction(InstructionType::Drop),
|
||||||
|
"_dbg_print" => TokenType::Instruction(InstructionType::Print),
|
||||||
|
"dup" => TokenType::Instruction(InstructionType::Dup),
|
||||||
|
"rot" => TokenType::Instruction(InstructionType::Rot),
|
||||||
|
"over" => TokenType::Instruction(InstructionType::Over),
|
||||||
|
"swap" => TokenType::Instruction(InstructionType::Swap),
|
||||||
|
"sub" => TokenType::Instruction(InstructionType::Minus),
|
||||||
|
"add" => TokenType::Instruction(InstructionType::Plus),
|
||||||
|
"eq" => TokenType::Instruction(InstructionType::Equals),
|
||||||
|
"gt" => TokenType::Instruction(InstructionType::Gt),
|
||||||
|
"lt" => TokenType::Instruction(InstructionType::Lt),
|
||||||
|
"ge" => TokenType::Instruction(InstructionType::Ge),
|
||||||
|
"le" => TokenType::Instruction(InstructionType::Le),
|
||||||
|
"neq" => TokenType::Instruction(InstructionType::NotEquals),
|
||||||
|
"band" => TokenType::Instruction(InstructionType::Band),
|
||||||
|
"bor" => TokenType::Instruction(InstructionType::Bor),
|
||||||
|
"shr" => TokenType::Instruction(InstructionType::Shr),
|
||||||
|
"shl" => TokenType::Instruction(InstructionType::Shl),
|
||||||
|
"divmod" => TokenType::Instruction(InstructionType::DivMod),
|
||||||
|
"mul" => TokenType::Instruction(InstructionType::Mul),
|
||||||
|
"read8" => TokenType::Instruction(InstructionType::Read8),
|
||||||
|
"write8" => TokenType::Instruction(InstructionType::Write8),
|
||||||
|
"read32" => TokenType::Instruction(InstructionType::Read32),
|
||||||
|
"write32" => TokenType::Instruction(InstructionType::Write32),
|
||||||
|
"read64" => TokenType::Instruction(InstructionType::Read64),
|
||||||
|
"write64" => TokenType::Instruction(InstructionType::Write64),
|
||||||
|
"syscall0" => TokenType::Instruction(InstructionType::Syscall0),
|
||||||
|
"syscall1" => TokenType::Instruction(InstructionType::Syscall1),
|
||||||
|
"syscall2" => TokenType::Instruction(InstructionType::Syscall2),
|
||||||
|
"syscall3" => TokenType::Instruction(InstructionType::Syscall3),
|
||||||
|
"syscall4" => TokenType::Instruction(InstructionType::Syscall4),
|
||||||
|
"syscall5" => TokenType::Instruction(InstructionType::Syscall5),
|
||||||
|
"syscall6" => TokenType::Instruction(InstructionType::Syscall6),
|
||||||
|
"(bool)" => TokenType::Instruction(InstructionType::CastBool),
|
||||||
|
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
|
||||||
|
"(int)" => TokenType::Instruction(InstructionType::CastInt),
|
||||||
|
"(void)" => TokenType::Instruction(InstructionType::CastVoid),
|
||||||
|
"return" => TokenType::Instruction(InstructionType::Return),
|
||||||
|
"ptr" => TokenType::Type(TypeType::Ptr),
|
||||||
|
"u8" => TokenType::Type(TypeType::U8),
|
||||||
|
"u16" => TokenType::Type(TypeType::U16),
|
||||||
|
"u32" => TokenType::Type(TypeType::U32),
|
||||||
|
"u64" => TokenType::Type(TypeType::U64),
|
||||||
|
"void" => TokenType::Type(TypeType::Void),
|
||||||
|
"any" => TokenType::Type(TypeType::Any),
|
||||||
|
t => TokenType::Unknown(t.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self, file: &Path) -> &mut Self {
|
||||||
|
self.loc.file = file.to_string_lossy().to_string();
|
||||||
|
self.loc.line = 1;
|
||||||
|
self.loc.col = 0;
|
||||||
|
self.tokens = Vec::new();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loc(&self) -> Loc {
|
||||||
|
self.loc.clone()
|
||||||
|
}
|
||||||
|
fn unescape(&self, s: &String) -> String {
|
||||||
|
//TODO: add more escapes
|
||||||
|
s
|
||||||
|
.replace("\\n", "\n")
|
||||||
|
.replace("\\0", "\0")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
src/logger/colors.rs
Normal file
32
src/logger/colors.rs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
pub const RESET: &str = "\x1b[0m";
|
||||||
|
pub const BOLD: &str = "\x1b[1m";
|
||||||
|
pub const ITALIC: &str = "\x1b[3m";
|
||||||
|
pub const UNDERLINE: &str = "\x1b[4m";
|
||||||
|
pub const BLINK: &str = "\x1b[5m";
|
||||||
|
pub const BLINK2: &str = "\x1b[6m";
|
||||||
|
pub const SELECTED: &str = "\x1b[7m";
|
||||||
|
pub const BLACK: &str = "\x1b[30m";
|
||||||
|
pub const RED: &str = "\x1b[31m";
|
||||||
|
pub const GREEN: &str = "\x1b[32m";
|
||||||
|
pub const YELLOW: &str = "\x1b[33m";
|
||||||
|
pub const BLUE: &str = "\x1b[34m";
|
||||||
|
pub const MAGENTA: &str = "\x1b[35m";
|
||||||
|
pub const BEIGE: &str = "\x1b[36m";
|
||||||
|
pub const WHITE: &str = "\x1b[37m";
|
||||||
|
pub const BLACKBG: &str = "\x1b[40m";
|
||||||
|
pub const REDBG: &str = "\x1b[41m";
|
||||||
|
pub const GREENBG: &str = "\x1b[42m";
|
||||||
|
pub const YELLOWBG: &str = "\x1b[43m";
|
||||||
|
pub const BLUEBG: &str = "\x1b[44m";
|
||||||
|
pub const MAGENTABG: &str = "\x1b[45m";
|
||||||
|
pub const BEIGEBG: &str = "\x1b[46m";
|
||||||
|
pub const WHITEBG: &str = "\x1b[47m";
|
||||||
|
pub const GREY: &str = "\x1b[90m";
|
||||||
|
pub const RED2: &str = "\x1b[91m";
|
||||||
|
pub const GREEN2: &str = "\x1b[92m";
|
||||||
|
pub const YELLOW2: &str = "\x1b[93m";
|
||||||
|
pub const BLUE2: &str = "\x1b[94m";
|
||||||
|
pub const MAGENTA2: &str = "\x1b[95m";
|
||||||
|
pub const BEIGE2: &str = "\x1b[96m";
|
||||||
|
pub const WHITE2: &str = "\x1b[97m";
|
106
src/logger/macros.rs
Normal file
106
src/logger/macros.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log {
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $lvl:expr, $($arg:tt),+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, crate::logger::Level::Info, $($arg)+)
|
||||||
|
};
|
||||||
|
(module: $module:expr, $lvl:expr, $($arg:tt)+) => {
|
||||||
|
unsafe {
|
||||||
|
crate::logger::LOGGER.log(
|
||||||
|
crate::logger::LogEvent {
|
||||||
|
level: $lvl,
|
||||||
|
module_path: $module.to_string(),
|
||||||
|
message: format!($($arg)+),
|
||||||
|
tags: std::collections::HashMap::new()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
($lvl:expr, $($arg:tt)+) => {
|
||||||
|
crate::log!(module: module_path!(), $lvl, $($arg)+)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! log_tagged {
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $module:expr, $lvl:expr, $($arg:tt)+) => {
|
||||||
|
unsafe {
|
||||||
|
crate::logger::LOGGER.log(
|
||||||
|
crate::logger::LogEvent {
|
||||||
|
level: $lvl,
|
||||||
|
module_path: $module.to_string(),
|
||||||
|
message: format!($($arg)+),
|
||||||
|
tags: map_macro::hash_map!{$(stringify!($k).to_string() => Box::new($v) as Box<dyn core::any::Any>,)*}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
(module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log!(module: $module, crate::logger::Level::Debug, $($arg:tt)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, module_path!(), crate::logger::Level::Debug, $($arg)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, $module, crate::logger::Level::Debug, $($arg)+)
|
||||||
|
};
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
crate::log!(crate::logger::Level::Debug, $($arg)+)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! info {
|
||||||
|
(module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log!(module: $module, crate::logger::Level::Info, $($arg:tt)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, module_path!(), crate::logger::Level::Info, $($arg)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, $module, crate::logger::Level::Info, $($arg)+)
|
||||||
|
};
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
crate::log!(crate::logger::Level::Info, $($arg)+)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn {
|
||||||
|
(module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log!(module: $module, crate::logger::Level::Warn, $($arg:tt)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, module_path!(), crate::logger::Level::Warn, $($arg)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, $module, crate::logger::Level::Warn, $($arg)+)
|
||||||
|
};
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
crate::log!(crate::logger::Level::Warn, $($arg)+)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! error {
|
||||||
|
(module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log!(module: $module, crate::logger::Level::Error, $($arg:tt)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, module_path!(), crate::logger::Level::Error, $($arg)+)
|
||||||
|
};
|
||||||
|
({$($k: expr => $v: expr),* $(,)? }, module: $module:expr, $($arg:tt)+) => {
|
||||||
|
crate::log_tagged!({$($k => $v,)*}, $module, crate::logger::Level::Error, $($arg)+)
|
||||||
|
};
|
||||||
|
($($arg:tt)+) => {
|
||||||
|
crate::log!(crate::logger::Level::Error, $($arg)+)
|
||||||
|
};
|
||||||
|
}
|
83
src/logger/mod.rs
Normal file
83
src/logger/mod.rs
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
|
||||||
|
// use log::{Level, LevelFilter, Metadata, Record, SetLoggerError};
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use crate::{cli::CliArgs, types::common::Loc};
|
||||||
|
|
||||||
|
mod types;
|
||||||
|
mod colors;
|
||||||
|
#[macro_use]
|
||||||
|
pub mod macros;
|
||||||
|
pub use types::{Level, LogEvent, LOGGER};
|
||||||
|
use types::*;
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Logger{
|
||||||
|
pub level: i8
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Logger {
|
||||||
|
pub fn new(args: &CliArgs) -> Box<Self> {
|
||||||
|
Box::new(Self {
|
||||||
|
level: args.verbose
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(args: &CliArgs) -> anyhow::Result<()>{
|
||||||
|
unsafe {
|
||||||
|
types::LOGGER = Box::leak(
|
||||||
|
Self::new(args)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_prefix(&self, level: Level) -> String {
|
||||||
|
use colors::{BOLD, RESET, RED, YELLOW, BLUE, GREEN, MAGENTA};
|
||||||
|
match level {
|
||||||
|
Level::Error => format!("{BOLD}{RED}error{RESET}", ),
|
||||||
|
Level::Warn => format!("{BOLD}{YELLOW}warn{RESET}", ),
|
||||||
|
Level::Info => format!("{BOLD}{GREEN}info{RESET}", ),
|
||||||
|
Level::Debug => format!("{BOLD}{BLUE}debug{RESET}", ),
|
||||||
|
Level::Trace => format!("{BOLD}{MAGENTA}trace{RESET}", ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Log for Logger {
|
||||||
|
fn enabled(&self, level: Level) -> bool {
|
||||||
|
match level {
|
||||||
|
Level::Error if self.level >= 0 => true,
|
||||||
|
Level::Warn |
|
||||||
|
Level::Info if self.level >= 1 => true,
|
||||||
|
Level::Debug if self.level >= 2 => true,
|
||||||
|
Level::Trace if self.level >= 3 => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(&self, event: LogEvent) {
|
||||||
|
|
||||||
|
if self.enabled(event.level) {
|
||||||
|
let modpath = if event.level > Level::Info {
|
||||||
|
format!(" [{}]", event.module_path)
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(loc) = event.tags.get("loc") {
|
||||||
|
let loc: String = (*loc.deref()).downcast_ref::<Loc>()
|
||||||
|
.map_or(String::from("INVALID"), |l| l.to_string());
|
||||||
|
println!("{} {}{modpath}: {}", loc, self.get_prefix(event.level), event.message);
|
||||||
|
} else {
|
||||||
|
println!("{}{modpath}: {}", self.get_prefix(event.level), event.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn level(&self) -> i8 {
|
||||||
|
self.level
|
||||||
|
}
|
||||||
|
}
|
40
src/logger/types.rs
Normal file
40
src/logger/types.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
use std::{any::Any, collections::HashMap, fmt::Debug };
|
||||||
|
|
||||||
|
|
||||||
|
pub static mut LOGGER: &dyn Log = &NopLogger;
|
||||||
|
|
||||||
|
struct NopLogger;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||||
|
pub enum Level {
|
||||||
|
Error = 1,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub trait Tag: Display + Debug + Any {}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct LogEvent {
|
||||||
|
pub level: Level,
|
||||||
|
pub module_path: String,
|
||||||
|
pub message: String,
|
||||||
|
pub tags: HashMap<String, Box<dyn Any>>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Log for NopLogger {
|
||||||
|
fn enabled(&self, _: Level) -> bool {false}
|
||||||
|
fn level(&self) -> i8 {0}
|
||||||
|
fn log(&self, _: LogEvent) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub trait Log {
|
||||||
|
fn enabled(&self, level: Level) -> bool;
|
||||||
|
fn log(&self, event: LogEvent);
|
||||||
|
fn level(&self) -> i8;
|
||||||
|
}
|
160
src/main.rs
160
src/main.rs
|
@ -1,141 +1,47 @@
|
||||||
#![allow(clippy::wildcard_imports)]
|
|
||||||
#![allow(clippy::too_many_lines)]
|
use std::collections::HashMap;
|
||||||
mod constants;
|
|
||||||
mod interpret;
|
#[macro_use]
|
||||||
mod util;
|
mod logger;
|
||||||
mod compile;
|
mod cli;
|
||||||
mod parser;
|
mod types;
|
||||||
mod lexer;
|
mod lexer;
|
||||||
mod preprocessor;
|
pub mod parser;
|
||||||
mod typechecker;
|
mod compiler;
|
||||||
mod precompiler;
|
|
||||||
mod config;
|
|
||||||
mod errors;
|
|
||||||
use config::*;
|
|
||||||
use std::{fs, collections::HashMap};
|
|
||||||
|
|
||||||
use clap::Parser;
|
fn main() {
|
||||||
use color_eyre::Result;
|
let cli_args = cli::CliArgs::parse_with_passthrough();
|
||||||
use eyre::eyre;
|
logger::Logger::init(&cli_args).expect("Failed to init logger");
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
let mut prog_map = HashMap::new();
|
||||||
#[command(author, version, about, long_about = None)]
|
for file in &cli_args.input {
|
||||||
pub struct Args {
|
let mut lexer = lexer::Lexer::new();
|
||||||
/// Input source file
|
|
||||||
#[arg(long, short)]
|
|
||||||
in_file: String,
|
|
||||||
|
|
||||||
/// Output compiled file
|
|
||||||
#[arg(long, short, default_value_t=String::from(DEFAULT_OUT_FILE))]
|
|
||||||
out_file: String,
|
|
||||||
|
|
||||||
/// Compile
|
|
||||||
#[arg(long, short)]
|
|
||||||
compile: bool,
|
|
||||||
|
|
||||||
/// Interpert
|
|
||||||
#[arg(long, short='s')]
|
|
||||||
interpret: bool,
|
|
||||||
|
|
||||||
/// Run the compiled executable
|
|
||||||
#[arg(long, short)]
|
|
||||||
run: bool,
|
|
||||||
|
|
||||||
/// Dont print any output exept the actual running codes output
|
|
||||||
#[arg(long, short)]
|
|
||||||
quiet: bool,
|
|
||||||
|
|
||||||
/// Add an include directory [default: ["./include", "~/.mclang/include"]]
|
|
||||||
#[arg(long, short='I')]
|
|
||||||
include: Vec<String>,
|
|
||||||
|
|
||||||
/// Unsafe mode, disables typechecking
|
|
||||||
#[arg(long="unsafe", default_value_t = false)]
|
|
||||||
unsaf: bool,
|
|
||||||
|
|
||||||
/// Optimisation level, available levels: 'D': debug, '0': No optimisations
|
|
||||||
#[arg(long, short='O', default_value_t=String::from("0"))]
|
|
||||||
optimisation: String,
|
|
||||||
|
|
||||||
// disables the main function
|
|
||||||
#[arg(long="lib")]
|
|
||||||
lib_mode: bool
|
|
||||||
//#[arg(long, short='F')]
|
|
||||||
//features: Vec<String>,
|
|
||||||
|
|
||||||
|
info!("Lexing file {file:?}");
|
||||||
|
if let Err(_) = lexer.lex(file.as_std_path()) {
|
||||||
|
error!("Lexing failed, exiting");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Args {
|
// for t in &lexer.tokens {
|
||||||
/// Get optimisation level
|
// info!({loc => t.loc.clone()}, "{:?}", t.typ);
|
||||||
/// 0 => no optimisations
|
// }
|
||||||
/// 1 => slight optimisations, mostly size ones
|
// dbg!(&lexer.tokens);
|
||||||
/// # Errors
|
|
||||||
///
|
|
||||||
/// Throws when the opt level is not known
|
|
||||||
pub fn get_opt_level(&self) -> Result<usize>{
|
|
||||||
match self.optimisation.as_str() {
|
|
||||||
"D" | "d" => Ok(0),
|
|
||||||
"0" | "" => Ok(1),
|
|
||||||
o => {
|
|
||||||
error!("Unknown optimisation level {o}");
|
|
||||||
Err(eyre!(""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() -> Result<()>{
|
info!("Parsing file {file:?}");
|
||||||
|
let prog = match parser::parse(&cli_args, &mut lexer.tokens) {
|
||||||
|
Ok(r) => r,
|
||||||
let args = Args::parse();
|
Err(_) => {
|
||||||
|
error!("Parsing failed, exiting");
|
||||||
let Ok(code) = fs::read_to_string(&args.in_file) else {
|
return;
|
||||||
error!("Failed to read file {}, exiting!", &args.in_file);
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
|
|
||||||
let tokens = lexer::lex(&code, args.in_file.as_str(), &args);
|
|
||||||
|
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(tokens, &args, None);
|
|
||||||
let tokens = match parser.parse(){
|
|
||||||
Ok(t) => t,
|
|
||||||
Err(e) => {
|
|
||||||
error!("Parsing failed, exiting!");
|
|
||||||
if crate::DEV_MODE {
|
|
||||||
return Err(e)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match typechecker::typecheck(tokens.clone(), &args, None, HashMap::new(), HashMap::new()) {
|
prog_map.insert(file.as_std_path(), prog);
|
||||||
Ok(_) => (),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Typechecking failed, exiting!");
|
|
||||||
if crate::DEV_MODE {
|
|
||||||
return Err(e);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let c = if args.compile && args.interpret {
|
|
||||||
error!("Cannot compile and interpret at the same time");
|
|
||||||
0
|
|
||||||
} else if args.interpret {
|
|
||||||
if let Ok(c) = interpret::linux_x86_64::run(&tokens) { c } else {
|
|
||||||
error!("Interpretation failed, exiting!");
|
|
||||||
1
|
|
||||||
}
|
}
|
||||||
} else if args.compile {
|
if let Err(_) = compiler::compile_program(&cli_args, prog_map) {
|
||||||
if let Ok(c) = compile::linux_x86_64::compile(&tokens, &args) { c } else {
|
error!("Failed to compile program, exiting");
|
||||||
error!("Compilation failed, exiting!");
|
|
||||||
1
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
error!("Did not choose to compile or to interpret, exiting");
|
|
||||||
0
|
|
||||||
};
|
|
||||||
std::process::exit(c);
|
|
||||||
}
|
}
|
||||||
|
|
222
src/parser.rs
222
src/parser.rs
|
@ -1,222 +0,0 @@
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::Preprocessor, Args};
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
|
||||||
let mut stack: Vec<usize> = Vec::new();
|
|
||||||
|
|
||||||
for ip in 0..program.len() {
|
|
||||||
let op = &program.clone()[ip];
|
|
||||||
// println!("{op:?}");
|
|
||||||
match op.typ {
|
|
||||||
// OpType::Keyword(KeywordType::FunctionDef) |
|
|
||||||
OpType::Keyword(KeywordType::If | KeywordType::While) => {
|
|
||||||
stack.push(ip);
|
|
||||||
}
|
|
||||||
OpType::Keyword(KeywordType::Else) => {
|
|
||||||
let Some(if_ip) = stack.pop() else {
|
|
||||||
lerror!(&op.loc, "Unclosed-if else block");
|
|
||||||
return Err(eyre!("Cross referencing"));
|
|
||||||
};
|
|
||||||
if program[if_ip].typ != OpType::Keyword(KeywordType::If) {
|
|
||||||
lerror!(&op.clone().loc,"'else' can only close 'if' blocks");
|
|
||||||
return Err(eyre!("Bad block"));
|
|
||||||
}
|
|
||||||
|
|
||||||
program[if_ip].jmp = ip + 1;
|
|
||||||
stack.push(ip);
|
|
||||||
},
|
|
||||||
OpType::Keyword(KeywordType::End) => {
|
|
||||||
let Some(block_ip) = stack.pop() else {
|
|
||||||
lerror!(&op.loc, "Unclosed if, if-else, while-do, function, memory, or constant");
|
|
||||||
return Err(eyre!("Cross referencing"));
|
|
||||||
};
|
|
||||||
|
|
||||||
match &program[block_ip].typ {
|
|
||||||
OpType::Keyword(KeywordType::If | KeywordType::Else) => {
|
|
||||||
program[block_ip].jmp = ip;
|
|
||||||
program[ip].jmp = ip + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Do) => {
|
|
||||||
program[ip].jmp = program[block_ip].jmp;
|
|
||||||
program[block_ip].jmp = ip + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Memory | KeywordType::Constant) => (),
|
|
||||||
|
|
||||||
a => {
|
|
||||||
println!("{a:?}");
|
|
||||||
lerror!(&op.clone().loc,"'end' can only close if, if-else, while-do, function, memory, or constant blocks");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
OpType::Keyword(KeywordType::Do) => {
|
|
||||||
let Some(block_ip) = stack.pop() else {
|
|
||||||
lerror!(&op.loc, "Unclosed while-do block");
|
|
||||||
return Err(eyre!("Cross referencing"));
|
|
||||||
};
|
|
||||||
|
|
||||||
program[ip].jmp = block_ip;
|
|
||||||
stack.push(ip);
|
|
||||||
}
|
|
||||||
_ => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if !stack.is_empty() {
|
|
||||||
// println!("{:?}", stack);
|
|
||||||
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block, {:?}", program[stack.pop().expect("Empy stack")].clone());
|
|
||||||
return Err(eyre!("Unclosed block"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(program.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Parser<'a> {
|
|
||||||
tokens: Vec<Token>,
|
|
||||||
pub preprocessor: Preprocessor<'a>,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
args: &'a Args
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
|
||||||
pub fn new(file: Vec<Token>, args: &'a Args, p: Option<Preprocessor<'a>>) -> Self {
|
|
||||||
let pre = if let Some(p) = p {p} else {
|
|
||||||
Preprocessor::new(Vec::new(), args)
|
|
||||||
};
|
|
||||||
|
|
||||||
Self{
|
|
||||||
tokens: file,
|
|
||||||
preprocessor: pre,
|
|
||||||
args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Vec<Operator>> {
|
|
||||||
let mut tokens = Vec::new();
|
|
||||||
|
|
||||||
for token in &self.tokens {
|
|
||||||
if token.text.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let pos = (token.file.clone(), token.line, token.col);
|
|
||||||
match token.typ {
|
|
||||||
TokenType::Word => {
|
|
||||||
let word_type = if token.op_typ == OpType::Instruction(InstructionType::MemUse) {
|
|
||||||
OpType::Instruction(InstructionType::MemUse)
|
|
||||||
} else {
|
|
||||||
lookup_word(&token.text, &pos)
|
|
||||||
};
|
|
||||||
|
|
||||||
tokens.push(Operator::new(word_type, token.typ, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0)));
|
|
||||||
},
|
|
||||||
TokenType::Int => {// negative numbers not yet implemented
|
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
|
|
||||||
},
|
|
||||||
TokenType::String => {
|
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), token.typ, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
|
||||||
}
|
|
||||||
TokenType::Char => {
|
|
||||||
let c = token.text.clone();
|
|
||||||
if c.len() != 1 {
|
|
||||||
lerror!(&token.loc(), "Chars can only be of lenght 1, got {}", c.len());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
self.preprocessor.program = tokens;
|
|
||||||
let t = self.preprocessor.preprocess()?.get_ops();
|
|
||||||
let t = cross_ref(t)?;
|
|
||||||
|
|
||||||
Ok(t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
|
|
||||||
let n = s.parse::<usize>();
|
|
||||||
if n.is_ok() {
|
|
||||||
return OpType::Instruction(InstructionType::PushInt);
|
|
||||||
}
|
|
||||||
match s {
|
|
||||||
//stack
|
|
||||||
"_dbg_print" => OpType::Instruction(InstructionType::Print),
|
|
||||||
"dup" => OpType::Instruction(InstructionType::Dup),
|
|
||||||
"drop" => OpType::Instruction(InstructionType::Drop),
|
|
||||||
"rot" => OpType::Instruction(InstructionType::Rot),
|
|
||||||
"over" => OpType::Instruction(InstructionType::Over),
|
|
||||||
"swap" => OpType::Instruction(InstructionType::Swap),
|
|
||||||
|
|
||||||
// comp and math
|
|
||||||
"+" => OpType::Instruction(InstructionType::Plus),
|
|
||||||
"-" => OpType::Instruction(InstructionType::Minus),
|
|
||||||
"=" => OpType::Instruction(InstructionType::Equals),
|
|
||||||
"!=" => OpType::Instruction(InstructionType::NotEquals),
|
|
||||||
">" => OpType::Instruction(InstructionType::Gt),
|
|
||||||
"<" => OpType::Instruction(InstructionType::Lt),
|
|
||||||
">=" => OpType::Instruction(InstructionType::Ge),
|
|
||||||
"<=" => OpType::Instruction(InstructionType::Le),
|
|
||||||
|
|
||||||
"band" => OpType::Instruction(InstructionType::Band),
|
|
||||||
"bor" => OpType::Instruction(InstructionType::Bor),
|
|
||||||
"shr" => OpType::Instruction(InstructionType::Shr),
|
|
||||||
"shl" => OpType::Instruction(InstructionType::Shl),
|
|
||||||
"divmod" => OpType::Instruction(InstructionType::DivMod),
|
|
||||||
"*" => OpType::Instruction(InstructionType::Mul),
|
|
||||||
|
|
||||||
|
|
||||||
// mem
|
|
||||||
"load8" => OpType::Instruction(InstructionType::Load8),
|
|
||||||
"store8" => OpType::Instruction(InstructionType::Store8),
|
|
||||||
"load32" => OpType::Instruction(InstructionType::Load32),
|
|
||||||
"store32" => OpType::Instruction(InstructionType::Store32),
|
|
||||||
"load64" => OpType::Instruction(InstructionType::Load64),
|
|
||||||
"store64" => OpType::Instruction(InstructionType::Store64),
|
|
||||||
|
|
||||||
"syscall0" => OpType::Instruction(InstructionType::Syscall0),
|
|
||||||
"syscall1" => OpType::Instruction(InstructionType::Syscall1),
|
|
||||||
"syscall2" => OpType::Instruction(InstructionType::Syscall2),
|
|
||||||
"syscall3" => OpType::Instruction(InstructionType::Syscall3),
|
|
||||||
"syscall4" => OpType::Instruction(InstructionType::Syscall4),
|
|
||||||
"syscall5" => OpType::Instruction(InstructionType::Syscall5),
|
|
||||||
"syscall6" => OpType::Instruction(InstructionType::Syscall6),
|
|
||||||
"cast(bool)" => OpType::Instruction(InstructionType::CastBool),
|
|
||||||
"cast(ptr)" => OpType::Instruction(InstructionType::CastPtr),
|
|
||||||
"cast(int)" => OpType::Instruction(InstructionType::CastInt),
|
|
||||||
"cast(void)" => OpType::Instruction(InstructionType::CastVoid),
|
|
||||||
// block
|
|
||||||
"if" => OpType::Keyword(KeywordType::If),
|
|
||||||
"else" => OpType::Keyword(KeywordType::Else),
|
|
||||||
"end" => OpType::Keyword(KeywordType::End),
|
|
||||||
"while" => OpType::Keyword(KeywordType::While),
|
|
||||||
"do" => OpType::Keyword(KeywordType::Do),
|
|
||||||
"include" => OpType::Keyword(KeywordType::Include),
|
|
||||||
"memory" => OpType::Keyword(KeywordType::Memory),
|
|
||||||
"const" => OpType::Keyword(KeywordType::Constant),
|
|
||||||
"fn" => OpType::Keyword(KeywordType::Function),
|
|
||||||
"then" => OpType::Keyword(KeywordType::FunctionThen),
|
|
||||||
"done" => OpType::Keyword(KeywordType::FunctionDone),
|
|
||||||
"inline" => OpType::Keyword(KeywordType::Inline),
|
|
||||||
"export" => OpType::Keyword(KeywordType::Export),
|
|
||||||
"return" => OpType::Instruction(InstructionType::Return),
|
|
||||||
"returns" => OpType::Instruction(InstructionType::Returns),
|
|
||||||
"bool" => OpType::Instruction(InstructionType::TypeBool),
|
|
||||||
"int" => OpType::Instruction(InstructionType::TypeInt),
|
|
||||||
"ptr" => OpType::Instruction(InstructionType::TypePtr),
|
|
||||||
"void" => OpType::Instruction(InstructionType::TypeVoid),
|
|
||||||
"any" => OpType::Instruction(InstructionType::TypeAny),
|
|
||||||
"with" => OpType::Instruction(InstructionType::With),
|
|
||||||
_ => OpType::Instruction(InstructionType::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
46
src/parser/builtin.rs
Normal file
46
src/parser/builtin.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use crate::types::{ast::{AstNode, Constant, Module, Program}, common::Loc};
|
||||||
|
|
||||||
|
|
||||||
|
lazy_static!(
|
||||||
|
static ref DEFAULT_CONSTANTS: HashMap<&'static str, AstNode> = {
|
||||||
|
let mut h = HashMap::new();
|
||||||
|
// No bsd cause im not about to create 3 or 4 diffrent compilation targets
|
||||||
|
h.insert("__WINDOWS", AstNode::Int(Loc::default(), cfg!(target_os = "windows") as usize));
|
||||||
|
h.insert("__LINUX", AstNode::Int(Loc::default(), cfg!(target_os = "linux") as usize));
|
||||||
|
h.insert("__ENDIAN_LITTLE", AstNode::Int(Loc::default(), cfg!(target_endian="little") as usize));
|
||||||
|
h.insert("__ENDIAN_BIG", AstNode::Int(Loc::default(), cfg!(target_endian="big") as usize));
|
||||||
|
|
||||||
|
|
||||||
|
h
|
||||||
|
};
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub fn get_builtin_symbols(prog: &mut Program) -> AstNode {
|
||||||
|
let mut md = Module {
|
||||||
|
loc: Loc::new(String::from("BUILTIN"), 0, 0),
|
||||||
|
path: vec![String::from("builtin")],
|
||||||
|
ident: String::from("BUILTIN"),
|
||||||
|
body: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (k, v) in DEFAULT_CONSTANTS.iter() {
|
||||||
|
let c = Constant {
|
||||||
|
loc: Loc::default(),
|
||||||
|
ident: k.to_string(),
|
||||||
|
value: Box::from(v.clone()),
|
||||||
|
};
|
||||||
|
prog.constants.insert(k.to_string(), c.clone());
|
||||||
|
md.body.push(AstNode::Constant(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AstNode::Module(md)
|
||||||
|
}
|
787
src/parser/mod.rs
Normal file
787
src/parser/mod.rs
Normal file
|
@ -0,0 +1,787 @@
|
||||||
|
mod utils;
|
||||||
|
mod precompiler;
|
||||||
|
mod builtin;
|
||||||
|
|
||||||
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
|
use crate::{cli::CliArgs, lexer::Lexer, types::{ast::{AstNode, Block, ConstUse, Constant, FnCall, Function, If, MemSize, MemUse, Memory, Module, Program, StructDef, While}, common::Loc, token::{InstructionType, KeywordType, Token, TokenType, TypeType}}};
|
||||||
|
|
||||||
|
use self::{builtin::get_builtin_symbols, precompiler::{precompile_const, precompile_mem}, utils::{expect, peek_check, peek_check_multiple, PeekResult}};
|
||||||
|
|
||||||
|
|
||||||
|
bitflags::bitflags! {
|
||||||
|
struct Flags: u8 {
|
||||||
|
const EXTERN = 1 << 0;
|
||||||
|
const EXPORT = 1 << 1;
|
||||||
|
const INLINE = 1 << 2;
|
||||||
|
const ALLOW_TYPES = 1 << 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Implement Module paths
|
||||||
|
pub fn parse(cli_args: &CliArgs, tokens: &mut Vec<Token>) -> Result<Program> {
|
||||||
|
tokens.reverse();
|
||||||
|
let module = Module {
|
||||||
|
loc: Loc::new(&tokens[0].loc.file, 0, 0),
|
||||||
|
ident: Path::new(&tokens[0].loc.file).file_stem().expect("Something went horribly wrong").to_string_lossy().to_string(),
|
||||||
|
body: Vec::new(),
|
||||||
|
path: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut prog = Program {
|
||||||
|
ast: AstNode::Module(module.clone()),
|
||||||
|
functions: HashMap::new(),
|
||||||
|
constants: HashMap::new(),
|
||||||
|
memories: HashMap::new(),
|
||||||
|
struct_defs: HashMap::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
let syms = get_builtin_symbols(&mut prog);
|
||||||
|
match &mut prog.ast {
|
||||||
|
AstNode::Module(module) => {
|
||||||
|
module.body.push(syms)
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
while !tokens.is_empty() {
|
||||||
|
let node = parse_next(cli_args, &mut prog, tokens, Flags::empty(), true)?;
|
||||||
|
match &mut prog.ast {
|
||||||
|
AstNode::Module(module) => {
|
||||||
|
module.body.push(node);
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// prog.ast = module;
|
||||||
|
|
||||||
|
Ok(prog)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, flags: Flags, is_module_root: bool) -> Result<AstNode> {
|
||||||
|
let token = tokens.pop().expect("We broke reality!");
|
||||||
|
// debug!({loc => token.loc.clone()}, "t: {:?}", token.typ);
|
||||||
|
let ret = match &token.typ {
|
||||||
|
TokenType::Keyword(kw) => {
|
||||||
|
match kw {
|
||||||
|
KeywordType::If => parse_if(&token, cli_args, prog, tokens)?,
|
||||||
|
KeywordType::While => parse_while(&token, cli_args, prog, tokens)?,
|
||||||
|
KeywordType::Include => parse_include(&token, cli_args, prog, tokens)?,
|
||||||
|
KeywordType::Memory => parse_memory(&token, cli_args, prog, tokens, is_module_root)?,
|
||||||
|
KeywordType::Constant => parse_const(&token, cli_args, prog, tokens)?,
|
||||||
|
KeywordType::Function => parse_function(&token, cli_args, prog, tokens, flags)?,
|
||||||
|
KeywordType::StructDef => parse_struct(&token, cli_args, prog, tokens)?,
|
||||||
|
KeywordType::TypeDef => todo!(),
|
||||||
|
KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
|
||||||
|
KeywordType::Export => parse_export(&token, cli_args, prog, tokens, flags)?,
|
||||||
|
KeywordType::Extern => parse_extern(&token, cli_args, prog, tokens, flags)?,
|
||||||
|
kw => {
|
||||||
|
dbg!(&prog.constants);
|
||||||
|
error!({loc => token.loc}, "Unexpected token {kw:?}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TokenType::Instruction(it) => {
|
||||||
|
if is_module_root {
|
||||||
|
error!({loc => token.loc}, "Unexpected token {it:?}, please create a main function, this is not a scripting language");
|
||||||
|
bail!("")
|
||||||
|
} else {
|
||||||
|
match it {
|
||||||
|
InstructionType::StructPath(p) => parse_struct_path(&token, prog, p)?,
|
||||||
|
InstructionType::StructItem(p) => parse_struct_item(&token, prog, p)?,
|
||||||
|
_ => AstNode::Token(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TokenType::Unknown(ut) => {
|
||||||
|
if is_module_root {
|
||||||
|
error!({loc => token.loc}, "Unexpected token {ut:?}, please create a main function, this is not a scripting language");
|
||||||
|
bail!("")
|
||||||
|
} else {
|
||||||
|
// AstNode::Token(token)
|
||||||
|
parse_unknown(&token, cli_args, prog, tokens, flags)?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TokenType::Type(t) => {
|
||||||
|
if flags.contains(Flags::ALLOW_TYPES) {
|
||||||
|
AstNode::Token(token)
|
||||||
|
} else {
|
||||||
|
error!({loc => token.loc}, "Unexpected type {t:?}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_struct_item(org: &Token, prog: &mut Program, p: &Vec<String>) -> Result<AstNode> {
|
||||||
|
fn find_disp(strct: &StructDef, disp: &mut usize, path: &[String]) {
|
||||||
|
let Some(p) = path.get(0) else {
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
for item in &strct.body {
|
||||||
|
if p == &item.0 {
|
||||||
|
match &item.2 {
|
||||||
|
TypeType::Struct(strct) => {
|
||||||
|
*disp += item.1;
|
||||||
|
find_disp(strct, disp, &path[1..])
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
*disp += item.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if let Some(mem) = prog.memories.get(&p[0].to_string()) {
|
||||||
|
match &mem.size {
|
||||||
|
MemSize::Size(_) => {
|
||||||
|
error!({loc => org.loc()}, "You can only access items in structs");
|
||||||
|
bail!("")
|
||||||
|
},
|
||||||
|
MemSize::Type(t) => {
|
||||||
|
match t {
|
||||||
|
TypeType::Struct(s) => {
|
||||||
|
|
||||||
|
let mut disp = 0;
|
||||||
|
find_disp(&s, &mut disp, &p[1..]);
|
||||||
|
return Ok(AstNode::MemUse(MemUse{
|
||||||
|
ident: p[0].clone(),
|
||||||
|
loc: org.loc(),
|
||||||
|
disp: Some(disp)
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
error!({loc => org.loc()}, "You can only access items in structs");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Failed to find memory {}", p[0]);
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_struct_path(org: &Token, prog: &mut Program, p: &Vec<String>) -> Result<AstNode> {
|
||||||
|
|
||||||
|
fn find_disp(strct: &StructDef, disp: &mut usize, path: &[String]) {
|
||||||
|
let Some(p) = path.get(0) else {
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
for item in &strct.body {
|
||||||
|
if p == &item.0 {
|
||||||
|
match &item.2 {
|
||||||
|
TypeType::Struct(strct) => {
|
||||||
|
*disp += item.1;
|
||||||
|
find_disp(strct, disp, &path[1..])
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
*disp += item.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
let mut disp = 0;
|
||||||
|
if let Some(strct) = prog.struct_defs.get(&p[0].to_string()) {
|
||||||
|
find_disp(strct, &mut disp, &p[1..]);
|
||||||
|
return Ok(AstNode::StructDispPush{
|
||||||
|
ident: org.lexem.clone(),
|
||||||
|
loc: org.loc(),
|
||||||
|
disp
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Failed to find struct {}", p[0]);
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_struct(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
|
||||||
|
let ident = expect(tokens, TokenType::Unknown(String::new()))?;
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
|
||||||
|
|
||||||
|
|
||||||
|
let mut body: Vec<(String, usize, TypeType)> = Vec::new();
|
||||||
|
let mut size = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let ident = expect(tokens, TokenType::Unknown(String::new()))?;
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
|
||||||
|
let typ = parse_next(cli_args, prog, tokens, Flags::ALLOW_TYPES, false)?;
|
||||||
|
let (typ, disp) = match &typ {
|
||||||
|
AstNode::Token(t) => {
|
||||||
|
match &t.typ {
|
||||||
|
TokenType::Type(t) => {
|
||||||
|
let disp = size;
|
||||||
|
size += t.get_size();
|
||||||
|
(t, disp)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!({loc => t.loc()}, "Expected type, got {t:?}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
t => {
|
||||||
|
error!({loc => typ.loc()}, "Expected type, got {t:?}");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::End))?;
|
||||||
|
|
||||||
|
body.push((ident.lexem, disp, typ.clone()));
|
||||||
|
|
||||||
|
if peek_check(tokens, TokenType::Keyword(KeywordType::Done)).correct(){
|
||||||
|
tokens.pop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// if peek_check(tokens, TokenType::Keyword(KeywordType::End)).correct()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let def = StructDef{
|
||||||
|
loc: org.loc(),
|
||||||
|
ident: ident.lexem.clone(),
|
||||||
|
body,
|
||||||
|
size,
|
||||||
|
};
|
||||||
|
|
||||||
|
prog.struct_defs.insert(ident.lexem, def.clone());
|
||||||
|
|
||||||
|
Ok(AstNode::StructDef(def))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_memory(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, is_module_root: bool) -> Result<AstNode> {
|
||||||
|
let name = expect(tokens, TokenType::Unknown(String::new()))?;
|
||||||
|
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
loop {
|
||||||
|
|
||||||
|
let t = peek_check(tokens, TokenType::Keyword(KeywordType::End));
|
||||||
|
match t {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(_) => (),
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
body.push(parse_next(cli_args, prog, tokens, Flags::ALLOW_TYPES, false)?);
|
||||||
|
}
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::End))?;
|
||||||
|
|
||||||
|
let val = precompile_mem(prog, body)?;
|
||||||
|
|
||||||
|
let name = name.lexem.clone()
|
||||||
|
.replace("(", "_OPRN_")
|
||||||
|
.replace(")", "_CPRN_");
|
||||||
|
|
||||||
|
let def = Memory{
|
||||||
|
loc: org.loc(),
|
||||||
|
ident: name.clone(),
|
||||||
|
size: val,
|
||||||
|
statc: is_module_root,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
prog.memories.insert(name, def.clone());
|
||||||
|
|
||||||
|
Ok(AstNode::Memory(def))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Extern functions
|
||||||
|
fn parse_function(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, flags: Flags ) -> Result<AstNode> {
|
||||||
|
|
||||||
|
|
||||||
|
let name = expect(tokens, TokenType::Unknown(String::new()))?;
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::With))?;
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
|
||||||
|
TokenType::Type(TypeType::Any),
|
||||||
|
TokenType::Type(TypeType::U8),
|
||||||
|
TokenType::Type(TypeType::U16),
|
||||||
|
TokenType::Type(TypeType::U32),
|
||||||
|
TokenType::Type(TypeType::U64),
|
||||||
|
TokenType::Type(TypeType::Ptr),
|
||||||
|
TokenType::Type(TypeType::Void),
|
||||||
|
TokenType::Type(TypeType::Custom(Vec::new())),
|
||||||
|
]) {
|
||||||
|
match &t.typ {
|
||||||
|
TokenType::Type(tt) => {
|
||||||
|
args.push(tt.clone());
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokens.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Returns))?;
|
||||||
|
|
||||||
|
let mut ret_args = Vec::new();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
|
||||||
|
TokenType::Type(TypeType::Any),
|
||||||
|
TokenType::Type(TypeType::U8),
|
||||||
|
TokenType::Type(TypeType::U16),
|
||||||
|
TokenType::Type(TypeType::U32),
|
||||||
|
TokenType::Type(TypeType::U64),
|
||||||
|
TokenType::Type(TypeType::Ptr),
|
||||||
|
TokenType::Type(TypeType::Void),
|
||||||
|
TokenType::Type(TypeType::Custom(Vec::new())),
|
||||||
|
]) {
|
||||||
|
match &t.typ {
|
||||||
|
TokenType::Type(tt) => {
|
||||||
|
ret_args.push(tt.clone());
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tokens.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Then))?;
|
||||||
|
let mut body = Vec::new();
|
||||||
|
loop {
|
||||||
|
|
||||||
|
let fn_got = peek_check(tokens, TokenType::Keyword(KeywordType::Done));
|
||||||
|
match fn_got {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(_) => (),
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
body.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
}
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Done))?;
|
||||||
|
|
||||||
|
let fn_def = Function {
|
||||||
|
loc: org.loc(),
|
||||||
|
inline: flags.contains(Flags::INLINE),
|
||||||
|
extrn: flags.contains(Flags::EXTERN),
|
||||||
|
export: flags.contains(Flags::EXPORT),
|
||||||
|
ident: name.lexem.clone(),
|
||||||
|
arg_types: args,
|
||||||
|
ret_types: ret_args,
|
||||||
|
body,
|
||||||
|
};
|
||||||
|
//TODO: Support module paths without double definitions
|
||||||
|
// let mut mp = match &prog.ast {
|
||||||
|
// AstNode::Module(m) => {
|
||||||
|
// m.path.clone()
|
||||||
|
// }
|
||||||
|
// _ => panic!("")
|
||||||
|
// };
|
||||||
|
// mp.push(name.lexem.clone());
|
||||||
|
// let mp = mp.join("::");
|
||||||
|
|
||||||
|
// prog.function_aliases.insert(mp, name.lexem.clone());
|
||||||
|
prog.functions.insert(name.lexem.clone(), fn_def.clone());
|
||||||
|
Ok(AstNode::Function(fn_def))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_if(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
|
||||||
|
let mut test: Vec<AstNode> = Vec::new();
|
||||||
|
let mut body: Vec<AstNode> = Vec::new();
|
||||||
|
let mut els: Vec<AstNode> = Vec::new();
|
||||||
|
loop {
|
||||||
|
test.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
match peek_check(tokens, TokenType::Keyword(KeywordType::Do)) {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(w) => {
|
||||||
|
match w.typ {
|
||||||
|
TokenType::Keyword(KeywordType::Then) => {
|
||||||
|
warn!({loc => w.loc()}, "If is defined as `if ... do ... done`");
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loop {
|
||||||
|
body.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
match peek_check_multiple(tokens, vec![
|
||||||
|
TokenType::Keyword(KeywordType::Else),
|
||||||
|
TokenType::Keyword(KeywordType::Done),
|
||||||
|
]) {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(_) => (),
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let els_t = tokens.last().expect("IMPOSSIBLEEE!!!!!!111").clone();
|
||||||
|
let els = match els_t.typ.clone() {
|
||||||
|
TokenType::Keyword(kw) => {
|
||||||
|
match kw {
|
||||||
|
KeywordType::Done => {
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Done))?;
|
||||||
|
AstNode::Block(Block{
|
||||||
|
comment: String::new(),
|
||||||
|
loc: els_t.loc,
|
||||||
|
body: Vec::new(),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
KeywordType::Else => {
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Else))?;
|
||||||
|
if peek_check(tokens, TokenType::Keyword(KeywordType::If)).correct() {
|
||||||
|
let if_org =expect(tokens, TokenType::Keyword(KeywordType::If))?;
|
||||||
|
parse_if(&if_org, cli_args, prog, tokens)?
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
els.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
match peek_check(tokens, TokenType::Keyword(KeywordType::Done)) {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(w) => {
|
||||||
|
match w.typ {
|
||||||
|
TokenType::Keyword(KeywordType::Then) => {
|
||||||
|
warn!("If is defined as `if ... do ... done`");
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Done))?;
|
||||||
|
|
||||||
|
AstNode::Block(Block{
|
||||||
|
comment: String::new(),
|
||||||
|
loc: els_t.loc,
|
||||||
|
body: els,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e => {
|
||||||
|
error!({loc => els_t.loc.clone()}, "Expected {:?} or {:?} but got {:?}", KeywordType::Done, KeywordType::Else, e);
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
e => {
|
||||||
|
error!({loc => els_t.loc.clone()}, "Expected {:?} or {:?} but got {:?}", KeywordType::Done, KeywordType::Else, e);
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok(AstNode::If(If{
|
||||||
|
test,
|
||||||
|
body,
|
||||||
|
els: Box::new(els),
|
||||||
|
loc: org.loc(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_while(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
|
||||||
|
let mut test: Vec<AstNode> = Vec::new();
|
||||||
|
let mut body: Vec<AstNode> = Vec::new();
|
||||||
|
loop {
|
||||||
|
test.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
match peek_check(tokens, TokenType::Keyword(KeywordType::Do)) {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(w) => {
|
||||||
|
match w.typ {
|
||||||
|
TokenType::Keyword(KeywordType::Then) => {
|
||||||
|
warn!("while is defined as `while ... do ... done`");
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loop {
|
||||||
|
body.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
match peek_check_multiple(tokens, vec![
|
||||||
|
TokenType::Keyword(KeywordType::Else),
|
||||||
|
TokenType::Keyword(KeywordType::Done),
|
||||||
|
]) {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(_) => (),
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::Done))?;
|
||||||
|
|
||||||
|
Ok(AstNode::While(While{
|
||||||
|
test,
|
||||||
|
body,
|
||||||
|
loc: org.loc(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_inline(_: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, flags: Flags) -> Result<AstNode> {
|
||||||
|
let allowed_tokens = vec!{
|
||||||
|
TokenType::Keyword(KeywordType::Function)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let Some(t) = tokens.last() else {
|
||||||
|
error!("Expected one of {:?} after {:?} but found nothing", allowed_tokens, TokenType::Keyword(KeywordType::Inline));
|
||||||
|
bail!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
for at in &allowed_tokens {
|
||||||
|
if utils::cmp(at, &t.typ) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
error!({loc => t.loc.clone()}, "Expected one of {:?} after {:?} but found {:?}", allowed_tokens, TokenType::Keyword(KeywordType::Inline), t.typ);
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_next(cli_args, prog, tokens, flags | Flags::INLINE, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_extern(_: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, flags: Flags) -> Result<AstNode> {
|
||||||
|
let allowed_tokens = vec!{
|
||||||
|
TokenType::Keyword(KeywordType::Function),
|
||||||
|
TokenType::Keyword(KeywordType::Constant),
|
||||||
|
TokenType::Keyword(KeywordType::Memory),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let Some(t) = tokens.last() else {
|
||||||
|
error!("Expected one of {:?} after {:?} but found nothing", allowed_tokens, TokenType::Keyword(KeywordType::Extern));
|
||||||
|
bail!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
for at in &allowed_tokens {
|
||||||
|
if utils::cmp(at, &t.typ) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
error!({loc => t.loc.clone()}, "Expected one of {:?} after {:?} but found {:?}", allowed_tokens, TokenType::Keyword(KeywordType::Extern), t.typ);
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_next(cli_args, prog, tokens, flags | Flags::EXTERN, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_export(_: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, flags: Flags) -> Result<AstNode> {
|
||||||
|
let allowed_tokens = vec!{
|
||||||
|
TokenType::Keyword(KeywordType::Function),
|
||||||
|
TokenType::Keyword(KeywordType::Constant),
|
||||||
|
TokenType::Keyword(KeywordType::Memory),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let Some(t) = tokens.last() else {
|
||||||
|
error!("Expected one of {:?} after {:?} but found nothing", allowed_tokens, TokenType::Keyword(KeywordType::Export));
|
||||||
|
bail!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
for at in &allowed_tokens {
|
||||||
|
if utils::cmp(at, &t.typ) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
error!({loc => t.loc.clone()}, "Expected one of {:?} after {:?} but found {:?}", allowed_tokens, TokenType::Keyword(KeywordType::Export), t.typ);
|
||||||
|
bail!("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse_next(cli_args, prog, tokens, flags | Flags::EXPORT, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn parse_include(_: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
|
||||||
|
let path = expect(tokens,
|
||||||
|
TokenType::Instruction(
|
||||||
|
InstructionType::PushStr(
|
||||||
|
String::new()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for ip in &cli_args.include_path {
|
||||||
|
let p = ip.join(&path.lexem).to_path_buf();
|
||||||
|
if p.exists() {
|
||||||
|
info!({loc => path.loc.clone()}, "Lexing file {}", path.lexem.clone());
|
||||||
|
let mut lexer = Lexer::new();
|
||||||
|
lexer.lex(p.as_std_path())?;
|
||||||
|
|
||||||
|
let mut mod_tokens = lexer.tokens;
|
||||||
|
|
||||||
|
mod_tokens.reverse();
|
||||||
|
|
||||||
|
let mut mp = match &prog.ast {
|
||||||
|
AstNode::Module(m) => {
|
||||||
|
m.path.clone()
|
||||||
|
}
|
||||||
|
_ => panic!("")
|
||||||
|
};
|
||||||
|
|
||||||
|
mp.push(p.file_stem().unwrap().to_string());
|
||||||
|
|
||||||
|
let module = Module {
|
||||||
|
loc: Loc::new(path.loc.file.clone(), 0, 0),
|
||||||
|
ident: Path::new(&path.loc.file).file_stem().expect("Something went horribly wrong").to_string_lossy().to_string(),
|
||||||
|
body: Vec::new(),
|
||||||
|
path: mp,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut mod_prog = Program {
|
||||||
|
ast: AstNode::Module(module),
|
||||||
|
functions: prog.functions.clone(),
|
||||||
|
constants: prog.constants.clone(),
|
||||||
|
memories: prog.memories.clone(),
|
||||||
|
struct_defs: prog.struct_defs.clone(),
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
info!({loc => path.loc.clone()}, "Parsing file {}", path.lexem.clone());
|
||||||
|
while !mod_tokens.is_empty() {
|
||||||
|
let node = parse_next(cli_args, &mut mod_prog, &mut mod_tokens, Flags::empty(), true)?;
|
||||||
|
match &mut mod_prog.ast {
|
||||||
|
AstNode::Module(module) => {
|
||||||
|
module.body.push(node);
|
||||||
|
}
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prog.constants = mod_prog.constants;
|
||||||
|
prog.functions = mod_prog.functions;
|
||||||
|
prog.memories = mod_prog.memories;
|
||||||
|
return Ok(mod_prog.ast)
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
error!("Could not find file {:?} in these locations: {:?}", path.lexem, cli_args.include_path);
|
||||||
|
bail!("")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_const(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
|
||||||
|
let name = expect(tokens, TokenType::Unknown(String::new()))?;
|
||||||
|
|
||||||
|
|
||||||
|
let mut body = Vec::new();
|
||||||
|
loop {
|
||||||
|
|
||||||
|
let t = peek_check(tokens, TokenType::Keyword(KeywordType::End));
|
||||||
|
match t {
|
||||||
|
PeekResult::Correct(_) => break,
|
||||||
|
PeekResult::Wrong(_) => (),
|
||||||
|
PeekResult::None => panic!("idk what to do herre"),
|
||||||
|
}
|
||||||
|
body.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
|
||||||
|
}
|
||||||
|
expect(tokens, TokenType::Keyword(KeywordType::End))?;
|
||||||
|
|
||||||
|
let val = precompile_const(prog, body, &mut Vec::new())?;
|
||||||
|
|
||||||
|
|
||||||
|
let def = Constant{
|
||||||
|
loc: org.loc(),
|
||||||
|
ident: name.lexem.clone(),
|
||||||
|
value: Box::new(val),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
prog.constants.insert(name.lexem, def.clone());
|
||||||
|
|
||||||
|
Ok(AstNode::Constant(def))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_unknown(org: &Token, _: &CliArgs, prog: &mut Program, _: &mut Vec<Token>, _: Flags ) -> Result<AstNode> {
|
||||||
|
//TODO: Typing?
|
||||||
|
if let Some(func) = prog.functions.get(&org.lexem.clone()) {
|
||||||
|
if func.inline {
|
||||||
|
return Ok(AstNode::Block(Block{ loc: org.loc.clone(), body: func.body.clone(), comment: format!("inline fn {}", func.ident) }))
|
||||||
|
} else {
|
||||||
|
return Ok(AstNode::FnCall(FnCall{ loc: org.loc.clone(), ident: org.lexem.clone() }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_) = prog.constants.get(&org.lexem.clone()) {
|
||||||
|
return Ok(AstNode::ConstUse(ConstUse{ loc: org.loc.clone(), ident: org.lexem.clone() }));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(_) = prog.memories.get(&org.lexem.clone()) {
|
||||||
|
return Ok(AstNode::MemUse(MemUse{ loc: org.loc.clone(), ident: org.lexem.clone(), disp: None }));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(t) = prog.struct_defs.get(&org.lexem.clone()) {
|
||||||
|
return Ok(AstNode::Token(Token {
|
||||||
|
typ: TokenType::Type(TypeType::Struct(t.clone())),
|
||||||
|
loc: org.loc(),
|
||||||
|
lexem: org.lexem.clone(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if org.lexem.clone().contains("::") {
|
||||||
|
// let pth = org.lexem.clone();
|
||||||
|
// let pth = pth.split("::").collect::<Vec<&str>>();
|
||||||
|
// dbg!(prog.struct_defs.clone());
|
||||||
|
// if let Some(t) = prog.struct_defs.get(&pth[0].to_string()) {
|
||||||
|
// if let Some(i) = t.body.iter().find(|i| i.0 == pth[1].to_string()) {
|
||||||
|
// return Ok(AstNode::StructDispPush{
|
||||||
|
// ident: org.lexem.clone(),
|
||||||
|
// loc: org.loc(),
|
||||||
|
// disp: i.1
|
||||||
|
// });
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// dbg!(&prog.constants);
|
||||||
|
debug!({loc => org.loc.clone()}, "Unknown token");
|
||||||
|
error!({loc => org.loc.clone()}, "Unknown token {:?}", org);
|
||||||
|
bail!("")
|
||||||
|
}
|
213
src/parser/precompiler.rs
Normal file
213
src/parser/precompiler.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
use anyhow::bail;
|
||||||
|
|
||||||
|
use crate::types::{ast::{AstNode, MemSize, Program}, common::Loc, token::{InstructionType, TokenType, TypeType}};
|
||||||
|
|
||||||
|
|
||||||
|
pub fn precompile_mem(prog: &Program, ast: Vec<AstNode> ) -> anyhow::Result<MemSize> {
|
||||||
|
match &ast[0] {
|
||||||
|
AstNode::Token(t) => {
|
||||||
|
match &t.typ {
|
||||||
|
TokenType::Type(_) => {
|
||||||
|
let mut buf = vec![];
|
||||||
|
let mut i = 0;
|
||||||
|
while ast.len() > i {
|
||||||
|
match &ast[i] {
|
||||||
|
AstNode::Token(t) => {
|
||||||
|
match &t.typ {
|
||||||
|
TokenType::Type(t) => {
|
||||||
|
match t {
|
||||||
|
TypeType::Struct(s) => {
|
||||||
|
return Ok(MemSize::Type(TypeType::Struct(s.clone())));
|
||||||
|
},
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
buf.push(t.clone());
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(MemSize::Type(TypeType::Custom(buf)));
|
||||||
|
}
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match precompile_const(prog, ast, &mut Vec::new()) {
|
||||||
|
Ok(v) => {
|
||||||
|
match v {
|
||||||
|
AstNode::Int(_, i) => {
|
||||||
|
return Ok(MemSize::Size(i))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
error!({loc => v.loc()}, "Can only have a type or a number as a memory size");
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => bail!(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn precompile_const(prog: &Program, ast: Vec<AstNode>, stack: &mut Vec<usize> ) -> anyhow::Result<AstNode> {
|
||||||
|
for node in ast.clone() {
|
||||||
|
match &node {
|
||||||
|
AstNode::ConstUse(c) => {
|
||||||
|
let Some(val) = prog.constants.get(&c.ident) else {
|
||||||
|
error!({loc => c.loc.clone()}, "Unknown constant {:?}", c.ident) ;
|
||||||
|
bail!("")
|
||||||
|
};
|
||||||
|
match Box::leak(val.value.clone()) {
|
||||||
|
t @ AstNode::Int(..) => {
|
||||||
|
return Ok(t.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
t @ AstNode::Str(..) => {
|
||||||
|
return Ok(t.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
t @ AstNode::CStr(..) => {
|
||||||
|
return Ok(t.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
t @ AstNode::Char(..) => {
|
||||||
|
return Ok(t.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AstNode::Token(t) => {
|
||||||
|
// match t.typ.clone() {
|
||||||
|
// TokenType::Instruction(it) => {
|
||||||
|
// match it {
|
||||||
|
// InstructionType::PushInt(i) => stack.push(i),
|
||||||
|
// InstructionType::PushCStr(_) => {
|
||||||
|
// //TODO: Handle this better
|
||||||
|
// return Ok(AstNode::Token(t.clone()));
|
||||||
|
// },
|
||||||
|
// InstructionType::PushChar(_) => {
|
||||||
|
// //TODO: Handle this better
|
||||||
|
// return Ok(AstNode::Token(t.clone()));
|
||||||
|
// },
|
||||||
|
// _ => panic!()
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// _ => panic!()
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
_ => panic!()
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
AstNode::Token(t) => {
|
||||||
|
match t.typ.clone() {
|
||||||
|
TokenType::Keyword(_) => {
|
||||||
|
error!({loc => t.loc.clone()}, "Unsupported token {t:?}, we dont support precompilation of this") ;
|
||||||
|
bail!("")
|
||||||
|
},
|
||||||
|
TokenType::Instruction(it) => {
|
||||||
|
match it {
|
||||||
|
InstructionType::PushInt(i) => {
|
||||||
|
stack.push(i);
|
||||||
|
},
|
||||||
|
InstructionType::PushCStr(s) => {
|
||||||
|
//TODO: Handle this better
|
||||||
|
return Ok(AstNode::CStr(t.loc.clone(), s));
|
||||||
|
},
|
||||||
|
InstructionType::PushStr(s) => {
|
||||||
|
//TODO: Handle this better
|
||||||
|
return Ok(AstNode::Str(t.loc.clone(), s));
|
||||||
|
},
|
||||||
|
InstructionType::PushChar(c) => {
|
||||||
|
//TODO: Handle this better
|
||||||
|
return Ok(AstNode::Char(t.loc.clone(), c));
|
||||||
|
},
|
||||||
|
InstructionType::Minus => {
|
||||||
|
let a = stack_pop(stack, &t.loc)?;
|
||||||
|
let b = stack_pop(stack, &t.loc)?;
|
||||||
|
stack.push(b - a);
|
||||||
|
},
|
||||||
|
InstructionType::Plus => {
|
||||||
|
let a = stack_pop(stack, &t.loc)?;
|
||||||
|
let b = stack_pop(stack, &t.loc)?;
|
||||||
|
stack.push(b + a);
|
||||||
|
},
|
||||||
|
InstructionType::DivMod => {
|
||||||
|
let a = stack_pop(stack, &t.loc)?;
|
||||||
|
let b = stack_pop(stack, &t.loc)?;
|
||||||
|
stack.push(b / a);
|
||||||
|
stack.push(b % a);
|
||||||
|
},
|
||||||
|
InstructionType::Mul => {
|
||||||
|
let a = stack_pop(stack, &t.loc)?;
|
||||||
|
let b = stack_pop(stack, &t.loc)?;
|
||||||
|
stack.push(b * a);
|
||||||
|
},
|
||||||
|
InstructionType::Drop => {
|
||||||
|
stack_pop(stack, &t.loc)?;
|
||||||
|
},
|
||||||
|
//TODO: Support these later
|
||||||
|
// InstructionType::Dup => todo!(),
|
||||||
|
// InstructionType::Rot => todo!(),
|
||||||
|
// InstructionType::Over => todo!(),
|
||||||
|
// InstructionType::Swap => todo!(),
|
||||||
|
// InstructionType::Equals => todo!(),
|
||||||
|
// InstructionType::Gt => todo!(),
|
||||||
|
// InstructionType::Lt => todo!(),
|
||||||
|
// InstructionType::Ge => todo!(),
|
||||||
|
// InstructionType::Le => todo!(),
|
||||||
|
// InstructionType::NotEquals => todo!(),
|
||||||
|
// InstructionType::Band => todo!(),
|
||||||
|
// InstructionType::Bor => todo!(),
|
||||||
|
// InstructionType::Shr => todo!(),
|
||||||
|
// InstructionType::Shl => todo!(),
|
||||||
|
//TODO: Support this when we have types
|
||||||
|
// InstructionType::CastBool => todo!(),
|
||||||
|
// InstructionType::CastPtr => todo!(),
|
||||||
|
// InstructionType::CastInt => todo!(),
|
||||||
|
// InstructionType::CastVoid => todo!(),
|
||||||
|
InstructionType::ConstUse => unreachable!(),
|
||||||
|
_ => {
|
||||||
|
error!({loc => t.loc.clone()}, "Unsupported token {t:?}, we dont support precompilation of this") ;
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
TokenType::Unknown(_) => unreachable!(),
|
||||||
|
TokenType::Type(_) => {
|
||||||
|
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
|
||||||
|
bail!("")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//TODO: Implement these
|
||||||
|
t @ AstNode::If { .. } |
|
||||||
|
t @ AstNode::While { .. } |
|
||||||
|
t => {
|
||||||
|
error!({loc => t.loc()}, "Unsupported token {t:?}, we dont support precompilation of this") ;
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(AstNode::Int(ast[0].loc(), stack[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> anyhow::Result<usize> {
|
||||||
|
match stack.pop() {
|
||||||
|
Some(i) => Ok(i),
|
||||||
|
None => {
|
||||||
|
error!({loc => loc.clone()}, "Failed to precompile tokens, failed to pop from stack");
|
||||||
|
bail!("")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
103
src/parser/utils.rs
Normal file
103
src/parser/utils.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
use anyhow::{bail, Result};
|
||||||
|
|
||||||
|
use crate::types::token::{Token, TokenType};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd)]
|
||||||
|
pub enum PeekResult<T> {
|
||||||
|
Correct(T),
|
||||||
|
Wrong(T),
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PeekResult<T> {
|
||||||
|
pub fn correct(&self) -> bool{
|
||||||
|
match self {
|
||||||
|
PeekResult::Correct(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn wrong(&self) -> bool{
|
||||||
|
match self {
|
||||||
|
PeekResult::Wrong(_) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn none(&self) -> bool{
|
||||||
|
match self {
|
||||||
|
PeekResult::None => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cmp(lhs: &TokenType, rhs: &TokenType) -> bool {
|
||||||
|
match (lhs, rhs) {
|
||||||
|
(TokenType::Keyword(lhs), TokenType::Keyword(rhs)) => {
|
||||||
|
std::mem::discriminant(lhs) == std::mem::discriminant(rhs)
|
||||||
|
},
|
||||||
|
(TokenType::Instruction(lhs), TokenType::Instruction(rhs)) => {
|
||||||
|
std::mem::discriminant(lhs) == std::mem::discriminant(rhs)
|
||||||
|
},
|
||||||
|
(TokenType::Type(lhs), TokenType::Type(rhs)) => {
|
||||||
|
std::mem::discriminant(lhs) == std::mem::discriminant(rhs)
|
||||||
|
},
|
||||||
|
(TokenType::Unknown(_), TokenType::Unknown(_)) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek_check_multiple(tokens: &Vec<Token>, typs: Vec<TokenType>) -> PeekResult<&Token>{
|
||||||
|
let t = tokens.last();
|
||||||
|
|
||||||
|
if let Some(t) = t {
|
||||||
|
for tt in typs.clone() {
|
||||||
|
if cmp(&t.typ, &tt) {
|
||||||
|
return PeekResult::Correct(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PeekResult::Wrong(t)
|
||||||
|
} else {
|
||||||
|
PeekResult::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn peek_check(tokens: &Vec<Token>, typ: TokenType) -> PeekResult<&Token> {
|
||||||
|
let t = tokens.last();
|
||||||
|
|
||||||
|
match t {
|
||||||
|
Some(t) => {
|
||||||
|
//? Source: https://doc.rust-lang.org/std/mem/fn.discriminant.html
|
||||||
|
if cmp(&t.typ, &typ) {
|
||||||
|
PeekResult::Correct(t)
|
||||||
|
} else {
|
||||||
|
PeekResult::Wrong(t)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
PeekResult::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expect(tokens: &mut Vec<Token>, typ: TokenType) -> Result<Token> {
|
||||||
|
let t = tokens.pop();
|
||||||
|
|
||||||
|
match t {
|
||||||
|
Some(t) => {
|
||||||
|
//? Source: https://doc.rust-lang.org/std/mem/fn.discriminant.html
|
||||||
|
if std::mem::discriminant(&t.typ) != std::mem::discriminant(&typ) {
|
||||||
|
error!({loc => t.loc()}, "Expected {:?}, but got {:?}", typ, t.typ);
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
Ok(t)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
error!("Expected {:?}, but found nothing", typ);
|
||||||
|
bail!("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,147 +0,0 @@
|
||||||
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
use crate::{constants::{ OpType, InstructionType, Loc, Operator}, lerror};
|
|
||||||
|
|
||||||
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
|
|
||||||
if let Some(i) = stack.pop() { Ok(i) } else {
|
|
||||||
lerror!(&loc.clone(), "Stack underflow");
|
|
||||||
Err(eyre!("Stack underflow"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn precompile(tokens: &Vec<Operator>) -> Result<Vec<usize>>{
|
|
||||||
|
|
||||||
let mut stack: Vec<usize> = Vec::new();
|
|
||||||
for token in tokens.iter() {
|
|
||||||
match token.typ.clone() {
|
|
||||||
OpType::Instruction(i) => {
|
|
||||||
let loc = token.loc.clone();
|
|
||||||
match i {
|
|
||||||
InstructionType::PushInt => {
|
|
||||||
stack.push(token.value);
|
|
||||||
},
|
|
||||||
InstructionType::Plus => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b + a);
|
|
||||||
},
|
|
||||||
InstructionType::Minus => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b - a);
|
|
||||||
},
|
|
||||||
InstructionType::Equals => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b == a));
|
|
||||||
},
|
|
||||||
InstructionType::Gt => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b > a));
|
|
||||||
},
|
|
||||||
InstructionType::Lt => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b < a));
|
|
||||||
},
|
|
||||||
InstructionType::NotEquals => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b != a));
|
|
||||||
},
|
|
||||||
InstructionType::Ge => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b >= a));
|
|
||||||
},
|
|
||||||
InstructionType::Le => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(usize::from(b <= a));
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Band => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(a & b);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Bor => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(a | b);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Shr => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b >> a);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::Shl => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b << a);
|
|
||||||
}
|
|
||||||
|
|
||||||
InstructionType::DivMod => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b / a);
|
|
||||||
stack.push(b % a);
|
|
||||||
}
|
|
||||||
InstructionType::Mul => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b * a);
|
|
||||||
}
|
|
||||||
InstructionType::Drop => {
|
|
||||||
stack.pop();
|
|
||||||
},
|
|
||||||
InstructionType::Dup => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(a);
|
|
||||||
},
|
|
||||||
|
|
||||||
InstructionType::Rot => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
let c = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b);
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(c);
|
|
||||||
}
|
|
||||||
InstructionType::Swap => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
}
|
|
||||||
InstructionType::Over => {
|
|
||||||
let a = stack_pop(&mut stack, &loc)?;
|
|
||||||
let b = stack_pop(&mut stack, &loc)?;
|
|
||||||
stack.push(b);
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
lerror!(&token.loc, "Unsupported precompiler instruction {:?}", i);
|
|
||||||
dbg!(tokens);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpType::Keyword(_) => {
|
|
||||||
lerror!(&token.loc, "Unsupported precompiler keyword {:?}", token.typ);
|
|
||||||
dbg!(tokens);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(stack)
|
|
||||||
}
|
|
|
@ -1,617 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ops::Deref;
|
|
||||||
use std::path::{PathBuf, Path};
|
|
||||||
|
|
||||||
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
use crate::constants::{Loc, OpType, TokenType, KeywordType, InstructionType, Operator};
|
|
||||||
use crate::lexer::lex;
|
|
||||||
use crate::precompiler::precompile;
|
|
||||||
use crate::{lerror, Args, warn, linfo, parser};
|
|
||||||
use crate::parser::lookup_word;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String,
|
|
||||||
pub inline: bool,
|
|
||||||
pub tokens: Option<Vec<Operator>>
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Constant {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub name: String
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Memory {
|
|
||||||
pub loc: Loc,
|
|
||||||
pub id: usize
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type Functions = HashMap<String, Function>;
|
|
||||||
type Memories = HashMap<String, Memory>;
|
|
||||||
type Constants = HashMap<String, Constant>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Preprocessor<'a> {
|
|
||||||
pub program: Vec<Operator>,
|
|
||||||
pub functions: Functions,
|
|
||||||
pub memories: Memories,
|
|
||||||
pub constants: Constants,
|
|
||||||
args: &'a Args
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> Preprocessor<'a> {
|
|
||||||
pub fn new(prog: Vec<Operator>, args: &'a Args) -> Self {
|
|
||||||
Self {
|
|
||||||
program: prog,
|
|
||||||
args,
|
|
||||||
functions: HashMap::new(),
|
|
||||||
memories: HashMap::new(),
|
|
||||||
constants: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{
|
|
||||||
// println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
|
||||||
|
|
||||||
let mut f_inline = false;
|
|
||||||
let mut f_extern = false;
|
|
||||||
|
|
||||||
let mut program: Vec<Operator> = Vec::new();
|
|
||||||
|
|
||||||
let mut rtokens = self.program.clone();
|
|
||||||
rtokens.reverse();
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let mut op = rtokens.pop().unwrap();
|
|
||||||
// println!("{token:?}");
|
|
||||||
let op_type = op.typ.clone();
|
|
||||||
match op_type {
|
|
||||||
OpType::Keyword(KeywordType::Include) => {
|
|
||||||
if rtokens.is_empty() {
|
|
||||||
lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let include_path = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
if include_path.tok_typ != TokenType::String {
|
|
||||||
lerror!(&include_path.loc, "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut in_paths = self.args.include.clone();
|
|
||||||
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
|
|
||||||
|
|
||||||
let mut include_code = String::new();
|
|
||||||
let mut pth = PathBuf::new();
|
|
||||||
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
|
|
||||||
let p = Path::new(include_path.loc.0.as_str());
|
|
||||||
let p = p.parent().unwrap();
|
|
||||||
let p = p.join(&include_path.text);
|
|
||||||
pth = p.clone();
|
|
||||||
include_code = std::fs::read_to_string(p)?;
|
|
||||||
} else {
|
|
||||||
for path in in_paths {
|
|
||||||
let p = PathBuf::from(path);
|
|
||||||
let p = p.join(&include_path.text);
|
|
||||||
pth = p.clone();
|
|
||||||
|
|
||||||
if p.exists() {
|
|
||||||
include_code = std::fs::read_to_string(p)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if include_code.is_empty() {
|
|
||||||
lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let a = pth.to_str().unwrap().to_string();
|
|
||||||
let code = lex(&include_code, a.as_str(), self.args);
|
|
||||||
let mut p = parser::Parser::new(code, self.args, Some(self.clone()));
|
|
||||||
let mut code = p.parse()?;
|
|
||||||
|
|
||||||
self.set_constants(p.preprocessor.get_constants());
|
|
||||||
self.set_functions(p.preprocessor.get_functions());
|
|
||||||
self.set_memories(p.preprocessor.get_memories());
|
|
||||||
code.reverse();
|
|
||||||
rtokens.append(&mut code);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Memory) => {
|
|
||||||
if rtokens.is_empty() {
|
|
||||||
lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
self.is_word_available(&name, KeywordType::Memory)?;
|
|
||||||
|
|
||||||
let mut code: Vec<Operator> = Vec::new();
|
|
||||||
|
|
||||||
let mut depth = 0;
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let t = rtokens.pop().unwrap();
|
|
||||||
let typ = t.typ.clone();
|
|
||||||
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
|
|
||||||
break;
|
|
||||||
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
|
|
||||||
depth -= 1;
|
|
||||||
code.push(t);
|
|
||||||
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
|
|
||||||
code.push(t);
|
|
||||||
depth += 1;
|
|
||||||
} else {
|
|
||||||
code.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let res = precompile(&code)?;
|
|
||||||
|
|
||||||
|
|
||||||
if res.len() != 1 {
|
|
||||||
lerror!(&op.loc, "Expected 1 number, got {:?}", res);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
op.value = res[0];
|
|
||||||
op.addr = Some(self.memories.len());
|
|
||||||
program.push(op.clone());
|
|
||||||
|
|
||||||
self.memories.insert(name.text, Memory { loc: op.loc, id: self.memories.len() });
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Function) => {
|
|
||||||
if rtokens.is_empty() {
|
|
||||||
lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut name = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
if let '0'..='9' = name.text.chars().next().unwrap() {
|
|
||||||
lerror!(&name.loc, "Function name starts with a number which is not allowed");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
// let mut should_warn = false;
|
|
||||||
for c in name.text.clone().chars() {
|
|
||||||
match c {
|
|
||||||
'a'..='z' |
|
|
||||||
'A'..='Z' |
|
|
||||||
'0'..='9' |
|
|
||||||
'-' | '_' => (),
|
|
||||||
'(' | ')' => {
|
|
||||||
name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
lerror!(&name.loc, "Function name contains '{c}', which is unsupported");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if should_warn {
|
|
||||||
//TODO: add -W option in cli args to enable more warnings
|
|
||||||
//lwarn!(&function_name.loc, "Function name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively ");
|
|
||||||
// }
|
|
||||||
|
|
||||||
self.is_word_available(&name, KeywordType::Function)?;
|
|
||||||
|
|
||||||
|
|
||||||
if f_inline {
|
|
||||||
f_inline = false;
|
|
||||||
let mut prog: Vec<Operator> = Vec::new();
|
|
||||||
let mut depth = -1;
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let op = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
match op.typ.clone() {
|
|
||||||
OpType::Instruction(i) => {
|
|
||||||
match i {
|
|
||||||
InstructionType::TypeAny |
|
|
||||||
InstructionType::TypeBool |
|
|
||||||
InstructionType::TypeInt |
|
|
||||||
InstructionType::TypePtr |
|
|
||||||
InstructionType::With |
|
|
||||||
InstructionType::Returns |
|
|
||||||
InstructionType::TypeVoid => {
|
|
||||||
if depth >= 0 {
|
|
||||||
prog.push(op);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => prog.push(op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OpType::Keyword(k) => {
|
|
||||||
match k {
|
|
||||||
KeywordType::Inline |
|
|
||||||
KeywordType::Include => {
|
|
||||||
todo!("make error")
|
|
||||||
},
|
|
||||||
KeywordType::FunctionThen => {
|
|
||||||
if depth >= 0 {
|
|
||||||
prog.push(op);
|
|
||||||
}
|
|
||||||
depth += 1;
|
|
||||||
},
|
|
||||||
KeywordType::FunctionDone => {
|
|
||||||
if depth == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
depth -= 1;
|
|
||||||
},
|
|
||||||
_ => prog.push(op)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let mut pre = self.clone();
|
|
||||||
pre.program = prog;
|
|
||||||
pre.preprocess()?;
|
|
||||||
prog = pre.get_ops();
|
|
||||||
|
|
||||||
self.functions.insert(name.text.clone(), Function{
|
|
||||||
loc: name.loc.clone(),
|
|
||||||
name: name.text.clone(),
|
|
||||||
inline: true,
|
|
||||||
tokens: Some(prog)
|
|
||||||
});
|
|
||||||
|
|
||||||
} else if f_extern {
|
|
||||||
f_extern = false;
|
|
||||||
self.functions.insert(name.text.clone(), Function{
|
|
||||||
loc: name.loc.clone(),
|
|
||||||
name: name.text.clone(),
|
|
||||||
inline: false,
|
|
||||||
tokens: None
|
|
||||||
});
|
|
||||||
let mut a: Vec<Operator> = Vec::new();
|
|
||||||
let mut fn_def = op.clone();
|
|
||||||
a.push(rtokens.pop().unwrap());
|
|
||||||
let mut ret = false;
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let op = rtokens.pop().unwrap();
|
|
||||||
// println!("{:?}",op);
|
|
||||||
a.push(op.clone());
|
|
||||||
if op.typ == OpType::Instruction(InstructionType::Returns) {
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.typ == OpType::Keyword(KeywordType::FunctionThen) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.typ == OpType::Instruction(InstructionType::TypeBool) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypeInt) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypePtr) {
|
|
||||||
|
|
||||||
if ret {
|
|
||||||
fn_def.types.1 += 1;
|
|
||||||
} else {
|
|
||||||
fn_def.types.0 += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn_def.typ = OpType::Keyword(KeywordType::FunctionDefExported);
|
|
||||||
fn_def.text = name.text;
|
|
||||||
// fn_def.set_types(args, rets);
|
|
||||||
// println!("{:?}", fn_def.types);
|
|
||||||
program.push(fn_def);
|
|
||||||
program.append(&mut a);
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
self.functions.insert(name.text.clone(), Function{
|
|
||||||
loc: name.loc.clone(),
|
|
||||||
name: name.text.clone(),
|
|
||||||
inline: false,
|
|
||||||
tokens: None
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut fn_def = op.clone();
|
|
||||||
fn_def.typ = OpType::Keyword(KeywordType::FunctionDef);
|
|
||||||
fn_def.text = name.text;
|
|
||||||
// println!("{:?}", token);
|
|
||||||
program.push(fn_def);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Constant) => {
|
|
||||||
if rtokens.is_empty() {
|
|
||||||
lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
// println!("{token:?}");
|
|
||||||
|
|
||||||
let mut name = rtokens.pop().unwrap();
|
|
||||||
// let mut should_warn = false;
|
|
||||||
|
|
||||||
if let '0'..='9' = name.text.chars().next().unwrap() {
|
|
||||||
lerror!(&name.loc, "Constant name starts with a number which is not allowed");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
for c in name.text.clone().chars() {
|
|
||||||
match c {
|
|
||||||
'a'..='z' |
|
|
||||||
'A'..='Z' |
|
|
||||||
'0'..='9' |
|
|
||||||
'-' | '_' => (),
|
|
||||||
'(' | ')' => {
|
|
||||||
// should_warn = true;
|
|
||||||
name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__");
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
lerror!(&name.loc, "Constant name contains '{c}', which is unsupported");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if should_warn {
|
|
||||||
//TODO: add -W option in cli args to enable more warnings
|
|
||||||
//lwarn!(&name.loc, "Constant name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively ");
|
|
||||||
// }
|
|
||||||
|
|
||||||
self.is_word_available(&name, KeywordType::Constant)?;
|
|
||||||
|
|
||||||
|
|
||||||
self.constants.insert(name.text.clone(), Constant{
|
|
||||||
loc: name.loc.clone(),
|
|
||||||
name: name.text.clone(),
|
|
||||||
});
|
|
||||||
|
|
||||||
// println!("{:?}", self.constants);
|
|
||||||
|
|
||||||
let mut const_def = op.clone();
|
|
||||||
const_def.typ = OpType::Keyword(KeywordType::ConstantDef);
|
|
||||||
const_def.text = name.text;
|
|
||||||
|
|
||||||
let item = rtokens.pop().unwrap();
|
|
||||||
if item.tok_typ == TokenType::Int {
|
|
||||||
const_def.value = item.value;
|
|
||||||
} else {
|
|
||||||
lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let posibly_end = rtokens.pop();
|
|
||||||
// println!("end: {posibly_end:?}");
|
|
||||||
if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) {
|
|
||||||
lerror!(&op.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
// token.value =
|
|
||||||
|
|
||||||
program.push(const_def);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Inline) => {
|
|
||||||
if f_extern {
|
|
||||||
lerror!(&op.loc, "Function is already marked as extern, function cannot be inline and extern at the same time");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
} else if f_inline {
|
|
||||||
lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
} else {
|
|
||||||
f_inline = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OpType::Keyword(KeywordType::Export) => {
|
|
||||||
if f_inline {
|
|
||||||
lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and extern at the same time");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
} else if f_extern {
|
|
||||||
lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
} else {
|
|
||||||
f_extern = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
program.push(op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.program = program;
|
|
||||||
// println!("has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
|
||||||
//* Feel free to fix this horrifying shit
|
|
||||||
//* i wanna kms
|
|
||||||
let mut times = 0;
|
|
||||||
// dbg!(program.clone());
|
|
||||||
while self.program.iter().map(|f| {
|
|
||||||
if f.tok_typ == TokenType::Word &&
|
|
||||||
f.typ != OpType::Instruction(InstructionType::FnCall) &&
|
|
||||||
f.typ != OpType::Instruction(InstructionType::MemUse) &&
|
|
||||||
f.typ != OpType::Keyword(KeywordType::FunctionDef) &&
|
|
||||||
f.typ != OpType::Keyword(KeywordType::FunctionDefExported) &&
|
|
||||||
f.typ != OpType::Keyword(KeywordType::ConstantDef) &&
|
|
||||||
f.typ != OpType::Instruction(InstructionType::ConstUse) {
|
|
||||||
lookup_word(&f.text, &f.loc)
|
|
||||||
} else {
|
|
||||||
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
|
|
||||||
}
|
|
||||||
|
|
||||||
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
|
|
||||||
|
|
||||||
if times >= 50 {
|
|
||||||
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
|
|
||||||
break
|
|
||||||
}
|
|
||||||
self.expand()?;
|
|
||||||
times += 1;
|
|
||||||
}
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expand(&mut self) -> Result<()> {
|
|
||||||
let mut program: Vec<Operator> = Vec::new();
|
|
||||||
// println!("{:?}", self.functions);
|
|
||||||
let mut rtokens = self.program.clone();
|
|
||||||
rtokens.reverse();
|
|
||||||
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let op = rtokens.pop().unwrap();
|
|
||||||
let op_type = op.typ.clone();
|
|
||||||
if op.tok_typ == TokenType::Word {
|
|
||||||
match op_type {
|
|
||||||
OpType::Instruction(InstructionType::None) => {
|
|
||||||
let m = self.functions.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"));
|
|
||||||
let mem = self.memories.get(&op.text);
|
|
||||||
let cons = self.constants.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"));
|
|
||||||
if let Some(m) = m {
|
|
||||||
if m.inline {
|
|
||||||
program.append(&mut m.tokens.clone().unwrap());
|
|
||||||
} else {
|
|
||||||
let mut t = op.clone();
|
|
||||||
t.typ = OpType::Instruction(InstructionType::FnCall);
|
|
||||||
t.text = m.name.clone();
|
|
||||||
program.push(t.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// println!("##### {:?}", t);
|
|
||||||
} else if let Some(mem) = mem {
|
|
||||||
let mut t = op.clone();
|
|
||||||
t.addr = Some(mem.deref().id);
|
|
||||||
t.typ = OpType::Instruction(InstructionType::MemUse);
|
|
||||||
program.push(t);
|
|
||||||
} else if let Some(cons) = cons {
|
|
||||||
let mut t = op.clone();
|
|
||||||
t.text = cons.deref().name.clone();
|
|
||||||
t.typ = OpType::Instruction(InstructionType::ConstUse);
|
|
||||||
program.push(t);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
lerror!(&op.loc, "Preprocess: Unknown word '{}'", op.text.clone());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
program.push(op.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
program.push(op.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// if op.typ == OpType::Keyword(KeywordType::Do) {
|
|
||||||
// println!("expand: {:?}", op);
|
|
||||||
// program.push(op.clone());
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
// println!("expand: has do tokens: {:?}", program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
|
||||||
|
|
||||||
self.program = program;
|
|
||||||
// println!("{:#?}", self.program);
|
|
||||||
// println!("{:?}", self.program.last().unwrap());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub fn get_ops(&mut self) -> Vec<Operator> {
|
|
||||||
self.program.clone()
|
|
||||||
}
|
|
||||||
pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result<bool> {
|
|
||||||
|
|
||||||
match typ {
|
|
||||||
KeywordType::Memory |
|
|
||||||
KeywordType::Constant |
|
|
||||||
KeywordType::Function => (),
|
|
||||||
_ => panic!()
|
|
||||||
}
|
|
||||||
|
|
||||||
if word.tok_typ != TokenType::Word {
|
|
||||||
lerror!(&word.loc, "Bad {typ:?}, expected {} but found {}", TokenType::Word.human(), word.typ.human());
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let w = lookup_word(&word.text, &word.loc);
|
|
||||||
if w != OpType::Instruction(InstructionType::None) {
|
|
||||||
lerror!(&word.loc, "Bad {typ:?}, {typ:?} definition cannot be builtin word, got {:?}", word.text);
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let m = self.memories.get(&word.text);
|
|
||||||
if let Some(m) = m {
|
|
||||||
if typ == KeywordType::Memory {
|
|
||||||
lerror!(&word.loc, "Memories cannot be redefined, got {}", word.text);
|
|
||||||
linfo!(&m.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
lerror!(&word.loc, "{typ:?} cannot replace memory, got {}", word.text);
|
|
||||||
linfo!(&m.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let f = self.functions.get(&word.text);
|
|
||||||
if let Some(f) = f {
|
|
||||||
if typ == KeywordType::Function {
|
|
||||||
lerror!(&word.loc, "Functions cannot be redefined, got {}", word.text);
|
|
||||||
linfo!(&f.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
lerror!(&word.loc, "{typ:?} cannot replace function, got {}", word.text);
|
|
||||||
linfo!(&f.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let c = self.constants.get(&word.text);
|
|
||||||
if let Some(c) = c {
|
|
||||||
if typ == KeywordType::Constant {
|
|
||||||
lerror!(&word.loc, "Constants cannot be redefined, got {}", word.text);
|
|
||||||
linfo!(&c.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
lerror!(&word.loc, "{typ:?} cannot replace constant, got {}", word.text);
|
|
||||||
linfo!(&c.loc, "first definition here");
|
|
||||||
if crate::DEV_MODE {println!("{word:?}")}
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_functions(&mut self, f: Functions) {
|
|
||||||
self.functions = f;
|
|
||||||
}
|
|
||||||
pub fn set_constants(&mut self, f: Constants) {
|
|
||||||
self.constants = f;
|
|
||||||
}
|
|
||||||
pub fn set_memories(&mut self, f: Memories) {
|
|
||||||
self.memories = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_functions(&mut self) -> Functions {
|
|
||||||
self.functions.clone()
|
|
||||||
}
|
|
||||||
pub fn get_constants(&mut self) -> Constants {
|
|
||||||
self.constants.clone()
|
|
||||||
}
|
|
||||||
pub fn get_memories(&mut self) -> Memories{
|
|
||||||
self.memories.clone()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,403 +0,0 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType, Loc}, Args, lerror, warn};
|
|
||||||
use color_eyre::Result;
|
|
||||||
use eyre::eyre;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
loc: Loc,
|
|
||||||
args: Vec<Types>,
|
|
||||||
returns: Vec<Types>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Constant {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
loc: Loc,
|
|
||||||
types: Vec<Types>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
args: Vec::new(),
|
|
||||||
returns: Vec::new(),
|
|
||||||
loc: (String::new(), 0, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type Functions = HashMap<String, Function>;
|
|
||||||
type Constants = HashMap<String, Constant>;
|
|
||||||
|
|
||||||
pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>, funcs: HashMap<String, Function>, consts: HashMap<String, Constant>) -> Result<(Vec<Types>, Functions, Constants)>{
|
|
||||||
if args.unsaf {
|
|
||||||
if !args.quiet {
|
|
||||||
warn!("Unsafe mode enabled, disabling typechecker, goodluck");
|
|
||||||
}
|
|
||||||
return Ok((Vec::new(), HashMap::new(), HashMap::new()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut functions: HashMap<String, Function> = funcs;
|
|
||||||
let mut constants: HashMap<String, Constant> = consts;
|
|
||||||
// let mut in_function: (String, Function, Loc) = (String::new(), Function::default(), (String::new(), 0, 0));
|
|
||||||
let mut stack: Vec<Types> = if let Some(i) = init_types {i} else {Vec::new()};
|
|
||||||
let mut stack_snapshots: Vec<Vec<Types>> = Vec::new();
|
|
||||||
let mut rtokens = ops;
|
|
||||||
rtokens.reverse();
|
|
||||||
// println!("{:#?}", ops);
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let op = rtokens.pop().unwrap();
|
|
||||||
// println!("{:?}", stack.clone());
|
|
||||||
// println!("{:?}", op);
|
|
||||||
// println!("{}", ops.len());
|
|
||||||
match op.typ.clone() {
|
|
||||||
OpType::Keyword(keyword) => {
|
|
||||||
match keyword {
|
|
||||||
KeywordType::If |
|
|
||||||
KeywordType::Do => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
|
||||||
},
|
|
||||||
|
|
||||||
KeywordType::FunctionDefExported |
|
|
||||||
KeywordType::FunctionDef => {
|
|
||||||
let name = op.text.clone();
|
|
||||||
// println!("{:?}", name);
|
|
||||||
if let Some(p) = rtokens.pop() {
|
|
||||||
if p.typ != OpType::Instruction(InstructionType::With){
|
|
||||||
lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
lerror!(&op.loc, "Expected {:?}, got nothing", OpType::Instruction(InstructionType::With));
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut p = rtokens.pop();
|
|
||||||
let mut func = Function {
|
|
||||||
args: Vec::new(),
|
|
||||||
returns: Vec::new(),
|
|
||||||
loc: op.loc
|
|
||||||
};
|
|
||||||
let mut return_args = false;
|
|
||||||
while p.as_ref().is_some() {
|
|
||||||
let op = p.as_ref().unwrap();
|
|
||||||
if op.typ == OpType::Instruction(InstructionType::TypeBool) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypeInt) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypePtr) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypeAny) ||
|
|
||||||
op.typ == OpType::Instruction(InstructionType::TypeVoid) {
|
|
||||||
let t = if op.typ == OpType::Instruction(InstructionType::TypeInt) {
|
|
||||||
Types::Int
|
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypeBool) {
|
|
||||||
Types::Bool
|
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypePtr) {
|
|
||||||
Types::Ptr
|
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypeVoid) {
|
|
||||||
if return_args {
|
|
||||||
func.returns = vec![Types::Void];
|
|
||||||
} else {
|
|
||||||
func.args = vec![Types::Void];
|
|
||||||
return_args = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Types::Void
|
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypeAny) {
|
|
||||||
Types::Any
|
|
||||||
} else {
|
|
||||||
panic!()
|
|
||||||
};
|
|
||||||
|
|
||||||
if return_args {
|
|
||||||
func.returns.push(t);
|
|
||||||
} else {
|
|
||||||
func.args.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.typ == OpType::Instruction(InstructionType::Returns) {
|
|
||||||
return_args = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.typ == OpType::Keyword(KeywordType::FunctionThen) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p = rtokens.pop();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let mut code: Vec<Operator> = Vec::new();
|
|
||||||
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let op = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
if op.typ == OpType::Keyword(KeywordType::FunctionDone) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
code.push(op);
|
|
||||||
}
|
|
||||||
let ts = if func.args.clone() == vec![Types::Void] {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
func.args.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
if ts.contains(&Types::Void) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
functions.insert(name.clone(), func.clone());
|
|
||||||
let (ret_typs, _, _) = typecheck(code, args, Some(ts.clone()), functions.clone(), constants.clone())?;
|
|
||||||
if ret_typs != func.returns && !func.returns.contains(&Types::Void){
|
|
||||||
lerror!(&func.loc, "Expected {:?}, but got {:?}", func.returns, ret_typs);
|
|
||||||
return Err(eyre!(""))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !func.args.contains(&Types::Void) {
|
|
||||||
stack.append(&mut func.args);
|
|
||||||
}
|
|
||||||
stack_snapshots.push(stack.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
KeywordType::Else |
|
|
||||||
KeywordType::End |
|
|
||||||
KeywordType::While |
|
|
||||||
KeywordType::Include |
|
|
||||||
KeywordType::Constant |
|
|
||||||
KeywordType::Memory => (),
|
|
||||||
KeywordType::ConstantDef => {
|
|
||||||
// println!("defined constant");
|
|
||||||
constants.insert(op.text, Constant { loc: op.loc.clone(), types: vec![Types::Int] });
|
|
||||||
|
|
||||||
},
|
|
||||||
KeywordType::FunctionThen |
|
|
||||||
KeywordType::FunctionDone |
|
|
||||||
KeywordType::Inline |
|
|
||||||
KeywordType::Export |
|
|
||||||
KeywordType::Function => {
|
|
||||||
println!("{:?}", op);
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
OpType::Instruction(instruction) => {
|
|
||||||
match instruction {
|
|
||||||
InstructionType::PushInt => {
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::PushStr => {
|
|
||||||
stack.push(Types::Int);
|
|
||||||
stack.push(Types::Ptr);
|
|
||||||
|
|
||||||
},
|
|
||||||
InstructionType::Drop => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
},
|
|
||||||
InstructionType::Print => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
},
|
|
||||||
InstructionType::Dup => {
|
|
||||||
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(a);
|
|
||||||
},
|
|
||||||
InstructionType::Rot => {
|
|
||||||
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
let c = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(b);
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(c);
|
|
||||||
},
|
|
||||||
InstructionType::Over => {
|
|
||||||
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(b.clone());
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
},
|
|
||||||
InstructionType::Swap => {
|
|
||||||
let a = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
let b = stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(a);
|
|
||||||
stack.push(b);
|
|
||||||
},
|
|
||||||
InstructionType::Minus |
|
|
||||||
InstructionType::Plus |
|
|
||||||
InstructionType::Band |
|
|
||||||
InstructionType::Bor |
|
|
||||||
InstructionType::Shr |
|
|
||||||
InstructionType::Shl |
|
|
||||||
InstructionType::Mul => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Equals |
|
|
||||||
InstructionType::Gt |
|
|
||||||
InstructionType::Lt |
|
|
||||||
InstructionType::Ge |
|
|
||||||
InstructionType::Le |
|
|
||||||
InstructionType::NotEquals => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack.push(Types::Bool);
|
|
||||||
},
|
|
||||||
InstructionType::DivMod => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Load8 |
|
|
||||||
InstructionType::Load32 |
|
|
||||||
InstructionType::Load64 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Store8 |
|
|
||||||
InstructionType::Store32 |
|
|
||||||
InstructionType::Store64 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Ptr])?;
|
|
||||||
},
|
|
||||||
InstructionType::Syscall0 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall1 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall2 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall3 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall4 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall5 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::Syscall6 => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Int])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::CastBool => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Bool);
|
|
||||||
},
|
|
||||||
InstructionType::CastPtr => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Ptr);
|
|
||||||
},
|
|
||||||
InstructionType::CastInt => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Int);
|
|
||||||
},
|
|
||||||
InstructionType::CastVoid => {
|
|
||||||
stack_pop(&mut stack, &op, &[Types::Any])?;
|
|
||||||
stack.push(Types::Any);
|
|
||||||
},
|
|
||||||
InstructionType::MemUse => {
|
|
||||||
stack.push(Types::Ptr);
|
|
||||||
},
|
|
||||||
InstructionType::FnCall => {
|
|
||||||
stack_snapshots.push(stack.clone());
|
|
||||||
|
|
||||||
let f = if let Some(f) = functions.get(&op.text) {f} else {
|
|
||||||
lerror!(&op.loc, "Could not find function {}", op.text);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
};
|
|
||||||
|
|
||||||
// in_function = (op.text.clone(), f.clone(), op.loc.clone());
|
|
||||||
|
|
||||||
let mut s = stack.clone();
|
|
||||||
let mut a = f.args.clone();
|
|
||||||
// s.reverse();
|
|
||||||
a.reverse();
|
|
||||||
|
|
||||||
for t in a{
|
|
||||||
if let Some(s2) = s.pop(){
|
|
||||||
if t != s2 {
|
|
||||||
lerror!(&op.loc, "Expected {:?}, but got {:?}", t, s2);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
InstructionType::Return |
|
|
||||||
InstructionType::None |
|
|
||||||
InstructionType::TypeBool |
|
|
||||||
InstructionType::TypePtr |
|
|
||||||
InstructionType::TypeInt |
|
|
||||||
InstructionType::TypeVoid |
|
|
||||||
InstructionType::TypeAny |
|
|
||||||
InstructionType::Returns |
|
|
||||||
InstructionType::With => (),
|
|
||||||
InstructionType::ConstUse => {
|
|
||||||
// println!("{constants:?}");
|
|
||||||
let mut c = constants.get(&op.text).unwrap().clone();
|
|
||||||
stack.append(&mut c.types);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok((stack, functions, constants))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fn stack_pop(v: &mut Vec<Types>, op: &Operator, t: &[Types]) -> Result<Types> {
|
|
||||||
if v.is_empty() {
|
|
||||||
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let r = v.pop().unwrap();
|
|
||||||
|
|
||||||
if !t.contains(&r) && t[0] != Types::Any {
|
|
||||||
lerror!(&op.loc, "Expected {:?}, but got {:?}", t, r);
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(r)
|
|
||||||
}
|
|
215
src/types/ast/mod.rs
Normal file
215
src/types/ast/mod.rs
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use super::{common::Loc, token::{Token, TypeType}};
|
||||||
|
|
||||||
|
|
||||||
|
//TODO: Implement missing stuff
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum AstNode {
|
||||||
|
Int(Loc, usize),
|
||||||
|
Str(Loc, String),
|
||||||
|
CStr(Loc, String),
|
||||||
|
Char(Loc, char),
|
||||||
|
// ExternFnDef {
|
||||||
|
// loc: Loc,
|
||||||
|
// ident: String,
|
||||||
|
// arg_types: Vec<TokenType>,
|
||||||
|
// ret_type: TokenType,
|
||||||
|
// },
|
||||||
|
Function(Function),
|
||||||
|
Constant(Constant),
|
||||||
|
// ExternConstantDef{
|
||||||
|
// loc: Loc,
|
||||||
|
// ident: String,
|
||||||
|
// value: InstructionType
|
||||||
|
// },
|
||||||
|
// StructDef{
|
||||||
|
// loc: Loc,
|
||||||
|
// extrn: bool,
|
||||||
|
// ident: String,
|
||||||
|
// body: Vec<(String, usize)> // (field ident, size in bytes)
|
||||||
|
// },
|
||||||
|
StructDef(StructDef),
|
||||||
|
StructDispPush{
|
||||||
|
loc: Loc,
|
||||||
|
disp: usize,
|
||||||
|
ident: String,
|
||||||
|
},
|
||||||
|
// StructItemPush{
|
||||||
|
// loc: Loc,
|
||||||
|
// disp: usize,
|
||||||
|
// ident: String,
|
||||||
|
// },
|
||||||
|
If(If),
|
||||||
|
While(While),
|
||||||
|
Module(Module),
|
||||||
|
Memory(Memory),
|
||||||
|
MemUse(MemUse),
|
||||||
|
ConstUse(ConstUse),
|
||||||
|
FnCall(FnCall),
|
||||||
|
Block(Block),
|
||||||
|
Token(Token),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AstNode {
|
||||||
|
pub fn loc(&self) -> Loc {
|
||||||
|
match self {
|
||||||
|
AstNode::Function(f) => f.loc.clone(),
|
||||||
|
AstNode::Constant(c) => c.loc.clone(),
|
||||||
|
AstNode::If(t)=> t.loc.clone(),
|
||||||
|
AstNode::While(t)=> t.loc.clone(),
|
||||||
|
AstNode::Module(m) => m.loc.clone(),
|
||||||
|
AstNode::Memory(m) => m.loc.clone(),
|
||||||
|
AstNode::MemUse(t)=> t.loc.clone(),
|
||||||
|
AstNode::ConstUse(t)=> t.loc.clone(),
|
||||||
|
AstNode::FnCall(t)=> t.loc.clone(),
|
||||||
|
AstNode::Block(t)=> t.loc.clone(),
|
||||||
|
AstNode::Token(tok) => tok.loc.clone(),
|
||||||
|
AstNode::Int(loc, _) => loc.clone(),
|
||||||
|
AstNode::Str(loc, _) => loc.clone(),
|
||||||
|
AstNode::CStr(loc, _) => loc.clone(),
|
||||||
|
AstNode::Char(loc, _) => loc.clone(),
|
||||||
|
AstNode::StructDef(s) => s.loc.clone(),
|
||||||
|
AstNode::StructDispPush { loc, ..} => loc.clone(),
|
||||||
|
// AstNode::StructItemPush { loc, .. } => loc.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct StructDef {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
pub body: Vec<(String, usize, TypeType)>, // (field ident, size in bytes)
|
||||||
|
pub size: usize
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct MemUse {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
pub disp: Option<usize>
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ConstUse {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct FnCall {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Block {
|
||||||
|
pub comment: String,
|
||||||
|
pub loc: Loc,
|
||||||
|
pub body: Vec<AstNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct While {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub test: Vec<AstNode>,
|
||||||
|
pub body: Vec<AstNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct If {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub test: Vec<AstNode>,
|
||||||
|
pub body: Vec<AstNode>,
|
||||||
|
pub els: Box<AstNode>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Module {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub path: Vec<String>,
|
||||||
|
pub ident: String,
|
||||||
|
pub body: Vec<AstNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Function {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
pub inline: bool,
|
||||||
|
pub extrn: bool,
|
||||||
|
pub export: bool,
|
||||||
|
pub arg_types: Vec<TypeType>,
|
||||||
|
pub ret_types: Vec<TypeType>,
|
||||||
|
pub body: Vec<AstNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Constant {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
pub value: Box<AstNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Memory {
|
||||||
|
pub loc: Loc,
|
||||||
|
pub ident: String,
|
||||||
|
pub statc: bool,
|
||||||
|
pub size: MemSize // bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Program {
|
||||||
|
pub ast: AstNode,
|
||||||
|
pub functions: HashMap<String, Function>,
|
||||||
|
pub constants: HashMap<String, Constant>,
|
||||||
|
pub memories: HashMap<String, Memory>,
|
||||||
|
pub struct_defs: HashMap<String, StructDef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum MemSize {
|
||||||
|
Size(usize),
|
||||||
|
Type(TypeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EscIdent for FnCall {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EscIdent for ConstUse {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EscIdent for MemUse {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EscIdent for Constant {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl EscIdent for Memory {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl EscIdent for Function {
|
||||||
|
fn ident(&self) -> String {
|
||||||
|
self.ident.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait EscIdent {
|
||||||
|
fn ident(&self) -> String;
|
||||||
|
fn get_ident_escaped(&self) -> String {
|
||||||
|
self.ident().replace("(", "_OPRN_")
|
||||||
|
.replace(")", "_CPRN_")
|
||||||
|
}
|
||||||
|
}
|
37
src/types/common.rs
Normal file
37
src/types/common.rs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq)]
|
||||||
|
pub struct Loc {
|
||||||
|
pub file: String,
|
||||||
|
pub line: usize,
|
||||||
|
pub col: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Loc {
|
||||||
|
pub fn new<T: Into<String>>(f: T, line: usize, col: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
file: f.into(),
|
||||||
|
line,
|
||||||
|
col,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn inc_line(&mut self) {
|
||||||
|
self.line += 1;
|
||||||
|
self.col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inc_col(&mut self) {
|
||||||
|
self.col += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Loc {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}:{}:{}", self.file, self.line, self.col)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
3
src/types/mod.rs
Normal file
3
src/types/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod common;
|
||||||
|
pub mod token;
|
||||||
|
pub mod ast;
|
162
src/types/token/mod.rs
Normal file
162
src/types/token/mod.rs
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use super::{ast::StructDef, common::Loc};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum InstructionType {
|
||||||
|
|
||||||
|
// stack
|
||||||
|
PushInt(usize),
|
||||||
|
PushStr(String),
|
||||||
|
PushCStr(String),
|
||||||
|
PushChar(char),
|
||||||
|
StructPath(Vec<String>), // foo::bar
|
||||||
|
StructItem(Vec<String>), // foo.bar
|
||||||
|
Drop,
|
||||||
|
Print,
|
||||||
|
Dup,
|
||||||
|
Rot, // a b c => b c a
|
||||||
|
Over, // a b => a b a
|
||||||
|
Swap, // a b => b a
|
||||||
|
|
||||||
|
// math
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
Equals,
|
||||||
|
Gt,
|
||||||
|
Lt,
|
||||||
|
Ge,
|
||||||
|
Le,
|
||||||
|
NotEquals,
|
||||||
|
Band, // &
|
||||||
|
Bor, // |
|
||||||
|
Shr, // >>
|
||||||
|
Shl, // <<
|
||||||
|
DivMod, // /
|
||||||
|
Mul,
|
||||||
|
|
||||||
|
|
||||||
|
// mem
|
||||||
|
Read8,
|
||||||
|
Write8,
|
||||||
|
Read32,
|
||||||
|
Write32,
|
||||||
|
Read64,
|
||||||
|
Write64,
|
||||||
|
|
||||||
|
// syscalls
|
||||||
|
Syscall0,
|
||||||
|
Syscall1,
|
||||||
|
Syscall2,
|
||||||
|
Syscall3,
|
||||||
|
Syscall4,
|
||||||
|
Syscall5,
|
||||||
|
Syscall6,
|
||||||
|
|
||||||
|
CastBool,
|
||||||
|
CastPtr,
|
||||||
|
CastInt,
|
||||||
|
CastVoid,
|
||||||
|
|
||||||
|
FnCall,
|
||||||
|
MemUse,
|
||||||
|
ConstUse,
|
||||||
|
|
||||||
|
Return,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum KeywordType {
|
||||||
|
If,
|
||||||
|
Else,
|
||||||
|
End,
|
||||||
|
While,
|
||||||
|
Do,
|
||||||
|
Include,
|
||||||
|
Memory,
|
||||||
|
Constant,
|
||||||
|
Function,
|
||||||
|
Then,
|
||||||
|
Done,
|
||||||
|
StructDef,
|
||||||
|
TypeDef,
|
||||||
|
Inline,
|
||||||
|
Export,
|
||||||
|
Extern,
|
||||||
|
Returns,
|
||||||
|
With,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub enum TypeType {
|
||||||
|
Ptr,
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
Void,
|
||||||
|
Any,
|
||||||
|
Custom(Vec<TypeType>),
|
||||||
|
Struct(StructDef)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TypeType {
|
||||||
|
pub fn get_size(&self) -> usize {
|
||||||
|
match self {
|
||||||
|
TypeType::Ptr => std::mem::size_of::<*const ()>(),
|
||||||
|
TypeType::U8 => 1,
|
||||||
|
TypeType::U16 => 2,
|
||||||
|
TypeType::U32 => 4,
|
||||||
|
TypeType::U64 => 8,
|
||||||
|
TypeType::Void => 0,
|
||||||
|
TypeType::Any => 0,
|
||||||
|
TypeType::Custom(ts) => ts.iter().map(|f| f.get_size()).sum(),
|
||||||
|
TypeType::Struct(s) => s.size,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for TypeType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Ptr => write!(f, "Ptr"),
|
||||||
|
Self::U8 => write!(f, "U8"),
|
||||||
|
Self::U16 => write!(f, "U16"),
|
||||||
|
Self::U32 => write!(f, "U32"),
|
||||||
|
Self::U64 => write!(f, "U64"),
|
||||||
|
Self::Void => write!(f, "Void"),
|
||||||
|
Self::Any => write!(f, "Any"),
|
||||||
|
Self::Custom(arg0) => f.debug_tuple("Custom").field(arg0).finish(),
|
||||||
|
Self::Struct(arg0) => write!(f, "{} {}{:?}", arg0.size, arg0.ident, arg0.body),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum TokenType {
|
||||||
|
Keyword(KeywordType),
|
||||||
|
Type(TypeType),
|
||||||
|
Instruction(InstructionType),
|
||||||
|
Unknown(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct Token {
|
||||||
|
pub typ: TokenType,
|
||||||
|
pub loc: Loc,
|
||||||
|
pub lexem: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
pub fn new(typ: TokenType, loc: Loc, lexem: String) -> Self {
|
||||||
|
Self {
|
||||||
|
typ,
|
||||||
|
loc,
|
||||||
|
lexem,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn loc(&self) -> Loc {
|
||||||
|
self.loc.clone()
|
||||||
|
}
|
||||||
|
}
|
117
src/util.rs
117
src/util.rs
|
@ -1,117 +0,0 @@
|
||||||
// use color_eyre::Result;
|
|
||||||
|
|
||||||
pub mod color {
|
|
||||||
#![allow(dead_code)]
|
|
||||||
pub const NONE: &str = "\x1b[0m";
|
|
||||||
pub const RESET: &str = "\x1b[0m";
|
|
||||||
pub const BRIGHT: &str = "\x1b[1m";
|
|
||||||
pub const DIM: &str = "\x1b[2m";
|
|
||||||
pub const UNDERSCORE: &str = "\x1b[4m";
|
|
||||||
pub const BLINK: &str = "\x1b[5m";
|
|
||||||
pub const REVERSE: &str = "\x1b[7m";
|
|
||||||
pub const HIDDEN: &str = "\x1b[8m";
|
|
||||||
pub const FG_BLACK: &str = "\x1b[30m";
|
|
||||||
pub const FG_RED: &str = "\x1b[31m";
|
|
||||||
pub const FG_GREEN: &str = "\x1b[32m";
|
|
||||||
pub const FG_YELLOW: &str = "\x1b[33m";
|
|
||||||
pub const FG_BLUE: &str = "\x1b[34m";
|
|
||||||
pub const FG_MAGENTA: &str = "\x1b[35m";
|
|
||||||
pub const FG_CYAN: &str = "\x1b[36m";
|
|
||||||
pub const FG_WHITE: &str = "\x1b[37m";
|
|
||||||
pub const BG_BLACK: &str = "\x1b[40m";
|
|
||||||
pub const BG_RED: &str = "\x1b[41m";
|
|
||||||
pub const BG_GREEN: &str = "\x1b[42m";
|
|
||||||
pub const BG_YELLOW: &str = "\x1b[43m";
|
|
||||||
pub const BG_BLUE: &str = "\x1b[44m";
|
|
||||||
pub const BG_MAGENTA: &str = "\x1b[45m";
|
|
||||||
pub const BG_CYAN: &str = "\x1b[46m";
|
|
||||||
pub const BG_WHITE: &str = "\x1b[47m";
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod logger {
|
|
||||||
#![allow(dead_code)]
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::{util::color, constants::Loc};
|
|
||||||
|
|
||||||
pub fn error(msg: &str) {
|
|
||||||
println!("{red}error{r}: {msg}", red=color::FG_RED, r=color::RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn warn(msg: &str) {
|
|
||||||
println!("{yellow}warn{r}: {msg}", yellow=color::FG_YELLOW, r=color::RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn info(msg: &str) {
|
|
||||||
println!("{green}info{r}: {msg}", green=color::FG_GREEN, r=color::RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn note(msg: &str) {
|
|
||||||
println!("{blue}note{r}: {msg}", blue=color::FG_BLUE, r=color::RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub fn lerror<P: Deref<Target = Loc>>(loc: P, msg: &str) {
|
|
||||||
println!("{f}:{r}:{c} {red}error{rs}: {msg}", red=color::FG_RED, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lwarn<P: Deref<Target = Loc>>(loc: P, msg: &str) {
|
|
||||||
println!("{f}:{r}:{c} {yellow}warn{rs}: {msg}", yellow=color::FG_YELLOW, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn linfo<P: Deref<Target = Loc>>(loc: P, msg: &str) {
|
|
||||||
println!("{f}:{r}:{c} {green}info{rs}: {msg}", green=color::FG_GREEN, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lnote<P: Deref<Target = Loc>>(loc: P, msg: &str) {
|
|
||||||
println!("{f}:{r}:{c} {blue}note{rs}: {msg}", blue=color::FG_BLUE, rs=color::RESET, f=loc.0, r=loc.1, c=loc.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn help(msg: &str) {
|
|
||||||
println!("{blue}help{r}: {msg}", blue=color::FG_CYAN, r=color::RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn code_block(code: &str) -> String {
|
|
||||||
let mut ret = String::new();
|
|
||||||
let lines = code.lines();
|
|
||||||
|
|
||||||
for (i, line) in lines.enumerate() {
|
|
||||||
use std::fmt::Write;
|
|
||||||
writeln!(ret, "{}{} | {}{}",color::FG_BLUE, i + 1, line, color::RESET).unwrap();
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
pub mod macros {
|
|
||||||
#[macro_export] macro_rules! error { ($($arg:tt)*) => { $crate::util::logger::error(std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! warn { ($($arg:tt)*) => { $crate::util::logger::warn( std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! info { ($($arg:tt)*) => { $crate::util::logger::info( std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! note { ($($arg:tt)*) => { $crate::util::logger::note( std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
|
|
||||||
#[macro_export] macro_rules! lerror { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lerror($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! lwarn { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lwarn($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! linfo { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::linfo($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! lnote { ($dst:expr, $($arg:tt)*) => { $crate::util::logger::lnote($dst, std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
|
|
||||||
#[macro_export] macro_rules! help { ($($arg:tt)*) => { $crate::util::logger::help( std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
#[macro_export] macro_rules! code_block { ($($arg:tt)*) => { $crate::util::logger::code_block( std::format_args!($($arg)*).to_string().as_str()) }; }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub trait StringExtra{
|
|
||||||
// fn find_idx(&self, pat: char, start: u32) -> Result<u32, ()>;
|
|
||||||
// }
|
|
||||||
// impl StringExtra for String {
|
|
||||||
// fn find_idx(&self, pat: char, start: u32) -> Result<u32, ()> {
|
|
||||||
// let mut col = start;
|
|
||||||
|
|
||||||
// for c in (*self).chars() {
|
|
||||||
// if c == pat {
|
|
||||||
// return Ok(col);
|
|
||||||
// }
|
|
||||||
// col += 1;
|
|
||||||
// }
|
|
||||||
// Err(())
|
|
||||||
|
|
||||||
// }
|
|
||||||
// }
|
|
49
test.mcl
49
test.mcl
|
@ -1,12 +1,49 @@
|
||||||
// include "std.mcl"
|
include "std.mcl"
|
||||||
fn mcl_print with int ptr returns void then
|
|
||||||
1 1 syscall3 drop
|
structdef Uwu do
|
||||||
|
owo do u64 end
|
||||||
|
twt do u64 end
|
||||||
done
|
done
|
||||||
|
|
||||||
fn mcl_dump with int returns void then
|
structdef Foo do
|
||||||
_dbg_print
|
buz do u64 end
|
||||||
|
uwu do Uwu end
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
||||||
|
memory s_foo Foo end
|
||||||
|
|
||||||
|
//? Comments :3
|
||||||
|
|
||||||
|
// extern fn a with void returns void then done
|
||||||
|
// inline fn b with void returns void then done
|
||||||
|
// export fn c with void returns void then done
|
||||||
|
|
||||||
|
// fn putd with int returns void then drop done
|
||||||
|
|
||||||
fn main with void returns void then
|
fn main with void returns void then
|
||||||
"hi\n" mcl_print
|
|
||||||
|
s_foo.uwu.twt 69 write64
|
||||||
|
|
||||||
|
s_foo.uwu.twt read64 _dbg_print
|
||||||
|
// 1 2 add
|
||||||
|
// 69 _dbg_print
|
||||||
|
// "Hewo\n" puts
|
||||||
|
|
||||||
|
// if 3 4 eq do
|
||||||
|
// "omg what impossible!\n"
|
||||||
|
// else if 1 1 eq do
|
||||||
|
// "whaaaaaaaaa\n"
|
||||||
|
// else
|
||||||
|
// "finally, some good soup\n"
|
||||||
|
// done
|
||||||
|
// puts
|
||||||
|
|
||||||
|
// 10
|
||||||
|
// while dup 0 gt do
|
||||||
|
// "uwu " puts
|
||||||
|
// dup _dbg_print
|
||||||
|
// 1 sub
|
||||||
|
// done
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
gftdesd5ryutfgyhibugtf6r4
|
|
|
@ -1,7 +0,0 @@
|
||||||
34 35 + print
|
|
||||||
|
|
||||||
800 380 - print
|
|
||||||
|
|
||||||
10 5 * print
|
|
||||||
|
|
||||||
40 5 / print
|
|
Loading…
Reference in New Issue
Block a user