Optimize with more SmallVecs
This commit is contained in:
parent
e5742f6294
commit
1c3c30ac21
@ -16,8 +16,8 @@ use log::{Level, LevelFilter};
|
||||
struct Cli {
|
||||
/// Log level, overrides the DUST_LOG environment variable
|
||||
///
|
||||
/// Possible values: trace, debug, info, warn, error
|
||||
#[arg(short, long, global = true, value_name = "LOG_LEVEL")]
|
||||
/// Possible values: trace, debug, info, warn, error, off
|
||||
#[arg(short, long, value_name = "LOG_LEVEL")]
|
||||
log: Option<LevelFilter>,
|
||||
|
||||
#[command(flatten)]
|
||||
@ -28,7 +28,7 @@ struct Cli {
|
||||
}
|
||||
|
||||
#[derive(Args)]
|
||||
#[group(required = true, multiple = false)]
|
||||
#[group(multiple = false)]
|
||||
struct ModeFlags {
|
||||
/// Run the source code (default)
|
||||
#[arg(short, long)]
|
||||
@ -106,24 +106,6 @@ fn main() {
|
||||
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 {
|
||||
let chunk = match compile(&source) {
|
||||
Ok(chunk) => chunk,
|
||||
@ -157,6 +139,20 @@ fn main() {
|
||||
|
||||
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)]
|
||||
|
@ -20,7 +20,8 @@ pub struct Chunk {
|
||||
name: Option<String>,
|
||||
r#type: FunctionType,
|
||||
|
||||
instructions: SmallVec<[(Instruction, Span); 32]>,
|
||||
instructions: SmallVec<[Instruction; 32]>,
|
||||
positions: SmallVec<[Span; 32]>,
|
||||
constants: SmallVec<[ConcreteValue; 16]>,
|
||||
locals: SmallVec<[Local; 8]>,
|
||||
}
|
||||
@ -30,12 +31,13 @@ impl Chunk {
|
||||
Self {
|
||||
name,
|
||||
instructions: SmallVec::new(),
|
||||
positions: SmallVec::new(),
|
||||
constants: SmallVec::new(),
|
||||
locals: SmallVec::new(),
|
||||
r#type: FunctionType {
|
||||
type_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(
|
||||
name: Option<String>,
|
||||
r#type: FunctionType,
|
||||
instructions: Vec<(Instruction, Span)>,
|
||||
constants: Vec<ConcreteValue>,
|
||||
locals: Vec<Local>,
|
||||
instructions: SmallVec<[Instruction; 32]>,
|
||||
positions: SmallVec<[Span; 32]>,
|
||||
constants: SmallVec<[ConcreteValue; 16]>,
|
||||
locals: SmallVec<[Local; 8]>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
r#type,
|
||||
instructions: instructions.into(),
|
||||
constants: constants.into(),
|
||||
locals: locals.into(),
|
||||
instructions,
|
||||
positions,
|
||||
constants,
|
||||
locals,
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,10 +80,14 @@ impl Chunk {
|
||||
&self.constants
|
||||
}
|
||||
|
||||
pub fn instructions(&self) -> &SmallVec<[(Instruction, Span); 32]> {
|
||||
pub fn instructions(&self) -> &SmallVec<[Instruction; 32]> {
|
||||
&self.instructions
|
||||
}
|
||||
|
||||
pub fn positions(&self) -> &SmallVec<[Span; 32]> {
|
||||
&self.positions
|
||||
}
|
||||
|
||||
pub fn locals(&self) -> &SmallVec<[Local; 8]> {
|
||||
&self.locals
|
||||
}
|
||||
@ -88,7 +96,7 @@ impl Chunk {
|
||||
self.instructions()
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, _)| {
|
||||
.find_map(|instruction| {
|
||||
if instruction.yields_value() {
|
||||
Some(instruction.a() as usize + 1)
|
||||
} else {
|
||||
|
@ -8,10 +8,10 @@ use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem::replace,
|
||||
num::{ParseFloatError, ParseIntError},
|
||||
vec,
|
||||
};
|
||||
|
||||
use colored::Colorize;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::{
|
||||
instruction::{
|
||||
@ -36,12 +36,11 @@ use crate::{
|
||||
/// ```
|
||||
pub fn compile(source: &str) -> Result<Chunk, DustError> {
|
||||
let lexer = Lexer::new(source);
|
||||
let mut compiler =
|
||||
Compiler::new(lexer).map_err(|error| DustError::Compile { error, source })?;
|
||||
let mut compiler = Compiler::new(lexer).map_err(|error| DustError::compile(error, source))?;
|
||||
|
||||
compiler
|
||||
.compile()
|
||||
.map_err(|error| DustError::Compile { error, source })?;
|
||||
.map_err(|error| DustError::compile(error, source))?;
|
||||
|
||||
let chunk = compiler.finish(None, None);
|
||||
|
||||
@ -54,9 +53,9 @@ pub fn compile(source: &str) -> Result<Chunk, DustError> {
|
||||
#[derive(Debug)]
|
||||
pub struct Compiler<'src> {
|
||||
self_name: Option<DustString>,
|
||||
instructions: Vec<(Instruction, Type, Span)>,
|
||||
constants: Vec<ConcreteValue>,
|
||||
locals: Vec<Local>,
|
||||
instructions: SmallVec<[(Instruction, Type, Span); 32]>,
|
||||
constants: SmallVec<[ConcreteValue; 16]>,
|
||||
locals: SmallVec<[Local; 8]>,
|
||||
|
||||
lexer: Lexer<'src>,
|
||||
|
||||
@ -83,9 +82,9 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
Ok(Compiler {
|
||||
self_name: None,
|
||||
instructions: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
locals: Vec::new(),
|
||||
instructions: SmallVec::new(),
|
||||
constants: SmallVec::new(),
|
||||
locals: SmallVec::new(),
|
||||
lexer,
|
||||
current_token,
|
||||
current_position,
|
||||
@ -100,26 +99,27 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
pub fn finish(
|
||||
self,
|
||||
type_parameters: Option<Vec<u16>>,
|
||||
value_parameters: Option<Vec<(u16, Type)>>,
|
||||
type_parameters: Option<SmallVec<[u16; 4]>>,
|
||||
value_parameters: Option<SmallVec<[(u16, Type); 4]>>,
|
||||
) -> Chunk {
|
||||
log::info!("End chunk");
|
||||
|
||||
let r#type = FunctionType {
|
||||
type_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
|
||||
.into_iter()
|
||||
.map(|(i, _, s)| (i, s))
|
||||
.collect();
|
||||
.map(|(instruction, _, position)| (instruction, position))
|
||||
.unzip();
|
||||
|
||||
Chunk::with_data(
|
||||
self.self_name,
|
||||
r#type,
|
||||
instructions,
|
||||
positions,
|
||||
self.constants,
|
||||
self.locals,
|
||||
)
|
||||
@ -1301,7 +1301,7 @@ impl<'src> Compiler<'src> {
|
||||
let end = self.previous_position.1;
|
||||
let destination = self.next_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 {
|
||||
destination: Destination::Register(destination),
|
||||
function,
|
||||
@ -1453,7 +1453,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
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)? {
|
||||
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() {
|
||||
value_parameters.push((identifier_index, r#type));
|
||||
} else {
|
||||
value_parameters = Some(vec![(identifier_index, r#type)]);
|
||||
value_parameters = Some(smallvec![(identifier_index, r#type)]);
|
||||
};
|
||||
|
||||
function_compiler.minimum_register += 1;
|
||||
@ -1504,12 +1504,12 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
function_compiler.advance()?;
|
||||
|
||||
Box::new(r#type)
|
||||
r#type
|
||||
} 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.compile()?;
|
||||
@ -1536,7 +1536,7 @@ impl<'src> Compiler<'src> {
|
||||
if let Some((identifier, position)) = identifier_info {
|
||||
let (local_index, _) = self.declare_local(
|
||||
identifier,
|
||||
Type::Function(function_type.clone()),
|
||||
Type::function(function_type.clone()),
|
||||
false,
|
||||
self.current_scope,
|
||||
);
|
||||
@ -1553,7 +1553,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
self.emit_instruction(
|
||||
load_constant,
|
||||
Type::Function(function_type),
|
||||
Type::function(function_type),
|
||||
Span(function_start, function_end),
|
||||
);
|
||||
self.emit_instruction(define_local, Type::None, position);
|
||||
@ -1566,7 +1566,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
self.emit_instruction(
|
||||
load_constant,
|
||||
Type::Function(function_type),
|
||||
Type::function(function_type),
|
||||
Span(function_start, function_end),
|
||||
);
|
||||
}
|
||||
@ -1598,7 +1598,7 @@ impl<'src> Compiler<'src> {
|
||||
})?;
|
||||
let register_type = self.get_register_type(function.index())?;
|
||||
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),
|
||||
_ => {
|
||||
return Err(CompileError::ExpectedFunction {
|
||||
@ -1610,12 +1610,8 @@ impl<'src> Compiler<'src> {
|
||||
};
|
||||
let start = self.current_position.0;
|
||||
|
||||
println!("{} {}", self.previous_token, self.current_token);
|
||||
|
||||
self.advance()?;
|
||||
|
||||
println!("{} {}", self.previous_token, self.current_token);
|
||||
|
||||
let mut argument_count = 0;
|
||||
|
||||
while !self.allow(Token::RightParenthesis)? {
|
||||
|
@ -209,7 +209,13 @@ impl<'a> Disassembler<'a> {
|
||||
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 operation = instruction.operation().to_string();
|
||||
let info = instruction.disassembly_info();
|
||||
|
@ -1,7 +1,10 @@
|
||||
//! Top-level Dust errors with source code annotations.
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
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.
|
||||
///
|
||||
@ -19,43 +22,60 @@ pub enum 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 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());
|
||||
}
|
||||
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.push_str(&renderer.render(message).to_string());
|
||||
|
||||
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 {
|
||||
|
@ -35,10 +35,9 @@ pub fn lex(source: &str) -> Result<Vec<(Token, Span)>, DustError> {
|
||||
let mut tokens = Vec::new();
|
||||
|
||||
loop {
|
||||
let (token, span) = lexer.next_token().map_err(|error| DustError::Compile {
|
||||
error: CompileError::Lex(error),
|
||||
source,
|
||||
})?;
|
||||
let (token, span) = lexer
|
||||
.next_token()
|
||||
.map_err(|error| DustError::compile(CompileError::Lex(error), source))?;
|
||||
|
||||
tokens.push((token, span));
|
||||
|
||||
|
@ -11,6 +11,7 @@ use std::{
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::smallvec;
|
||||
|
||||
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 {
|
||||
match self {
|
||||
$(
|
||||
NativeFunction::$name => *$type.return_type != Type::None,
|
||||
NativeFunction::$name => $type.return_type != Type::None,
|
||||
)*
|
||||
}
|
||||
}
|
||||
@ -131,7 +132,7 @@ define_native_function! {
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Box::new(Type::None)
|
||||
return_type: Type::None
|
||||
},
|
||||
logic::panic
|
||||
),
|
||||
@ -147,8 +148,8 @@ define_native_function! {
|
||||
"to_string",
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(vec![(0, Type::Any)]),
|
||||
return_type: Box::new(Type::String)
|
||||
value_parameters: Some(smallvec![(0, Type::Any)]),
|
||||
return_type: Type::String
|
||||
},
|
||||
logic::to_string
|
||||
),
|
||||
@ -209,7 +210,7 @@ define_native_function! {
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: None,
|
||||
return_type: Box::new(Type::String)
|
||||
return_type: Type::String
|
||||
},
|
||||
logic::read_line
|
||||
),
|
||||
@ -224,8 +225,8 @@ define_native_function! {
|
||||
"write",
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(vec![(0, Type::String)]),
|
||||
return_type: Box::new(Type::None)
|
||||
value_parameters: Some(smallvec![(0, Type::String)]),
|
||||
return_type: Type::None
|
||||
},
|
||||
logic::write
|
||||
),
|
||||
@ -236,8 +237,8 @@ define_native_function! {
|
||||
"write_line",
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(vec![(0, Type::String)]),
|
||||
return_type: Box::new(Type::None)
|
||||
value_parameters: Some(smallvec![(0, Type::String)]),
|
||||
return_type: Type::None
|
||||
},
|
||||
logic::write_line
|
||||
)
|
||||
|
@ -1,5 +1,7 @@
|
||||
//! Tools used by the compiler to optimize a chunk's bytecode.
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{instruction::SetLocal, Instruction, Operation, Span, Type};
|
||||
|
||||
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:
|
||||
/// - `Add`, `Subtract`, `Multiply`, `Divide` or `Modulo`
|
||||
/// - `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!(
|
||||
get_last_operations(instructions),
|
||||
Some([
|
||||
|
@ -6,6 +6,7 @@ use std::{
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// Description of a kind of value.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
@ -16,7 +17,7 @@ pub enum Type {
|
||||
Character,
|
||||
Enum(EnumType),
|
||||
Float,
|
||||
Function(FunctionType),
|
||||
Function(Box<FunctionType>),
|
||||
Generic {
|
||||
identifier_index: u8,
|
||||
concrete_type: Option<Box<Type>>,
|
||||
@ -24,7 +25,7 @@ pub enum Type {
|
||||
Integer,
|
||||
List(Box<Type>),
|
||||
Map {
|
||||
pairs: HashMap<u8, Type>,
|
||||
pairs: Box<SmallVec<[(u8, Type); 8]>>,
|
||||
},
|
||||
None,
|
||||
Range {
|
||||
@ -34,11 +35,19 @@ pub enum Type {
|
||||
String,
|
||||
Struct(StructType),
|
||||
Tuple {
|
||||
fields: Option<Vec<Type>>,
|
||||
fields: Option<Box<SmallVec<[Type; 4]>>>,
|
||||
},
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn concrete_type(&self) -> &Type {
|
||||
if let Type::Generic {
|
||||
@ -107,18 +116,18 @@ impl Type {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(
|
||||
Type::Function(FunctionType {
|
||||
(Type::Function(left_function_type), Type::Function(right_function_type)) => {
|
||||
let FunctionType {
|
||||
type_parameters: left_type_parameters,
|
||||
value_parameters: left_value_parameters,
|
||||
return_type: left_return,
|
||||
}),
|
||||
Type::Function(FunctionType {
|
||||
} = left_function_type.as_ref();
|
||||
let FunctionType {
|
||||
type_parameters: right_type_parameters,
|
||||
value_parameters: right_value_parameters,
|
||||
return_type: right_return,
|
||||
}),
|
||||
) => {
|
||||
} = right_function_type.as_ref();
|
||||
|
||||
if left_return != right_return
|
||||
|| left_type_parameters != right_type_parameters
|
||||
|| left_value_parameters != right_value_parameters
|
||||
@ -269,9 +278,23 @@ impl Ord for Type {
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionType {
|
||||
pub type_parameters: Option<Vec<u16>>,
|
||||
pub value_parameters: Option<Vec<(u16, Type)>>,
|
||||
pub return_type: Box<Type>,
|
||||
pub type_parameters: Option<SmallVec<[u16; 4]>>,
|
||||
pub value_parameters: Option<SmallVec<[(u16, Type); 4]>>,
|
||||
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 {
|
||||
@ -306,7 +329,7 @@ impl Display for FunctionType {
|
||||
|
||||
write!(f, ")")?;
|
||||
|
||||
if *self.return_type != Type::None {
|
||||
if self.return_type != Type::None {
|
||||
write!(f, " -> {}", self.return_type)?;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ impl ConcreteValue {
|
||||
ConcreteValue::Byte(_) => Type::Byte,
|
||||
ConcreteValue::Character(_) => Type::Character,
|
||||
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::List(list) => {
|
||||
let item_type = list.first().map_or(Type::Any, |item| item.r#type());
|
||||
|
@ -14,10 +14,9 @@ use crate::{
|
||||
|
||||
pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
|
||||
let chunk = compile(source)?;
|
||||
let mut vm = Vm::new(&chunk, None);
|
||||
let mut vm = Vm::new(source, &chunk, None);
|
||||
|
||||
vm.run()
|
||||
.map_err(|error| DustError::Runtime { error, source })
|
||||
vm.run().map_err(|error| DustError::runtime(error, source))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[derive(Debug)]
|
||||
pub struct Vm<'a> {
|
||||
chunk: &'a Chunk,
|
||||
stack: SmallVec<[Register; 64]>,
|
||||
|
||||
chunk: &'a Chunk,
|
||||
parent: Option<&'a Vm<'a>>,
|
||||
local_definitions: SmallVec<[Option<u16>; 16]>,
|
||||
|
||||
ip: usize,
|
||||
last_assigned_register: Option<u16>,
|
||||
current_position: Span,
|
||||
source: &'a str,
|
||||
}
|
||||
|
||||
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 {
|
||||
chunk,
|
||||
stack: smallvec![Register::Empty; chunk.stack_size()],
|
||||
@ -44,7 +44,7 @@ impl<'a> Vm<'a> {
|
||||
local_definitions: smallvec![None; chunk.locals().len()],
|
||||
ip: 0,
|
||||
last_assigned_register: None,
|
||||
current_position: Span(0, 0),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ impl<'a> Vm<'a> {
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -63,7 +63,7 @@ impl<'a> Vm<'a> {
|
||||
log::info!(
|
||||
"{} | {} | {} | {}",
|
||||
self.ip - 1,
|
||||
self.current_position,
|
||||
self.current_position(),
|
||||
instruction.operation(),
|
||||
instruction.disassembly_info()
|
||||
);
|
||||
@ -86,7 +86,7 @@ impl<'a> Vm<'a> {
|
||||
|
||||
if self.stack.len() < to as usize {
|
||||
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(
|
||||
VmError::UndefinedLocal {
|
||||
local_index,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
},
|
||||
)?;
|
||||
let register = Register::Pointer(Pointer::Stack(local_register));
|
||||
@ -199,7 +199,17 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(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();
|
||||
|
||||
@ -216,7 +226,7 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(right)?;
|
||||
let difference = left.subtract(right).map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
self.set_register(register_index, Register::Value(difference))?;
|
||||
@ -232,7 +242,7 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(right)?;
|
||||
let product = left.multiply(right).map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
self.set_register(register_index, Register::Value(product))?;
|
||||
@ -248,7 +258,7 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(right)?;
|
||||
let quotient = left.divide(right).map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
self.set_register(register_index, Register::Value(quotient))?;
|
||||
@ -264,7 +274,7 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(right)?;
|
||||
let remainder = left.modulo(right).map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
self.set_register(register_index, Register::Value(remainder))?;
|
||||
@ -281,7 +291,7 @@ impl<'a> Vm<'a> {
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: value.to_owned(),
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
});
|
||||
};
|
||||
|
||||
@ -303,7 +313,7 @@ impl<'a> Vm<'a> {
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
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]
|
||||
.ok_or(VmError::UndefinedLocal {
|
||||
local_index,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
Pointer::Stack(register_index)
|
||||
@ -334,7 +344,7 @@ impl<'a> Vm<'a> {
|
||||
let right = self.get_argument(right)?;
|
||||
let equal_result = left.equal(right).map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
let is_equal =
|
||||
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = equal_result {
|
||||
@ -342,7 +352,7 @@ impl<'a> Vm<'a> {
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: equal_result,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
});
|
||||
};
|
||||
|
||||
@ -360,7 +370,7 @@ impl<'a> Vm<'a> {
|
||||
less_result.is_ok(),
|
||||
"VM Error: {}\nPosition: {}",
|
||||
less_result.unwrap_err(),
|
||||
self.current_position
|
||||
self.current_position()
|
||||
);
|
||||
|
||||
let less_than_value = less_result.unwrap();
|
||||
@ -369,7 +379,7 @@ impl<'a> Vm<'a> {
|
||||
assert!(
|
||||
less_than_boolean.is_some(),
|
||||
"VM Error: Expected a boolean\nPosition: {}",
|
||||
self.current_position
|
||||
self.current_position()
|
||||
);
|
||||
|
||||
let is_less_than = less_than_boolean.unwrap();
|
||||
@ -386,7 +396,7 @@ impl<'a> Vm<'a> {
|
||||
left.less_than_or_equal(right)
|
||||
.map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
let is_less_than_or_equal =
|
||||
if let Value::Concrete(ConcreteValue::Boolean(boolean)) =
|
||||
@ -396,7 +406,7 @@ impl<'a> Vm<'a> {
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
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 negated = value.negate().map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
let register_index = self.get_destination(destination)?;
|
||||
let register = Register::Value(negated);
|
||||
@ -427,7 +437,7 @@ impl<'a> Vm<'a> {
|
||||
let value = self.get_argument(argument)?;
|
||||
let not = value.not().map_err(|error| VmError::Value {
|
||||
error,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
let register_index = self.get_destination(destination)?;
|
||||
let register = Register::Value(not);
|
||||
@ -458,10 +468,10 @@ impl<'a> Vm<'a> {
|
||||
} else {
|
||||
return Err(VmError::ExpectedFunction {
|
||||
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;
|
||||
|
||||
for (argument_index, argument_register_index) in
|
||||
@ -515,7 +525,7 @@ impl<'a> Vm<'a> {
|
||||
Ok(Some(return_value))
|
||||
} else {
|
||||
Err(VmError::StackUnderflow {
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})
|
||||
};
|
||||
}
|
||||
@ -536,7 +546,7 @@ impl<'a> Vm<'a> {
|
||||
.parent
|
||||
.as_ref()
|
||||
.ok_or_else(|| VmError::ExpectedParent {
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
parent.open_register(register_index)
|
||||
@ -546,7 +556,7 @@ impl<'a> Vm<'a> {
|
||||
.parent
|
||||
.as_ref()
|
||||
.ok_or_else(|| VmError::ExpectedParent {
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
let constant = parent.get_constant(constant_index);
|
||||
|
||||
@ -572,7 +582,7 @@ impl<'a> Vm<'a> {
|
||||
Register::Pointer(pointer) => self.follow_pointer(*pointer),
|
||||
Register::Empty => Err(VmError::EmptyRegister {
|
||||
index: register_index,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@ -587,7 +597,7 @@ impl<'a> Vm<'a> {
|
||||
.get(register_index)
|
||||
.ok_or_else(|| VmError::RegisterIndexOutOfBounds {
|
||||
index: register_index,
|
||||
position: self.current_position,
|
||||
position: self.current_position(),
|
||||
})?;
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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.current_position = position;
|
||||
|
||||
instruction
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ fn add_assign_expects_mutable_variable() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
@ -22,7 +22,7 @@ fn divide_assign_expects_mutable_variable() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
@ -38,7 +38,7 @@ fn multiply_assign_expects_mutable_variable() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
@ -54,7 +54,7 @@ fn subtract_assign_expects_mutable_variable() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
@ -70,7 +70,7 @@ fn modulo_assign_expects_mutable_variable() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
|
@ -6,7 +6,7 @@ fn add_boolean_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
@ -22,7 +22,7 @@ fn add_boolean_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
@ -38,7 +38,7 @@ fn add_function_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -58,7 +58,7 @@ fn add_function_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -78,7 +78,7 @@ fn add_list_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
@ -94,7 +94,7 @@ fn add_list_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(4, 10)
|
||||
@ -121,7 +121,7 @@ fn add_byte_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::Character,
|
||||
@ -138,7 +138,7 @@ fn add_byte_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::Integer,
|
||||
@ -155,7 +155,7 @@ fn add_byte_and_string() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Byte,
|
||||
right_type: Type::String,
|
||||
@ -172,7 +172,7 @@ fn add_character_and_byte() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Character,
|
||||
right_type: Type::Byte,
|
||||
@ -189,7 +189,7 @@ fn add_character_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Character,
|
||||
right_type: Type::Float,
|
||||
@ -206,7 +206,7 @@ fn add_character_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Character,
|
||||
right_type: Type::Integer,
|
||||
@ -223,7 +223,7 @@ fn add_float_and_byte() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Byte,
|
||||
@ -240,7 +240,7 @@ fn add_float_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Character,
|
||||
@ -257,7 +257,7 @@ fn add_float_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
@ -274,7 +274,7 @@ fn add_float_and_string() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::String,
|
||||
@ -291,7 +291,7 @@ fn add_integer_and_byte() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Byte,
|
||||
@ -308,7 +308,7 @@ fn add_integer_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Character,
|
||||
@ -325,7 +325,7 @@ fn add_integer_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
@ -342,7 +342,7 @@ fn add_integer_and_string() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::String,
|
||||
@ -359,7 +359,7 @@ fn add_string_and_byte() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::String,
|
||||
right_type: Type::Byte,
|
||||
@ -376,7 +376,7 @@ fn add_string_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::String,
|
||||
right_type: Type::Float,
|
||||
@ -393,7 +393,7 @@ fn add_string_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotAddArguments {
|
||||
left_type: Type::String,
|
||||
right_type: Type::Integer,
|
||||
|
@ -6,7 +6,7 @@ fn divide_boolean_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
@ -22,7 +22,7 @@ fn divide_boolean_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
@ -38,7 +38,7 @@ fn divide_character_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
@ -54,7 +54,7 @@ fn divide_character_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
@ -70,7 +70,7 @@ fn divide_float_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
@ -86,7 +86,7 @@ fn divide_float_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
@ -103,7 +103,7 @@ fn divide_function_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -123,7 +123,7 @@ fn divide_function_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -143,7 +143,7 @@ fn divide_integer_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
@ -160,7 +160,7 @@ fn divide_list_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
@ -176,7 +176,7 @@ fn divide_list_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(4, 10)
|
||||
@ -202,7 +202,7 @@ fn divide_string_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
@ -218,7 +218,7 @@ fn divide_string_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotDivideType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
|
@ -6,7 +6,7 @@ fn modulo_boolean_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
@ -22,7 +22,7 @@ fn modulo_boolean_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
@ -38,7 +38,7 @@ fn modulo_character_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
@ -54,7 +54,7 @@ fn modulo_character_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
@ -70,7 +70,7 @@ fn modulo_float_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
@ -86,7 +86,7 @@ fn modulo_float_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
@ -103,7 +103,7 @@ fn modulo_function_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -123,7 +123,7 @@ fn modulo_function_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -143,7 +143,7 @@ fn modulo_integer_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
@ -160,7 +160,7 @@ fn modulo_list_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
@ -176,7 +176,7 @@ fn modulo_list_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(4, 10)
|
||||
@ -202,7 +202,7 @@ fn modulo_string_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
@ -218,7 +218,7 @@ fn modulo_string_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotModuloType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
|
@ -6,7 +6,7 @@ fn multiply_boolean_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
@ -22,7 +22,7 @@ fn multiply_boolean_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
@ -38,7 +38,7 @@ fn multiply_character_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
@ -54,7 +54,7 @@ fn multiply_character_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
@ -70,7 +70,7 @@ fn multiply_float_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
@ -86,7 +86,7 @@ fn multiply_float_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
@ -103,7 +103,7 @@ fn multiply_function_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -123,7 +123,7 @@ fn multiply_function_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -143,7 +143,7 @@ fn multiply_integer_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
@ -160,7 +160,7 @@ fn multiply_list_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
@ -176,7 +176,7 @@ fn multiply_list_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(4, 10)
|
||||
@ -202,7 +202,7 @@ fn multiply_string_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
@ -218,7 +218,7 @@ fn multiply_string_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotMultiplyType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
|
@ -6,7 +6,7 @@ fn subtract_boolean_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(0, 4)
|
||||
@ -22,7 +22,7 @@ fn subtract_boolean_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Boolean,
|
||||
position: Span(4, 8)
|
||||
@ -38,7 +38,7 @@ fn subtract_character_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(0, 3)
|
||||
@ -54,7 +54,7 @@ fn subtract_character_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(4, 7)
|
||||
@ -70,7 +70,7 @@ fn subtract_float_and_character() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Character,
|
||||
position: Span(6, 9)
|
||||
@ -86,7 +86,7 @@ fn subtract_float_and_integer() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractArguments {
|
||||
left_type: Type::Float,
|
||||
right_type: Type::Integer,
|
||||
@ -103,7 +103,7 @@ fn subtract_function_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -123,7 +123,7 @@ fn subtract_function_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::Function(FunctionType {
|
||||
type_parameters: None,
|
||||
@ -143,7 +143,7 @@ fn subtract_integer_and_float() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractArguments {
|
||||
left_type: Type::Integer,
|
||||
right_type: Type::Float,
|
||||
@ -160,7 +160,7 @@ fn subtract_list_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(0, 6)
|
||||
@ -176,7 +176,7 @@ fn subtract_list_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::List(Box::new(Type::Integer)),
|
||||
position: Span(4, 10)
|
||||
@ -202,7 +202,7 @@ fn subtract_string_left() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::String,
|
||||
position: Span(0, 7)
|
||||
@ -218,7 +218,7 @@ fn subtract_string_right() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::CannotSubtractType {
|
||||
argument_type: Type::String,
|
||||
position: Span(4, 11)
|
||||
|
@ -38,7 +38,7 @@ fn panic() {
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Runtime {
|
||||
Err(CreateReport::Runtime {
|
||||
error: VmError::NativeFunction(NativeFunctionError::Panic {
|
||||
message: Some("Goodbye world! 42".to_string()),
|
||||
position: Span(0, 27)
|
||||
|
@ -205,7 +205,7 @@ fn disallow_access_to_child_scope() {
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
position: Span(52, 53),
|
||||
@ -230,7 +230,7 @@ fn disallow_access_to_child_scope_nested() {
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
position: Span(78, 79),
|
||||
@ -255,7 +255,7 @@ fn disallow_access_to_sibling_scope() {
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
variable_scope: Scope::new(1, 1),
|
||||
@ -282,7 +282,7 @@ fn disallow_access_to_sibling_scope_nested() {
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::VariableOutOfScope {
|
||||
identifier: "x".to_string(),
|
||||
variable_scope: Scope::new(2, 2),
|
||||
|
@ -35,7 +35,7 @@ fn let_statement_expects_identifier() {
|
||||
|
||||
assert_eq!(
|
||||
compile(source),
|
||||
Err(DustError::Compile {
|
||||
Err(CreateReport::Compile {
|
||||
error: CompileError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
found: Token::Integer("1").to_owned(),
|
||||
|
Loading…
Reference in New Issue
Block a user