diff --git a/.gitignore b/.gitignore index bc90cfa..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1 @@ -/* -!/.vscode -!/.gitignore -!/.gitkeep -!/src -!/include -!/Cargo* -!/REF.md -!/*.mcl \ No newline at end of file +/target diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 0334e57..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "include"] - path = include - url = git@github.com:mc-lang/libmc.git diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index c2c934d..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "recommendations": [ - "aaron-bond.better-comments", - "usernamehw.errorlens", - "tamasfe.even-better-toml", - "platformio.platformio-ide", - "1YiB.rust-bundle", - "tamasfe.even-better-toml", - "ms-vscode.cpptools" - ] -} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 2c194bb..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - // 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}" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index c46eec0..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.associations": { - "*.s": "platformio-debug.asm" - } -} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 0bb41c5..ef0007a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,48 +3,58 @@ version = 3 [[package]] -name = "anstream" -version = "0.6.13" +name = "aho-corasick" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -52,33 +62,27 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bitflags" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" [[package]] name = "clap" -version = "4.5.2" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" dependencies = [ "clap_builder", "clap_derive", @@ -86,9 +90,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" dependencies = [ "anstream", "anstyle", @@ -98,9 +102,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" dependencies = [ "heck", "proc-macro2", @@ -110,54 +114,86 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] -name = "heck" -version = "0.4.1" +name = "env_filter" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "map-macro" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb950a42259642e5a3483115aca87eebed2a64886993463af9c9739c205b8d3a" - -[[package]] -name = "mclangc-v2" -version = "0.1.0" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ - "anyhow", - "bitflags", - "camino", - "clap", - "clap_derive", - "lazy_static", - "map-macro", - "parse_int", - "snailquote", + "log", + "regex", ] [[package]] -name = "num-traits" -version = "0.2.18" +name = "env_logger" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "mclangc" +version = "0.1.0" +dependencies = [ + "anyhow", + "camino", + "clap", + "env_logger", + "log", + "parse_int", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -173,86 +209,79 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] -name = "snailquote" -version = "0.3.1" +name = "regex" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec62a949bda7f15800481a711909f946e1204f2460f89210eaf7f57730f88f86" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ - "thiserror", - "unicode_categories", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "strsim" -version = "0.11.0" +name = "regex-automata" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.52" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "thiserror" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "windows-sys" @@ -265,13 +294,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -280,42 +310,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 42b7c0f..cdfd394 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,14 @@ [package] -name = "mclangc-v2" +name = "mclangc" version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.80" -bitflags = "2.4.2" -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" +anyhow = "1.0.86" +camino = "1.1.7" +clap = { version = "4.5.11", features = ["derive"] } +env_logger = "0.11.5" +log = "0.4.22" parse_int = "0.6.0" -# serde = { version = "1.0.197", features = ["derive"] } -# regex = "1.10.3" -snailquote = "0.3.1" diff --git a/REF.md b/REF.md deleted file mode 100644 index 7d7a011..0000000 --- a/REF.md +++ /dev/null @@ -1,53 +0,0 @@ -# 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 - - -``` diff --git a/include b/include deleted file mode 160000 index 33ccced..0000000 --- a/include +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 33cccedea1ed7b86531f250127654d1973d8e36a diff --git a/src/ast.rs b/src/ast.rs new file mode 100644 index 0000000..a1eee0d --- /dev/null +++ b/src/ast.rs @@ -0,0 +1,164 @@ +use std::collections::HashMap; + +use camino::Utf8PathBuf; + +use crate::{common::Loc, token::Token}; + +#[derive(Debug, Eq, PartialEq, Clone, Hash)] +pub struct Ident { + pub text: String, + pub loc: Loc, +} + +impl Ident { + pub fn from_tok(t: Token) -> Self { + let text; + match t.typ { + crate::token::TokenType::Ident(s) => text = s, + _ => unreachable!(), + } + Self { text, loc: t.loc.clone() } + } +} + +#[derive(Debug, Clone)] +pub struct Type { + pub name: Ident, + pub inner: Option>, +} + +#[derive(Debug, Clone)] +pub struct Program { + pub file: Utf8PathBuf, + pub items: Vec +} + +#[derive(Debug, Clone)] +pub struct Stat { + pub typ: StatType, + pub loc: Loc, +} + +#[derive(Debug, Clone)] +pub enum StatType { + Struct(StructStat), + Enum(EnumStat), + Var(VarStat), + Set(SetStat), + Match(MatchStat), + Not(UnaryStat), + Eq(BinaryStat), + Neq(BinaryStat), + Lt(BinaryStat), + Gt(BinaryStat), + Le(BinaryStat), + Ge(BinaryStat), + Add(BinaryStat), + Sub(BinaryStat), + Mul(BinaryStat), + Div(BinaryStat), + Mod(BinaryStat), + Shr(BinaryStat), + Shl(BinaryStat), + Band(BinaryStat), + Bor(BinaryStat), + Bnot(UnaryStat), + And(BinaryStat), + Or(BinaryStat), + Xor(BinaryStat), + Inc(UnaryStat), + Dec(UnaryStat), + Ref(UnaryStat), + Export(ExportStat), + Function(FnStat), + FunctionCall(FnCallStat), + Return(ReturnStat), + If(IfStat), + While(WhileStat), + Block(BlockStat), + Literal(ValueType) +} + +#[derive(Debug, Clone)] +pub enum ValueType { + Float(f64), + Int(i64), + Bool(bool), + String(String), + Char(char), +} + +#[derive(Debug, Clone)] +pub struct BlockStat(pub Vec); +#[derive(Debug, Clone)] +pub struct UnaryStat(pub Box); +#[derive(Debug, Clone)] +pub struct BinaryStat(pub Box, pub Box); + +#[derive(Debug, Clone)] +pub struct MatchStat { + pub val: Ident, + pub cases: HashMap +} + +#[derive(Debug, Clone)] +pub struct SetStat { + pub name: Ident, + pub val: Box, +} + +#[derive(Debug, Clone)] +pub struct VarStat { + pub name: Ident, + pub typ: Option, + pub val: Option>, +} + +#[derive(Debug, Clone)] +pub struct EnumStat { + pub name: Ident, + pub fields: Vec +} + +#[derive(Debug, Clone)] +pub struct StructStat { + pub name: Ident, + pub fields: HashMap, +} + +#[derive(Debug, Clone)] +pub struct FnStat { + pub name: Ident, + pub args: HashMap, + pub body: BlockStat, +} + +#[derive(Debug, Clone)] +pub struct FnCallStat { + pub name: Ident, + pub args: Vec, +} + +#[derive(Debug, Clone)] +pub struct ReturnStat { + pub arg: Option>, +} + +#[derive(Debug, Clone)] +pub struct IfStat { + pub condition: Box, + pub body: BlockStat, + pub els: Box +} + +#[derive(Debug, Clone)] +pub struct WhileStat { + pub condition: Box, + pub body: BlockStat, +} + +#[derive(Debug, Clone)] +pub struct ExportStat { + pub name: Ident, +} + diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index d0b8f6a..0000000 --- a/src/cli.rs +++ /dev/null @@ -1,129 +0,0 @@ -use clap::{builder::PossibleValue, Parser, ValueEnum}; -use camino::Utf8PathBuf; - -lazy_static::lazy_static! { - static ref DEFAULT_INCLUDE_PATHS: Vec = 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, - - /// 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, - - #[clap(skip)] - pub passthrough: Vec -} - - - -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 { - 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 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 { -// match value { -// "X86_64_linux_nasm" => Ok(CompilationTarget::X86_64_linux_nasm) -// _ => bail!("Unknown compilation target {value}") -// } -// } - -// } - diff --git a/src/cliargs.rs b/src/cliargs.rs new file mode 100644 index 0000000..8a43fab --- /dev/null +++ b/src/cliargs.rs @@ -0,0 +1,24 @@ +use camino::Utf8PathBuf; +use clap::Parser; +use log::LevelFilter; + + +#[derive(Debug, Parser)] +pub struct CliArgs { + #[arg(long, short, default_value="./a.out")] + pub output: Utf8PathBuf, + #[arg(long, short)] + pub debug: bool, + pub input: Vec, +} + + +impl CliArgs { + pub fn get_logger_filter(&self) -> LevelFilter { + if self.debug { + LevelFilter::Debug + } else { + LevelFilter::Info + } + } +} diff --git a/src/common.rs b/src/common.rs new file mode 100644 index 0000000..14a6632 --- /dev/null +++ b/src/common.rs @@ -0,0 +1,26 @@ +use std::fmt::Display; + +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct Loc { + pub file: camino::Utf8PathBuf, + pub line: usize, + pub col: usize, +} + +impl Loc { + pub fn new>(file: P) -> Self { + Self { + file: file.into(), + line: 1, + 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(()) + } +} diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs deleted file mode 100644 index 1fc074e..0000000 --- a/src/compiler/mod.rs +++ /dev/null @@ -1,104 +0,0 @@ -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) -> anyhow::Result<()>; - fn compile(&mut self, asm_fp: &Path, obj: &Path) -> anyhow::Result<()>; - fn link(&mut self, obj_files: Vec, 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(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(()) -} \ No newline at end of file diff --git a/src/compiler/utils.rs b/src/compiler/utils.rs deleted file mode 100644 index ede944c..0000000 --- a/src/compiler/utils.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::{fmt::Debug, process::{Command, Stdio}}; - -use anyhow::bail; - - - -pub fn run_cmd<'a, S: Into + Debug + Clone>(bin: S, args: Vec) -> 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(()) -} \ No newline at end of file diff --git a/src/compiler/x86_64_linux_nasm/mod.rs b/src/compiler/x86_64_linux_nasm/mod.rs deleted file mode 100644 index aec1169..0000000 --- a/src/compiler/x86_64_linux_nasm/mod.rs +++ /dev/null @@ -1,521 +0,0 @@ -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, - // func_mem_i: Vec, - // func_mem_list: HashMap, - if_i: usize, - while_i: usize, - used_consts: Vec -} - -impl X86_64LinuxNasmCompiler { - fn handle_token(&mut self, fd: &mut BufWriter, _: &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 64")?; - 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, 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, 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, prog: &Program, ast: Vec) -> 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) -> 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::>(); - 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::>(); - 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, 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" - ] - } -} \ No newline at end of file diff --git a/src/compiler/x86_64_linux_nasm/utils.rs b/src/compiler/x86_64_linux_nasm/utils.rs deleted file mode 100644 index 82a0895..0000000 --- a/src/compiler/x86_64_linux_nasm/utils.rs +++ /dev/null @@ -1,37 +0,0 @@ - - -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 -"; \ No newline at end of file diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs deleted file mode 100644 index 3124647..0000000 --- a/src/lexer/mod.rs +++ /dev/null @@ -1,389 +0,0 @@ -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 -} - -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::>(); - - - 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::(&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::(&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, 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") - } - -} \ No newline at end of file diff --git a/src/logger/colors.rs b/src/logger/colors.rs deleted file mode 100644 index 5950972..0000000 --- a/src/logger/colors.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![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"; diff --git a/src/logger/macros.rs b/src/logger/macros.rs deleted file mode 100644 index 5b1056a..0000000 --- a/src/logger/macros.rs +++ /dev/null @@ -1,106 +0,0 @@ - - -#[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,)*} - } - ) - } - }; -} - - -#[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)+) - }; -} diff --git a/src/logger/mod.rs b/src/logger/mod.rs deleted file mode 100644 index 4e96324..0000000 --- a/src/logger/mod.rs +++ /dev/null @@ -1,83 +0,0 @@ - -// 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 { - 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::() - .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 - } -} \ No newline at end of file diff --git a/src/logger/types.rs b/src/logger/types.rs deleted file mode 100644 index 36c59c2..0000000 --- a/src/logger/types.rs +++ /dev/null @@ -1,40 +0,0 @@ -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> -} - - -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; -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0761d80..b19ee1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,47 +1,32 @@ +use clap::Parser; +use log::LevelFilter; -use std::collections::HashMap; +mod ast; +mod cliargs; +mod parser; +mod token; +mod tokeniser; +mod common; -#[macro_use] -mod logger; -mod cli; -mod types; -mod lexer; -pub mod parser; -mod compiler; fn main() { - let cli_args = cli::CliArgs::parse_with_passthrough(); - logger::Logger::init(&cli_args).expect("Failed to init logger"); + let cliargs = cliargs::CliArgs::parse(); + env_logger::builder() + .format_timestamp(None) + .filter(None, cliargs.get_logger_filter()) + .init(); - let mut prog_map = HashMap::new(); - for file in &cli_args.input { - let mut lexer = lexer::Lexer::new(); - - info!("Lexing file {file:?}"); - if let Err(_) = lexer.lex(file.as_std_path()) { - error!("Lexing failed, exiting"); - return; + let mut tokeniser = tokeniser::Tokeniser::new(); + let mut parser = parser::Parser::new(); + for file in &cliargs.input { + if let Err(_) = tokeniser.tokenise(file.as_path()) { + break; } - // for t in &lexer.tokens { - // info!({loc => t.loc.clone()}, "{:?}", t.typ); - // } - // dbg!(&lexer.tokens); - - info!("Parsing file {file:?}"); - let prog = match parser::parse(&cli_args, &mut lexer.tokens) { - Ok(r) => r, - Err(_) => { - error!("Parsing failed, exiting"); - return; - } + let tokens = tokeniser.tokens(); + let Ok(ast) = parser.parse(file, tokens) else { + break; }; - - prog_map.insert(file.as_std_path(), prog); - + dbg!(ast); } - if let Err(_) = compiler::compile_program(&cli_args, prog_map) { - error!("Failed to compile program, exiting"); - } - } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..0e3756a --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,423 @@ +use std::collections::HashMap; + +use anyhow::{bail, Result}; +use camino::Utf8Path; + +use crate::{ast::{self, StructStat}, common::Loc, token::{KeywordType, Token, TokenType}}; + + +pub struct Parser { + tokens: Vec, + loc: Loc, + is_in_func: bool, +} + +impl Parser { + pub fn new() -> Self { + Self { + tokens: Vec::new(), + loc: Loc::new(""), + is_in_func: false, + } + } + + pub fn parse(&mut self, file: &Utf8Path, _tokens: &Vec) -> Result { + self.tokens = _tokens.to_vec(); + self.tokens.reverse(); + let mut prog = ast::Program { + file: file.into(), + items: Vec::new() + }; + + while !self.tokens.is_empty() { + prog.items.push(self.parse_stat()?); + } + + Ok(prog) + } + + fn parse_stat(&mut self) -> Result { + log::debug!("parse_stat"); + self.expect_next(TokenType::ParenL)?; + log::debug!("parse_stat.2"); + let Some(main) = self.tokens.pop() else { + log::error!("Expected function, struct, enum definitions, but found nothing"); + bail!(""); + }; + self.loc = main.loc; + let ret = match main.typ { + TokenType::ParenL => { + ast::Stat { + loc: self.loc.clone(), + typ: ast::StatType::Block(self.parse_block_stat()?), + } + } + TokenType::Keyword(kw) => { + log::debug!("kw: {kw:?}"); + match kw { + KeywordType::Eq | KeywordType::Neq | + KeywordType::Lt | KeywordType::Gt | + KeywordType::Ge | KeywordType::Le | + KeywordType::Or | KeywordType::And | + KeywordType::Shr | KeywordType::Shl | + KeywordType::Bor | KeywordType::Band | + KeywordType::Xor | KeywordType::Add | + KeywordType::Sub | KeywordType::Div | + KeywordType::Mod | KeywordType::Mul => { + if !self.is_in_func { + log::error!("Can only use {:?} in a function", kw); + bail!(""); + } + self.parse_binary_stat(kw)? + } + + KeywordType::Not | KeywordType::Bnot | + KeywordType::Inc | KeywordType::Dec | + KeywordType::Ref => { + if !self.is_in_func { + log::error!("Can only use {:?} in a function", kw); + bail!(""); + } + self.parse_unary_stat(kw)? + } + KeywordType::Var | KeywordType::Set | + KeywordType::If | KeywordType::While | + KeywordType::Match if !self.is_in_func => { + log::error!("Can only use {:?} in a function", kw); + bail!(""); + } + // TODO: Dont allow structs exports, and enums in functions + KeywordType::Struct => self.parse_struct_stat()?, + KeywordType::Fn => self.parse_fn_stat()?, + KeywordType::Export => self.parse_export_stat()?, + KeywordType::Enum => self.parse_enum_stat()?, + + KeywordType::Call if self.is_in_func => self.parse_call_stat()?, + KeywordType::Var if self.is_in_func => self.parse_var_stat()?, + KeywordType::Set if self.is_in_func => self.parse_set_stat()?, + KeywordType::If if self.is_in_func => self.parse_if_stat()?, + KeywordType::While if self.is_in_func => self.parse_while_stat()?, + KeywordType::Match if self.is_in_func => self.parse_match_stat()?, + KeywordType::Return if self.is_in_func => self.parse_return_stat()?, + + KeywordType::Else => { + log::error!("Keyword else is only suppost to be put after an else statement"); + bail!(""); + } + v => unreachable!("{v:?}") + } + } + _ => { + log::error!("Expected function, struct, enum definitions, but found {:?}", main.typ); + bail!(""); + } + }; + Ok(ret) + } + + + + fn parse_binary_stat(&mut self, kw: KeywordType) -> Result { + let bs = ast::BinaryStat( + Box::new(self.parse_stat()?), + Box::new(self.parse_stat()?) + ); + + let typ = match kw { + KeywordType::Eq => ast::StatType::Eq(bs), + KeywordType::Neq => ast::StatType::Neq(bs), + KeywordType::Lt => ast::StatType::Lt(bs), + KeywordType::Gt => ast::StatType::Gt(bs), + KeywordType::Ge => ast::StatType::Ge(bs), + KeywordType::Le => ast::StatType::Le(bs), + KeywordType::Or => ast::StatType::Or(bs), + KeywordType::And => ast::StatType::And(bs), + KeywordType::Add => ast::StatType::Add(bs), + KeywordType::Sub => ast::StatType::Sub(bs), + KeywordType::Div => ast::StatType::Div(bs), + KeywordType::Mul => ast::StatType::Mul(bs), + KeywordType::Mod => ast::StatType::Mod(bs), + KeywordType::Shr => ast::StatType::Shr(bs), + KeywordType::Shl => ast::StatType::Shl(bs), + KeywordType::Bor => ast::StatType::Bor(bs), + KeywordType::Band => ast::StatType::Band(bs), + KeywordType::Xor => ast::StatType::Xor(bs), + _ => unreachable!("{kw:?}") + }; + self.expect_next(TokenType::ParenR)?; + Ok(ast::Stat { + loc: self.loc.clone(), + typ, + }) + } + + fn parse_unary_stat(&mut self, kw: KeywordType) -> Result { + let us = ast::UnaryStat(Box::new(self.parse_stat()?)); + let typ = match kw { + KeywordType::Not => ast::StatType::Not(us), + KeywordType::Bnot => ast::StatType::Bnot(us), + KeywordType::Inc => ast::StatType::Inc(us), + KeywordType::Dec => ast::StatType::Dec(us), + KeywordType::Ref => ast::StatType::Ref(us), + _ => unreachable!("{kw:?}") + }; + self.expect_next(TokenType::ParenR)?; + Ok(ast::Stat { typ, loc: self.loc.clone() }) + } + + fn parse_block_stat(&mut self) -> Result { + log::debug!("parse_block_stat.1"); + self.expect_next(TokenType::ParenL)?; + let mut bs = Vec::new(); + while let Some(t) = self.tokens.last() { + match &t.typ { + TokenType::ParenL => { + log::debug!("parse_block_stat.2"); + bs.push(self.parse_stat()?); + } + TokenType::ParenR => { + log::debug!("parse_block_stat.3"); + self.expect_next(TokenType::ParenR)?; + break; + } + typ => { + log::debug!("parse_block_stat.4"); + log::error!("{}: Expected '(' found {typ:?}", self.loc); + bail!(""); + } + } + } + + Ok(ast::BlockStat(bs)) + } + fn parse_struct_stat(&mut self) -> Result { + todo!(); + } + + fn parse_fn_stat(&mut self) -> Result { + self.is_in_func = true; + let name = self.expect_next(TokenType::Ident(String::new()))?; + let mut args: HashMap = HashMap::new(); + + log::debug!("parse_fn_stat.1"); + self.expect_next(TokenType::ParenL)?; + log::debug!("parse_fn_stat.2"); + + while self.try_next(TokenType::ParenR).is_none() { + log::debug!("parse_fn_stat.3"); + self.expect_next(TokenType::ParenL)?; + log::debug!("parse_fn_stat.4"); + let arg_name = self.expect_next(TokenType::Ident(String::new()))?; + let typ = self.parse_type()?; + self.expect_next(TokenType::ParenR)?; + args.insert(ast::Ident::from_tok(arg_name), typ); + } + + log::debug!("parse_fn_stat.5"); + self.expect_next(TokenType::ParenR)?; + + let body = self.parse_block_stat()?; + log::debug!("parse_fn_stat.6"); + + let fs = ast::FnStat { + name: ast::Ident::from_tok(name.clone()), + args, + body + }; + + self.is_in_func = false; + + self.expect_next(TokenType::ParenR)?; + Ok(ast::Stat { + loc: name.loc.clone(), + typ: ast::StatType::Function(fs) + }) + } + + fn parse_type(&mut self) -> Result { // (args (arr string_t)) + let has_another = self.try_next(TokenType::ParenL).is_some(); + if has_another { + self.tokens.pop(); + } + let name = self.expect_next(TokenType::Ident(String::new()))?; + let mut typ = ast::Type { + name: ast::Ident::from_tok(name), + inner: None, + }; + + if has_another { + typ.inner = Some(Box::new(self.parse_type()?)); + self.expect_next(TokenType::ParenR)?; + } + Ok(typ) + } + + + fn parse_enum_stat(&mut self) -> Result { + todo!(); + } + fn parse_var_stat(&mut self) -> Result { + let name = self.expect_next(TokenType::Ident(String::new()))?; + let typ; + let typ_tok = self.expect_several(&[ + TokenType::Ident(String::new()), + TokenType::Underscore + ])?; + match &typ_tok.typ { + TokenType::Underscore => { + typ = None; + } + TokenType::Ident(_) => { + self.tokens.push(typ_tok); + typ = Some(self.parse_type()?); + } + _ => unreachable!() + } + let val; + if self.try_next(TokenType::ParenR).is_some() { + val = None; + } else { + val = Some(Box::new(self.parse_val()?)); + } + + self.expect_next(TokenType::ParenR)?; + + Ok(ast::Stat { + loc: name.loc.clone(), + typ: ast::StatType::Var(ast::VarStat { + name: ast::Ident::from_tok(name), + typ, + val, + }) + }) + } + + fn parse_val(&mut self) -> Result { + if self.try_next(TokenType::ParenL).is_some() { + Ok(self.parse_stat()?) + } else { + let tok = self.expect_several(&[ + TokenType::String(String::new()), + TokenType::Int(0), + TokenType::Float(0.0), + TokenType::Char('\0'), + ])?; + let vt = match tok.typ { + TokenType::String(s) => ast::ValueType::String(s), + TokenType::Int(i) => ast::ValueType::Int(i), + TokenType::Float(f) => ast::ValueType::Float(f), + TokenType::Char(c) => ast::ValueType::Char(c), + _ => unreachable!("") + }; + Ok(ast::Stat { + loc: tok.loc.clone(), + typ: ast::StatType::Literal(vt) + }) + } + } + fn parse_set_stat(&mut self) -> Result { + let name = self.expect_next(TokenType::Ident(String::new()))?; + let val = self.parse_val()?; + self.expect_next(TokenType::ParenR)?; + + Ok(ast::Stat { + loc: name.loc.clone(), + typ: ast::StatType::Set(ast::SetStat { + name: ast::Ident::from_tok(name), + val: Box::new(val), + }) + }) + } + + fn parse_call_stat(&mut self) -> Result { + let name = self.expect_next(TokenType::Ident(String::new()))?; + let mut args = Vec::new(); + + while self.try_next(TokenType::ParenR).is_none() { + args.push(ast::Ident::from_tok(self.expect_next(TokenType::Ident(String::new()))?)); + } + self.expect_next(TokenType::ParenR)?; + + Ok(ast::Stat { + loc: name.loc.clone(), + typ: ast::StatType::FunctionCall(ast::FnCallStat { + name: ast::Ident::from_tok(name), + args + }) + }) + } + fn parse_return_stat(&mut self) -> Result { + let loc = self.loc.clone(); + let val; + if self.try_next(TokenType::ParenR).is_some() { + val = None; + } else { + val = Some(Box::new(self.parse_val()?)); + } + self.expect_next(TokenType::ParenR)?; + Ok(ast::Stat { + loc, + typ: ast::StatType::Return(ast::ReturnStat { + arg: val, + }) + }) + } + fn parse_if_stat(&mut self) -> Result { + todo!(); + } + fn parse_while_stat(&mut self) -> Result { + todo!(); + } + fn parse_match_stat(&mut self) -> Result { + todo!(); + } + fn parse_export_stat(&mut self) -> Result { + todo!(); + } + + + fn expect_next(&mut self, tt: TokenType) -> Result { + if let Some(t) = self.tokens.pop() { + log::debug!("en: {:?}", t.typ); + if std::mem::discriminant(&t.typ) == std::mem::discriminant(&tt) { + self.loc = t.loc.clone(); + return Ok(t); + } else { + log::error!("{}: Expected {:?}, got {:?}", t.loc, tt, t.typ); + bail!("") + } + } + log::error!("{}: Expected {:?}, got Nothing", self.loc, tt); + bail!("") + } + + fn expect_several(&mut self, tt: &[TokenType]) -> Result { + let tt_text = tt + .into_iter() + .map(|v| format!("{:?}", v)) + .collect::>() + .join(", "); + + if let Some(t) = self.tokens.pop() { + for typ in tt { + if std::mem::discriminant(&t.typ) == std::mem::discriminant(&typ) { + self.loc = t.loc.clone(); + return Ok(t); + } + } + log::error!("{}: Expected {}, got {:?}", t.loc, tt_text, t.typ); + bail!("") + } + log::error!("{}: Expected {}, got Nothing", self.loc, tt_text); + bail!("") + } + fn try_next(&mut self, tt: TokenType) -> Option<&Token> { + if let Some(t) = self.tokens.last() { + if std::mem::discriminant(&t.typ) == std::mem::discriminant(&tt) { + return Some(t); + } + } + None + } +} + diff --git a/src/parser/builtin.rs b/src/parser/builtin.rs deleted file mode 100644 index 4bb61e5..0000000 --- a/src/parser/builtin.rs +++ /dev/null @@ -1,46 +0,0 @@ -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) -} \ No newline at end of file diff --git a/src/parser/mod.rs b/src/parser/mod.rs deleted file mode 100644 index e726310..0000000 --- a/src/parser/mod.rs +++ /dev/null @@ -1,787 +0,0 @@ -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) -> Result { - 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, flags: Flags, is_module_root: bool) -> Result { - 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) -> Result { - 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) -> Result { - - 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) -> Result { - 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, is_module_root: bool) -> Result { - 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, flags: Flags ) -> Result { - - - 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) -> Result { - let mut test: Vec = Vec::new(); - let mut body: Vec = Vec::new(); - let mut els: Vec = 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) -> Result { - let mut test: Vec = Vec::new(); - let mut body: Vec = 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, flags: Flags) -> Result { - 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, flags: Flags) -> Result { - 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, flags: Flags) -> Result { - 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) -> Result { - 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) -> Result { - 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, _: Flags ) -> Result { - //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::>(); - // 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!("") -} \ No newline at end of file diff --git a/src/parser/precompiler.rs b/src/parser/precompiler.rs deleted file mode 100644 index c8fd8e4..0000000 --- a/src/parser/precompiler.rs +++ /dev/null @@ -1,213 +0,0 @@ -use anyhow::bail; - -use crate::types::{ast::{AstNode, MemSize, Program}, common::Loc, token::{InstructionType, TokenType, TypeType}}; - - -pub fn precompile_mem(prog: &Program, ast: Vec ) -> anyhow::Result { - 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, stack: &mut Vec ) -> anyhow::Result { - 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, loc: &Loc) -> anyhow::Result { - match stack.pop() { - Some(i) => Ok(i), - None => { - error!({loc => loc.clone()}, "Failed to precompile tokens, failed to pop from stack"); - bail!("") - }, - } -} \ No newline at end of file diff --git a/src/parser/utils.rs b/src/parser/utils.rs deleted file mode 100644 index 484cac2..0000000 --- a/src/parser/utils.rs +++ /dev/null @@ -1,103 +0,0 @@ -use anyhow::{bail, Result}; - -use crate::types::token::{Token, TokenType}; - -#[derive(Debug, Clone, PartialEq, PartialOrd)] -pub enum PeekResult { - Correct(T), - Wrong(T), - None -} - -impl PeekResult { - 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, typs: Vec) -> 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, 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, typ: TokenType) -> Result { - 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!("") - } - } - -} \ No newline at end of file diff --git a/src/token.rs b/src/token.rs new file mode 100644 index 0000000..034c9d6 --- /dev/null +++ b/src/token.rs @@ -0,0 +1,124 @@ +use anyhow::{anyhow, bail}; + +use crate::common::Loc; + + +#[derive(Debug, Clone)] +pub struct Token { + pub typ: TokenType, + pub loc: Loc, +} + +impl Token { + pub fn new(typ: TokenType, loc: Loc) -> Self { + Self {typ, loc} + } +} + +#[derive(Debug, Clone, PartialEq, PartialOrd)] +pub enum TokenType { + Ident(String), + Keyword(KeywordType), + Int(i64), + Float(f64), + String(String), + Char(char), + Underscore, + ParenR, + ParenL, + Dot, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum KeywordType { + Struct, + Enum, + Fn, + Var, + Set, + If, + While, + Match, + Not, + Eq, + Neq, + Lt, + Gt, + Le, + Ge, + Add, + Sub, + Div, + Mod, + Mul, + Shr, + Shl, + Band, + Bor, + Bnot, + And, + Or, + Xor, + Inc, + Dec, + Ref, + Export, + Else, + Call, + Return, + StructInit, +} + +impl TryFrom<&str> for KeywordType { + type Error = anyhow::Error; + fn try_from(value: &str) -> Result { + match value { + "fn" => Ok(Self::Fn), + "var" => Ok(Self::Var), + "set" => Ok(Self::Set), + "if" => Ok(Self::If), + "while" => Ok(Self::While), + "match" => Ok(Self::Match), + "not" => Ok(Self::Not), + "eq" => Ok(Self::Eq), + "neq" => Ok(Self::Neq), + "lt" => Ok(Self::Lt), + "gt" => Ok(Self::Gt), + "le" => Ok(Self::Le), + "ge" => Ok(Self::Ge), + "add" => Ok(Self::Add), + "sub" => Ok(Self::Sub), + "div" => Ok(Self::Div), + "mod" => Ok(Self::Mod), + "mul" => Ok(Self::Mul), + "shr" => Ok(Self::Shr), + "shl" => Ok(Self::Shl), + "band" => Ok(Self::Band), + "bor" => Ok(Self::Bor), + "bnot" => Ok(Self::Bnot), + "and" => Ok(Self::And), + "or" => Ok(Self::Or), + "xor" => Ok(Self::Xor), + "inc" => Ok(Self::Inc), + "dec" => Ok(Self::Dec), + "ref" => Ok(Self::Ref), + "struct" => Ok(Self::Struct), + "enum" => Ok(Self::Enum), + "export" => Ok(Self::Export), + "else" => Ok(Self::Else), + "call" => Ok(Self::Call), + "return" => Ok(Self::Return), + "structinit" => Ok(Self::StructInit), + _ => bail!("Unknown keyword: {}", value) + } + } +} + +impl TryFrom for KeywordType { + type Error = anyhow::Error; + fn try_from(value: String) -> Result { + value.as_str().try_into() + } +} + + diff --git a/src/tokeniser.rs b/src/tokeniser.rs new file mode 100644 index 0000000..aa451f7 --- /dev/null +++ b/src/tokeniser.rs @@ -0,0 +1,226 @@ +use std::io::BufRead; + +use anyhow::bail; +use camino::Utf8Path; + +use crate::{common::Loc, token::{KeywordType, Token, TokenType}}; + + + + +pub struct Tokeniser { + loc: Loc, + tokens: Vec, +} + +impl Tokeniser { + pub fn new() -> Self { + Self { + loc: Loc::new(""), + tokens: Vec::new(), + } + } + + pub fn tokenise(&mut self, file: &Utf8Path) -> anyhow::Result<()>{ + self.reset(); + self.loc.file = file.into(); + let Ok(f) = std::fs::File::open(file) else { + log::error!("Failed to open file {file}, permissions?"); + bail!(""); + }; + let mut f = std::io::BufReader::new(f); + + let mut line = String::new(); + loop { + match f.read_line(&mut line) { + Ok(c) if c == 0 => break, + Ok(_) => (), + Err(e) => { + log::error!("Failed to read line from file: {e}"); + bail!(""); + } + } + let mut chars = line.chars().into_iter().peekable(); + 'line: while let Some(c) = chars.next() { + match c { + '(' => self.tokens.push(Token::new(TokenType::ParenL, self.loc.clone())), + ')' => self.tokens.push(Token::new(TokenType::ParenR, self.loc.clone())), + '.' => self.tokens.push(Token::new(TokenType::Dot, self.loc.clone())), + ';' => break 'line, + '-' | '+' | '0'..='9' => { + let loc = self.loc.clone(); + let mut buf = String::from(c); + let mut is_float = false; + while let Some(c) = chars.peek() { + match c { + '0'..='9' => { + buf.push(*c); + chars.next(); + } + '.' => { + if is_float { + log::error!("{}: Invalid float", loc); + bail!(""); + } else { + is_float = true; + buf.push(*c); + chars.next(); + } + } + 'x' | 'b' | 'o' => { + if buf.len() != 1 { + log::error!("{}: Invalid int", loc); + bail!(""); + } + buf.push(*c); + chars.next(); + } + _ => break + } + self.loc.col += 1; + } + if is_float { + let v; + match parse_int::parse::(&buf) { + Ok(f) => v = f, + Err(e) => { + log::error!("{}: Failed to parse float: {e}", loc); + bail!(""); + } + } + + self.tokens.push(Token::new(TokenType::Float(v), loc)) + } else { + let v; + match parse_int::parse::(&buf) { + Ok(i) => v = i, + Err(e) => { + log::error!("{}: Failed to parse float: {e}", loc); + bail!(""); + } + } + + self.tokens.push(Token::new(TokenType::Int(v), loc)) + } + } + 'a'..='z' | 'A'..='Z' | '_' => { + let loc = self.loc.clone(); + let mut buf = String::from(c); + while let Some(c) = chars.peek() { + if !matches!(c, 'a'..='z' | 'A'..='Z' | '_' | '0'..='9') { + self.loc.col -= 1; + break; + } + buf.push(*c); + chars.next(); + self.loc.col += 1; + } + + if buf == "_" { + self.tokens.push(Token::new(TokenType::Underscore, self.loc.clone())); + } else if let Ok(kw) = KeywordType::try_from(buf.clone()) { + self.tokens.push(Token::new(TokenType::Keyword(kw), loc)); + } else { + self.tokens.push(Token::new(TokenType::Ident(buf), loc)); + } + } + '"' => { + let loc = self.loc.clone(); + let mut buf = String::new(); + let mut escaped = false; + while let Some(c) = chars.next() { + match c { + '"' if escaped => { + buf.push(c); + escaped = false; + } + '"' if !escaped => break, + '\\' if !escaped => escaped = true, + '\\' if escaped => { + buf.push(c); + escaped = false; + } + 'n' if escaped => { + buf.push('\n'); + escaped = false; + } + 'r' if escaped => { + buf.push('\r'); + escaped = false; + } + _ if !escaped => buf.push(c), + _ if escaped => { + log::warn!("{}: Unknown escape \\{}, skipping and putting it as literal", self.loc, c); + buf.push('\\'); + buf.push(c); + } + _ => unreachable!() + } + self.loc.col += 1; + } + self.tokens.push(Token::new(TokenType::String(buf), loc)); + } + '\'' => { + let loc = self.loc.clone(); + let mut buf = String::new(); + let mut escaped = false; + while let Some(c) = chars.next() { + match c { + '\'' if escaped => { + buf.push(c); + escaped = false; + } + '\'' if !escaped => break, + '\\' if !escaped => escaped = true, + '\\' if escaped => { + buf.push(c); + escaped = false; + } + 'n' if escaped => { + buf.push('\n'); + escaped = false; + } + 'r' if escaped => { + buf.push('\r'); + escaped = false; + } + _ if !escaped => buf.push(c), + _ if escaped => { + log::warn!("{}: Unknown escape \\{}, skipping and putting it as literal", self.loc, c); + buf.push('\\'); + buf.push(c); + } + _ => unreachable!() + } + self.loc.col += 1; + } + + if buf.len() > 1 { + log::error!("{}: Chars can only have 1 character", loc); + bail!(""); + } + self.tokens.push(Token::new(TokenType::Char(buf.chars().nth(0).unwrap()), loc)) + } + _ => () + } + self.loc.col += 1; + } + self.loc.line += 1; + self.loc.col = 1; + line.clear(); + } + + Ok(()) + } + + fn reset(&mut self) { + self.loc.col = 1; + self.loc.line = 1; + // self.loc.file = "".into(); + self.tokens.clear(); + } + + pub fn tokens(&self) -> &Vec { + &self.tokens + } +} diff --git a/src/types/ast/mod.rs b/src/types/ast/mod.rs deleted file mode 100644 index 204c120..0000000 --- a/src/types/ast/mod.rs +++ /dev/null @@ -1,215 +0,0 @@ -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, - // 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 -} -#[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 -} - -#[derive(Debug, Clone)] -pub struct While { - pub loc: Loc, - pub test: Vec, - pub body: Vec, -} - -#[derive(Debug, Clone)] -pub struct If { - pub loc: Loc, - pub test: Vec, - pub body: Vec, - pub els: Box, -} - -#[derive(Debug, Clone)] -pub struct Module { - pub loc: Loc, - pub path: Vec, - pub ident: String, - pub body: Vec -} - -#[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, - pub ret_types: Vec, - pub body: Vec -} - -#[derive(Debug, Clone)] -pub struct Constant { - pub loc: Loc, - pub ident: String, - pub value: Box -} - -#[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, - pub constants: HashMap, - pub memories: HashMap, - pub struct_defs: HashMap, -} - -#[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_") - } -} \ No newline at end of file diff --git a/src/types/common.rs b/src/types/common.rs deleted file mode 100644 index 1ac7443..0000000 --- a/src/types/common.rs +++ /dev/null @@ -1,37 +0,0 @@ -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>(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(()) - } -} - - diff --git a/src/types/mod.rs b/src/types/mod.rs deleted file mode 100644 index 286aa7f..0000000 --- a/src/types/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod common; -pub mod token; -pub mod ast; diff --git a/src/types/token/mod.rs b/src/types/token/mod.rs deleted file mode 100644 index 8b33b3a..0000000 --- a/src/types/token/mod.rs +++ /dev/null @@ -1,162 +0,0 @@ -#![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), // foo::bar - StructItem(Vec), // 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), - 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() - } -} \ No newline at end of file diff --git a/test.mcl b/test.mcl index a7131f2..2095f53 100644 --- a/test.mcl +++ b/test.mcl @@ -1,49 +1,30 @@ -include "std.mcl" +; vim: set ft=commonlisp: -structdef Uwu do - owo do u64 end - twt do u64 end -done +(fn main ((args (arr_t string_t))) ( + (var a i32 35) + (var b i32_t) + (set b 34) + (set a (call uwu a b)) + ;(match a ( + ; (69 ( + ; print "ooooo" + ; )) + ; (420 ( + ; print "aaaaaaaa" + ; )) + ;)) -structdef Foo do - buz do u64 end - uwu do Uwu end -done + ;(if (eq a b) ( + ; print "yes" + ;)) + ;(while (not (eq a b)) ( + ; (set_add (ref b) 1) + ;)) +)) - -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 - - 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 +;(fn uwu((a i32_t) (b i32_t)) ( + ; (return (add a b)) +;)) +;(fn set_add ((a (ref i32_t)) (b i32_t)) ( +; (ref_set a (add (deref a) b) +;))