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() {
|
for (index, value_option) in self.chunk.constants.iter().enumerate() {
|
||||||
let value_display = value_option
|
let value_display = value_option
|
||||||
.as_ref()
|
.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());
|
.unwrap_or("empty".to_string());
|
||||||
let trucated_length = 8;
|
let trucated_length = 8;
|
||||||
let with_elipsis = trucated_length - 3;
|
let with_elipsis = trucated_length - 3;
|
||||||
@ -540,35 +543,16 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
|
|
||||||
if let Some(function_disassembly) =
|
if let Some(function_disassembly) =
|
||||||
value_option.as_ref().and_then(|value| match value {
|
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
|
function
|
||||||
.body()
|
.body
|
||||||
.disassembler("function")
|
.disassembler("function")
|
||||||
.styled(self.styled)
|
.styled(self.styled)
|
||||||
.indent(self.indent + 1)
|
.indent(self.indent + 1)
|
||||||
.width(self.width)
|
.width(self.width)
|
||||||
.disassemble()
|
.disassemble()
|
||||||
}),
|
}),
|
||||||
Value::Reference(arc) => arc.as_function().map(|function| {
|
Value::Object(_) => None,
|
||||||
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()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
push(&function_disassembly, false);
|
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 {
|
let constant = if let Some(chunk) = chunk {
|
||||||
match chunk.get_constant(constant_index, Span(0, 0)) {
|
match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||||
Ok(constant) => constant.to_string(),
|
Ok(value) => value.to_string(),
|
||||||
Err(error) => format!("{error:?}"),
|
Err(error) => format!("{error:?}"),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
mod chunk;
|
mod chunk;
|
||||||
mod constructor;
|
|
||||||
mod dust_error;
|
mod dust_error;
|
||||||
mod identifier;
|
mod identifier;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
@ -14,7 +13,6 @@ mod vm;
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
pub use chunk::{Chunk, ChunkDisassembler, ChunkError, Local};
|
||||||
pub use constructor::Constructor;
|
|
||||||
pub use dust_error::{AnnotatedError, DustError};
|
pub use dust_error::{AnnotatedError, DustError};
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use instruction::Instruction;
|
pub use instruction::Instruction;
|
||||||
@ -23,7 +21,7 @@ pub use operation::Operation;
|
|||||||
pub use parser::{parse, ParseError, Parser};
|
pub use parser::{parse, ParseError, Parser};
|
||||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||||
pub use token::{Token, TokenKind, TokenOwned};
|
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};
|
pub use vm::{run, Vm, VmError};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -17,7 +17,7 @@ use std::{
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{Constructor, Identifier};
|
use crate::Identifier;
|
||||||
|
|
||||||
/// Description of a kind of value.
|
/// Description of a kind of value.
|
||||||
///
|
///
|
||||||
@ -488,12 +488,6 @@ impl StructType {
|
|||||||
StructType::Fields { name, .. } => name,
|
StructType::Fields { name, .. } => name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constructor(&self) -> Constructor {
|
|
||||||
Constructor {
|
|
||||||
struct_type: self.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for StructType {
|
impl Display for StructType {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
|||||||
use std::mem::replace;
|
use std::mem::replace;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parse, AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, Operation, Span,
|
parse, value::Primitive, AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction,
|
||||||
Value, ValueError,
|
Operation, Span, Value, ValueError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
||||||
@ -116,20 +116,9 @@ impl Vm {
|
|||||||
let to_register = instruction.a();
|
let to_register = instruction.a();
|
||||||
let first_register = instruction.b();
|
let first_register = instruction.b();
|
||||||
let last_register = instruction.c();
|
let last_register = instruction.c();
|
||||||
let length = last_register - first_register + 1;
|
let value = Value::list(first_register, last_register);
|
||||||
let mut list = Vec::with_capacity(length as usize);
|
|
||||||
|
|
||||||
for register_index in first_register..=last_register {
|
self.set(to_register, value, position)?;
|
||||||
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)?;
|
|
||||||
}
|
}
|
||||||
Operation::DefineLocal => {
|
Operation::DefineLocal => {
|
||||||
let from_register = instruction.a();
|
let from_register = instruction.a();
|
||||||
@ -211,10 +200,14 @@ impl Vm {
|
|||||||
let register = instruction.a();
|
let register = instruction.a();
|
||||||
let test_value = instruction.c_as_boolean();
|
let test_value = instruction.c_as_boolean();
|
||||||
let value = self.get(register, position)?;
|
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(),
|
found: value.clone(),
|
||||||
position,
|
position,
|
||||||
})?;
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if boolean != test_value {
|
if boolean != test_value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
@ -226,12 +219,14 @@ impl Vm {
|
|||||||
let test_value = instruction.c_as_boolean();
|
let test_value = instruction.c_as_boolean();
|
||||||
let borrowed_value = self.get(argument, position)?;
|
let borrowed_value = self.get(argument, position)?;
|
||||||
let boolean =
|
let boolean =
|
||||||
borrowed_value
|
if let Value::Primitive(Primitive::Boolean(boolean)) = borrowed_value {
|
||||||
.as_boolean()
|
*boolean
|
||||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
} else {
|
||||||
|
return Err(VmError::ExpectedBoolean {
|
||||||
found: borrowed_value.clone(),
|
found: borrowed_value.clone(),
|
||||||
position,
|
position,
|
||||||
})?;
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if boolean == test_value {
|
if boolean == test_value {
|
||||||
let value = self.take(argument, to_register, position)?;
|
let value = self.take(argument, to_register, position)?;
|
||||||
@ -248,15 +243,18 @@ impl Vm {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (left, right) = get_arguments(self, instruction, position)?;
|
let (left, right) = get_arguments(self, instruction, position)?;
|
||||||
|
let equal_result = left
|
||||||
let boolean = left
|
|
||||||
.equal(right)
|
.equal(right)
|
||||||
.map_err(|error| VmError::Value { error, position })?
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
.as_boolean()
|
let boolean =
|
||||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
if let Value::Primitive(Primitive::Boolean(boolean)) = equal_result {
|
||||||
found: left.clone(),
|
boolean
|
||||||
|
} else {
|
||||||
|
return Err(VmError::ExpectedBoolean {
|
||||||
|
found: equal_result.clone(),
|
||||||
position,
|
position,
|
||||||
})?;
|
});
|
||||||
|
};
|
||||||
let compare_to = instruction.a_as_boolean();
|
let compare_to = instruction.a_as_boolean();
|
||||||
|
|
||||||
if boolean == compare_to {
|
if boolean == compare_to {
|
||||||
@ -281,14 +279,18 @@ impl Vm {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (left, right) = get_arguments(self, instruction, position)?;
|
let (left, right) = get_arguments(self, instruction, position)?;
|
||||||
let boolean = left
|
let less_result = left
|
||||||
.less_than(right)
|
.less_than(right)
|
||||||
.map_err(|error| VmError::Value { error, position })?
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
.as_boolean()
|
let boolean = if let Value::Primitive(Primitive::Boolean(boolean)) = less_result
|
||||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
{
|
||||||
found: left.clone(),
|
boolean
|
||||||
|
} else {
|
||||||
|
return Err(VmError::ExpectedBoolean {
|
||||||
|
found: less_result.clone(),
|
||||||
position,
|
position,
|
||||||
})?;
|
});
|
||||||
|
};
|
||||||
let compare_to = instruction.a_as_boolean();
|
let compare_to = instruction.a_as_boolean();
|
||||||
|
|
||||||
if boolean == compare_to {
|
if boolean == compare_to {
|
||||||
@ -313,14 +315,19 @@ impl Vm {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let (left, right) = get_arguments(self, instruction, position)?;
|
let (left, right) = get_arguments(self, instruction, position)?;
|
||||||
let boolean = left
|
let less_or_equal_result = left
|
||||||
.less_than_or_equal(right)
|
.less_than_or_equal(right)
|
||||||
.map_err(|error| VmError::Value { error, position })?
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
.as_boolean()
|
let boolean = if let Value::Primitive(Primitive::Boolean(boolean)) =
|
||||||
.ok_or_else(|| VmError::ExpectedBoolean {
|
less_or_equal_result
|
||||||
found: left.clone(),
|
{
|
||||||
|
boolean
|
||||||
|
} else {
|
||||||
|
return Err(VmError::ExpectedBoolean {
|
||||||
|
found: less_or_equal_result.clone(),
|
||||||
position,
|
position,
|
||||||
})?;
|
});
|
||||||
|
};
|
||||||
let compare_to = instruction.a_as_boolean();
|
let compare_to = instruction.a_as_boolean();
|
||||||
|
|
||||||
if boolean == compare_to {
|
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 index = index as usize;
|
||||||
let register = self
|
let register = self
|
||||||
.stack
|
.stack
|
||||||
|
@ -506,14 +506,7 @@ fn list() {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(run(source), Ok(Some(Value::list(0, 2))));
|
||||||
run(source),
|
|
||||||
Ok(Some(Value::list(vec![
|
|
||||||
Value::integer(1),
|
|
||||||
Value::integer(2),
|
|
||||||
Value::integer(3)
|
|
||||||
])))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -553,13 +546,7 @@ fn list_with_complex_expression() {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(run(source), Ok(Some(Value::list(0, 3))));
|
||||||
run(source),
|
|
||||||
Ok(Some(Value::list(vec![
|
|
||||||
Value::integer(1),
|
|
||||||
Value::integer(-15)
|
|
||||||
])))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -591,14 +578,7 @@ fn list_with_simple_expression() {
|
|||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(run(source), Ok(Some(Value::list(0, 2))));
|
||||||
run(source),
|
|
||||||
Ok(Some(Value::list(vec![
|
|
||||||
Value::integer(1),
|
|
||||||
Value::integer(5),
|
|
||||||
Value::integer(4)
|
|
||||||
])))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user