1
0

Optimize with more SmallVecs

This commit is contained in:
Jeff 2024-12-04 13:31:02 -05:00
parent e5742f6294
commit 1c3c30ac21
20 changed files with 316 additions and 246 deletions

View File

@ -16,8 +16,8 @@ use log::{Level, LevelFilter};
struct Cli { struct Cli {
/// Log level, overrides the DUST_LOG environment variable /// Log level, overrides the DUST_LOG environment variable
/// ///
/// Possible values: trace, debug, info, warn, error /// Possible values: trace, debug, info, warn, error, off
#[arg(short, long, global = true, value_name = "LOG_LEVEL")] #[arg(short, long, value_name = "LOG_LEVEL")]
log: Option<LevelFilter>, log: Option<LevelFilter>,
#[command(flatten)] #[command(flatten)]
@ -28,7 +28,7 @@ struct Cli {
} }
#[derive(Args)] #[derive(Args)]
#[group(required = true, multiple = false)] #[group(multiple = false)]
struct ModeFlags { struct ModeFlags {
/// Run the source code (default) /// Run the source code (default)
#[arg(short, long)] #[arg(short, long)]
@ -106,24 +106,6 @@ fn main() {
read_to_string(path).expect("Failed to read file") read_to_string(path).expect("Failed to read file")
}; };
if mode.run {
let run_result = run(&source);
match run_result {
Ok(Some(value)) => {
if !mode.no_output {
println!("{}", value)
}
}
Ok(None) => {}
Err(error) => {
eprintln!("{}", error.report());
}
}
return;
}
if mode.disassemble { if mode.disassemble {
let chunk = match compile(&source) { let chunk = match compile(&source) {
Ok(chunk) => chunk, Ok(chunk) => chunk,
@ -157,6 +139,20 @@ fn main() {
write_token_list(&tokens, mode.style, &mut stdout) write_token_list(&tokens, mode.style, &mut stdout)
} }
let run_result = run(&source);
match run_result {
Ok(Some(value)) => {
if !mode.no_output {
println!("{}", value)
}
}
Ok(None) => {}
Err(error) => {
eprintln!("{}", error.report());
}
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -20,7 +20,8 @@ pub struct Chunk {
name: Option<String>, name: Option<String>,
r#type: FunctionType, r#type: FunctionType,
instructions: SmallVec<[(Instruction, Span); 32]>, instructions: SmallVec<[Instruction; 32]>,
positions: SmallVec<[Span; 32]>,
constants: SmallVec<[ConcreteValue; 16]>, constants: SmallVec<[ConcreteValue; 16]>,
locals: SmallVec<[Local; 8]>, locals: SmallVec<[Local; 8]>,
} }
@ -30,12 +31,13 @@ impl Chunk {
Self { Self {
name, name,
instructions: SmallVec::new(), instructions: SmallVec::new(),
positions: SmallVec::new(),
constants: SmallVec::new(), constants: SmallVec::new(),
locals: SmallVec::new(), locals: SmallVec::new(),
r#type: FunctionType { r#type: FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: None,
return_type: Box::new(Type::None), return_type: Type::None,
}, },
} }
} }
@ -43,16 +45,18 @@ impl Chunk {
pub fn with_data( pub fn with_data(
name: Option<String>, name: Option<String>,
r#type: FunctionType, r#type: FunctionType,
instructions: Vec<(Instruction, Span)>, instructions: SmallVec<[Instruction; 32]>,
constants: Vec<ConcreteValue>, positions: SmallVec<[Span; 32]>,
locals: Vec<Local>, constants: SmallVec<[ConcreteValue; 16]>,
locals: SmallVec<[Local; 8]>,
) -> Self { ) -> Self {
Self { Self {
name, name,
r#type, r#type,
instructions: instructions.into(), instructions,
constants: constants.into(), positions,
locals: locals.into(), constants,
locals,
} }
} }
@ -76,10 +80,14 @@ impl Chunk {
&self.constants &self.constants
} }
pub fn instructions(&self) -> &SmallVec<[(Instruction, Span); 32]> { pub fn instructions(&self) -> &SmallVec<[Instruction; 32]> {
&self.instructions &self.instructions
} }
pub fn positions(&self) -> &SmallVec<[Span; 32]> {
&self.positions
}
pub fn locals(&self) -> &SmallVec<[Local; 8]> { pub fn locals(&self) -> &SmallVec<[Local; 8]> {
&self.locals &self.locals
} }
@ -88,7 +96,7 @@ impl Chunk {
self.instructions() self.instructions()
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, _)| { .find_map(|instruction| {
if instruction.yields_value() { if instruction.yields_value() {
Some(instruction.a() as usize + 1) Some(instruction.a() as usize + 1)
} else { } else {

View File

@ -8,10 +8,10 @@ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
mem::replace, mem::replace,
num::{ParseFloatError, ParseIntError}, num::{ParseFloatError, ParseIntError},
vec,
}; };
use colored::Colorize; use colored::Colorize;
use smallvec::{smallvec, SmallVec};
use crate::{ use crate::{
instruction::{ instruction::{
@ -36,12 +36,11 @@ use crate::{
/// ``` /// ```
pub fn compile(source: &str) -> Result<Chunk, DustError> { pub fn compile(source: &str) -> Result<Chunk, DustError> {
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
let mut compiler = let mut compiler = Compiler::new(lexer).map_err(|error| DustError::compile(error, source))?;
Compiler::new(lexer).map_err(|error| DustError::Compile { error, source })?;
compiler compiler
.compile() .compile()
.map_err(|error| DustError::Compile { error, source })?; .map_err(|error| DustError::compile(error, source))?;
let chunk = compiler.finish(None, None); let chunk = compiler.finish(None, None);
@ -54,9 +53,9 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
#[derive(Debug)] #[derive(Debug)]
pub struct Compiler<'src> { pub struct Compiler<'src> {
self_name: Option<DustString>, self_name: Option<DustString>,
instructions: Vec<(Instruction, Type, Span)>, instructions: SmallVec<[(Instruction, Type, Span); 32]>,
constants: Vec<ConcreteValue>, constants: SmallVec<[ConcreteValue; 16]>,
locals: Vec<Local>, locals: SmallVec<[Local; 8]>,
lexer: Lexer<'src>, lexer: Lexer<'src>,
@ -83,9 +82,9 @@ impl<'src> Compiler<'src> {
Ok(Compiler { Ok(Compiler {
self_name: None, self_name: None,
instructions: Vec::new(), instructions: SmallVec::new(),
constants: Vec::new(), constants: SmallVec::new(),
locals: Vec::new(), locals: SmallVec::new(),
lexer, lexer,
current_token, current_token,
current_position, current_position,
@ -100,26 +99,27 @@ impl<'src> Compiler<'src> {
pub fn finish( pub fn finish(
self, self,
type_parameters: Option<Vec<u16>>, type_parameters: Option<SmallVec<[u16; 4]>>,
value_parameters: Option<Vec<(u16, Type)>>, value_parameters: Option<SmallVec<[(u16, Type); 4]>>,
) -> Chunk { ) -> Chunk {
log::info!("End chunk"); log::info!("End chunk");
let r#type = FunctionType { let r#type = FunctionType {
type_parameters, type_parameters,
value_parameters, value_parameters,
return_type: Box::new(self.return_type.unwrap_or(Type::None)), return_type: self.return_type.unwrap_or(Type::None),
}; };
let instructions = self let (instructions, positions) = self
.instructions .instructions
.into_iter() .into_iter()
.map(|(i, _, s)| (i, s)) .map(|(instruction, _, position)| (instruction, position))
.collect(); .unzip();
Chunk::with_data( Chunk::with_data(
self.self_name, self.self_name,
r#type, r#type,
instructions, instructions,
positions,
self.constants, self.constants,
self.locals, self.locals,
) )
@ -1301,7 +1301,7 @@ impl<'src> Compiler<'src> {
let end = self.previous_position.1; let end = self.previous_position.1;
let destination = self.next_register(); let destination = self.next_register();
let argument_count = destination - start_register; let argument_count = destination - start_register;
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::Register(destination), destination: Destination::Register(destination),
function, function,
@ -1453,7 +1453,7 @@ impl<'src> Compiler<'src> {
function_compiler.expect(Token::LeftParenthesis)?; function_compiler.expect(Token::LeftParenthesis)?;
let mut value_parameters: Option<Vec<(u16, Type)>> = None; let mut value_parameters: Option<SmallVec<[(u16, Type); 4]>> = None;
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)?;
@ -1488,7 +1488,7 @@ impl<'src> Compiler<'src> {
if let Some(value_parameters) = value_parameters.as_mut() { if let Some(value_parameters) = value_parameters.as_mut() {
value_parameters.push((identifier_index, r#type)); value_parameters.push((identifier_index, r#type));
} else { } else {
value_parameters = Some(vec![(identifier_index, r#type)]); value_parameters = Some(smallvec![(identifier_index, r#type)]);
}; };
function_compiler.minimum_register += 1; function_compiler.minimum_register += 1;
@ -1504,12 +1504,12 @@ impl<'src> Compiler<'src> {
function_compiler.advance()?; function_compiler.advance()?;
Box::new(r#type) r#type
} else { } else {
Box::new(Type::None) Type::None
}; };
function_compiler.return_type = Some((*return_type).clone()); function_compiler.return_type = Some((return_type).clone());
function_compiler.expect(Token::LeftBrace)?; function_compiler.expect(Token::LeftBrace)?;
function_compiler.compile()?; function_compiler.compile()?;
@ -1536,7 +1536,7 @@ impl<'src> Compiler<'src> {
if let Some((identifier, position)) = identifier_info { if let Some((identifier, position)) = identifier_info {
let (local_index, _) = self.declare_local( let (local_index, _) = self.declare_local(
identifier, identifier,
Type::Function(function_type.clone()), Type::function(function_type.clone()),
false, false,
self.current_scope, self.current_scope,
); );
@ -1553,7 +1553,7 @@ impl<'src> Compiler<'src> {
self.emit_instruction( self.emit_instruction(
load_constant, load_constant,
Type::Function(function_type), Type::function(function_type),
Span(function_start, function_end), Span(function_start, function_end),
); );
self.emit_instruction(define_local, Type::None, position); self.emit_instruction(define_local, Type::None, position);
@ -1566,7 +1566,7 @@ impl<'src> Compiler<'src> {
self.emit_instruction( self.emit_instruction(
load_constant, load_constant,
Type::Function(function_type), Type::function(function_type),
Span(function_start, function_end), Span(function_start, function_end),
); );
} }
@ -1598,7 +1598,7 @@ impl<'src> Compiler<'src> {
})?; })?;
let register_type = self.get_register_type(function.index())?; let register_type = self.get_register_type(function.index())?;
let function_return_type = match register_type { let function_return_type = match register_type {
Type::Function(function_type) => *function_type.return_type, Type::Function(function_type) => function_type.return_type,
Type::SelfChunk => self.return_type.clone().unwrap_or(Type::None), Type::SelfChunk => self.return_type.clone().unwrap_or(Type::None),
_ => { _ => {
return Err(CompileError::ExpectedFunction { return Err(CompileError::ExpectedFunction {
@ -1610,12 +1610,8 @@ impl<'src> Compiler<'src> {
}; };
let start = self.current_position.0; let start = self.current_position.0;
println!("{} {}", self.previous_token, self.current_token);
self.advance()?; self.advance()?;
println!("{} {}", self.previous_token, self.current_token);
let mut argument_count = 0; let mut argument_count = 0;
while !self.allow(Token::RightParenthesis)? { while !self.allow(Token::RightParenthesis)? {

View File

@ -209,7 +209,13 @@ impl<'a> Disassembler<'a> {
self.push_header(line); self.push_header(line);
} }
for (index, (instruction, position)) in self.chunk.instructions().iter().enumerate() { for (index, (instruction, position)) in self
.chunk
.instructions()
.iter()
.zip(self.chunk.positions().iter())
.enumerate()
{
let position = position.to_string(); let position = position.to_string();
let operation = instruction.operation().to_string(); let operation = instruction.operation().to_string();
let info = instruction.disassembly_info(); let info = instruction.disassembly_info();

View File

@ -1,7 +1,10 @@
//! Top-level Dust errors with source code annotations. //! Top-level Dust errors with source code annotations.
use std::fmt::{self, Display, Formatter};
use annotate_snippets::{Level, Renderer, Snippet}; use annotate_snippets::{Level, Renderer, Snippet};
use crate::{vm::VmError, CompileError, Span}; use crate::{CompileError, Span, VmError};
/// A top-level error that can occur during the execution of Dust code. /// A top-level error that can occur during the execution of Dust code.
/// ///
@ -19,43 +22,60 @@ pub enum DustError<'src> {
} }
impl<'src> DustError<'src> { impl<'src> DustError<'src> {
pub fn report(&self) -> String { pub fn compile(error: CompileError, source: &'src str) -> Self {
DustError::Compile { error, source }
}
pub fn runtime(error: VmError, source: &'src str) -> Self {
DustError::Runtime { error, source }
}
pub fn create_report(&self) -> String {
let (position, title, description, details) = self.error_data();
let label = format!("{}: {}", title, description);
let details = details.unwrap_or_else(|| "While parsing this code".to_string());
let message = Level::Error.title(&label).snippet(
Snippet::source(self.source())
.fold(false)
.annotation(Level::Error.span(position.0..position.1).label(&details)),
);
let mut report = String::new(); let mut report = String::new();
let renderer = Renderer::styled(); let renderer = Renderer::styled();
match self {
DustError::Runtime { error, source } => {
let position = error.position();
let label = format!("{}: {}", VmError::title(), error.description());
let details = error
.details()
.unwrap_or_else(|| "While running this code".to_string());
let message = Level::Error.title(&label).snippet(
Snippet::source(source)
.fold(false)
.annotation(Level::Error.span(position.0..position.1).label(&details)),
);
report.push_str(&renderer.render(message).to_string()); report.push_str(&renderer.render(message).to_string());
}
DustError::Compile { error, source } => {
let position = error.position();
let label = format!("{}: {}", CompileError::title(), error.description());
let details = error
.details()
.unwrap_or_else(|| "While parsing this code".to_string());
let message = Level::Error.title(&label).snippet(
Snippet::source(source)
.fold(false)
.annotation(Level::Error.span(position.0..position.1).label(&details)),
);
report.push_str(&renderer.render(message).to_string());
}
}
report report
} }
fn error_data(&self) -> (Span, &str, &str, Option<String>) {
match self {
Self::Compile { error, .. } => (
error.position(),
CompileError::title(),
error.description(),
error.details(),
),
Self::Runtime { error, .. } => (
error.position(),
VmError::title(),
error.description(),
error.details(),
),
}
}
fn source(&self) -> &str {
match self {
Self::Compile { source, .. } => source,
Self::Runtime { source, .. } => source,
}
}
}
impl Display for DustError<'_> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.create_report())
}
} }
pub trait AnnotatedError { pub trait AnnotatedError {

View File

@ -35,10 +35,9 @@ pub fn lex(source: &str) -> Result<Vec<(Token, Span)>, DustError> {
let mut tokens = Vec::new(); let mut tokens = Vec::new();
loop { loop {
let (token, span) = lexer.next_token().map_err(|error| DustError::Compile { let (token, span) = lexer
error: CompileError::Lex(error), .next_token()
source, .map_err(|error| DustError::compile(CompileError::Lex(error), source))?;
})?;
tokens.push((token, span)); tokens.push((token, span));

View File

@ -11,6 +11,7 @@ use std::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::smallvec;
use crate::{AnnotatedError, FunctionType, Instruction, Span, Type, Value, Vm, VmError}; use crate::{AnnotatedError, FunctionType, Instruction, Span, Type, Value, Vm, VmError};
@ -68,7 +69,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 != Type::None,
)* )*
} }
} }
@ -131,7 +132,7 @@ define_native_function! {
FunctionType { FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: None,
return_type: Box::new(Type::None) return_type: Type::None
}, },
logic::panic logic::panic
), ),
@ -147,8 +148,8 @@ define_native_function! {
"to_string", "to_string",
FunctionType { FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: Some(vec![(0, Type::Any)]), value_parameters: Some(smallvec![(0, Type::Any)]),
return_type: Box::new(Type::String) return_type: Type::String
}, },
logic::to_string logic::to_string
), ),
@ -209,7 +210,7 @@ define_native_function! {
FunctionType { FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: None,
return_type: Box::new(Type::String) return_type: Type::String
}, },
logic::read_line logic::read_line
), ),
@ -224,8 +225,8 @@ define_native_function! {
"write", "write",
FunctionType { FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: Some(vec![(0, Type::String)]), value_parameters: Some(smallvec![(0, Type::String)]),
return_type: Box::new(Type::None) return_type: Type::None
}, },
logic::write logic::write
), ),
@ -236,8 +237,8 @@ define_native_function! {
"write_line", "write_line",
FunctionType { FunctionType {
type_parameters: None, type_parameters: None,
value_parameters: Some(vec![(0, Type::String)]), value_parameters: Some(smallvec![(0, Type::String)]),
return_type: Box::new(Type::None) return_type: Type::None
}, },
logic::write_line logic::write_line
) )

View File

@ -1,5 +1,7 @@
//! Tools used by the compiler to optimize a chunk's bytecode. //! Tools used by the compiler to optimize a chunk's bytecode.
use smallvec::SmallVec;
use crate::{instruction::SetLocal, Instruction, Operation, Span, Type}; use crate::{instruction::SetLocal, Instruction, Operation, Span, Type};
fn get_last_operations<const COUNT: usize>( fn get_last_operations<const COUNT: usize>(
@ -83,7 +85,7 @@ pub fn optimize_control_flow(instructions: &mut [(Instruction, Type, Span)]) {
/// The instructions must be in the following order: /// The instructions must be in the following order:
/// - `Add`, `Subtract`, `Multiply`, `Divide` or `Modulo` /// - `Add`, `Subtract`, `Multiply`, `Divide` or `Modulo`
/// - `SetLocal` /// - `SetLocal`
pub fn optimize_set_local(instructions: &mut Vec<(Instruction, Type, Span)>) { pub fn optimize_set_local(instructions: &mut SmallVec<[(Instruction, Type, Span); 32]>) {
if !matches!( if !matches!(
get_last_operations(instructions), get_last_operations(instructions),
Some([ Some([

View File

@ -6,6 +6,7 @@ use std::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smallvec::SmallVec;
/// Description of a kind of value. /// Description of a kind of value.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
@ -16,7 +17,7 @@ pub enum Type {
Character, Character,
Enum(EnumType), Enum(EnumType),
Float, Float,
Function(FunctionType), Function(Box<FunctionType>),
Generic { Generic {
identifier_index: u8, identifier_index: u8,
concrete_type: Option<Box<Type>>, concrete_type: Option<Box<Type>>,
@ -24,7 +25,7 @@ pub enum Type {
Integer, Integer,
List(Box<Type>), List(Box<Type>),
Map { Map {
pairs: HashMap<u8, Type>, pairs: Box<SmallVec<[(u8, Type); 8]>>,
}, },
None, None,
Range { Range {
@ -34,11 +35,19 @@ pub enum Type {
String, String,
Struct(StructType), Struct(StructType),
Tuple { Tuple {
fields: Option<Vec<Type>>, fields: Option<Box<SmallVec<[Type; 4]>>>,
}, },
} }
impl Type { impl Type {
pub fn function(function_type: FunctionType) -> Self {
Type::Function(Box::new(function_type))
}
pub fn list(element_type: Type) -> Self {
Type::List(Box::new(element_type))
}
/// 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 {
@ -107,18 +116,18 @@ impl Type {
return Ok(()); return Ok(());
} }
( (Type::Function(left_function_type), Type::Function(right_function_type)) => {
Type::Function(FunctionType { let FunctionType {
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();
Type::Function(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();
) => {
if left_return != right_return if left_return != right_return
|| left_type_parameters != right_type_parameters || left_type_parameters != right_type_parameters
|| left_value_parameters != right_value_parameters || left_value_parameters != right_value_parameters
@ -269,9 +278,23 @@ 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: Option<Vec<u16>>, pub type_parameters: Option<SmallVec<[u16; 4]>>,
pub value_parameters: Option<Vec<(u16, Type)>>, pub value_parameters: Option<SmallVec<[(u16, Type); 4]>>,
pub return_type: Box<Type>, pub return_type: Type,
}
impl FunctionType {
pub fn new<T: Into<SmallVec<[u16; 4]>>, U: Into<SmallVec<[(u16, Type); 4]>>>(
type_parameters: Option<T>,
value_parameters: Option<U>,
return_type: Type,
) -> Self {
FunctionType {
type_parameters: type_parameters.map(|into_types| into_types.into()),
value_parameters: value_parameters.map(|into_values| into_values.into()),
return_type,
}
}
} }
impl Display for FunctionType { impl Display for FunctionType {
@ -306,7 +329,7 @@ impl Display for FunctionType {
write!(f, ")")?; write!(f, ")")?;
if *self.return_type != Type::None { if self.return_type != Type::None {
write!(f, " -> {}", self.return_type)?; write!(f, " -> {}", self.return_type)?;
} }

View File

@ -57,7 +57,7 @@ impl ConcreteValue {
ConcreteValue::Byte(_) => Type::Byte, ConcreteValue::Byte(_) => Type::Byte,
ConcreteValue::Character(_) => Type::Character, ConcreteValue::Character(_) => Type::Character,
ConcreteValue::Float(_) => Type::Float, ConcreteValue::Float(_) => Type::Float,
ConcreteValue::Function(chunk) => Type::Function(chunk.r#type().clone()), ConcreteValue::Function(chunk) => Type::function(chunk.r#type().clone()),
ConcreteValue::Integer(_) => Type::Integer, ConcreteValue::Integer(_) => Type::Integer,
ConcreteValue::List(list) => { ConcreteValue::List(list) => {
let item_type = list.first().map_or(Type::Any, |item| item.r#type()); let item_type = list.first().map_or(Type::Any, |item| item.r#type());

View File

@ -14,10 +14,9 @@ use crate::{
pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> { pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
let chunk = compile(source)?; let chunk = compile(source)?;
let mut vm = Vm::new(&chunk, None); let mut vm = Vm::new(source, &chunk, None);
vm.run() vm.run().map_err(|error| DustError::runtime(error, source))
.map_err(|error| DustError::Runtime { error, source })
} }
/// Dust virtual machine. /// Dust virtual machine.
@ -25,18 +24,19 @@ pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
/// See the [module-level documentation](index.html) for more information. /// See the [module-level documentation](index.html) for more information.
#[derive(Debug)] #[derive(Debug)]
pub struct Vm<'a> { pub struct Vm<'a> {
chunk: &'a Chunk,
stack: SmallVec<[Register; 64]>, stack: SmallVec<[Register; 64]>,
chunk: &'a Chunk,
parent: Option<&'a Vm<'a>>, parent: Option<&'a Vm<'a>>,
local_definitions: SmallVec<[Option<u16>; 16]>, local_definitions: SmallVec<[Option<u16>; 16]>,
ip: usize, ip: usize,
last_assigned_register: Option<u16>, last_assigned_register: Option<u16>,
current_position: Span, source: &'a str,
} }
impl<'a> Vm<'a> { impl<'a> Vm<'a> {
pub fn new(chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self { pub fn new(source: &'a str, chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self {
Self { Self {
chunk, chunk,
stack: smallvec![Register::Empty; chunk.stack_size()], stack: smallvec![Register::Empty; chunk.stack_size()],
@ -44,7 +44,7 @@ impl<'a> Vm<'a> {
local_definitions: smallvec![None; chunk.locals().len()], local_definitions: smallvec![None; chunk.locals().len()],
ip: 0, ip: 0,
last_assigned_register: None, last_assigned_register: None,
current_position: Span(0, 0), source,
} }
} }
@ -53,7 +53,7 @@ impl<'a> Vm<'a> {
} }
pub fn current_position(&self) -> Span { pub fn current_position(&self) -> Span {
self.current_position self.chunk.positions()[self.ip.saturating_sub(1)]
} }
pub fn run(&mut self) -> Result<Option<ConcreteValue>, VmError> { pub fn run(&mut self) -> Result<Option<ConcreteValue>, VmError> {
@ -63,7 +63,7 @@ impl<'a> Vm<'a> {
log::info!( log::info!(
"{} | {} | {} | {}", "{} | {} | {} | {}",
self.ip - 1, self.ip - 1,
self.current_position, self.current_position(),
instruction.operation(), instruction.operation(),
instruction.disassembly_info() instruction.disassembly_info()
); );
@ -86,7 +86,7 @@ impl<'a> Vm<'a> {
if self.stack.len() < to as usize { if self.stack.len() < to as usize {
return Err(VmError::StackUnderflow { return Err(VmError::StackUnderflow {
position: self.current_position, position: self.current_position(),
}); });
} }
@ -173,7 +173,7 @@ impl<'a> Vm<'a> {
let local_register = self.local_definitions[local_index as usize].ok_or( let local_register = self.local_definitions[local_index as usize].ok_or(
VmError::UndefinedLocal { VmError::UndefinedLocal {
local_index, local_index,
position: self.current_position, position: self.current_position(),
}, },
)?; )?;
let register = Register::Pointer(Pointer::Stack(local_register)); let register = Register::Pointer(Pointer::Stack(local_register));
@ -199,7 +199,17 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let sum_result = left.add(right); let sum_result = left.add(right);
assert!(sum_result.is_ok(), "VM Error: {}", sum_result.unwrap_err()); assert!(
sum_result.is_ok(),
"VM Error: {}",
DustError::runtime(
VmError::Value {
error: sum_result.unwrap_err(),
position: self.current_position()
},
self.source
)
);
let sum = sum_result.unwrap(); let sum = sum_result.unwrap();
@ -216,7 +226,7 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let difference = left.subtract(right).map_err(|error| VmError::Value { let difference = left.subtract(right).map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
self.set_register(register_index, Register::Value(difference))?; self.set_register(register_index, Register::Value(difference))?;
@ -232,7 +242,7 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let product = left.multiply(right).map_err(|error| VmError::Value { let product = left.multiply(right).map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
self.set_register(register_index, Register::Value(product))?; self.set_register(register_index, Register::Value(product))?;
@ -248,7 +258,7 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let quotient = left.divide(right).map_err(|error| VmError::Value { let quotient = left.divide(right).map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
self.set_register(register_index, Register::Value(quotient))?; self.set_register(register_index, Register::Value(quotient))?;
@ -264,7 +274,7 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let remainder = left.modulo(right).map_err(|error| VmError::Value { let remainder = left.modulo(right).map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
self.set_register(register_index, Register::Value(remainder))?; self.set_register(register_index, Register::Value(remainder))?;
@ -281,7 +291,7 @@ impl<'a> Vm<'a> {
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: value.to_owned(), found: value.to_owned(),
position: self.current_position, position: self.current_position(),
}); });
}; };
@ -303,7 +313,7 @@ impl<'a> Vm<'a> {
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: value.to_owned(), found: value.to_owned(),
position: self.current_position, position: self.current_position(),
}); });
}; };
@ -316,7 +326,7 @@ impl<'a> Vm<'a> {
let register_index = self.local_definitions[local_index as usize] let register_index = self.local_definitions[local_index as usize]
.ok_or(VmError::UndefinedLocal { .ok_or(VmError::UndefinedLocal {
local_index, local_index,
position: self.current_position, position: self.current_position(),
})?; })?;
Pointer::Stack(register_index) Pointer::Stack(register_index)
@ -334,7 +344,7 @@ impl<'a> Vm<'a> {
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let equal_result = left.equal(right).map_err(|error| VmError::Value { let equal_result = left.equal(right).map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
let is_equal = let is_equal =
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = equal_result { if let Value::Concrete(ConcreteValue::Boolean(boolean)) = equal_result {
@ -342,7 +352,7 @@ impl<'a> Vm<'a> {
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: equal_result, found: equal_result,
position: self.current_position, position: self.current_position(),
}); });
}; };
@ -360,7 +370,7 @@ impl<'a> Vm<'a> {
less_result.is_ok(), less_result.is_ok(),
"VM Error: {}\nPosition: {}", "VM Error: {}\nPosition: {}",
less_result.unwrap_err(), less_result.unwrap_err(),
self.current_position self.current_position()
); );
let less_than_value = less_result.unwrap(); let less_than_value = less_result.unwrap();
@ -369,7 +379,7 @@ impl<'a> Vm<'a> {
assert!( assert!(
less_than_boolean.is_some(), less_than_boolean.is_some(),
"VM Error: Expected a boolean\nPosition: {}", "VM Error: Expected a boolean\nPosition: {}",
self.current_position self.current_position()
); );
let is_less_than = less_than_boolean.unwrap(); let is_less_than = less_than_boolean.unwrap();
@ -386,7 +396,7 @@ impl<'a> Vm<'a> {
left.less_than_or_equal(right) left.less_than_or_equal(right)
.map_err(|error| VmError::Value { .map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
let is_less_than_or_equal = let is_less_than_or_equal =
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = if let Value::Concrete(ConcreteValue::Boolean(boolean)) =
@ -396,7 +406,7 @@ impl<'a> Vm<'a> {
} else { } else {
return Err(VmError::ExpectedBoolean { return Err(VmError::ExpectedBoolean {
found: less_or_equal_result, found: less_or_equal_result,
position: self.current_position, position: self.current_position(),
}); });
}; };
@ -412,7 +422,7 @@ impl<'a> Vm<'a> {
let value = self.get_argument(argument)?; let value = self.get_argument(argument)?;
let negated = value.negate().map_err(|error| VmError::Value { let negated = value.negate().map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
let register_index = self.get_destination(destination)?; let register_index = self.get_destination(destination)?;
let register = Register::Value(negated); let register = Register::Value(negated);
@ -427,7 +437,7 @@ impl<'a> Vm<'a> {
let value = self.get_argument(argument)?; let value = self.get_argument(argument)?;
let not = value.not().map_err(|error| VmError::Value { let not = value.not().map_err(|error| VmError::Value {
error, error,
position: self.current_position, position: self.current_position(),
})?; })?;
let register_index = self.get_destination(destination)?; let register_index = self.get_destination(destination)?;
let register = Register::Value(not); let register = Register::Value(not);
@ -458,10 +468,10 @@ impl<'a> Vm<'a> {
} else { } else {
return Err(VmError::ExpectedFunction { return Err(VmError::ExpectedFunction {
found: function.to_concrete_owned(self)?, found: function.to_concrete_owned(self)?,
position: self.current_position, position: self.current_position(),
}); });
}; };
let mut function_vm = Vm::new(chunk, Some(self)); let mut function_vm = Vm::new(self.source, chunk, Some(self));
let first_argument_index = register_index - argument_count; let first_argument_index = register_index - argument_count;
for (argument_index, argument_register_index) in for (argument_index, argument_register_index) in
@ -515,7 +525,7 @@ impl<'a> Vm<'a> {
Ok(Some(return_value)) Ok(Some(return_value))
} else { } else {
Err(VmError::StackUnderflow { Err(VmError::StackUnderflow {
position: self.current_position, position: self.current_position(),
}) })
}; };
} }
@ -536,7 +546,7 @@ impl<'a> Vm<'a> {
.parent .parent
.as_ref() .as_ref()
.ok_or_else(|| VmError::ExpectedParent { .ok_or_else(|| VmError::ExpectedParent {
position: self.current_position, position: self.current_position(),
})?; })?;
parent.open_register(register_index) parent.open_register(register_index)
@ -546,7 +556,7 @@ impl<'a> Vm<'a> {
.parent .parent
.as_ref() .as_ref()
.ok_or_else(|| VmError::ExpectedParent { .ok_or_else(|| VmError::ExpectedParent {
position: self.current_position, position: self.current_position(),
})?; })?;
let constant = parent.get_constant(constant_index); let constant = parent.get_constant(constant_index);
@ -572,7 +582,7 @@ impl<'a> Vm<'a> {
Register::Pointer(pointer) => self.follow_pointer(*pointer), Register::Pointer(pointer) => self.follow_pointer(*pointer),
Register::Empty => Err(VmError::EmptyRegister { Register::Empty => Err(VmError::EmptyRegister {
index: register_index, index: register_index,
position: self.current_position, position: self.current_position(),
}), }),
} }
} }
@ -587,7 +597,7 @@ impl<'a> Vm<'a> {
.get(register_index) .get(register_index)
.ok_or_else(|| VmError::RegisterIndexOutOfBounds { .ok_or_else(|| VmError::RegisterIndexOutOfBounds {
index: register_index, index: register_index,
position: self.current_position, position: self.current_position(),
})?; })?;
log::trace!("Open R{register_index} to {register}"); log::trace!("Open R{register_index} to {register}");
@ -685,7 +695,7 @@ impl<'a> Vm<'a> {
self.local_definitions[local_index].ok_or_else(|| VmError::UndefinedLocal { self.local_definitions[local_index].ok_or_else(|| VmError::UndefinedLocal {
local_index: local_index as u16, local_index: local_index as u16,
position: self.current_position, position: self.current_position(),
}) })
} }
@ -693,12 +703,21 @@ impl<'a> Vm<'a> {
fn read(&mut self) -> Instruction { fn read(&mut self) -> Instruction {
let instructions = self.chunk.instructions(); let instructions = self.chunk.instructions();
assert!(self.ip < instructions.len(), "VM Error: IP out of bounds"); assert!(
self.ip < instructions.len(),
"{}",
DustError::runtime(
VmError::InstructionIndexOutOfBounds {
index: self.ip,
position: self.current_position()
},
self.source,
)
);
let (instruction, position) = instructions[self.ip]; let instruction = instructions[self.ip];
self.ip += 1; self.ip += 1;
self.current_position = position;
instruction instruction
} }

View File

@ -6,7 +6,7 @@ fn add_assign_expects_mutable_variable() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedMutableVariable { error: CompileError::ExpectedMutableVariable {
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),
position: Span(0, 1) position: Span(0, 1)
@ -22,7 +22,7 @@ fn divide_assign_expects_mutable_variable() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedMutableVariable { error: CompileError::ExpectedMutableVariable {
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),
position: Span(0, 1) position: Span(0, 1)
@ -38,7 +38,7 @@ fn multiply_assign_expects_mutable_variable() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedMutableVariable { error: CompileError::ExpectedMutableVariable {
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),
position: Span(0, 1) position: Span(0, 1)
@ -54,7 +54,7 @@ fn subtract_assign_expects_mutable_variable() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedMutableVariable { error: CompileError::ExpectedMutableVariable {
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),
position: Span(0, 1) position: Span(0, 1)
@ -70,7 +70,7 @@ fn modulo_assign_expects_mutable_variable() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedMutableVariable { error: CompileError::ExpectedMutableVariable {
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),
position: Span(0, 1) position: Span(0, 1)

View File

@ -6,7 +6,7 @@ fn add_boolean_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(0, 4) position: Span(0, 4)
@ -22,7 +22,7 @@ fn add_boolean_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(4, 8) position: Span(4, 8)
@ -38,7 +38,7 @@ fn add_function_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -58,7 +58,7 @@ fn add_function_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -78,7 +78,7 @@ fn add_list_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(0, 6) position: Span(0, 6)
@ -94,7 +94,7 @@ fn add_list_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddType { error: CompileError::CannotAddType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(4, 10) position: Span(4, 10)
@ -121,7 +121,7 @@ fn add_byte_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Byte, left_type: Type::Byte,
right_type: Type::Character, right_type: Type::Character,
@ -138,7 +138,7 @@ fn add_byte_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Byte, left_type: Type::Byte,
right_type: Type::Integer, right_type: Type::Integer,
@ -155,7 +155,7 @@ fn add_byte_and_string() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Byte, left_type: Type::Byte,
right_type: Type::String, right_type: Type::String,
@ -172,7 +172,7 @@ fn add_character_and_byte() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Character, left_type: Type::Character,
right_type: Type::Byte, right_type: Type::Byte,
@ -189,7 +189,7 @@ fn add_character_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Character, left_type: Type::Character,
right_type: Type::Float, right_type: Type::Float,
@ -206,7 +206,7 @@ fn add_character_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Character, left_type: Type::Character,
right_type: Type::Integer, right_type: Type::Integer,
@ -223,7 +223,7 @@ fn add_float_and_byte() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Byte, right_type: Type::Byte,
@ -240,7 +240,7 @@ fn add_float_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Character, right_type: Type::Character,
@ -257,7 +257,7 @@ fn add_float_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Integer, right_type: Type::Integer,
@ -274,7 +274,7 @@ fn add_float_and_string() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::String, right_type: Type::String,
@ -291,7 +291,7 @@ fn add_integer_and_byte() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Byte, right_type: Type::Byte,
@ -308,7 +308,7 @@ fn add_integer_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Character, right_type: Type::Character,
@ -325,7 +325,7 @@ fn add_integer_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Float, right_type: Type::Float,
@ -342,7 +342,7 @@ fn add_integer_and_string() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::String, right_type: Type::String,
@ -359,7 +359,7 @@ fn add_string_and_byte() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::String, left_type: Type::String,
right_type: Type::Byte, right_type: Type::Byte,
@ -376,7 +376,7 @@ fn add_string_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::String, left_type: Type::String,
right_type: Type::Float, right_type: Type::Float,
@ -393,7 +393,7 @@ fn add_string_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotAddArguments { error: CompileError::CannotAddArguments {
left_type: Type::String, left_type: Type::String,
right_type: Type::Integer, right_type: Type::Integer,

View File

@ -6,7 +6,7 @@ fn divide_boolean_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(0, 4) position: Span(0, 4)
@ -22,7 +22,7 @@ fn divide_boolean_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(4, 8) position: Span(4, 8)
@ -38,7 +38,7 @@ fn divide_character_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(0, 3) position: Span(0, 3)
@ -54,7 +54,7 @@ fn divide_character_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(4, 7) position: Span(4, 7)
@ -70,7 +70,7 @@ fn divide_float_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(6, 9) position: Span(6, 9)
@ -86,7 +86,7 @@ fn divide_float_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideArguments { error: CompileError::CannotDivideArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Integer, right_type: Type::Integer,
@ -103,7 +103,7 @@ fn divide_function_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -123,7 +123,7 @@ fn divide_function_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -143,7 +143,7 @@ fn divide_integer_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideArguments { error: CompileError::CannotDivideArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Float, right_type: Type::Float,
@ -160,7 +160,7 @@ fn divide_list_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(0, 6) position: Span(0, 6)
@ -176,7 +176,7 @@ fn divide_list_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(4, 10) position: Span(4, 10)
@ -202,7 +202,7 @@ fn divide_string_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::String, argument_type: Type::String,
position: Span(0, 7) position: Span(0, 7)
@ -218,7 +218,7 @@ fn divide_string_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotDivideType { error: CompileError::CannotDivideType {
argument_type: Type::String, argument_type: Type::String,
position: Span(4, 11) position: Span(4, 11)

View File

@ -6,7 +6,7 @@ fn modulo_boolean_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(0, 4) position: Span(0, 4)
@ -22,7 +22,7 @@ fn modulo_boolean_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(4, 8) position: Span(4, 8)
@ -38,7 +38,7 @@ fn modulo_character_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(0, 3) position: Span(0, 3)
@ -54,7 +54,7 @@ fn modulo_character_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(4, 7) position: Span(4, 7)
@ -70,7 +70,7 @@ fn modulo_float_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(6, 9) position: Span(6, 9)
@ -86,7 +86,7 @@ fn modulo_float_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloArguments { error: CompileError::CannotModuloArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Integer, right_type: Type::Integer,
@ -103,7 +103,7 @@ fn modulo_function_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -123,7 +123,7 @@ fn modulo_function_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -143,7 +143,7 @@ fn modulo_integer_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloArguments { error: CompileError::CannotModuloArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Float, right_type: Type::Float,
@ -160,7 +160,7 @@ fn modulo_list_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(0, 6) position: Span(0, 6)
@ -176,7 +176,7 @@ fn modulo_list_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(4, 10) position: Span(4, 10)
@ -202,7 +202,7 @@ fn modulo_string_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::String, argument_type: Type::String,
position: Span(0, 7) position: Span(0, 7)
@ -218,7 +218,7 @@ fn modulo_string_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotModuloType { error: CompileError::CannotModuloType {
argument_type: Type::String, argument_type: Type::String,
position: Span(4, 11) position: Span(4, 11)

View File

@ -6,7 +6,7 @@ fn multiply_boolean_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(0, 4) position: Span(0, 4)
@ -22,7 +22,7 @@ fn multiply_boolean_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(4, 8) position: Span(4, 8)
@ -38,7 +38,7 @@ fn multiply_character_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(0, 3) position: Span(0, 3)
@ -54,7 +54,7 @@ fn multiply_character_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(4, 7) position: Span(4, 7)
@ -70,7 +70,7 @@ fn multiply_float_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(6, 9) position: Span(6, 9)
@ -86,7 +86,7 @@ fn multiply_float_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyArguments { error: CompileError::CannotMultiplyArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Integer, right_type: Type::Integer,
@ -103,7 +103,7 @@ fn multiply_function_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -123,7 +123,7 @@ fn multiply_function_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -143,7 +143,7 @@ fn multiply_integer_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyArguments { error: CompileError::CannotMultiplyArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Float, right_type: Type::Float,
@ -160,7 +160,7 @@ fn multiply_list_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(0, 6) position: Span(0, 6)
@ -176,7 +176,7 @@ fn multiply_list_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(4, 10) position: Span(4, 10)
@ -202,7 +202,7 @@ fn multiply_string_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::String, argument_type: Type::String,
position: Span(0, 7) position: Span(0, 7)
@ -218,7 +218,7 @@ fn multiply_string_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotMultiplyType { error: CompileError::CannotMultiplyType {
argument_type: Type::String, argument_type: Type::String,
position: Span(4, 11) position: Span(4, 11)

View File

@ -6,7 +6,7 @@ fn subtract_boolean_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(0, 4) position: Span(0, 4)
@ -22,7 +22,7 @@ fn subtract_boolean_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Boolean, argument_type: Type::Boolean,
position: Span(4, 8) position: Span(4, 8)
@ -38,7 +38,7 @@ fn subtract_character_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(0, 3) position: Span(0, 3)
@ -54,7 +54,7 @@ fn subtract_character_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(4, 7) position: Span(4, 7)
@ -70,7 +70,7 @@ fn subtract_float_and_character() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Character, argument_type: Type::Character,
position: Span(6, 9) position: Span(6, 9)
@ -86,7 +86,7 @@ fn subtract_float_and_integer() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractArguments { error: CompileError::CannotSubtractArguments {
left_type: Type::Float, left_type: Type::Float,
right_type: Type::Integer, right_type: Type::Integer,
@ -103,7 +103,7 @@ fn subtract_function_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -123,7 +123,7 @@ fn subtract_function_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::Function(FunctionType { argument_type: Type::Function(FunctionType {
type_parameters: None, type_parameters: None,
@ -143,7 +143,7 @@ fn subtract_integer_and_float() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractArguments { error: CompileError::CannotSubtractArguments {
left_type: Type::Integer, left_type: Type::Integer,
right_type: Type::Float, right_type: Type::Float,
@ -160,7 +160,7 @@ fn subtract_list_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(0, 6) position: Span(0, 6)
@ -176,7 +176,7 @@ fn subtract_list_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::List(Box::new(Type::Integer)), argument_type: Type::List(Box::new(Type::Integer)),
position: Span(4, 10) position: Span(4, 10)
@ -202,7 +202,7 @@ fn subtract_string_left() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::String, argument_type: Type::String,
position: Span(0, 7) position: Span(0, 7)
@ -218,7 +218,7 @@ fn subtract_string_right() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::CannotSubtractType { error: CompileError::CannotSubtractType {
argument_type: Type::String, argument_type: Type::String,
position: Span(4, 11) position: Span(4, 11)

View File

@ -38,7 +38,7 @@ fn panic() {
assert_eq!( assert_eq!(
run(source), run(source),
Err(DustError::Runtime { Err(CreateReport::Runtime {
error: VmError::NativeFunction(NativeFunctionError::Panic { error: VmError::NativeFunction(NativeFunctionError::Panic {
message: Some("Goodbye world! 42".to_string()), message: Some("Goodbye world! 42".to_string()),
position: Span(0, 27) position: Span(0, 27)

View File

@ -205,7 +205,7 @@ fn disallow_access_to_child_scope() {
assert_eq!( assert_eq!(
run(source), run(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::VariableOutOfScope { error: CompileError::VariableOutOfScope {
identifier: "x".to_string(), identifier: "x".to_string(),
position: Span(52, 53), position: Span(52, 53),
@ -230,7 +230,7 @@ fn disallow_access_to_child_scope_nested() {
assert_eq!( assert_eq!(
run(source), run(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::VariableOutOfScope { error: CompileError::VariableOutOfScope {
identifier: "x".to_string(), identifier: "x".to_string(),
position: Span(78, 79), position: Span(78, 79),
@ -255,7 +255,7 @@ fn disallow_access_to_sibling_scope() {
assert_eq!( assert_eq!(
run(source), run(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::VariableOutOfScope { error: CompileError::VariableOutOfScope {
identifier: "x".to_string(), identifier: "x".to_string(),
variable_scope: Scope::new(1, 1), variable_scope: Scope::new(1, 1),
@ -282,7 +282,7 @@ fn disallow_access_to_sibling_scope_nested() {
assert_eq!( assert_eq!(
run(source), run(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::VariableOutOfScope { error: CompileError::VariableOutOfScope {
identifier: "x".to_string(), identifier: "x".to_string(),
variable_scope: Scope::new(2, 2), variable_scope: Scope::new(2, 2),

View File

@ -35,7 +35,7 @@ fn let_statement_expects_identifier() {
assert_eq!( assert_eq!(
compile(source), compile(source),
Err(DustError::Compile { Err(CreateReport::Compile {
error: CompileError::ExpectedToken { error: CompileError::ExpectedToken {
expected: TokenKind::Identifier, expected: TokenKind::Identifier,
found: Token::Integer("1").to_owned(), found: Token::Integer("1").to_owned(),