Reimplement more instruction and compiler logic
This commit is contained in:
parent
07001a03e7
commit
3af1b64820
@ -1020,44 +1020,52 @@ impl<'src> Compiler<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_logical_binary(&mut self) -> Result<(), CompileError> {
|
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
|
self.instructions
|
||||||
.pop()
|
.pop()
|
||||||
.ok_or_else(|| CompileError::ExpectedExpression {
|
.ok_or_else(|| CompileError::ExpectedExpression {
|
||||||
found: self.previous_token.to_owned(),
|
found: self.previous_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.previous_position,
|
||||||
})?;
|
})?;
|
||||||
let operand_register = if last_instruction.operation() == Operation::POINT {
|
let operand_register = if left_instruction.operation() == Operation::POINT {
|
||||||
let Point { to, .. } = Point::from(last_instruction);
|
let Point { to, .. } = Point::from(left_instruction);
|
||||||
let local = self.get_local(to.index())?;
|
let local = self.get_local(to.index())?;
|
||||||
|
|
||||||
local.register_index
|
local.register_index
|
||||||
} else if last_instruction.yields_value() {
|
} else if left_instruction.yields_value() {
|
||||||
let register = last_instruction.a_field();
|
let register = left_instruction.a_field();
|
||||||
|
|
||||||
self.instructions
|
self.instructions
|
||||||
.push((last_instruction, last_type, last_position));
|
.push((left_instruction, left_type, left_position));
|
||||||
|
|
||||||
register
|
register
|
||||||
} else {
|
} else {
|
||||||
let register = match last_type {
|
return Err(CompileError::ExpectedExpression {
|
||||||
Type::Boolean => self.next_boolean_register() - 1,
|
found: self.previous_token.to_owned(),
|
||||||
Type::Byte => self.next_byte_register() - 1,
|
position: self.previous_position,
|
||||||
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
|
|
||||||
};
|
};
|
||||||
let operator = self.current_token;
|
|
||||||
let operator_position = self.current_position;
|
// TODO: Check if the left type is boolean
|
||||||
let rule = ParseRule::from(&operator);
|
|
||||||
|
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 {
|
let test_boolean = match operator {
|
||||||
Token::DoubleAmpersand => true,
|
Token::DoubleAmpersand => true,
|
||||||
Token::DoublePipe => false,
|
Token::DoublePipe => false,
|
||||||
@ -1074,8 +1082,8 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
self.emit_instruction(test, Type::None, operator_position);
|
self.emit_instruction(test, Type::None, operator_position);
|
||||||
self.emit_instruction(jump, Type::None, operator_position);
|
self.emit_instruction(jump, Type::None, operator_position);
|
||||||
self.advance()?;
|
self.instructions
|
||||||
self.parse_sub_expression(&rule.precedence)?;
|
.push((right_instruction, right_type, right_position));
|
||||||
|
|
||||||
let instructions_length = self.instructions.len();
|
let instructions_length = self.instructions.len();
|
||||||
|
|
||||||
@ -1571,7 +1579,7 @@ impl<'src> Compiler<'src> {
|
|||||||
|
|
||||||
fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> {
|
fn parse_call_native(&mut self, function: NativeFunction) -> Result<(), CompileError> {
|
||||||
let start = self.previous_position.0;
|
let start = self.previous_position.0;
|
||||||
let mut argument_count = 0;
|
let mut first_argument_index = None;
|
||||||
|
|
||||||
self.expect(Token::LeftParenthesis)?;
|
self.expect(Token::LeftParenthesis)?;
|
||||||
|
|
||||||
@ -1579,7 +1587,9 @@ impl<'src> Compiler<'src> {
|
|||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
self.allow(Token::Comma)?;
|
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;
|
let end = self.previous_position.1;
|
||||||
@ -1594,11 +1604,8 @@ impl<'src> Compiler<'src> {
|
|||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
let return_type = *function.r#type().return_type;
|
let return_type = *function.r#type().return_type;
|
||||||
let call_native = Instruction::from(CallNative {
|
let call_native =
|
||||||
destination,
|
Instruction::call_native(destination, function, first_argument_index.unwrap_or(0));
|
||||||
function,
|
|
||||||
argument_count,
|
|
||||||
});
|
|
||||||
|
|
||||||
self.emit_instruction(call_native, return_type, Span(start, end));
|
self.emit_instruction(call_native, return_type, Span(start, end));
|
||||||
|
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::{Instruction, NativeFunction, Operation};
|
use crate::{Instruction, NativeFunction, Operation, Type};
|
||||||
|
|
||||||
use super::InstructionFields;
|
use super::InstructionFields;
|
||||||
|
|
||||||
pub struct CallNative {
|
pub struct CallNative {
|
||||||
pub destination: u16,
|
pub destination: u16,
|
||||||
pub function: NativeFunction,
|
pub function: NativeFunction,
|
||||||
pub argument_count: u16,
|
pub first_argument_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Instruction> for CallNative {
|
impl From<Instruction> for CallNative {
|
||||||
fn from(instruction: Instruction) -> Self {
|
fn from(instruction: Instruction) -> Self {
|
||||||
let destination = instruction.a_field();
|
let destination = instruction.a_field();
|
||||||
let function = NativeFunction::from(instruction.b_field());
|
let function = NativeFunction::from(instruction.b_field());
|
||||||
|
let first_argument_index = instruction.c_field();
|
||||||
|
|
||||||
CallNative {
|
CallNative {
|
||||||
destination,
|
destination,
|
||||||
function,
|
function,
|
||||||
argument_count: instruction.c_field(),
|
first_argument_index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,7 +29,7 @@ impl From<CallNative> for Instruction {
|
|||||||
let operation = Operation::CALL_NATIVE;
|
let operation = Operation::CALL_NATIVE;
|
||||||
let a_field = call_native.destination;
|
let a_field = call_native.destination;
|
||||||
let b_field = call_native.function as u16;
|
let b_field = call_native.function as u16;
|
||||||
let c_field = call_native.argument_count;
|
let c_field = call_native.first_argument_index;
|
||||||
|
|
||||||
InstructionFields {
|
InstructionFields {
|
||||||
operation,
|
operation,
|
||||||
@ -46,21 +47,57 @@ impl Display for CallNative {
|
|||||||
let CallNative {
|
let CallNative {
|
||||||
destination,
|
destination,
|
||||||
function,
|
function,
|
||||||
argument_count,
|
first_argument_index,
|
||||||
} = self;
|
} = self;
|
||||||
let arguments_start = destination.saturating_sub(*argument_count);
|
let argument_count = function.r#type().value_parameters.len() as u16;
|
||||||
let arguments_end = arguments_start + argument_count;
|
|
||||||
|
|
||||||
if function.returns_value() {
|
if function.returns_value() {
|
||||||
write!(f, "R{destination} = ")?;
|
write!(f, "R{destination} = ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write!(f, "{function}")?;
|
||||||
|
|
||||||
match argument_count {
|
match argument_count {
|
||||||
0 => {
|
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})"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,12 +556,12 @@ impl Instruction {
|
|||||||
pub fn call_native(
|
pub fn call_native(
|
||||||
destination: u16,
|
destination: u16,
|
||||||
function: NativeFunction,
|
function: NativeFunction,
|
||||||
argument_count: u16,
|
first_argument_index: u16,
|
||||||
) -> Instruction {
|
) -> Instruction {
|
||||||
Instruction::from(CallNative {
|
Instruction::from(CallNative {
|
||||||
destination,
|
destination,
|
||||||
function,
|
function,
|
||||||
argument_count,
|
first_argument_index,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,6 @@ impl Display for Test {
|
|||||||
} = self;
|
} = self;
|
||||||
let bang = if *test_value { "" } else { "!" };
|
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 }}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,13 +143,13 @@ define_native_function! {
|
|||||||
// (ToByte, 5_u8, "to_byte", true),
|
// (ToByte, 5_u8, "to_byte", true),
|
||||||
// (ToFloat, 6_u8, "to_float", true),
|
// (ToFloat, 6_u8, "to_float", true),
|
||||||
// (ToInteger, 7_u8, "to_integer", true),
|
// (ToInteger, 7_u8, "to_integer", true),
|
||||||
(
|
// (
|
||||||
ToString,
|
// ToString,
|
||||||
8,
|
// 8,
|
||||||
"to_string",
|
// "to_string",
|
||||||
FunctionType::new([], [Type::Any], Type::String),
|
// FunctionType::new([], [Type::Any], Type::String),
|
||||||
string::to_string
|
// string::to_string
|
||||||
),
|
// ),
|
||||||
|
|
||||||
// // List and string
|
// // List and string
|
||||||
// (All, 9_u8, "all", true),
|
// (All, 9_u8, "all", true),
|
||||||
@ -216,7 +216,7 @@ define_native_function! {
|
|||||||
Write,
|
Write,
|
||||||
55,
|
55,
|
||||||
"write",
|
"write",
|
||||||
FunctionType::new([], [Type::Any], Type::None),
|
FunctionType::new([], [Type::String], Type::None),
|
||||||
io::write
|
io::write
|
||||||
),
|
),
|
||||||
// (WriteFile, 56_u8, "write_file", false),
|
// (WriteFile, 56_u8, "write_file", false),
|
||||||
@ -224,7 +224,7 @@ define_native_function! {
|
|||||||
WriteLine,
|
WriteLine,
|
||||||
57,
|
57,
|
||||||
"write_line",
|
"write_line",
|
||||||
FunctionType::new([], [Type::Any], Type::None),
|
FunctionType::new([], [Type::String], Type::None),
|
||||||
io::write_line
|
io::write_line
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ define_native_function! {
|
|||||||
Spawn,
|
Spawn,
|
||||||
60,
|
60,
|
||||||
"spawn",
|
"spawn",
|
||||||
FunctionType::new([], [ Type::function([], [], Type::Any)], Type::None),
|
FunctionType::new([], [ Type::function([], [], Type::None)], Type::None),
|
||||||
thread::spawn
|
thread::spawn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ use crate::instruction::TypeCode;
|
|||||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(tag = "Type", content = "Value")]
|
#[serde(tag = "Type", content = "Value")]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
Any,
|
|
||||||
Boolean,
|
Boolean,
|
||||||
Byte,
|
Byte,
|
||||||
Character,
|
Character,
|
||||||
@ -77,9 +76,7 @@ impl Type {
|
|||||||
/// Checks that the type is compatible with another type.
|
/// Checks that the type is compatible with another type.
|
||||||
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
|
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
|
||||||
match (self.concrete_type(), other.concrete_type()) {
|
match (self.concrete_type(), other.concrete_type()) {
|
||||||
(Type::Any, _)
|
(Type::Boolean, Type::Boolean)
|
||||||
| (_, Type::Any)
|
|
||||||
| (Type::Boolean, Type::Boolean)
|
|
||||||
| (Type::Byte, Type::Byte)
|
| (Type::Byte, Type::Byte)
|
||||||
| (Type::Character, Type::Character)
|
| (Type::Character, Type::Character)
|
||||||
| (Type::Float, Type::Float)
|
| (Type::Float, Type::Float)
|
||||||
@ -171,7 +168,6 @@ impl Type {
|
|||||||
impl Display for Type {
|
impl Display for Type {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Type::Any => write!(f, "any"),
|
|
||||||
Type::Boolean => write!(f, "bool"),
|
Type::Boolean => write!(f, "bool"),
|
||||||
Type::Byte => write!(f, "byte"),
|
Type::Byte => write!(f, "byte"),
|
||||||
Type::Character => write!(f, "char"),
|
Type::Character => write!(f, "char"),
|
||||||
@ -235,8 +231,6 @@ impl PartialOrd for Type {
|
|||||||
impl Ord for Type {
|
impl Ord for Type {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Type::Any, Type::Any) => Ordering::Equal,
|
|
||||||
(Type::Any, _) => Ordering::Greater,
|
|
||||||
(Type::Boolean, Type::Boolean) => Ordering::Equal,
|
(Type::Boolean, Type::Boolean) => Ordering::Equal,
|
||||||
(Type::Boolean, _) => Ordering::Greater,
|
(Type::Boolean, _) => Ordering::Greater,
|
||||||
(Type::Byte, Type::Byte) => Ordering::Equal,
|
(Type::Byte, Type::Byte) => Ordering::Equal,
|
||||||
|
@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use smartstring::{LazyCompact, SmartString};
|
use smartstring::{LazyCompact, SmartString};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{Type, Value, ValueError};
|
use crate::{Type, Value, ValueError, instruction::TypeCode};
|
||||||
|
|
||||||
use super::RangeValue;
|
use super::RangeValue;
|
||||||
|
|
||||||
@ -18,7 +18,10 @@ pub enum ConcreteValue {
|
|||||||
Character(char),
|
Character(char),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<ConcreteValue>),
|
List {
|
||||||
|
items: Vec<ConcreteValue>,
|
||||||
|
item_type: TypeCode,
|
||||||
|
},
|
||||||
Range(RangeValue),
|
Range(RangeValue),
|
||||||
String(DustString),
|
String(DustString),
|
||||||
}
|
}
|
||||||
@ -28,8 +31,11 @@ impl ConcreteValue {
|
|||||||
Value::Concrete(self)
|
Value::Concrete(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
|
pub fn list<T: Into<Vec<ConcreteValue>>>(into_items: T, type_code: TypeCode) -> Self {
|
||||||
ConcreteValue::List(into_list.into())
|
ConcreteValue::List {
|
||||||
|
items: into_items.into(),
|
||||||
|
item_type: type_code,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn string<T: Into<SmartString<LazyCompact>>>(to_string: T) -> Self {
|
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>> {
|
pub fn as_list(&self) -> Option<&Vec<ConcreteValue>> {
|
||||||
if let ConcreteValue::List(list) = self {
|
if let ConcreteValue::List { items, .. } = self {
|
||||||
Some(list)
|
Some(items)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -111,239 +117,11 @@ impl ConcreteValue {
|
|||||||
ConcreteValue::Character(_) => Type::Character,
|
ConcreteValue::Character(_) => Type::Character,
|
||||||
ConcreteValue::Float(_) => Type::Float,
|
ConcreteValue::Float(_) => Type::Float,
|
||||||
ConcreteValue::Integer(_) => Type::Integer,
|
ConcreteValue::Integer(_) => Type::Integer,
|
||||||
ConcreteValue::List(list) => {
|
ConcreteValue::List { item_type, .. } => Type::List(*item_type),
|
||||||
let item_type = list
|
|
||||||
.first()
|
|
||||||
.map_or(Type::Any, |item| item.r#type())
|
|
||||||
.type_code();
|
|
||||||
|
|
||||||
Type::List(item_type)
|
|
||||||
}
|
|
||||||
ConcreteValue::Range(range) => range.r#type(),
|
ConcreteValue::Range(range) => range.r#type(),
|
||||||
ConcreteValue::String(_) => Type::String,
|
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 {
|
impl Clone for ConcreteValue {
|
||||||
@ -356,7 +134,10 @@ impl Clone for ConcreteValue {
|
|||||||
ConcreteValue::Character(character) => ConcreteValue::Character(*character),
|
ConcreteValue::Character(character) => ConcreteValue::Character(*character),
|
||||||
ConcreteValue::Float(float) => ConcreteValue::Float(*float),
|
ConcreteValue::Float(float) => ConcreteValue::Float(*float),
|
||||||
ConcreteValue::Integer(integer) => ConcreteValue::Integer(*integer),
|
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::Range(range) => ConcreteValue::Range(*range),
|
||||||
ConcreteValue::String(string) => ConcreteValue::String(string.clone()),
|
ConcreteValue::String(string) => ConcreteValue::String(string.clone()),
|
||||||
}
|
}
|
||||||
@ -379,10 +160,10 @@ impl Display for ConcreteValue {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
ConcreteValue::Integer(integer) => write!(f, "{integer}"),
|
ConcreteValue::Integer(integer) => write!(f, "{integer}"),
|
||||||
ConcreteValue::List(list) => {
|
ConcreteValue::List { items, .. } => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
|
|
||||||
for (index, item) in list.iter().enumerate() {
|
for (index, item) in items.iter().enumerate() {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
pub fn display(&self, data: &Thread) -> DustString {
|
||||||
match self {
|
match self {
|
||||||
Value::AbstractList(list) => list.display(data),
|
Value::AbstractList(list) => list.display(data),
|
||||||
|
@ -759,7 +759,7 @@ pub fn multiply(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
let result = left_value.saturating_mul(*right_value);
|
let result = left_value.saturating_mul(*right_value);
|
||||||
let register = Register::Value(result);
|
let register = Register::Value(result);
|
||||||
|
|
||||||
thread.set_integer_register(destination as usize, register);
|
thread.set_integer_register(destination, register);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
@ -850,9 +850,18 @@ pub fn divide(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn modulo(instruction: InstructionFields, thread: &mut Thread) {}
|
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) {}
|
pub fn test_set(instruction: InstructionFields, thread: &mut Thread) {}
|
||||||
|
|
||||||
@ -976,16 +985,18 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) {
|
|||||||
}
|
}
|
||||||
TypeCode::LIST => {
|
TypeCode::LIST => {
|
||||||
let abstract_list = thread.get_list_register(return_register).clone();
|
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 {
|
for pointer in &abstract_list.item_pointers {
|
||||||
let value = thread.get_value_from_pointer(pointer);
|
let value = thread.get_value_from_pointer(pointer);
|
||||||
|
|
||||||
concrete_list.push(value);
|
items.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread.return_value =
|
thread.return_value = Some(Some(Value::Concrete(ConcreteValue::List {
|
||||||
Some(Some(Value::Concrete(ConcreteValue::List(concrete_list))));
|
items,
|
||||||
|
item_type: abstract_list.item_type,
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
@ -119,15 +119,18 @@ impl Thread {
|
|||||||
}
|
}
|
||||||
Pointer::RegisterList(register_index) => {
|
Pointer::RegisterList(register_index) => {
|
||||||
let abstract_list = self.get_list_register(*register_index).clone();
|
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 {
|
for pointer in &abstract_list.item_pointers {
|
||||||
let value = self.get_value_from_pointer(pointer);
|
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::RegisterFunction(_) => unimplemented!(),
|
||||||
Pointer::ConstantCharacter(constant_index) => {
|
Pointer::ConstantCharacter(constant_index) => {
|
||||||
|
@ -147,10 +147,10 @@ fn load_boolean_list() {
|
|||||||
positions: vec![Span(1, 5), Span(7, 12), Span(0, 13), Span(13, 13)],
|
positions: vec![Span(1, 5), Span(7, 12), Span(0, 13), Span(13, 13)],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::Boolean(true),
|
items: vec![ConcreteValue::Boolean(true), ConcreteValue::Boolean(false)],
|
||||||
ConcreteValue::Boolean(false),
|
item_type: TypeCode::BOOLEAN,
|
||||||
])));
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(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)],
|
positions: vec![Span(1, 5), Span(7, 11), Span(0, 12), Span(12, 12)],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::Byte(0x2a),
|
items: vec![ConcreteValue::Byte(0x2a), ConcreteValue::Byte(0x42)],
|
||||||
ConcreteValue::Byte(0x42),
|
item_type: TypeCode::BYTE,
|
||||||
])));
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(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')],
|
constants: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::Character('a'),
|
items: vec![ConcreteValue::Character('a'), ConcreteValue::Character('b')],
|
||||||
ConcreteValue::Character('b'),
|
item_type: TypeCode::CHARACTER,
|
||||||
])));
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(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)],
|
constants: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::Float(42.42),
|
items: vec![ConcreteValue::Float(42.42), ConcreteValue::Float(24.24)],
|
||||||
ConcreteValue::Float(24.24),
|
item_type: TypeCode::FLOAT,
|
||||||
])));
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(source).unwrap());
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
@ -247,11 +247,14 @@ fn load_integer_list() {
|
|||||||
],
|
],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::Integer(1),
|
items: vec![
|
||||||
ConcreteValue::Integer(2),
|
ConcreteValue::Integer(1),
|
||||||
ConcreteValue::Integer(3),
|
ConcreteValue::Integer(2),
|
||||||
])));
|
ConcreteValue::Integer(3),
|
||||||
|
],
|
||||||
|
item_type: TypeCode::INTEGER,
|
||||||
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(source).unwrap());
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
@ -275,10 +278,13 @@ fn load_string_list() {
|
|||||||
],
|
],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::String(DustString::from("Hello")),
|
items: vec![
|
||||||
ConcreteValue::String(DustString::from("World")),
|
ConcreteValue::String(DustString::from("Hello")),
|
||||||
])));
|
ConcreteValue::String(DustString::from("World")),
|
||||||
|
],
|
||||||
|
item_type: TypeCode::STRING,
|
||||||
|
}));
|
||||||
|
|
||||||
assert_eq!(chunk, compile(source).unwrap());
|
assert_eq!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(source).unwrap());
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
@ -317,10 +323,19 @@ fn load_nested_list() {
|
|||||||
],
|
],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
items: vec![
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
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!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(source).unwrap());
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
@ -383,16 +398,37 @@ fn load_deeply_nested_list() {
|
|||||||
],
|
],
|
||||||
..Chunk::default()
|
..Chunk::default()
|
||||||
};
|
};
|
||||||
let return_value = Some(Value::Concrete(ConcreteValue::List(vec![
|
let return_value = Some(Value::Concrete(ConcreteValue::List {
|
||||||
ConcreteValue::List(vec![
|
items: vec![
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)]),
|
ConcreteValue::List {
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(3), ConcreteValue::Integer(4)]),
|
items: vec![
|
||||||
]),
|
ConcreteValue::List {
|
||||||
ConcreteValue::List(vec![
|
items: vec![ConcreteValue::Integer(1), ConcreteValue::Integer(2)],
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(5), ConcreteValue::Integer(6)]),
|
item_type: TypeCode::INTEGER,
|
||||||
ConcreteValue::List(vec![ConcreteValue::Integer(7), ConcreteValue::Integer(8)]),
|
},
|
||||||
]),
|
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!(chunk, compile(source).unwrap());
|
||||||
assert_eq!(return_value, run(source).unwrap());
|
assert_eq!(return_value, run(source).unwrap());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user