1
0

Add formatting disassembly output into JSON or TOML

This commit is contained in:
Jeff 2025-02-08 05:56:49 -05:00
parent e387579a81
commit 71a92c078b
14 changed files with 385 additions and 332 deletions

85
Cargo.lock generated
View File

@ -96,6 +96,15 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "basic-toml"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@ -328,11 +337,13 @@ dependencies = [
name = "dust-cli" name = "dust-cli"
version = "0.5.0" version = "0.5.0"
dependencies = [ dependencies = [
"basic-toml",
"clap 4.5.20", "clap 4.5.20",
"color-print", "color-print",
"dust-lang", "dust-lang",
"postcard", "postcard",
"serde_json", "serde_json",
"toml",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
] ]
@ -360,6 +371,12 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.10" version = "0.3.10"
@ -398,6 +415,12 @@ dependencies = [
"byteorder", "byteorder",
] ]
[[package]]
name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
[[package]] [[package]]
name = "heapless" name = "heapless"
version = "0.7.17" version = "0.7.17"
@ -427,6 +450,16 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "indexmap"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
@ -792,6 +825,15 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_spanned"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@ -899,6 +941,40 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "toml"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]] [[package]]
name = "tracing" name = "tracing"
version = "0.1.41" version = "0.1.41"
@ -1237,6 +1313,15 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.7.35" version = "0.7.35"

View File

