Fix tests; Rename point to move; Implement lists in the VM
This commit is contained in:
parent
5de44b58ee
commit
4a169bc515
@ -30,7 +30,7 @@ use type_checks::{check_math_type, check_math_types};
|
||||
use std::{mem::replace, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
instruction::{Jump, Point, Return, TypeCode},
|
||||
instruction::{Jump, Move, Return, TypeCode},
|
||||
Chunk, DustError, DustString, FunctionType, Instruction, Lexer, Local, NativeFunction, Operand,
|
||||
Operation, Scope, Span, Token, TokenKind, Type,
|
||||
};
|
||||
@ -876,8 +876,8 @@ impl<'src> Compiler<'src> {
|
||||
position: self.previous_position,
|
||||
})?;
|
||||
let (left, push_back_left) = self.handle_binary_argument(&left_instruction);
|
||||
let left_is_mutable_local = if left_instruction.operation() == Operation::POINT {
|
||||
let Point { to, .. } = Point::from(left_instruction);
|
||||
let left_is_mutable_local = if left_instruction.operation() == Operation::MOVE {
|
||||
let Move { operand: to, .. } = Move::from(&left_instruction);
|
||||
|
||||
self.locals
|
||||
.get(to.index() as usize)
|
||||
@ -1084,8 +1084,8 @@ impl<'src> Compiler<'src> {
|
||||
found: self.previous_token.to_owned(),
|
||||
position: self.previous_position,
|
||||
})?;
|
||||
let operand_register = if left_instruction.operation() == Operation::POINT {
|
||||
let Point { to, .. } = Point::from(left_instruction);
|
||||
let operand_register = if left_instruction.operation() == Operation::MOVE {
|
||||
let Move { operand: to, .. } = Move::from(&left_instruction);
|
||||
let local = self.get_local(to.index())?;
|
||||
|
||||
local.register_index
|
||||
@ -1239,7 +1239,7 @@ impl<'src> Compiler<'src> {
|
||||
Type::String => self.next_string_register(),
|
||||
_ => todo!(),
|
||||
};
|
||||
let point = Instruction::point(
|
||||
let point = Instruction::r#move(
|
||||
destination,
|
||||
Operand::Register(local_register_index, local_type.type_code()),
|
||||
);
|
||||
@ -1756,20 +1756,21 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
|
||||
fn parse_implicit_return(&mut self) -> Result<(), CompileError> {
|
||||
if matches!(self.get_last_operation(), Some(Operation::POINT)) {
|
||||
let Point { to, .. } = Point::from(self.instructions.last().unwrap().0);
|
||||
if matches!(self.get_last_operation(), Some(Operation::MOVE)) {
|
||||
let last_instruction = self.instructions.last().unwrap().0;
|
||||
let Move { operand, .. } = Move::from(&last_instruction);
|
||||
|
||||
let (point, r#type, position) = self.instructions.pop().unwrap();
|
||||
let (r#move, r#type, position) = self.instructions.pop().unwrap();
|
||||
let (should_return, target_register) = if r#type == Type::None {
|
||||
(false, 0)
|
||||
} else {
|
||||
(true, to.index())
|
||||
(true, operand.index())
|
||||
};
|
||||
let r#return =
|
||||
Instruction::r#return(should_return, target_register, r#type.type_code());
|
||||
|
||||
if !should_return {
|
||||
self.instructions.push((point, r#type.clone(), position));
|
||||
self.instructions.push((r#move, r#type.clone(), position));
|
||||
}
|
||||
|
||||
self.emit_instruction(r#return, r#type, self.current_position);
|
||||
|
@ -10,8 +10,8 @@ pub struct Close {
|
||||
pub r#type: TypeCode,
|
||||
}
|
||||
|
||||
impl From<Instruction> for Close {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
impl From<&Instruction> for Close {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
Close {
|
||||
from: instruction.b_field(),
|
||||
to: instruction.c_field(),
|
||||
|
@ -93,11 +93,11 @@ mod load_function;
|
||||
mod load_list;
|
||||
mod load_self;
|
||||
mod modulo;
|
||||
mod r#move;
|
||||
mod multiply;
|
||||
mod negate;
|
||||
mod not;
|
||||
mod operation;
|
||||
mod point;
|
||||
mod r#return;
|
||||
mod subtract;
|
||||
mod test;
|
||||
@ -123,7 +123,7 @@ pub use multiply::Multiply;
|
||||
pub use negate::Negate;
|
||||
pub use not::Not;
|
||||
pub use operation::Operation;
|
||||
pub use point::Point;
|
||||
pub use r#move::Move;
|
||||
pub use r#return::Return;
|
||||
pub use subtract::Subtract;
|
||||
pub use test::Test;
|
||||
@ -183,7 +183,7 @@ impl From<&Instruction> for InstructionFields {
|
||||
impl Default for InstructionFields {
|
||||
fn default() -> Self {
|
||||
InstructionFields {
|
||||
operation: Operation::POINT,
|
||||
operation: Operation::MOVE,
|
||||
a_field: 0,
|
||||
b_field: 0,
|
||||
c_field: 0,
|
||||
@ -277,8 +277,8 @@ impl Instruction {
|
||||
|
||||
pub fn as_operand(&self) -> Operand {
|
||||
match self.operation() {
|
||||
Operation::POINT => {
|
||||
let Point { to, .. } = Point::from(*self);
|
||||
Operation::MOVE => {
|
||||
let Move { operand: to, .. } = Move::from(self);
|
||||
|
||||
Operand::Register(to.index(), to.as_type())
|
||||
}
|
||||
@ -370,8 +370,11 @@ impl Instruction {
|
||||
Instruction(Operation::NO_OP.0 as u64)
|
||||
}
|
||||
|
||||
pub fn point(destination: u16, to: Operand) -> Instruction {
|
||||
Instruction::from(Point { destination, to })
|
||||
pub fn r#move(destination: u16, to: Operand) -> Instruction {
|
||||
Instruction::from(Move {
|
||||
destination,
|
||||
operand: to,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn close(from: u16, to: u16, r#type: TypeCode) -> Instruction {
|
||||
@ -605,7 +608,7 @@ impl Instruction {
|
||||
|
||||
pub fn yields_value(&self) -> bool {
|
||||
match self.operation() {
|
||||
Operation::POINT
|
||||
Operation::MOVE
|
||||
| Operation::LOAD_ENCODED
|
||||
| Operation::LOAD_CONSTANT
|
||||
| Operation::LOAD_FUNCTION
|
||||
@ -640,8 +643,8 @@ impl Instruction {
|
||||
let operation = self.operation();
|
||||
|
||||
match operation {
|
||||
Operation::POINT => Point::from(*self).to_string(),
|
||||
Operation::CLOSE => Close::from(*self).to_string(),
|
||||
Operation::MOVE => Move::from(self).to_string(),
|
||||
Operation::CLOSE => Close::from(self).to_string(),
|
||||
Operation::LOAD_ENCODED => LoadEncoded::from(*self).to_string(),
|
||||
Operation::LOAD_CONSTANT => LoadConstant::from(*self).to_string(),
|
||||
Operation::LOAD_FUNCTION => LoadFunction::from(*self).to_string(),
|
||||
|
@ -4,26 +4,26 @@ use crate::{Instruction, Operation};
|
||||
|
||||
use super::{InstructionFields, Operand, TypeCode};
|
||||
|
||||
pub struct Point {
|
||||
pub struct Move {
|
||||
pub destination: u16,
|
||||
pub to: Operand,
|
||||
pub operand: Operand,
|
||||
}
|
||||
|
||||
impl From<Instruction> for Point {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
Point {
|
||||
impl From<&Instruction> for Move {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
Move {
|
||||
destination: instruction.a_field(),
|
||||
to: instruction.b_as_operand(),
|
||||
operand: instruction.b_as_operand(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Point> for Instruction {
|
||||
fn from(r#move: Point) -> Self {
|
||||
let operation = Operation::POINT;
|
||||
impl From<Move> for Instruction {
|
||||
fn from(r#move: Move) -> Self {
|
||||
let operation = Operation::MOVE;
|
||||
let a_field = r#move.destination;
|
||||
let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag();
|
||||
let b_type = r#move.to.as_type();
|
||||
let (b_field, b_is_constant) = r#move.operand.as_index_and_constant_flag();
|
||||
let b_type = r#move.operand.as_type();
|
||||
|
||||
InstructionFields {
|
||||
operation,
|
||||
@ -37,9 +37,12 @@ impl From<Point> for Instruction {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Point {
|
||||
impl Display for Move {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let Point { destination, to } = self;
|
||||
let Move {
|
||||
destination,
|
||||
operand: to,
|
||||
} = self;
|
||||
|
||||
match to.as_type() {
|
||||
TypeCode::BOOLEAN => write!(f, "R_BOOL_{destination} -> {to}"),
|
||||
@ -50,7 +53,7 @@ impl Display for Point {
|
||||
TypeCode::STRING => write!(f, "R_STR_{destination} -> {to}"),
|
||||
unsupported => write!(
|
||||
f,
|
||||
"Unsupported type code: {unsupported} for Point instruction"
|
||||
"Unsupported type code: {unsupported} for MOVE instruction"
|
||||
),
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ impl Operation {
|
||||
pub const NO_OP: Operation = Operation(0);
|
||||
|
||||
// Stack manipulation
|
||||
pub const POINT: Operation = Operation(1);
|
||||
pub const MOVE: Operation = Operation(1);
|
||||
pub const CLOSE: Operation = Operation(2);
|
||||
|
||||
// Loaders
|
||||
@ -55,7 +55,7 @@ impl Operation {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match *self {
|
||||
Self::NO_OP => "NO_OP",
|
||||
Self::POINT => "POINT",
|
||||
Self::MOVE => "MOVE",
|
||||
Self::CLOSE => "CLOSE",
|
||||
Self::LOAD_ENCODED => "LOAD_ENCODED",
|
||||
Self::LOAD_CONSTANT => "LOAD_CONSTANT",
|
||||
|
@ -27,6 +27,7 @@
|
||||
//!
|
||||
//! println!("{}", report);
|
||||
//! ```
|
||||
#![feature(get_many_mut)]
|
||||
|
||||
pub mod chunk;
|
||||
pub mod compiler;
|
||||
@ -40,17 +41,17 @@ pub mod value;
|
||||
pub mod vm;
|
||||
|
||||
pub use crate::chunk::{Chunk, Disassembler, Local, Scope};
|
||||
pub use crate::compiler::{CompileError, Compiler, compile};
|
||||
pub use crate::compiler::{compile, CompileError, Compiler};
|
||||
pub use crate::dust_error::{AnnotatedError, DustError};
|
||||
pub use crate::instruction::{Instruction, Operand, Operation};
|
||||
pub use crate::lexer::{LexError, Lexer, lex};
|
||||
pub use crate::lexer::{lex, LexError, Lexer};
|
||||
pub use crate::native_function::{NativeFunction, NativeFunctionError};
|
||||
pub use crate::token::{Token, TokenKind, TokenOwned};
|
||||
pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict};
|
||||
pub use crate::token::{Token, TokenKind, TokenOwned};
|
||||
pub use crate::value::{
|
||||
AbstractList, ConcreteValue, DustString, Function, RangeValue, Value, ValueError,
|
||||
};
|
||||
pub use crate::vm::{Vm, run};
|
||||
pub use crate::vm::{run, Vm};
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
|
@ -8,7 +8,11 @@ pub fn panic(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let mut message = format!("Dust panic at {position}!");
|
||||
|
||||
for register_index in argument_range {
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
let string = current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get(register_index)
|
||||
.as_value();
|
||||
|
||||
message.push_str(string);
|
||||
message.push('\n');
|
||||
|
@ -27,7 +27,11 @@ pub fn write(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let mut stdout = stdout();
|
||||
|
||||
for register_index in argument_range {
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
let string = current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get(register_index)
|
||||
.as_value();
|
||||
let _ = stdout.write(string.as_bytes());
|
||||
}
|
||||
|
||||
@ -39,7 +43,11 @@ pub fn write_line(data: &mut Thread, _: usize, argument_range: Range<usize>) {
|
||||
let mut stdout = stdout().lock();
|
||||
|
||||
for register_index in argument_range {
|
||||
let string = current_frame.get_string_from_register(register_index);
|
||||
let string = current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get(register_index)
|
||||
.as_value();
|
||||
let _ = stdout.write(string.as_bytes());
|
||||
}
|
||||
|
||||
|
@ -14,17 +14,21 @@ pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range<u
|
||||
let register_index = argument_range_iter
|
||||
.next()
|
||||
.unwrap_or_else(|| panic!("No argument was passed to \"random_int\""));
|
||||
let integer = current_frame.get_integer_from_register(register_index);
|
||||
let integer = current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get(register_index)
|
||||
.copy_value();
|
||||
|
||||
if min.is_none() {
|
||||
min = Some(integer);
|
||||
} else {
|
||||
if let Some(min) = min {
|
||||
break (min, integer);
|
||||
} else {
|
||||
min = Some(integer);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let random_integer = rand::thread_rng().gen_range(min.unwrap()..max);
|
||||
let random_integer = rand::thread_rng().gen_range(min..max);
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
|
@ -13,6 +13,7 @@ use crate::instruction::TypeCode;
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "Type", content = "Value")]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Byte,
|
||||
Character,
|
||||
@ -168,6 +169,7 @@ impl Type {
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Byte => write!(f, "byte"),
|
||||
Type::Character => write!(f, "char"),
|
||||
@ -231,6 +233,8 @@ impl PartialOrd for Type {
|
||||
impl Ord for Type {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match (self, other) {
|
||||
(Type::Any, Type::Any) => Ordering::Equal,
|
||||
(Type::Any, _) => Ordering::Greater,
|
||||
(Type::Boolean, Type::Boolean) => Ordering::Equal,
|
||||
(Type::Boolean, _) => Ordering::Greater,
|
||||
(Type::Byte, Type::Byte) => Ordering::Equal,
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
vm::{Pointer, Thread},
|
||||
};
|
||||
|
||||
use super::DustString;
|
||||
use super::{ConcreteValue, DustString};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||
pub struct AbstractList {
|
||||
@ -20,7 +20,7 @@ impl AbstractList {
|
||||
|
||||
display.push('[');
|
||||
|
||||
for (i, pointer) in self.item_pointers.iter().enumerate() {
|
||||
for (i, pointer) in self.item_pointers.iter().copied().enumerate() {
|
||||
if i > 0 {
|
||||
display.push_str(", ");
|
||||
}
|
||||
@ -44,6 +44,71 @@ impl AbstractList {
|
||||
|
||||
display
|
||||
}
|
||||
|
||||
pub fn to_concrete(&self, thread: &Thread) -> ConcreteValue {
|
||||
let mut concrete_list = Vec::with_capacity(self.item_pointers.len());
|
||||
|
||||
match self.item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for pointer in &self.item_pointers {
|
||||
let boolean = thread.current_frame().get_boolean_from_pointer(*pointer);
|
||||
|
||||
concrete_list.push(ConcreteValue::Boolean(boolean));
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for pointer in &self.item_pointers {
|
||||
let byte = thread.current_frame().get_byte_from_pointer(*pointer);
|
||||
|
||||
concrete_list.push(ConcreteValue::Byte(byte));
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for pointer in &self.item_pointers {
|
||||
let character = thread.current_frame().get_character_from_pointer(*pointer);
|
||||
|
||||
concrete_list.push(ConcreteValue::Character(character));
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for pointer in &self.item_pointers {
|
||||
let float = thread.current_frame().get_float_from_pointer(*pointer);
|
||||
|
||||
concrete_list.push(ConcreteValue::Float(float));
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for pointer in &self.item_pointers {
|
||||
let integer = thread.current_frame().get_integer_from_pointer(*pointer);
|
||||
|
||||
concrete_list.push(ConcreteValue::Integer(integer));
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for pointer in &self.item_pointers {
|
||||
let string = thread
|
||||
.current_frame()
|
||||
.get_string_from_pointer(*pointer)
|
||||
.clone();
|
||||
|
||||
concrete_list.push(ConcreteValue::String(string));
|
||||
}
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
for pointer in &self.item_pointers {
|
||||
let list = thread
|
||||
.current_frame()
|
||||
.get_list_from_pointer(pointer)
|
||||
.to_concrete(thread);
|
||||
|
||||
concrete_list.push(list);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
||||
ConcreteValue::List(concrete_list)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AbstractList {
|
||||
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
||||
use smartstring::{LazyCompact, SmartString};
|
||||
use tracing::trace;
|
||||
|
||||
use crate::{Type, Value, instruction::TypeCode};
|
||||
use crate::{Type, Value};
|
||||
|
||||
use super::RangeValue;
|
||||
|
||||
@ -18,10 +18,7 @@ pub enum ConcreteValue {
|
||||
Character(char),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
List {
|
||||
items: Vec<ConcreteValue>,
|
||||
item_type: TypeCode,
|
||||
},
|
||||
List(Vec<ConcreteValue>),
|
||||
Range(RangeValue),
|
||||
String(DustString),
|
||||
}
|
||||
@ -31,11 +28,8 @@ impl ConcreteValue {
|
||||
Value::Concrete(self)
|
||||
}
|
||||
|
||||
pub fn list<T: Into<Vec<ConcreteValue>>>(into_items: T, type_code: TypeCode) -> Self {
|
||||
ConcreteValue::List {
|
||||
items: into_items.into(),
|
||||
item_type: type_code,
|
||||
}
|
||||
pub fn list<T: Into<Vec<ConcreteValue>>>(into_items: T) -> Self {
|
||||
ConcreteValue::List(into_items.into())
|
||||
}
|
||||
|
||||
pub fn string<T: Into<SmartString<LazyCompact>>>(to_string: T) -> Self {
|
||||
@ -91,8 +85,8 @@ impl ConcreteValue {
|
||||
}
|
||||
|
||||
pub fn as_list(&self) -> Option<&Vec<ConcreteValue>> {
|
||||
if let ConcreteValue::List { items, .. } = self {
|
||||
Some(items)
|
||||
if let ConcreteValue::List(list) = self {
|
||||
Some(list)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -117,7 +111,7 @@ impl ConcreteValue {
|
||||
ConcreteValue::Character(_) => Type::Character,
|
||||
ConcreteValue::Float(_) => Type::Float,
|
||||
ConcreteValue::Integer(_) => Type::Integer,
|
||||
ConcreteValue::List { item_type, .. } => Type::List(*item_type),
|
||||
ConcreteValue::List(items) => items.first().map_or(Type::Any, |item| item.r#type()),
|
||||
ConcreteValue::Range(range) => range.r#type(),
|
||||
ConcreteValue::String(_) => Type::String,
|
||||
}
|
||||
@ -134,10 +128,7 @@ impl Clone for ConcreteValue {
|
||||
ConcreteValue::Character(character) => ConcreteValue::Character(*character),
|
||||
ConcreteValue::Float(float) => ConcreteValue::Float(*float),
|
||||
ConcreteValue::Integer(integer) => ConcreteValue::Integer(*integer),
|
||||
ConcreteValue::List { items, item_type } => ConcreteValue::List {
|
||||
items: items.clone(),
|
||||
item_type: *item_type,
|
||||
},
|
||||
ConcreteValue::List(items) => ConcreteValue::List(items.clone()),
|
||||
ConcreteValue::Range(range) => ConcreteValue::Range(*range),
|
||||
ConcreteValue::String(string) => ConcreteValue::String(string.clone()),
|
||||
}
|
||||
@ -160,7 +151,7 @@ impl Display for ConcreteValue {
|
||||
Ok(())
|
||||
}
|
||||
ConcreteValue::Integer(integer) => write!(f, "{integer}"),
|
||||
ConcreteValue::List { items, .. } => {
|
||||
ConcreteValue::List(items) => {
|
||||
write!(f, "[")?;
|
||||
|
||||
for (index, item) in items.iter().enumerate() {
|
||||
|
@ -1,8 +1,7 @@
|
||||
use std::{
|
||||
cell::{RefCell, RefMut},
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
ops::{Add, Index, IndexMut},
|
||||
rc::Rc,
|
||||
ops::{Index, IndexMut, RangeInclusive},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use smallvec::SmallVec;
|
||||
@ -11,14 +10,14 @@ use crate::{AbstractList, Chunk, DustString, Function};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CallFrame {
|
||||
pub chunk: Rc<Chunk>,
|
||||
pub chunk: Arc<Chunk>,
|
||||
pub ip: usize,
|
||||
pub return_register: u16,
|
||||
pub registers: RegisterTable,
|
||||
}
|
||||
|
||||
impl CallFrame {
|
||||
pub fn new(chunk: Rc<Chunk>, return_register: u16) -> Self {
|
||||
pub fn new(chunk: Arc<Chunk>, return_register: u16) -> Self {
|
||||
let registers = RegisterTable {
|
||||
booleans: RegisterList::new(chunk.boolean_register_count as usize),
|
||||
bytes: RegisterList::new(chunk.byte_register_count as usize),
|
||||
@ -38,129 +37,81 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_register(&self, register_index: usize) -> bool {
|
||||
let register = self.registers.booleans.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_boolean_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_boolean_from_pointer(&self, pointer: &Pointer) -> bool {
|
||||
pub fn get_boolean_from_pointer(&self, pointer: Pointer) -> bool {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_boolean_from_register(*register_index),
|
||||
Pointer::Register(register_index) => {
|
||||
*self.registers.booleans.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(_) => panic!("Attempted to get boolean from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_register(&self, register_index: usize) -> u8 {
|
||||
let register = self.registers.bytes.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_byte_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_byte_from_pointer(&self, pointer: &Pointer) -> u8 {
|
||||
pub fn get_byte_from_pointer(&self, pointer: Pointer) -> u8 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_byte_from_register(*register_index),
|
||||
Pointer::Register(register_index) => {
|
||||
*self.registers.bytes.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(_) => panic!("Attempted to get byte from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_register(&self, register_index: usize) -> char {
|
||||
let register = self.registers.characters.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_character_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_from_pointer(&self, pointer: &Pointer) -> char {
|
||||
pub fn get_character_from_pointer(&self, pointer: Pointer) -> char {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_character_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_character_constant(*constant_index),
|
||||
Pointer::Register(register_index) => {
|
||||
*self.registers.characters.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_character_constant(constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_character_constant(&self, constant_index: usize) -> char {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.character_constants.get(constant_index).unwrap()
|
||||
if cfg!(debug_assertions) {
|
||||
*self.chunk.character_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.chunk.character_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_float_from_register(&self, register_index: usize) -> f64 {
|
||||
let register = self.registers.floats.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_float_from_pointer(pointer),
|
||||
unsafe { *self.chunk.character_constants.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_from_pointer(&self, pointer: &Pointer) -> f64 {
|
||||
pub fn get_float_from_pointer(&self, pointer: Pointer) -> f64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_float_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_float_constant(*constant_index),
|
||||
Pointer::Register(register_index) => {
|
||||
*self.registers.floats.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_float_constant(constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_float_constant(&self, constant_index: usize) -> f64 {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.float_constants.get(constant_index).unwrap()
|
||||
if cfg!(debug_assertions) {
|
||||
*self.chunk.float_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.chunk.float_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_integer_from_register(&self, register_index: usize) -> i64 {
|
||||
let register = self.registers.integers.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => *value,
|
||||
Register::Pointer { pointer, .. } => self.get_integer_from_pointer(pointer),
|
||||
unsafe { *self.chunk.float_constants.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_from_pointer(&self, pointer: &Pointer) -> i64 {
|
||||
pub fn get_integer_from_pointer(&self, pointer: Pointer) -> i64 {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_integer_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant(*constant_index),
|
||||
Pointer::Register(register_index) => {
|
||||
*self.registers.integers.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_integer_constant(constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_integer_constant(&self, constant_index: usize) -> i64 {
|
||||
let constant = if cfg!(debug_assertions) {
|
||||
self.chunk.integer_constants.get(constant_index).unwrap()
|
||||
if cfg!(debug_assertions) {
|
||||
*self.chunk.integer_constants.get(constant_index).unwrap()
|
||||
} else {
|
||||
unsafe { self.chunk.integer_constants.get_unchecked(constant_index) }
|
||||
};
|
||||
|
||||
*constant
|
||||
}
|
||||
|
||||
pub fn get_string_from_register(&self, register_index: usize) -> &DustString {
|
||||
let register = self.registers.strings.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_string_from_pointer(pointer),
|
||||
unsafe { *self.chunk.integer_constants.get_unchecked(constant_index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_string_from_pointer(&self, pointer: &Pointer) -> &DustString {
|
||||
pub fn get_string_from_pointer(&self, pointer: Pointer) -> &DustString {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_string_from_register(*register_index),
|
||||
Pointer::Constant(constant_index) => self.get_string_constant(*constant_index),
|
||||
Pointer::Register(register_index) => {
|
||||
self.registers.strings.get(register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(constant_index) => self.get_string_constant(constant_index),
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,52 +123,20 @@ impl CallFrame {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_register(&self, register_index: usize) -> &AbstractList {
|
||||
let register = self.registers.lists.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_list_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_register_mut(&mut self, register_index: usize) -> &mut AbstractList {
|
||||
let register = self.registers.lists.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => panic!("Attempted to get mutable list from pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_list_from_pointer(&self, pointer: &Pointer) -> &AbstractList {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_list_from_register(*register_index),
|
||||
Pointer::Register(register_index) => {
|
||||
self.registers.lists.get(*register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(_) => panic!("Attempted to get list from constant pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_register(&self, register_index: usize) -> &Function {
|
||||
let register = self.registers.functions.get(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { pointer, .. } => self.get_function_from_pointer(pointer),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_register_mut(&mut self, register_index: usize) -> &mut Function {
|
||||
let register = self.registers.functions.get_mut(register_index);
|
||||
|
||||
match register {
|
||||
Register::Value { value, .. } => value,
|
||||
Register::Pointer { .. } => panic!("Attempted to get mutable function from pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_function_from_pointer(&self, pointer: &Pointer) -> &Function {
|
||||
match pointer {
|
||||
Pointer::Register(register_index) => self.get_function_from_register(*register_index),
|
||||
Pointer::Register(register_index) => {
|
||||
self.registers.functions.get(*register_index).as_value()
|
||||
}
|
||||
Pointer::Constant(_) => panic!("Attempted to get function from constant pointer"),
|
||||
}
|
||||
}
|
||||
@ -276,6 +195,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_many_mut(&mut self, indices: RangeInclusive<usize>) -> &mut [Register<T>] {
|
||||
let registers = if cfg!(debug_assertions) {
|
||||
self.registers.get_many_mut([indices]).unwrap()
|
||||
} else {
|
||||
unsafe { self.registers.get_many_unchecked_mut([indices]) }
|
||||
};
|
||||
|
||||
registers[0]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, index: usize) -> &mut Register<T> {
|
||||
if cfg!(debug_assertions) {
|
||||
let length = self.registers.len();
|
||||
@ -302,6 +231,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close_many(&mut self, indices: RangeInclusive<usize>) {
|
||||
let registers = if cfg!(debug_assertions) {
|
||||
&mut self.registers.get_many_mut([indices]).unwrap()[0]
|
||||
} else {
|
||||
unsafe { &mut self.registers.get_many_unchecked_mut([indices])[0] }
|
||||
};
|
||||
|
||||
for register in registers.iter_mut() {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self, index: usize) -> bool {
|
||||
if cfg!(debug_assertions) {
|
||||
self.registers.get(index).unwrap().is_closed()
|
||||
@ -325,66 +266,56 @@ impl<T> IndexMut<usize> for RegisterList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Register<T> {
|
||||
Value { value: T, is_closed: bool },
|
||||
Pointer { pointer: Pointer, is_closed: bool },
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Register<T> {
|
||||
value: T,
|
||||
is_closed: bool,
|
||||
}
|
||||
|
||||
impl<T> Register<T> {
|
||||
pub fn value(value: T) -> Self {
|
||||
Self::Value {
|
||||
Self {
|
||||
value,
|
||||
is_closed: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_closed(&self) -> bool {
|
||||
match self {
|
||||
Self::Value { is_closed, .. } => *is_closed,
|
||||
Self::Pointer { is_closed, .. } => *is_closed,
|
||||
}
|
||||
self.is_closed
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
match self {
|
||||
Self::Value { is_closed, .. } => *is_closed = true,
|
||||
Self::Pointer { is_closed, .. } => *is_closed = true,
|
||||
}
|
||||
self.is_closed = true;
|
||||
}
|
||||
|
||||
pub fn set(&mut self, new_value: T) {
|
||||
match self {
|
||||
Self::Value {
|
||||
value: old_value, ..
|
||||
} => *old_value = new_value,
|
||||
Self::Pointer { is_closed, .. } => {
|
||||
*self = Self::Value {
|
||||
value: new_value,
|
||||
is_closed: *is_closed,
|
||||
}
|
||||
}
|
||||
}
|
||||
self.value = new_value;
|
||||
}
|
||||
|
||||
pub fn as_value(&self) -> &T {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
}
|
||||
&self.value
|
||||
}
|
||||
|
||||
pub fn as_value_mut(&mut self) -> &mut T {
|
||||
match self {
|
||||
Self::Value { value, .. } => value,
|
||||
Self::Pointer { .. } => panic!("Attempted to use pointer as value"),
|
||||
}
|
||||
&mut self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy> Register<T> {
|
||||
pub fn copy_value(&self) -> T {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> Register<T> {
|
||||
pub fn clone_value(&self) -> T {
|
||||
self.value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default> Default for Register<T> {
|
||||
fn default() -> Self {
|
||||
Self::Value {
|
||||
Self {
|
||||
value: Default::default(),
|
||||
is_closed: false,
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
mod call_frame;
|
||||
mod thread;
|
||||
|
||||
use std::{rc::Rc, thread::Builder};
|
||||
use std::{sync::Arc, thread::Builder};
|
||||
|
||||
pub use call_frame::{CallFrame, Pointer, Register, RegisterTable};
|
||||
pub use thread::Thread;
|
||||
@ -32,6 +32,7 @@ impl Vm {
|
||||
pub fn run(self) -> Option<Value> {
|
||||
let span = span!(Level::INFO, "Run");
|
||||
let _enter = span.enter();
|
||||
|
||||
let thread_name = self
|
||||
.main_chunk
|
||||
.name
|
||||
@ -43,7 +44,7 @@ impl Vm {
|
||||
Builder::new()
|
||||
.name(thread_name)
|
||||
.spawn(move || {
|
||||
let main_chunk = Rc::new(self.main_chunk);
|
||||
let main_chunk = Arc::new(self.main_chunk);
|
||||
let main_thread = Thread::new(main_chunk);
|
||||
let return_value = main_thread.run();
|
||||
let _ = tx.send(return_value);
|
||||
|
@ -1,21 +1,23 @@
|
||||
use std::{rc::Rc, thread::JoinHandle};
|
||||
use std::{sync::Arc, thread::JoinHandle};
|
||||
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
instruction::TypeCode, vm::CallFrame, Chunk, ConcreteValue, DustString, Operation, Span, Value,
|
||||
instruction::TypeCode,
|
||||
vm::{CallFrame, Pointer},
|
||||
AbstractList, Chunk, DustString, Operation, Span, Value,
|
||||
};
|
||||
|
||||
pub struct Thread {
|
||||
chunk: Rc<Chunk>,
|
||||
chunk: Arc<Chunk>,
|
||||
call_stack: Vec<CallFrame>,
|
||||
_spawned_threads: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
pub fn new(chunk: Rc<Chunk>) -> Self {
|
||||
pub fn new(chunk: Arc<Chunk>) -> Self {
|
||||
let mut call_stack = Vec::with_capacity(chunk.prototypes.len() + 1);
|
||||
let main_call = CallFrame::new(Rc::clone(&chunk), 0);
|
||||
let main_call = CallFrame::new(Arc::clone(&chunk), 0);
|
||||
|
||||
call_stack.push(main_call);
|
||||
|
||||
@ -52,6 +54,168 @@ impl Thread {
|
||||
info!("Run instruction {}", instruction.operation());
|
||||
|
||||
match instruction.operation() {
|
||||
Operation::MOVE => {
|
||||
let source = instruction.b_field() as usize;
|
||||
let destination = instruction.a_field() as usize;
|
||||
let source_type = instruction.b_type();
|
||||
|
||||
match source_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let value = current_frame.registers.booleans.get(source).copy_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.booleans
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let value = current_frame.registers.bytes.get(source).copy_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.bytes
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
let value = current_frame.registers.characters.get(source).copy_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let value = current_frame.registers.floats.get(source).copy_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.floats
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let value = current_frame.registers.integers.get(source).copy_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let value = current_frame.registers.strings.get(source).clone_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.strings
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let value = current_frame.registers.lists.get(source).clone_value();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.lists
|
||||
.get_mut(destination)
|
||||
.set(value);
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
Operation::CLOSE => {
|
||||
let from = instruction.b_field() as usize;
|
||||
let to = instruction.c_field() as usize;
|
||||
let r#type = instruction.b_type();
|
||||
|
||||
match r#type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let registers =
|
||||
current_frame.registers.booleans.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let registers = current_frame.registers.bytes.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
let registers =
|
||||
current_frame.registers.characters.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let registers = current_frame.registers.floats.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let registers =
|
||||
current_frame.registers.integers.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let registers = current_frame.registers.strings.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let registers = current_frame.registers.lists.get_many_mut(from..=to);
|
||||
|
||||
for register in registers {
|
||||
register.close();
|
||||
}
|
||||
}
|
||||
_ => unreachable!("Invalid CLOSE operation"),
|
||||
}
|
||||
}
|
||||
Operation::LOAD_ENCODED => {
|
||||
let destination = instruction.a_field() as usize;
|
||||
let value_type = instruction.b_type();
|
||||
let jump_next = instruction.c_field() != 0;
|
||||
|
||||
match value_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let boolean = instruction.b_field() != 0;
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.booleans
|
||||
.set_to_new_register(destination, boolean);
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let byte = instruction.b_field() as u8;
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.bytes
|
||||
.set_to_new_register(destination, byte);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
if jump_next {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LOAD_CONSTANT => {
|
||||
let destination = instruction.a_field() as usize;
|
||||
let constant_index = instruction.b_field() as usize;
|
||||
@ -102,6 +266,139 @@ impl Thread {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LOAD_LIST => {
|
||||
let destination = instruction.a_field() as usize;
|
||||
let start_register = instruction.b_field() as usize;
|
||||
let item_type = instruction.b_type();
|
||||
let end_register = instruction.c_field() as usize;
|
||||
let jump_next = instruction.d_field();
|
||||
|
||||
let mut item_pointers = Vec::with_capacity(end_register - start_register + 1);
|
||||
|
||||
match item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.booleans.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.bytes.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.characters.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.floats.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.integers.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.strings.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
for register_index in start_register..=end_register {
|
||||
let register_is_closed =
|
||||
current_frame.registers.lists.is_closed(register_index);
|
||||
|
||||
if register_is_closed {
|
||||
continue;
|
||||
}
|
||||
|
||||
item_pointers.push(Pointer::Register(register_index));
|
||||
}
|
||||
}
|
||||
_ => unreachable!("Invalid LOAD_LIST operation"),
|
||||
}
|
||||
|
||||
let list = AbstractList {
|
||||
item_type,
|
||||
item_pointers,
|
||||
};
|
||||
|
||||
current_frame.registers.lists.get_mut(destination).set(list);
|
||||
|
||||
if jump_next {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LOAD_FUNCTION => {
|
||||
let destination = instruction.a_field() as usize;
|
||||
let prototype_index = instruction.b_field() as usize;
|
||||
let jump_next = instruction.c_field() != 0;
|
||||
let prototype = if cfg!(debug_assertions) {
|
||||
current_frame.chunk.prototypes.get(prototype_index).unwrap()
|
||||
} else {
|
||||
unsafe {
|
||||
current_frame
|
||||
.chunk
|
||||
.prototypes
|
||||
.get_unchecked(prototype_index)
|
||||
}
|
||||
};
|
||||
let function = prototype.as_function();
|
||||
|
||||
current_frame
|
||||
.registers
|
||||
.functions
|
||||
.set_to_new_register(destination, function);
|
||||
|
||||
if jump_next {
|
||||
current_frame.ip += 1;
|
||||
}
|
||||
}
|
||||
Operation::LESS => match (instruction.b_type(), instruction.c_type()) {
|
||||
(TypeCode::INTEGER, TypeCode::INTEGER) => {
|
||||
let left = instruction.b_field() as usize;
|
||||
@ -113,12 +410,12 @@ impl Thread {
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(left)
|
||||
current_frame.registers.integers.get(left).copy_value()
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(right)
|
||||
current_frame.registers.integers.get(right).copy_value()
|
||||
};
|
||||
let is_less_than = left_value < right_value;
|
||||
|
||||
@ -134,8 +431,9 @@ impl Thread {
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = current_frame.get_byte_from_register(left_index);
|
||||
let right_value = current_frame.get_byte_from_register(right_index);
|
||||
let left_value = current_frame.registers.bytes.get(left_index).copy_value();
|
||||
let right_value =
|
||||
current_frame.registers.bytes.get(right_index).copy_value();
|
||||
let sum = left_value + right_value;
|
||||
|
||||
current_frame
|
||||
@ -153,12 +451,20 @@ impl Thread {
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(left_index)
|
||||
current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get(left_index)
|
||||
.copy_value()
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_character_constant(right_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(right_index)
|
||||
current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get(right_index)
|
||||
.copy_value()
|
||||
};
|
||||
let concatenated = {
|
||||
let mut concatenated = DustString::from(String::with_capacity(2));
|
||||
@ -184,12 +490,16 @@ impl Thread {
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_character_constant(left_index)
|
||||
} else {
|
||||
current_frame.get_character_from_register(left_index)
|
||||
current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get(left_index)
|
||||
.copy_value()
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_string_constant(right_index)
|
||||
} else {
|
||||
current_frame.get_string_from_register(right_index)
|
||||
current_frame.registers.strings.get(right_index).as_value()
|
||||
};
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
@ -203,8 +513,10 @@ impl Thread {
|
||||
let right_index = instruction.c_field() as usize;
|
||||
let destination_index = instruction.a_field() as usize;
|
||||
|
||||
let left_value = current_frame.get_float_from_register(left_index);
|
||||
let right_value = current_frame.get_float_from_register(right_index);
|
||||
let left_value =
|
||||
current_frame.registers.floats.get(left_index).copy_value();
|
||||
let right_value =
|
||||
current_frame.registers.floats.get(right_index).copy_value();
|
||||
let sum = left_value + right_value;
|
||||
|
||||
current_frame
|
||||
@ -222,12 +534,12 @@ impl Thread {
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_integer_constant(left)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(left)
|
||||
current_frame.registers.integers.get(left).copy_value()
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_integer_constant(right)
|
||||
} else {
|
||||
current_frame.get_integer_from_register(right)
|
||||
current_frame.registers.integers.get(right).copy_value()
|
||||
};
|
||||
let sum = left_value + right_value;
|
||||
|
||||
@ -246,12 +558,12 @@ impl Thread {
|
||||
let left_value = if left_is_constant {
|
||||
current_frame.get_string_constant(left)
|
||||
} else {
|
||||
current_frame.get_string_from_register(left)
|
||||
current_frame.registers.strings.get(left).as_value()
|
||||
};
|
||||
let right_value = if right_is_constant {
|
||||
current_frame.get_string_constant(right)
|
||||
} else {
|
||||
current_frame.get_string_from_register(right)
|
||||
current_frame.registers.strings.get(right).as_value()
|
||||
};
|
||||
let concatenated = DustString::from(format!("{left_value}{right_value}"));
|
||||
|
||||
@ -260,7 +572,7 @@ impl Thread {
|
||||
.strings
|
||||
.set_to_new_register(destination_index, concatenated);
|
||||
}
|
||||
_ => todo!(),
|
||||
_ => unreachable!("Invalid ADD operation"),
|
||||
},
|
||||
Operation::JUMP => {
|
||||
let offset = instruction.b_field() as usize;
|
||||
@ -280,112 +592,69 @@ impl Thread {
|
||||
if should_return_value {
|
||||
match return_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
let return_value =
|
||||
current_frame.get_boolean_from_register(return_register);
|
||||
let return_value = current_frame
|
||||
.registers
|
||||
.booleans
|
||||
.get(return_register)
|
||||
.copy_value();
|
||||
|
||||
return Some(Value::boolean(return_value));
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
let return_value =
|
||||
current_frame.get_byte_from_register(return_register);
|
||||
let return_value = current_frame
|
||||
.registers
|
||||
.bytes
|
||||
.get(return_register)
|
||||
.copy_value();
|
||||
|
||||
return Some(Value::byte(return_value));
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
let return_value =
|
||||
current_frame.get_character_from_register(return_register);
|
||||
let return_value = current_frame
|
||||
.registers
|
||||
.characters
|
||||
.get(return_register)
|
||||
.copy_value();
|
||||
|
||||
return Some(Value::character(return_value));
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
let return_value =
|
||||
current_frame.get_float_from_register(return_register);
|
||||
let return_value = current_frame
|
||||
.registers
|
||||
.floats
|
||||
.get(return_register)
|
||||
.copy_value();
|
||||
|
||||
return Some(Value::float(return_value));
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
let return_value =
|
||||
current_frame.get_integer_from_register(return_register);
|
||||
let return_value = current_frame
|
||||
.registers
|
||||
.integers
|
||||
.get(return_register)
|
||||
.copy_value();
|
||||
|
||||
return Some(Value::integer(return_value));
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
let return_value = current_frame
|
||||
.get_string_from_register(return_register)
|
||||
.clone();
|
||||
.registers
|
||||
.strings
|
||||
.get(return_register)
|
||||
.clone_value();
|
||||
|
||||
return Some(Value::string(return_value));
|
||||
}
|
||||
TypeCode::LIST => {
|
||||
let abstract_list =
|
||||
current_frame.get_list_from_register(return_register);
|
||||
let concrete_list = current_frame
|
||||
.registers
|
||||
.lists
|
||||
.get(return_register)
|
||||
.as_value()
|
||||
.clone()
|
||||
.to_concrete(&self);
|
||||
|
||||
let mut concrete_list =
|
||||
Vec::with_capacity(abstract_list.item_pointers.len());
|
||||
|
||||
match abstract_list.item_type {
|
||||
TypeCode::BOOLEAN => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let boolean =
|
||||
current_frame.get_boolean_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Boolean(boolean);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::BYTE => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let byte =
|
||||
current_frame.get_byte_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Byte(byte);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::CHARACTER => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let character =
|
||||
current_frame.get_character_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Character(character);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::FLOAT => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let float =
|
||||
current_frame.get_float_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Float(float);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::INTEGER => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let integer =
|
||||
current_frame.get_integer_from_pointer(&pointer);
|
||||
let value = ConcreteValue::Integer(integer);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
TypeCode::STRING => {
|
||||
for pointer in &abstract_list.item_pointers {
|
||||
let string = current_frame
|
||||
.get_string_from_pointer(pointer)
|
||||
.clone();
|
||||
let value = ConcreteValue::String(string);
|
||||
|
||||
concrete_list.push(value);
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
||||
return Some(Value::Concrete(ConcreteValue::list(
|
||||
concrete_list,
|
||||
abstract_list.item_type,
|
||||
)));
|
||||
return Some(Value::Concrete(concrete_list));
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
Chunk, ConcreteValue, FunctionType, Instruction, Operand, Span, Type, Value, compile,
|
||||
instruction::TypeCode, run,
|
||||
compile, instruction::TypeCode, run, Chunk, FunctionType, Instruction, Operand, Span, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -78,7 +78,7 @@ fn divide_floats() {
|
||||
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 10), Span(10, 10)],
|
||||
constants: vec![ConcreteValue::Float(1.0), ConcreteValue::Float(0.25)],
|
||||
float_constants: vec![1.0, 0.25],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(4.0));
|
||||
@ -106,11 +106,7 @@ fn divide_many_floats() {
|
||||
Instruction::r#return(true, 1, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 10), Span(0, 16), Span(16, 16)],
|
||||
constants: vec![
|
||||
ConcreteValue::Float(1.0),
|
||||
ConcreteValue::Float(0.25),
|
||||
ConcreteValue::Float(0.5),
|
||||
],
|
||||
float_constants: vec![1.0, 0.25, 0.5],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(8.0));
|
||||
@ -133,7 +129,7 @@ fn divide_integers() {
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(6, 6)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(2)],
|
||||
integer_constants: vec![10, 2],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(5));
|
||||
@ -161,7 +157,7 @@ fn divide_many_integers() {
|
||||
Instruction::r#return(true, 1, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(0, 10), Span(10, 10)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(2)],
|
||||
integer_constants: vec![10, 2],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(2));
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
Chunk, ConcreteValue, FunctionType, Instruction, Operand, Span, Type, Value, compile,
|
||||
instruction::TypeCode, run,
|
||||
compile, instruction::TypeCode, run, Chunk, FunctionType, Instruction, Operand, Span, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -78,7 +78,7 @@ fn modulo_integers() {
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(6, 6)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(3)],
|
||||
integer_constants: vec![10, 3],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(1));
|
||||
@ -106,11 +106,7 @@ fn modulo_many_integers() {
|
||||
Instruction::r#return(true, 1, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(0, 10), Span(10, 10)],
|
||||
constants: vec![
|
||||
ConcreteValue::Integer(10),
|
||||
ConcreteValue::Integer(5),
|
||||
ConcreteValue::Integer(3),
|
||||
],
|
||||
integer_constants: vec![10, 5, 3],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(0));
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
Chunk, ConcreteValue, FunctionType, Instruction, Operand, Span, Type, Value, compile,
|
||||
instruction::TypeCode, run,
|
||||
compile, instruction::TypeCode, run, Chunk, FunctionType, Instruction, Operand, Span, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -78,7 +78,7 @@ fn multiply_floats() {
|
||||
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 9), Span(9, 9)],
|
||||
constants: vec![ConcreteValue::Float(0.5), ConcreteValue::Float(2.0)],
|
||||
float_constants: vec![0.5, 2.0],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(1.0));
|
||||
@ -106,7 +106,7 @@ fn multiply_many_floats() {
|
||||
Instruction::r#return(true, 1, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 9), Span(0, 15), Span(15, 15)],
|
||||
constants: vec![ConcreteValue::Float(0.5), ConcreteValue::Float(2.0)],
|
||||
float_constants: vec![0.5, 2.0],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(0.5));
|
||||
@ -129,7 +129,7 @@ fn multiply_integers() {
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(6, 6)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(5)],
|
||||
integer_constants: vec![10, 5],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(50));
|
||||
@ -157,11 +157,7 @@ fn multiply_many_integers() {
|
||||
Instruction::r#return(true, 1, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(0, 10), Span(10, 10)],
|
||||
constants: vec![
|
||||
ConcreteValue::Integer(10),
|
||||
ConcreteValue::Integer(5),
|
||||
ConcreteValue::Integer(2),
|
||||
],
|
||||
integer_constants: vec![10, 5, 2],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(100));
|
||||
|
@ -1,6 +1,6 @@
|
||||
use dust_lang::{
|
||||
Chunk, ConcreteValue, FunctionType, Instruction, Operand, Span, Type, Value, compile,
|
||||
instruction::TypeCode, run,
|
||||
compile, instruction::TypeCode, run, Chunk, FunctionType, Instruction, Operand, Span, Type,
|
||||
Value,
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -78,7 +78,7 @@ fn add_floats() {
|
||||
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 10), Span(10, 10)],
|
||||
constants: vec![ConcreteValue::Float(0.5), ConcreteValue::Float(0.25)],
|
||||
float_constants: vec![0.5, 0.25],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(0.25));
|
||||
@ -106,7 +106,7 @@ fn add_many_floats() {
|
||||
Instruction::r#return(true, 1, TypeCode::FLOAT),
|
||||
],
|
||||
positions: vec![Span(0, 10), Span(0, 17), Span(17, 17)],
|
||||
constants: vec![ConcreteValue::Float(0.5), ConcreteValue::Float(0.25)],
|
||||
float_constants: vec![0.5, 0.25],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::float(0.0));
|
||||
@ -129,7 +129,7 @@ fn subtract_integers() {
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(6, 6)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(5)],
|
||||
integer_constants: vec![10, 5],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(5));
|
||||
@ -157,7 +157,7 @@ fn subtract_many_integers() {
|
||||
Instruction::r#return(true, 1, TypeCode::INTEGER),
|
||||
],
|
||||
positions: vec![Span(0, 6), Span(0, 10), Span(10, 10)],
|
||||
constants: vec![ConcreteValue::Integer(10), ConcreteValue::Integer(5)],
|
||||
integer_constants: vec![10, 5],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::integer(0));
|
||||
|
@ -147,10 +147,10 @@ fn load_boolean_list() {
|
||||
positions: vec![Span(1, 5), Span(7, 12), Span(0, 13), Span(13, 13)],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Boolean(true), ConcreteValue::Boolean(false)],
|
||||
item_type: TypeCode::BOOLEAN,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::Boolean(true),
|
||||
ConcreteValue::Boolean(false),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -170,10 +170,10 @@ fn load_byte_list() {
|
||||
positions: vec![Span(1, 5), Span(7, 11), Span(0, 12), Span(12, 12)],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Byte(0x2a), ConcreteValue::Byte(0x42)],
|
||||
item_type: TypeCode::BYTE,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::Byte(0x2a),
|
||||
ConcreteValue::Byte(0x42),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -194,10 +194,10 @@ fn load_character_list() {
|
||||
character_constants: vec!['a', 'b'],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||
item_type: TypeCode::CHARACTER,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::Character('a'),
|
||||
ConcreteValue::Character('b'),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -218,10 +218,10 @@ fn load_float_list() {
|
||||
float_constants: vec![42.42, 24.24],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
|
||||
item_type: TypeCode::FLOAT,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::Float(42.42),
|
||||
ConcreteValue::Float(24.24),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -243,14 +243,11 @@ fn load_integer_list() {
|
||||
integer_constants: vec![1, 2, 3],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
],
|
||||
item_type: TypeCode::INTEGER,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::Integer(1),
|
||||
ConcreteValue::Integer(2),
|
||||
ConcreteValue::Integer(3),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -271,13 +268,10 @@ fn load_string_list() {
|
||||
string_constants: vec![DustString::from("Hello"), DustString::from("World")],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::String(DustString::from("Hello")),
|
||||
ConcreteValue::String(DustString::from("World")),
|
||||
],
|
||||
item_type: TypeCode::STRING,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::String(DustString::from("Hello")),
|
||||
ConcreteValue::String(DustString::from("World")),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -311,19 +305,10 @@ fn load_nested_list() {
|
||||
integer_constants: vec![1, 2, 3, 4],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
],
|
||||
item_type: TypeCode::LIST,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
@ -377,37 +362,16 @@ fn load_deeply_nested_list() {
|
||||
integer_constants: vec![1, 2, 3, 4, 5, 6, 7, 8],
|
||||
..Chunk::default()
|
||||
};
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
],
|
||||
item_type: TypeCode::LIST,
|
||||
},
|
||||
ConcreteValue::List {
|
||||
items: vec![
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(5), ConcreteValue::Integer(6)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
ConcreteValue::List {
|
||||
items: vec![ConcreteValue::Integer(7), ConcreteValue::Integer(8)],
|
||||
item_type: TypeCode::INTEGER,
|
||||
},
|
||||
],
|
||||
item_type: TypeCode::LIST,
|
||||
},
|
||||
],
|
||||
item_type: TypeCode::LIST,
|
||||
}));
|
||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
||||
ConcreteValue::List(vec![
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
||||
]),
|
||||
ConcreteValue::List(vec![
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(5), ConcreteValue::Integer(6)]),
|
||||
ConcreteValue::List(vec![ConcreteValue::Integer(7), ConcreteValue::Integer(8)]),
|
||||
]),
|
||||
])));
|
||||
|
||||
assert_eq!(chunk, compile(source).unwrap());
|
||||
assert_eq!(return_value, run(source).unwrap());
|
||||
|
Loading…
x
Reference in New Issue
Block a user