diff --git a/examples/hello_world.mcl b/examples/hello_world.mcl index b206a6d..a7fef71 100644 --- a/examples/hello_world.mcl +++ b/examples/hello_world.mcl @@ -1,18 +1,4 @@ +include "std.mcl" -mem dup 72 @8 -1 + dup 101 @8 -1 + dup 110 @8 -1 + dup 108 @8 -1 + dup 111 @8 -1 + dup 32 @8 -1 + dup 119 @8 -1 + dup 111 @8 -1 + dup 114 @8 -1 + dup 108 @8 -1 + dup 100 @8 -1 + dup 33 @8 -1 + dup 10 @8 -1 + - -mem - mem 1 1 syscall3 +"Henlo World! :3\n" puts diff --git a/examples/rule110.mcl b/examples/rule110.mcl index 4cec46f..916e49d 100755 --- a/examples/rule110.mcl +++ b/examples/rule110.mcl @@ -1,4 +1,4 @@ -include "io.mcl" +include "std.mcl" macro BOARD_SIZE 100 end diff --git a/include/fs.mcl b/include/fs.mcl new file mode 100644 index 0000000..2060661 --- /dev/null +++ b/include/fs.mcl @@ -0,0 +1,19 @@ + +macro FS_O_APPEND 1024 end // append to existing file +macro FS_O_ASYNC 8192 end // use signal-driven IO +macro FS_O_CLOEXEC 524288 end // use close-on-exec (avoid race conditions and lock contentions) +macro FS_O_CREAT 64 end // create file if it doesn’t exist +macro FS_O_DIRECT 16384 end // bypass cache (slower) +macro FS_O_DIRECTORY 65536 end // fail if pathname isn’t a directory +macro FS_O_DSYNC 4096 end // ensure output is sent to hardware and metadata written before return +macro FS_O_EXCL 128 end // ensure creation of file +macro FS_O_LARGEFILE 0 end // allows use of file sizes represented by off64_t +macro FS_O_NOATIME 262144 end // do not increment access time upon open +macro FS_O_NOCTTY 256 end // if pathname is a terminal device, don’t become controlling terminal +macro FS_O_NOFOLLOW 131072 end // fail if pathname is symbolic link +macro FS_O_NONBLOCK 2048 end // if possible, open file with non-blocking IO +macro FS_O_NDELAY 2048 end // same as O_NONBLOCK +macro FS_O_PATH 2097152 end // open descriptor for obtaining permissions and status of a file but does not allow read/write operations +macro FS_O_SYNC 1052672 end // wait for IO to complete before returning +macro FS_O_TMPFILE 4259840 end // create an unnamed, unreachable (via any other open call) temporary file +macro FS_O_TRUNC 512 end // if file exists, ovewrite it (careful!) diff --git a/include/int.mcl b/include/int.mcl index 6a5e3b9..c74ee7e 100644 --- a/include/int.mcl +++ b/include/int.mcl @@ -1,5 +1,16 @@ macro NULL 0 end macro false 0 end macro true 1 end + macro div divmod drop end -macro mod divmod swap drop end \ No newline at end of file +macro mod divmod swap drop end +macro / div end +macro % mod end + +macro 2dup over over end +macro 2drop drop drop end + +macro sizeof(u64) 8 end +macro sizeof(u32) 4 end +macro sizeof(u16) 2 end +macro sizeof(u8) 1 end \ No newline at end of file diff --git a/include/io.mcl b/include/io.mcl index b37d846..76b7ae5 100644 --- a/include/io.mcl +++ b/include/io.mcl @@ -1,21 +1,29 @@ -include "linux.mcl" - // Write to a file descriptor using the SYS_write syscall -// args: [str_size, str_ptr, fd] -// @arg str_size: Int -// @arg str_ptr: Ptr -// @arg fd: Int +// args: [buff_size, buff_ptr, fd] +// @arg buff_size: Int - number of bytes to write +// @arg buff_ptr: Ptr - pointer to the buffer to write +// @arg fd: Int - file descriptor // @ret Int macro write SYS_write syscall3 end +// Write to a file descriptor using the SYS_write syscall +// args: [buff_size, buff_ptr, fd] +// @arg buff_size: Int - number of bytes to write +// @arg buff_ptr: Ptr - pointer to the buffer to write +// @arg fd: Int - file descriptor +// @ret Int +macro read + SYS_read syscall3 +end + // Print a string to STDOUT // args: [str_size, str_ptr] -// @arg str_size: Int -// @arg str_ptr: Ptr +// @arg buff_size: Int - number of bytes to write +// @arg buff_ptr: Ptr - pointer to the buffer to write // @ret NULL macro puts STDOUT write drop @@ -23,8 +31,8 @@ end // Print a string to STDERR // args: [str_size, str_ptr] -// @arg str_size: Int -// @arg str_ptr: Ptr +// @arg buff_size: Int - number of bytes to write +// @arg buff_ptr: Ptr - pointer to the buffer to write // @ret NULL macro eputs STDOUT write drop diff --git a/include/mem.mcl b/include/mem.mcl new file mode 100644 index 0000000..2f1ae8e --- /dev/null +++ b/include/mem.mcl @@ -0,0 +1,27 @@ + +macro load8 @8 end +macro store8 !8 end + +macro load64 + 7 + 0 + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap 1 - swap + 8 shl over !8 + swap drop +end + +macro store64 + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 1 + swap + 2dup 255 band @8 shr swap 2drop +end + diff --git a/include/std.mcl b/include/std.mcl new file mode 100644 index 0000000..78fcb01 --- /dev/null +++ b/include/std.mcl @@ -0,0 +1,5 @@ +include "linux.mcl" +include "io.mcl" +include "util.mcl" +include "int.mcl" +include "fs.mcl" \ No newline at end of file diff --git a/src/bin/mcl_test_dev.rs b/src/bin/mcl_test_dev.rs index 0893642..73fb03f 100644 --- a/src/bin/mcl_test_dev.rs +++ b/src/bin/mcl_test_dev.rs @@ -1,5 +1,5 @@ -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use std::process::Stdio; use std::{process, fs}; use clap::Parser; @@ -47,10 +47,10 @@ fn run_test + std::convert::AsRef>(f_in: PathB let mut command = process::Command::new(compiler); command.stdout(Stdio::piped()); command.stderr(Stdio::piped()); - if !compile_mode { - command.arg("-sq"); - } else { + if compile_mode { command.arg("-cqr"); + } else { + command.arg("-sq"); } command.arg("-i"); @@ -63,18 +63,18 @@ fn run_test + std::convert::AsRef>(f_in: PathB let out = child.wait_with_output()?; let stdout = out.stdout.iter().map(|c| { - char::from_u32((*c) as u32).expect("Failed to parse stdout char").to_string() + char::from_u32(u32::from(*c)).expect("Failed to parse stdout char").to_string() }).collect::(); let stderr = out.stderr.iter().map(|c| { - char::from_u32((*c) as u32).expect("Failed to parse stderr char").to_string() + char::from_u32(u32::from(*c)).expect("Failed to parse stderr char").to_string() }).collect::(); Ok(TestOutput { - stdout: stdout, - stderr: stderr, - stdin: stdin, + stdout, + stderr, + stdin, status: out.status.code().unwrap() }) } @@ -91,14 +91,14 @@ fn run_tests(args: Args) -> Result<()>{ let intp = run_test(file.path(), &f_out, &args.compiler_path, false, String::new())?; let comp = run_test(file.path(), &f_out, &args.compiler_path, true, String::new())?; - compare_results(intp, comp, file.path())?; + compare_results(&intp, &comp, &file.path())?; } Ok(()) } -fn compare_results(intp: TestOutput, comp: TestOutput, f_in: PathBuf) -> Result<()> { +fn compare_results(intp: &TestOutput, comp: &TestOutput, f_in: &Path) -> Result<()> { if intp.stdout != comp.stdout { println!("{b}[ {r}ERR{rs}{b} ]{rs} {f} compiled and interpreted stdout versions differ", r=color::FG_RED, rs=color::RESET, b=color::BRIGHT, f=f_in.display()); diff --git a/src/compile/commands.rs b/src/compile/commands.rs index 45f7db9..98426e6 100644 --- a/src/compile/commands.rs +++ b/src/compile/commands.rs @@ -1,9 +1,9 @@ -use std::path::PathBuf; +use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; use color_eyre::Result; use crate::info; -pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &PathBuf, quiet: bool) -> Result<()> { +pub fn linux_x86_64_compile_and_link(of_a: &Path, of_o: &Path, of_c: &Path, quiet: bool) -> Result<()> { let nasm_args = [ "-felf64", @@ -23,7 +23,7 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path return Ok(()); } else { Command::new("nasm") - .args(&nasm_args) + .args(nasm_args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn()? @@ -42,7 +42,7 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path return Ok(()); } else { Command::new("ld") - .args(&ld_args) + .args(ld_args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn()? @@ -60,28 +60,28 @@ pub fn linux_x86_64_compile_and_link(of_a: &PathBuf, of_o: &PathBuf, of_c: &Path Ok(()) } -pub fn linux_x86_64_run(_bin: &PathBuf, args: Vec, quiet: bool) -> Result { +pub fn linux_x86_64_run(bin: &Path, args: &[String], quiet: bool) -> Result { let bin = PathBuf::from( - format!("./{}", _bin.to_string_lossy()) + format!("./{}", bin.to_string_lossy()) ); let mut proc = if cfg!(target_os = "windows") { return Ok(0); } else { - Command::new(bin) - .args(&args) + Command::new(bin.clone()) + .args(args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn()? }; // println!("{}", quiet); if !quiet { - info!("running {} {}", _bin.to_string_lossy(), args.join(" ")); + info!("running {} {}", bin.to_string_lossy(), args.join(" ")); } let exit = proc.wait()?; if !quiet { - info!("{} process exited with code {}", _bin.to_string_lossy(), exit); + info!("{} process exited with code {}", bin.to_string_lossy(), exit); } Ok(exit.code().unwrap_or(0)) diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index dd02b9f..5b1a7b9 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -1,14 +1,14 @@ use std::{fs, path::PathBuf, io::{Write, BufWriter}}; -use crate::{constants::{Operator, OpType}, Args}; +use crate::{constants::{Operator, OpType, KeywordType}, Args}; use color_eyre::Result; use crate::compile::commands::linux_x86_64_compile_and_link; - +use crate::constants::InstructionType; use super::commands::linux_x86_64_run; -pub fn compile(tokens: Vec, args: Args) -> Result{ +pub fn compile(tokens: &[Operator], args: &Args) -> Result{ let mut of_c = PathBuf::from(&args.out_file); - let (mut of_o, mut of_a) = if &args.out_file == &crate::DEFAULT_OUT_FILE.to_string() { + let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE { let of_o = PathBuf::from("/tmp/mclang_comp.o"); let of_a = PathBuf::from("/tmp/mclang_comp.nasm"); (of_o, of_a) @@ -22,6 +22,8 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ of_o.set_extension("o"); of_a.set_extension("nasm"); + + let file = fs::File::create(&of_a)?; let mut writer = BufWriter::new(&file); @@ -72,16 +74,16 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ while ti < tokens.len() { let token = &tokens[ti]; - writeln!(writer, "addr_{}:", ti)?; + writeln!(writer, "addr_{ti}:")?; match token.typ { // stack - OpType::PushInt => { + OpType::Instruction(InstructionType::PushInt) => { writeln!(writer, " ;; -- push int {}", token.value)?; writeln!(writer, " mov rax, {}", token.value)?; writeln!(writer, " push rax")?; ti += 1; }, - OpType::PushStr => { + OpType::Instruction(InstructionType::PushStr) => { writeln!(writer, " ;; -- push str \"{}\"", token.text.escape_default())?; writeln!(writer, " mov rax, {}", token.text.len())?; writeln!(writer, " push rax")?; @@ -89,19 +91,19 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ strings.push(token.text.clone()); ti += 1; } - OpType::Drop => { + OpType::Instruction(InstructionType::Drop) => { writeln!(writer, " ;; -- drop")?; writeln!(writer, " pop rax")?; ti += 1; }, - OpType::Print => { + OpType::Instruction(InstructionType::Print) => { writeln!(writer, " ;; -- print")?; writeln!(writer, " pop rdi")?; writeln!(writer, " call print")?; ti += 1; }, - OpType::Dup => { + OpType::Instruction(InstructionType::Dup) => { writeln!(writer, " ;; -- dup")?; writeln!(writer, " pop rax")?; writeln!(writer, " push rax")?; @@ -109,19 +111,8 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ ti += 1; }, - OpType::Dup2 => { - writeln!(writer, " ;; -- 2dup")?; - writeln!(writer, " pop rbx")?; - writeln!(writer, " pop rax")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rbx")?; - writeln!(writer, " push rax")?; - writeln!(writer, " push rbx")?; - ti += 1; - }, - - OpType::Rot => { + OpType::Instruction(InstructionType::Rot) => { writeln!(writer, " ;; -- rot")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -132,7 +123,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ ti += 1; }, - OpType::Swap => { + OpType::Instruction(InstructionType::Swap) => { writeln!(writer, " ;; -- swap")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -141,7 +132,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ ti += 1; }, - OpType::Over => { + OpType::Instruction(InstructionType::Over) => { writeln!(writer, " ;; -- over")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -153,12 +144,12 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ }, //mem - OpType::Mem => { + OpType::Instruction(InstructionType::Mem) => { writeln!(writer, " ;; -- mem")?; writeln!(writer, " push mem")?; ti += 1; } - OpType::Load8 => { + OpType::Instruction(InstructionType::Load8) => { writeln!(writer, " ;; -- load")?; writeln!(writer, " pop rax")?; writeln!(writer, " xor rbx, rbx")?; @@ -167,7 +158,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ ti += 1; } - OpType::Store8 => { + OpType::Instruction(InstructionType::Store8) => { writeln!(writer, " ;; -- store")?; writeln!(writer, " pop rbx")?; writeln!(writer, " pop rax")?; @@ -176,7 +167,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ } // math - OpType::Plus => { + OpType::Instruction(InstructionType::Plus) => { writeln!(writer, " ;; -- plus")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -184,7 +175,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::Minus => { + OpType::Instruction(InstructionType::Minus) => { writeln!(writer, " ;; -- minus")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -192,7 +183,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rbx")?; ti += 1; }, - OpType::Equals => { + OpType::Instruction(InstructionType::Equals) => { writeln!(writer, " ;; -- equals")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; @@ -203,7 +194,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::Lt => { + OpType::Instruction(InstructionType::Lt) => { writeln!(writer, " ;; -- lt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; @@ -214,7 +205,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::Gt => { + OpType::Instruction(InstructionType::Gt) => { writeln!(writer, " ;; -- gt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; @@ -225,7 +216,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::NotEquals => { + OpType::Instruction(InstructionType::NotEquals) => { writeln!(writer, " ;; -- not equals")?; writeln!(writer, " mov rcx, 1")?; writeln!(writer, " mov rdx, 0")?; @@ -236,7 +227,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::Le => { + OpType::Instruction(InstructionType::Le) => { writeln!(writer, " ;; -- lt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; @@ -247,7 +238,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::Ge => { + OpType::Instruction(InstructionType::Ge) => { writeln!(writer, " ;; -- gt")?; writeln!(writer, " mov rcx, 0")?; writeln!(writer, " mov rdx, 1")?; @@ -258,7 +249,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rcx")?; ti += 1; }, - OpType::Band => { + OpType::Instruction(InstructionType::Band) => { writeln!(writer, " ;; -- band")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -266,7 +257,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rbx")?; ti += 1; }, - OpType::Bor => { + OpType::Instruction(InstructionType::Bor) => { writeln!(writer, " ;; -- bor")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -274,7 +265,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rbx")?; ti += 1; }, - OpType::Shr => { + OpType::Instruction(InstructionType::Shr) => { writeln!(writer, " ;; -- shr")?; writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; @@ -282,7 +273,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rbx")?; ti += 1; }, - OpType::Shl => { + OpType::Instruction(InstructionType::Shl) => { writeln!(writer, " ;; -- shl")?; writeln!(writer, " pop rcx")?; writeln!(writer, " pop rbx")?; @@ -290,7 +281,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rbx")?; ti += 1; }, - OpType::DivMod => { + OpType::Instruction(InstructionType::DivMod) => { writeln!(writer, " ;; -- div")?; writeln!(writer, " xor rdx, rdx")?; writeln!(writer, " pop rbx")?; @@ -300,7 +291,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rdx")?; ti += 1; }, - OpType::Mul => { + OpType::Instruction(InstructionType::Mul) => { writeln!(writer, " ;; -- mul")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rbx")?; @@ -311,44 +302,44 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ // block - OpType::If => { + OpType::Keyword(KeywordType::If) => { writeln!(writer, " ;; -- if")?; writeln!(writer, " pop rax")?; writeln!(writer, " test rax, rax")?; writeln!(writer, " jz addr_{}", token.jmp)?; ti += 1; }, - OpType::Else => { + OpType::Keyword(KeywordType::Else) => { writeln!(writer, " ;; -- else")?; writeln!(writer, " jmp addr_{}", token.jmp)?; ti += 1; }, - OpType::While => { + OpType::Keyword(KeywordType::While) => { writeln!(writer, " ;; -- while")?; ti += 1; } - OpType::Do => { + OpType::Keyword(KeywordType::Do) => { writeln!(writer, " ;; -- do")?; writeln!(writer, " pop rax")?; writeln!(writer, " test rax, rax")?; writeln!(writer, " jz addr_{}", token.jmp)?; ti += 1; } - OpType::End => { + OpType::Keyword(KeywordType::End) => { writeln!(writer, " ;; -- end")?; - if ti + 1 != token.jmp as usize { + if ti + 1 != token.jmp { writeln!(writer, " jmp addr_{}", token.jmp)?; } ti += 1; }, - OpType::Syscall0 => { + OpType::Instruction(InstructionType::Syscall0) => { writeln!(writer, " ;; -- syscall0")?; writeln!(writer, " pop rax")?; writeln!(writer, " syscall")?; writeln!(writer, " push rax")?; ti += 1; }, - OpType::Syscall1 => { + OpType::Instruction(InstructionType::Syscall1) => { writeln!(writer, " ;; -- syscall1")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -356,7 +347,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::Syscall2 => { + OpType::Instruction(InstructionType::Syscall2) => { writeln!(writer, " ;; -- syscall2")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -365,7 +356,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::Syscall3 => { + OpType::Instruction(InstructionType::Syscall3) => { writeln!(writer, " ;; -- syscall3")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -376,7 +367,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ ti += 1; }, - OpType::Syscall4 => { + OpType::Instruction(InstructionType::Syscall4) => { writeln!(writer, " ;; -- syscall4")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -387,7 +378,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::Syscall5 => { + OpType::Instruction(InstructionType::Syscall5) => { writeln!(writer, " ;; -- syscall5")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -399,7 +390,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::Syscall6 => { + OpType::Instruction(InstructionType::Syscall6) => { writeln!(writer, " ;; -- syscall6")?; writeln!(writer, " pop rax")?; writeln!(writer, " pop rdi")?; @@ -412,20 +403,18 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, - OpType::None => unreachable!(), - OpType::Macro => unreachable!(), - OpType::Include => unreachable!() + OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() } } - writeln!(writer, "addr_{}:", ti)?; + writeln!(writer, "addr_{ti}:")?; writeln!(writer, " mov rax, 60")?; writeln!(writer, " mov rdi, 0")?; writeln!(writer, " syscall")?; writeln!(writer, "segment .data")?; - for s in 0..strings.len() { - let s_chars = strings[s].chars().map(|c| (c as u32).to_string()).collect::>(); + for (_, s) in strings.iter().enumerate() { + let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::>(); let s_list = s_chars.join(","); - writeln!(writer, " str_{}: db {} ; {}", s, s_list, strings[s].escape_default())?; + writeln!(writer, " str_{}: db {} ; {}", s, s_list, s.escape_default())?; } writeln!(writer, "segment .bss")?; @@ -434,7 +423,7 @@ pub fn compile(tokens: Vec, args: Args) -> Result{ writer.flush()?; 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, vec![], args.quiet)?; + let c = linux_x86_64_run(&of_c, &[], args.quiet)?; return Ok(c); } diff --git a/src/compile/mod.rs b/src/compile/mod.rs index ba135f0..9c22480 100644 --- a/src/compile/mod.rs +++ b/src/compile/mod.rs @@ -1,5 +1,5 @@ pub mod linux_x86_64; pub mod commands; -pub const MEM_SZ: u32 = 640 * 1000; // 4kb -pub const STRING_SZ: u32 = 640 * 1000; // 4kb +pub const MEM_SZ: usize = 640 * 1000; // 4kb +pub const STRING_SZ: usize = 640 * 1000; // 4kb diff --git a/src/constants.rs b/src/constants.rs index 475aaed..aa203bf 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,7 +3,7 @@ pub const ALLOW_MACRO_REDEFINITION: bool = true; #[derive(Debug, Clone, PartialEq)] -pub enum OpType { +pub enum InstructionType { // stack PushInt, @@ -11,7 +11,6 @@ pub enum OpType { Drop, Print, Dup, - Dup2, // a b => a b a b Rot, // a b c => b c a Over, // a b => a b a Swap, // a b => b a @@ -37,15 +36,6 @@ pub enum OpType { Mem, Load8, Store8, - - // block - If, - Else, - End, - While, - Do, - Macro, - Include, // syscalls Syscall0, @@ -59,24 +49,40 @@ pub enum OpType { None // Used for macros and any other non built in word definitions } +#[derive(Debug, Clone, PartialEq)] +pub enum KeywordType { + If, + Else, + End, + While, + Do, + Macro, + Include, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum OpType { + Keyword(KeywordType), + Instruction(InstructionType) +} #[derive(Debug, Clone)] -pub struct Operator { +pub struct Operator{ pub typ: OpType, - pub value: i64, + pub value: usize, pub text: String, //? only used for OpType::PushStr - pub addr: i64, //? only used for OpType::PushStr - pub jmp: i32, - pub loc: (String, u32, u32) + pub addr: Option, //? only used for OpType::PushStr + pub jmp: usize, + pub loc: (String, usize, usize) } impl Operator { - pub fn new(typ: OpType, value: i64, text: String, file: String, row: u32, col: u32) -> Self { + pub fn new(typ: OpType, value: usize, text: String, file: String, row: usize, col: usize) -> Self { Self { typ, value, jmp: 0, - addr: -1, + addr: None, text, loc: (file, row, col) } @@ -86,48 +92,47 @@ impl Operator { impl OpType { pub fn human(&self) -> String { - match self { - &OpType::PushInt => "Number", - &OpType::PushStr => "String", - &OpType::Print => "print", - &OpType::Dup => "dup", - &OpType::Drop => "drop", - &OpType::Dup2 => "2dup", - &OpType::Rot => "rot", - &OpType::Over => "over", - &OpType::Swap => "swap", - &OpType::Plus => "+", - &OpType::Minus => "-", - &OpType::Equals => "=", - &OpType::Gt => ">", - &OpType::Lt => "<", - &OpType::NotEquals => "!=", - &OpType::Le => "<=", - &OpType::Ge => ">=", - &OpType::Band => "band", - &OpType::Bor => "bor", - &OpType::Shr => "shr", - &OpType::Shl => "shl", - &OpType::DivMod => "divmod", - &OpType::Mul => "*", - &OpType::If => "if", - &OpType::Else => "else", - &OpType::End => "end", - &OpType::While => "while", - &OpType::Do => "do", - &OpType::Macro => "macro", - &OpType::Include => "include", - &OpType::Mem => "mem", - &OpType::Load8 => "!8", - &OpType::Store8 => "@8", - &OpType::Syscall0 => "syscall0", - &OpType::Syscall1 => "syscall1", - &OpType::Syscall2 => "syscall2", - &OpType::Syscall3 => "syscall3", - &OpType::Syscall4 => "syscall4", - &OpType::Syscall5 => "syscall5", - &OpType::Syscall6 => "syscall6", - &OpType::None => "None" + match *self { + OpType::Instruction(InstructionType::PushInt) => "Number", + OpType::Instruction(InstructionType::PushStr) => "String", + OpType::Instruction(InstructionType::Print) => "print", + OpType::Instruction(InstructionType::Dup) => "dup", + OpType::Instruction(InstructionType::Drop) => "drop", + OpType::Instruction(InstructionType::Rot) => "rot", + OpType::Instruction(InstructionType::Over) => "over", + OpType::Instruction(InstructionType::Swap) => "swap", + OpType::Instruction(InstructionType::Plus) => "+", + OpType::Instruction(InstructionType::Minus) => "-", + OpType::Instruction(InstructionType::Equals) => "=", + OpType::Instruction(InstructionType::Gt) => ">", + OpType::Instruction(InstructionType::Lt) => "<", + OpType::Instruction(InstructionType::NotEquals) => "!=", + OpType::Instruction(InstructionType::Le) => "<=", + OpType::Instruction(InstructionType::Ge) => ">=", + OpType::Instruction(InstructionType::Band) => "band", + OpType::Instruction(InstructionType::Bor) => "bor", + OpType::Instruction(InstructionType::Shr) => "shr", + OpType::Instruction(InstructionType::Shl) => "shl", + OpType::Instruction(InstructionType::DivMod) => "divmod", + OpType::Instruction(InstructionType::Mul) => "*", + OpType::Keyword(KeywordType::If) => "if", + OpType::Keyword(KeywordType::Else) => "else", + OpType::Keyword(KeywordType::End) => "end", + OpType::Keyword(KeywordType::While) => "while", + OpType::Keyword(KeywordType::Do) => "do", + OpType::Keyword(KeywordType::Macro) => "macro", + OpType::Keyword(KeywordType::Include) => "include", + OpType::Instruction(InstructionType::Mem) => "mem", + OpType::Instruction(InstructionType::Load8) => "!8", + OpType::Instruction(InstructionType::Store8) => "@8", + OpType::Instruction(InstructionType::Syscall0) => "syscall0", + OpType::Instruction(InstructionType::Syscall1) => "syscall1", + OpType::Instruction(InstructionType::Syscall2) => "syscall2", + OpType::Instruction(InstructionType::Syscall3) => "syscall3", + OpType::Instruction(InstructionType::Syscall4) => "syscall4", + OpType::Instruction(InstructionType::Syscall5) => "syscall5", + OpType::Instruction(InstructionType::Syscall6) => "syscall6", + OpType::Instruction(InstructionType::None) => "None" }.to_string() } } @@ -135,13 +140,13 @@ impl OpType { #[derive(Debug, Clone)] pub struct Token { pub file: String, - pub line: u32, - pub col: u32, + pub line: usize, + pub col: usize, pub text: String, pub typ: TokenType } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Copy)] pub enum TokenType { Word, Int, @@ -160,7 +165,7 @@ impl Token { } impl TokenType { - pub fn human(&self) -> String { + pub fn human(self) -> String { match self { TokenType::Word => "Word", TokenType::Int => "Int", @@ -170,4 +175,4 @@ impl TokenType { } } -pub type Loc = (String, u32, u32); \ No newline at end of file +pub type Loc = (String, usize, usize); \ No newline at end of file diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index b8644ad..a53f34d 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -1,23 +1,20 @@ -use crate::{constants::OpType, lerror, error}; +use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error}; // use crate::util::logger; use color_eyre::Result; use eyre::eyre; mod syscalls; -fn stack_pop(stack: &mut Vec, pos: &(String, u32, u32)) -> Result { - match stack.pop() { - Some(i) => Ok(i), - None => { - lerror!(&pos.clone(), "Stack underflow"); - Err(eyre!("Stack underflow")) - }, +fn stack_pop(stack: &mut Vec, pos: &Loc) -> Result { + if let Some(i) = stack.pop() { Ok(i) } else { + lerror!(&pos.clone(), "Stack underflow"); + Err(eyre!("Stack underflow")) } } -pub fn run(tokens: Vec) -> Result{ - let mut stack: Vec = Vec::new(); +pub fn run(tokens: &[crate::constants::Operator]) -> Result{ + let mut stack: Vec = Vec::new(); let mut ti = 0; - let mut mem: Vec = vec![0; crate::compile::MEM_SZ as usize + crate::compile::STRING_SZ as usize]; + let mut mem: Vec = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; let mut string_idx = 0; // for token in &tokens { // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); @@ -30,47 +27,41 @@ pub fn run(tokens: Vec) -> Result{ match token.typ { // stack - OpType::PushInt => { - stack.push(token.value as u64); + OpType::Instruction(InstructionType::PushInt) => { + stack.push(token.value); ti += 1; }, - OpType::PushStr => { - if token.addr < 0 { - stack.push(token.text.len() as u64); // string len - stack.push(string_idx + crate::compile::MEM_SZ as u64); + OpType::Instruction(InstructionType::PushStr) => { + if token.addr.is_none() { + stack.push(token.text.len()); // string len + stack.push(string_idx + crate::compile::MEM_SZ); for c in token.text.bytes() { - mem[crate::compile::MEM_SZ as usize + string_idx as usize] = c; + mem[crate::compile::MEM_SZ + string_idx] = c; string_idx += 1; } } else { - stack.push(token.text.len() as u64); - stack.push(token.addr as u64); + stack.push(token.text.len()); + if let Some(addr) = token.addr { + stack.push(addr); + } } ti += 1; }, - OpType::Drop => { + OpType::Instruction(InstructionType::Drop) => { stack.pop(); ti += 1; }, - OpType::Dup => { + OpType::Instruction(InstructionType::Dup) => { let a = stack_pop(&mut stack, &pos)?; stack.push(a); stack.push(a); ti += 1; }, - OpType::Dup2 => { - let a = stack_pop(&mut stack, &pos)?; - let b = stack_pop(&mut stack, &pos)?; - stack.push(b); - stack.push(a); - stack.push(b); - stack.push(a); - ti += 1; - } - OpType::Rot => { + + OpType::Instruction(InstructionType::Rot) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; let c = stack_pop(&mut stack, &pos)?; @@ -79,14 +70,14 @@ pub fn run(tokens: Vec) -> Result{ stack.push(c); ti += 1; } - OpType::Swap => { + OpType::Instruction(InstructionType::Swap) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(a); stack.push(b); ti += 1; } - OpType::Over => { + OpType::Instruction(InstructionType::Over) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b); @@ -95,7 +86,7 @@ pub fn run(tokens: Vec) -> Result{ ti += 1; } - OpType::Print => { + OpType::Instruction(InstructionType::Print) => { let a = stack_pop(&mut stack, &pos)?; println!("{a}"); // let _ = io::stdout().flush(); @@ -103,159 +94,155 @@ pub fn run(tokens: Vec) -> Result{ }, // mem - OpType::Mem => { + OpType::Instruction(InstructionType::Mem) => { stack.push(0); ti += 1; } - OpType::Load8 => { + OpType::Instruction(InstructionType::Load8) => { let a = stack_pop(&mut stack, &pos)?; - let byte = mem[a as usize]; - stack.push(byte as u64); + let byte = mem[a]; + stack.push(byte as usize); ti += 1; } - OpType::Store8 => { + #[allow(clippy::cast_possible_truncation)] + OpType::Instruction(InstructionType::Store8) => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; - mem[addr as usize] = (val & 0xFF) as u8; + mem[addr] = (val & 0xFF) as u8; ti += 1; } // math - OpType::Plus => { + OpType::Instruction(InstructionType::Plus) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b + a); ti += 1; }, - OpType::Minus => { + OpType::Instruction(InstructionType::Minus) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; stack.push(b - a); ti += 1; }, - OpType::Equals => { + OpType::Instruction(InstructionType::Equals) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b == a) as u64); + stack.push(usize::from(b == a)); ti += 1; }, - OpType::Gt => { + OpType::Instruction(InstructionType::Gt) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b > a) as u64); + stack.push(usize::from(b > a)); ti += 1; }, - OpType::Lt => { + OpType::Instruction(InstructionType::Lt) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b < a) as u64); + stack.push(usize::from(b < a)); ti += 1; }, - OpType::NotEquals => { + OpType::Instruction(InstructionType::NotEquals) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b != a) as u64); + stack.push(usize::from(b != a)); ti += 1; }, - OpType::Ge => { + OpType::Instruction(InstructionType::Ge) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b >= a) as u64); + stack.push(usize::from(b >= a)); ti += 1; }, - OpType::Le => { + OpType::Instruction(InstructionType::Le) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b <= a) as u64); + stack.push(usize::from(b <= a)); ti += 1; }, - OpType::Band => { + OpType::Instruction(InstructionType::Band) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((a & b) as u64); + stack.push(a & b); ti += 1; } - OpType::Bor => { + OpType::Instruction(InstructionType::Bor) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((a | b) as u64); + stack.push(a | b); ti += 1; } - OpType::Shr => { + OpType::Instruction(InstructionType::Shr) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b >> a) as u64); + stack.push(b >> a); ti += 1; } - OpType::Shl => { + OpType::Instruction(InstructionType::Shl) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b << a) as u64); + stack.push(b << a); ti += 1; } - OpType::DivMod => { + OpType::Instruction(InstructionType::DivMod) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b / a) as u64); - stack.push((b % a) as u64); + stack.push(b / a); + stack.push(b % a); ti += 1; } - OpType::Mul => { + OpType::Instruction(InstructionType::Mul) => { let a = stack_pop(&mut stack, &pos)?; let b = stack_pop(&mut stack, &pos)?; - stack.push((b * a) as u64); + stack.push(b * a); ti += 1; } // blocks - OpType::If => { + OpType::Keyword(KeywordType::If) => { let a = stack_pop(&mut stack, &pos)?; if a == 0 { // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); - ti = (token.jmp) as usize; + ti = token.jmp; } else { ti += 1; } }, - OpType::Else => { - // println!("Else({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); - ti = (token.jmp) as usize; - }, - OpType::End => { - // println!("End({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); - ti = (token.jmp) as usize; + OpType::Keyword(KeywordType::Else) | OpType::Keyword(KeywordType::End) => { + ti = token.jmp; } - OpType::While => { + OpType::Keyword(KeywordType::While) => { ti += 1; } - OpType::Do => { + OpType::Keyword(KeywordType::Do) => { let a = stack.pop().unwrap(); if a == 0 { - ti = (token.jmp) as usize; + ti = token.jmp; } else { ti += 1; } } - OpType::Syscall0 => { + OpType::Instruction(InstructionType::Syscall0) => { todo!(); // ti += 1; }, - OpType::Syscall1 => { + OpType::Instruction(InstructionType::Syscall1) => { todo!(); // ti += 1; }, - OpType::Syscall2 => { + OpType::Instruction(InstructionType::Syscall2) => { todo!(); // ti += 1; }, - OpType::Syscall3 => { + OpType::Instruction(InstructionType::Syscall3) => { let rax = stack_pop(&mut stack, &pos)?; let rdi = stack_pop(&mut stack, &pos)?; let rsi = stack_pop(&mut stack, &pos)?; @@ -263,6 +250,7 @@ pub fn run(tokens: Vec) -> Result{ // println!("yes"); let ret = match rax { 1 => syscalls::sys_write(rax, rdi, rsi, rdx, &mem), + 0 => 0, //? temp, so clippy doesnt complain _ => { error!("Syscall(3) #{} is not implemented", rax); return Err(eyre!("Syscall not implemented")); @@ -272,21 +260,19 @@ pub fn run(tokens: Vec) -> Result{ // println!("{}", stack.len()); ti += 1; }, - OpType::Syscall4 => { + OpType::Instruction(InstructionType::Syscall4) => { todo!(); // ti += 1; }, - OpType::Syscall5 => { + OpType::Instruction(InstructionType::Syscall5) => { todo!(); // ti += 1; }, - OpType::Syscall6 => { + OpType::Instruction(InstructionType::Syscall6) => { todo!(); // ti += 1; }, - OpType::None => unreachable!(), - OpType::Macro => unreachable!(), - OpType::Include => unreachable!() + OpType::Instruction(InstructionType::None) | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() } } diff --git a/src/interpret/linux_x86_64/syscalls.rs b/src/interpret/linux_x86_64/syscalls.rs index 4fb6919..c764c95 100644 --- a/src/interpret/linux_x86_64/syscalls.rs +++ b/src/interpret/linux_x86_64/syscalls.rs @@ -1,22 +1,20 @@ -pub fn sys_write(sys_n: u64, fd: u64, buff: u64, count: u64, mem: &Vec ) -> u64 { +pub fn sys_write(sys_n: usize, fd: usize, buff: usize, count: usize, mem: &Vec ) -> usize { let mem = (*mem).clone(); - let buff = buff as usize; - let count = count as usize; // println!("{:?}", &mem[buff..(buff + count)]); // return 0 ; let s = &mem[buff..(buff + count)].iter().map(|i| { - char::from_u32((*i) as u32).unwrap_or('_').to_string() - }).collect::>().join(""); + char::from_u32(u32::from(*i)).unwrap_or('_').to_string() + }).collect::(); match fd { 1 => { - print!("{}", s); + print!("{s}"); }, 2 => { - eprint!("{}", s); + eprint!("{s}"); }, - _ => panic!("Unknown file {}", fd) + _ => panic!("Unknown file {fd}") }; let _ = std::io::Write::flush(&mut std::io::stdout()); let _ = std::io::Write::flush(&mut std::io::stderr()); diff --git a/src/lexer.rs b/src/lexer.rs index a2aae5c..533a720 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -5,45 +5,45 @@ use color_eyre::Result; fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) { match s { s if s.parse::().is_ok() && tok_type == TokenType::Word => { // negative numbers not yet implemented - return (TokenType::Int, s); + (TokenType::Int, s) }, s if tok_type == TokenType::Word => { - return (TokenType::Word, s); + (TokenType::Word, s) }, s if tok_type == TokenType::String => { - return (TokenType::String, s); + (TokenType::String, s) } - s if tok_type == TokenType::Char=> { - return (TokenType::Char, s); + s if tok_type == TokenType::Char => { + (TokenType::Char, s) } _ => unreachable!() } } -pub fn find_col(text: String, mut col: u32, predicate: F) -> Result where F: Fn(char, char) -> bool { +pub fn find_col(text: &str, mut col: usize, predicate: F) -> usize where F: Fn(char, char) -> bool { let mut last = '\0'; - while (col as usize) < text.len() && !predicate(text.chars().nth(col as usize).unwrap(), last) { - last = text.chars().nth(col as usize).unwrap(); + while col < text.len() && !predicate(text.chars().nth(col).unwrap(), last) { + last = text.chars().nth(col).unwrap(); col += 1; } - Ok(col) + col } // TODO: Implement multiline strings -fn lex_line(text: String) -> Result> { - let mut tokens: Vec<(u32, String, TokenType)> = Vec::new(); +fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> { + let mut tokens: Vec<(usize, String, TokenType)> = Vec::new(); - let mut col = find_col(text.clone(), 0, |x, _| !x.is_whitespace())?; - let mut col_end: u32 = 0; - while col_end < text.clone().len() as u32 { - if (text.len() - col as usize) < 1 { - return Ok(tokens); + let mut col = find_col(text, 0, |x, _| !x.is_whitespace()); + let mut col_end: usize = 0; + while col_end < text.to_string().len() { + if (text.len() - col) < 1 { + return tokens; } - if &text[(col as usize)..(col + 1) as usize] == "\"" { - col_end = find_col(text.clone(), col + 1, |x, x2| x == '"' && x2 != '\\')?; - let t = &text[((col + 1) as usize)..(col_end as usize)]; + if &text[col..=col] == "\"" { + col_end = find_col(text, col + 1, |x, x2| x == '"' && x2 != '\\'); + let t = &text[(col + 1)..col_end]; let t = t.replace("\\n", "\n") .replace("\\t", "\t") .replace("\\r", "\r") @@ -53,11 +53,11 @@ fn lex_line(text: String) -> Result> { if !t.is_empty() { tokens.push((col, t.to_string(), TokenType::String)); } - col = find_col(text.clone(), col_end + 1, |x, _| !x.is_whitespace())?; + col = find_col(text, col_end + 1, |x, _| !x.is_whitespace()); - } else if &text[(col as usize)..(col + 1) as usize] == "'"{ - col_end = find_col(text.clone(), col + 1, |x, x2| x == '\'' && x2 != '\\')?; - let t = &text[((col + 1) as usize)..(col_end as usize)]; + } else if &text[col..=col] == "'"{ + col_end = find_col(text, col + 1, |x, x2| x == '\'' && x2 != '\\'); + let t = &text[(col + 1)..col_end]; let t = t.replace("\\n", "\n") .replace("\\t", "\t") .replace("\\r", "\r") @@ -69,44 +69,44 @@ fn lex_line(text: String) -> Result> { if !t.is_empty() { tokens.push((col, t.to_string(), TokenType::Char)); } - col = find_col(text.clone(), col_end + 1, |x, _| !x.is_whitespace())?; + col = find_col(text, col_end + 1, |x, _| !x.is_whitespace()); } else { - col_end = find_col(text.clone(), col, |x, _| x.is_whitespace())?; - let t = &text[(col as usize)..((col_end as usize))]; + col_end = find_col(text, col, |x, _| x.is_whitespace()); + let t = &text[col..col_end]; if t == "//" { - return Ok(tokens); + return tokens; } if !t.is_empty() { tokens.push((col, t.to_string(), TokenType::Word)); } - col = find_col(text.clone(), col_end, |x, _| !x.is_whitespace())?; + col = find_col(text, col_end, |x, _| !x.is_whitespace()); } } - Ok(tokens) + tokens } -pub fn lex(code: String, file: &String, args: Args, preprocessing: bool) -> Result> { +pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args, preprocessing: bool) -> Result> { let lines: Vec<(usize, &str)> = code .split(['\n', '\r']) .enumerate() .collect(); - let lines: Vec<(u32, String)> = lines.iter().map(|i| (i.0 as u32, i.1.to_string())).collect(); + let lines: Vec<(usize, String)> = lines.iter().map(|i| (i.0, i.1.to_string())).collect(); let mut tokens: Vec = Vec::new(); for (row, line) in lines { - let lt = lex_line(line)?; + let lt = lex_line(&line); for (col, tok, tok_type) in lt { let (tok_type, tok) = lex_word(tok, tok_type); let t = Token{ - file: file.clone(), + file: file.into(), line: row + 1, - col: col, + col, text: tok, typ: tok_type }; diff --git a/src/main.rs b/src/main.rs index 7607b41..b5b0bfa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,6 @@ mod preprocessor; use std::fs; -use color_eyre::Result; use clap::Parser; pub const DEFAULT_OUT_FILE: &str = "a.out"; @@ -54,52 +53,38 @@ pub struct Args { } -fn main() -> Result<()> { +fn main() { let args = Args::parse(); - let code = match fs::read_to_string(&args.in_file) { - Ok(t) => t, - Err(_) => { - error!("Failed to read file {}, exiting!", &args.in_file); - return Ok(()); - } + let Ok(code) = fs::read_to_string(&args.in_file) else { + error!("Failed to read file {}, exiting!", &args.in_file); + return; + }; - let tokens = match lexer::lex(code, &args.in_file, args.clone(), true) { - Ok(t) => t, - Err(_) => { - error!("Lexing failed, exiting!"); - return Ok(()); - } + let Ok(tokens) = lexer::lex(&code, &args.in_file, &args, true) else { + error!("Lexing failed, exiting!"); + return; }; let mut parser = parser::Parser::new(tokens); - let tokens = match parser.parse() { - Ok(t) => t, - Err(_) => { - error!("Parsing failed, exiting!"); - return Ok(()); - } + let Ok(tokens) = parser.parse() else { + error!("Parsing failed, exiting!"); + return; }; let c = if args.compile && args.interpret { error!("Cannot compile and interpret at the same time"); 0 } else if args.interpret { - match interpret::linux_x86_64::run(tokens) { - Ok(c) => c, - Err(_) => { - error!("Interpretation failed, exiting!"); - 1 - } + if let Ok(c) = interpret::linux_x86_64::run(&tokens) { c } else { + error!("Interpretation failed, exiting!"); + 1 } } else if args.compile { - match compile::linux_x86_64::compile(tokens, args) { - Ok(c) => c, - Err(_) => { - error!("Compilation failed, exiting!"); - 1 - } + if let Ok(c) = compile::linux_x86_64::compile(&tokens, &args) { c } else { + error!("Compilation failed, exiting!"); + 1 } } else { error!("Did not choose to compile or to interpret, exiting"); diff --git a/src/parser.rs b/src/parser.rs index afd5d07..9c8f444 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,61 +1,57 @@ -use std::{collections::HashMap, ops::Deref}; +use std::ops::Deref; -use crate::{constants::{Operator, OpType, Token, TokenType}, lerror}; +use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror}; use color_eyre::Result; use eyre::eyre; pub fn cross_ref(mut program: Vec) -> Result> { - let mut stack: Vec = Vec::new(); + let mut stack: Vec = Vec::new(); for ip in 0..program.len() { let op = &program.clone()[ip]; match op.typ { - OpType::If => { - stack.push(ip as u32) + OpType::Keyword(KeywordType::If) | + OpType::Keyword(KeywordType::While) => { + stack.push(ip); } - OpType::Else => { + OpType::Keyword(KeywordType::Else) => { let if_ip = stack.pop().unwrap(); - if program[if_ip as usize].typ != OpType::If { + if program[if_ip].typ != OpType::Keyword(KeywordType::If) { lerror!(&op.clone().loc,"'end' can only close 'if' blocks"); return Err(eyre!("Bad block")); } - // let mut if_og = &mut tokens[if_ip as usize]; - // (*if_og).jmp = (ip + 1) as i32; - program[if_ip as usize].jmp = (ip + 1) as i32; - stack.push(ip as u32); + program[if_ip].jmp = ip + 1; + stack.push(ip); }, - OpType::End => { + OpType::Keyword(KeywordType::End) => { let block_ip = stack.pop().unwrap(); - // let mut block_og = &mut tokens[block_ip as usize].clone(); - if program[block_ip as usize].typ == OpType::If || - program[block_ip as usize].typ == OpType::Else { - - program[block_ip as usize].jmp = ip as i32; - program[ip as usize].jmp = (ip + 1)as i32; - } else if program[block_ip as usize].typ == OpType::Do { - program[ip].jmp = program[block_ip as usize].jmp; - program[block_ip as usize].jmp = (ip + 1) as i32; + if program[block_ip].typ == OpType::Keyword(KeywordType::If) || + program[block_ip].typ == OpType::Keyword(KeywordType::Else) { + + program[block_ip].jmp = ip; + program[ip].jmp = ip + 1; + + } else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) { + program[ip].jmp = program[block_ip].jmp; + program[block_ip].jmp = ip + 1; } else { lerror!(&op.clone().loc,"'end' can only close 'if' blocks"); return Err(eyre!("")); } } - OpType::While => { - stack.push(ip as u32); - } - OpType::Do => { + OpType::Keyword(KeywordType::Do) => { let while_ip = stack.pop().unwrap(); - program[ip as usize].jmp = while_ip as i32; - stack.push(ip as u32); + program[ip].jmp = while_ip; + stack.push(ip); } _ => () } } - if stack.len() > 0 { - lerror!(&program[stack.pop().expect("Empy stack") as usize].clone().loc,"Unclosed block"); + if !stack.is_empty() { + lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block"); return Err(eyre!("Unclosed block")); } @@ -83,14 +79,14 @@ impl Parser { let pos = (token.file.clone(), token.line, token.col); match token.typ { TokenType::Word => { - let word_type = lookup_word(token.text.clone(), &pos); + let word_type = lookup_word(&token.text, &pos); tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col)); }, TokenType::Int => {// negative numbers not yet implemented - tokens.push(Operator::new(OpType::PushInt, token.text.parse::()?, String::new(), token.file.clone(), token.line, token.col)); + tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::()?, String::new(), token.file.clone(), token.line, token.col)); }, TokenType::String => { - tokens.push(Operator::new(OpType::PushStr, 0, token.text.clone(), token.file.clone(), token.line, token.col)); + tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), 0, token.text.clone(), token.file.clone(), token.line, token.col)); } TokenType::Char => { let c = token.text.clone(); @@ -99,7 +95,7 @@ impl Parser { return Err(eyre!("")); } - tokens.push(Operator::new(OpType::PushInt, token.text.chars().next().unwrap() as i64, String::new(), token.file.clone(), token.line, token.col)); + tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col)); } }; @@ -107,66 +103,60 @@ impl Parser { //"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)), } - Ok(cross_ref(tokens)?) + cross_ref(tokens) } } -pub fn lookup_word>(s: String, _pos: P) -> OpType { - let lookup_table: HashMap<&str, OpType> = HashMap::from([ +pub fn lookup_word>(s: &str, _pos: P) -> OpType { + match s { //stack - ("print", OpType::Print), - ("dup", OpType::Dup), - ("drop", OpType::Drop), - ("2dup", OpType::Dup2), - ("rot", OpType::Rot), - ("over", OpType::Over), - ("swap", OpType::Swap), + "print" => OpType::Instruction(InstructionType::Print), + "dup" => OpType::Instruction(InstructionType::Dup), + "drop" => OpType::Instruction(InstructionType::Drop), + "rot" => OpType::Instruction(InstructionType::Rot), + "over" => OpType::Instruction(InstructionType::Over), + "swap" => OpType::Instruction(InstructionType::Swap), // comp and math - ("+", OpType::Plus), - ("-", OpType::Minus), - ("=", OpType::Equals), - ("!=", OpType::NotEquals), - (">", OpType::Gt), - ("<", OpType::Lt), - (">=", OpType::Ge), - ("<=", OpType::Le), + "+" => OpType::Instruction(InstructionType::Plus), + "-" => OpType::Instruction(InstructionType::Minus), + "=" => OpType::Instruction(InstructionType::Equals), + "!=" => OpType::Instruction(InstructionType::NotEquals), + ">" => OpType::Instruction(InstructionType::Gt), + "<" => OpType::Instruction(InstructionType::Lt), + ">=" => OpType::Instruction(InstructionType::Ge), + "<=" => OpType::Instruction(InstructionType::Le), - ("band", OpType::Band), - ("bor", OpType::Bor), - ("shr", OpType::Shr), - ("shl", OpType::Shl), - ("divmod", OpType::DivMod), - ("*", OpType::Mul), + "band" => OpType::Instruction(InstructionType::Band), + "bor" => OpType::Instruction(InstructionType::Bor), + "shr" => OpType::Instruction(InstructionType::Shr), + "shl" => OpType::Instruction(InstructionType::Shl), + "divmod" => OpType::Instruction(InstructionType::DivMod), + "*" => OpType::Instruction(InstructionType::Mul), // block - ("if", OpType::If), - ("else", OpType::Else), - ("end", OpType::End), - ("while", OpType::While), - ("do", OpType::Do), - ("macro", OpType::Macro), - ("include", OpType::Include), // technically not but it fits next to macros + "if" => OpType::Keyword(KeywordType::If), + "else" => OpType::Keyword(KeywordType::Else), + "end" => OpType::Keyword(KeywordType::End), + "while" => OpType::Keyword(KeywordType::While), + "do" => OpType::Keyword(KeywordType::Do), + "macro" => OpType::Keyword(KeywordType::Macro), + "include" => OpType::Keyword(KeywordType::Include), // mem - ("mem", OpType::Mem), - ("!8", OpType::Load8), - ("@8", OpType::Store8), + "mem" => OpType::Instruction(InstructionType::Mem), + "!8" => OpType::Instruction(InstructionType::Load8), + "@8" => OpType::Instruction(InstructionType::Store8), - ("syscall0", OpType::Syscall0), - ("syscall1", OpType::Syscall1), - ("syscall2", OpType::Syscall2), - ("syscall3", OpType::Syscall3), - ("syscall4", OpType::Syscall4), - ("syscall5", OpType::Syscall5), - ("syscall6", OpType::Syscall6), - ]); - - match lookup_table.get(s.as_str()) { - Some(v) => v.clone(), - None => { - OpType::None - } + "syscall0" => OpType::Instruction(InstructionType::Syscall0), + "syscall1" => OpType::Instruction(InstructionType::Syscall1), + "syscall2" => OpType::Instruction(InstructionType::Syscall2), + "syscall3" => OpType::Instruction(InstructionType::Syscall3), + "syscall4" => OpType::Instruction(InstructionType::Syscall4), + "syscall5" => OpType::Instruction(InstructionType::Syscall5), + "syscall6" => OpType::Instruction(InstructionType::Syscall6), + _ => OpType::Instruction(InstructionType::None) } + } \ No newline at end of file diff --git a/src/preprocessor.rs b/src/preprocessor.rs index 47502a0..d539ee0 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use color_eyre::Result; use eyre::eyre; -use crate::constants::{Token, Loc, OpType, TokenType}; +use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType}; use crate::lexer::lex; use crate::{lerror, lnote, Args, warn}; use crate::parser::lookup_word; @@ -15,19 +15,19 @@ pub struct Macro { pub tokens: Vec } -pub fn preprocess(tokens: Vec, args: Args) -> Result>{ +pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ let mut program: Vec = Vec::new(); let mut macros: HashMap = HashMap::new(); - let mut rtokens = tokens.clone(); + let mut rtokens = tokens; rtokens.reverse(); - while rtokens.len() > 0 { + while !rtokens.is_empty() { let token = rtokens.pop().unwrap(); - let op_type = lookup_word(token.text.clone(), &token.loc()); + let op_type = lookup_word(&token.text, &token.loc()); match token.clone() { - _ if op_type == OpType::Macro => { - if rtokens.len() == 0 { + _ if op_type == OpType::Keyword(KeywordType::Macro) => { + if rtokens.is_empty(){ lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human()); return Err(eyre!("")); } @@ -37,41 +37,36 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ lerror!(¯o_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human()); return Err(eyre!("")); } - let word = lookup_word(macro_name.text.clone(), ¯o_name.loc()); - if word != OpType::None { + let word = lookup_word(¯o_name.text, ¯o_name.loc()); + if word != OpType::Instruction(InstructionType::None) { lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human()); return Err(eyre!("")); } - if macros.get(¯o_name.text.clone()).is_some() { - if crate::constants::ALLOW_MACRO_REDEFINITION { - lerror!(¯o_name.loc(), "Macro redefinition is not allowed"); - lnote!(¯os.get(¯o_name.text.clone()).unwrap().loc, "First definition here"); - return Err(eyre!("")); - } else { - //TODO: somehow warn about redefinition of only built in macros - } + if macros.get(¯o_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION { + lerror!(¯o_name.loc(), "Macro redefinition is not allowed"); + lnote!(¯os.get(¯o_name.text).unwrap().loc, "First definition here"); + return Err(eyre!("")); } let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() }; let mut depth = 0; - while rtokens.len() > 0 { + while !rtokens.is_empty() { let t = rtokens.pop().unwrap(); - let typ = lookup_word(t.text.clone(), &t.loc()); - if typ == OpType::End && depth == 0 { + let typ = lookup_word(&t.text, &t.loc()); + if typ == OpType::Keyword(KeywordType::End) && depth == 0 { break; - } else if typ == OpType::End && depth != 0 { + } else if typ == OpType::Keyword(KeywordType::End) && depth != 0 { depth -= 1; macr.tokens.push(t); + } else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) { + macr.tokens.push(t); + depth += 1; } else { - if typ == OpType::If || typ == OpType::Do { - macr.tokens.push(t); - depth += 1; - } else { - macr.tokens.push(t); - } + macr.tokens.push(t); } + } @@ -80,8 +75,8 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ } - _ if op_type == OpType::Include => { - if rtokens.len() == 0 { + _ if op_type == OpType::Keyword(KeywordType::Include) => { + if rtokens.is_empty() { lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human()); return Err(eyre!("")); } @@ -94,7 +89,7 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ } let mut in_paths = args.include.clone(); - in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| f.to_string()).collect::>()); + in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::>()); let mut include_code = String::new(); @@ -113,7 +108,7 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ return Err(eyre!("")); } - let mut code = lex(include_code, &include_path.text, args.clone(), false)?; + let mut code = lex(&include_code, &include_path.text, args, false)?; code.reverse(); rtokens.append(&mut code); @@ -130,12 +125,12 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ let mut times = 0; while program.iter().map(|f| { if f.typ == TokenType::Word { - lookup_word(f.text.clone(), &f.loc()) + lookup_word(&f.text, &f.loc()) } else { - OpType::PushInt // i hate myself, this is a randomly picked optype so its happy and works + OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works } - }).collect::>().contains(&OpType::None){ + }).collect::>().contains(&OpType::Instruction(InstructionType::None)){ if times >= 50 { warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it"); @@ -152,18 +147,20 @@ pub fn preprocess(tokens: Vec, args: Args) -> Result>{ pub fn expand_macros(tokens: Vec, macros: &HashMap) -> Result> { let mut program: Vec = Vec::new(); - let mut rtokens = tokens.clone(); + let mut rtokens = tokens; rtokens.reverse(); - while rtokens.len() > 0 { + while !rtokens.is_empty() { let op = rtokens.pop().unwrap(); - let op_type = lookup_word(op.text.clone(), &op.loc()); + let op_type = lookup_word(&op.text, &op.loc()); if op.typ == TokenType::Word { match op_type { - OpType::None => { + OpType::Instruction(InstructionType::None) => { let m = macros.get(&op.text); if m.is_some() { - program.append(&mut m.unwrap().tokens.clone()) + if let Some(m) = m { + program.append(&mut m.tokens.clone()); + } } else { lerror!(&op.loc(), "Unknown word '{}'", op.text.clone()); return Err(eyre!(""));