1
0

Reimplement more instruction and compiler logic

This commit is contained in:
Jeff 2025-02-08 17:36:30 -05:00
parent 07001a03e7
commit 3af1b64820
11 changed files with 217 additions and 443 deletions

View File

@ -1020,44 +1020,52 @@ impl<'src> Compiler<'src> {
}
fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
let (last_instruction, last_type, last_position) =
let operator = self.current_token;
let operator_position = self.current_position;
let rule = ParseRule::from(&operator);
let (left_instruction, left_type, left_position) =
self.instructions
.pop()
.ok_or_else(|| CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
let operand_register = if last_instruction.operation() == Operation::POINT {
let Point { to, .. } = Point::from(last_instruction);
let operand_register = if left_instruction.operation() == Operation::POINT {
let Point { to, .. } = Point::from(left_instruction);
let local = self.get_local(to.index())?;
local.register_index
} else if last_instruction.yields_value() {
let register = last_instruction.a_field();
} else if left_instruction.yields_value() {
let register = left_instruction.a_field();
self.instructions
.push((last_instruction, last_type, last_position));
.push((left_instruction, left_type, left_position));
register
} else {
let register = match last_type {
Type::Boolean => self.next_boolean_register() - 1,
Type::Byte => self.next_byte_register() - 1,
Type::Character => self.next_character_register() - 1,
Type::Float => self.next_float_register() - 1,
Type::Integer => self.next_integer_register() - 1,
Type::String => self.next_string_register() - 1,
_ => todo!(),
};
self.instructions
.push((last_instruction, last_type, last_position));
register
return Err(CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
};
let operator = self.current_token;
let operator_position = self.current_position;
let rule = ParseRule::from(&operator);
// TODO: Check if the left type is boolean
self.advance()?;
self.parse_sub_expression(&rule.precedence)?;
let (mut right_instruction, right_type, right_position) = self
.instructions
.pop()
.ok_or_else(|| CompileError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
})?;
// TODO: Check if the right type is boolean
right_instruction.set_a_field(operand_register);
let test_boolean = match operator {
Token::DoubleAmpersand => true,
Token::DoublePipe => false,
@ -1074,8 +1082,8 @@ impl<'src> Compiler<'src> {
self.emit_instruction(test, Type::None, operator_position);
self.emit_instruction(jump, Type::None, operator_position);
self.advance()?;
self.parse_sub_expression(&rule.precedence)?;
self.instructions
.push((right_instruction, right_type, right_position));
let instructions_length = self.instructions.len();
@ -1571,7 +1579,7 @@ impl<'src> Compiler<'src> {
fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> {
let start = self.previous_position.0;
let mut argument_count = 0;
let mut first_argument_index = None;
self.expect(Token::LeftParenthesis)?;
@ -1579,7 +1587,9 @@ impl<'src> Compiler<'src> {
self.parse_expression()?;
self.allow(Token::Comma)?;
argument_count += 1;
if first_argument_index.is_none() {
first_argument_index = Some(self.instructions.last().unwrap().0.a_field());
}
}
let end = self.previous_position.1;
@ -1594,11 +1604,8 @@ impl<'src> Compiler<'src> {
_ => todo!(),
};
let return_type = *function.r#type().return_type;
let call_native = Instruction::from(CallNative {
destination,
function,
argument_count,
});
let call_native =
Instruction::call_native(destination, function, first_argument_index.unwrap_or(0));
self.emit_instruction(call_native, return_type, Span(start, end));

View File

@ -1,24 +1,25 @@
use std::fmt::Display;
use crate::{Instruction, NativeFunction, Operation};
use crate::{Instruction, NativeFunction, Operation, Type};
use super::InstructionFields;
pub struct CallNative {
pub destination: u16,
pub function: NativeFunction,
pub argument_count: u16,
pub first_argument_index: u16,
}
impl From<Instruction> for CallNative {
fn from(instruction: Instruction) -> Self {
let destination = instruction.a_field();
let function = NativeFunction::from(instruction.b_field());
let first_argument_index = instruction.c_field();
CallNative {
destination,
function,
argument_count: instruction.c_field(),
first_argument_index,
}
}
}
@ -28,7 +29,7 @@ impl From<CallNative> for Instruction {
let operation = Operation::CALL_NATIVE;
let a_field = call_native.destination;
let b_field = call_native.function as u16;
let c_field = call_native.argument_count;
let c_field = call_native.first_argument_index;
InstructionFields {
operation,
@ -46,21 +47,57 @@ impl Display for CallNative {
let CallNative {
destination,
function,
argument_count,
first_argument_index,
} = self;
let arguments_start = destination.saturating_sub(*argument_count);
let arguments_end = arguments_start + argument_count;
let argument_count = function.r#type().value_parameters.len() as u16;
if function.returns_value() {
write!(f, "R{destination} = ")?;
}
write!(f, "{function}")?;
match argument_count {
0 => {
write!(f, "{function}()")
write!(f, "()")
}
_ => {
let arguments_end = first_argument_index + argument_count - 1;
let arguments_index_range = *first_argument_index..=arguments_end;
let function_type = function.r#type();
let argument_types = function_type.value_parameters.iter();
write!(f, "(")?;
for (index, r#type) in arguments_index_range.zip(argument_types) {
match r#type {
Type::Boolean => {
write!(f, "R_BOOL_{index}")
}
Type::Byte => {
write!(f, "R_BYTE_{index}")
}
Type::Float => {
write!(f, "R_FLOAT_{index}")
}
Type::Integer => {
write!(f, "R_INT_{index}")
}
Type::String => {
write!(f, "R_STR_{index}")
}
unsupported => {
todo!("Support for {unsupported:?} arguments")
}
}?;
if index != arguments_end {
write!(f, ", ")?;
}
}
write!(f, ")")
}
1 => write!(f, "{function}(R{arguments_start})"),
_ => write!(f, "{function}(R{arguments_start}..R{arguments_end})"),
}
}
}

View File

@ -556,12 +556,12 @@ impl Instruction {
pub fn call_native(
destination: u16,
function: NativeFunction,
argument_count: u16,
first_argument_index: u16,
) -> Instruction {
Instruction::from(CallNative {
destination,
function,
argument_count,
first_argument_index,
})
}

View File

@ -44,6 +44,6 @@ impl Display for Test {
} = self;
let bang = if *test_value { "" } else { "!" };
write!(f, "if {bang}R{operand_register} {{ JUMP +1 }}")
write!(f, "if {bang}R_BOOL_{operand_register} {{ JUMP +1 }}")
}
}

View File

@ -143,13 +143,13 @@ define_native_function! {
// (ToByte, 5_u8, "to_byte", true),
// (ToFloat, 6_u8, "to_float", true),
// (ToInteger, 7_u8, "to_integer", true),
(
ToString,
8,
"to_string",
FunctionType::new([], [Type::Any], Type::String),
string::to_string
),
// (
// ToString,
// 8,
// "to_string",
// FunctionType::new([], [Type::Any], Type::String),
// string::to_string
// ),
// // List and string
// (All, 9_u8, "all", true),
@ -216,7 +216,7 @@ define_native_function! {
Write,
55,
"write",
FunctionType::new([], [Type::Any], Type::None),
FunctionType::new([], [Type::String], Type::None),
io::write
),
// (WriteFile, 56_u8, "write_file", false),
@ -224,7 +224,7 @@ define_native_function! {
WriteLine,
57,
"write_line",
FunctionType::new([], [Type::Any], Type::None),
FunctionType::new([], [Type::String], Type::None),
io::write_line
),
@ -242,7 +242,7 @@ define_native_function! {
Spawn,
60,
"spawn",
FunctionType::new([], [ Type::function([], [], Type::Any)], Type::None),
FunctionType::new([], [ Type::function([], [], Type::None)], Type::None),
thread::spawn
)
}

View File

@ -13,7 +13,6 @@ use crate::instruction::TypeCode;
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(tag = "Type", content = "Value")]
pub enum Type {
Any,
Boolean,
Byte,
Character,
@ -77,9 +76,7 @@ impl Type {
/// Checks that the type is compatible with another type.
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
match (self.concrete_type(), other.concrete_type()) {
(Type::Any, _)
| (_, Type::Any)
| (Type::Boolean, Type::Boolean)
(Type::Boolean, Type::Boolean)
| (Type::Byte, Type::Byte)
| (Type::Character, Type::Character)
| (Type::Float, Type::Float)
@ -171,7 +168,6 @@ 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"),
@ -235,8 +231,6 @@ 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,

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
use smartstring::{LazyCompact, SmartString};
use tracing::trace;
use crate::{Type, Value, ValueError};
use crate::{Type, Value, ValueError, instruction::TypeCode};
use super::RangeValue;
@ -18,7 +18,10 @@ pub enum ConcreteValue {
Character(char),
Float(f64),
Integer(i64),
List(Vec<ConcreteValue>),
List {
items: Vec<ConcreteValue>,
item_type: TypeCode,
},
Range(RangeValue),
String(DustString),
}
@ -28,8 +31,11 @@ impl ConcreteValue {
Value::Concrete(self)
}
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
ConcreteValue::List(into_list.into())
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 string<T: Into<SmartString<LazyCompact>>>(to_string: T) -> Self {
@ -85,8 +91,8 @@ impl ConcreteValue {
}
pub fn as_list(&self) -> Option<&Vec<ConcreteValue>> {
if let ConcreteValue::List(list) = self {
Some(list)
if let ConcreteValue::List { items, .. } = self {
Some(items)
} else {
None
}
@ -111,239 +117,11 @@ impl ConcreteValue {
ConcreteValue::Character(_) => Type::Character,
ConcreteValue::Float(_) => Type::Float,
ConcreteValue::Integer(_) => Type::Integer,
ConcreteValue::List(list) => {
let item_type = list
.first()
.map_or(Type::Any, |item| item.r#type())
.type_code();
Type::List(item_type)
}
ConcreteValue::List { item_type, .. } => Type::List(*item_type),
ConcreteValue::Range(range) => range.r#type(),
ConcreteValue::String(_) => Type::String,
}
}
pub fn add(&self, other: &Self) -> ConcreteValue {
use ConcreteValue::*;
match (self, other) {
(Byte(left), Byte(right)) => {
let sum = left.saturating_add(*right);
Byte(sum)
}
(Character(left), Character(right)) => {
let mut concatenated = DustString::new();
concatenated.push(*left);
concatenated.push(*right);
String(concatenated)
}
(Character(left), String(right)) => {
let mut concatenated = DustString::new();
concatenated.push(*left);
concatenated.push_str(right);
String(concatenated)
}
(Float(left), Float(right)) => {
let sum = left + right;
Float(sum)
}
(Integer(left), Integer(right)) => {
let sum = left.saturating_add(*right);
Integer(sum)
}
(String(left), Character(right)) => {
let concatenated = format!("{}{}", left, right);
String(DustString::from(concatenated))
}
(String(left), String(right)) => {
let concatenated = format!("{}{}", left, right);
String(DustString::from(concatenated))
}
_ => panic!(
"{}",
ValueError::CannotAdd(
Value::Concrete(self.clone()),
Value::Concrete(other.clone())
)
),
}
}
pub fn subtract(&self, other: &Self) -> ConcreteValue {
use ConcreteValue::*;
match (self, other) {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_sub(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left - right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_sub(*right)),
_ => panic!(
"{}",
ValueError::CannotSubtract(
Value::Concrete(self.clone()),
Value::Concrete(other.clone())
)
),
}
}
pub fn multiply(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let product = match (self, other) {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_mul(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left * right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_mul(*right)),
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
));
}
};
Ok(product)
}
pub fn divide(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let quotient = match (self, other) {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.saturating_div(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left / right),
(Integer(left), Integer(right)) => ConcreteValue::Integer(left.saturating_div(*right)),
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
));
}
};
Ok(quotient)
}
pub fn modulo(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let product = match (self, other) {
(Byte(left), Byte(right)) => ConcreteValue::Byte(left.wrapping_rem(*right)),
(Float(left), Float(right)) => ConcreteValue::Float(left % right),
(Integer(left), Integer(right)) => {
ConcreteValue::Integer(left.wrapping_rem_euclid(*right))
}
_ => {
return Err(ValueError::CannotMultiply(
self.clone().to_value(),
other.clone().to_value(),
));
}
};
Ok(product)
}
pub fn negate(&self) -> ConcreteValue {
use ConcreteValue::*;
match self {
Boolean(value) => ConcreteValue::Boolean(!value),
Byte(value) => ConcreteValue::Byte(value.wrapping_neg()),
Float(value) => ConcreteValue::Float(-value),
Integer(value) => ConcreteValue::Integer(value.wrapping_neg()),
_ => panic!("{}", ValueError::CannotNegate(self.clone().to_value())),
}
}
pub fn not(&self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let not = match self {
Boolean(value) => ConcreteValue::Boolean(!value),
_ => return Err(ValueError::CannotNot(self.clone().to_value())),
};
Ok(not)
}
pub fn equals(&self, other: &ConcreteValue) -> bool {
use ConcreteValue::*;
match (self, other) {
(Boolean(left), Boolean(right)) => left == right,
(Byte(left), Byte(right)) => left == right,
(Character(left), Character(right)) => left == right,
(Float(left), Float(right)) => left == right,
(Integer(left), Integer(right)) => left == right,
(List(left), List(right)) => left == right,
(Range(left), Range(right)) => left == right,
(String(left), String(right)) => left == right,
_ => {
panic!(
"{}",
ValueError::CannotCompare(
Value::Concrete(self.clone()),
Value::Concrete(other.clone())
)
)
}
}
}
pub fn less_than(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let less_than = match (self, other) {
(Boolean(left), Boolean(right)) => ConcreteValue::Boolean(left < right),
(Byte(left), Byte(right)) => ConcreteValue::Boolean(left < right),
(Character(left), Character(right)) => ConcreteValue::Boolean(left < right),
(Float(left), Float(right)) => ConcreteValue::Boolean(left < right),
(Integer(left), Integer(right)) => ConcreteValue::Boolean(left < right),
(List(left), List(right)) => ConcreteValue::Boolean(left < right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left < right),
(String(left), String(right)) => ConcreteValue::Boolean(left < right),
_ => {
return Err(ValueError::CannotCompare(
self.clone().to_value(),
other.clone().to_value(),
));
}
};
Ok(less_than)
}
pub fn less_than_or_equals(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*;
let less_than_or_equal = match (self, other) {
(Boolean(left), Boolean(right)) => ConcreteValue::Boolean(left <= right),
(Byte(left), Byte(right)) => ConcreteValue::Boolean(left <= right),
(Character(left), Character(right)) => ConcreteValue::Boolean(left <= right),
(Float(left), Float(right)) => ConcreteValue::Boolean(left <= right),
(Integer(left), Integer(right)) => ConcreteValue::Boolean(left <= right),
(List(left), List(right)) => ConcreteValue::Boolean(left <= right),
(Range(left), Range(right)) => ConcreteValue::Boolean(left <= right),
(String(left), String(right)) => ConcreteValue::Boolean(left <= right),
_ => {
return Err(ValueError::CannotCompare(
self.clone().to_value(),
other.clone().to_value(),
));
}
};
Ok(less_than_or_equal)
}
}
impl Clone for ConcreteValue {
@ -356,7 +134,10 @@ impl Clone for ConcreteValue {
ConcreteValue::Character(character) => ConcreteValue::Character(*character),
ConcreteValue::Float(float) => ConcreteValue::Float(*float),
ConcreteValue::Integer(integer) => ConcreteValue::Integer(*integer),
ConcreteValue::List(list) => ConcreteValue::List(list.clone()),
ConcreteValue::List { items, item_type } => ConcreteValue::List {
items: items.clone(),
item_type: *item_type,
},
ConcreteValue::Range(range) => ConcreteValue::Range(*range),
ConcreteValue::String(string) => ConcreteValue::String(string.clone()),
}
@ -379,10 +160,10 @@ impl Display for ConcreteValue {
Ok(())
}
ConcreteValue::Integer(integer) => write!(f, "{integer}"),
ConcreteValue::List(list) => {
ConcreteValue::List { items, .. } => {
write!(f, "[")?;
for (index, item) in list.iter().enumerate() {
for (index, item) in items.iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}

View File

@ -130,101 +130,6 @@ impl Value {
}
}
pub fn add(&self, other: &Value) -> Value {
let sum = match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => left.add(right),
_ => panic!("{}", ValueError::CannotAdd(self.clone(), other.clone())),
};
Value::Concrete(sum)
}
pub fn subtract(&self, other: &Value) -> Value {
let difference = match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => left.subtract(right),
_ => panic!(
"{}",
ValueError::CannotSubtract(self.clone(), other.clone())
),
};
Value::Concrete(difference)
}
pub fn multiply(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => {
left.multiply(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotMultiply(
self.to_owned(),
other.to_owned(),
)),
}
}
pub fn divide(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => {
left.divide(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())),
}
}
pub fn modulo(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => {
left.modulo(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
}
}
pub fn negate(&self) -> Value {
let concrete = match self {
Value::Concrete(concrete_value) => concrete_value.negate(),
_ => panic!("{}", ValueError::CannotNegate(self.clone())),
};
Value::Concrete(concrete)
}
pub fn not(&self) -> Result<Value, ValueError> {
match self {
Value::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete),
_ => Err(ValueError::CannotNot(self.to_owned())),
}
}
pub fn equals(&self, other: &Value) -> bool {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => left.equals(right),
_ => panic!(
"{}",
ValueError::CannotCompare(self.to_owned(), other.to_owned())
),
}
}
pub fn less(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => {
left.less_than(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
}
}
pub fn less_than_or_equals(&self, other: &Value) -> Result<Value, ValueError> {
match (self, other) {
(Value::Concrete(left), Value::Concrete(right)) => {
left.less_than_or_equals(right).map(Value::Concrete)
}
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
}
}
pub fn display(&self, data: &Thread) -> DustString {
match self {
Value::AbstractList(list) => list.display(data),

View File

@ -759,7 +759,7 @@ pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {
let result = left_value.saturating_mul(*right_value);
let register = Register::Value(result);
thread.set_integer_register(destination as usize, register);
thread.set_integer_register(destination, register);
}
_ => unimplemented!(),
}
@ -850,9 +850,18 @@ pub fn divide(instruction: InstructionFields, thread: &mut Thread) {
_ => unreachable!(),
}
}
pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {}
pub fn test(instruction: InstructionFields, thread: &mut Thread) {}
pub fn test(instruction: InstructionFields, thread: &mut Thread) {
let operand_register = instruction.b_field as usize;
let test_value = instruction.c_field != 0;
let operand_boolean = thread.get_boolean_register(operand_register);
if *operand_boolean == test_value {
thread.current_frame_mut().ip += 1;
}
}
pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {}
@ -976,16 +985,18 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
}
TypeCode::LIST => {
let abstract_list = thread.get_list_register(return_register).clone();
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
let mut items = Vec::with_capacity(abstract_list.item_pointers.len());
for pointer in &abstract_list.item_pointers {
let value = thread.get_value_from_pointer(pointer);
concrete_list.push(value);
items.push(value);
}
thread.return_value =
Some(Some(Value::Concrete(ConcreteValue::List(concrete_list))));
thread.return_value = Some(Some(Value::Concrete(ConcreteValue::List {
items,
item_type: abstract_list.item_type,
})));
}
_ => unimplemented!(),
}

