Decide on an optimization strategy for the VM
This commit is contained in:
parent
5030171bb6
commit
07f8b36c99
204
Cargo.lock
generated
204
Cargo.lock
generated
@ -11,6 +11,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "annotate-snippets"
|
||||
version = "0.11.5"
|
||||
@ -18,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"unicode-width 0.2.0",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -80,17 +86,6 @@ dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@ -103,12 +98,6 @@ version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.8.0"
|
||||
@ -143,21 +132,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"textwrap",
|
||||
"unicode-width 0.1.14",
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.28"
|
||||
version = "4.5.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff"
|
||||
checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@ -165,9 +170,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.27"
|
||||
version = "4.5.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
|
||||
checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@ -218,24 +223,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.3.6"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"anes",
|
||||
"cast",
|
||||
"clap 2.34.0",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"csv",
|
||||
"is-terminal",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_cbor",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
@ -244,9 +249,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.4.5"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
@ -293,31 +298,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.1"
|
||||
name = "crunchy"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.11"
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dust-cli"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"clap 4.5.28",
|
||||
"clap",
|
||||
"dust-lang",
|
||||
"postcard",
|
||||
"ron",
|
||||
@ -381,9 +380,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "1.8.3"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
|
||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
@ -422,12 +425,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
@ -439,6 +439,17 @@ dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
@ -520,6 +531,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@ -592,6 +609,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
@ -705,7 +728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bitflags 2.8.0",
|
||||
"bitflags",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
]
|
||||
@ -725,7 +748,7 @@ version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags 2.8.0",
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@ -774,16 +797,6 @@ dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_cbor"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
|
||||
dependencies = [
|
||||
"half",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
@ -831,9 +844,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
@ -898,15 +911,6 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.8"
|
||||
@ -917,6 +921,37 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
@ -980,6 +1015,7 @@ dependencies = [
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"time",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
@ -990,12 +1026,6 @@ version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
|
@ -13,7 +13,7 @@ name = "dust"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.14", features = [
|
||||
clap = { version = "4.5.29", features = [
|
||||
"cargo",
|
||||
"color",
|
||||
"derive",
|
||||
@ -21,9 +21,9 @@ clap = { version = "4.5.14", features = [
|
||||
"wrap_help",
|
||||
] }
|
||||
dust-lang = { path = "../dust-lang" }
|
||||
postcard = "1.0.10"
|
||||
postcard = "1.1.1"
|
||||
ron = "0.8.1"
|
||||
serde_json = "1.0.133"
|
||||
serde_json = "1.0.138"
|
||||
serde_yaml = "0.9.34"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
tracing-subscriber = { version = "0.3.19", features = ["time"] }
|
||||
|
@ -1,19 +1,19 @@
|
||||
use std::{
|
||||
fs::read_to_string,
|
||||
io::{self, Read, stdout},
|
||||
io::{self, stdout, Read},
|
||||
path::PathBuf,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use clap::{
|
||||
Args, ColorChoice, Error, Parser, Subcommand, ValueEnum, ValueHint,
|
||||
builder::{Styles, styling::AnsiColor},
|
||||
builder::{styling::AnsiColor, Styles},
|
||||
crate_authors, crate_description, crate_version,
|
||||
error::ErrorKind,
|
||||
Args, ColorChoice, Error, Parser, Subcommand, ValueEnum, ValueHint,
|
||||
};
|
||||
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
|
||||
use tracing::{Level, subscriber::set_global_default};
|
||||
use tracing_subscriber::FmtSubscriber;
|
||||
use tracing::{subscriber::set_global_default, Level};
|
||||
use tracing_subscriber::{fmt::time::Uptime, FmtSubscriber};
|
||||
|
||||
const STYLES: Styles = Styles::styled()
|
||||
.header(AnsiColor::BrightMagenta.on_default().bold().underline())
|
||||
@ -180,9 +180,11 @@ fn main() {
|
||||
let mode = mode.unwrap_or(Command::Run(run));
|
||||
let subscriber = FmtSubscriber::builder()
|
||||
.with_max_level(log_level)
|
||||
.with_thread_names(true)
|
||||
.with_ansi(true)
|
||||
.with_file(false)
|
||||
.without_time()
|
||||
.with_line_number(false)
|
||||
.with_thread_names(true)
|
||||
.with_timer(Uptime::from(start_time))
|
||||
.finish();
|
||||
|
||||
set_global_default(subscriber).expect("Failed to set tracing subscriber");
|
||||
|
@ -9,11 +9,11 @@ repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
annotate-snippets = "0.11.4"
|
||||
colored = "2.1.0"
|
||||
annotate-snippets = "0.11.5"
|
||||
colored = "2.2.0"
|
||||
rand = "0.8.5"
|
||||
serde = { version = "1.0.203", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.117"
|
||||
serde = { version = "1.0.217", features = ["derive", "rc"] }
|
||||
serde_json = "1.0.138"
|
||||
getrandom = { version = "0.2", features = [
|
||||
"js",
|
||||
] } # Indirect dependency, for WASM builds
|
||||
@ -22,10 +22,10 @@ smartstring = { version = "1.0.1", features = [
|
||||
], default-features = false }
|
||||
tracing = "0.1.41"
|
||||
crossbeam-channel = "0.5.14"
|
||||
smallvec = { version = "1.13.2", features = ["serde", "const_generics"] }
|
||||
smallvec = { version = "1.14.0", features = ["serde", "const_generics"] }
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3.4", features = ["html_reports"] }
|
||||
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||
|
||||
[[bench]]
|
||||
name = "addictive_addition"
|
||||
|
@ -41,7 +41,7 @@ use std::io::{self, Write};
|
||||
|
||||
use colored::{ColoredString, Colorize};
|
||||
|
||||
use crate::{Chunk, Local};
|
||||
use crate::{Chunk, Local, Type};
|
||||
|
||||
const INSTRUCTION_COLUMNS: [(&str, usize); 4] =
|
||||
[("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 41)];
|
||||
@ -321,7 +321,7 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
||||
{
|
||||
let identifier_display = self
|
||||
.chunk
|
||||
.constants
|
||||
.string_constants
|
||||
.get(*identifier_index as usize)
|
||||
.map(|value| value.to_string())
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
@ -354,8 +354,56 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
||||
self.write_center_border(&column_name_line)?;
|
||||
self.write_center_border(CONSTANT_BORDERS[1])?;
|
||||
|
||||
for (index, value) in self.chunk.constants.iter().enumerate() {
|
||||
let type_display = value.r#type().to_string();
|
||||
for (index, value) in self.chunk.character_constants.iter().enumerate() {
|
||||
let type_display = Type::Character.to_string();
|
||||
let value_display = {
|
||||
let mut value_string = value.to_string();
|
||||
|
||||
if value_string.len() > 26 {
|
||||
value_string = format!("{value_string:.23}...");
|
||||
}
|
||||
|
||||
value_string
|
||||
};
|
||||
let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│");
|
||||
|
||||
self.write_center_border(&constant_display)?;
|
||||
}
|
||||
|
||||
for (index, value) in self.chunk.float_constants.iter().enumerate() {
|
||||
let type_display = Type::Float.to_string();
|
||||
let value_display = {
|
||||
let mut value_string = value.to_string();
|
||||
|
||||
if value_string.len() > 26 {
|
||||
value_string = format!("{value_string:.23}...");
|
||||
}
|
||||
|
||||
value_string
|
||||
};
|
||||
let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│");
|
||||
|
||||
self.write_center_border(&constant_display)?;
|
||||
}
|
||||
|
||||
for (index, value) in self.chunk.integer_constants.iter().enumerate() {
|
||||
let type_display = Type::Integer.to_string();
|
||||
let value_display = {
|
||||
let mut value_string = value.to_string();
|
||||
|
||||
if value_string.len() > 26 {
|
||||
value_string = format!("{value_string:.23}...");
|
||||
}
|
||||
|
||||
value_string
|
||||
};
|
||||
let constant_display = format!("│{index:^5}│{type_display:^26}│{value_display:^26}│");
|
||||
|
||||
self.write_center_border(&constant_display)?;
|
||||
}
|
||||
|
||||
for (index, value) in self.chunk.string_constants.iter().enumerate() {
|
||||
let type_display = Type::String.to_string();
|
||||
let value_display = {
|
||||
let mut value_string = value.to_string();
|
||||
|
||||
@ -420,7 +468,10 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
||||
let info_line = format!(
|
||||
"{} instructions, {} constants, {} locals, returns {}",
|
||||
self.chunk.instructions.len(),
|
||||
self.chunk.constants.len(),
|
||||
self.chunk.character_constants.len()
|
||||
+ self.chunk.float_constants.len()
|
||||
+ self.chunk.integer_constants.len()
|
||||
+ self.chunk.string_constants.len(),
|
||||
self.chunk.locals.len(),
|
||||
self.chunk.r#type.return_type
|
||||
);
|
||||
@ -436,7 +487,11 @@ impl<'a, W: Write> Disassembler<'a, W> {
|
||||
self.write_local_section()?;
|
||||
}
|
||||
|
||||
if !self.chunk.constants.is_empty() {
|
||||
if !self.chunk.character_constants.is_empty()
|
||||
|| !self.chunk.float_constants.is_empty()
|
||||
|| !self.chunk.integer_constants.is_empty()
|
||||
|| !self.chunk.string_constants.is_empty()
|
||||
{
|
||||
self.write_constant_section()?;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span};
|
||||
use crate::{DustString, Function, FunctionType, Instruction, Span};
|
||||
|
||||
/// Representation of a Dust program or function.
|
||||
///
|
||||
@ -36,7 +36,10 @@ pub struct Chunk {
|
||||
|
||||
pub instructions: Vec<Instruction>,
|
||||
pub positions: Vec<Span>,
|
||||
pub constants: Vec<ConcreteValue>,
|
||||
pub character_constants: Vec<char>,
|
||||
pub float_constants: Vec<f64>,
|
||||
pub integer_constants: Vec<i64>,
|
||||
pub string_constants: Vec<DustString>,
|
||||
pub locals: Vec<Local>,
|
||||
pub prototypes: Vec<Arc<Chunk>>,
|
||||
|
||||
@ -107,7 +110,10 @@ impl PartialEq for Chunk {
|
||||
&& self.r#type == other.r#type
|
||||
&& self.instructions == other.instructions
|
||||
&& self.positions == other.positions
|
||||
&& self.constants == other.constants
|
||||
&& self.character_constants == other.character_constants
|
||||
&& self.float_constants == other.float_constants
|
||||
&& self.integer_constants == other.integer_constants
|
||||
&& self.string_constants == other.string_constants
|
||||
&& self.locals == other.locals
|
||||
&& self.prototypes == other.prototypes
|
||||
}
|
||||
|
@ -24,15 +24,15 @@ mod type_checks;
|
||||
|
||||
pub use error::CompileError;
|
||||
use parse_rule::{ParseRule, Precedence};
|
||||
use tracing::{Level, debug, info, span};
|
||||
use tracing::{debug, info, span, Level};
|
||||
use type_checks::{check_math_type, check_math_types};
|
||||
|
||||
use std::{mem::replace, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local,
|
||||
NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type,
|
||||
instruction::{Jump, Point, Return, TypeCode},
|
||||
Chunk, DustError, DustString, FunctionType, Instruction, Lexer, Local, NativeFunction, Operand,
|
||||
Operation, Scope, Span, Token, TokenKind, Type,
|
||||
};
|
||||
|
||||
/// Compiles the input and returns a chunk.
|
||||
@ -83,9 +83,21 @@ pub struct Compiler<'src> {
|
||||
/// The types are discarded after compilation.
|
||||
instructions: Vec<(Instruction, Type, Span)>,
|
||||
|
||||
/// Constants that have been compiled. These are assigned to the chunk when [`Compiler::finish`]
|
||||
/// is called.
|
||||
constants: Vec<ConcreteValue>,
|
||||
/// Character constants that have been compiled. These are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called.
|
||||
character_constants: Vec<char>,
|
||||
|
||||
/// Float constants that have been compiled. These are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called.
|
||||
float_constants: Vec<f64>,
|
||||
|
||||
/// Integer constants that have been compiled. These are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called.
|
||||
integer_constants: Vec<i64>,
|
||||
|
||||
/// String constants that have been compiled. These are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called.
|
||||
string_constants: Vec<DustString>,
|
||||
|
||||
/// Block-local variables and their types. The locals are assigned to the chunk when
|
||||
/// [`Compiler::finish`] is called. The types are discarded after compilation.
|
||||
@ -161,7 +173,10 @@ impl<'src> Compiler<'src> {
|
||||
function_name,
|
||||
r#type: FunctionType::default(),
|
||||
instructions: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
character_constants: Vec::new(),
|
||||
float_constants: Vec::new(),
|
||||
integer_constants: Vec::new(),
|
||||
string_constants: Vec::new(),
|
||||
locals: Vec::new(),
|
||||
prototypes: Vec::new(),
|
||||
lexer,
|
||||
@ -241,7 +256,10 @@ impl<'src> Compiler<'src> {
|
||||
r#type: self.r#type,
|
||||
instructions,
|
||||
positions,
|
||||
constants: self.constants,
|
||||
character_constants: self.character_constants,
|
||||
float_constants: self.float_constants,
|
||||
integer_constants: self.integer_constants,
|
||||
string_constants: self.string_constants,
|
||||
locals: self.locals,
|
||||
prototypes: self.prototypes,
|
||||
boolean_register_count,
|
||||
@ -329,7 +347,10 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if r#type == &Type::Integer {
|
||||
if (instruction.operation() == Operation::LOAD_CONSTANT
|
||||
&& instruction.b_type() == TypeCode::INTEGER)
|
||||
|| r#type == &Type::Integer
|
||||
{
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
None
|
||||
@ -416,12 +437,7 @@ impl<'src> Compiler<'src> {
|
||||
.enumerate()
|
||||
.rev()
|
||||
.find_map(|(index, local)| {
|
||||
let constant = self.constants.get(local.identifier_index as usize)?;
|
||||
let identifier = if let ConcreteValue::String(identifier) = constant {
|
||||
identifier
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let identifier = self.string_constants.get(local.identifier_index as usize)?;
|
||||
|
||||
if identifier == identifier_text {
|
||||
Some(index as u16)
|
||||
@ -445,8 +461,8 @@ impl<'src> Compiler<'src> {
|
||||
) -> (u16, u16) {
|
||||
info!("Declaring local {identifier}");
|
||||
|
||||
let identifier = ConcreteValue::string(identifier);
|
||||
let identifier_index = self.push_or_get_constant(identifier);
|
||||
let identifier = DustString::from(identifier);
|
||||
let identifier_index = self.push_or_get_constant_string(identifier);
|
||||
let local_index = self.locals.len() as u16;
|
||||
|
||||
self.locals.push(Local::new(
|
||||
@ -462,23 +478,23 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
fn get_identifier(&self, local_index: u16) -> Option<String> {
|
||||
self.locals.get(local_index as usize).and_then(|local| {
|
||||
self.constants
|
||||
self.string_constants
|
||||
.get(local.identifier_index as usize)
|
||||
.map(|value| value.to_string())
|
||||
})
|
||||
}
|
||||
|
||||
fn push_or_get_constant(&mut self, value: ConcreteValue) -> u16 {
|
||||
fn push_or_get_constant_string(&mut self, string: DustString) -> u16 {
|
||||
if let Some(index) = self
|
||||
.constants
|
||||
.string_constants
|
||||
.iter()
|
||||
.position(|constant| constant == &value)
|
||||
.position(|constant| constant == &string)
|
||||
{
|
||||
index as u16
|
||||
} else {
|
||||
let index = self.constants.len() as u16;
|
||||
let index = self.string_constants.len() as u16;
|
||||
|
||||
self.constants.push(value);
|
||||
self.string_constants.push(string);
|
||||
|
||||
index
|
||||
}
|
||||
@ -563,28 +579,6 @@ impl<'src> Compiler<'src> {
|
||||
self.instructions.push((instruction, r#type, position));
|
||||
}
|
||||
|
||||
fn emit_constant(
|
||||
&mut self,
|
||||
constant: ConcreteValue,
|
||||
position: Span,
|
||||
) -> Result<(), CompileError> {
|
||||
let r#type = constant.r#type();
|
||||
let constant_index = self.push_or_get_constant(constant);
|
||||
let destination = match r#type {
|
||||
Type::Character => self.next_character_register(),
|
||||
Type::Float => self.next_float_register(),
|
||||
Type::Integer => self.next_integer_register(),
|
||||
Type::String => self.next_string_register(),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, r#type.type_code(), false);
|
||||
|
||||
self.emit_instruction(load_constant, r#type, position);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_boolean(&mut self) -> Result<(), CompileError> {
|
||||
let position = self.current_position;
|
||||
|
||||
@ -637,9 +631,13 @@ impl<'src> Compiler<'src> {
|
||||
if let Token::Character(character) = self.current_token {
|
||||
self.advance()?;
|
||||
|
||||
let value = ConcreteValue::Character(character);
|
||||
let destination = self.next_character_register();
|
||||
let constant_index = self.character_constants.len() as u16;
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, TypeCode::CHARACTER, false);
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
self.character_constants.push(character);
|
||||
self.emit_instruction(load_constant, Type::Character, position);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -663,9 +661,13 @@ impl<'src> Compiler<'src> {
|
||||
error,
|
||||
position: self.previous_position,
|
||||
})?;
|
||||
let value = ConcreteValue::Float(float);
|
||||
let destination = self.next_float_register();
|
||||
let constant_index = self.float_constants.len() as u16;
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, TypeCode::FLOAT, false);
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
self.float_constants.push(float);
|
||||
self.emit_instruction(load_constant, Type::Float, position);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -683,7 +685,7 @@ impl<'src> Compiler<'src> {
|
||||
if let Token::Integer(text) = self.current_token {
|
||||
self.advance()?;
|
||||
|
||||
let mut integer_value = 0_i64;
|
||||
let mut integer = 0_i64;
|
||||
|
||||
for digit in text.chars() {
|
||||
let digit = if let Some(digit) = digit.to_digit(10) {
|
||||
@ -692,12 +694,16 @@ impl<'src> Compiler<'src> {
|
||||
continue;
|
||||
};
|
||||
|
||||
integer_value = integer_value * 10 + digit;
|
||||
integer = integer * 10 + digit;
|
||||
}
|
||||
|
||||
let value = ConcreteValue::Integer(integer_value);
|
||||
let constant_index = self.integer_constants.len() as u16;
|
||||
let destination = self.next_integer_register();
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, TypeCode::INTEGER, false);
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
self.integer_constants.push(integer);
|
||||
self.emit_instruction(load_constant, Type::Integer, position);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -715,9 +721,13 @@ impl<'src> Compiler<'src> {
|
||||
if let Token::String(text) = self.current_token {
|
||||
self.advance()?;
|
||||
|
||||
let value = ConcreteValue::string(text);
|
||||
let string = DustString::from(text);
|
||||
let constant_index = self.push_or_get_constant_string(string);
|
||||
let destination = self.next_string_register();
|
||||
let load_constant =
|
||||
Instruction::load_constant(destination, constant_index, TypeCode::STRING, false);
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
self.emit_instruction(load_constant, Type::String, position);
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
@ -932,13 +942,8 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
|
||||
fn parse_comparison_binary(&mut self) -> Result<(), CompileError> {
|
||||
if let Some(
|
||||
[
|
||||
Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL,
|
||||
_,
|
||||
_,
|
||||
],
|
||||
) = self.get_last_operations()
|
||||
if let Some([Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL, _, _]) =
|
||||
self.get_last_operations()
|
||||
{
|
||||
return Err(CompileError::ComparisonChain {
|
||||
position: self.current_position,
|
||||
|
@ -1,15 +1,27 @@
|
||||
use std::{ops::Range, panic};
|
||||
|
||||
use crate::vm::Thread;
|
||||
use crate::vm::{RuntimeValue, Thread};
|
||||
|
||||
pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
let position = data.current_position();
|
||||
let mut message = format!("Dust panic at {position}!");
|
||||
|
||||
for register_index in argument_range {
|
||||
let string = data.get_string_register(register_index);
|
||||
let string_value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match string_value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
message.push_str(value.as_str());
|
||||
}
|
||||
RuntimeValue::Rc(rc) => {
|
||||
message.push_str(rc.as_str());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
message.push_str(ref_cell.borrow().as_str());
|
||||
}
|
||||
}
|
||||
|
||||
message.push_str(string);
|
||||
message.push('\n');
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
use std::io::{Write, stdin, stdout};
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::ops::Range;
|
||||
|
||||
use crate::vm::{Register, RuntimeValue, Thread};
|
||||
use crate::DustString;
|
||||
use crate::vm::{Register, Thread};
|
||||
|
||||
pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame_mut();
|
||||
let mut buffer = String::new();
|
||||
|
||||
if stdin().read_line(&mut buffer).is_ok() {
|
||||
@ -12,30 +13,53 @@ pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range<u
|
||||
|
||||
buffer.truncate(length.saturating_sub(1));
|
||||
|
||||
let string = DustString::from(buffer);
|
||||
let register = Register::Value(string);
|
||||
let string = RuntimeValue::Raw(DustString::from(buffer));
|
||||
|
||||
data.set_string_register(destination, register);
|
||||
current_frame.registers.strings[destination].set(string);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
let mut stdout = stdout();
|
||||
|
||||
for register_index in argument_range {
|
||||
let value = data.get_string_register(register_index);
|
||||
let _ = stdout.write(value.to_string().as_bytes());
|
||||
let value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::Rc(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
let _ = stdout.write(ref_cell.borrow().as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = stdout.flush();
|
||||
}
|
||||
|
||||
pub fn write_line(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame();
|
||||
let mut stdout = stdout().lock();
|
||||
|
||||
for register_index in argument_range {
|
||||
let value = data.get_string_register(register_index);
|
||||
let _ = stdout.write(value.to_string().as_bytes());
|
||||
let value = current_frame.get_string_from_register(register_index);
|
||||
|
||||
match value {
|
||||
RuntimeValue::Raw(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::Rc(value) => {
|
||||
let _ = stdout.write(value.as_bytes());
|
||||
}
|
||||
RuntimeValue::RefCell(ref_cell) => {
|
||||
let _ = stdout.write(ref_cell.borrow().as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = stdout.write(b"\n");
|
||||
|
@ -2,9 +2,10 @@ use std::ops::Range;
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
use crate::vm::{Register, Thread};
|
||||
use crate::vm::{Register, RuntimeValue, Thread};
|
||||
|
||||
pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<usize>) {
|
||||
let current_frame = data.current_frame_mut();
|
||||
let mut argument_range_iter = argument_range.into_iter();
|
||||
let (min, max) = {
|
||||
let mut min = None;
|
||||
@ -13,18 +14,23 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<u
|
||||
let register_index = argument_range_iter
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
|
||||
let integer = data.get_integer_register(register_index);
|
||||
let integer = current_frame
|
||||
.get_integer_from_register(register_index)
|
||||
.clone_inner();
|
||||
|
||||
if min.is_none() {
|
||||
min = Some(*integer);
|
||||
min = Some(integer);
|
||||
} else {
|
||||
break (min, *integer);
|
||||
break (min, integer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let random_integer = rand::thread_rng().gen_range(min.unwrap()..max);
|
||||
let register = Register::Value(random_integer);
|
||||
|
||||
data.set_integer_register(destination, register);
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(destination)
|
||||
.set(RuntimeValue::Raw(random_integer));
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ pub struct AbstractList {
|
||||
|
||||
impl AbstractList {
|
||||
pub fn display(&self, thread: &Thread) -> DustString {
|
||||
let current_frame = thread.current_frame();
|
||||
let mut display = DustString::new();
|
||||
|
||||
display.push('[');
|
||||
@ -25,12 +26,14 @@ impl AbstractList {
|
||||
}
|
||||
|
||||
let item_display = match self.item_type {
|
||||
TypeCode::BOOLEAN => thread.get_pointer_to_boolean(pointer).to_string(),
|
||||
TypeCode::BYTE => thread.get_pointer_to_byte(pointer).to_string(),
|
||||
TypeCode::CHARACTER => thread.get_pointer_to_character(pointer).to_string(),
|
||||
TypeCode::FLOAT => thread.get_pointer_to_float(pointer).to_string(),
|
||||
TypeCode::INTEGER => thread.get_pointer_to_integer(pointer).to_string(),
|
||||
TypeCode::STRING => thread.get_pointer_to_string(pointer).to_string(),
|
||||
TypeCode::BOOLEAN => current_frame.get_boolean_from_pointer(pointer).to_string(),
|
||||
TypeCode::BYTE => current_frame.get_byte_from_pointer(pointer).to_string(),
|
||||
TypeCode::CHARACTER => current_frame
|
||||
.get_character_from_pointer(pointer)
|
||||
.to_string(),
|
||||
TypeCode::FLOAT => current_frame.get_float_from_pointer(pointer).to_string(),
|
||||
TypeCode::INTEGER => current_frame.get_integer_from_pointer(pointer).to_string(),
|
||||
TypeCode::STRING => current_frame.get_string_from_pointer(pointer).to_string(),
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
@ -57,7 +60,7 @@ impl Display for AbstractList {
|
||||
write!(f, "[")?;
|
||||
|
||||
for pointer in &self.item_pointers {
|
||||
write!(f, "{}", pointer)?;
|
||||
write!(f, "{:?}", pointer)?;
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
|
@ -1,68 +1,63 @@
|
||||
use std::ops::Add;
|
||||
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
instruction::InstructionFields,
|
||||
vm::{Register, Thread},
|
||||
vm::{call_frame::RuntimeValue, Thread},
|
||||
DustString,
|
||||
};
|
||||
|
||||
pub fn add_bytes(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
let destination = instruction.a_field as usize;
|
||||
let left = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_byte().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_byte_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_byte().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_byte_register(right)
|
||||
};
|
||||
let sum = left_value.saturating_add(*right_value);
|
||||
let destination_index = instruction.a_field as usize;
|
||||
let left_index = instruction.b_field as usize;
|
||||
let right_index = instruction.c_field as usize;
|
||||
|
||||
thread.set_byte_register(destination, Register::Value(sum));
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = current_frame.get_byte_from_register(left_index);
|
||||
let right_value = current_frame.get_byte_from_register(right_index);
|
||||
let sum = left_value.add(right_value);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.bytes
|
||||
.get_mut(destination_index)
|
||||
.as_value_mut()
|
||||
.set_inner(sum);
|
||||
}
|
||||
|
||||
pub fn add_characters(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
let destination = instruction.a_field as usize;
|
||||
let left = instruction.b_field as usize;
|
||||
let destination_index = instruction.a_field as usize;
|
||||
let left_index = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
thread.get_character_register(left)
|
||||
current_frame.get_character_from_register(left_index)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(right)
|
||||
} else {
|
||||
thread.get_character_register(right)
|
||||
current_frame.get_character_from_register(right)
|
||||
};
|
||||
let mut concatenated = DustString::from(String::with_capacity(2));
|
||||
let concatenated = {
|
||||
let mut concatenated = DustString::from(String::with_capacity(2));
|
||||
|
||||
concatenated.push(*left_value);
|
||||
concatenated.push(*right_value);
|
||||
concatenated.push(left_value.clone_inner());
|
||||
concatenated.push(right_value.clone_inner());
|
||||
|
||||
thread.set_string_register(destination, Register::Value(concatenated));
|
||||
RuntimeValue::Raw(concatenated)
|
||||
};
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination_index)
|
||||
.set(concatenated);
|
||||
}
|
||||
|
||||
pub fn add_floats(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
@ -71,27 +66,26 @@ pub fn add_floats(_: &mut usize, instruction: &InstructionFields, thread: &mut T
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_float().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_float().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_float_constant(left)
|
||||
} else {
|
||||
thread.get_float_register(left)
|
||||
current_frame.get_float_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_float().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_float().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_float_constant(right)
|
||||
} else {
|
||||
thread.get_float_register(right)
|
||||
current_frame.get_float_from_register(right)
|
||||
};
|
||||
let sum = left_value + *right_value;
|
||||
let sum = left_value.add(right_value);
|
||||
|
||||
thread.set_float_register(destination, Register::Value(sum));
|
||||
current_frame
|
||||
.registers
|
||||
.floats
|
||||
.get_mut(destination)
|
||||
.as_value_mut()
|
||||
.set_inner(sum);
|
||||
}
|
||||
|
||||
pub fn add_integers(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
@ -100,27 +94,26 @@ pub fn add_integers(_: &mut usize, instruction: &InstructionFields, thread: &mut
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
thread.get_integer_register(left)
|
||||
current_frame.get_integer_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
thread.get_integer_register(right)
|
||||
current_frame.get_integer_from_register(right)
|
||||
};
|
||||
let sum = left_value.saturating_add(*right_value);
|
||||
let sum = left_value.add(right_value);
|
||||
|
||||
thread.set_integer_register(destination, Register::Value(sum));
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(destination)
|
||||
.as_value_mut()
|
||||
.set_inner(sum);
|
||||
}
|
||||
|
||||
pub fn add_strings(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
@ -129,31 +122,26 @@ pub fn add_strings(_: &mut usize, instruction: &InstructionFields, thread: &mut
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(left)
|
||||
} else {
|
||||
thread.get_string_register(left)
|
||||
current_frame.get_string_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(right)
|
||||
} else {
|
||||
thread.get_string_register(right)
|
||||
current_frame.get_string_from_register(right)
|
||||
};
|
||||
let mut concatenated =
|
||||
DustString::from(String::with_capacity(left_value.len() + right_value.len()));
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
concatenated.push_str(left_value);
|
||||
concatenated.push_str(right_value);
|
||||
|
||||
thread.set_string_register(destination, Register::Value(concatenated));
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination)
|
||||
.as_value_mut()
|
||||
.set_inner(concatenated);
|
||||
}
|
||||
|
||||
pub fn add_character_string(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
@ -162,30 +150,26 @@ pub fn add_character_string(_: &mut usize, instruction: &InstructionFields, thre
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(left)
|
||||
} else {
|
||||
thread.get_character_register(left)
|
||||
current_frame.get_character_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(right)
|
||||
} else {
|
||||
thread.get_string_register(right)
|
||||
current_frame.get_string_from_register(right)
|
||||
};
|
||||
let mut concatenated = DustString::from(String::with_capacity(right_value.len() + 1));
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
concatenated.push(*left_value);
|
||||
concatenated.push_str(right_value);
|
||||
|
||||
thread.set_string_register(destination, Register::Value(concatenated));
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination)
|
||||
.as_value_mut()
|
||||
.set_inner(concatenated);
|
||||
}
|
||||
|
||||
pub fn add_string_character(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
@ -194,28 +178,89 @@ pub fn add_string_character(_: &mut usize, instruction: &InstructionFields, thre
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(left)
|
||||
} else {
|
||||
thread.get_string_register(left)
|
||||
current_frame.get_string_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(right)
|
||||
} else {
|
||||
thread.get_character_register(right)
|
||||
current_frame.get_character_from_register(right)
|
||||
};
|
||||
let mut concatenated = DustString::from(String::with_capacity(left_value.len() + 1));
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
concatenated.push_str(left_value);
|
||||
concatenated.push(*right_value);
|
||||
|
||||
thread.set_string_register(destination, Register::Value(concatenated));
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination)
|
||||
.as_value_mut()
|
||||
.set_inner(concatenated);
|
||||
}
|
||||
|
||||
pub fn optimized_add_integer(
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 3]>,
|
||||
) {
|
||||
if let Some([destination, left, right]) = cache {
|
||||
trace!("ADD_INTEGERS_OPTIMIZED using cache");
|
||||
|
||||
let sum = left.add(right);
|
||||
|
||||
*destination.borrow_mut() = sum;
|
||||
} else {
|
||||
let destination_index = instruction.a_field as usize;
|
||||
let left_index = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right_index = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
let value = current_frame.get_integer_constant_mut(left_index).to_rc();
|
||||
|
||||
current_frame.constants.integers[left_index] = value.clone();
|
||||
|
||||
value
|
||||
} else {
|
||||
let value = current_frame
|
||||
.get_integer_from_register_mut(left_index)
|
||||
.to_ref_cell();
|
||||
|
||||
current_frame.registers.integers[left_index].set(value.clone());
|
||||
|
||||
value
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
let value = current_frame.get_integer_constant_mut(right_index).to_rc();
|
||||
|
||||
current_frame.constants.integers[right_index] = value.clone();
|
||||
|
||||
value
|
||||
} else {
|
||||
let value = current_frame
|
||||
.get_integer_from_register_mut(right_index)
|
||||
.to_ref_cell();
|
||||
|
||||
current_frame.registers.integers[right_index].set(value.clone());
|
||||
|
||||
value
|
||||
};
|
||||
let sum = left_value.add(&right_value);
|
||||
let destination = {
|
||||
let mut value = current_frame
|
||||
.get_integer_from_register_mut(destination_index)
|
||||
.to_ref_cell();
|
||||
|
||||
value.set_inner(sum);
|
||||
|
||||
current_frame.registers.integers[destination_index].set(value.clone());
|
||||
|
||||
value
|
||||
};
|
||||
|
||||
*cache = Some([destination, left_value, right_value]);
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,20 @@
|
||||
use crate::{instruction::InstructionFields, vm::Thread};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{
|
||||
instruction::InstructionFields,
|
||||
vm::{RuntimeValue, Thread},
|
||||
};
|
||||
|
||||
pub fn less_booleans(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
let left = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_boolean().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_boolean_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_boolean().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_boolean_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let left_index = instruction.b_field as usize;
|
||||
let right_index = instruction.c_field as usize;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = current_frame.get_boolean_from_register(left_index);
|
||||
let right_value = current_frame.get_boolean_from_register(right_index);
|
||||
let is_less_than = left_value < right_value;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
}
|
||||
@ -33,60 +22,38 @@ pub fn less_booleans(ip: &mut usize, instruction: &InstructionFields, thread: &m
|
||||
|
||||
pub fn less_bytes(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
let left = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_byte().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_byte_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_byte().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
thread.get_byte_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = current_frame.get_byte_from_register(left);
|
||||
let right_value = current_frame.get_byte_from_register(right);
|
||||
let is_less_than = left_value < right_value;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn less_characters(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||
let left = instruction.b_field as usize;
|
||||
let left_index = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_index = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
thread.get_character_register(left)
|
||||
current_frame.get_character_from_register(left_index)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_character().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_character().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_character_constant(right_index)
|
||||
} else {
|
||||
thread.get_character_register(right)
|
||||
current_frame.get_character_from_register(right_index)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
@ -98,26 +65,20 @@ pub fn less_floats(ip: &mut usize, instruction: &InstructionFields, thread: &mut
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_float().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_float().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_float_constant(left)
|
||||
} else {
|
||||
thread.get_float_register(left)
|
||||
current_frame.get_float_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_float().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_float().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_float_constant(right)
|
||||
} else {
|
||||
thread.get_float_register(right)
|
||||
current_frame.get_float_from_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
@ -129,26 +90,20 @@ pub fn less_integers(ip: &mut usize, instruction: &InstructionFields, thread: &m
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
thread.get_integer_register(left)
|
||||
current_frame.get_integer_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
thread.get_integer_register(right)
|
||||
current_frame.get_integer_from_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
@ -160,28 +115,84 @@ pub fn less_strings(ip: &mut usize, instruction: &InstructionFields, thread: &mu
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(left).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(left).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(left)
|
||||
} else {
|
||||
thread.get_string_register(left)
|
||||
current_frame.get_string_from_register(left)
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
thread.get_constant(right).as_string().unwrap()
|
||||
} else {
|
||||
unsafe { thread.get_constant(right).as_string().unwrap_unchecked() }
|
||||
}
|
||||
current_frame.get_string_constant(right)
|
||||
} else {
|
||||
thread.get_string_register(right)
|
||||
current_frame.get_string_from_register(right)
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimized_less_integers(
|
||||
ip: &mut usize,
|
||||
instruction: &InstructionFields,
|
||||
thread: &mut Thread,
|
||||
cache: &mut Option<[RuntimeValue<i64>; 2]>,
|
||||
) {
|
||||
if let Some([left, right]) = cache {
|
||||
trace!("LESS_INTEGERS_OPTIMIZED using cache");
|
||||
|
||||
let is_less_than = left < right;
|
||||
|
||||
if is_less_than {
|
||||
*ip += 1;
|
||||
}
|
||||
} else {
|
||||
let left_index = instruction.b_field as usize;
|
||||
let left_is_constant = instruction.b_is_constant;
|
||||
let right_index = instruction.c_field as usize;
|
||||
let right_is_constant = instruction.c_is_constant;
|
||||
let comparator = instruction.d_field;
|
||||
|
||||
let current_frame = thread.current_frame_mut();
|
||||
let left_value = if left_is_constant {
|
||||
let value = current_frame.get_integer_constant_mut(left_index).to_rc();
|
||||
|
||||
current_frame.constants.integers[left_index] = value.clone();
|
||||
|
||||
value
|
||||
} else {
|
||||
let value = current_frame
|
||||
.get_integer_from_register_mut(left_index)
|
||||
.to_ref_cell();
|
||||
|
||||
current_frame.registers.integers[left_index].set(value.clone());
|
||||
|
||||
value
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
let value = current_frame.get_integer_constant_mut(right_index).to_rc();
|
||||
|
||||
current_frame.constants.integers[right_index] = value.clone();
|
||||
|
||||
value
|
||||
} else {
|
||||
let value = current_frame
|
||||
.get_integer_from_register_mut(right_index)
|
||||
.to_ref_cell();
|
||||
|
||||
current_frame.registers.integers[right_index].set(value.clone());
|
||||
|
||||
value
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
|
||||
if is_less_than == comparator {
|
||||
*ip += 1;
|
||||
}
|
||||
|
||||
*cache = Some([left_value, right_value]);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,11 @@
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
ops::{Add, Index, IndexMut},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{AbstractList, Chunk, DustString, Function};
|
||||
|
||||
@ -13,17 +15,220 @@ pub struct CallFrame {
|
||||
pub ip: usize,
|
||||
pub return_register: u16,
|
||||
pub registers: RegisterTable,
|
||||
pub constants: ConstantTable,
|
||||
}
|
||||
|
||||
impl CallFrame {
|
||||
pub fn new(chunk: Rc<Chunk>, return_register: u16) -> Self {
|
||||
let registers = RegisterTable::new();
|
||||
let registers = RegisterTable {
|
||||
booleans: RegisterList::new(chunk.boolean_register_count as usize),
|
||||
bytes: RegisterList::new(chunk.byte_register_count as usize),
|
||||
characters: RegisterList::new(chunk.character_register_count as usize),
|
||||
floats: RegisterList::new(chunk.float_register_count as usize),
|
||||
integers: RegisterList::new(chunk.integer_register_count as usize),
|
||||
strings: RegisterList::new(chunk.string_register_count as usize),
|
||||
lists: RegisterList::new(chunk.list_register_count as usize),
|
||||
functions: RegisterList::new(chunk.function_register_count as usize),
|
||||
};
|
||||
let constants = ConstantTable {
|
||||
characters: chunk
|
||||
.character_constants
|
||||
.iter()
|
||||
.map(|&character| RuntimeValue::Raw(character))
|
||||
.collect(),
|
||||
floats: chunk
|
||||
.float_constants
|
||||
.iter()
|
||||
.map(|&float| RuntimeValue::Raw(float))
|
||||
.collect(),
|
||||
integers: chunk
|
||||
.integer_constants
|
||||
.iter()
|
||||
.map(|&integer| RuntimeValue::Raw(integer))
|
||||
.collect(),
|
||||
strings: chunk
|
||||
.string_constants
|
||||
.iter()
|
||||
.map(|string| RuntimeValue::Raw(string.clone()))
|
||||
.collect(),
|
||||
};
|
||||
|
||||
Self {
|
||||
chunk,
|
||||
ip: 0,
|
||||
return_register,
|
||||
registers,
|
||||
constants,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_register(&self, register_index: usize) -> &RuntimeValue<bool> {
|
||||
let register = self.registers.booleans.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_boolean_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<bool> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_boolean_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get boolean from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_register(&self, register_index: usize) -> &RuntimeValue<u8> {
|
||||
let register = self.registers.bytes.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_byte_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<u8> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_byte_from_register(*register_index),
|
||||
Pointer::Constant(_) => panic!("Attempted to get byte from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_register(&self, register_index: usize) -> &RuntimeValue<char> {
|
||||
let register = self.registers.characters.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_character_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<char> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_character_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_character_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_constant(&self, constant_index: usize) -> &RuntimeValue<char> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.characters.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.characters.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_from_register(&self, register_index: usize) -> &RuntimeValue<f64> {
|
||||
let register = self.registers.floats.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_float_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<f64> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_float_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_float_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_constant(&self, constant_index: usize) -> &RuntimeValue<f64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.floats.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.floats.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_register(&self, register_index: usize) -> &RuntimeValue<i64> {
|
||||
let register = self.registers.integers.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_integer_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_register_mut(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
) -> &mut RuntimeValue<i64> {
|
||||
let register = self.registers.integers.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => {
|
||||
panic!("Attempted to get mutable integer from pointer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<i64> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_integer_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_pointer_mut(&mut self, pointer: &Pointer) -> &mut RuntimeValue<i64> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => {
|
||||
self.get_integer_from_register_mut(*register_index)
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant_mut(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_constant(&self, constant_index: usize) -> &RuntimeValue<i64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.integers.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.integers.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_constant_mut(&mut self, constant_index: usize) -> &mut RuntimeValue<i64> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.integers.get_mut(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.integers.get_unchecked_mut(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_register(&self, register_index: usize) -> &RuntimeValue<DustString> {
|
||||
let register = self.registers.strings.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_string_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_pointer(&self, pointer: &Pointer) -> &RuntimeValue<DustString> {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_string_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_string_constant(*constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_constant(&self, constant_index: usize) -> &RuntimeValue<DustString> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.strings.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.strings.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_constant_mut(
|
||||
&mut self,
|
||||
constant_index: usize,
|
||||
) -> &mut RuntimeValue<DustString> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.constants.strings.get_mut(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.constants.strings.get_unchecked_mut(constant_index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -42,103 +247,348 @@ impl Display for CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RegisterTable {
|
||||
pub booleans: SmallVec<[Register<bool>; 64]>,
|
||||
pub bytes: SmallVec<[Register<u8>; 64]>,
|
||||
pub characters: SmallVec<[Register<char>; 64]>,
|
||||
pub floats: SmallVec<[Register<f64>; 64]>,
|
||||
pub integers: SmallVec<[Register<i64>; 64]>,
|
||||
pub strings: SmallVec<[Register<DustString>; 64]>,
|
||||
pub lists: SmallVec<[Register<AbstractList>; 64]>,
|
||||
pub functions: SmallVec<[Register<Function>; 64]>,
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ConstantTable {
|
||||
pub characters: Vec<RuntimeValue<char>>,
|
||||
pub floats: Vec<RuntimeValue<f64>>,
|
||||
pub integers: Vec<RuntimeValue<i64>>,
|
||||
pub strings: Vec<RuntimeValue<DustString>>,
|
||||
}
|
||||
|
||||
impl RegisterTable {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
booleans: smallvec![Register::default(); 64],
|
||||
bytes: smallvec![Register::default(); 64],
|
||||
characters: smallvec![Register::default(); 64],
|
||||
floats: smallvec![Register::default(); 64],
|
||||
integers: smallvec![Register::default(); 64],
|
||||
strings: smallvec![Register::default(); 64],
|
||||
lists: smallvec![Register::default(); 64],
|
||||
functions: smallvec![Register::default(); 64],
|
||||
#[derive(Debug)]
|
||||
pub struct RegisterTable {
|
||||
pub booleans: RegisterList<bool>,
|
||||
pub bytes: RegisterList<u8>,
|
||||
pub characters: RegisterList<char>,
|
||||
pub floats: RegisterList<f64>,
|
||||
pub integers: RegisterList<i64>,
|
||||
pub strings: RegisterList<DustString>,
|
||||
pub lists: RegisterList<AbstractList>,
|
||||
pub functions: RegisterList<Function>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RegisterList<T, const STACK_LEN: usize = 64> {
|
||||
pub registers: SmallVec<[Register<T>; STACK_LEN]>,
|
||||
}
|
||||
|
||||
impl<T, const STACK_LEN: usize> RegisterList<T, STACK_LEN>
|
||||
where
|
||||
T: Clone + Default,
|
||||
{
|
||||
pub fn new(length: usize) -> Self {
|
||||
let mut registers = SmallVec::with_capacity(length);
|
||||
|
||||
for _ in 0..length {
|
||||
registers.push(Register::default());
|
||||
}
|
||||
|
||||
Self { registers }
|
||||
}
|
||||
|
||||
pub fn get(&self, index: usize) -> &Register<T> {
|
||||
if cfg!(debug_assertions) {
|
||||
self.registers.get(index).unwrap()
|
||||
} else {
|
||||
unsafe { self.registers.get_unchecked(index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, index: usize) -> &mut Register<T> {
|
||||
if cfg!(debug_assertions) {
|
||||
let length = self.registers.len();
|
||||
|
||||
self.registers
|
||||
.get_mut(index)
|
||||
.unwrap_or_else(|| panic!("Index out of bounds: {index}. Length is {length}"))
|
||||
} else {
|
||||
unsafe { self.registers.get_unchecked_mut(index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&mut self, index: usize) {
|
||||
if cfg!(debug_assertions) {
|
||||
self.registers.get_mut(index).unwrap().close()
|
||||
} else {
|
||||
unsafe { self.registers.get_unchecked_mut(index).close() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self, index: usize) -> bool {
|
||||
if cfg!(debug_assertions) {
|
||||
self.registers.get(index).unwrap().is_closed()
|
||||
} else {
|
||||
unsafe { self.registers.get_unchecked(index).is_closed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RegisterTable {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
impl<T> Index<usize> for RegisterList<T> {
|
||||
type Output = Register<T>;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.registers[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Register<T: Default> {
|
||||
Value(T),
|
||||
Closed(T),
|
||||
Pointer(Pointer),
|
||||
impl<T> IndexMut<usize> for RegisterList<T> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.registers[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Register<T> {
|
||||
pub fn contained_value_mut(&mut self) -> Option<&mut T> {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Register<T> {
|
||||
Value {
|
||||
value: RuntimeValue<T>,
|
||||
is_closed: bool,
|
||||
},
|
||||
Pointer {
|
||||
pointer: Pointer,
|
||||
is_closed: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> Register<T> {
|
||||
pub fn is_closed(&self) -> bool {
|
||||
match self {
|
||||
Self::Value(value) => Some(value),
|
||||
Self::Closed(value) => Some(value),
|
||||
Self::Pointer(_) => None,
|
||||
Self::Value { is_closed, .. } => *is_closed,
|
||||
Self::Pointer { is_closed, .. } => *is_closed,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
match self {
|
||||
Self::Value { is_closed, .. } => *is_closed = true,
|
||||
Self::Pointer { is_closed, .. } => *is_closed = true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, new_value: RuntimeValue<T>) {
|
||||
match self {
|
||||
Self::Value {
|
||||
value: old_value, ..
|
||||
} => *old_value = new_value,
|
||||
Self::Pointer { is_closed, .. } => {
|
||||
*self = Self::Value {
|
||||
value: new_value,
|
||||
is_closed: *is_closed,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value(&self) -> &RuntimeValue<T> {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_value_mut(&mut self) -> &mut RuntimeValue<T> {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Register<T> {
|
||||
fn default() -> Self {
|
||||
Self::Value(T::default())
|
||||
Self::Value {
|
||||
value: RuntimeValue::Raw(Default::default()),
|
||||
is_closed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Display> Display for Register<T> {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum RuntimeValue<T> {
|
||||
Raw(T),
|
||||
Rc(Rc<T>),
|
||||
RefCell(Rc<RefCell<T>>),
|
||||
}
|
||||
|
||||
impl<T: Clone> RuntimeValue<T> {
|
||||
pub fn ref_cell(value: T) -> Self {
|
||||
Self::RefCell(Rc::new(RefCell::new(value)))
|
||||
}
|
||||
|
||||
pub fn rc(value: T) -> Self {
|
||||
Self::Rc(Rc::new(value))
|
||||
}
|
||||
|
||||
pub fn to_ref_cell(&mut self) -> Self {
|
||||
match self {
|
||||
Self::Raw(value) => RuntimeValue::ref_cell(value.clone()),
|
||||
Self::Rc(value) => RuntimeValue::ref_cell(value.as_ref().clone()),
|
||||
Self::RefCell(_) => self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_rc(&mut self) -> Self {
|
||||
match self {
|
||||
Self::Raw(value) => RuntimeValue::rc(value.clone()),
|
||||
Self::Rc(_) => self.clone(),
|
||||
Self::RefCell(value) => RuntimeValue::rc(value.borrow().clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_inner(&mut self, new_value: T) {
|
||||
match self {
|
||||
Self::Raw(value) => *value = new_value,
|
||||
Self::Rc(value) => {
|
||||
if let Some(mutable) = Rc::get_mut(value) {
|
||||
*mutable = new_value;
|
||||
}
|
||||
}
|
||||
Self::RefCell(value) => {
|
||||
let _ = value.replace(new_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_inner(&self) -> T {
|
||||
match self {
|
||||
Self::Raw(value) => value.clone(),
|
||||
Self::Rc(value) => value.as_ref().clone(),
|
||||
Self::RefCell(value) => value.borrow().clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow_mut(&self) -> RefMut<T> {
|
||||
match self {
|
||||
Self::RefCell(value) => value.borrow_mut(),
|
||||
_ => panic!("Attempted to borrow mutable reference from immutable register value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Add<Output = T> + Copy> Add for &RuntimeValue<T> {
|
||||
type Output = T;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
match (self, other) {
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Raw(right)) => *left + *right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Rc(right)) => *left + **right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
*left + *right
|
||||
}
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Raw(right)) => **left + *right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Rc(right)) => **left + **right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
**left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
|
||||
*left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left + *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left + **right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq> PartialEq for RuntimeValue<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Raw(right)) => left == right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Rc(right)) => left == &**right,
|
||||
(RuntimeValue::Raw(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
left == &*right
|
||||
}
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Raw(right)) => **left == *right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Rc(right)) => **left == **right,
|
||||
(RuntimeValue::Rc(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
**left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
|
||||
*left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left == *right
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
*left == **right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialOrd> PartialOrd for RuntimeValue<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
match (self, other) {
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Raw(right)) => left.partial_cmp(right),
|
||||
(RuntimeValue::Raw(left), RuntimeValue::Rc(right)) => left.partial_cmp(&**right),
|
||||
(RuntimeValue::Raw(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
left.partial_cmp(&*right)
|
||||
}
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Raw(right)) => (**left).partial_cmp(right),
|
||||
(RuntimeValue::Rc(left), RuntimeValue::Rc(right)) => left.partial_cmp(right),
|
||||
(RuntimeValue::Rc(left), RuntimeValue::RefCell(right)) => {
|
||||
let right = right.borrow();
|
||||
|
||||
(**left).partial_cmp(&right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::RefCell(right)) => {
|
||||
let left = left.borrow();
|
||||
let right = right.borrow();
|
||||
|
||||
left.partial_cmp(&*right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Raw(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
left.partial_cmp(right)
|
||||
}
|
||||
(RuntimeValue::RefCell(left), RuntimeValue::Rc(right)) => {
|
||||
let left = left.borrow();
|
||||
|
||||
left.partial_cmp(&**right)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Display> Display for RuntimeValue<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Closed(value) => write!(f, "Closed({value})"),
|
||||
Self::Value(value) => write!(f, "Value({value})"),
|
||||
Self::Pointer(pointer) => write!(f, "Pointer({pointer:?})"),
|
||||
Self::Raw(value) => write!(f, "{}", value),
|
||||
Self::Rc(value) => write!(f, "{}", value),
|
||||
Self::RefCell(value) => write!(f, "{}", value.borrow()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Pointer {
|
||||
RegisterBoolean(usize),
|
||||
RegisterByte(usize),
|
||||
RegisterCharacter(usize),
|
||||
RegisterFloat(usize),
|
||||
RegisterInteger(usize),
|
||||
RegisterString(usize),
|
||||
RegisterList(usize),
|
||||
RegisterFunction(usize),
|
||||
ConstantCharacter(usize),
|
||||
ConstantFloat(usize),
|
||||
ConstantInteger(usize),
|
||||
ConstantString(usize),
|
||||
}
|
||||
|
||||
impl Display for Pointer {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::RegisterBoolean(index) => write!(f, "P_R_BOOL_{index}"),
|
||||
Self::RegisterByte(index) => write!(f, "P_R_BYTE_{index}"),
|
||||
Self::RegisterCharacter(index) => write!(f, "P_R_CHAR_{index}"),
|
||||
Self::RegisterFloat(index) => write!(f, "P_R_FLOAT_{index}"),
|
||||
Self::RegisterInteger(index) => write!(f, "P_R_INT_{index}"),
|
||||
Self::RegisterString(index) => write!(f, "P_R_STR_{index}"),
|
||||
Self::RegisterList(index) => write!(f, "P_R_LIST_{index}"),
|
||||
Self::RegisterFunction(index) => write!(f, "P_R_FN_{index}"),
|
||||
Self::ConstantCharacter(index) => write!(f, "P_C_CHAR_{index}"),
|
||||
Self::ConstantFloat(index) => write!(f, "P_C_FLOAT_{index}"),
|
||||
Self::ConstantInteger(index) => write!(f, "P_C_INT_{index}"),
|
||||
Self::ConstantString(index) => write!(f, "P_C_STR_{index}"),
|
||||
}
|
||||
}
|
||||
Register(usize),
|
||||
Constant(usize),
|
||||
}
|
||||
|
@ -5,14 +5,13 @@ mod thread;
|
||||
|
||||
use std::{rc::Rc, thread::Builder};
|
||||
|
||||
pub use action::Action;
|
||||
pub use call_frame::{CallFrame, Pointer, Register, RegisterTable};
|
||||
pub use call_frame::{CallFrame, Pointer, Register, RegisterTable, RuntimeValue};
|
||||
pub use thread::Thread;
|
||||
|
||||
use crossbeam_channel::bounded;
|
||||
use tracing::{Level, span};
|
||||
use tracing::{span, Level};
|
||||
|
||||
use crate::{Chunk, DustError, Value, compile};
|
||||
use crate::{compile, Chunk, DustError, Value};
|
||||
|
||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
let chunk = compile(source)?;
|
||||
|
@ -5,11 +5,9 @@ use tracing::{info, trace};
|
||||
use crate::{
|
||||
instruction::InstructionFields,
|
||||
vm::{action::ActionSequence, CallFrame},
|
||||
AbstractList, Chunk, ConcreteValue, DustString, Span, Value,
|
||||
Chunk, DustString, Span, Value,
|
||||
};
|
||||
|
||||
use super::call_frame::{Pointer, Register};
|
||||
|
||||
pub struct Thread {
|
||||
chunk: Rc<Chunk>,
|
||||
call_stack: Vec<CallFrame>,
|
||||
@ -77,811 +75,4 @@ impl Thread {
|
||||
unsafe { self.call_stack.last_mut().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_value_from_pointer(&self, pointer: &Pointer) -> ConcreteValue {
|
||||
match pointer {
|
||||
Pointer::RegisterBoolean(register_index) => {
|
||||
let boolean = *self.get_boolean_register(*register_index);
|
||||
|
||||
ConcreteValue::Boolean(boolean)
|
||||
}
|
||||
Pointer::RegisterByte(register_index) => {
|
||||
let byte = *self.get_byte_register(*register_index);
|
||||
|
||||
ConcreteValue::Byte(byte)
|
||||
}
|
||||
Pointer::RegisterCharacter(register_index) => {
|
||||
let character = *self.get_character_register(*register_index);
|
||||
|
||||
ConcreteValue::Character(character)
|
||||
}
|
||||
Pointer::RegisterFloat(register_index) => {
|
||||
let float = *self.get_float_register(*register_index);
|
||||
|
||||
ConcreteValue::Float(float)
|
||||
}
|
||||
Pointer::RegisterInteger(register_index) => {
|
||||
let integer = *self.get_integer_register(*register_index);
|
||||
|
||||
ConcreteValue::Integer(integer)
|
||||
}
|
||||
Pointer::RegisterString(register_index) => {
|
||||
let string = self.get_string_register(*register_index).clone();
|
||||
|
||||
ConcreteValue::String(string)
|
||||
}
|
||||
Pointer::RegisterList(register_index) => {
|
||||
let abstract_list = self.get_list_register(*register_index).clone();
|
||||
let mut items = Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let value = self.get_value_from_pointer(pointer);
|
||||
|
||||
items.push(value);
|
||||
}
|
||||
|
||||
ConcreteValue::List {
|
||||
items,
|
||||
item_type: abstract_list.item_type,
|
||||
}
|
||||
}
|
||||
Pointer::RegisterFunction(_) => unimplemented!(),
|
||||
Pointer::ConstantCharacter(constant_index) => {
|
||||
let character = *self.get_constant(*constant_index).as_character().unwrap();
|
||||
|
||||
ConcreteValue::Character(character)
|
||||
}
|
||||
Pointer::ConstantFloat(constant_index) => {
|
||||
let float = *self.get_constant(*constant_index).as_float().unwrap();
|
||||
|
||||
ConcreteValue::Float(float)
|
||||
}
|
||||
Pointer::ConstantInteger(constant_index) => {
|
||||
let integer = *self.get_constant(*constant_index).as_integer().unwrap();
|
||||
|
||||
ConcreteValue::Integer(integer)
|
||||
}
|
||||
Pointer::ConstantString(constant_index) => {
|
||||
let string = self
|
||||
.get_constant(*constant_index)
|
||||
.as_string()
|
||||
.unwrap()
|
||||
.clone();
|
||||
|
||||
ConcreteValue::String(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_register(&self, register_index: usize) -> &bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.booleans
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.booleans
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_boolean(&self, pointer: &Pointer) -> &bool {
|
||||
match pointer {
|
||||
Pointer::RegisterBoolean(register_index) => self.get_boolean_register(*register_index),
|
||||
_ => panic!("Attempted to get boolean from non-boolean pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_boolean_register(&mut self, register_index: usize, new_register: Register<bool>) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.booleans
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.booleans
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_boolean_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.booleans
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.booleans
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_boolean_register(&mut self, register_index: usize) {
|
||||
let register = self
|
||||
.current_frame_mut()
|
||||
.registers
|
||||
.booleans
|
||||
.get_mut(register_index)
|
||||
.unwrap();
|
||||
|
||||
*register = match register {
|
||||
Register::Value(value) => Register::Closed(*value),
|
||||
_ => panic!("Attempted to close non-value register"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_byte_register(&self, register_index: usize) -> &u8 {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.bytes
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.bytes
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_byte(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_byte(&self, pointer: &Pointer) -> &u8 {
|
||||
match pointer {
|
||||
Pointer::RegisterByte(register_index) => self.get_byte_register(*register_index),
|
||||
_ => panic!("Attempted to get byte from non-byte pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_byte_register(&mut self, register_index: usize, new_register: Register<u8>) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.bytes
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.bytes
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_byte_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.bytes
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.bytes
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_byte_register(&mut self, register_index: usize) {
|
||||
let register = self
|
||||
.current_frame_mut()
|
||||
.registers
|
||||
.bytes
|
||||
.get_mut(register_index)
|
||||
.unwrap();
|
||||
|
||||
*register = match register {
|
||||
Register::Value(value) => Register::Closed(*value),
|
||||
_ => panic!("Attempted to close non-value register"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_character_register(&self, register_index: usize) -> &char {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.characters
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.characters
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_character(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_character(&self, pointer: &Pointer) -> &char {
|
||||
match pointer {
|
||||
Pointer::RegisterCharacter(register_index) => {
|
||||
self.get_character_register(*register_index)
|
||||
}
|
||||
Pointer::ConstantCharacter(constant_index) => {
|
||||
self.get_constant(*constant_index).as_character().unwrap()
|
||||
}
|
||||
_ => panic!("Attempted to get character from non-character pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_character_register(&mut self, register_index: usize, new_register: Register<char>) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.characters
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.characters
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_character_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.characters
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.characters
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_character_register(&mut self, register_index: usize) {
|
||||
let register = self
|
||||
.current_frame_mut()
|
||||
.registers
|
||||
.characters
|
||||
.get_mut(register_index)
|
||||
.unwrap();
|
||||
|
||||
*register = match register {
|
||||
Register::Value(value) => Register::Closed(*value),
|
||||
_ => panic!("Attempted to close non-value register"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_float_register(&self, register_index: usize) -> &f64 {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.floats
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.floats
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_float(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_float(&self, pointer: &Pointer) -> &f64 {
|
||||
match pointer {
|
||||
Pointer::RegisterFloat(register_index) => self.get_float_register(*register_index),
|
||||
Pointer::ConstantFloat(constant_index) => {
|
||||
self.get_constant(*constant_index).as_float().unwrap()
|
||||
}
|
||||
_ => panic!("Attempted to get float from non-float pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_float_register(&mut self, register_index: usize, new_register: Register<f64>) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.floats
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.floats
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_float_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.floats
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.floats
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_float_register(&mut self, register_index: usize) {
|
||||
let register = self
|
||||
.current_frame_mut()
|
||||
.registers
|
||||
.floats
|
||||
.get_mut(register_index)
|
||||
.unwrap();
|
||||
|
||||
*register = match register {
|
||||
Register::Value(value) => Register::Closed(*value),
|
||||
_ => panic!("Attempted to close non-value register"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_integer(&self, index: usize, is_constant: bool) -> &i64 {
|
||||
if is_constant {
|
||||
if cfg!(debug_assertions) {
|
||||
self.get_constant(index).as_integer().unwrap()
|
||||
} else {
|
||||
unsafe { self.get_constant(index).as_integer().unwrap_unchecked() }
|
||||
}
|
||||
} else {
|
||||
self.get_integer_register(index)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_register(&self, register_index: usize) -> &i64 {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.integers
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.integers
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_integer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_register_mut_allow_empty(&mut self, register_index: usize) -> &mut i64 {
|
||||
if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
.contained_value_mut()
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.integers
|
||||
.get_unchecked_mut(register_index)
|
||||
.contained_value_mut()
|
||||
.unwrap_unchecked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_integer(&self, pointer: &Pointer) -> &i64 {
|
||||
match pointer {
|
||||
Pointer::RegisterInteger(register_index) => self.get_integer_register(*register_index),
|
||||
Pointer::ConstantInteger(constant_index) => {
|
||||
self.get_constant(*constant_index).as_integer().unwrap()
|
||||
}
|
||||
_ => panic!("Attempted to get integer from non-integer pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_integer_register(&mut self, register_index: usize, new_register: Register<i64>) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.integers
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_integer_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.integers
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.integers
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_integer_register(&mut self, register_index: usize) {
|
||||
let register = self
|
||||
.current_frame_mut()
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(register_index)
|
||||
.unwrap();
|
||||
|
||||
*register = match register {
|
||||
Register::Value(value) => Register::Closed(*value),
|
||||
_ => panic!("Attempted to close non-value register"),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_string_register(&self, register_index: usize) -> &DustString {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.strings
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.strings
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_string(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_string(&self, pointer: &Pointer) -> &DustString {
|
||||
match pointer {
|
||||
Pointer::RegisterString(register_index) => self.get_string_register(*register_index),
|
||||
Pointer::ConstantString(constant_index) => {
|
||||
self.get_constant(*constant_index).as_string().unwrap()
|
||||
}
|
||||
_ => panic!("Attempted to get string from non-string pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_string_register(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
new_register: Register<DustString>,
|
||||
) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.strings
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_string_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.strings
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.strings
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_string_register(&mut self, register_index: usize) {
|
||||
let current_frame = self.current_frame_mut();
|
||||
|
||||
current_frame.registers.strings.push(Register::default());
|
||||
|
||||
let old_register = current_frame.registers.strings.swap_remove(register_index);
|
||||
|
||||
if let Register::Value(value) = old_register {
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.push(Register::Closed(value));
|
||||
|
||||
let _ = current_frame.registers.strings.swap_remove(register_index);
|
||||
} else {
|
||||
panic!("Attempted to close non-value register");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_register(&self, register_index: usize) -> &AbstractList {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.lists
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.lists
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
match register {
|
||||
Register::Value(value) => value,
|
||||
Register::Closed(value) => value,
|
||||
Register::Pointer(pointer) => self.get_pointer_to_list(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pointer_to_list(&self, pointer: &Pointer) -> &AbstractList {
|
||||
match pointer {
|
||||
Pointer::RegisterList(register_index) => self.get_list_register(*register_index),
|
||||
_ => panic!("Attempted to get list from non-list pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_list_register(
|
||||
&mut self,
|
||||
register_index: usize,
|
||||
new_register: Register<AbstractList>,
|
||||
) {
|
||||
let old_register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.registers
|
||||
.lists
|
||||
.get_mut(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last_mut()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.lists
|
||||
.get_unchecked_mut(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
*old_register = new_register;
|
||||
}
|
||||
|
||||
pub fn is_list_register_closed(&self, register_index: usize) -> bool {
|
||||
let register = if cfg!(debug_assertions) {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.registers
|
||||
.lists
|
||||
.get(register_index)
|
||||
.unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
self.call_stack
|
||||
.last()
|
||||
.unwrap_unchecked()
|
||||
.registers
|
||||
.lists
|
||||
.get_unchecked(register_index)
|
||||
}
|
||||
};
|
||||
|
||||
matches!(register, Register::Closed(_))
|
||||
}
|
||||
|
||||
pub fn close_list_register(&mut self, register_index: usize) {
|
||||
let current_frame = self.current_frame_mut();
|
||||
|
||||
current_frame.registers.lists.push(Register::default());
|
||||
|
||||
let old_register = current_frame.registers.lists.swap_remove(register_index);
|
||||
|
||||
if let Register::Value(value) = old_register {
|
||||
current_frame.registers.lists.push(Register::Closed(value));
|
||||
|
||||
let _ = current_frame.registers.lists.swap_remove(register_index);
|
||||
} else {
|
||||
panic!("Attempted to close non-value register");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_constant(&self, constant_index: usize) -> &ConcreteValue {
|
||||
if cfg!(debug_assertions) {
|
||||
self.chunk.constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.chunk.constants.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user