Refactor values to use register pointers for complex values
This commit is contained in:
parent
6e1ef77192
commit
9c612317dc
@ -526,7 +526,10 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
for (index, value_option) in self.chunk.constants.iter().enumerate() {
|
||||
let value_display = value_option
|
||||
.as_ref()
|
||||
.map(|value| value.to_string())
|
||||
.map(|value| match value {
|
||||
Value::Primitive(value_data) => value_data.to_string(),
|
||||
Value::Object(_) => "object".to_string(),
|
||||
})
|
||||
.unwrap_or("empty".to_string());
|
||||
let trucated_length = 8;
|
||||
let with_elipsis = trucated_length - 3;
|
||||
@ -540,35 +543,16 @@ impl<'a> ChunkDisassembler<'a> {
|
||||
|
||||
if let Some(function_disassembly) =
|
||||
value_option.as_ref().and_then(|value| match value {
|
||||
Value::Raw(value_data) => value_data.as_function().map(|function| {
|
||||
Value::Primitive(value_data) => value_data.as_function().map(|function| {
|
||||
function
|
||||
.body()
|
||||
.body
|
||||
.disassembler("function")
|
||||
.styled(self.styled)
|
||||
.indent(self.indent + 1)
|
||||
.width(self.width)
|
||||
.disassemble()
|
||||
}),
|
||||
Value::Reference(arc) => arc.as_function().map(|function| {
|
||||
function
|
||||
.body()
|
||||
.disassembler("function")
|
||||
.styled(self.styled)
|
||||
.indent(self.indent + 1)
|
||||
.width(self.width)
|
||||
.disassemble()
|
||||
}),
|
||||
Value::Mutable(rw_lock) => {
|
||||
rw_lock.read().unwrap().as_function().map(|function| {
|
||||
function
|
||||
.body()
|
||||
.disassembler("function")
|
||||
.styled(self.styled)
|
||||
.indent(self.indent + 1)
|
||||
.width(self.width)
|
||||
.disassemble()
|
||||
})
|
||||
}
|
||||
Value::Object(_) => None,
|
||||
})
|
||||
{
|
||||
push(&function_disassembly, false);
|
||||
|
@ -1,107 +0,0 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::{self, Display, Formatter},
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Identifier, Struct, StructType, TypeConflict, Value};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Constructor {
|
||||
pub struct_type: StructType,
|
||||
}
|
||||
|
||||
impl Constructor {
|
||||
pub fn construct_unit(&self) -> Result<Value, ConstructError> {
|
||||
if let StructType::Unit { name } = &self.struct_type {
|
||||
Ok(Value::r#struct(Struct::Unit { name: name.clone() }))
|
||||
} else {
|
||||
Err(ConstructError::ExpectedUnit)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_tuple(&self, fields: Vec<Value>) -> Result<Value, ConstructError> {
|
||||
if let StructType::Tuple {
|
||||
name: expected_name,
|
||||
fields: expected_fields,
|
||||
} = &self.struct_type
|
||||
{
|
||||
if fields.len() != expected_fields.len() {
|
||||
return Err(ConstructError::FieldCountMismatch);
|
||||
}
|
||||
|
||||
for (i, value) in fields.iter().enumerate() {
|
||||
let expected_type = expected_fields.get(i).unwrap();
|
||||
let actual_type = value.r#type();
|
||||
|
||||
expected_type.check(&actual_type)?;
|
||||
}
|
||||
|
||||
Ok(Value::r#struct(Struct::Tuple {
|
||||
name: expected_name.clone(),
|
||||
fields,
|
||||
}))
|
||||
} else {
|
||||
Err(ConstructError::ExpectedTuple)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn construct_fields(
|
||||
&self,
|
||||
fields: HashMap<Identifier, Value>,
|
||||
) -> Result<Value, ConstructError> {
|
||||
if let StructType::Fields {
|
||||
name: expected_name,
|
||||
fields: expected_fields,
|
||||
} = &self.struct_type
|
||||
{
|
||||
if fields.len() != expected_fields.len() {
|
||||
return Err(ConstructError::FieldCountMismatch);
|
||||
}
|
||||
|
||||
for (field_name, field_value) in fields.iter() {
|
||||
let expected_type = expected_fields.get(field_name).unwrap();
|
||||
let actual_type = field_value.r#type();
|
||||
|
||||
expected_type.check(&actual_type)?;
|
||||
}
|
||||
|
||||
Ok(Value::r#struct(Struct::Fields {
|
||||
name: expected_name.clone(),
|
||||
fields,
|
||||
}))
|
||||
} else {
|
||||
Err(ConstructError::ExpectedFields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ConstructError {
|
||||
FieldCountMismatch,
|
||||
ExpectedUnit,
|
||||
ExpectedTuple,
|
||||
ExpectedFields,
|
||||
TypeConflict(TypeConflict),
|
||||
}
|
||||
|
||||
impl From<TypeConflict> for ConstructError {
|
||||
fn from(conflict: TypeConflict) -> Self {
|
||||
Self::TypeConflict(conflict)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ConstructError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ConstructError::FieldCountMismatch => write!(f, "Field count mismatch"),
|
||||
ConstructError::ExpectedUnit => write!(f, "Expected unit struct"),
|
||||
ConstructError::ExpectedTuple => write!(f, "Expected tuple struct"),
|
||||
ConstructError::ExpectedFields => write!(f, "Expected fields struct"),
|
||||
ConstructError::TypeConflict(TypeConflict { expected, actual }) => {
|
||||
write!(f, "Type conflict: expected {}, got {}", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -394,7 +394,7 @@ impl Instruction {
|
||||
|
||||
let constant = if let Some(chunk) = chunk {
|
||||
match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||
Ok(constant) => constant.to_string(),
|
||||
Ok(value) => value.to_string(),
|
||||
Err(error) => format!("{error:?}"),
|
||||
}
|
||||
} else {
|
||||
|
@ -1,5 +1,4 @@
|
||||
mod chunk;
|
||||
mod constructor;
|
||||
mod dust_error;
|
||||
mod identifier;
|
||||
mod instruction;
|
||||
@ -14,7 +13,6 @@ mod vm;
|
||||
use std::fmt::Display;
|
||||
|
||||
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
||||
pub use constructor::Constructor;
|
||||
pub use dust_error::{AnnotatedError, DustError};
|
||||
pub use identifier::Identifier;
|
||||
pub use instruction::Instruction;
|
||||
@ -23,7 +21,7 @@ pub use operation::Operation;
|
||||
pub use parser::{parse, ParseError, Parser};
|
||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||
pub use token::{Token, TokenKind, TokenOwned};
|
||||
pub use value::{Enum, Function, Struct, Value, ValueError};
|
||||
pub use value::{Function, Value, ValueError};
|
||||
pub use vm::{run, Vm, VmError};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -17,7 +17,7 @@ use std::{
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{Constructor, Identifier};
|
||||
use crate::Identifier;
|
||||
|
||||
/// Description of a kind of value.
|
||||
///
|
||||
@ -488,12 +488,6 @@ impl StructType {
|
||||
StructType::Fields { name, .. } => name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn constructor(&self) -> Constructor {
|
||||
Constructor {
|
||||
struct_type: self.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for StructType {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
use std::mem::replace;
|
||||
|
||||
use crate::{
|
||||
parse, AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, Operation, Span,
|
||||
Value, ValueError,
|
||||
parse, value::Primitive, AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction,
|
||||
Operation, Span, Value, ValueError,
|
||||
};
|
||||
|
||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||
@ -116,20 +116,9 @@ impl Vm {
|
||||
let to_register = instruction.a();
|
||||
let first_register = instruction.b();
|
||||
let last_register = instruction.c();
|
||||
let length = last_register - first_register + 1;
|
||||
let mut list = Vec::with_capacity(length as usize);
|
||||
let value = Value::list(first_register, last_register);
|
||||
|
||||
for register_index in first_register..=last_register {
|
||||
let value = match self.take(register_index, to_register, position) {
|
||||
Ok(value) => value,
|
||||
Err(VmError::EmptyRegister { .. }) => continue,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
self.set(to_register, Value::list(list), position)?;
|
||||
self.set(to_register, value, position)?;
|
||||
}
|
||||
Operation::DefineLocal => {
|
||||
let from_register = instruction.a();
|
||||
@ -211,10 +200,14 @@ impl Vm {
|
||||
let register = instruction.a();
|
||||
let test_value = instruction.c_as_boolean();
|
||||
let value = self.get(register, position)?;
|
||||
let boolean = value.as_boolean().ok_or_else(|| VmError::ExpectedBoolean {
|
||||
let boolean = if let Value::Primitive(Primitive::Boolean(boolean)) = value {
|
||||
*boolean
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: value.clone(),
|
||||
position,
|
||||
})?;
|
||||
});
|
||||
};
|
||||
|
||||
if boolean != test_value {
|
||||
self.ip += 1;
|
||||
@ -226,12 +219,14 @@ impl Vm {
|
||||
let test_value = instruction.c_as_boolean();
|
||||
let borrowed_value = self.get(argument, position)?;
|
||||
let boolean =
|
||||
borrowed_value
|
||||
.as_boolean()
|
||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
||||
if let Value::Primitive(Primitive::Boolean(boolean)) = borrowed_value {
|
||||
*boolean
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: borrowed_value.clone(),
|
||||
position,
|
||||
})?;
|
||||
});
|
||||
};
|
||||
|
||||
if boolean == test_value {
|
||||
let value = self.take(argument, to_register, position)?;
|
||||
@ -248,15 +243,18 @@ impl Vm {
|
||||
);
|
||||
|
||||
let (left, right) = get_arguments(self, instruction, position)?;
|
||||
|
||||
let boolean = left
|
||||
let equal_result = left
|
||||
.equal(right)
|
||||
.map_err(|error| VmError::Value { error, position })?
|
||||
.as_boolean()
|
||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
||||
found: left.clone(),
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
let boolean =
|
||||
if let Value::Primitive(Primitive::Boolean(boolean)) = equal_result {
|
||||
boolean
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: equal_result.clone(),
|
||||
position,
|
||||
})?;
|
||||
});
|
||||
};
|
||||
let compare_to = instruction.a_as_boolean();
|
||||
|
||||
if boolean == compare_to {
|
||||
@ -281,14 +279,18 @@ impl Vm {
|
||||
);
|
||||
|
||||
let (left, right) = get_arguments(self, instruction, position)?;
|
||||
let boolean = left
|
||||
let less_result = left
|
||||
.less_than(right)
|
||||
.map_err(|error| VmError::Value { error, position })?
|
||||
.as_boolean()
|
||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
||||
found: left.clone(),
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
let boolean = if let Value::Primitive(Primitive::Boolean(boolean)) = less_result
|
||||
{
|
||||
boolean
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: less_result.clone(),
|
||||
position,
|
||||
})?;
|
||||
});
|
||||
};
|
||||
let compare_to = instruction.a_as_boolean();
|
||||
|
||||
if boolean == compare_to {
|
||||
@ -313,14 +315,19 @@ impl Vm {
|
||||
);
|
||||
|
||||
let (left, right) = get_arguments(self, instruction, position)?;
|
||||
let boolean = left
|
||||
let less_or_equal_result = left
|
||||
.less_than_or_equal(right)
|
||||
.map_err(|error| VmError::Value { error, position })?
|
||||
.as_boolean()
|
||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
||||
found: left.clone(),
|
||||
.map_err(|error| VmError::Value { error, position })?;
|
||||
let boolean = if let Value::Primitive(Primitive::Boolean(boolean)) =
|
||||
less_or_equal_result
|
||||
{
|
||||
boolean
|
||||
} else {
|
||||
return Err(VmError::ExpectedBoolean {
|
||||
found: less_or_equal_result.clone(),
|
||||
position,
|
||||
})?;
|
||||
});
|
||||
};
|
||||
let compare_to = instruction.a_as_boolean();
|
||||
|
||||
if boolean == compare_to {
|
||||
@ -457,7 +464,7 @@ impl Vm {
|
||||
})
|
||||
}
|
||||
|
||||
fn get(&self, index: u8, position: Span) -> Result<&Value, VmError> {
|
||||
pub fn get(&self, index: u8, position: Span) -> Result<&Value, VmError> {
|
||||
let index = index as usize;
|
||||
let register = self
|
||||
.stack
|
||||
|
@ -506,14 +506,7 @@ fn list() {
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(1),
|
||||
Value::integer(2),
|
||||
Value::integer(3)
|
||||
])))
|
||||
);
|
||||
assert_eq!(run(source), Ok(Some(Value::list(0, 2))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -553,13 +546,7 @@ fn list_with_complex_expression() {
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(1),
|
||||
Value::integer(-15)
|
||||
])))
|
||||
);
|
||||
assert_eq!(run(source), Ok(Some(Value::list(0, 3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -591,14 +578,7 @@ fn list_with_simple_expression() {
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
run(source),
|
||||
Ok(Some(Value::list(vec![
|
||||
Value::integer(1),
|
||||
Value::integer(5),
|
||||
Value::integer(4)
|
||||
])))
|
||||
);
|
||||
assert_eq!(run(source), Ok(Some(Value::list(0, 2))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user