View File

@ -119,15 +119,18 @@ impl Thread {
}
Pointer::RegisterList(register_index) => {
let abstract_list = self.get_list_register(*register_index).clone();
let mut concrete_list = Vec::with_capacity(abstract_list.item_pointers.len());
let mut items = Vec::with_capacity(abstract_list.item_pointers.len());
for pointer in &abstract_list.item_pointers {
let value = self.get_value_from_pointer(pointer);
concrete_list.push(value);
items.push(value);
}
ConcreteValue::List(concrete_list)
ConcreteValue::List {
items,
item_type: abstract_list.item_type,
}
}
Pointer::RegisterFunction(_) => unimplemented!(),
Pointer::ConstantCharacter(constant_index) => {

View File

@ -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(vec![
ConcreteValue::Boolean(true),
ConcreteValue::Boolean(false),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![ConcreteValue::Boolean(true), ConcreteValue::Boolean(false)],
item_type: TypeCode::BOOLEAN,
}));
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(vec![
ConcreteValue::Byte(0x2a),
ConcreteValue::Byte(0x42),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![ConcreteValue::Byte(0x2a), ConcreteValue::Byte(0x42)],
item_type: TypeCode::BYTE,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -194,10 +194,10 @@ fn load_character_list() {
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
..Chunk::default()
};
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
ConcreteValue::Character('a'),
ConcreteValue::Character('b'),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
item_type: TypeCode::CHARACTER,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -218,10 +218,10 @@ fn load_float_list() {
constants: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
..Chunk::default()
};
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
ConcreteValue::Float(42.42),
ConcreteValue::Float(24.24),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
item_type: TypeCode::FLOAT,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -247,11 +247,14 @@ fn load_integer_list() {
],
..Chunk::default()
};
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
ConcreteValue::Integer(1),
ConcreteValue::Integer(2),
ConcreteValue::Integer(3),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![
ConcreteValue::Integer(1),
ConcreteValue::Integer(2),
ConcreteValue::Integer(3),
],
item_type: TypeCode::INTEGER,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -275,10 +278,13 @@ fn load_string_list() {
],
..Chunk::default()
};
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
ConcreteValue::String(DustString::from("Hello")),
ConcreteValue::String(DustString::from("World")),
])));
let return_value = Some(Value::Concrete(ConcreteValue::List {
items: vec![
ConcreteValue::String(DustString::from("Hello")),
ConcreteValue::String(DustString::from("World")),
],
item_type: TypeCode::STRING,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -317,10 +323,19 @@ fn load_nested_list() {
],
..Chunk::default()
};
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)]),
])));
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,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());
@ -383,16 +398,37 @@ fn load_deeply_nested_list() {
],
..Chunk::default()
};
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)]),
]),
])));
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,
}));
assert_eq!(chunk, compile(source).unwrap());
assert_eq!(return_value, run(source).unwrap());