diff --git a/.gitignore b/.gitignore index 281acbf..4dcbbe1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,18 @@ /target -/a +/* -test -test.nasm -test.o \ No newline at end of file +# files +!/.gitignore +!/cargo.lock +!/cargo.toml +!/README.md + +# folders +!/.github +!/editor +!/examples +!/include +!/playground +!/src +!/tests +!/tools \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 8623e04..cb93f03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,34 +3,10 @@ version = 3 [[package]] -name = "addr2line" -version = "0.19.0" +name = "anyhow" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "backtrace" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "bitflags" @@ -44,12 +20,6 @@ version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "clap" version = "4.1.8" @@ -87,33 +57,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "color-eyre" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - [[package]] name = "errno" version = "0.2.8" @@ -135,22 +78,6 @@ dependencies = [ "libc", ] -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "gimli" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" - [[package]] name = "heck" version = "0.4.1" @@ -163,12 +90,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - [[package]] name = "io-lifetimes" version = "1.0.6" @@ -191,12 +112,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.140" @@ -213,33 +128,8 @@ checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" name = "mclangc" version = "0.1.0" dependencies = [ + "anyhow", "clap", - "color-eyre", - "eyre", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.30.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" -dependencies = [ - "memchr", ] [[package]] @@ -254,18 +144,6 @@ version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -308,12 +186,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - [[package]] name = "rustix" version = "0.36.9" @@ -328,15 +200,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - [[package]] name = "strsim" version = "0.10.0" @@ -363,70 +226,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - [[package]] name = "unicode-ident" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 1dbe310..9777276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,5 @@ authors=[ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.79" clap = { version = "4.1.8", features = ["derive"] } -color-eyre = "0.6.2" -eyre = "0.6.8" diff --git a/README.md b/README.md index e861a0b..3f5dd4d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ You can find the docs [here](/docs/index.md) Usefull things that i search for a lot in the sourcecode so i added them here +add them in reverse order in mclang + Syscall arg order: \[rax ,rdi ,rsi ,rdx ,r10 ,r8 ,r9\] ## Credits diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..4e20864 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,3 @@ +/* +!/.gitignore +!/*.mcl \ No newline at end of file diff --git a/include/fs.mcl b/include/fs.mcl index f84828e..5395bbe 100644 --- a/include/fs.mcl +++ b/include/fs.mcl @@ -1,7 +1,13 @@ +const FS_O_RDONLY 0 end +const FS_O_WRONLY 1 end +const FS_O_RDWR 2 end + const FS_O_APPEND 1024 end // append to existing file +const FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!) +const FS_O_CREAT 64 end // create file if it doesn’t exist + const FS_O_ASYNC 8192 end // use signal-driven IO const FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions) -const FS_O_CREAT 64 end // create file if it doesn’t exist const FS_O_DIRECT 16384 end // bypass cache (slower) const FS_O_DIRECTORY 65536 end // fail if pathname isn’t a directory const FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return @@ -15,7 +21,6 @@ const FS_O_NDELAY 2048 end // same as O_NONBLOCK const FS_O_PATH 2097152 end // open descriptor for obtaining permissions and status of a file but does not allow read/write operations const FS_O_SYNC 1052672 end // wait for IO to complete before returning const FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file -const FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!) fn fs_read_to_string with int ptr returns int ptr then diff --git a/include/int.mcl b/include/int.mcl index 4d9366f..82b27b8 100644 --- a/include/int.mcl +++ b/include/int.mcl @@ -12,4 +12,9 @@ inline fn drop2 with any any returns void then drop drop done const sizeof(u64) 8 end const sizeof(u32) 4 end const sizeof(u16) 2 end -const sizeof(u8) 1 end \ No newline at end of file +const sizeof(u8) 1 end + +const u64 8 end +const u32 4 end +const u16 2 end +const u8 1 end \ No newline at end of file diff --git a/include/io.mcl b/include/io.mcl index a35ca6f..e7f49f0 100644 --- a/include/io.mcl +++ b/include/io.mcl @@ -49,7 +49,7 @@ inline fn eputs with int ptr returns void then STDOUT fwrite drop done -// TODO: make putc and eputc after we make local mem +// TODO: make putc, eputc, putd, and eputd after we make local mem // Exit the program with exit_code // args: [exit_code] diff --git a/include/mem.mcl b/include/mem.mcl index e69de29..8b13789 100644 --- a/include/mem.mcl +++ b/include/mem.mcl @@ -0,0 +1 @@ + diff --git a/include/string.mcl b/include/string.mcl new file mode 100644 index 0000000..6b2ce25 --- /dev/null +++ b/include/string.mcl @@ -0,0 +1,5 @@ + + +fn cstr_len with ptr returns int then + dup while dup load8 '\0' != do 1 + end swap - +done \ No newline at end of file diff --git a/playground/.gitignore b/playground/.gitignore new file mode 100644 index 0000000..4bd61ca --- /dev/null +++ b/playground/.gitignore @@ -0,0 +1,4 @@ +/* +!/.gitignore +!/*.mcl +!/mclangc \ No newline at end of file diff --git a/playground/mclangc b/playground/mclangc new file mode 100755 index 0000000..0e9bec8 --- /dev/null +++ b/playground/mclangc @@ -0,0 +1,13 @@ +#!/usr/bin/bash + +#? This is just a passthrough for the compiled mclangc binary for ease of use +#? It also compiles mclangc every time its ran + +pushd ../ > /dev/null + +cargo build --release -q + +popd > /dev/null + + +../target/release/mclangc -I../include ${@:1} \ No newline at end of file diff --git a/playground/test.mcl b/playground/test.mcl new file mode 100644 index 0000000..1ac4c68 --- /dev/null +++ b/playground/test.mcl @@ -0,0 +1,35 @@ +include "std.mcl" + + +struct StatDef do + val -> u32 + val2 -> i8 +end + +alloc Stat StatDef end + +fn main with int ptr returns void then + // p l + "Hello!\n" puts + + Stat.val 69 write32 + + Stat.val read32 _dbg_print + Stat.__size read32 _dbg_print + + // memory fd 4 end + + // NULL + // FS_O_RDWR + // c"/home/mcorange/@Projects/rust/programming_languages/mclang/mclangc/playground/test.mcl" + // fopen + // dup _dbg_print + // fd swap write32 + + + + + + + +done \ No newline at end of file diff --git a/src/bin/mcl_test_dev.rs b/src/bin/mcl_test_dev.rs index b3164ba..bee1329 100644 --- a/src/bin/mcl_test_dev.rs +++ b/src/bin/mcl_test_dev.rs @@ -3,8 +3,7 @@ use std::path::{PathBuf, Path}; use std::process::Stdio; use std::{process, fs}; use clap::Parser; -use color_eyre::Result; -use eyre::eyre; +use anyhow::{Result, bail}; pub mod color { #![allow(dead_code)] @@ -104,21 +103,21 @@ fn compare_results(intp: &TestOutput, comp: &TestOutput, f_in: &Path) -> Result< println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); println!("compiled:\n{}", comp.stdout); println!("interpreted:\n{}", intp.stdout); - return Err(eyre!("Testing failed")); + bail!("Testing failed"); } if intp.stderr != comp.stderr { println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stderr versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); println!("compiled:\n{}", comp.stderr); println!("interpreted:\n{}", intp.stderr); - return Err(eyre!("Testing failed")); + bail!("Testing failed"); } if intp.status != comp.status { println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted status codes differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); println!("compiled:\n{}", comp.status); println!("interpreted:\n{}", intp.status); - return Err(eyre!("Testing failed")); + bail!("Testing failed"); } println!("{b}[ {g}OK{rs}{b} ]{rs} {f} ", g=color::FG_GREEN, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); @@ -164,7 +163,7 @@ fn main() -> Result<()> { "record" => todo!("Implement test result recording"), s => { eprintln!("Unknown mode '{s}'"); - return Err(eyre!("Bad subcommand")); + bail!("Bad subcommand"); } }?; diff --git a/src/compile/commands.rs b/src/compile/commands.rs index 98426e6..d1f2532 100644 --- a/src/compile/commands.rs +++ b/src/compile/commands.rs @@ -1,7 +1,7 @@ use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; -use color_eyre::Result; -use crate::info; +use anyhow::Result; +use crate::{info, error}; pub fn linux_x86_64_compile_and_link(of_a: &Path, of_o: &Path, of_c: &Path, quiet: bool) -> Result<()> { @@ -22,11 +22,16 @@ pub fn linux_x86_64_compile_and_link(of_a: &Path, of_o: &Path, of_c: &Path, quie let mut proc = if cfg!(target_os = "windows") { return Ok(()); } else { - Command::new("nasm") + let ret = Command::new("nasm") .args(nasm_args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) - .spawn()? + .spawn(); + + if ret.is_err() { + error!("Nasm not installed") + } + ret? }; if !quiet { info!("running 'nasm {}'", nasm_args.join(" ")); diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index 1c3b120..e264960 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -1,13 +1,13 @@ use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap}; -use crate::{constants::{Operator, OpType, KeywordType}, Args, warn, lerror}; -use color_eyre::Result; +use crate::{definitions::*, Args, warn, lerror}; use crate::compile::commands::linux_x86_64_compile_and_link; -use crate::constants::InstructionType; +use crate::definitions::InstructionType; use super::{commands::linux_x86_64_run, Constant, Memory, Function}; -use eyre::eyre; + +use anyhow::{Result, bail}; -pub fn compile(tokens: &[Operator], args: &Args) -> Result{ +pub fn compile(program: &Program, args: &Args) -> Result{ let debug = args.get_opt_level()? < 1; let mut of_c = PathBuf::from(&args.out_file); @@ -32,45 +32,17 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ let mut memories: Vec = Vec::new(); let mut constants: HashMap = HashMap::new(); let mut functions: Vec = Vec::new(); + + let mut alloced_structs: Vec<(String, String)> = Vec::new(); // println!("{}", tokens.len()); let mut strings: Vec = Vec::new(); writeln!(writer, "BITS 64")?; writeln!(writer, "segment .text")?; - writeln!(writer, "_dbg_print:")?; - writeln!(writer, " mov r9, -3689348814741910323")?; - writeln!(writer, " sub rsp, 40")?; - writeln!(writer, " mov BYTE [rsp+31], 10")?; - writeln!(writer, " lea rcx, [rsp+30]")?; - writeln!(writer, ".L2:")?; - writeln!(writer, " mov rax, rdi")?; - writeln!(writer, " lea r8, [rsp+32]")?; - writeln!(writer, " mul r9")?; - writeln!(writer, " mov rax, rdi")?; - writeln!(writer, " sub r8, rcx")?; - writeln!(writer, " shr rdx, 3")?; - writeln!(writer, " lea rsi, [rdx+rdx*4]")?; - writeln!(writer, " add rsi, rsi")?; - writeln!(writer, " sub rax, rsi")?; - writeln!(writer, " add eax, 48")?; - writeln!(writer, " mov BYTE [rcx], al")?; - writeln!(writer, " mov rax, rdi")?; - writeln!(writer, " mov rdi, rdx")?; - writeln!(writer, " mov rdx, rcx")?; - writeln!(writer, " sub rcx, 1")?; - writeln!(writer, " cmp rax, 9")?; - writeln!(writer, " ja .L2")?; - writeln!(writer, " lea rax, [rsp+32]")?; - writeln!(writer, " mov edi, 1")?; - writeln!(writer, " sub rdx, rax")?; - writeln!(writer, " xor eax, eax")?; - writeln!(writer, " lea rsi, [rsp+32+rdx]")?; - writeln!(writer, " mov rdx, r8")?; - writeln!(writer, " mov rax, 1")?; - writeln!(writer, " syscall")?; - writeln!(writer, " add rsp, 40")?; - writeln!(writer, " ret")?; + writeln!(writer, "{}", super::MACRO_DEFINITIONS)?; + writeln!(writer, "{}", super::DBG_PRINT)?; + if !crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode { writeln!(writer, "global _start")?; @@ -82,8 +54,8 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ let mut ti = 0; - while ti < tokens.len() { - let token = &tokens[ti]; + while ti < program.ops.len() { + let token = &program.ops[ti]; if debug { writeln!(writer, "addr_{ti}:")?; if token.typ == OpType::Instruction(InstructionType::PushInt) { @@ -95,13 +67,13 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ } } else { if ti > 0 { - if tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) || - tokens[ti-1].typ == OpType::Keyword(KeywordType::End){ + if program.ops[ti-1].typ == OpType::Keyword(KeywordType::Else) || + program.ops[ti-1].typ == OpType::Keyword(KeywordType::End){ writeln!(writer, "addr_{ti}:")?; } } - if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) { + if ti + 1 < program.ops.len() && program.ops[ti+1].typ == OpType::Keyword(KeywordType::End) { writeln!(writer, "addr_{ti}:")?; } @@ -122,298 +94,160 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ OpType::Instruction(instruction) => { match instruction { InstructionType::PushInt => { - writeln!(writer, " mov rax, {}", token.value)?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_PushInt {}", token.value)?; ti += 1; }, InstructionType::PushStr => { - writeln!(writer, " mov rax, {}", token.text.len())?; - writeln!(writer, " push rax")?; - writeln!(writer, " mov rax, str_{}", strings.len())?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_PushStr {}, str_{}", token.text.len(), strings.len())?; strings.push(token.text.clone()); ti += 1; } InstructionType::PushCStr => { - writeln!(writer, " push rax")?; - writeln!(writer, " mov rax, str_{}", strings.len())?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_PushCStr str_{}", strings.len())?; strings.push(token.text.clone()); ti += 1; } InstructionType::Drop => { - writeln!(writer, " pop rax")?; + writeln!(writer, " OP_Drop")?; ti += 1; }, InstructionType::Print => { - writeln!(writer, " pop rdi")?; - writeln!(writer, " call _dbg_print")?; + writeln!(writer, " OP_Print")?; ti += 1; }, InstructionType::Dup => { - writeln!(writer, " pop rax")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rax")?; - + writeln!(writer, " OP_Dup")?; ti += 1; }, InstructionType::Rot => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rcx")?; - writeln!(writer, " push rbx")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rcx")?; - + writeln!(writer, " OP_Rot")?; ti += 1; }, InstructionType::Swap => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rbx")?; - + writeln!(writer, " OP_Swap")?; ti += 1; }, InstructionType::Over => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " push rbx")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rbx")?; - + writeln!(writer, " OP_Over")?; ti += 1; }, - InstructionType::Load8 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " xor rbx, rbx")?; - writeln!(writer, " mov bl, byte [rax]")?; - writeln!(writer, " push rbx")?; + InstructionType::Read8 => { + writeln!(writer, " OP_Load8")?; ti += 1; } - InstructionType::Store8 => { - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " mov byte [rax], bl")?; + InstructionType::Write8 => { + writeln!(writer, " OP_Store8")?; ti += 1; } - InstructionType::Load32 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " xor rbx, rbx")?; - writeln!(writer, " mov ebx, dword [rax]")?; - writeln!(writer, " push rbx")?; + InstructionType::Read32 => { + writeln!(writer, " OP_Load32")?; ti += 1; } - InstructionType::Store32 => { - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " mov dword[rax], ebx")?; + InstructionType::Write32 => { + writeln!(writer, " OP_Store32")?; ti += 1; } - InstructionType::Load64 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " xor rbx, rbx")?; - writeln!(writer, " mov rbx, qword [rax]")?; - writeln!(writer, " push rbx")?; + InstructionType::Read64 => { + writeln!(writer, " OP_Load64")?; ti += 1; } - InstructionType::Store64 => { - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " mov qword [rax], rbx")?; + InstructionType::Write64 => { + writeln!(writer, " OP_Store64")?; ti += 1; } // math InstructionType::Plus => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " add rax, rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Plus")?; ti += 1; }, InstructionType::Minus => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " sub rbx, rax")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " OP_Minus")?; ti += 1; }, InstructionType::Equals => { - writeln!(writer, " mov rcx, 0")?; - writeln!(writer, " mov rdx, 1")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmove rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_Equals")?; ti += 1; }, InstructionType::Lt => { - writeln!(writer, " mov rcx, 0")?; - writeln!(writer, " mov rdx, 1")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmovl rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_Lt")?; ti += 1; }, InstructionType::Gt => { - writeln!(writer, " mov rcx, 0")?; - writeln!(writer, " mov rdx, 1")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmovg rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_Gt")?; ti += 1; }, InstructionType::NotEquals => { - writeln!(writer, " mov rcx, 1")?; - writeln!(writer, " mov rdx, 0")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmove rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_NotEquals")?; ti += 1; }, InstructionType::Le => { - writeln!(writer, " mov rcx, 0")?; - writeln!(writer, " mov rdx, 1")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmovle rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_Le")?; ti += 1; }, InstructionType::Ge => { - writeln!(writer, " mov rcx, 0")?; - writeln!(writer, " mov rdx, 1")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " cmp rax, rbx")?; - writeln!(writer, " cmovge rcx, rdx")?; - writeln!(writer, " push rcx")?; + writeln!(writer, " OP_Ge")?; ti += 1; }, InstructionType::Band => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " and rbx, rax")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " OP_Band")?; ti += 1; }, InstructionType::Bor => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " or rbx, rax")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " OP_Bor")?; ti += 1; }, InstructionType::Shr => { - writeln!(writer, " pop rcx")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " shr rbx, cl")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " OP_Shr")?; ti += 1; }, InstructionType::Shl => { - writeln!(writer, " pop rcx")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " shl rbx, cl")?; - writeln!(writer, " push rbx")?; + writeln!(writer, " OP_Shl")?; ti += 1; }, InstructionType::DivMod => { - writeln!(writer, " xor rdx, rdx")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " div rbx")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rdx")?; + writeln!(writer, " OP_DivMod")?; ti += 1; }, InstructionType::Mul => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " mul rbx")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Mul")?; ti += 1; }, InstructionType::Syscall0 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall0")?; ti += 1; }, InstructionType::Syscall1 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall1")?; ti += 1; }, InstructionType::Syscall2 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " pop rsi")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall2")?; ti += 1; }, InstructionType::Syscall3 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " pop rsi")?; - writeln!(writer, " pop rdx")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; - + writeln!(writer, " OP_Syscall3")?; ti += 1; }, InstructionType::Syscall4 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " pop rsi")?; - writeln!(writer, " pop rdx")?; - writeln!(writer, " pop r10")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall4")?; ti += 1; }, InstructionType::Syscall5 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " pop rsi")?; - writeln!(writer, " pop rdx")?; - writeln!(writer, " pop r10")?; - writeln!(writer, " pop r8")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall5")?; ti += 1; }, InstructionType::Syscall6 => { - writeln!(writer, " pop rax")?; - writeln!(writer, " pop rdi")?; - writeln!(writer, " pop rsi")?; - writeln!(writer, " pop rdx")?; - writeln!(writer, " pop r10")?; - writeln!(writer, " pop r8")?; - writeln!(writer, " pop r9")?; - writeln!(writer, " syscall")?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_Syscall6")?; ti += 1; }, InstructionType::MemUse => { - writeln!(writer, " push mem_{}", token.addr.unwrap())?; + writeln!(writer, " OP_MemUse {}", token.addr.unwrap())?; ti += 1; }, InstructionType::None => { @@ -421,7 +255,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ unreachable!() }, InstructionType::FnCall => { - writeln!(writer, " call {}", token.text)?; + writeln!(writer, " OP_FnCall {}", token.text)?; ti += 1; }, InstructionType::Return => { @@ -452,8 +286,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; } InstructionType::ConstUse => { - writeln!(writer, " mov rax, qword [const_{}]", token.text)?; - writeln!(writer, " push rax")?; + writeln!(writer, " OP_ConstUse {}", token.text)?; let mut c = constants.get(&token.text).unwrap().clone(); c.used = true; @@ -461,6 +294,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ constants.insert(token.text.clone(), c); ti += 1; }, + InstructionType::StructUse => { + writeln!(writer, " OP_StructUse {}", token.text)?; + ti += 1; + }, } } @@ -529,16 +366,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ ti += 1; } KeywordType::FunctionThen => ti += 1, - KeywordType::Function | - KeywordType::Include | - KeywordType::Inline | - KeywordType::Export | - KeywordType::Constant => unreachable!(), KeywordType::FunctionDefExported => { if !crate::config::ENABLE_EXPORTED_FUNCTIONS { lerror!(&token.loc, "Experimental feature 'exported functions' is not enabled"); - return Err(eyre!("")); + bail!(""); } writeln!(writer, "global {}", token.text)?; @@ -571,7 +403,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ } if token.types.0 >= 7 { lerror!(&token.loc, "More than 6 arguments in an external function is not supported"); - return Err(eyre!("")); + bail!(""); } } @@ -579,14 +411,29 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ should_push_ret = true; } else if token.types.1 > 1 { lerror!(&token.loc, "More than 1 return arguments in an external function is not supported"); - return Err(eyre!("")); + bail!(""); } functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false}); ti += 1; }, + KeywordType::Function | + KeywordType::Include | + KeywordType::Inline | + KeywordType::Export | + KeywordType::Struct | + KeywordType::Constant => unreachable!(), } } + OpType::Internal(t) => { + match t { + InternalType::StructAlloc{name} => { + alloced_structs.push((name, token.text.clone())); + ti += 1; + }, + InternalType::Arrow => panic!("{t:?}"), + } + }, } } writeln!(writer, "addr_{ti}:")?; @@ -615,16 +462,37 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ } else { unreachable!(); } - } writeln!(writer, "segment .bss")?; - for s in memories { - writeln!(writer, " mem_{}: resb {}", s.id, s.size)?; + for m in memories { + writeln!(writer, " mem_{}: resb {}", m.id, m.size)?; } - writeln!(writer, " ret_stack: resq 256")?; + + for s in alloced_structs { + let Some(st) = program.struct_defs.get(&s.0) else { + // TODO: Make better error + panic!("Couldn find struct in struct defs"); + }; + + let name = &s.1; + let mut st_size = 0; + + writeln!(writer, " struct_{name}:")?; + for f in &st.fields { + let size = f.1.get_size(); + writeln!(writer, " struct_{name}.{}: resb {}", f.0, size)?; + st_size += size; + } + + writeln!(writer, " struct_{name}.__size: db {}", st_size)?; + + } + + + writeln!(writer, " ret_stack: resq 256")?; // for t in tokens { // println!("{t:?}"); // } @@ -637,7 +505,8 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ functions )?; - linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?; + linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet); + if args.run { let c = linux_x86_64_run(&of_c, &[], args.quiet)?; return Ok(c); @@ -660,7 +529,7 @@ fn pre_compile_steps(_code: &str, functions: Vec) -> Result<()> { if !has_main { crate::errors::missing_main_fn(); - return Err(eyre!("")); + bail!(""); } Ok(()) diff --git a/src/compile/mod.rs b/src/compile/mod.rs index 542e6ed..a02012b 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,4 +1,4 @@ -use crate::constants::Loc; +use crate::definitions::Loc; pub mod linux_x86_64; pub mod commands; @@ -25,4 +25,338 @@ pub struct Function { pub loc: Loc, pub name: String, pub exter: bool, -} \ No newline at end of file +} + +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 +"; + +const MACRO_DEFINITIONS: &'static str = "\ +%macro OP_PushInt 1 + mov rax, %1 + push rax +%endmacro + +; str_len, str_id +%macro OP_PushStr 2 + mov rax, %1 + push rax + mov rax, %2 + push rax +%endmacro + +; str_id +%macro OP_PushCStr 1 + push rax + mov rax, %1 + push rax +%endmacro + +%macro OP_Drop 0 + pop rax +%endmacro + +%macro OP_Print 0 + pop rdi + call _dbg_print +%endmacro + +%macro OP_Dup 0 + pop rax + push rax + push rax +%endmacro + +%macro OP_Rot 0 + pop rax + pop rbx + pop rcx + push rbx + push rax + push rcx +%endmacro + +%macro OP_Swap 0 + pop rax + pop rbx + push rax + push rbx +%endmacro + +%macro OP_Over 0 + pop rax + pop rbx + push rbx + push rax + push rbx +%endmacro + +%macro OP_Load8 0 + pop rax + xor rbx, rbx + mov bl, byte [rax] + push rbx +%endmacro + +%macro OP_Store8 0 + pop rbx + pop rax + mov byte [rax], bl +%endmacro + +%macro OP_Load32 0 + pop rax + xor rbx, rbx + mov ebx, dword [rax] + push rbx +%endmacro + +%macro OP_Store32 0 + pop rbx + pop rax + mov dword[rax], ebx +%endmacro + +%macro OP_Load64 0 + pop rax + xor rbx, rbx + mov rbx, qword [rax] + push rbx +%endmacro + +%macro OP_Store64 0 + pop rbx + pop rax + mov qword [rax], rbx +%endmacro + +%macro OP_Plus 0 + pop rax + pop rbx + add rax, rbx + push rax +%endmacro + +%macro OP_Minus 0 + pop rax + pop rbx + sub rbx, rax + push rbx +%endmacro + +%macro OP_Equals 0 + mov rcx, 0 + mov rdx, 1 + pop rax + pop rbx + cmp rax, rbx + cmove rcx, rdx + push rcx +%endmacro + +%macro OP_Lt 0 + mov rcx, 0 + mov rdx, 1 + pop rbx + pop rax + cmp rax, rbx + cmovl rcx, rdx + push rcx +%endmacro + +%macro OP_Gt 0 + mov rcx, 0 + mov rdx, 1 + pop rbx + pop rax + cmp rax, rbx + cmovg rcx, rdx + push rcx +%endmacro + +%macro OP_NotEquals 0 + mov rcx, 1 + mov rdx, 0 + pop rax + pop rbx + cmp rax, rbx + cmove rcx, rdx + push rcx +%endmacro + +%macro OP_Le 0 + mov rcx, 0 + mov rdx, 1 + pop rbx + pop rax + cmp rax, rbx + cmovle rcx, rdx + push rcx +%endmacro + +%macro OP_Ge 0 + mov rcx, 0 + mov rdx, 1 + pop rbx + pop rax + cmp rax, rbx + cmovge rcx, rdx + push rcx +%endmacro + +%macro OP_Band 0 + pop rax + pop rbx + and rbx, rax + push rbx +%endmacro + +%macro OP_Bor 0 + pop rax + pop rbx + or rbx, rax + push rbx +%endmacro + +%macro OP_Shr 0 + pop rcx + pop rbx + shr rbx, cl + push rbx +%endmacro + +%macro OP_Shl 0 + pop rcx + pop rbx + shl rbx, cl + push rbx +%endmacro + +%macro OP_DivMod 0 + xor rdx, rdx + pop rbx + pop rax + div rbx + push rax + push rdx +%endmacro + +%macro OP_Mul 0 + pop rax + pop rbx + mul rbx + push rax +%endmacro + +%macro OP_Syscall0 0 + pop rax + syscall + push rax +%endmacro + +%macro OP_Syscall1 0 + pop rax + pop rdi + syscall + push rax +%endmacro + +%macro OP_Syscall2 0 + pop rax + pop rdi + pop rsi + syscall + push rax +%endmacro + +%macro OP_Syscall3 0 + pop rax + pop rdi + pop rsi + pop rdx + syscall + push rax +%endmacro + +%macro OP_Syscall4 0 + pop rax + pop rdi + pop rsi + pop rdx + pop r10 + syscall + push rax +%endmacro + +%macro OP_Syscall5 0 + pop rax + pop rdi + pop rsi + pop rdx + pop r10 + pop r8 + syscall + push rax +%endmacro + +%macro OP_Syscall6 0 + pop rax + pop rdi + pop rsi + pop rdx + pop r10 + pop r8 + pop r9 + syscall + push rax +%endmacro + +%macro OP_MemUse 1 + push mem_%1 +%endmacro + +%macro OP_FnCall 1 + call %1 +%endmacro + +%macro OP_ConstUse 1 + mov rax, qword [const_%1] + push rax +%endmacro + +%macro OP_StructUse 1 + push struct_%1 +%endmacro +"; \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 1334086..925a518 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,7 @@ /** * Prints out extra information */ -pub const DEV_MODE: bool = false; +pub const DEV_MODE: bool = true; pub const DEFAULT_OUT_FILE: &str = "a.out"; pub const DEFAULT_INCLUDES: [&str;2] = [ @@ -10,16 +10,6 @@ pub const DEFAULT_INCLUDES: [&str;2] = [ ]; -/** - * Interpreting configs - * `MEM_SZ` is the buffer size for memory - * `STRING_SZ` is the buffer size for strings - * if you have buffer overflow consider increasing these - */ -pub const MEM_SZ: usize = 640 * 1000; // 4kb -pub const STRING_SZ: usize = 640 * 1000; // 4kb - - /** * Experimental options */ diff --git a/src/constants.rs b/src/constants.rs index 21da70c..45d0035 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -33,12 +33,12 @@ pub enum InstructionType { // mem - Load8, - Store8, - Load32, - Store32, - Load64, - Store64, + Read8, + Write8, + Read32, + Write32, + Read64, + Write64, // syscalls Syscall0, @@ -89,7 +89,8 @@ pub enum KeywordType { FunctionThen, FunctionDone, Inline, - Export + Export, + Struct } #[derive(Debug, Clone, PartialEq)] @@ -164,12 +165,12 @@ impl OpType { InstructionType::Shl => "shl", InstructionType::DivMod => "divmod", InstructionType::Mul => "*", - InstructionType::Load8 => "load8", - InstructionType::Store8 => "store8", - InstructionType::Load32 => "load32", - InstructionType::Store32 => "store32", - InstructionType::Load64 => "load64", - InstructionType::Store64 => "store64", + InstructionType::Read8 => "read8", + InstructionType::Write8 => "write8", + InstructionType::Read32 => "read32", + InstructionType::Write32 => "write32", + InstructionType::Read64 => "read64", + InstructionType::Write64 => "write64", InstructionType::Syscall0 => "syscall0", InstructionType::Syscall1 => "syscall1", InstructionType::Syscall2 => "syscall2", @@ -213,6 +214,7 @@ impl OpType { KeywordType::FunctionDefExported => "extern function definition (internal)", KeywordType::Inline => "inline", KeywordType::Export => "export", + KeywordType::Struct => "struct", } } diff --git a/src/definitions/mod.rs b/src/definitions/mod.rs new file mode 100644 index 0000000..3a5f835 --- /dev/null +++ b/src/definitions/mod.rs @@ -0,0 +1,392 @@ +use std::collections::HashMap; + +use anyhow::{Result, bail}; + + +#[derive(Debug, Clone, PartialEq)] +pub enum InstructionType { + + // stack + PushInt, + PushStr, + PushCStr, + 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, + + // typing + TypeBool, + TypePtr, + TypeInt, + TypeVoid, + // TypeStr, + TypeAny, + Returns, + With, + + FnCall, + MemUse, + ConstUse, + StructUse, + + Return, + None // Used for macros and any other non built in word definitions + +} +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum KeywordType { + If, + Else, + End, + While, + Do, + Include, + Memory, + Constant, + ConstantDef, + Function, + FunctionDef, + FunctionDefExported, + FunctionThen, + FunctionDone, + Inline, + Export, + Struct, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum InternalType { + Arrow, + StructAlloc { + name: String + } +} +#[derive(Debug, Clone, PartialEq)] +pub enum OpType { + Keyword(KeywordType), + Instruction(InstructionType), + Internal(InternalType) +} + +#[derive(Debug, Clone)] +pub struct Operator{ + pub typ: OpType, + pub tok_typ: TokenType, + pub value: usize, + pub text: String, //? only used for OpType::PushStr + pub addr: Option, //? only used for OpType::PushStr + pub jmp: usize, + pub loc: Loc, + pub types: (usize, usize) +} + +impl Operator { + pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self { + Self { + typ, + value, + jmp: 0, + addr: None, + text, + loc: (file, row, col), + tok_typ, + types: (0, 0) + } + } + pub fn set_addr(&mut self, addr: usize) -> Self { + self.addr = Some(addr); + (*self).clone() + } + + // pub fn set_types(&mut self, args: usize, rets: usize) -> Self { + // self.types = (args, rets); + // (*self).clone() + // } + +} + +impl OpType { + pub fn human(&self) -> String { + match (*self).clone() { + OpType::Instruction(instruction) => { + match instruction { + + InstructionType::PushInt => "Number", + InstructionType::PushStr => "String", + InstructionType::PushCStr => "CString", + InstructionType::Print => "_dbg_print", + InstructionType::Dup => "dup", + InstructionType::Drop => "drop", + InstructionType::Rot => "rot", + InstructionType::Over => "over", + InstructionType::Swap => "swap", + InstructionType::Plus => "+", + InstructionType::Minus => "-", + InstructionType::Equals => "=", + InstructionType::Gt => ">", + InstructionType::Lt => "<", + InstructionType::NotEquals => "!=", + InstructionType::Le => "<=", + InstructionType::Ge => ">=", + InstructionType::Band => "band", + InstructionType::Bor => "bor", + InstructionType::Shr => "shr", + InstructionType::Shl => "shl", + InstructionType::DivMod => "divmod", + InstructionType::Mul => "*", + InstructionType::Read8 => "read8", + InstructionType::Write8 => "write8", + InstructionType::Read32 => "read32", + InstructionType::Write32 => "write32", + InstructionType::Read64 => "read64", + InstructionType::Write64 => "write64", + InstructionType::Syscall0 => "syscall0", + InstructionType::Syscall1 => "syscall1", + InstructionType::Syscall2 => "syscall2", + InstructionType::Syscall3 => "syscall3", + InstructionType::Syscall4 => "syscall4", + InstructionType::Syscall5 => "syscall5", + InstructionType::Syscall6 => "syscall6", + InstructionType::CastBool => "cast(bool", + InstructionType::CastPtr => "cast(ptr)", + InstructionType::CastInt => "cast(int)", + InstructionType::CastVoid => "cast(void)", + InstructionType::None => "None", + InstructionType::MemUse => "Memory use (internal)", + InstructionType::FnCall => "Function Call (Internal)", + InstructionType::ConstUse => "Constant Use (Internal)", + InstructionType::StructUse => "Struct Use (Internal)", + InstructionType::Return => "return", + InstructionType::TypeBool => "bool", + InstructionType::TypePtr => "ptr", + InstructionType::TypeInt => "int", + InstructionType::TypeVoid => "void", + InstructionType::Returns => "returns", + InstructionType::With => "with", + InstructionType::TypeAny => "any", + } + } + OpType::Keyword(keyword) => { + match keyword { + KeywordType::If => "if", + KeywordType::Else => "else", + KeywordType::End => "end", + KeywordType::While => "while", + KeywordType::Do => "do", + KeywordType::Include => "include", + KeywordType::Memory => "memory", + KeywordType::Function => "fn", + KeywordType::Constant => "const", + KeywordType::FunctionThen => "then", + KeywordType::FunctionDone => "done", + KeywordType::ConstantDef => "constant Definition (internal)", + KeywordType::FunctionDef => "function definition (internal)", + KeywordType::FunctionDefExported => "extern function definition (internal)", + KeywordType::Inline => "inline", + KeywordType::Export => "export", + KeywordType::Struct => "struct", + } + } + OpType::Internal(t) => { + match t { + InternalType::Arrow => "->", + InternalType::StructAlloc{..} => "Struct alloc ( internal )", + } + }, + + }.to_string() + } +} + +#[derive(Debug, Clone)] +pub struct Token { + pub file: String, + pub line: usize, + pub col: usize, + pub text: String, + pub typ: TokenType, + pub value: Option, //* only used for Memories + pub addr: Option, //* only used for Memories + pub op_typ: OpType //* only used for Memories +} + +#[derive(Debug, Clone, PartialEq, Copy)] +pub enum TokenType { + Word, + Int, + String, + CString, + Char +} + +impl Token { + pub fn loc(&self) -> Loc { + ( + self.file.clone(), + self.line, + self.col + ) + } +} + +impl TokenType { + pub fn human(self) -> String { + match self { + TokenType::Word => "Word", + TokenType::Int => "Int", + TokenType::String => "String", + TokenType::CString => "CString", + TokenType::Char => "Char" + }.to_string() + } +} + +pub type Loc = (String, usize, usize); + +#[derive(Debug, PartialEq, Clone)] +pub enum Types { + Any, + Bool, + Ptr, + Void, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + + #[allow(dead_code)] //TODO: Implement custom types + Custom{ + size: u64 // in bytes + }, + // todo: add signed numbers since we dont have them yet lol +} + +impl Types { + pub fn get_size(&self) -> u64 { + match *self { + Types::Any => 0, // any cant be a known size + Types::Void => 0, + Types::Bool => 1, + Types::U8 | + Types::I8 => 1, + Types::U16 | + Types::I16 => 2, + Types::U32 | + Types::I32 => 4, + Types::Ptr | + Types::U64 | + Types::I64 => 8, + Types::Custom { size } => size, + } + } + pub fn from_string + std::fmt::Display>(s: &S) -> Result { + match s.to_string().as_str() { + "any" => Ok(Types::Any), + "void" => Ok(Types::Void), + "bool" => Ok(Types::Bool), + "u8" => Ok(Types::U8), + "i8" => Ok(Types::I8), + "u16" => Ok(Types::U16), + "i16" => Ok(Types::I16), + "u32" => Ok(Types::U32), + "i32" => Ok(Types::I32), + "ptr" => Ok(Types::Ptr), + "u64" => Ok(Types::U64), + "i64" => Ok(Types::I64), + _ => bail!("Unknown type {s}") + } + } +} + + + + + +#[derive(Debug, Clone)] +pub struct Function { + pub loc: Loc, + pub name: String, + pub inline: bool, + pub tokens: Option> +} + +#[derive(Debug, Clone)] +pub struct Constant { + pub loc: Loc, + pub name: String +} + +#[derive(Debug, Clone)] +pub struct Memory { + pub loc: Loc, + pub id: usize + +} + +#[derive(Debug, Clone)] +pub struct StructDef { + pub loc: Loc, + pub name: String, + pub fields: Vec<(String, Types)> +} + +pub type Functions = HashMap; +pub type Memories = HashMap; +pub type Constants = HashMap; +pub type StructDefs = HashMap; + +#[derive(Debug, Clone)] +pub struct Program { + pub ops: Vec, + pub functions: Functions, + pub memories: Memories, + pub constants: Constants, + pub struct_defs: StructDefs, + pub struct_allocs: HashMap +} diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 99a636d..7fb23ff 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -126,9 +126,9 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ ip += 1; }, #[allow(clippy::cast_possible_truncation)] - InstructionType::Load8 | - InstructionType::Load32 | - InstructionType::Load64 => { + InstructionType::Read8 | + InstructionType::Read32 | + InstructionType::Read64 => { let a = stack_pop(&mut stack, &pos)?; if a > crate::MEM_SZ + crate::STRING_SZ { lerror!(&op.loc, "Invalid memory address {a}"); @@ -139,7 +139,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ ip += 1; } #[allow(clippy::cast_possible_truncation)] - InstructionType::Store8 => { + InstructionType::Write8 => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; @@ -152,7 +152,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ ip += 1; } #[allow(clippy::cast_possible_truncation)] - InstructionType::Store32 => { + InstructionType::Write32 => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; @@ -166,7 +166,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result{ } #[allow(clippy::cast_possible_truncation)] - InstructionType::Store64 => { + InstructionType::Write64 => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; diff --git a/src/lexer.rs b/src/lexer.rs index 5864ec4..c9db904 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -1,5 +1,5 @@ -use crate::{constants::{Token, TokenType}, Args}; +use crate::{definitions::{Token, TokenType}, Args}; fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) { match s { @@ -131,7 +131,7 @@ pub fn lex(code: &str, file: &str, _args: &Args) -> Vec { typ: tok_type, value: None, addr: None, - op_typ: crate::constants::OpType::Instruction(crate::constants::InstructionType::None) + op_typ: crate::definitions::OpType::Instruction(crate::definitions::InstructionType::None) }; tokens.push(t); } diff --git a/src/main.rs b/src/main.rs index 2dd5c07..d813ecb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,6 @@ #![allow(clippy::wildcard_imports)] #![allow(clippy::too_many_lines)] -mod constants; -mod interpret; +mod definitions; mod util; mod compile; mod parser; @@ -11,28 +10,23 @@ mod typechecker; mod precompiler; mod config; mod errors; +pub mod test; use config::*; use std::{fs, collections::HashMap}; use clap::Parser; -use color_eyre::Result; -use eyre::eyre; +use anyhow::{Result, bail}; #[derive(Parser, Debug, Clone)] #[command(author=env!("CARGO_PKG_AUTHORS"), version=env!("CARGO_PKG_VERSION"), about=env!("CARGO_PKG_DESCRIPTION"), long_about=env!("CARGO_PKG_DESCRIPTION"))] pub struct Args { /// Input source file - #[arg(long, short)] in_file: String, /// Output compiled file #[arg(long, short, default_value_t=String::from(DEFAULT_OUT_FILE))] out_file: String, - /// Compile - #[arg(long, short)] - compile: bool, - /// Interpert #[arg(long, short='s')] interpret: bool, @@ -78,7 +72,7 @@ impl Args { "0" | "" => Ok(1), o => { error!("Unknown optimisation level {o}"); - Err(eyre!("")) + bail!("") } } } @@ -98,7 +92,7 @@ fn main() -> Result<()>{ let mut parser = parser::Parser::new(tokens, &args, None); - let tokens = match parser.parse(){ + let program = match parser.parse(){ Ok(t) => t, Err(e) => { error!("Parsing failed, exiting!"); @@ -109,7 +103,7 @@ fn main() -> Result<()>{ } }; - match typechecker::typecheck(tokens.clone(), &args, None, HashMap::new(), HashMap::new()) { + match typechecker::typecheck(program.ops.clone(), &args, None, HashMap::new(), HashMap::new()) { Ok(_) => (), Err(e) => { error!("Typechecking failed, exiting!"); @@ -120,22 +114,14 @@ fn main() -> Result<()>{ } }; - let c = if args.compile && args.interpret { - error!("Cannot compile and interpret at the same time"); - 0 - } else if args.interpret { - if let Ok(c) = interpret::linux_x86_64::run(&tokens) { c } else { - error!("Interpretation failed, exiting!"); - 1 - } - } else if args.compile { - if let Ok(c) = compile::linux_x86_64::compile(&tokens, &args) { c } else { + let c =match compile::linux_x86_64::compile(&program, &args) { + Ok(c) => c, + Err(e) => { error!("Compilation failed, exiting!"); + println!("{e}"); 1 } - } else { - error!("Did not choose to compile or to interpret, exiting"); - 0 }; + std::process::exit(c); } diff --git a/src/parser.rs b/src/parser.rs index 971cacd..f16a463 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,8 +1,7 @@ use std::ops::Deref; -use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::Preprocessor, Args}; -use color_eyre::Result; -use eyre::eyre; +use crate::{definitions::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType, InternalType, Program}, lerror, preprocessor::Preprocessor, Args}; +use anyhow::{Result, bail}; pub fn cross_ref(mut program: Vec) -> Result> { let mut stack: Vec = Vec::new(); @@ -18,11 +17,11 @@ pub fn cross_ref(mut program: Vec) -> Result> { OpType::Keyword(KeywordType::Else) => { let Some(if_ip) = stack.pop() else { lerror!(&op.loc, "Unclosed-if else block"); - return Err(eyre!("Cross referencing")); + bail!("Cross referencing") }; if program[if_ip].typ != OpType::Keyword(KeywordType::If) { lerror!(&op.clone().loc,"'else' can only close 'if' blocks"); - return Err(eyre!("Bad block")); + bail!("Bad block") } program[if_ip].jmp = ip + 1; @@ -31,7 +30,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { OpType::Keyword(KeywordType::End) => { let Some(block_ip) = stack.pop() else { lerror!(&op.loc, "Unclosed if, if-else, while-do, function, memory, or constant"); - return Err(eyre!("Cross referencing")); + bail!("Cross referencing") }; match &program[block_ip].typ { @@ -50,7 +49,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { a => { println!("{a:?}"); lerror!(&op.clone().loc,"'end' can only close if, if-else, while-do, function, memory, or constant blocks"); - return Err(eyre!("")); + bail!("") } } @@ -58,7 +57,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { OpType::Keyword(KeywordType::Do) => { let Some(block_ip) = stack.pop() else { lerror!(&op.loc, "Unclosed while-do block"); - return Err(eyre!("Cross referencing")); + bail!("Cross referencing") }; program[ip].jmp = block_ip; @@ -72,7 +71,7 @@ pub fn cross_ref(mut program: Vec) -> Result> { // println!("{:?}", stack); let i = stack.pop().expect("Empy stack"); lerror!(&program[i].clone().loc,"Unclosed block, {:?}", program[i].clone()); - return Err(eyre!("Unclosed block")); + bail!("Unclosed block") } Ok(program.clone()) @@ -98,7 +97,7 @@ impl<'a> Parser<'a> { } } - pub fn parse(&mut self) -> Result> { + pub fn parse(&mut self) -> Result { let mut tokens = Vec::new(); for token in &self.tokens { @@ -129,7 +128,7 @@ impl<'a> Parser<'a> { let c = token.text.clone(); if c.len() != 1 { lerror!(&token.loc(), "Chars can only be of lenght 1, got {}", c.len()); - return Err(eyre!("")); + bail!("") } tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col)); @@ -138,9 +137,9 @@ impl<'a> Parser<'a> { } - self.preprocessor.program = tokens; - let t = self.preprocessor.preprocess()?.get_ops(); - let t = cross_ref(t)?; + self.preprocessor.program.ops = tokens; + let mut t = self.preprocessor.preprocess()?.get_program(); + t.ops = cross_ref(t.ops)?; Ok(t) } @@ -180,12 +179,12 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { // mem - "load8" => OpType::Instruction(InstructionType::Load8), - "store8" => OpType::Instruction(InstructionType::Store8), - "load32" => OpType::Instruction(InstructionType::Load32), - "store32" => OpType::Instruction(InstructionType::Store32), - "load64" => OpType::Instruction(InstructionType::Load64), - "store64" => OpType::Instruction(InstructionType::Store64), + "read8" => OpType::Instruction(InstructionType::Read8), + "write8" => OpType::Instruction(InstructionType::Write8), + "read32" => OpType::Instruction(InstructionType::Read32), + "write32" => OpType::Instruction(InstructionType::Write32), + "read64" => OpType::Instruction(InstructionType::Read64), + "write64" => OpType::Instruction(InstructionType::Write64), "syscall0" => OpType::Instruction(InstructionType::Syscall0), "syscall1" => OpType::Instruction(InstructionType::Syscall1), @@ -212,6 +211,7 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "done" => OpType::Keyword(KeywordType::FunctionDone), "inline" => OpType::Keyword(KeywordType::Inline), "export" => OpType::Keyword(KeywordType::Export), + "struct" => OpType::Keyword(KeywordType::Struct), "return" => OpType::Instruction(InstructionType::Return), "returns" => OpType::Instruction(InstructionType::Returns), "bool" => OpType::Instruction(InstructionType::TypeBool), @@ -220,6 +220,9 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "void" => OpType::Instruction(InstructionType::TypeVoid), "any" => OpType::Instruction(InstructionType::TypeAny), "with" => OpType::Instruction(InstructionType::With), + + "->" => OpType::Internal(InternalType::Arrow), + _ => OpType::Instruction(InstructionType::None) } diff --git a/src/precompiler.rs b/src/precompiler.rs index 9c4bc3e..7f60dab 100644 --- a/src/precompiler.rs +++ b/src/precompiler.rs @@ -1,13 +1,12 @@ -use color_eyre::Result; -use eyre::eyre; +use anyhow::{Result, bail}; -use crate::{constants::{ OpType, InstructionType, Loc, Operator}, lerror}; +use crate::{definitions::{ OpType, InstructionType, Loc, Operator}, lerror}; fn stack_pop(stack: &mut Vec, loc: &Loc) -> Result { if let Some(i) = stack.pop() { Ok(i) } else { lerror!(&loc.clone(), "Stack underflow"); - Err(eyre!("Stack underflow")) + bail!("Stack underflow") } } @@ -131,15 +130,16 @@ pub fn precompile(tokens: &Vec) -> Result>{ _ => { lerror!(&token.loc, "Unsupported precompiler instruction {:?}", i); dbg!(tokens); - return Err(eyre!("")); + bail!(""); } } } OpType::Keyword(_) => { lerror!(&token.loc, "Unsupported precompiler keyword {:?}", token.typ); dbg!(tokens); - return Err(eyre!("")); + bail!(""); } + OpType::Internal(t) => panic!("{t:?}"), } } diff --git a/src/preprocessor.rs b/src/preprocessor.rs index f4e8993..2100388 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -1,12 +1,10 @@ use std::collections::HashMap; -use std::ops::Deref; use std::path::{PathBuf, Path}; -use color_eyre::Result; -use eyre::eyre; +use anyhow::{Result, bail}; -use crate::constants::{Loc, OpType, TokenType, KeywordType, InstructionType, Operator}; +use crate::definitions::*; use crate::lexer::lex; use crate::precompiler::precompile; use crate::{lerror, Args, warn, linfo, parser}; @@ -14,51 +12,32 @@ use crate::parser::lookup_word; -#[derive(Debug, Clone)] -pub struct Function { - pub loc: Loc, - pub name: String, - pub inline: bool, - pub tokens: Option> -} - -#[derive(Debug, Clone)] -pub struct Constant { - pub loc: Loc, - pub name: String -} - -#[derive(Debug, Clone)] -pub struct Memory { - pub loc: Loc, - pub id: usize - -} - -type Functions = HashMap; -type Memories = HashMap; -type Constants = HashMap; #[derive(Debug, Clone)] pub struct Preprocessor<'a> { - pub program: Vec, - pub functions: Functions, - pub memories: Memories, - pub constants: Constants, - pub in_function: Option, - args: &'a Args + pub program: Program, + in_function: Option, + args: &'a Args, + f_inline: bool, + f_export: bool, } impl<'a> Preprocessor<'a> { pub fn new(prog: Vec, args: &'a Args) -> Self { Self { - program: prog, args, - functions: HashMap::new(), - memories: HashMap::new(), - constants: HashMap::new(), - in_function: None + program: Program { + ops: prog, + functions: HashMap::new(), + memories: HashMap::new(), + constants: HashMap::new(), + struct_defs: HashMap::new(), + struct_allocs: HashMap::new() + }, + in_function: None, + f_inline: false, + f_export: false, } } @@ -66,374 +45,46 @@ impl<'a> Preprocessor<'a> { pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{ // println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::>>()); - let mut f_inline = false; - let mut f_export = false; let mut program: Vec = Vec::new(); - let mut rtokens = self.program.clone(); + let mut rtokens = self.program.ops.clone(); rtokens.reverse(); while !rtokens.is_empty() { let mut op = rtokens.pop().unwrap(); // println!("{token:?}"); let op_type = op.typ.clone(); match op_type { - OpType::Keyword(KeywordType::Include) => { - if rtokens.is_empty() { - lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human()); - return Err(eyre!("")); - } - - let include_path = rtokens.pop().unwrap(); - - if include_path.tok_typ != TokenType::String { - lerror!(&include_path.loc, "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human()); - return Err(eyre!("")); - } - - let mut in_paths = self.args.include.clone(); - in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::>()); - - let mut include_code = String::new(); - let mut pth = PathBuf::new(); - if include_path.text.chars().next().unwrap() == '.' { - let p = Path::new(include_path.loc.0.as_str()); - let p = p.parent().unwrap(); - let p = p.join(&include_path.text); - pth = p.clone(); - include_code = std::fs::read_to_string(p)?; - } else { - for path in in_paths { - let p = PathBuf::from(path); - let p = p.join(&include_path.text); - pth = p.clone(); - - if p.exists() { - include_code = std::fs::read_to_string(p)?; - break; - } - - } - } - - if include_code.is_empty() { - lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text); - return Err(eyre!("")); - } - let a = pth.to_str().unwrap().to_string(); - let code = lex(&include_code, a.as_str(), self.args); - let mut p = parser::Parser::new(code, self.args, Some(self.clone())); - let mut code = p.parse()?; - - self.set_constants(p.preprocessor.get_constants()); - self.set_functions(p.preprocessor.get_functions()); - self.set_memories(p.preprocessor.get_memories()); - code.reverse(); - rtokens.append(&mut code); - - - } - - OpType::Keyword(KeywordType::Memory) => { - if rtokens.is_empty() { - lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human()); - return Err(eyre!("")); - } - - let name = rtokens.pop().unwrap(); - - self.is_word_available(&name, KeywordType::Memory)?; - - let mut code: Vec = Vec::new(); - - let mut depth = 0; - while !rtokens.is_empty() { - let t = rtokens.pop().unwrap(); - let typ = t.typ.clone(); - if typ == OpType::Keyword(KeywordType::End) && depth == 0 { - break; - } else if typ == OpType::Keyword(KeywordType::End) && depth != 0 { - depth -= 1; - code.push(t); - } else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) { - code.push(t); - depth += 1; - } else { - code.push(t); - } - } - let res = precompile(&code)?; - - - if res.len() != 1 { - lerror!(&op.loc, "Expected 1 number, got {:?}", res); - return Err(eyre!("")); - } - op.value = res[0]; - op.addr = Some(self.memories.len()); - program.push(op.clone()); - - self.memories.insert(name.text, Memory { loc: op.loc, id: self.memories.len() }); - - } - - OpType::Keyword(KeywordType::Function) => { - if rtokens.is_empty() { - lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human()); - return Err(eyre!("")); - } - - let mut name = rtokens.pop().unwrap(); - - if let '0'..='9' = name.text.chars().next().unwrap() { - lerror!(&name.loc, "Function name starts with a number which is not allowed"); - return Err(eyre!("")); - } - - // let mut should_warn = false; - for c in name.text.clone().chars() { - match c { - 'a'..='z' | - 'A'..='Z' | - '0'..='9' | - '-' | '_' => (), - '(' | ')' => { - name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"); - } - _ => { - lerror!(&name.loc, "Function name contains '{c}', which is unsupported"); - return Err(eyre!("")); - } - } - } - // if should_warn { - //TODO: add -W option in cli args to enable more warnings - //lwarn!(&function_name.loc, "Function name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively "); - // } - - self.is_word_available(&name, KeywordType::Function)?; - - - if f_inline { - f_inline = false; - let mut prog: Vec = Vec::new(); - let mut depth = -1; - while !rtokens.is_empty() { - let op = rtokens.pop().unwrap(); - - match op.typ.clone() { - OpType::Instruction(i) => { - match i { - InstructionType::TypeAny | - InstructionType::TypeBool | - InstructionType::TypeInt | - InstructionType::TypePtr | - InstructionType::With | - InstructionType::Returns | - InstructionType::TypeVoid => { - if depth >= 0 { - prog.push(op); - } - }, - _ => prog.push(op) - } - } - OpType::Keyword(k) => { - match k { - KeywordType::Inline | - KeywordType::Include => { - todo!("make error") - }, - KeywordType::FunctionThen => { - if depth >= 0 { - prog.push(op); - } - depth += 1; - }, - KeywordType::FunctionDone => { - if depth == 0 { - break; - } - - depth -= 1; - }, - _ => prog.push(op) - } - } - } - } - let mut pre = self.clone(); - pre.program = prog; - if name.text.chars().next().unwrap() == '.' { - pre.in_function = Some(name.text[1..].to_string()); - } - pre.preprocess()?; - prog = pre.get_ops(); - - self.functions.insert(name.text.clone(), Function{ - loc: name.loc.clone(), - name: name.text.clone(), - inline: true, - tokens: Some(prog) - }); - - } else if f_export { - f_export = false; - self.functions.insert(name.text.clone(), Function{ - loc: name.loc.clone(), - name: name.text.clone(), - inline: false, - tokens: None - }); - let mut a: Vec = Vec::new(); - let mut fn_def = op.clone(); - a.push(rtokens.pop().unwrap()); - let mut ret = false; - while !rtokens.is_empty() { - let op = rtokens.pop().unwrap(); - // println!("{:?}",op); - a.push(op.clone()); - if op.typ == OpType::Instruction(InstructionType::Returns) { - ret = true; - } - - if op.typ == OpType::Keyword(KeywordType::FunctionThen) { - break; - } - - if op.typ == OpType::Instruction(InstructionType::TypeBool) || - op.typ == OpType::Instruction(InstructionType::TypeInt) || - op.typ == OpType::Instruction(InstructionType::TypePtr) { - - if ret { - fn_def.types.1 += 1; - } else { - fn_def.types.0 += 1; - } - } - } - - fn_def.typ = OpType::Keyword(KeywordType::FunctionDefExported); - fn_def.text = name.text; - // fn_def.set_types(args, rets); - // println!("{:?}", fn_def.types); - program.push(fn_def); - program.append(&mut a); - - - } else { - - self.functions.insert(name.text.clone(), Function{ - loc: name.loc.clone(), - name: name.text.clone(), - inline: false, - tokens: None - }); - - let mut fn_def = op.clone(); - fn_def.typ = OpType::Keyword(KeywordType::FunctionDef); - fn_def.text = name.text; - // println!("{:?}", token); - program.push(fn_def); - } - } - - OpType::Keyword(KeywordType::Constant) => { - if rtokens.is_empty() { - lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human()); - return Err(eyre!("")); - } - // println!("{token:?}"); - - let mut name = rtokens.pop().unwrap(); - // let mut should_warn = false; - - - if let '0'..='9' | '.' = name.text.chars().next().unwrap() { - lerror!(&name.loc, "Constant name starts with a number or dot which is not allowed"); - return Err(eyre!("")); - } - - for c in name.text.clone().chars() { - match c { - 'a'..='z' | - 'A'..='Z' | - '0'..='9' | - '-' | '_' => (), - '(' | ')' => { - // should_warn = true; - name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"); - } - _ => { - lerror!(&name.loc, "Constant name contains '{c}', which is unsupported"); - return Err(eyre!("")); - } - } - } - - // if should_warn { - //TODO: add -W option in cli args to enable more warnings - //lwarn!(&name.loc, "Constant name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively "); - // } - - self.is_word_available(&name, KeywordType::Constant)?; - - - self.constants.insert(name.text.clone(), Constant{ - loc: name.loc.clone(), - name: name.text.clone(), - }); - - // println!("{:?}", self.constants); - - let mut const_def = op.clone(); - const_def.typ = OpType::Keyword(KeywordType::ConstantDef); - const_def.text = name.text; - - let item = rtokens.pop().unwrap(); - if item.tok_typ == TokenType::Int { - const_def.value = item.value; - } else { - lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int); - return Err(eyre!("")); - } - - let posibly_end = rtokens.pop(); - // println!("end: {posibly_end:?}"); - if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) { - lerror!(&op.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing"); - return Err(eyre!("")); - } - // token.value = - - program.push(const_def); - } - + OpType::Keyword(KeywordType::Include) => self.handle_include(&mut rtokens, &mut op)?, + OpType::Keyword(KeywordType::Memory) => self.handle_memory(&mut rtokens, &mut op, &mut program)?, + OpType::Keyword(KeywordType::Function) => self.handle_function(&mut rtokens, &mut op, &mut program)?, + OpType::Keyword(KeywordType::Constant) => self.handle_constant(&mut rtokens, &mut op, &mut program)?, + OpType::Keyword(KeywordType::Struct) => self.handle_struct(&mut rtokens, &mut op, &mut program)?, OpType::Keyword(KeywordType::Inline) => { - if f_export { + if self.f_export { lerror!(&op.loc, "Function is already marked as exported, function cannot be inline and exported at the same time"); - return Err(eyre!("")); - } else if f_inline { + bail!(""); + } else if self.f_inline { lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword"); - return Err(eyre!("")); + bail!(""); } else { - f_inline = true; + self.f_inline = true; } } OpType::Keyword(KeywordType::Export) => { if !crate::config::ENABLE_EXPORTED_FUNCTIONS { lerror!(&op.loc, "Experimental feature Exported functions not enabled"); - return Err(eyre!("")); + bail!(""); } - if f_inline { + if self.f_inline { lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and exported at the same time"); - return Err(eyre!("")); - } else if f_export { + bail!(""); + } else if self.f_export { lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword"); - return Err(eyre!("")); + bail!(""); } else { - f_export = true; + self.f_export = true; } } @@ -442,21 +93,27 @@ impl<'a> Preprocessor<'a> { } } } - self.program = program; + self.program.ops = program; // println!("has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::>>()); //* Feel free to fix this horrifying shit //* i wanna kms let mut times = 0; // dbg!(program.clone()); - while self.program.iter().map(|f| { - if f.tok_typ == TokenType::Word && - f.typ != OpType::Instruction(InstructionType::FnCall) && - f.typ != OpType::Instruction(InstructionType::MemUse) && - f.typ != OpType::Keyword(KeywordType::FunctionDef) && - f.typ != OpType::Keyword(KeywordType::FunctionDefExported) && - f.typ != OpType::Keyword(KeywordType::ConstantDef) && - f.typ != OpType::Instruction(InstructionType::ConstUse) { - lookup_word(&f.text, &f.loc) + while self.program.ops.iter().map(|f| { + if f.tok_typ == TokenType::Word { + match f.typ { + OpType::Instruction(InstructionType::FnCall) | + OpType::Instruction(InstructionType::MemUse) | + OpType::Instruction(InstructionType::StructUse) | + OpType::Keyword(KeywordType::FunctionDef) | + OpType::Keyword(KeywordType::FunctionDefExported)| + OpType::Keyword(KeywordType::ConstantDef) | + OpType::Internal(InternalType::StructAlloc{..}) | + OpType::Instruction(InstructionType::ConstUse) => OpType::Instruction(InstructionType::PushInt), + _ => { + lookup_word(&f.text, &f.loc) + } + } } else { OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works } @@ -473,21 +130,455 @@ impl<'a> Preprocessor<'a> { Ok(self) } + + fn handle_include(&mut self, rtokens: &mut Vec, op: &mut Operator) -> Result<()> { + if rtokens.is_empty() { + lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human()); + bail!(""); + } + + let include_path = rtokens.pop().unwrap(); + + if include_path.tok_typ != TokenType::String { + lerror!(&include_path.loc, "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human()); + bail!(""); + } + + let mut in_paths = self.args.include.clone(); + in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::>()); + + let mut include_code = String::new(); + let mut pth = PathBuf::new(); + if include_path.text.chars().next().unwrap() == '.' { + let p = Path::new(include_path.loc.0.as_str()); + let p = p.parent().unwrap(); + let p = p.join(&include_path.text); + pth = p.clone(); + include_code = std::fs::read_to_string(p)?; + } else { + for path in in_paths { + let p = PathBuf::from(path); + let p = p.join(&include_path.text); + pth = p.clone(); + + if p.exists() { + include_code = std::fs::read_to_string(p)?; + break; + } + + } + } + + if include_code.is_empty() { + lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text); + bail!(""); + } + let a = pth.to_str().unwrap().to_string(); + let code = lex(&include_code, a.as_str(), self.args); + let mut p = parser::Parser::new(code, self.args, Some(self.clone())); + let mut code = p.parse()?; + + self.set_constants(p.preprocessor.get_constants()); + self.set_functions(p.preprocessor.get_functions()); + self.set_memories(p.preprocessor.get_memories()); + code.ops.reverse(); + rtokens.append(&mut code.ops); + Ok(()) + } + + fn handle_memory(&mut self, rtokens: &mut Vec, op: &mut Operator, program: &mut Vec) -> Result<()> { + if rtokens.is_empty() { + lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human()); + bail!(""); + } + + let name = rtokens.pop().unwrap(); + + self.is_word_available(&name, KeywordType::Memory)?; + + let mut code: Vec = Vec::new(); + + let mut depth = 0; + while !rtokens.is_empty() { + let t = rtokens.pop().unwrap(); + let typ = t.typ.clone(); + if typ == OpType::Keyword(KeywordType::End) && depth == 0 { + break; + } else if typ == OpType::Keyword(KeywordType::End) && depth != 0 { + depth -= 1; + code.push(t); + } else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) { + code.push(t); + depth += 1; + } else { + code.push(t); + } + } + let res = precompile(&code)?; + + + if res.len() != 1 { + lerror!(&op.loc, "Expected 1 number, got {:?}", res); + bail!(""); + } + op.value = res[0]; + op.addr = Some(self.program.memories.len()); + program.push(op.clone()); + + self.program.memories.insert(name.text, Memory { loc: op.loc.clone(), id: self.program.memories.len() }); + Ok(()) + } + + fn handle_function(&mut self, rtokens: &mut Vec, op: &mut Operator, program: &mut Vec) -> Result<()> { + if rtokens.is_empty() { + lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human()); + bail!(""); + } + + let mut name = rtokens.pop().unwrap(); + + if let '0'..='9' = name.text.chars().next().unwrap() { + lerror!(&name.loc, "Function name starts with a number which is not allowed"); + bail!(""); + } + + // let mut should_warn = false; + for c in name.text.clone().chars() { + match c { + 'a'..='z' | + 'A'..='Z' | + '0'..='9' | + '-' | '_' => (), + '(' | ')' => { + name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"); + } + _ => { + lerror!(&name.loc, "Function name contains '{c}', which is unsupported"); + bail!(""); + } + } + } + // if should_warn { + //TODO: add -W option in cli args to enable more warnings + //lwarn!(&function_name.loc, "Function name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively "); + // } + + self.is_word_available(&name, KeywordType::Function)?; + + + if self.f_inline { + self.f_inline = false; + let mut prog: Vec = Vec::new(); + let mut depth = -1; + while !rtokens.is_empty() { + let op = rtokens.pop().unwrap(); + + match op.typ.clone() { + OpType::Instruction(i) => { + match i { + InstructionType::TypeAny | + InstructionType::TypeBool | + InstructionType::TypeInt | + InstructionType::TypePtr | + InstructionType::With | + InstructionType::Returns | + InstructionType::TypeVoid => { + if depth >= 0 { + prog.push(op); + } + }, + _ => prog.push(op) + } + } + OpType::Keyword(k) => { + match k { + KeywordType::Inline | + KeywordType::Include => { + todo!("make error") + }, + KeywordType::FunctionThen => { + if depth >= 0 { + prog.push(op); + } + depth += 1; + }, + KeywordType::FunctionDone => { + if depth == 0 { + break; + } + + depth -= 1; + }, + _ => prog.push(op) + } + } + _ => prog.push(op) + } + } + let mut pre = self.clone(); + pre.program.ops = prog; + if name.text.chars().next().unwrap() == '.' { + pre.in_function = Some(name.text[1..].to_string()); + } + pre.preprocess()?; + prog = pre.get_ops(); + + self.program.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: true, + tokens: Some(prog) + }); + + } else if self.f_export { + self.f_export = false; + self.program.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: false, + tokens: None + }); + let mut a: Vec = Vec::new(); + let mut fn_def = op.clone(); + a.push(rtokens.pop().unwrap()); + let mut ret = false; + while !rtokens.is_empty() { + let op = rtokens.pop().unwrap(); + // println!("{:?}",op); + a.push(op.clone()); + if op.typ == OpType::Instruction(InstructionType::Returns) { + ret = true; + } + + if op.typ == OpType::Keyword(KeywordType::FunctionThen) { + break; + } + + if op.typ == OpType::Instruction(InstructionType::TypeBool) || + op.typ == OpType::Instruction(InstructionType::TypeInt) || + op.typ == OpType::Instruction(InstructionType::TypePtr) { + + if ret { + fn_def.types.1 += 1; + } else { + fn_def.types.0 += 1; + } + } + } + + fn_def.typ = OpType::Keyword(KeywordType::FunctionDefExported); + fn_def.text = name.text; + // fn_def.set_types(args, rets); + // println!("{:?}", fn_def.types); + program.push(fn_def); + program.append(&mut a); + + + } else { + + self.program.functions.insert(name.text.clone(), Function{ + loc: name.loc.clone(), + name: name.text.clone(), + inline: false, + tokens: None + }); + + let mut fn_def = op.clone(); + fn_def.typ = OpType::Keyword(KeywordType::FunctionDef); + fn_def.text = name.text; + // println!("{:?}", token); + program.push(fn_def); + } + Ok(()) + } + + fn handle_constant(&mut self, rtokens: &mut Vec, op: &mut Operator, program: &mut Vec) -> Result<()> { + let Some(mut name) = rtokens.pop() else { + lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human()); + bail!(""); + }; + + + if let '0'..='9' | '.' = name.text.chars().next().unwrap() { + lerror!(&name.loc, "Constant name starts with a number or dot which is not allowed"); + bail!(""); + } + + for c in name.text.clone().chars() { + match c { + 'a'..='z' | + 'A'..='Z' | + '0'..='9' | + '-' | '_' => (), + '(' | ')' => { + // should_warn = true; + name.text = name.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"); + } + _ => { + lerror!(&name.loc, "Constant name contains '{c}', which is unsupported"); + bail!(""); + } + } + } + + // if should_warn { + //TODO: add -W option in cli args to enable more warnings + //lwarn!(&name.loc, "Constant name contains '(' or ')', this character is not supported but will be replaced with '__OP_PAREN__' or '__CL_PAREN__' respectively "); + // } + + self.is_word_available(&name, KeywordType::Constant)?; + + + self.program.constants.insert(name.text.clone(), Constant{ + loc: name.loc.clone(), + name: name.text.clone(), + }); + + // println!("{:?}", self.program.constants); + + let mut const_def = op.clone(); + const_def.typ = OpType::Keyword(KeywordType::ConstantDef); + const_def.text = name.text; + + let item = rtokens.pop().unwrap(); + if item.tok_typ == TokenType::Int { + const_def.value = item.value; + } else { + lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int); + bail!(""); + } + + let posibly_end = rtokens.pop(); + // println!("end: {posibly_end:?}"); + if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) { + lerror!(&op.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing"); + bail!(""); + } + // token.value = + + program.push(const_def); + Ok(()) + } + + fn handle_struct(&mut self, rtokens: &mut Vec, op: &mut Operator, program: &mut Vec) -> Result<()> { + let Some(name) = rtokens.pop() else { + lerror!(&op.loc, "Struct name not found, expected {} but found nothing", TokenType::Word.human()); + bail!(""); + }; + + if let '0'..='9' | '.' = name.text.chars().next().unwrap() { + lerror!(&name.loc, "Struct name starts with a number or dot which is not allowed"); + bail!(""); + } + + self.is_word_available(&name, KeywordType::Struct)?; + + if let Some(kw_do) = rtokens.pop() { + if kw_do.typ != OpType::Keyword(KeywordType::Do) { + lerror!(&name.loc, "Expected keyword 'do' but found {:?}", kw_do.typ); + bail!(""); + } + } else { + lerror!(&name.loc, "Expected keyword 'do' but found nothing"); + bail!(""); + } + + let mut structure = StructDef{ + loc: name.loc, + name: name.text, + fields: vec![], + }; + + loop { + let fl_name = rtokens.pop().unwrap(); + + if fl_name.typ == OpType::Keyword(KeywordType::End) { + break; + } + + if let '0'..='9' = fl_name.text.chars().next().unwrap() { + lerror!(&fl_name.loc, "Struct field name starts with a number which is not allowed"); + bail!(""); + } + + // let mut should_warn = false; + for c in fl_name.text.clone().chars() { + match c { + 'a'..='z' | + 'A'..='Z' | + '0'..='9' | + '_' => (), + _ => { + lerror!(&fl_name.loc, "Struct field name contains '{c}', which is unsupported"); + bail!(""); + } + } + } + + if let Some(arrow) = rtokens.pop() { + if arrow.typ != OpType::Internal(InternalType::Arrow) { + lerror!(&arrow.loc, "Expected '->' but found {:?}", arrow.typ); + bail!(""); + } + } else { + lerror!(&fl_name.loc, "Expected '->' but found nothing"); + bail!(""); + } + + + let Some(typ) = rtokens.pop() else { + lerror!(&fl_name.loc, "Expected a type but found nothing"); + bail!(""); + }; + + let Ok(typ) = Types::from_string(&typ.text) else { + lerror!(&typ.loc, "Expected a type but found {:?}", typ.text); + bail!(""); + }; + + structure.fields.push((fl_name.text, typ)); + + } + + self.program.struct_defs.insert(structure.name.clone(), structure.clone()); + + if let Some(def_name) = rtokens.pop() { + if def_name.typ == OpType::Instruction(InstructionType::None){ + let mut def = def_name.clone(); + + def.typ = OpType::Internal(InternalType::StructAlloc { + name: structure.name.clone() + }); + self.program.struct_allocs.insert(def_name.text, structure.name); + program.push(def); + + } else { + rtokens.push(def_name); + } + } + + + Ok(()) + } + pub fn expand(&mut self) -> Result<()> { let mut program: Vec = Vec::new(); - // println!("{:?}", self.functions); - let mut rtokens = self.program.clone(); + // println!("{:?}", self.program.functions); + let mut rtokens = self.program.ops.clone(); rtokens.reverse(); - while !rtokens.is_empty() { + 'main_loop: while !rtokens.is_empty() { let op = rtokens.pop().unwrap(); let op_type = op.typ.clone(); if op.tok_typ == TokenType::Word { match op_type { OpType::Instruction(InstructionType::None) => { - let m = self.functions.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); - let mem = self.memories.get(&op.text); - let cons = self.constants.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); + let m = self.program.functions.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); + let mem = self.program.memories.get(&op.text); + let cons = self.program.constants.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__")); + + + if let Some(m) = m { if m.inline { program.append(&mut m.tokens.clone().unwrap()); @@ -501,18 +592,33 @@ impl<'a> Preprocessor<'a> { // println!("##### {:?}", t); } else if let Some(mem) = mem { let mut t = op.clone(); - t.addr = Some(mem.deref().id); + t.addr = Some(mem.id); t.typ = OpType::Instruction(InstructionType::MemUse); program.push(t); } else if let Some(cons) = cons { let mut t = op.clone(); - t.text = cons.deref().name.clone(); + t.text = cons.name.clone(); t.typ = OpType::Instruction(InstructionType::ConstUse); program.push(t); - } else { + let mut t = op.clone(); + let parts = op.text.split('.').map(|f| f.to_string()).collect::>(); + let alc = self.program.struct_allocs.get(&parts[0]); + if let Some(alc) = alc { + if let Some(def) = self.program.struct_defs.get(alc) { + // if def.fields.iter().for_each(|f| f.0 == parts[1]) + println!("{:?}", def.fields); + if def.fields.iter().find(|f| f.0 == parts[1]).is_some() || parts.len() < 2{ + t.typ = OpType::Instruction(InstructionType::StructUse); + program.push(t); + continue 'main_loop; + } + } + } + + lerror!(&op.loc, "Preprocess: Unknown word '{}'", op.text.clone()); - return Err(eyre!("")); + bail!(""); } } _ => { @@ -531,7 +637,7 @@ impl<'a> Preprocessor<'a> { } // println!("expand: has do tokens: {:?}", program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::>>()); - self.program = program; + self.program.ops = program; // println!("{:#?}", self.program); // println!("{:?}", self.program.last().unwrap()); Ok(()) @@ -540,13 +646,14 @@ impl<'a> Preprocessor<'a> { pub fn get_ops(&mut self) -> Vec { - self.program.clone() + self.program.ops.clone() } pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result { match typ { KeywordType::Memory | KeywordType::Constant | + KeywordType::Struct | KeywordType::Function => (), _ => panic!() } @@ -554,76 +661,94 @@ impl<'a> Preprocessor<'a> { if word.tok_typ != TokenType::Word { lerror!(&word.loc, "Bad {typ:?}, expected {} but found {}", TokenType::Word.human(), word.typ.human()); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } let w = lookup_word(&word.text, &word.loc); if w != OpType::Instruction(InstructionType::None) { lerror!(&word.loc, "Bad {typ:?}, {typ:?} definition cannot be builtin word, got {:?}", word.text); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } - let m = self.memories.get(&word.text); + let m = self.program.memories.get(&word.text); if let Some(m) = m { if typ == KeywordType::Memory { lerror!(&word.loc, "Memories cannot be redefined, got {}", word.text); linfo!(&m.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } lerror!(&word.loc, "{typ:?} cannot replace memory, got {}", word.text); linfo!(&m.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } - let f = self.functions.get(&word.text); + let f = self.program.functions.get(&word.text); if let Some(f) = f { if typ == KeywordType::Function { lerror!(&word.loc, "Functions cannot be redefined, got {}", word.text); linfo!(&f.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } lerror!(&word.loc, "{typ:?} cannot replace function, got {}", word.text); linfo!(&f.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } - let c = self.constants.get(&word.text); + let c = self.program.constants.get(&word.text); if let Some(c) = c { if typ == KeywordType::Constant { lerror!(&word.loc, "Constants cannot be redefined, got {}", word.text); linfo!(&c.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); } lerror!(&word.loc, "{typ:?} cannot replace constant, got {}", word.text); linfo!(&c.loc, "first definition here"); if crate::DEV_MODE {println!("{word:?}")} - return Err(eyre!("")); + bail!(""); + } + + let s = self.program.struct_defs.get(&word.text); + if let Some(s) = s { + if typ == KeywordType::Constant { + lerror!(&word.loc, "Structs cannot be redefined, got {}", word.text); + linfo!(&s.loc, "first definition here"); + if crate::DEV_MODE {println!("{word:?}")} + bail!(""); + } + lerror!(&word.loc, "{typ:?} cannot replace struct, got {}", word.text); + linfo!(&s.loc, "first definition here"); + if crate::DEV_MODE {println!("{word:?}")} + bail!(""); } Ok(true) } pub fn set_functions(&mut self, f: Functions) { - self.functions = f; + self.program.functions = f; } pub fn set_constants(&mut self, f: Constants) { - self.constants = f; + self.program.constants = f; } pub fn set_memories(&mut self, f: Memories) { - self.memories = f; + self.program.memories = f; } pub fn get_functions(&mut self) -> Functions { - self.functions.clone() + self.program.functions.clone() } pub fn get_constants(&mut self) -> Constants { - self.constants.clone() + self.program.constants.clone() } pub fn get_memories(&mut self) -> Memories{ - self.memories.clone() + self.program.memories.clone() + } + + pub fn get_program(&mut self) -> Program { + self.program.clone() } } \ No newline at end of file diff --git a/src/typechecker.rs b/src/typechecker.rs index a7ca095..6a2482b 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1,8 +1,7 @@ use std::collections::HashMap; -use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType, Loc}, Args, lerror, warn}; -use color_eyre::Result; -use eyre::eyre; +use crate::{definitions::{Operator, Types, OpType, KeywordType, InstructionType, Loc}, Args, lerror, warn}; +use anyhow::{Result, bail}; #[allow(dead_code)] #[derive(Debug, Clone)] @@ -69,12 +68,12 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> if let Some(p) = rtokens.pop() { if p.typ != OpType::Instruction(InstructionType::With){ lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ); - return Err(eyre!("")); + bail!(""); } } else { lerror!(&op.loc, "Expected {:?}, got nothing", OpType::Instruction(InstructionType::With)); - return Err(eyre!("")); + bail!(""); } let mut p = rtokens.pop(); @@ -92,7 +91,7 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> op.typ == OpType::Instruction(InstructionType::TypeAny) || op.typ == OpType::Instruction(InstructionType::TypeVoid) { let t = if op.typ == OpType::Instruction(InstructionType::TypeInt) { - Types::Int + Types::U64 } else if op.typ == OpType::Instruction(InstructionType::TypeBool) { Types::Bool } else if op.typ == OpType::Instruction(InstructionType::TypePtr) { @@ -153,7 +152,7 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> let (ret_typs, _, _) = typecheck(code, args, Some(ts.clone()), functions.clone(), constants.clone())?; if ret_typs != func.returns && !func.returns.contains(&Types::Void){ lerror!(&func.loc, "Expected {:?}, but got {:?}", func.returns, ret_typs); - return Err(eyre!("")) + bail!(""); } if !func.args.contains(&Types::Void) { @@ -170,7 +169,7 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> KeywordType::Memory => (), KeywordType::ConstantDef => { // println!("defined constant"); - constants.insert(op.text, Constant { loc: op.loc.clone(), types: vec![Types::Int] }); + constants.insert(op.text, Constant { loc: op.loc.clone(), types: vec![Types::U64] }); }, KeywordType::FunctionThen | @@ -181,26 +180,27 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> println!("{:?}", op); unreachable!() }, + KeywordType::Struct => todo!(), } }, OpType::Instruction(instruction) => { match instruction { InstructionType::PushInt => { - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::PushStr => { - stack.push(Types::Int); + stack.push(Types::U64); stack.push(Types::Ptr); }, InstructionType::PushCStr => { - stack.push(Types::Int); + stack.push(Types::U64); stack.push(Types::Ptr); }, InstructionType::Drop => { stack_pop(&mut stack, &op, &[Types::Any])?; }, InstructionType::Print => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; }, InstructionType::Dup => { let a = stack_pop(&mut stack, &op, &[Types::Any])?; @@ -234,9 +234,9 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> InstructionType::Shr | InstructionType::Shl | InstructionType::Mul => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack_pop(&mut stack, &op, &[Types::Int])?; - stack.push(Types::Int); + stack_pop(&mut stack, &op, &[Types::U64])?; + stack_pop(&mut stack, &op, &[Types::U64])?; + stack.push(Types::U64); }, InstructionType::Equals | InstructionType::Gt | @@ -244,76 +244,76 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> InstructionType::Ge | InstructionType::Le | InstructionType::NotEquals => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack.push(Types::Bool); }, InstructionType::DivMod => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack_pop(&mut stack, &op, &[Types::Int])?; - stack.push(Types::Int); - stack.push(Types::Int); + stack_pop(&mut stack, &op, &[Types::U64])?; + stack_pop(&mut stack, &op, &[Types::U64])?; + stack.push(Types::U64); + stack.push(Types::U64); }, - InstructionType::Load8 | - InstructionType::Load32 | - InstructionType::Load64 => { + InstructionType::Read8 | + InstructionType::Read32 | + InstructionType::Read64 => { stack_pop(&mut stack, &op, &[Types::Ptr])?; - stack.push(Types::Int); + stack.push(Types::U64); }, - InstructionType::Store8 | - InstructionType::Store32 | - InstructionType::Store64 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + InstructionType::Write8 | + InstructionType::Write32 | + InstructionType::Write64 => { + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Ptr])?; }, InstructionType::Syscall0 => { - stack_pop(&mut stack, &op, &[Types::Int])?; - stack.push(Types::Int); + stack_pop(&mut stack, &op, &[Types::U64])?; + stack.push(Types::U64); }, InstructionType::Syscall1 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::Syscall2 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::Syscall3 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::Syscall4 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::Syscall5 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::Syscall6 => { - stack_pop(&mut stack, &op, &[Types::Int])?; + stack_pop(&mut stack, &op, &[Types::U64])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::CastBool => { stack_pop(&mut stack, &op, &[Types::Any])?; @@ -325,7 +325,7 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> }, InstructionType::CastInt => { stack_pop(&mut stack, &op, &[Types::Any])?; - stack.push(Types::Int); + stack.push(Types::U64); }, InstructionType::CastVoid => { stack_pop(&mut stack, &op, &[Types::Any])?; @@ -339,7 +339,7 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> let f = if let Some(f) = functions.get(&op.text) {f} else { lerror!(&op.loc, "Could not find function {}", op.text); - return Err(eyre!("")); + bail!(""); }; // in_function = (op.text.clone(), f.clone(), op.loc.clone()); @@ -353,11 +353,11 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> if let Some(s2) = s.pop(){ if t != s2 { lerror!(&op.loc, "Expected {:?}, but got {:?}", t, s2); - return Err(eyre!("")); + bail!(""); } } else { lerror!(&op.loc, "Expected {:?}, but got nothing", t); - return Err(eyre!("")); + bail!(""); } } @@ -377,8 +377,10 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> let mut c = constants.get(&op.text).unwrap().clone(); stack.append(&mut c.types); }, + InstructionType::StructUse => todo!(), } }, + OpType::Internal(t) => panic!("{t:?}"), } @@ -393,13 +395,13 @@ pub fn typecheck(ops: Vec, args: &Args, init_types: Option> fn stack_pop(v: &mut Vec, op: &Operator, t: &[Types]) -> Result { if v.is_empty() { lerror!(&op.loc, "Expected {:?}, but got nothing", t); - return Err(eyre!("")); + bail!(""); } let r = v.pop().unwrap(); if !t.contains(&r) && t[0] != Types::Any { lerror!(&op.loc, "Expected {:?}, but got {:?}", t, r); - return Err(eyre!("")); + bail!(""); } Ok(r) diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..5c38914 --- /dev/null +++ b/src/types.rs @@ -0,0 +1,392 @@ +use std::collections::{HashMap, HashSet}; + +use eyre::bail; + + + + +#[derive(Debug, Clone, PartialEq)] +pub enum InstructionType { + + // stack + PushInt, + PushStr, + PushCStr, + 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, + + // typing + TypeBool, + TypePtr, + TypeInt, + TypeVoid, + // TypeStr, + TypeAny, + Returns, + With, + + FnCall, + MemUse, + ConstUse, + + Return, + None // Used for macros and any other non built in word definitions + +} +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum KeywordType { + If, + Else, + End, + While, + Do, + Include, + Memory, + Constant, + ConstantDef, + Function, + FunctionDef, + FunctionDefExported, + FunctionThen, + FunctionDone, + Inline, + Export, + Struct, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum InternalType { + Arrow +} +#[derive(Debug, Clone, PartialEq)] +pub enum OpType { + Keyword(KeywordType), + Instruction(InstructionType), + Internal(InternalType) +} + +#[derive(Debug, Clone)] +pub struct Operator{ + pub typ: OpType, + pub tok_typ: TokenType, + pub value: usize, + pub text: String, //? only used for OpType::PushStr + pub addr: Option, //? only used for OpType::PushStr + pub jmp: usize, + pub loc: Loc, + pub types: (usize, usize) +} + +impl Operator { + pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self { + Self { + typ, + value, + jmp: 0, + addr: None, + text, + loc: (file, row, col), + tok_typ, + types: (0, 0) + } + } + pub fn set_addr(&mut self, addr: usize) -> Self { + self.addr = Some(addr); + (*self).clone() + } + + // pub fn set_types(&mut self, args: usize, rets: usize) -> Self { + // self.types = (args, rets); + // (*self).clone() + // } + +} + +impl OpType { + pub fn human(&self) -> String { + match (*self).clone() { + OpType::Instruction(instruction) => { + match instruction { + + InstructionType::PushInt => "Number", + InstructionType::PushStr => "String", + InstructionType::PushCStr => "CString", + InstructionType::Print => "_dbg_print", + InstructionType::Dup => "dup", + InstructionType::Drop => "drop", + InstructionType::Rot => "rot", + InstructionType::Over => "over", + InstructionType::Swap => "swap", + InstructionType::Plus => "+", + InstructionType::Minus => "-", + InstructionType::Equals => "=", + InstructionType::Gt => ">", + InstructionType::Lt => "<", + InstructionType::NotEquals => "!=", + InstructionType::Le => "<=", + InstructionType::Ge => ">=", + InstructionType::Band => "band", + InstructionType::Bor => "bor", + InstructionType::Shr => "shr", + InstructionType::Shl => "shl", + InstructionType::DivMod => "divmod", + InstructionType::Mul => "*", + InstructionType::Read8 => "read8", + InstructionType::Write8 => "write8", + InstructionType::Read32 => "read32", + InstructionType::Write32 => "write32", + InstructionType::Read64 => "read64", + InstructionType::Write64 => "write64", + InstructionType::Syscall0 => "syscall0", + InstructionType::Syscall1 => "syscall1", + InstructionType::Syscall2 => "syscall2", + InstructionType::Syscall3 => "syscall3", + InstructionType::Syscall4 => "syscall4", + InstructionType::Syscall5 => "syscall5", + InstructionType::Syscall6 => "syscall6", + InstructionType::CastBool => "cast(bool", + InstructionType::CastPtr => "cast(ptr)", + InstructionType::CastInt => "cast(int)", + InstructionType::CastVoid => "cast(void)", + InstructionType::None => "None", + InstructionType::MemUse => "Memory use (internal)", + InstructionType::FnCall => "Function Call (Internal)", + InstructionType::ConstUse => "Constant Use (Internal)", + InstructionType::Return => "return", + InstructionType::TypeBool => "bool", + InstructionType::TypePtr => "ptr", + InstructionType::TypeInt => "int", + InstructionType::TypeVoid => "void", + InstructionType::Returns => "returns", + InstructionType::With => "with", + InstructionType::TypeAny => "any", + } + } + OpType::Keyword(keyword) => { + match keyword { + KeywordType::If => "if", + KeywordType::Else => "else", + KeywordType::End => "end", + KeywordType::While => "while", + KeywordType::Do => "do", + KeywordType::Include => "include", + KeywordType::Memory => "memory", + KeywordType::Function => "fn", + KeywordType::Constant => "const", + KeywordType::FunctionThen => "then", + KeywordType::FunctionDone => "done", + KeywordType::ConstantDef => "constant Definition (internal)", + KeywordType::FunctionDef => "function definition (internal)", + KeywordType::FunctionDefExported => "extern function definition (internal)", + KeywordType::Inline => "inline", + KeywordType::Export => "export", + KeywordType::Struct => "struct", + } + } + OpType::Internal(t) => panic!("{t:?}"), + + }.to_string() + } +} + +#[derive(Debug, Clone)] +pub struct Token { + pub file: String, + pub line: usize, + pub col: usize, + pub text: String, + pub typ: TokenType, + pub value: Option, //* only used for Memories + pub addr: Option, //* only used for Memories + pub op_typ: OpType //* only used for Memories +} + +#[derive(Debug, Clone, PartialEq, Copy)] +pub enum TokenType { + Word, + Int, + String, + CString, + Char +} + +impl Token { + pub fn loc(&self) -> Loc { + ( + self.file.clone(), + self.line, + self.col + ) + } +} + +impl TokenType { + pub fn human(self) -> String { + match self { + TokenType::Word => "Word", + TokenType::Int => "Int", + TokenType::String => "String", + TokenType::CString => "CString", + TokenType::Char => "Char" + }.to_string() + } +} + +pub type Loc = (String, usize, usize); + +#[derive(Debug, PartialEq, Clone)] +pub enum Types { + Any, + Bool, + Ptr, + Void, + U8, + U16, + U32, + U64, + I8, + I16, + I32, + I64, + Custom{ + size: u64 // in bytes + }, + // todo: add signed numbers since we dont have them yet lol +} + +impl Types { + pub fn get_size(&self) -> u64 { + match *self { + Types::Any => 0, // any cant be a known size + Types::Void => 0, + Types::Bool => 1, + Types::U8 | + Types::I8 => 1, + Types::U16 | + Types::I16 => 2, + Types::U32 | + Types::I32 => 4, + Types::Ptr | + Types::U64 | + Types::I64 => 8, + Types::Custom { size } => size, + } + } +} + +impl TryInto for &str { + type Error = color_eyre::eyre::Error; + + fn try_into(self) -> Result { + match self { + "Any" => Ok(Types::Any), + "Void" => Ok(Types::Void), + "Bool" => Ok(Types::Bool), + "U8" => Ok(Types::U8), + "I8" => Ok(Types::I8), + "U16" => Ok(Types::U16), + "I16" => Ok(Types::I16), + "U32" => Ok(Types::U32), + "I32" => Ok(Types::I32), + "Ptr" => Ok(Types::Ptr), + "U64" => Ok(Types::U64), + "I64" => Ok(Types::I64), + _ => bail!("Unknown type {self}") + } + } +} + +impl TryInto for String { + type Error = color_eyre::eyre::Error; + + fn try_into(self) -> Result { + self.into() + } +} + + + +#[derive(Debug, Clone)] +pub struct Function { + pub loc: Loc, + pub name: String, + pub inline: bool, + pub tokens: Option> +} + +#[derive(Debug, Clone)] +pub struct Constant { + pub loc: Loc, + pub name: String +} + +#[derive(Debug, Clone)] +pub struct Memory { + pub loc: Loc, + pub id: usize + +} + +#[derive(Debug, Clone)] +pub struct StructDef { + pub loc: Loc, + pub name: String, + pub fields: HashSet<(String, Types)> +} + +pub type Functions = HashMap; +pub type Memories = HashMap; +pub type Constants = HashMap; +pub type StructDefs = HashMap; + +#[derive(Debug, Clone)] +pub struct Program { + pub ops: Vec, + pub functions: Functions, + pub memories: Memories, + pub constants: Constants, + pub struct_defs: StructDefs +} diff --git a/src/types/common/loc.rs b/src/types/common/loc.rs new file mode 100644 index 0000000..9106b4e --- /dev/null +++ b/src/types/common/loc.rs @@ -0,0 +1,29 @@ + + +pub struct Loc { + pub ln: usize, + pub col: usize, + pub file: String +} + +impl Loc { + pub fn new(file: String, ln: usize, col: usize) -> Self { + Self { + ln, + col, + file, + } + } +} + +impl ToString for Loc { + fn to_string(&self) -> String { + format!("{}:{}:{}", self.file, self.ln, self.col) + } +} + +impl Into for Loc { + fn into(self) -> String { + self.to_string() + } +} \ No newline at end of file diff --git a/src/types/common/mod.rs b/src/types/common/mod.rs new file mode 100644 index 0000000..2fda988 --- /dev/null +++ b/src/types/common/mod.rs @@ -0,0 +1,4 @@ +mod loc; + + +pub use loc::*; \ No newline at end of file diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..7c66537 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,4 @@ + + +pub mod common; +pub mod token; \ No newline at end of file diff --git a/src/types/token.rs b/src/types/token.rs new file mode 100644 index 0000000..8c52760 --- /dev/null +++ b/src/types/token.rs @@ -0,0 +1,65 @@ +use super::common::Loc; + + + + +struct Token { + loc: Loc, + typ: TokenType, + val: TokenValue +} + +pub enum TokenValue { + Int(usize), + Str(String) +} + +pub enum TokenType { + DbgPrint, + Keyword(TokenKeyword), + Syscall(u8), + + //? Literal + PushInt, + PushStr, + + //? Stack manipulation + Dup, + Rot, // a b c => b c a + Over, // a b => a b a + Swap, // a b => b a + + //? Math + Plus, + Minus, + Mul, + Div, + Mod, + + //? Logical + And, + Or, + Eq, + Gt, + Lt, + Ge, + Le, + Ne, + + //? Bitwise + Shr, + Shl, + Bor, + Band, +} + +pub enum TokenKeyword { + Function, + If, + Else, + End, + Done, + Macro, + While, + Do +} \ No newline at end of file diff --git a/src/util.rs b/src/util.rs index 15b41ac..43ab584 100644 --- a/src/util.rs +++ b/src/util.rs @@ -32,7 +32,7 @@ pub mod logger { #![allow(dead_code)] use std::ops::Deref; - use crate::{util::color, constants::Loc}; + use crate::{util::color, definitions::Loc}; pub fn error(msg: &str) { println!("{red}error{r}: {msg}", red=color::FG_RED, r=color::RESET); diff --git a/test.mcl b/test.mcl index a96f8fe..bcbd7fa 100644 --- a/test.mcl +++ b/test.mcl @@ -1,7 +1,13 @@ include "std.mcl" + fn main with int ptr returns void then // p l - c"bad, wait no, good\n\0" dup cstr_len swap puts + "Hello!\n" puts + // memory fd 4 end + + // c"./test.mcl" FS_O_SYNC 0 fopen + // dup _dbg_print + // fd swap write32 done \ No newline at end of file diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 0000000..73bda96 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,4 @@ +/* +!/.gitignore +!/*.c +!/build_tools.sh \ No newline at end of file diff --git a/tools/build_tools.sh b/tools/build_tools.sh new file mode 100644 index 0000000..2edcd42 --- /dev/null +++ b/tools/build_tools.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +gcc intcnv.c -o intcnv \ No newline at end of file diff --git a/tools/intcnv.c b/tools/intcnv.c new file mode 100644 index 0000000..9e8e469 --- /dev/null +++ b/tools/intcnv.c @@ -0,0 +1,47 @@ +#include +#include +#include + +int main(int argc, char** argv) { + if (argc < 3) { + printf("Usage: intcnv i32 134\n"); + return 1; + } + + const char* typ = argv[1]; + __uint64_t num = atoi(argv[2]); + + if (strcmp(typ, "u8") == 0) { + __uint8_t num2 = (__uint8_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "i8") == 0) { + __int8_t num2 = (__int8_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "u16") == 0) { + __uint16_t num2 = (__uint16_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "i16") == 0) { + __int16_t num2 = (__int16_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "u32") == 0) { + __uint32_t num2 = (__uint32_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "i32") == 0) { + __int32_t num2 = (__int32_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "u64") == 0) { + __uint64_t num2 = (__uint64_t)num; + printf("%d\n", num2); + } + if (strcmp(typ, "i64") == 0) { + __int64_t num2 = (__int64_t)num; + printf("%d\n", num2); + } + +} \ No newline at end of file