@ -13,6 +13,7 @@ name = "dust"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
basic-toml = "0.1.9"
clap = { version = "4.5.14", features = [ clap = { version = "4.5.14", features = [
"cargo", "cargo",
"color", "color",
@ -24,5 +25,6 @@ color-print = "0.3.7"
dust-lang = { path = "../dust-lang" } dust-lang = { path = "../dust-lang" }
postcard = "1.0.10" postcard = "1.0.10"
serde_json = "1.0.133" serde_json = "1.0.133"
toml = "0.8.20"
tracing = "0.1.41" tracing = "0.1.41"
tracing-subscriber = "0.3.19" tracing-subscriber = "0.3.19"

View File

@ -1,19 +1,19 @@
use std::{ use std::{
fs::read_to_string, fs::read_to_string,
io::{self, stdout, Read}, io::{self, Read, stdout},
path::PathBuf, path::PathBuf,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use clap::{ use clap::{
builder::{styling::AnsiColor, Styles}, Args, ColorChoice, Error, Parser, Subcommand, ValueEnum, ValueHint,
builder::{Styles, styling::AnsiColor},
crate_authors, crate_description, crate_version, crate_authors, crate_description, crate_version,
error::ErrorKind, error::ErrorKind,
Args, ColorChoice, Error, Parser, Subcommand, ValueHint,
}; };
use color_print::{cformat, cstr}; use color_print::{cformat, cstr};
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm}; use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
use tracing::{subscriber::set_global_default, Level}; use tracing::{Level, subscriber::set_global_default};
use tracing_subscriber::FmtSubscriber; use tracing_subscriber::FmtSubscriber;
const ABOUT: &str = cstr!( const ABOUT: &str = cstr!(
@ -158,11 +158,14 @@ enum Mode {
style: bool, style: bool,
/// Custom program name, overrides the file name /// Custom program name, overrides the file name
#[arg(long)] #[arg(short, long)]
name: Option<DustString>, name: Option<DustString>,
#[command(flatten)] #[command(flatten)]
input: Input, input: Input,
#[arg(short, long, default_value = "cli")]
format: Format,
}, },
/// Lex the source code and print the tokens /// Lex the source code and print the tokens
@ -180,6 +183,13 @@ enum Mode {
}, },
} }
#[derive(ValueEnum, Clone, Copy)]
enum Format {
Cli,
Json,
Toml,
}
fn get_source_and_file_name(input: Input) -> (String, Option<DustString>) { fn get_source_and_file_name(input: Input) -> (String, Option<DustString>) {
if let Some(path) = input.file { if let Some(path) = input.file {
let source = read_to_string(&path).expect("Failed to read source file"); let source = read_to_string(&path).expect("Failed to read source file");
@ -221,88 +231,6 @@ fn main() {
set_global_default(subscriber).expect("Failed to set tracing subscriber"); set_global_default(subscriber).expect("Failed to set tracing subscriber");
if let Mode::Disassemble { style, name, input } = mode {
let (source, file_name) = get_source_and_file_name(input);
let lexer = Lexer::new(&source);
let program_name = name.or(file_name);
let mut compiler = match Compiler::new(lexer, program_name, true) {
Ok(compiler) => compiler,
Err(error) => {
handle_compile_error(error, &source);
return;
}
};
match compiler.compile() {
Ok(()) => {}
Err(error) => {
handle_compile_error(error, &source);
return;
}
}
let chunk = compiler.finish();
let mut stdout = stdout().lock();
chunk
.disassembler(&mut stdout)
.width(65)
.style(style)
.source(&source)
.disassemble()
.expect("Failed to write disassembly to stdout");
return;
}
if let Mode::Tokenize { input, .. } = mode {
let (source, _) = get_source_and_file_name(input);
let mut lexer = Lexer::new(&source);
let mut next_token = || -> Option<(Token, Span, bool)> {
match lexer.next_token() {
Ok((token, position)) => Some((token, position, lexer.is_eof())),
Err(error) => {
let report = DustError::compile(CompileError::Lex(error), &source).report();
eprintln!("{report}");
None
}
}
};
println!("{:^66}", "Tokens");
for _ in 0..66 {
print!("-");
}
println!();
println!("{:^21}|{:^22}|{:^22}", "Kind", "Value", "Position");
for _ in 0..66 {
print!("-");
}
println!();
while let Some((token, position, is_eof)) = next_token() {
if is_eof {
break;
}
let token_kind = token.kind().to_string();
let token = token.to_string();
let position = position.to_string();
println!("{token_kind:^21}|{token:^22}|{position:^22}");
}
return;
}
if let Mode::Run(Run { if let Mode::Run(Run {
time, time,
no_output, no_output,
@ -352,6 +280,111 @@ fn main() {
print_time("Run Time", run_time); print_time("Run Time", run_time);
print_time("Total Time", total_time); print_time("Total Time", total_time);
} }
return;
}
if let Mode::Disassemble {
style,
name,
input,
format,
} = mode
{
let (source, file_name) = get_source_and_file_name(input);
let lexer = Lexer::new(&source);
let program_name = name.or(file_name);
let mut compiler = match Compiler::new(lexer, program_name, true) {
Ok(compiler) => compiler,
Err(error) => {
handle_compile_error(error, &source);
return;
}
};
match compiler.compile() {
Ok(()) => {}
Err(error) => {
handle_compile_error(error, &source);
return;
}
}
let chunk = compiler.finish();
let mut stdout = stdout().lock();
match format {
Format::Cli => {
chunk
.disassembler(&mut stdout)
.width(65)
.style(style)
.source(&source)
.disassemble()
.expect("Failed to write disassembly to stdout");
}
Format::Json => {
let json = serde_json::to_string_pretty(&chunk)
.expect("Failed to serialize chunk to JSON");
println!("{json}");
}
Format::Toml => {
let toml = basic_toml::to_string(&chunk)
.inspect_err(|error| println!("{:?}", error.to_string()))
.expect("Failed to serialize chunk to TOML");
println!("{toml}");
}
}
return;
}
if let Mode::Tokenize { input, .. } = mode {
let (source, _) = get_source_and_file_name(input);
let mut lexer = Lexer::new(&source);
let mut next_token = || -> Option<(Token, Span, bool)> {
match lexer.next_token() {
Ok((token, position)) => Some((token, position, lexer.is_eof())),
Err(error) => {
let report = DustError::compile(CompileError::Lex(error), &source).report();
eprintln!("{report}");
None
}
}
};
println!("{:^66}", "Tokens");
for _ in 0..66 {
print!("-");
}
println!();
println!("{:^21}|{:^22}|{:^22}", "Kind", "Value", "Position");
for _ in 0..66 {
print!("-");
}
println!();
while let Some((token, position, is_eof)) = next_token() {
if is_eof {
break;
}
let token_kind = token.kind().to_string();
let token = token.to_string();
let position = position.to_string();
println!("{token_kind:^21}|{token:^22}|{position:^22}");
}
} }
} }

View File

@ -13,12 +13,12 @@ pub struct Local {
/// Index of the register where the variable's value is stored. /// Index of the register where the variable's value is stored.
pub register_index: u16, pub register_index: u16,
/// Type of the variable's value.
pub r#type: Type,
/// Whether the local is mutable. /// Whether the local is mutable.
pub is_mutable: bool, pub is_mutable: bool,
/// Type of the variable's value.
pub r#type: Type,
/// Scope where the variable was declared. /// Scope where the variable was declared.
pub scope: Scope, pub scope: Scope,
} }

View File

@ -20,19 +20,20 @@ mod scope;
pub use disassembler::Disassembler; pub use disassembler::Disassembler;
pub use local::Local; pub use local::Local;
pub use scope::Scope; pub use scope::Scope;
use serde::ser::SerializeStruct;
use std::fmt::{self, Debug, Display, Formatter, Write as FmtWrite}; use std::fmt::{self, Debug, Display, Formatter, Write as FmtWrite};
use std::io::Write; use std::io::Write;
use std::sync::Arc; use std::sync::Arc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize, Serializer};
use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span}; use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span};
/// Representation of a Dust program or function. /// Representation of a Dust program or function.
/// ///
/// See the [module-level documentation](index.html) for more information. /// See the [module-level documentation](index.html) for more information.
#[derive(Clone, Default, PartialOrd, Serialize, Deserialize)] #[derive(Clone, Default, PartialOrd, Deserialize)]
pub struct Chunk { pub struct Chunk {
pub name: Option<DustString>, pub name: Option<DustString>,
pub r#type: FunctionType, pub r#type: FunctionType,
@ -114,3 +115,28 @@ impl PartialEq for Chunk {
&& self.prototypes == other.prototypes && self.prototypes == other.prototypes
} }
} }
impl Serialize for Chunk {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut state = serializer.serialize_struct("Chunk", 11)?;
state.serialize_field("name", &self.name)?;
state.serialize_field("boolean_register_count", &self.boolean_register_count)?;
state.serialize_field("byte_register_count", &self.byte_register_count)?;
state.serialize_field("character_register_count", &self.character_register_count)?;
state.serialize_field("float_register_count", &self.float_register_count)?;
state.serialize_field("integer_register_count", &self.integer_register_count)?;
state.serialize_field("string_register_count", &self.string_register_count)?;
state.serialize_field("list_register_count", &self.list_register_count)?;
state.serialize_field("function_register_count", &self.function_register_count)?;
state.serialize_field("prototype_index", &self.prototype_index)?;
state.serialize_field("instructions", &self.instructions)?;
state.serialize_field("positions", &self.positions)?;
state.serialize_field("prototypes", &self.prototypes)?;
state.serialize_field("locals", &self.locals)?;
state.serialize_field("constants", &self.constants)?;
state.serialize_field("type", &self.r#type)?;
state.end()
}
}

View File

@ -159,11 +159,7 @@ impl<'src> Compiler<'src> {
Ok(Compiler { Ok(Compiler {
function_name, function_name,
r#type: FunctionType { r#type: FunctionType::default(),
type_parameters: Vec::with_capacity(0),
value_parameters: Vec::with_capacity(0),
return_type: Type::None,
},
instructions: Vec::new(), instructions: Vec::new(),
constants: Vec::new(), constants: Vec::new(),
locals: Vec::new(), locals: Vec::new(),
@ -268,12 +264,14 @@ impl<'src> Compiler<'src> {
self.instructions self.instructions
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, r#type, _)| { .find_map(|(instruction, _, _)| {
if instruction.b_type() == TypeCode::BOOLEAN && instruction.yields_value() { if instruction.operation() == Operation::LOAD_ENCODED
Some(instruction.a_field() + 1) && instruction.b_type() == TypeCode::BOOLEAN
} else { {
None return Some(instruction.a_field() + 1);
} }
None
}) })
.unwrap_or(self.minimum_boolean_register) .unwrap_or(self.minimum_boolean_register)
} }
@ -283,15 +281,13 @@ impl<'src> Compiler<'src> {
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, _, _)| { .find_map(|(instruction, _, _)| {
if instruction.operation() == Operation::LOAD_ENCODED { if instruction.operation() == Operation::LOAD_ENCODED
if instruction.b_type() == TypeCode::BYTE { && instruction.b_type() == TypeCode::BYTE
Some(instruction.a_field() + 1) {
} else { return Some(instruction.a_field() + 1);
None
}
} else {
None
} }
None
}) })
.unwrap_or(self.minimum_byte_register) .unwrap_or(self.minimum_byte_register)
} }
@ -332,7 +328,9 @@ impl<'src> Compiler<'src> {
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, r#type, _)| { .find_map(|(instruction, r#type, _)| {
if r#type == &Type::Integer { if r#type == &Type::Integer
|| (instruction.b_type() == TypeCode::INTEGER && instruction.yields_value())
{
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
None None
@ -346,9 +344,8 @@ impl<'src> Compiler<'src> {
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, r#type, _)| { .find_map(|(instruction, r#type, _)| {
if instruction.b_type() == TypeCode::STRING if r#type == &Type::String
&& r#type == &Type::String || (instruction.b_type() == TypeCode::STRING && instruction.yields_value())
&& instruction.yields_value()
{ {
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
@ -363,7 +360,7 @@ impl<'src> Compiler<'src> {
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, r#type, _)| { .find_map(|(instruction, r#type, _)| {
if let Type::List(_) = r#type { if let Type::List { .. } = r#type {
if instruction.yields_value() { if instruction.yields_value() {
Some(instruction.a_field() + 1) Some(instruction.a_field() + 1)
} else { } else {
@ -546,7 +543,7 @@ impl<'src> Compiler<'src> {
/// ///
/// If [`Self::type`] is already set, it will check if the given [Type] is compatible. /// If [`Self::type`] is already set, it will check if the given [Type] is compatible.
fn update_return_type(&mut self, new_return_type: Type) -> Result<(), CompileError> { fn update_return_type(&mut self, new_return_type: Type) -> Result<(), CompileError> {
if self.r#type.return_type != Type::None { if self.r#type.return_type.as_ref() != &Type::None {
self.r#type self.r#type
.return_type .return_type
.check(&new_return_type) .check(&new_return_type)
@ -556,7 +553,7 @@ impl<'src> Compiler<'src> {
})?; })?;
} }
self.r#type.return_type = new_return_type; *self.r#type.return_type.as_mut() = new_return_type;
Ok(()) Ok(())
} }
@ -900,7 +897,7 @@ impl<'src> Compiler<'src> {
match left_type { match left_type {
Type::Boolean => self.next_boolean_register(), Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(), Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(), Type::Character => self.next_string_register(),
Type::Float => self.next_float_register(), Type::Float => self.next_float_register(),
Type::Integer => self.next_integer_register(), Type::Integer => self.next_integer_register(),
Type::String => self.next_string_register(), Type::String => self.next_string_register(),
@ -1274,7 +1271,7 @@ impl<'src> Compiler<'src> {
if used_boolean_registers > 1 { if used_boolean_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_boolean_register, next_boolean_register,
next_boolean_register + used_boolean_registers, self.next_boolean_register() - 2,
TypeCode::BOOLEAN, TypeCode::BOOLEAN,
); );
@ -1282,12 +1279,12 @@ impl<'src> Compiler<'src> {
} }
} }
Type::Byte => { Type::Byte => {
let used_byte_registers = self.next_byte_register() - 1 - next_byte_register; let used_byte_registers = self.next_byte_register() - next_byte_register;
if used_byte_registers > 1 { if used_byte_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_byte_register, next_byte_register,
next_byte_register + used_byte_registers, self.next_byte_register() - 2,
TypeCode::BYTE, TypeCode::BYTE,
); );
@ -1296,12 +1293,12 @@ impl<'src> Compiler<'src> {
} }
Type::Character => { Type::Character => {
let used_character_registers = let used_character_registers =
self.next_character_register() - 1 - next_character_register; self.next_character_register() - next_character_register;
if used_character_registers > 1 { if used_character_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_character_register, next_character_register,
next_character_register + used_character_registers, self.next_character_register() - 2,
TypeCode::CHARACTER, TypeCode::CHARACTER,
); );
@ -1309,12 +1306,12 @@ impl<'src> Compiler<'src> {
} }
} }
Type::Float => { Type::Float => {
let used_float_registers = self.next_float_register() - 1 - next_float_register; let used_float_registers = self.next_float_register() - next_float_register;
if used_float_registers > 1 { if used_float_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_float_register, next_float_register,
next_float_register + used_float_registers, self.next_float_register() - 2,
TypeCode::FLOAT, TypeCode::FLOAT,
); );
@ -1323,12 +1320,12 @@ impl<'src> Compiler<'src> {
} }
Type::Integer => { Type::Integer => {
let used_integer_registers = let used_integer_registers =
self.next_integer_register() - 1 - next_integer_register; self.next_integer_register() - next_integer_register;
if used_integer_registers > 1 { if used_integer_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_integer_register, next_integer_register,
next_integer_register + used_integer_registers, self.next_integer_register() - 2,
TypeCode::INTEGER, TypeCode::INTEGER,
); );
@ -1336,20 +1333,19 @@ impl<'src> Compiler<'src> {
} }
} }
Type::String => { Type::String => {
let used_string_registers = let used_string_registers = self.next_string_register() - next_string_register;
self.next_string_register() - 1 - next_string_register;
if used_string_registers > 1 { if used_string_registers > 1 {
let close = Instruction::close( let close = Instruction::close(
next_string_register, next_string_register,
next_string_register + used_string_registers, self.next_string_register() - 2,
TypeCode::STRING, TypeCode::STRING,
); );
self.emit_instruction(close, Type::None, self.current_position); self.emit_instruction(close, Type::None, self.current_position);
} }
} }
Type::List(_) => { Type::List { .. } => {
let used_list_registers = self.next_list_register() - next_list_register; let used_list_registers = self.next_list_register() - next_list_register;
if used_list_registers > 1 { if used_list_registers > 1 {
@ -1374,7 +1370,7 @@ impl<'src> Compiler<'src> {
Type::Float => self.next_float_register().saturating_sub(1), Type::Float => self.next_float_register().saturating_sub(1),
Type::Integer => self.next_integer_register().saturating_sub(1), Type::Integer => self.next_integer_register().saturating_sub(1),
Type::String => self.next_string_register().saturating_sub(1), Type::String => self.next_string_register().saturating_sub(1),
Type::List(_) => self.next_list_register().saturating_sub(1), Type::List { .. } => self.next_list_register().saturating_sub(1),
_ => todo!(), _ => todo!(),
}; };
let destination = self.next_list_register(); let destination = self.next_list_register();
@ -1595,7 +1591,7 @@ impl<'src> Compiler<'src> {
} }
let end = self.previous_position.1; let end = self.previous_position.1;
let destination = match function.r#type().return_type { let destination = match function.r#type().return_type.as_ref() {
Type::Boolean => self.next_boolean_register(), Type::Boolean => self.next_boolean_register(),
Type::Byte => self.next_byte_register(), Type::Byte => self.next_byte_register(),
Type::Character => self.next_character_register(), Type::Character => self.next_character_register(),
@ -1605,7 +1601,7 @@ impl<'src> Compiler<'src> {
Type::None => 0, Type::None => 0,
_ => todo!(), _ => todo!(),
}; };
let return_type = function.r#type().return_type; let return_type = *function.r#type().return_type;
let call_native = Instruction::from(CallNative { let call_native = Instruction::from(CallNative {
destination, destination,
function, function,
@ -1865,7 +1861,7 @@ impl<'src> Compiler<'src> {
function_compiler.prototype_index = self.prototypes.len() as u16; function_compiler.prototype_index = self.prototypes.len() as u16;
let mut value_parameters: Vec<(u16, Type)> = Vec::with_capacity(3); let mut value_parameters = Vec::with_capacity(3);
while !function_compiler.allow(Token::RightParenthesis)? { while !function_compiler.allow(Token::RightParenthesis)? {
let is_mutable = function_compiler.allow(Token::Mut)?; let is_mutable = function_compiler.allow(Token::Mut)?;
@ -1899,7 +1895,7 @@ impl<'src> Compiler<'src> {
Type::String => function_compiler.next_string_register(), Type::String => function_compiler.next_string_register(),
_ => todo!(), _ => todo!(),
}; };
let (_, identifier_index) = function_compiler.declare_local( function_compiler.declare_local(
parameter, parameter,
local_register_index, local_register_index,
r#type.clone(), r#type.clone(),
@ -1917,7 +1913,7 @@ impl<'src> Compiler<'src> {
_ => {} _ => {}
} }
value_parameters.push((identifier_index, r#type)); value_parameters.push(r#type);
function_compiler.allow(Token::Comma)?; function_compiler.allow(Token::Comma)?;
} }
@ -1933,11 +1929,7 @@ impl<'src> Compiler<'src> {
} else { } else {
Type::None Type::None
}; };
let function_type = FunctionType { let function_type = FunctionType::new([], value_parameters, return_type);
type_parameters: Vec::with_capacity(0),
value_parameters,
return_type,
};
function_compiler.r#type = function_type.clone(); function_compiler.r#type = function_type.clone();
@ -1963,7 +1955,7 @@ impl<'src> Compiler<'src> {
self.declare_local( self.declare_local(
identifier, identifier,
destination, destination,
Type::function(function_type.clone()), Type::Function(function_type.clone()),
false, false,
self.current_scope, self.current_scope,
); );
@ -1973,7 +1965,7 @@ impl<'src> Compiler<'src> {
self.emit_instruction( self.emit_instruction(
load_function, load_function,
Type::function(function_type), Type::Function(function_type),
Span(function_start, function_end), Span(function_start, function_end),
); );
@ -1995,7 +1987,7 @@ impl<'src> Compiler<'src> {
if !matches!( if !matches!(
last_instruction_type, last_instruction_type,
Type::Function(_) | Type::SelfFunction Type::Function { .. } | Type::SelfFunction
) { ) {
return Err(CompileError::ExpectedFunction { return Err(CompileError::ExpectedFunction {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -2006,8 +1998,8 @@ impl<'src> Compiler<'src> {
let function_register = last_instruction.a_field(); let function_register = last_instruction.a_field();
let function_return_type = match last_instruction_type { let function_return_type = match last_instruction_type {
Type::Function(function_type) => function_type.return_type.clone(), Type::Function(function_type) => *function_type.return_type.clone(),
Type::SelfFunction => self.r#type.return_type.clone(), Type::SelfFunction => *self.r#type.return_type.clone(),
_ => { _ => {
return Err(CompileError::ExpectedFunction { return Err(CompileError::ExpectedFunction {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),

View File

@ -597,7 +597,8 @@ impl Instruction {
function.returns_value() function.returns_value()
} }
Operation::EQUAL Operation::CLOSE
| Operation::EQUAL
| Operation::LESS | Operation::LESS
| Operation::LESS_EQUAL | Operation::LESS_EQUAL
| Operation::TEST | Operation::TEST

View File

@ -74,7 +74,7 @@ macro_rules! define_native_function {
pub fn returns_value(&self) -> bool { pub fn returns_value(&self) -> bool {
match self { match self {
$( $(
NativeFunction::$name => $type.return_type != Type::None, NativeFunction::$name => $type.return_type.as_ref() != &Type::None,
)* )*
} }
} }
@ -134,11 +134,7 @@ define_native_function! {
Panic, Panic,
3, 3,
"panic", "panic",
FunctionType { FunctionType::new([], [], Type::None),
type_parameters: Vec::with_capacity(0),
value_parameters: Vec::with_capacity(0),
return_type: Type::None
},
assert::panic assert::panic
), ),
@ -151,11 +147,7 @@ define_native_function! {
ToString, ToString,
8, 8,
"to_string", "to_string",
FunctionType { FunctionType::new([], [Type::Any], Type::String),
type_parameters: Vec::with_capacity(0),
value_parameters: vec![(0, Type::Any)],
return_type: Type::String
},
string::to_string string::to_string
), ),
@ -212,11 +204,7 @@ define_native_function! {
ReadLine, ReadLine,
50, 50,
"read_line", "read_line",
FunctionType { FunctionType::new([], [], Type::String),
type_parameters: Vec::with_capacity(0),
value_parameters: Vec::with_capacity(0),
return_type: Type::String
},
io::read_line io::read_line
), ),
// (ReadTo, 51_u8, "read_to", false), // (ReadTo, 51_u8, "read_to", false),
@ -228,11 +216,7 @@ define_native_function! {
Write, Write,
55, 55,
"write", "write",
FunctionType { FunctionType::new([], [Type::Any], Type::None),
type_parameters: Vec::with_capacity(0),
value_parameters: vec![(0, Type::String)],
return_type: Type::None
},
io::write io::write
), ),
// (WriteFile, 56_u8, "write_file", false), // (WriteFile, 56_u8, "write_file", false),
@ -240,11 +224,7 @@ define_native_function! {
WriteLine, WriteLine,
57, 57,
"write_line", "write_line",
FunctionType { FunctionType::new([], [Type::Any], Type::None),
type_parameters: Vec::with_capacity(0),
value_parameters: vec![(0, Type::String)],
return_type: Type::None
},
io::write_line io::write_line
), ),
@ -253,11 +233,7 @@ define_native_function! {
RandomInteger, RandomInteger,
58, 58,
"random_int", "random_int",
FunctionType { FunctionType::new([], [Type::Integer, Type::Integer], Type::Integer),
type_parameters: Vec::with_capacity(0),
value_parameters: vec![(0, Type::Integer), (1, Type::Integer)],
return_type: Type::Integer
},
random::random_int random::random_int
), ),
@ -266,20 +242,7 @@ define_native_function! {
Spawn, Spawn,
60, 60,
"spawn", "spawn",
FunctionType { FunctionType::new([], [ Type::function([], [], Type::Any)], Type::None),
type_parameters: Vec::with_capacity(0),
value_parameters: vec![
(
0,
Type::Function(Box::new(FunctionType {
type_parameters: Vec::with_capacity(0),
value_parameters: Vec::with_capacity(0),
return_type: Type::Any
}))
)
],
return_type: Type::None
},
thread::spawn thread::spawn
) )
} }

View File

@ -10,7 +10,8 @@ use serde::{Deserialize, Serialize};
use crate::instruction::TypeCode; use crate::instruction::TypeCode;
/// Description of a kind of value. /// Description of a kind of value.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "Type", content = "Value")]
pub enum Type { pub enum Type {
Any, Any,
Boolean, Boolean,
@ -18,31 +19,31 @@ pub enum Type {
Character, Character,
Enum(EnumType), Enum(EnumType),
Float, Float,
Function(Box<FunctionType>), Function(FunctionType),
Generic { Generic(GenericType),
identifier_index: u8,
concrete_type: Option<Box<Type>>,
},
Integer, Integer,
List(TypeCode), List(TypeCode),
Map { Map(Vec<Type>),
pairs: Vec<(u8, Type)>, #[default]
},
None, None,
Range { Range(Box<Type>),
r#type: Box<Type>,
},
SelfFunction, SelfFunction,
String, String,
Struct(StructType), Struct(StructType),
Tuple { Tuple(Vec<Type>),
fields: Vec<Type>,
},
} }
impl Type { impl Type {
pub fn function(function_type: FunctionType) -> Self { pub fn function<T: Into<Vec<u16>>, U: Into<Vec<Type>>>(
Type::Function(Box::new(function_type)) type_parameters: T,
value_parameters: U,
return_type: Type,
) -> Self {
Type::Function(FunctionType {
type_parameters: type_parameters.into(),
value_parameters: value_parameters.into(),
return_type: Box::new(return_type),
})
} }
pub fn type_code(&self) -> TypeCode { pub fn type_code(&self) -> TypeCode {
@ -54,18 +55,18 @@ impl Type {
Type::Integer => TypeCode::INTEGER, Type::Integer => TypeCode::INTEGER,
Type::None => TypeCode::NONE, Type::None => TypeCode::NONE,
Type::String => TypeCode::STRING, Type::String => TypeCode::STRING,
Type::List(_) => TypeCode::LIST, Type::List { .. } => TypeCode::LIST,
Type::Function(_) => TypeCode::FUNCTION, Type::Function { .. } => TypeCode::FUNCTION,
_ => todo!(), _ => todo!(),
} }
} }
/// Returns a concrete type, either the type itself or the concrete type of a generic type. /// Returns a concrete type, either the type itself or the concrete type of a generic type.
pub fn concrete_type(&self) -> &Type { pub fn concrete_type(&self) -> &Type {
if let Type::Generic { if let Type::Generic(GenericType {
concrete_type: Some(concrete_type), concrete_type: Some(concrete_type),
.. ..
} = self }) = self
{ {
concrete_type.concrete_type() concrete_type.concrete_type()
} else { } else {
@ -86,14 +87,14 @@ impl Type {
| (Type::None, Type::None) | (Type::None, Type::None)
| (Type::String { .. }, Type::String { .. }) => return Ok(()), | (Type::String { .. }, Type::String { .. }) => return Ok(()),
( (
Type::Generic { Type::Generic(GenericType {
concrete_type: left, concrete_type: left,
.. ..
}, }),
Type::Generic { Type::Generic(GenericType {
concrete_type: right, concrete_type: right,
.. ..
}, }),
) => match (left, right) { ) => match (left, right) {
(Some(left), Some(right)) => { (Some(left), Some(right)) => {
if left.check(right).is_ok() { if left.check(right).is_ok() {
@ -105,8 +106,8 @@ impl Type {
} }
_ => {} _ => {}
}, },
(Type::Generic { concrete_type, .. }, other) (Type::Generic(GenericType { concrete_type, .. }), other)
| (other, Type::Generic { concrete_type, .. }) => { | (other, Type::Generic(GenericType { concrete_type, .. })) => {
if let Some(concrete_type) = concrete_type { if let Some(concrete_type) = concrete_type {
if other == concrete_type.as_ref() { if other == concrete_type.as_ref() {
return Ok(()); return Ok(());
@ -133,12 +134,12 @@ impl Type {
type_parameters: left_type_parameters, type_parameters: left_type_parameters,
value_parameters: left_value_parameters, value_parameters: left_value_parameters,
return_type: left_return, return_type: left_return,
} = left_function_type.as_ref(); } = left_function_type;
let FunctionType { let FunctionType {
type_parameters: right_type_parameters, type_parameters: right_type_parameters,
value_parameters: right_value_parameters, value_parameters: right_value_parameters,
return_type: right_return, return_type: right_return,
} = right_function_type.as_ref(); } = right_function_type;
if left_return != right_return if left_return != right_return
|| left_type_parameters != right_type_parameters || left_type_parameters != right_type_parameters
@ -152,7 +153,7 @@ impl Type {
return Ok(()); return Ok(());
} }
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => { (Type::Range(left_type), Type::Range(right_type)) => {
if left_type == right_type { if left_type == right_type {
return Ok(()); return Ok(());
} }
@ -177,25 +178,24 @@ impl Display for Type {
Type::Enum(EnumType { name, .. }) => write!(f, "{name}"), Type::Enum(EnumType { name, .. }) => write!(f, "{name}"),
Type::Float => write!(f, "float"), Type::Float => write!(f, "float"),
Type::Function(function_type) => write!(f, "{function_type}"), Type::Function(function_type) => write!(f, "{function_type}"),
Type::Generic { concrete_type, .. } => { Type::Generic(GenericType { concrete_type, .. }) => {
match concrete_type.clone().map(|r#box| *r#box) { match concrete_type.clone().map(|r#box| *r#box) {
Some(Type::Generic { Some(Type::Generic(GenericType {
identifier_index: identifier, identifier_index, ..
.. })) => write!(f, "C_{identifier_index}"),
}) => write!(f, "{identifier}"),
Some(concrete_type) => write!(f, "implied to be {concrete_type}"), Some(concrete_type) => write!(f, "implied to be {concrete_type}"),
None => write!(f, "unknown"), None => write!(f, "unknown"),
} }
} }
Type::Integer => write!(f, "int"), Type::Integer => write!(f, "int"),
Type::List(item_type) => write!(f, "[{item_type}]"), Type::List(item_type) => write!(f, "[{item_type}]"),
Type::Map { pairs } => { Type::Map(pairs) => {
write!(f, "map ")?; write!(f, "map ")?;
write!(f, "{{")?; write!(f, "{{")?;
for (index, (key, value)) in pairs.iter().enumerate() { for (index, r#type) in pairs.iter().enumerate() {
write!(f, "{key}: {value}")?; write!(f, "???: {type}")?;
if index != pairs.len() - 1 { if index != pairs.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
@ -205,11 +205,11 @@ impl Display for Type {
write!(f, "}}") write!(f, "}}")
} }
Type::None => write!(f, "none"), Type::None => write!(f, "none"),
Type::Range { r#type } => write!(f, "{type} range"), Type::Range(r#type) => write!(f, "{type} range"),
Type::SelfFunction => write!(f, "self"), Type::SelfFunction => write!(f, "self"),
Type::String => write!(f, "str"), Type::String => write!(f, "str"),
Type::Struct(struct_type) => write!(f, "{struct_type}"), Type::Struct(struct_type) => write!(f, "{struct_type}"),
Type::Tuple { fields } => { Type::Tuple(fields) => {
write!(f, "(")?; write!(f, "(")?;
for (index, r#type) in fields.iter().enumerate() { for (index, r#type) in fields.iter().enumerate() {
@ -244,13 +244,13 @@ impl Ord for Type {
(Type::Character, Type::Character) => Ordering::Equal, (Type::Character, Type::Character) => Ordering::Equal,
(Type::Character, _) => Ordering::Greater, (Type::Character, _) => Ordering::Greater,
(Type::Enum(left_enum), Type::Enum(right_enum)) => left_enum.cmp(right_enum), (Type::Enum(left_enum), Type::Enum(right_enum)) => left_enum.cmp(right_enum),
(Type::Enum(_), _) => Ordering::Greater, (Type::Enum { .. }, _) => Ordering::Greater,
(Type::Float, Type::Float) => Ordering::Equal, (Type::Float, Type::Float) => Ordering::Equal,
(Type::Float, _) => Ordering::Greater, (Type::Float, _) => Ordering::Greater,
(Type::Function(left_function), Type::Function(right_function)) => { (Type::Function(left_function), Type::Function(right_function)) => {
left_function.cmp(right_function) left_function.cmp(right_function)
} }
(Type::Function(_), _) => Ordering::Greater, (Type::Function { .. }, _) => Ordering::Greater,
(Type::Generic { .. }, Type::Generic { .. }) => Ordering::Equal, (Type::Generic { .. }, Type::Generic { .. }) => Ordering::Equal,
(Type::Generic { .. }, _) => Ordering::Greater, (Type::Generic { .. }, _) => Ordering::Greater,
(Type::Integer, Type::Integer) => Ordering::Equal, (Type::Integer, Type::Integer) => Ordering::Equal,
@ -259,15 +259,13 @@ impl Ord for Type {
left_item_type.cmp(right_item_type) left_item_type.cmp(right_item_type)
} }
(Type::List { .. }, _) => Ordering::Greater, (Type::List { .. }, _) => Ordering::Greater,
(Type::Map { pairs: left_pairs }, Type::Map { pairs: right_pairs }) => { (Type::Map(left_pairs), Type::Map(right_pairs)) => {
left_pairs.iter().cmp(right_pairs.iter()) left_pairs.iter().cmp(right_pairs.iter())
} }
(Type::Map { .. }, _) => Ordering::Greater, (Type::Map { .. }, _) => Ordering::Greater,
(Type::None, Type::None) => Ordering::Equal, (Type::None, Type::None) => Ordering::Equal,
(Type::None, _) => Ordering::Greater, (Type::None, _) => Ordering::Greater,
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => { (Type::Range(left_type), Type::Range(right_type)) => left_type.cmp(right_type),
left_type.cmp(right_type)
}
(Type::Range { .. }, _) => Ordering::Greater, (Type::Range { .. }, _) => Ordering::Greater,
(Type::SelfFunction, Type::SelfFunction) => Ordering::Equal, (Type::SelfFunction, Type::SelfFunction) => Ordering::Equal,
(Type::SelfFunction, _) => Ordering::Greater, (Type::SelfFunction, _) => Ordering::Greater,
@ -276,9 +274,9 @@ impl Ord for Type {
(Type::Struct(left_struct), Type::Struct(right_struct)) => { (Type::Struct(left_struct), Type::Struct(right_struct)) => {
left_struct.cmp(right_struct) left_struct.cmp(right_struct)
} }
(Type::Struct(_), _) => Ordering::Greater, (Type::Struct { .. }, _) => Ordering::Greater,
(Type::Tuple { fields: left }, Type::Tuple { fields: right }) => left.cmp(right), (Type::Tuple(left), Type::Tuple(right)) => left.cmp(right),
(Type::Tuple { .. }, _) => Ordering::Greater, (Type::Tuple { .. }, _) => Ordering::Greater,
} }
} }
@ -287,12 +285,12 @@ impl Ord for Type {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType { pub struct FunctionType {
pub type_parameters: Vec<u16>, pub type_parameters: Vec<u16>,
pub value_parameters: Vec<(u16, Type)>, pub value_parameters: Vec<Type>,
pub return_type: Type, pub return_type: Box<Type>,
} }
impl FunctionType { impl FunctionType {
pub fn new<T: Into<Vec<u16>>, U: Into<Vec<(u16, Type)>>>( pub fn new<T: Into<Vec<u16>>, U: Into<Vec<Type>>>(
type_parameters: T, type_parameters: T,
value_parameters: U, value_parameters: U,
return_type: Type, return_type: Type,
@ -300,7 +298,7 @@ impl FunctionType {
FunctionType { FunctionType {
type_parameters: type_parameters.into(), type_parameters: type_parameters.into(),
value_parameters: value_parameters.into(), value_parameters: value_parameters.into(),
return_type, return_type: Box::new(return_type),
} }
} }
} }
@ -310,7 +308,7 @@ impl Default for FunctionType {
FunctionType { FunctionType {
type_parameters: Vec::new(), type_parameters: Vec::new(),
value_parameters: Vec::new(), value_parameters: Vec::new(),
return_type: Type::None, return_type: Box::new(Type::None),
} }
} }
} }
@ -336,7 +334,7 @@ impl Display for FunctionType {
write!(f, "(")?; write!(f, "(")?;
if !self.value_parameters.is_empty() { if !self.value_parameters.is_empty() {
for (index, (_, r#type)) in self.value_parameters.iter().enumerate() { for (index, r#type) in self.value_parameters.iter().enumerate() {
if index > 0 { if index > 0 {
write!(f, ", ")?; write!(f, ", ")?;
} }
@ -347,7 +345,7 @@ impl Display for FunctionType {
write!(f, ")")?; write!(f, ")")?;
if self.return_type != Type::None { if self.return_type.as_ref() != &Type::None {
write!(f, " -> {}", self.return_type)?; write!(f, " -> {}", self.return_type)?;
} }
@ -491,6 +489,12 @@ impl Display for EnumType {
} }
} }
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct GenericType {
pub identifier_index: u8,
pub concrete_type: Option<Box<Type>>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict { pub struct TypeConflict {
pub expected: Type, pub expected: Type,

View File

@ -11,6 +11,7 @@ use super::RangeValue;
pub type DustString = SmartString<LazyCompact>; pub type DustString = SmartString<LazyCompact>;
#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)] #[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
#[serde(tag = "type", content = "value")]
pub enum ConcreteValue { pub enum ConcreteValue {
Boolean(bool), Boolean(bool),
Byte(u8), Byte(u8),

View File

@ -50,6 +50,14 @@ impl Value {
Value::Concrete(ConcreteValue::String(string.into())) Value::Concrete(ConcreteValue::String(string.into()))
} }
pub fn as_concrete(&self) -> Option<&ConcreteValue> {
if let Value::Concrete(concrete_value) = self {
Some(concrete_value)
} else {
None
}
}
pub fn as_boolean(&self) -> Option<bool> { pub fn as_boolean(&self) -> Option<bool> {
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = self { if let Value::Concrete(ConcreteValue::Boolean(boolean)) = self {
Some(*boolean) Some(*boolean)
@ -118,7 +126,7 @@ impl Value {
match self { match self {
Value::Concrete(concrete_value) => concrete_value.r#type(), Value::Concrete(concrete_value) => concrete_value.r#type(),
Value::AbstractList(AbstractList { item_type, .. }) => Type::List(*item_type), Value::AbstractList(AbstractList { item_type, .. }) => Type::List(*item_type),
Value::Function(Function { r#type, .. }) => Type::Function(Box::new(r#type.clone())), Value::Function(Function { r#type, .. }) => Type::Function(r#type.clone()),
} }
} }

View File

@ -32,9 +32,7 @@ impl RangeValue {
} }
}; };
Type::Range { Type::Range(Box::new(inner_type))
r#type: Box::new(inner_type),
}
} }
} }

View File

@ -7,10 +7,7 @@ use dust_lang::{
fn add_bytes() { fn add_bytes() {
let source = "0x28 + 0x02"; let source = "0x28 + 0x02";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Byte),
return_type: Type::Byte,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, 40, TypeCode::BYTE, false), Instruction::load_encoded(0, 40, TypeCode::BYTE, false),
Instruction::load_encoded(1, 2, TypeCode::BYTE, false), Instruction::load_encoded(1, 2, TypeCode::BYTE, false),
@ -34,10 +31,7 @@ fn add_bytes() {
fn add_characters() { fn add_characters() {
let source = "'a' + 'b'"; let source = "'a' + 'b'";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::String),
return_type: Type::String,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::add( Instruction::add(
0, 0,
@ -60,10 +54,7 @@ fn add_characters() {
fn add_floats() { fn add_floats() {
let source = "2.40 + 40.02"; let source = "2.40 + 40.02";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Float),
return_type: Type::Float,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::add( Instruction::add(
0, 0,
@ -86,10 +77,7 @@ fn add_floats() {
fn add_integers() { fn add_integers() {
let source = "40 + 2"; let source = "40 + 2";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Integer),
return_type: Type::Integer,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::add( Instruction::add(
0, 0,
@ -112,10 +100,7 @@ fn add_integers() {
fn add_strings() { fn add_strings() {
let source = "\"Hello, \" + \"World!\""; let source = "\"Hello, \" + \"World!\"";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::String),
return_type: Type::String,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::add( Instruction::add(
0, 0,

View File

@ -7,10 +7,7 @@ use dust_lang::{
fn load_boolean_true() { fn load_boolean_true() {
let source = "true"; let source = "true";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Boolean),
return_type: Type::Boolean,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false), Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
Instruction::r#return(true, 0, TypeCode::BOOLEAN), Instruction::r#return(true, 0, TypeCode::BOOLEAN),
@ -28,10 +25,7 @@ fn load_boolean_true() {
fn load_boolean_false() { fn load_boolean_false() {
let source = "false"; let source = "false";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Boolean),
return_type: Type::Boolean,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false), Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
Instruction::r#return(true, 0, TypeCode::BOOLEAN), Instruction::r#return(true, 0, TypeCode::BOOLEAN),
@ -49,10 +43,7 @@ fn load_boolean_false() {
fn load_byte() { fn load_byte() {
let source = "0x2a"; let source = "0x2a";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Byte),
return_type: Type::Byte,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false), Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
Instruction::r#return(true, 0, TypeCode::BYTE), Instruction::r#return(true, 0, TypeCode::BYTE),
@ -70,10 +61,7 @@ fn load_byte() {
fn load_character() { fn load_character() {
let source = "'a'"; let source = "'a'";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Character),
return_type: Type::Character,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false), Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
Instruction::r#return(true, 0, TypeCode::CHARACTER), Instruction::r#return(true, 0, TypeCode::CHARACTER),
@ -92,10 +80,7 @@ fn load_character() {
fn load_float() { fn load_float() {
let source = "42.42"; let source = "42.42";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Float),
return_type: Type::Float,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::FLOAT, false), Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
Instruction::r#return(true, 0, TypeCode::FLOAT), Instruction::r#return(true, 0, TypeCode::FLOAT),
@ -114,10 +99,7 @@ fn load_float() {
fn load_integer() { fn load_integer() {
let source = "42"; let source = "42";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::Integer),
return_type: Type::Integer,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::INTEGER, false), Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
Instruction::r#return(true, 0, TypeCode::INTEGER), Instruction::r#return(true, 0, TypeCode::INTEGER),
@ -136,10 +118,7 @@ fn load_integer() {
fn load_string() { fn load_string() {
let source = "\"Hello, World!\""; let source = "\"Hello, World!\"";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::String),
return_type: Type::String,
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::STRING, false), Instruction::load_constant(0, 0, TypeCode::STRING, false),
Instruction::r#return(true, 0, TypeCode::STRING), Instruction::r#return(true, 0, TypeCode::STRING),
@ -158,10 +137,7 @@ fn load_string() {
fn load_boolean_list() { fn load_boolean_list() {
let source = "[true, false]"; let source = "[true, false]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::BOOLEAN)),
return_type: Type::List(TypeCode::BOOLEAN),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false), Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false), Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
@ -184,10 +160,7 @@ fn load_boolean_list() {
fn load_byte_list() { fn load_byte_list() {
let source = "[0x2a, 0x42]"; let source = "[0x2a, 0x42]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::BYTE)),
return_type: Type::List(TypeCode::BYTE),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false), Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
Instruction::load_encoded(1, 0x42, TypeCode::BYTE, false), Instruction::load_encoded(1, 0x42, TypeCode::BYTE, false),
@ -210,10 +183,7 @@ fn load_byte_list() {
fn load_character_list() { fn load_character_list() {
let source = "['a', 'b']"; let source = "['a', 'b']";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::CHARACTER)),
return_type: Type::List(TypeCode::CHARACTER),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false), Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
Instruction::load_constant(1, 1, TypeCode::CHARACTER, false), Instruction::load_constant(1, 1, TypeCode::CHARACTER, false),
@ -237,10 +207,7 @@ fn load_character_list() {
fn load_float_list() { fn load_float_list() {
let source = "[42.42, 24.24]"; let source = "[42.42, 24.24]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::FLOAT)),
return_type: Type::List(TypeCode::FLOAT),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::FLOAT, false), Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
Instruction::load_constant(1, 1, TypeCode::FLOAT, false), Instruction::load_constant(1, 1, TypeCode::FLOAT, false),
@ -264,10 +231,7 @@ fn load_float_list() {
fn load_integer_list() { fn load_integer_list() {
let source = "[1, 2, 3]"; let source = "[1, 2, 3]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::INTEGER)),
return_type: Type::List(TypeCode::INTEGER),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::INTEGER, false), Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
Instruction::load_constant(1, 1, TypeCode::INTEGER, false), Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
@ -297,10 +261,7 @@ fn load_integer_list() {
fn load_string_list() { fn load_string_list() {
let source = "[\"Hello\", \"World\"]"; let source = "[\"Hello\", \"World\"]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::STRING)),
return_type: Type::List(TypeCode::STRING),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::STRING, false), Instruction::load_constant(0, 0, TypeCode::STRING, false),
Instruction::load_constant(1, 1, TypeCode::STRING, false), Instruction::load_constant(1, 1, TypeCode::STRING, false),
@ -327,10 +288,7 @@ fn load_string_list() {
fn load_nested_list() { fn load_nested_list() {
let source = "[[1, 2], [3, 4]]"; let source = "[[1, 2], [3, 4]]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::LIST)),
return_type: Type::List(TypeCode::LIST),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::INTEGER, false), Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
Instruction::load_constant(1, 1, TypeCode::INTEGER, false), Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
@ -372,10 +330,7 @@ fn load_nested_list() {
fn load_deeply_nested_list() { fn load_deeply_nested_list() {
let source = "[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]"; let source = "[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]";
let chunk = Chunk { let chunk = Chunk {
r#type: FunctionType { r#type: FunctionType::new([], [], Type::List(TypeCode::LIST)),
return_type: Type::List(TypeCode::LIST),
..FunctionType::default()
},
instructions: vec![ instructions: vec![
Instruction::load_constant(0, 0, TypeCode::INTEGER, false), Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
Instruction::load_constant(1, 1, TypeCode::INTEGER, false), Instruction::load_constant(1, 1, TypeCode::INTEGER, false),