1
0

Decide on an optimization strategy for the VM

This commit is contained in:
Jeff 2025-02-16 22:55:55 -05:00
parent 5030171bb6
commit 07f8b36c99
17 changed files with 1229 additions and 2395 deletions

204
Cargo.lock generated
View File

@ -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"

View File

@ -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"] }

View File

@ -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");

View File

@ -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"

View File

@ -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()?;
}

View File

@ -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
}

View File

@ -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,

View File

@ -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');
}

View File

@ -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");

View File

@ -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));
}

View File

@ -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, "]")

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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),
}

View File

@ -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)?;

View File

@ -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) }
}
}
}