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> {
|
||||
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));
|
||||
|
||||
|
@ -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})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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 }}")
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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, ", ")?;
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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!(),
|
||||
}
|
||||
|
@ -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) => {
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user