Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5b51430df1 | ||
|
9625256554 |
20
.gitignore
vendored
20
.gitignore
vendored
|
@ -1,6 +1,18 @@
|
|||
/target
|
||||
/a
|
||||
/*
|
||||
|
||||
test
|
||||
test.nasm
|
||||
test.o
|
||||
# files
|
||||
!/.gitignore
|
||||
!/cargo.lock
|
||||
!/cargo.toml
|
||||
!/README.md
|
||||
|
||||
# folders
|
||||
!/.github
|
||||
!/editor
|
||||
!/examples
|
||||
!/include
|
||||
!/playground
|
||||
!/src
|
||||
!/tests
|
||||
!/tools
|
205
Cargo.lock
generated
205
Cargo.lock
generated
|
@ -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"
|
||||
|
@ -210,36 +125,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "mclang"
|
||||
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"
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
[package]
|
||||
name = "mclangc"
|
||||
description="The McLang Programming language compiler"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors=[
|
||||
"MCorange <mcorangecodes@gmail.com> (https://mcorangehq.xyz/)"
|
||||
]
|
||||
# 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"
|
||||
|
|
|
@ -18,6 +18,14 @@ This is the second revision of [MCLang](https://github.com/mc-lang/mclang) now w
|
|||
The docs are currently are just made in MarkDown.
|
||||
You can find the docs [here](/docs/index.md)
|
||||
|
||||
## Cheatsheet
|
||||
|
||||
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
|
||||
|
||||
[MCotange](https://github.com/MCorange99) - The one and only me, the creator and current maintainer or mclang rev1 and rev2
|
||||
|
|
3
examples/.gitignore
vendored
Normal file
3
examples/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/*
|
||||
!/.gitignore
|
||||
!/*.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,4 +21,9 @@ 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
|
||||
|
||||
|
||||
done
|
|
@ -13,3 +13,8 @@ const sizeof(u64) 8 end
|
|||
const sizeof(u32) 4 end
|
||||
const sizeof(u16) 2 end
|
||||
const sizeof(u8) 1 end
|
||||
|
||||
const u64 8 end
|
||||
const u32 4 end
|
||||
const u16 2 end
|
||||
const u8 1 end
|
|
@ -5,7 +5,7 @@
|
|||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||
// @arg fd: Int - file descriptor
|
||||
// @ret Int
|
||||
inline fn write with int ptr int returns int then
|
||||
inline fn fwrite with int ptr int returns int then
|
||||
SYS_write syscall3
|
||||
done
|
||||
|
||||
|
@ -15,18 +15,29 @@ done
|
|||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||
// @arg fd: Int - file descriptor
|
||||
// @ret Int
|
||||
inline fn read with int ptr int returns int then
|
||||
inline fn fread with int ptr int returns int then
|
||||
SYS_read syscall3
|
||||
done
|
||||
|
||||
|
||||
// Write to a file descriptor using the SYS_write syscall
|
||||
// args: [buff_ptr, flags, mode]
|
||||
// @arg buff_ptr: Ptr - File to open
|
||||
// @arg flags: Int - Flags
|
||||
// @arg mode: Int - Mode
|
||||
// @ret Int - Fd
|
||||
inline fn fopen with int ptr int returns int then
|
||||
SYS_open syscall3
|
||||
done
|
||||
|
||||
|
||||
// Print a string to STDOUT
|
||||
// args: [str_size, str_ptr]
|
||||
// @arg buff_size: Int - number of bytes to write
|
||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||
// @ret NULL
|
||||
inline fn puts with int ptr returns void then
|
||||
STDOUT write drop
|
||||
STDOUT fwrite drop
|
||||
done
|
||||
|
||||
// Print a string to STDERR
|
||||
|
@ -35,10 +46,10 @@ done
|
|||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||
// @ret NULL
|
||||
inline fn eputs with int ptr returns void then
|
||||
STDOUT write drop
|
||||
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]
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
|
5
include/string.mcl
Normal file
5
include/string.mcl
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
|
||||
fn cstr_len with ptr returns int then
|
||||
dup while dup load8 '\0' != do 1 + end swap -
|
||||
done
|
4
playground/.gitignore
vendored
Normal file
4
playground/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
!/.gitignore
|
||||
!/*.mcl
|
||||
!/mclangc
|
13
playground/mclangc
Executable file
13
playground/mclangc
Executable file
|
@ -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}
|
35
playground/test.mcl
Normal file
35
playground/test.mcl
Normal file
|
@ -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
|
|
@ -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");
|
||||
}
|
||||
}?;
|
||||
|
||||
|
|
|
@ -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(" "));
|
||||
|
|
|
@ -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<i32>{
|
||||
pub fn compile(program: &Program, args: &Args) -> Result<i32>{
|
||||
let debug = args.get_opt_level()? < 1;
|
||||
|
||||
let mut of_c = PathBuf::from(&args.out_file);
|
||||
|
@ -32,60 +32,30 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
let mut memories: Vec<Memory> = Vec::new();
|
||||
let mut constants: HashMap<String, Constant> = HashMap::new();
|
||||
let mut functions: Vec<Function> = Vec::new();
|
||||
|
||||
let mut alloced_structs: Vec<(String, String)> = Vec::new();
|
||||
// println!("{}", tokens.len());
|
||||
let mut strings: Vec<String> = Vec::new();
|
||||
|
||||
writeln!(writer, "BITS 64")?;
|
||||
writeln!(writer, "segment .text")?;
|
||||
|
||||
writeln!(writer, "_dbg_print:")?;
|
||||
writeln!(writer, " mov r9, -3689348814741910323")?;
|
||||
writeln!(writer, " sub rsp, 40")?;
|
||||
writeln!(writer, " mov BYTE [rsp+31], 10")?;
|
||||
writeln!(writer, " lea rcx, [rsp+30]")?;
|
||||
writeln!(writer, ".L2:")?;
|
||||
writeln!(writer, " mov rax, rdi")?;
|
||||
writeln!(writer, " lea r8, [rsp+32]")?;
|
||||
writeln!(writer, " mul r9")?;
|
||||
writeln!(writer, " mov rax, rdi")?;
|
||||
writeln!(writer, " sub r8, rcx")?;
|
||||
writeln!(writer, " shr rdx, 3")?;
|
||||
writeln!(writer, " lea rsi, [rdx+rdx*4]")?;
|
||||
writeln!(writer, " add rsi, rsi")?;
|
||||
writeln!(writer, " sub rax, rsi")?;
|
||||
writeln!(writer, " add eax, 48")?;
|
||||
writeln!(writer, " mov BYTE [rcx], al")?;
|
||||
writeln!(writer, " mov rax, rdi")?;
|
||||
writeln!(writer, " mov rdi, rdx")?;
|
||||
writeln!(writer, " mov rdx, rcx")?;
|
||||
writeln!(writer, " sub rcx, 1")?;
|
||||
writeln!(writer, " cmp rax, 9")?;
|
||||
writeln!(writer, " ja .L2")?;
|
||||
writeln!(writer, " lea rax, [rsp+32]")?;
|
||||
writeln!(writer, " mov edi, 1")?;
|
||||
writeln!(writer, " sub rdx, rax")?;
|
||||
writeln!(writer, " xor eax, eax")?;
|
||||
writeln!(writer, " lea rsi, [rsp+32+rdx]")?;
|
||||
writeln!(writer, " mov rdx, r8")?;
|
||||
writeln!(writer, " mov rax, 1")?;
|
||||
writeln!(writer, " syscall")?;
|
||||
writeln!(writer, " add rsp, 40")?;
|
||||
writeln!(writer, " ret")?;
|
||||
writeln!(writer, "{}", super::MACRO_DEFINITIONS)?;
|
||||
writeln!(writer, "{}", super::DBG_PRINT)?;
|
||||
|
||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||
|
||||
if !crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||
writeln!(writer, "global _start")?;
|
||||
writeln!(writer, "_start:")?;
|
||||
writeln!(writer, " lea rbp, [rel ret_stack]")?;
|
||||
writeln!(writer, " call main")?;
|
||||
writeln!(writer, " jmp end")?;
|
||||
|
||||
}
|
||||
|
||||
|
||||
let mut ti = 0;
|
||||
while ti < tokens.len() {
|
||||
let token = &tokens[ti];
|
||||
// println!("{:?}", token);
|
||||
while ti < program.ops.len() {
|
||||
let token = &program.ops[ti];
|
||||
if debug {
|
||||
writeln!(writer, "addr_{ti}:")?;
|
||||
if token.typ == OpType::Instruction(InstructionType::PushInt) {
|
||||
|
@ -97,13 +67,13 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
}
|
||||
} 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}:")?;
|
||||
}
|
||||
|
||||
|
@ -116,299 +86,168 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
_ => ()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
match token.typ.clone() {
|
||||
// stack
|
||||
|
||||
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, " 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 bl, 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], bl")?;
|
||||
InstructionType::Write32 => {
|
||||
writeln!(writer, " OP_Store32")?;
|
||||
ti += 1;
|
||||
}
|
||||
InstructionType::Load64 => {
|
||||
writeln!(writer, " pop rax")?;
|
||||
writeln!(writer, " xor rbx, rbx")?;
|
||||
writeln!(writer, " mov bl, 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], bl")?;
|
||||
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 => {
|
||||
|
@ -416,11 +255,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
unreachable!()
|
||||
},
|
||||
InstructionType::FnCall => {
|
||||
writeln!(writer, " call {}", token.text)?;
|
||||
writeln!(writer, " OP_FnCall {}", token.text)?;
|
||||
ti += 1;
|
||||
},
|
||||
InstructionType::Return => {
|
||||
|
||||
// Experimental feature exported functions
|
||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret {
|
||||
writeln!(writer, " pop rdx")?;
|
||||
should_push_ret = false;
|
||||
|
@ -446,8 +286,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
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;
|
||||
|
@ -455,6 +294,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
constants.insert(token.text.clone(), c);
|
||||
ti += 1;
|
||||
},
|
||||
InstructionType::StructUse => {
|
||||
writeln!(writer, " OP_StructUse {}", token.text)?;
|
||||
ti += 1;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,7 +322,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
}
|
||||
KeywordType::End => {
|
||||
if ti + 1 != token.jmp {
|
||||
// writeln!(writer, " jmp addr_{}", token.jmp)?;
|
||||
writeln!(writer, " jmp addr_{}", token.jmp)?;
|
||||
}
|
||||
ti += 1;
|
||||
},
|
||||
|
@ -523,16 +366,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
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)?;
|
||||
|
@ -565,7 +403,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
}
|
||||
if token.types.0 >= 7 {
|
||||
lerror!(&token.loc, "More than 6 arguments in an external function is not supported");
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,18 +411,33 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
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}:")?;
|
||||
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||
if !crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||
writeln!(writer, "end:")?;
|
||||
writeln!(writer, " mov rax, 60")?;
|
||||
writeln!(writer, " mov rdi, 0")?;
|
||||
|
@ -609,16 +462,37 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
} 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:?}");
|
||||
// }
|
||||
|
@ -631,7 +505,8 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
|||
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);
|
||||
|
@ -654,7 +529,7 @@ fn pre_compile_steps(_code: &str, functions: Vec<Function>) -> Result<()> {
|
|||
|
||||
if !has_main {
|
||||
crate::errors::missing_main_fn();
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::constants::Loc;
|
||||
use crate::definitions::Loc;
|
||||
|
||||
pub mod linux_x86_64;
|
||||
pub mod commands;
|
||||
|
@ -26,3 +26,337 @@ pub struct Function {
|
|||
pub name: String,
|
||||
pub exter: bool,
|
||||
}
|
||||
|
||||
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
|
||||
";
|
|
@ -1,25 +1,15 @@
|
|||
/**
|
||||
* 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;1] = [
|
||||
pub const DEFAULT_INCLUDES: [&str;2] = [
|
||||
"./include",
|
||||
// "~/.mclang/include",
|
||||
"~/.mclang/include",
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Interpreting configs
|
||||
* `MEM_SZ` is the buffer size for memory
|
||||
* `STRING_SZ` is the buffer size for strings
|
||||
* if you have buffer overflow consider increasing these
|
||||
*/
|
||||
pub const MEM_SZ: usize = 640 * 1000; // 4kb
|
||||
pub const STRING_SZ: usize = 640 * 1000; // 4kb
|
||||
|
||||
|
||||
/**
|
||||
* Experimental options
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@ pub enum InstructionType {
|
|||
// stack
|
||||
PushInt,
|
||||
PushStr,
|
||||
PushCStr,
|
||||
Drop,
|
||||
Print,
|
||||
Dup,
|
||||
|
@ -32,12 +33,12 @@ pub enum InstructionType {
|
|||
|
||||
|
||||
// mem
|
||||
Load8,
|
||||
Store8,
|
||||
Load32,
|
||||
Store32,
|
||||
Load64,
|
||||
Store64,
|
||||
Read8,
|
||||
Write8,
|
||||
Read32,
|
||||
Write32,
|
||||
Read64,
|
||||
Write64,
|
||||
|
||||
// syscalls
|
||||
Syscall0,
|
||||
|
@ -88,7 +89,8 @@ pub enum KeywordType {
|
|||
FunctionThen,
|
||||
FunctionDone,
|
||||
Inline,
|
||||
Export
|
||||
Export,
|
||||
Struct
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
|
@ -142,6 +144,7 @@ impl OpType {
|
|||
|
||||
InstructionType::PushInt => "Number",
|
||||
InstructionType::PushStr => "String",
|
||||
InstructionType::PushCStr => "CString",
|
||||
InstructionType::Print => "_dbg_print",
|
||||
InstructionType::Dup => "dup",
|
||||
InstructionType::Drop => "drop",
|
||||
|
@ -162,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",
|
||||
|
@ -211,6 +214,7 @@ impl OpType {
|
|||
KeywordType::FunctionDefExported => "extern function definition (internal)",
|
||||
KeywordType::Inline => "inline",
|
||||
KeywordType::Export => "export",
|
||||
KeywordType::Struct => "struct",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,6 +239,7 @@ pub enum TokenType {
|
|||
Word,
|
||||
Int,
|
||||
String,
|
||||
CString,
|
||||
Char
|
||||
}
|
||||
|
||||
|
@ -254,6 +259,7 @@ impl TokenType {
|
|||
TokenType::Word => "Word",
|
||||
TokenType::Int => "Int",
|
||||
TokenType::String => "String",
|
||||
TokenType::CString => "CString",
|
||||
TokenType::Char => "Char"
|
||||
}.to_string()
|
||||
}
|
||||
|
|
392
src/definitions/mod.rs
Normal file
392
src/definitions/mod.rs
Normal file
|
@ -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<usize>, //? only used for OpType::PushStr
|
||||
pub jmp: usize,
|
||||
pub loc: Loc,
|
||||
pub types: (usize, usize)
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
||||
Self {
|
||||
typ,
|
||||
value,
|
||||
jmp: 0,
|
||||
addr: None,
|
||||
text,
|
||||
loc: (file, row, col),
|
||||
tok_typ,
|
||||
types: (0, 0)
|
||||
}
|
||||
}
|
||||
pub fn set_addr(&mut self, addr: usize) -> Self {
|
||||
self.addr = Some(addr);
|
||||
(*self).clone()
|
||||
}
|
||||
|
||||
// pub fn set_types(&mut self, args: usize, rets: usize) -> Self {
|
||||
// self.types = (args, rets);
|
||||
// (*self).clone()
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
impl OpType {
|
||||
pub fn human(&self) -> String {
|
||||
match (*self).clone() {
|
||||
OpType::Instruction(instruction) => {
|
||||
match instruction {
|
||||
|
||||
InstructionType::PushInt => "Number",
|
||||
InstructionType::PushStr => "String",
|
||||
InstructionType::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<usize>, //* only used for Memories
|
||||
pub addr: Option<usize>, //* only used for Memories
|
||||
pub op_typ: OpType //* only used for Memories
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum TokenType {
|
||||
Word,
|
||||
Int,
|
||||
String,
|
||||
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<S: Into<String> + std::fmt::Display>(s: &S) -> Result<Self> {
|
||||
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<Vec<Operator>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Constant {
|
||||
pub loc: Loc,
|
||||
pub name: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Memory {
|
||||
pub loc: Loc,
|
||||
pub id: usize
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StructDef {
|
||||
pub loc: Loc,
|
||||
pub name: String,
|
||||
pub fields: Vec<(String, Types)>
|
||||
}
|
||||
|
||||
pub type Functions = HashMap<String, Function>;
|
||||
pub type Memories = HashMap<String, Memory>;
|
||||
pub type Constants = HashMap<String, Constant>;
|
||||
pub type StructDefs = HashMap<String, StructDef>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Program {
|
||||
pub ops: Vec<Operator>,
|
||||
pub functions: Functions,
|
||||
pub memories: Memories,
|
||||
pub constants: Constants,
|
||||
pub struct_defs: StructDefs,
|
||||
pub struct_allocs: HashMap<String, String>
|
||||
}
|
|
@ -64,6 +64,23 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|||
}
|
||||
|
||||
|
||||
ip += 1;
|
||||
},
|
||||
InstructionType::PushCStr => {
|
||||
if op.addr.is_none() {
|
||||
stack.push(string_idx + crate::MEM_SZ);
|
||||
|
||||
for c in op.text.bytes() {
|
||||
mem[crate::MEM_SZ + string_idx] = u64::from(c);
|
||||
string_idx += 1;
|
||||
}
|
||||
} else {
|
||||
if let Some(addr) = op.addr {
|
||||
stack.push(addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ip += 1;
|
||||
},
|
||||
InstructionType::Drop => {
|
||||
|
@ -109,11 +126,11 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|||
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 {
|
||||
if a > crate::MEM_SZ + crate::STRING_SZ {
|
||||
lerror!(&op.loc, "Invalid memory address {a}");
|
||||
return Ok(1);
|
||||
}
|
||||
|
@ -122,7 +139,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|||
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)?;
|
||||
|
||||
|
@ -135,7 +152,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|||
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)?;
|
||||
|
||||
|
@ -149,7 +166,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
|||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
InstructionType::Store64 => {
|
||||
InstructionType::Write64 => {
|
||||
let val = stack_pop(&mut stack, &pos)?;
|
||||
let addr = stack_pop(&mut stack, &pos)?;
|
||||
|
||||
|
|
25
src/lexer.rs
25
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 {
|
||||
|
@ -12,6 +12,9 @@ fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
|
|||
s if tok_type == TokenType::String => {
|
||||
(TokenType::String, s)
|
||||
}
|
||||
s if tok_type == TokenType::CString => {
|
||||
(TokenType::CString, s)
|
||||
}
|
||||
s if tok_type == TokenType::Char => {
|
||||
(TokenType::Char, s)
|
||||
}
|
||||
|
@ -72,6 +75,23 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
|
|||
|
||||
} else {
|
||||
|
||||
if &text[col..=col] == "c" && text.len() - 1 + col > 0 && &text[col+1..=col+1] == "\"" {
|
||||
col_end = find_col(text, col + 2, |x, x2| x == '"' && x2 != '\\');
|
||||
let t = &text[(col + 2)..col_end];
|
||||
let mut t = t.replace("\\n", "\n")
|
||||
.replace("\\t", "\t")
|
||||
.replace("\\r", "\r")
|
||||
.replace("\\\'", "\'")
|
||||
.replace("\\\"", "\"")
|
||||
.replace("\\0", "\0");
|
||||
|
||||
if !t.is_empty() {
|
||||
t.push('\0');
|
||||
tokens.push((col, t.to_string(), TokenType::CString));
|
||||
}
|
||||
col = find_col(text, col_end + 1, |x, _| !x.is_whitespace());
|
||||
|
||||
} else {
|
||||
col_end = find_col(text, col, |x, _| x.is_whitespace());
|
||||
let t = &text[col..col_end];
|
||||
|
||||
|
@ -85,6 +105,7 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
|
|||
col = find_col(text, col_end, |x, _| !x.is_whitespace());
|
||||
}
|
||||
}
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
||||
|
@ -110,7 +131,7 @@ pub fn lex(code: &str, file: &str, _args: &Args) -> Vec<Token> {
|
|||
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);
|
||||
}
|
||||
|
|
38
src/main.rs
38
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, version, about, long_about = None)]
|
||||
#[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);
|
||||
}
|
||||
|
|
|
@ -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<Operator>) -> Result<Vec<Operator>> {
|
||||
let mut stack: Vec<usize> = Vec::new();
|
||||
|
@ -18,11 +17,11 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
|||
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<Operator>) -> Result<Vec<Operator>> {
|
|||
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<Operator>) -> Result<Vec<Operator>> {
|
|||
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<Operator>) -> Result<Vec<Operator>> {
|
|||
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;
|
||||
|
@ -70,8 +69,9 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
|||
}
|
||||
if !stack.is_empty() {
|
||||
// println!("{:?}", stack);
|
||||
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block, {:?}", program[stack.pop().expect("Empy stack")].clone());
|
||||
return Err(eyre!("Unclosed block"));
|
||||
let i = stack.pop().expect("Empy stack");
|
||||
lerror!(&program[i].clone().loc,"Unclosed block, {:?}", program[i].clone());
|
||||
bail!("Unclosed block")
|
||||
}
|
||||
|
||||
Ok(program.clone())
|
||||
|
@ -97,7 +97,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse(&mut self) -> Result<Vec<Operator>> {
|
||||
pub fn parse(&mut self) -> Result<Program> {
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
for token in &self.tokens {
|
||||
|
@ -120,12 +120,15 @@ impl<'a> Parser<'a> {
|
|||
},
|
||||
TokenType::String => {
|
||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), token.typ, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||
}
|
||||
},
|
||||
TokenType::CString => {
|
||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushCStr), token.typ, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||
},
|
||||
TokenType::Char => {
|
||||
let c = token.text.clone();
|
||||
if c.len() != 1 {
|
||||
lerror!(&token.loc(), "Chars can only be of lenght 1, got {}", c.len());
|
||||
return Err(eyre!(""));
|
||||
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));
|
||||
|
@ -134,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)
|
||||
}
|
||||
|
@ -176,12 +179,12 @@ pub fn lookup_word<P: Deref<Target = Loc>>(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),
|
||||
|
@ -208,6 +211,7 @@ pub fn lookup_word<P: Deref<Target = Loc>>(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),
|
||||
|
@ -216,6 +220,9 @@ pub fn lookup_word<P: Deref<Target = Loc>>(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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<usize>, loc: &Loc) -> Result<usize> {
|
||||
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<Operator>) -> Result<Vec<usize>>{
|
|||
_ => {
|
||||
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:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,49 +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<Vec<Operator>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Constant {
|
||||
pub loc: Loc,
|
||||
pub name: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Memory {
|
||||
pub loc: Loc,
|
||||
pub id: usize
|
||||
|
||||
}
|
||||
|
||||
type Functions = HashMap<String, Function>;
|
||||
type Memories = HashMap<String, Memory>;
|
||||
type Constants = HashMap<String, Constant>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Preprocessor<'a> {
|
||||
pub program: Vec<Operator>,
|
||||
pub functions: Functions,
|
||||
pub memories: Memories,
|
||||
pub constants: Constants,
|
||||
args: &'a Args
|
||||
pub program: Program,
|
||||
in_function: Option<String>,
|
||||
args: &'a Args,
|
||||
f_inline: bool,
|
||||
f_export: bool,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> Preprocessor<'a> {
|
||||
pub fn new(prog: Vec<Operator>, args: &'a Args) -> Self {
|
||||
Self {
|
||||
program: prog,
|
||||
args,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,29 +45,103 @@ 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::<Vec<Option<&Operator>>>());
|
||||
|
||||
let mut f_inline = false;
|
||||
let mut f_extern = false;
|
||||
|
||||
let mut program: Vec<Operator> = Vec::new();
|
||||
|
||||
let mut rtokens = self.program.clone();
|
||||
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) => {
|
||||
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 self.f_export {
|
||||
lerror!(&op.loc, "Function is already marked as exported, function cannot be inline and exported at the same time");
|
||||
bail!("");
|
||||
} else if self.f_inline {
|
||||
lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword");
|
||||
bail!("");
|
||||
} else {
|
||||
self.f_inline = true;
|
||||
}
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Export) => {
|
||||
if !crate::config::ENABLE_EXPORTED_FUNCTIONS {
|
||||
lerror!(&op.loc, "Experimental feature Exported functions not enabled");
|
||||
bail!("");
|
||||
}
|
||||
if self.f_inline {
|
||||
lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and exported at the same time");
|
||||
bail!("");
|
||||
} else if self.f_export {
|
||||
lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword");
|
||||
bail!("");
|
||||
} else {
|
||||
self.f_export = true;
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
program.push(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
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::<Vec<Option<&Operator>>>());
|
||||
//* Feel free to fix this horrifying shit
|
||||
//* i wanna kms
|
||||
let mut times = 0;
|
||||
// dbg!(program.clone());
|
||||
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
|
||||
}
|
||||
|
||||
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
|
||||
|
||||
if times >= 50 {
|
||||
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
|
||||
break
|
||||
}
|
||||
self.expand()?;
|
||||
times += 1;
|
||||
}
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
|
||||
fn handle_include(&mut self, rtokens: &mut Vec<Operator>, op: &mut Operator) -> Result<()> {
|
||||
if rtokens.is_empty() {
|
||||
lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
|
||||
return Err(eyre!(""));
|
||||
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());
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
|
||||
let mut in_paths = self.args.include.clone();
|
||||
|
@ -94,7 +149,7 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
let mut include_code = String::new();
|
||||
let mut pth = PathBuf::new();
|
||||
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
|
||||
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);
|
||||
|
@ -108,6 +163,7 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
if p.exists() {
|
||||
include_code = std::fs::read_to_string(p)?;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -115,7 +171,7 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
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!(""));
|
||||
bail!("");
|
||||
}
|
||||
let a = pth.to_str().unwrap().to_string();
|
||||
let code = lex(&include_code, a.as_str(), self.args);
|
||||
|
@ -125,16 +181,15 @@ impl<'a> Preprocessor<'a> {
|
|||
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);
|
||||
|
||||
|
||||
code.ops.reverse();
|
||||
rtokens.append(&mut code.ops);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Memory) => {
|
||||
fn handle_memory(&mut self, rtokens: &mut Vec<Operator>, op: &mut Operator, program: &mut Vec<Operator>) -> Result<()> {
|
||||
if rtokens.is_empty() {
|
||||
lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
|
||||
let name = rtokens.pop().unwrap();
|
||||
|
@ -164,27 +219,27 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
if res.len() != 1 {
|
||||
lerror!(&op.loc, "Expected 1 number, got {:?}", res);
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
op.value = res[0];
|
||||
op.addr = Some(self.memories.len());
|
||||
op.addr = Some(self.program.memories.len());
|
||||
program.push(op.clone());
|
||||
|
||||
self.memories.insert(name.text, Memory { loc: op.loc, id: self.memories.len() });
|
||||
|
||||
self.program.memories.insert(name.text, Memory { loc: op.loc.clone(), id: self.program.memories.len() });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Function) => {
|
||||
fn handle_function(&mut self, rtokens: &mut Vec<Operator>, op: &mut Operator, program: &mut Vec<Operator>) -> Result<()> {
|
||||
if rtokens.is_empty() {
|
||||
lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
|
||||
return Err(eyre!(""));
|
||||
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");
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
|
||||
// let mut should_warn = false;
|
||||
|
@ -199,7 +254,7 @@ impl<'a> Preprocessor<'a> {
|
|||
}
|
||||
_ => {
|
||||
lerror!(&name.loc, "Function name contains '{c}', which is unsupported");
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,8 +266,8 @@ impl<'a> Preprocessor<'a> {
|
|||
self.is_word_available(&name, KeywordType::Function)?;
|
||||
|
||||
|
||||
if f_inline {
|
||||
f_inline = false;
|
||||
if self.f_inline {
|
||||
self.f_inline = false;
|
||||
let mut prog: Vec<Operator> = Vec::new();
|
||||
let mut depth = -1;
|
||||
while !rtokens.is_empty() {
|
||||
|
@ -257,23 +312,27 @@ impl<'a> Preprocessor<'a> {
|
|||
_ => prog.push(op)
|
||||
}
|
||||
}
|
||||
_ => prog.push(op)
|
||||
}
|
||||
}
|
||||
let mut pre = self.clone();
|
||||
pre.program = prog;
|
||||
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.functions.insert(name.text.clone(), Function{
|
||||
self.program.functions.insert(name.text.clone(), Function{
|
||||
loc: name.loc.clone(),
|
||||
name: name.text.clone(),
|
||||
inline: true,
|
||||
tokens: Some(prog)
|
||||
});
|
||||
|
||||
} else if f_extern {
|
||||
f_extern = false;
|
||||
self.functions.insert(name.text.clone(), Function{
|
||||
} 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,
|
||||
|
@ -317,7 +376,7 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
} else {
|
||||
|
||||
self.functions.insert(name.text.clone(), Function{
|
||||
self.program.functions.insert(name.text.clone(), Function{
|
||||
loc: name.loc.clone(),
|
||||
name: name.text.clone(),
|
||||
inline: false,
|
||||
|
@ -330,21 +389,19 @@ impl<'a> Preprocessor<'a> {
|
|||
// println!("{:?}", token);
|
||||
program.push(fn_def);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Constant) => {
|
||||
if rtokens.is_empty() {
|
||||
fn handle_constant(&mut self, rtokens: &mut Vec<Operator>, op: &mut Operator, program: &mut Vec<Operator>) -> Result<()> {
|
||||
let Some(mut name) = rtokens.pop() else {
|
||||
lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
|
||||
return Err(eyre!(""));
|
||||
}
|
||||
// println!("{token:?}");
|
||||
bail!("");
|
||||
};
|
||||
|
||||
let mut name = rtokens.pop().unwrap();
|
||||
// let mut should_warn = false;
|
||||
|
||||
if let '0'..='9' = name.text.chars().next().unwrap() {
|
||||
lerror!(&name.loc, "Constant name starts with a number which is not allowed");
|
||||
return Err(eyre!(""));
|
||||
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() {
|
||||
|
@ -359,10 +416,11 @@ impl<'a> Preprocessor<'a> {
|
|||
}
|
||||
_ => {
|
||||
lerror!(&name.loc, "Constant name contains '{c}', which is unsupported");
|
||||
return Err(eyre!(""));
|
||||
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 ");
|
||||
|
@ -371,12 +429,12 @@ impl<'a> Preprocessor<'a> {
|
|||
self.is_word_available(&name, KeywordType::Constant)?;
|
||||
|
||||
|
||||
self.constants.insert(name.text.clone(), Constant{
|
||||
self.program.constants.insert(name.text.clone(), Constant{
|
||||
loc: name.loc.clone(),
|
||||
name: name.text.clone(),
|
||||
});
|
||||
|
||||
// println!("{:?}", self.constants);
|
||||
// println!("{:?}", self.program.constants);
|
||||
|
||||
let mut const_def = op.clone();
|
||||
const_def.typ = OpType::Keyword(KeywordType::ConstantDef);
|
||||
|
@ -387,95 +445,140 @@ impl<'a> Preprocessor<'a> {
|
|||
const_def.value = item.value;
|
||||
} else {
|
||||
lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int);
|
||||
return Err(eyre!(""));
|
||||
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");
|
||||
return Err(eyre!(""));
|
||||
bail!("");
|
||||
}
|
||||
// token.value =
|
||||
|
||||
program.push(const_def);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Inline) => {
|
||||
if f_extern {
|
||||
lerror!(&op.loc, "Function is already marked as extern, function cannot be inline and extern at the same time");
|
||||
return Err(eyre!(""));
|
||||
} else if f_inline {
|
||||
lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword");
|
||||
return Err(eyre!(""));
|
||||
fn handle_struct(&mut self, rtokens: &mut Vec<Operator>, op: &mut Operator, program: &mut Vec<Operator>) -> 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 {
|
||||
f_inline = true;
|
||||
}
|
||||
lerror!(&name.loc, "Expected keyword 'do' but found nothing");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
OpType::Keyword(KeywordType::Export) => {
|
||||
if f_inline {
|
||||
lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and extern at the same time");
|
||||
return Err(eyre!(""));
|
||||
} else if f_extern {
|
||||
lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword");
|
||||
return Err(eyre!(""));
|
||||
} else {
|
||||
f_extern = true;
|
||||
}
|
||||
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' |
|
||||
'_' => (),
|
||||
_ => {
|
||||
program.push(op);
|
||||
lerror!(&fl_name.loc, "Struct field name contains '{c}', which is unsupported");
|
||||
bail!("");
|
||||
}
|
||||
}
|
||||
}
|
||||
self.program = program;
|
||||
// println!("has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
||||
//* Feel free to fix this horrifying shit
|
||||
//* i wanna kms
|
||||
let mut times = 0;
|
||||
// dbg!(program.clone());
|
||||
while self.program.iter().map(|f| {
|
||||
if f.tok_typ == TokenType::Word &&
|
||||
f.typ != OpType::Instruction(InstructionType::FnCall) &&
|
||||
f.typ != OpType::Instruction(InstructionType::MemUse) &&
|
||||
f.typ != OpType::Keyword(KeywordType::FunctionDef) &&
|
||||
f.typ != OpType::Keyword(KeywordType::FunctionDefExported) &&
|
||||
f.typ != OpType::Keyword(KeywordType::ConstantDef) &&
|
||||
f.typ != OpType::Instruction(InstructionType::ConstUse) {
|
||||
lookup_word(&f.text, &f.loc)
|
||||
|
||||
if let Some(arrow) = rtokens.pop() {
|
||||
if arrow.typ != OpType::Internal(InternalType::Arrow) {
|
||||
lerror!(&arrow.loc, "Expected '->' but found {:?}", arrow.typ);
|
||||
bail!("");
|
||||
}
|
||||
} else {
|
||||
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
|
||||
lerror!(&fl_name.loc, "Expected '->' but found nothing");
|
||||
bail!("");
|
||||
}
|
||||
|
||||
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
|
||||
|
||||
if times >= 50 {
|
||||
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
|
||||
break
|
||||
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.expand()?;
|
||||
times += 1;
|
||||
|
||||
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(self)
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn expand(&mut self) -> Result<()> {
|
||||
let mut program: Vec<Operator> = 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());
|
||||
|
@ -489,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::<Vec<String>>();
|
||||
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!("");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
@ -519,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::<Vec<Option<&Operator>>>());
|
||||
|
||||
self.program = program;
|
||||
self.program.ops = program;
|
||||
// println!("{:#?}", self.program);
|
||||
// println!("{:?}", self.program.last().unwrap());
|
||||
Ok(())
|
||||
|
@ -528,13 +646,14 @@ impl<'a> Preprocessor<'a> {
|
|||
|
||||
|
||||
pub fn get_ops(&mut self) -> Vec<Operator> {
|
||||
self.program.clone()
|
||||
self.program.ops.clone()
|
||||
}
|
||||
pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result<bool> {
|
||||
|
||||
match typ {
|
||||
KeywordType::Memory |
|
||||
KeywordType::Constant |
|
||||
KeywordType::Struct |
|
||||
KeywordType::Function => (),
|
||||
_ => panic!()
|
||||
}
|
||||
|
@ -542,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()
|
||||
}
|
||||
}
|
|
@ -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<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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,23 +180,27 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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::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])?;
|
||||
|
@ -231,9 +234,9 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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 |
|
||||
|
@ -241,76 +244,76 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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])?;
|
||||
|
@ -322,7 +325,7 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
},
|
||||
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])?;
|
||||
|
@ -336,7 +339,7 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
|
||||
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());
|
||||
|
@ -350,11 +353,11 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
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!("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,8 +377,10 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
let mut c = constants.get(&op.text).unwrap().clone();
|
||||
stack.append(&mut c.types);
|
||||
},
|
||||
InstructionType::StructUse => todo!(),
|
||||
}
|
||||
},
|
||||
OpType::Internal(t) => panic!("{t:?}"),
|
||||
|
||||
}
|
||||
|
||||
|
@ -390,13 +395,13 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
|||
fn stack_pop(v: &mut Vec<Types>, op: &Operator, t: &[Types]) -> Result<Types> {
|
||||
if v.is_empty() {
|
||||
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
|
||||
return Err(eyre!(""));
|
||||
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)
|
||||
|
|
392
src/types.rs
Normal file
392
src/types.rs
Normal file
|
@ -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<usize>, //? only used for OpType::PushStr
|
||||
pub jmp: usize,
|
||||
pub loc: Loc,
|
||||
pub types: (usize, usize)
|
||||
}
|
||||
|
||||
impl Operator {
|
||||
pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
||||
Self {
|
||||
typ,
|
||||
value,
|
||||
jmp: 0,
|
||||
addr: None,
|
||||
text,
|
||||
loc: (file, row, col),
|
||||
tok_typ,
|
||||
types: (0, 0)
|
||||
}
|
||||
}
|
||||
pub fn set_addr(&mut self, addr: usize) -> Self {
|
||||
self.addr = Some(addr);
|
||||
(*self).clone()
|
||||
}
|
||||
|
||||
// pub fn set_types(&mut self, args: usize, rets: usize) -> Self {
|
||||
// self.types = (args, rets);
|
||||
// (*self).clone()
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
impl OpType {
|
||||
pub fn human(&self) -> String {
|
||||
match (*self).clone() {
|
||||
OpType::Instruction(instruction) => {
|
||||
match instruction {
|
||||
|
||||
InstructionType::PushInt => "Number",
|
||||
InstructionType::PushStr => "String",
|
||||
InstructionType::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<usize>, //* only used for Memories
|
||||
pub addr: Option<usize>, //* only used for Memories
|
||||
pub op_typ: OpType //* only used for Memories
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||
pub enum TokenType {
|
||||
Word,
|
||||
Int,
|
||||
String,
|
||||
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<Types> for &str {
|
||||
type Error = color_eyre::eyre::Error;
|
||||
|
||||
fn try_into(self) -> Result<Types, Self::Error> {
|
||||
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<Types> for String {
|
||||
type Error = color_eyre::eyre::Error;
|
||||
|
||||
fn try_into(self) -> Result<Types, Self::Error> {
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Function {
|
||||
pub loc: Loc,
|
||||
pub name: String,
|
||||
pub inline: bool,
|
||||
pub tokens: Option<Vec<Operator>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Constant {
|
||||
pub loc: Loc,
|
||||
pub name: String
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Memory {
|
||||
pub loc: Loc,
|
||||
pub id: usize
|
||||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StructDef {
|
||||
pub loc: Loc,
|
||||
pub name: String,
|
||||
pub fields: HashSet<(String, Types)>
|
||||
}
|
||||
|
||||
pub type Functions = HashMap<String, Function>;
|
||||
pub type Memories = HashMap<String, Memory>;
|
||||
pub type Constants = HashMap<String, Constant>;
|
||||
pub type StructDefs = HashMap<String, StructDef>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Program {
|
||||
pub ops: Vec<Operator>,
|
||||
pub functions: Functions,
|
||||
pub memories: Memories,
|
||||
pub constants: Constants,
|
||||
pub struct_defs: StructDefs
|
||||
}
|
29
src/types/common/loc.rs
Normal file
29
src/types/common/loc.rs
Normal file
|
@ -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<String> for Loc {
|
||||
fn into(self) -> String {
|
||||
self.to_string()
|
||||
}
|
||||
}
|
4
src/types/common/mod.rs
Normal file
4
src/types/common/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
mod loc;
|
||||
|
||||
|
||||
pub use loc::*;
|
4
src/types/mod.rs
Normal file
4
src/types/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
|
||||
pub mod common;
|
||||
pub mod token;
|
65
src/types/token.rs
Normal file
65
src/types/token.rs
Normal file
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
|
|
19
test.mcl
19
test.mcl
|
@ -1,12 +1,13 @@
|
|||
// include "std.mcl"
|
||||
fn mcl_print with int ptr returns void then
|
||||
1 1 syscall3 drop
|
||||
done
|
||||
include "std.mcl"
|
||||
|
||||
fn mcl_dump with int returns void then
|
||||
_dbg_print
|
||||
done
|
||||
|
||||
fn main with void returns void then
|
||||
"hi\n" mcl_print
|
||||
fn main with int ptr returns void then
|
||||
// p l
|
||||
"Hello!\n" puts
|
||||
|
||||
// memory fd 4 end
|
||||
|
||||
// c"./test.mcl" FS_O_SYNC 0 fopen
|
||||
// dup _dbg_print
|
||||
// fd swap write32
|
||||
done
|
4
tools/.gitignore
vendored
Normal file
4
tools/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
!/.gitignore
|
||||
!/*.c
|
||||
!/build_tools.sh
|
3
tools/build_tools.sh
Normal file
3
tools/build_tools.sh
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
gcc intcnv.c -o intcnv
|
47
tools/intcnv.c
Normal file
47
tools/intcnv.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user