Experiment with instruction optimization
This commit is contained in:
parent
6ff25a22ec
commit
78c9ed97e2
@ -6,64 +6,68 @@ use crate::{AnnotatedError, Identifier, Instruction, Span, Value};
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
code: Vec<(Instruction, Span)>,
|
instructions: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Option<Value>>,
|
constants: Vec<Option<Value>>,
|
||||||
identifiers: Vec<Local>,
|
locals: Vec<Local>,
|
||||||
scope_depth: usize,
|
scope_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
code: Vec::new(),
|
instructions: Vec::new(),
|
||||||
constants: Vec::new(),
|
constants: Vec::new(),
|
||||||
identifiers: Vec::new(),
|
locals: Vec::new(),
|
||||||
scope_depth: 0,
|
scope_depth: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_data(
|
pub fn with_data(
|
||||||
code: Vec<(Instruction, Span)>,
|
instructions: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Value>,
|
constants: Vec<Value>,
|
||||||
identifiers: Vec<Local>,
|
identifiers: Vec<Local>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
code,
|
instructions,
|
||||||
constants: constants.into_iter().map(Some).collect(),
|
constants: constants.into_iter().map(Some).collect(),
|
||||||
identifiers,
|
locals: identifiers,
|
||||||
scope_depth: 0,
|
scope_depth: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.code.len()
|
self.instructions.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.code.is_empty()
|
self.instructions.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scope_depth(&self) -> usize {
|
pub fn scope_depth(&self) -> usize {
|
||||||
self.scope_depth
|
self.scope_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_code(
|
pub fn get_instruction(
|
||||||
&self,
|
&self,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<&(Instruction, Span), ChunkError> {
|
) -> Result<&(Instruction, Span), ChunkError> {
|
||||||
self.code
|
self.instructions
|
||||||
.get(offset)
|
.get(offset)
|
||||||
.ok_or(ChunkError::CodeIndexOfBounds { offset, position })
|
.ok_or(ChunkError::CodeIndexOfBounds { offset, position })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_code(&mut self, instruction: Instruction, position: Span) {
|
pub fn push_instruction(&mut self, instruction: Instruction, position: Span) {
|
||||||
self.code.push((instruction, position));
|
self.instructions.push((instruction, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_constant(&self, index: u16, position: Span) -> Result<&Value, ChunkError> {
|
pub fn pop_instruction(&mut self) -> Option<(Instruction, Span)> {
|
||||||
|
self.instructions.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_constant(&self, index: usize, position: Span) -> Result<&Value, ChunkError> {
|
||||||
self.constants
|
self.constants
|
||||||
.get(index as usize)
|
.get(index)
|
||||||
.ok_or(ChunkError::ConstantIndexOutOfBounds { index, position })
|
.ok_or(ChunkError::ConstantIndexOutOfBounds { index, position })
|
||||||
.and_then(|value| {
|
.and_then(|value| {
|
||||||
value
|
value
|
||||||
@ -72,9 +76,9 @@ impl Chunk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_constant(&mut self, index: u16, position: Span) -> Result<Value, ChunkError> {
|
pub fn use_constant(&mut self, index: usize, position: Span) -> Result<Value, ChunkError> {
|
||||||
self.constants
|
self.constants
|
||||||
.get_mut(index as usize)
|
.get_mut(index)
|
||||||
.ok_or_else(|| ChunkError::ConstantIndexOutOfBounds { index, position })?
|
.ok_or_else(|| ChunkError::ConstantIndexOutOfBounds { index, position })?
|
||||||
.take()
|
.take()
|
||||||
.ok_or(ChunkError::ConstantAlreadyUsed { index, position })
|
.ok_or(ChunkError::ConstantAlreadyUsed { index, position })
|
||||||
@ -93,31 +97,31 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains_identifier(&self, identifier: &Identifier) -> bool {
|
pub fn contains_identifier(&self, identifier: &Identifier) -> bool {
|
||||||
self.identifiers
|
self.locals
|
||||||
.iter()
|
.iter()
|
||||||
.any(|local| &local.identifier == identifier)
|
.any(|local| &local.identifier == identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_local(&self, index: u16, position: Span) -> Result<&Local, ChunkError> {
|
pub fn get_local(&self, index: usize, position: Span) -> Result<&Local, ChunkError> {
|
||||||
self.identifiers
|
self.locals
|
||||||
.get(index as usize)
|
.get(index as usize)
|
||||||
.ok_or(ChunkError::IdentifierIndexOutOfBounds { index, position })
|
.ok_or(ChunkError::LocalIndexOutOfBounds { index, position })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_identifier(&self, index: u8) -> Option<&Identifier> {
|
pub fn get_identifier(&self, index: u8) -> Option<&Identifier> {
|
||||||
if let Some(local) = self.identifiers.get(index as usize) {
|
if let Some(local) = self.locals.get(index as usize) {
|
||||||
Some(&local.identifier)
|
Some(&local.identifier)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_identifier_index(
|
pub fn get_local_index(
|
||||||
&self,
|
&self,
|
||||||
identifier: &Identifier,
|
identifier: &Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u16, ChunkError> {
|
) -> Result<u16, ChunkError> {
|
||||||
self.identifiers
|
self.locals
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
@ -134,25 +138,39 @@ impl Chunk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn declare_variable(
|
pub fn declare_local(
|
||||||
&mut self,
|
&mut self,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u16, ChunkError> {
|
) -> Result<u16, ChunkError> {
|
||||||
let starting_length = self.identifiers.len();
|
let starting_length = self.locals.len();
|
||||||
|
|
||||||
if starting_length + 1 > (u8::MAX as usize) {
|
if starting_length + 1 > (u8::MAX as usize) {
|
||||||
Err(ChunkError::IdentifierOverflow { position })
|
Err(ChunkError::IdentifierOverflow { position })
|
||||||
} else {
|
} else {
|
||||||
self.identifiers.push(Local {
|
self.locals
|
||||||
identifier,
|
.push(Local::new(identifier, self.scope_depth, None));
|
||||||
depth: self.scope_depth,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(starting_length as u16)
|
Ok(starting_length as u16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn define_local(
|
||||||
|
&mut self,
|
||||||
|
index: usize,
|
||||||
|
value: Value,
|
||||||
|
position: Span,
|
||||||
|
) -> Result<(), ChunkError> {
|
||||||
|
let local = self
|
||||||
|
.locals
|
||||||
|
.get_mut(index)
|
||||||
|
.ok_or_else(|| ChunkError::LocalIndexOutOfBounds { index, position })?;
|
||||||
|
|
||||||
|
local.value = Some(value);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn begin_scope(&mut self) {
|
pub fn begin_scope(&mut self) {
|
||||||
self.scope_depth += 1;
|
self.scope_depth += 1;
|
||||||
}
|
}
|
||||||
@ -162,17 +180,17 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.code.clear();
|
self.instructions.clear();
|
||||||
self.constants.clear();
|
self.constants.clear();
|
||||||
self.identifiers.clear();
|
self.locals.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn identifiers(&self) -> &[Local] {
|
pub fn identifiers(&self) -> &[Local] {
|
||||||
&self.identifiers
|
&self.locals
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop_identifier(&mut self) -> Option<Local> {
|
pub fn pop_identifier(&mut self) -> Option<Local> {
|
||||||
self.identifiers.pop()
|
self.locals.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self, name: &str) -> String {
|
pub fn disassemble(&self, name: &str) -> String {
|
||||||
@ -186,13 +204,13 @@ impl Chunk {
|
|||||||
output.push_str(&format!("{name_buffer}{name}{name_buffer}\n"));
|
output.push_str(&format!("{name_buffer}{name}{name_buffer}\n"));
|
||||||
output.push_str(&format!("{name_buffer}{underline}{name_buffer}\n",));
|
output.push_str(&format!("{name_buffer}{underline}{name_buffer}\n",));
|
||||||
output.push_str(" Code \n");
|
output.push_str(" Code \n");
|
||||||
output.push_str("------ ---------------- ------------------ --------\n");
|
output.push_str("------ ---------------- -------------------- --------\n");
|
||||||
output.push_str("OFFSET INSTRUCTION INFO POSITION\n");
|
output.push_str("OFFSET INSTRUCTION INFO POSITION\n");
|
||||||
output.push_str("------ ---------------- ------------------ --------\n");
|
output.push_str("------ ---------------- -------------------- --------\n");
|
||||||
|
|
||||||
for (offset, (instruction, position)) in self.code.iter().enumerate() {
|
for (offset, (instruction, position)) in self.instructions.iter().enumerate() {
|
||||||
let display = format!(
|
let display = format!(
|
||||||
"{offset:^6} {:35} {position}\n",
|
"{offset:^6} {:37} {position}\n",
|
||||||
instruction.disassemble(self)
|
instruction.disassemble(self)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -220,13 +238,29 @@ impl Chunk {
|
|||||||
output.push_str(&display);
|
output.push_str(&display);
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push_str("\n Identifiers\n");
|
output.push_str("\n Locals\n");
|
||||||
output.push_str("----- ---------- -----\n");
|
output.push_str("----- ---------- ----- -----\n");
|
||||||
output.push_str("INDEX NAME DEPTH\n");
|
output.push_str("INDEX NAME DEPTH VALUE\n");
|
||||||
output.push_str("----- ---------- -----\n");
|
output.push_str("----- ---------- ----- -----\n");
|
||||||
|
|
||||||
for (index, Local { identifier, depth }) in self.identifiers.iter().enumerate() {
|
for (
|
||||||
let display = format!("{index:3} {:10} {depth}\n", identifier.as_str());
|
index,
|
||||||
|
Local {
|
||||||
|
identifier,
|
||||||
|
depth,
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
) in self.locals.iter().enumerate()
|
||||||
|
{
|
||||||
|
let value_display = value
|
||||||
|
.as_ref()
|
||||||
|
.map(|value| value.to_string())
|
||||||
|
.unwrap_or_else(|| "EMPTY".to_string());
|
||||||
|
|
||||||
|
let display = format!(
|
||||||
|
"{index:3} {:10} {depth:<5} {value_display}\n",
|
||||||
|
identifier.as_str()
|
||||||
|
);
|
||||||
output.push_str(&display);
|
output.push_str(&display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,9 +290,9 @@ impl Eq for Chunk {}
|
|||||||
|
|
||||||
impl PartialEq for Chunk {
|
impl PartialEq for Chunk {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.code == other.code
|
self.instructions == other.instructions
|
||||||
&& self.constants == other.constants
|
&& self.constants == other.constants
|
||||||
&& self.identifiers == other.identifiers
|
&& self.locals == other.locals
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,11 +300,16 @@ impl PartialEq for Chunk {
|
|||||||
pub struct Local {
|
pub struct Local {
|
||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
|
pub value: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Local {
|
impl Local {
|
||||||
pub fn new(identifier: Identifier, depth: usize) -> Self {
|
pub fn new(identifier: Identifier, depth: usize, value: Option<Value>) -> Self {
|
||||||
Self { identifier, depth }
|
Self {
|
||||||
|
identifier,
|
||||||
|
depth,
|
||||||
|
value,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,18 +320,18 @@ pub enum ChunkError {
|
|||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantAlreadyUsed {
|
ConstantAlreadyUsed {
|
||||||
index: u16,
|
index: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantOverflow {
|
ConstantOverflow {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantIndexOutOfBounds {
|
ConstantIndexOutOfBounds {
|
||||||
index: u16,
|
index: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierIndexOutOfBounds {
|
LocalIndexOutOfBounds {
|
||||||
index: u16,
|
index: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierOverflow {
|
IdentifierOverflow {
|
||||||
@ -315,7 +354,7 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::ConstantAlreadyUsed { .. } => "Constant already used",
|
ChunkError::ConstantAlreadyUsed { .. } => "Constant already used",
|
||||||
ChunkError::ConstantOverflow { .. } => "Constant overflow",
|
ChunkError::ConstantOverflow { .. } => "Constant overflow",
|
||||||
ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
|
ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
|
||||||
ChunkError::IdentifierIndexOutOfBounds { .. } => "Identifier index out of bounds",
|
ChunkError::LocalIndexOutOfBounds { .. } => "Identifier index out of bounds",
|
||||||
ChunkError::IdentifierOverflow { .. } => "Identifier overflow",
|
ChunkError::IdentifierOverflow { .. } => "Identifier overflow",
|
||||||
ChunkError::IdentifierNotFound { .. } => "Identifier not found",
|
ChunkError::IdentifierNotFound { .. } => "Identifier not found",
|
||||||
}
|
}
|
||||||
@ -330,7 +369,7 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::ConstantIndexOutOfBounds { index, .. } => {
|
ChunkError::ConstantIndexOutOfBounds { index, .. } => {
|
||||||
Some(format!("Constant index: {}", index))
|
Some(format!("Constant index: {}", index))
|
||||||
}
|
}
|
||||||
ChunkError::IdentifierIndexOutOfBounds { index, .. } => {
|
ChunkError::LocalIndexOutOfBounds { index, .. } => {
|
||||||
Some(format!("Identifier index: {}", index))
|
Some(format!("Identifier index: {}", index))
|
||||||
}
|
}
|
||||||
ChunkError::IdentifierNotFound { identifier, .. } => {
|
ChunkError::IdentifierNotFound { identifier, .. } => {
|
||||||
|
@ -5,7 +5,7 @@ use crate::{Chunk, Span};
|
|||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub struct Instruction {
|
pub struct Instruction {
|
||||||
pub operation: Operation,
|
pub operation: Operation,
|
||||||
pub to_register: u8,
|
pub destination: u8,
|
||||||
pub arguments: [u8; 2],
|
pub arguments: [u8; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,15 +17,15 @@ impl Instruction {
|
|||||||
|
|
||||||
Instruction {
|
Instruction {
|
||||||
operation,
|
operation,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments,
|
arguments,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(&self) -> u32 {
|
pub fn encode(&self) -> u32 {
|
||||||
let operation = u32::from(self.operation as u8);
|
let operation = self.operation as u8 as u32;
|
||||||
let to_register = u32::from(self.to_register);
|
let to_register = self.destination as u32;
|
||||||
let arguments = u32::from(self.arguments[0]) << 8 | u32::from(self.arguments[1]);
|
let arguments = (self.arguments[0] as u32) << 8 | (self.arguments[1] as u32);
|
||||||
|
|
||||||
operation << 24 | to_register << 16 | arguments
|
operation << 24 | to_register << 16 | arguments
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ impl Instruction {
|
|||||||
pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
|
pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Move,
|
operation: Operation::Move,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [from_register, 0],
|
arguments: [from_register, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ impl Instruction {
|
|||||||
pub fn close(to_register: u8) -> Instruction {
|
pub fn close(to_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Close,
|
operation: Operation::Close,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [0, 0],
|
arguments: [0, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ impl Instruction {
|
|||||||
pub fn load_constant(to_register: u8, constant_index: u16) -> Instruction {
|
pub fn load_constant(to_register: u8, constant_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::LoadConstant,
|
operation: Operation::LoadConstant,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: constant_index.to_le_bytes(),
|
arguments: constant_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ impl Instruction {
|
|||||||
pub fn declare_variable(to_register: u8, variable_index: u16) -> Instruction {
|
pub fn declare_variable(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::DeclareVariable,
|
operation: Operation::DeclareVariable,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,15 +65,15 @@ impl Instruction {
|
|||||||
pub fn get_variable(to_register: u8, variable_index: u16) -> Instruction {
|
pub fn get_variable(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::GetVariable,
|
operation: Operation::GetVariable,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_variable(from_register: u8, variable_index: u16) -> Instruction {
|
pub fn set_local(from_register: u8, variable_index: u16) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::SetVariable,
|
operation: Operation::SetVariable,
|
||||||
to_register: from_register,
|
destination: from_register,
|
||||||
arguments: variable_index.to_le_bytes(),
|
arguments: variable_index.to_le_bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ impl Instruction {
|
|||||||
pub fn add(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
pub fn add(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Add,
|
operation: Operation::Add,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [left_register, right_register],
|
arguments: [left_register, right_register],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ impl Instruction {
|
|||||||
pub fn subtract(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
pub fn subtract(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Subtract,
|
operation: Operation::Subtract,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [left_register, right_register],
|
arguments: [left_register, right_register],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ impl Instruction {
|
|||||||
pub fn multiply(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
pub fn multiply(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Multiply,
|
operation: Operation::Multiply,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [left_register, right_register],
|
arguments: [left_register, right_register],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ impl Instruction {
|
|||||||
pub fn divide(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
pub fn divide(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Divide,
|
operation: Operation::Divide,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [left_register, right_register],
|
arguments: [left_register, right_register],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ impl Instruction {
|
|||||||
pub fn negate(to_register: u8, from_register: u8) -> Instruction {
|
pub fn negate(to_register: u8, from_register: u8) -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Negate,
|
operation: Operation::Negate,
|
||||||
to_register,
|
destination: to_register,
|
||||||
arguments: [from_register, 0],
|
arguments: [from_register, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ impl Instruction {
|
|||||||
pub fn r#return() -> Instruction {
|
pub fn r#return() -> Instruction {
|
||||||
Instruction {
|
Instruction {
|
||||||
operation: Operation::Return,
|
operation: Operation::Return,
|
||||||
to_register: 0,
|
destination: 0,
|
||||||
arguments: [0, 0],
|
arguments: [0, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,34 +132,34 @@ impl Instruction {
|
|||||||
format!(
|
format!(
|
||||||
"{:16} R({}) R({})",
|
"{:16} R({}) R({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0]
|
self.arguments[0]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Close => format!("{} R({})", self.operation, self.to_register),
|
Operation::Close => format!("{:16} R({})", self.operation, self.destination),
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let constant_index = u16::from_le_bytes(self.arguments);
|
let constant_index = u16::from_le_bytes(self.arguments) as usize;
|
||||||
let constant_display = match chunk.get_constant(constant_index, Span(0, 0)) {
|
let constant_display = match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||||
Ok(value) => value.to_string(),
|
Ok(value) => value.to_string(),
|
||||||
Err(error) => format!("{:?}", error),
|
Err(error) => format!("{:?}", error),
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = C({}) {} ",
|
"{:16} R({}) = C({}) {}",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
constant_index,
|
constant_index,
|
||||||
constant_display
|
constant_display
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::DeclareVariable => {
|
Operation::DeclareVariable => {
|
||||||
let identifier_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
let local_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{:16} R[C({})] = R({})",
|
"{:16} L({}) = R({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
identifier_index,
|
local_index,
|
||||||
self.to_register
|
self.destination
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::GetVariable => {
|
Operation::GetVariable => {
|
||||||
@ -168,7 +168,7 @@ impl Instruction {
|
|||||||
format!(
|
format!(
|
||||||
"{:16} R{} = R[I({})]",
|
"{:16} R{} = R[I({})]",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
identifier_index
|
identifier_index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -179,50 +179,50 @@ impl Instruction {
|
|||||||
"{:16} R[C({})] = R({})",
|
"{:16} R[C({})] = R({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
identifier_index,
|
identifier_index,
|
||||||
self.to_register
|
self.destination
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = R({}) + R({})",
|
"{:16} R({}) = RC({}) + RC({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0],
|
self.arguments[0],
|
||||||
self.arguments[1]
|
self.arguments[1]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = R({}) - R({})",
|
"{:16} R({}) = RC({}) - RC({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0],
|
self.arguments[0],
|
||||||
self.arguments[1]
|
self.arguments[1]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = R({}) * R({})",
|
"{:16} R({}) = RC({}) * RC({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0],
|
self.arguments[0],
|
||||||
self.arguments[1]
|
self.arguments[1]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = R({}) / R({})",
|
"{:16} R({}) = RC({}) / RC({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0],
|
self.arguments[0],
|
||||||
self.arguments[1]
|
self.arguments[1]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Negate => {
|
Operation::Negate => {
|
||||||
format!(
|
format!(
|
||||||
"{:16} R({}) = -R({})",
|
"{:16} R({}) = -RC({})",
|
||||||
self.operation.to_string(),
|
self.operation.to_string(),
|
||||||
self.to_register,
|
self.destination,
|
||||||
self.arguments[0]
|
self.arguments[0]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -239,22 +239,18 @@ impl Display for Instruction {
|
|||||||
Operation::Move => {
|
Operation::Move => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) R({})",
|
"{} R({}) R({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Close => write!(f, "{} R({})", self.operation, self.to_register),
|
Operation::Close => write!(f, "{} R({})", self.operation, self.destination),
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let constant_index = u16::from_le_bytes(self.arguments);
|
let constant_index = u16::from_le_bytes(self.arguments);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) C({})",
|
"{} R({}) = C({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, constant_index
|
||||||
self.to_register,
|
|
||||||
constant_index
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::DeclareVariable => {
|
Operation::DeclareVariable => {
|
||||||
@ -262,10 +258,8 @@ impl Display for Instruction {
|
|||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R[C({})] = R({})",
|
"{} L({}) = R({})",
|
||||||
self.operation.to_string(),
|
self.operation, identifier_index, self.destination
|
||||||
identifier_index,
|
|
||||||
self.to_register
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::GetVariable => {
|
Operation::GetVariable => {
|
||||||
@ -273,10 +267,8 @@ impl Display for Instruction {
|
|||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R{} = R[I({})]",
|
"{} R{} = R[I({})]",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, identifier_index
|
||||||
self.to_register,
|
|
||||||
identifier_index
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::SetVariable => {
|
Operation::SetVariable => {
|
||||||
@ -284,63 +276,47 @@ impl Display for Instruction {
|
|||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R[C({})] = R({})",
|
"{} R[C({})] = R({})",
|
||||||
self.operation.to_string(),
|
self.operation, identifier_index, self.destination
|
||||||
identifier_index,
|
|
||||||
self.to_register
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) = R({}) + R({})",
|
"{} R({}) = RC({}) + RC({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) = R({}) - R({})",
|
"{} R({}) = RC({}) - RC({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) = R({}) * R({})",
|
"{} R({}) = RC({}) * RC({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) = R({}) / R({})",
|
"{} R({}) = RC({}) / RC({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0], self.arguments[1]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0],
|
|
||||||
self.arguments[1]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Negate => {
|
Operation::Negate => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{:16} R({}) = -R({})",
|
"{} R({}) = -RC({})",
|
||||||
self.operation.to_string(),
|
self.operation, self.destination, self.arguments[0]
|
||||||
self.to_register,
|
|
||||||
self.arguments[0]
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Operation::Return => {
|
Operation::Return => {
|
||||||
write!(f, "{:16}", self.operation.to_string())
|
write!(f, "{}", self.operation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError,
|
dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError,
|
||||||
Lexer, Span, Token, TokenKind, TokenOwned, Value,
|
Lexer, Operation, Span, Token, TokenKind, TokenOwned, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||||
@ -75,6 +75,20 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decrement_register(&mut self) -> Result<(), ParseError> {
|
||||||
|
let current = self.current_register;
|
||||||
|
|
||||||
|
if current == 0 {
|
||||||
|
Err(ParseError::RegisterUnderflow {
|
||||||
|
position: self.current_position,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.current_register -= 1;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn advance(&mut self) -> Result<(), ParseError> {
|
fn advance(&mut self) -> Result<(), ParseError> {
|
||||||
if self.is_eof() {
|
if self.is_eof() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -113,7 +127,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
||||||
self.chunk.push_code(instruction, position);
|
self.chunk.push_instruction(instruction, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
|
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
|
||||||
@ -241,18 +255,61 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.parse(rule.precedence.increment())?;
|
self.parse(rule.precedence.increment())?;
|
||||||
|
|
||||||
let to_register = if self.current_register < 2 {
|
let previous_instruction = self.chunk.pop_instruction();
|
||||||
self.current_register + 2
|
let right_register = match previous_instruction {
|
||||||
} else {
|
Some((
|
||||||
self.current_register
|
Instruction {
|
||||||
|
operation: Operation::LoadConstant,
|
||||||
|
arguments,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
|
self.decrement_register()?;
|
||||||
|
|
||||||
|
arguments[0]
|
||||||
|
}
|
||||||
|
Some((instruction, position)) => {
|
||||||
|
self.chunk.push_instruction(instruction, position);
|
||||||
|
|
||||||
|
self.current_register - 1
|
||||||
|
}
|
||||||
|
_ => self.current_register - 1,
|
||||||
};
|
};
|
||||||
let left_register = to_register - 2;
|
let last_instruction = self.chunk.pop_instruction();
|
||||||
let right_register = to_register - 1;
|
let left_register = match last_instruction {
|
||||||
let byte = match operator {
|
Some((
|
||||||
TokenKind::Plus => Instruction::add(to_register, left_register, right_register),
|
Instruction {
|
||||||
TokenKind::Minus => Instruction::subtract(to_register, left_register, right_register),
|
operation: Operation::LoadConstant,
|
||||||
TokenKind::Star => Instruction::multiply(to_register, left_register, right_register),
|
arguments,
|
||||||
TokenKind::Slash => Instruction::divide(to_register, left_register, right_register),
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
)) => {
|
||||||
|
self.decrement_register()?;
|
||||||
|
|
||||||
|
arguments[0]
|
||||||
|
}
|
||||||
|
Some((instruction, position)) => {
|
||||||
|
self.chunk.push_instruction(instruction, position);
|
||||||
|
|
||||||
|
self.current_register - 2
|
||||||
|
}
|
||||||
|
_ => self.current_register - 2,
|
||||||
|
};
|
||||||
|
let instruction = match operator {
|
||||||
|
TokenKind::Plus => {
|
||||||
|
Instruction::add(self.current_register, left_register, right_register)
|
||||||
|
}
|
||||||
|
TokenKind::Minus => {
|
||||||
|
Instruction::subtract(self.current_register, left_register, right_register)
|
||||||
|
}
|
||||||
|
TokenKind::Star => {
|
||||||
|
Instruction::multiply(self.current_register, left_register, right_register)
|
||||||
|
}
|
||||||
|
TokenKind::Slash => {
|
||||||
|
Instruction::divide(self.current_register, left_register, right_register)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParseError::ExpectedTokenMultiple {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: vec![
|
expected: vec![
|
||||||
@ -268,7 +325,7 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
self.emit_instruction(byte, operator_position);
|
self.emit_instruction(instruction, operator_position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -279,21 +336,16 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
fn parse_named_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
|
fn parse_named_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
|
||||||
let token = self.previous_token.to_owned();
|
let token = self.previous_token.to_owned();
|
||||||
let identifier_index = self.parse_identifier_from(token, self.previous_position)?;
|
let local_index = self.parse_identifier_from(token, self.previous_position)?;
|
||||||
|
|
||||||
if allow_assignment && self.allow(TokenKind::Equal)? {
|
if allow_assignment && self.allow(TokenKind::Equal)? {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::set_variable(self.current_register, identifier_index),
|
Instruction::set_local(self.current_register, local_index),
|
||||||
self.previous_position,
|
self.previous_position,
|
||||||
);
|
);
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
} else {
|
|
||||||
self.emit_instruction(
|
|
||||||
Instruction::get_variable(self.current_register - 1, identifier_index),
|
|
||||||
self.previous_position,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -307,8 +359,8 @@ impl<'src> Parser<'src> {
|
|||||||
if let TokenOwned::Identifier(text) = token {
|
if let TokenOwned::Identifier(text) = token {
|
||||||
let identifier = Identifier::new(text);
|
let identifier = Identifier::new(text);
|
||||||
|
|
||||||
if let Ok(identifier_index) = self.chunk.get_identifier_index(&identifier, position) {
|
if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) {
|
||||||
Ok(identifier_index)
|
Ok(local_index)
|
||||||
} else {
|
} else {
|
||||||
Err(ParseError::UndefinedVariable {
|
Err(ParseError::UndefinedVariable {
|
||||||
identifier,
|
identifier,
|
||||||
@ -392,13 +444,12 @@ impl<'src> Parser<'src> {
|
|||||||
self.expect(TokenKind::Equal)?;
|
self.expect(TokenKind::Equal)?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
let identifier_index = self.chunk.declare_variable(identifier, position)?;
|
let local_index = self.chunk.declare_local(identifier, position)?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::declare_variable(self.current_register, identifier_index),
|
Instruction::declare_variable(self.current_register - 1, local_index),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
self.increment_register()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -661,6 +712,9 @@ pub enum ParseError {
|
|||||||
RegisterOverflow {
|
RegisterOverflow {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
RegisterUnderflow {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
|
||||||
// Wrappers around foreign errors
|
// Wrappers around foreign errors
|
||||||
Chunk(ChunkError),
|
Chunk(ChunkError),
|
||||||
@ -694,6 +748,7 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
Self::UndefinedVariable { .. } => "Undefined variable",
|
||||||
Self::RegisterOverflow { .. } => "Register overflow",
|
Self::RegisterOverflow { .. } => "Register overflow",
|
||||||
|
Self::RegisterUnderflow { .. } => "Register underflow",
|
||||||
Self::Chunk { .. } => "Chunk error",
|
Self::Chunk { .. } => "Chunk error",
|
||||||
Self::Lex(_) => "Lex error",
|
Self::Lex(_) => "Lex error",
|
||||||
Self::ParseFloatError { .. } => "Failed to parse float",
|
Self::ParseFloatError { .. } => "Failed to parse float",
|
||||||
@ -717,6 +772,7 @@ impl AnnotatedError for ParseError {
|
|||||||
Some(format!("Undefined variable \"{identifier}\""))
|
Some(format!("Undefined variable \"{identifier}\""))
|
||||||
}
|
}
|
||||||
Self::RegisterOverflow { .. } => None,
|
Self::RegisterOverflow { .. } => None,
|
||||||
|
Self::RegisterUnderflow { .. } => None,
|
||||||
Self::Chunk(error) => error.details(),
|
Self::Chunk(error) => error.details(),
|
||||||
Self::Lex(error) => error.details(),
|
Self::Lex(error) => error.details(),
|
||||||
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
||||||
@ -732,6 +788,7 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::InvalidAssignmentTarget { position, .. } => *position,
|
Self::InvalidAssignmentTarget { position, .. } => *position,
|
||||||
Self::UndefinedVariable { position, .. } => *position,
|
Self::UndefinedVariable { position, .. } => *position,
|
||||||
Self::RegisterOverflow { position } => *position,
|
Self::RegisterOverflow { position } => *position,
|
||||||
|
Self::RegisterUnderflow { position } => *position,
|
||||||
Self::Chunk(error) => error.position(),
|
Self::Chunk(error) => error.position(),
|
||||||
Self::Lex(error) => error.position(),
|
Self::Lex(error) => error.position(),
|
||||||
Self::ParseFloatError { position, .. } => *position,
|
Self::ParseFloatError { position, .. } => *position,
|
||||||
|
@ -12,8 +12,8 @@ fn let_statement() {
|
|||||||
(Instruction::declare_variable(1, 0), Span(4, 5)),
|
(Instruction::declare_variable(1, 0), Span(4, 5)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42),],
|
vec![Value::integer(42),],
|
||||||
vec![Local::new(Identifier::new("x"), 0)]
|
vec![Local::new(Identifier::new("x"), 0, None)]
|
||||||
))
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,69 +38,77 @@ impl Vm {
|
|||||||
Operation::Move => todo!(),
|
Operation::Move => todo!(),
|
||||||
Operation::Close => todo!(),
|
Operation::Close => todo!(),
|
||||||
Operation::LoadConstant => {
|
Operation::LoadConstant => {
|
||||||
let register_index = instruction.to_register as usize;
|
let constant_index = u16::from_le_bytes(instruction.arguments) as usize;
|
||||||
let constant_index = u16::from_le_bytes(instruction.arguments);
|
|
||||||
let value = self.chunk.use_constant(constant_index, position)?;
|
let value = self.chunk.use_constant(constant_index, position)?;
|
||||||
|
|
||||||
self.insert(value, register_index, position)?;
|
self.insert(value, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::DeclareVariable => {
|
Operation::DeclareVariable => {
|
||||||
let register_index = instruction.to_register as usize;
|
let register_index = instruction.destination as usize;
|
||||||
let identifier_index = u16::from_le_bytes(instruction.arguments) as usize;
|
let local_index = u16::from_le_bytes(instruction.arguments) as usize;
|
||||||
let value = self.take(identifier_index, position)?;
|
let value = self.clone(register_index, position)?;
|
||||||
|
|
||||||
self.insert(value, register_index, position)?;
|
self.chunk.define_local(local_index, value, position)?;
|
||||||
}
|
}
|
||||||
Operation::GetVariable => {
|
Operation::GetVariable => {
|
||||||
let identifier_index = u16::from_le_bytes(instruction.arguments) as usize;
|
let identifier_index = u16::from_le_bytes(instruction.arguments) as usize;
|
||||||
let value = self.take(identifier_index, position)?;
|
let value = self.clone(identifier_index, position)?;
|
||||||
|
|
||||||
self.insert(value, identifier_index, position)?;
|
self.insert(value, identifier_index, position)?;
|
||||||
}
|
}
|
||||||
Operation::SetVariable => todo!(),
|
Operation::SetVariable => todo!(),
|
||||||
Operation::Add => {
|
Operation::Add => {
|
||||||
let left = self.take(instruction.arguments[0] as usize, position)?;
|
let left =
|
||||||
let right = self.take(instruction.arguments[1] as usize, position)?;
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
|
let right =
|
||||||
|
self.take_or_use_constant(instruction.arguments[1] as usize, position)?;
|
||||||
let sum = left
|
let sum = left
|
||||||
.add(&right)
|
.add(&right)
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
|
|
||||||
self.insert(sum, instruction.to_register as usize, position)?;
|
self.insert(sum, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::Subtract => {
|
Operation::Subtract => {
|
||||||
let left = self.take(instruction.arguments[0] as usize, position)?;
|
let left =
|
||||||
let right = self.take(instruction.arguments[1] as usize, position)?;
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
|
let right =
|
||||||
|
self.take_or_use_constant(instruction.arguments[1] as usize, position)?;
|
||||||
let difference = left
|
let difference = left
|
||||||
.subtract(&right)
|
.subtract(&right)
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
|
|
||||||
self.insert(difference, instruction.to_register as usize, position)?;
|
self.insert(difference, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::Multiply => {
|
Operation::Multiply => {
|
||||||
let left = self.take(instruction.arguments[0] as usize, position)?;
|
let left =
|
||||||
let right = self.take(instruction.arguments[1] as usize, position)?;
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
|
let right =
|
||||||
|
self.take_or_use_constant(instruction.arguments[1] as usize, position)?;
|
||||||
let product = left
|
let product = left
|
||||||
.multiply(&right)
|
.multiply(&right)
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
|
|
||||||
self.insert(product, instruction.to_register as usize, position)?;
|
self.insert(product, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::Divide => {
|
Operation::Divide => {
|
||||||
let left = self.take(instruction.arguments[0] as usize, position)?;
|
let left =
|
||||||
let right = self.take(instruction.arguments[1] as usize, position)?;
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
|
let right =
|
||||||
|
self.take_or_use_constant(instruction.arguments[1] as usize, position)?;
|
||||||
let quotient = left
|
let quotient = left
|
||||||
.divide(&right)
|
.divide(&right)
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
|
|
||||||
self.insert(quotient, instruction.to_register as usize, position)?;
|
self.insert(quotient, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::Negate => {
|
Operation::Negate => {
|
||||||
let value = self.take(instruction.arguments[0] as usize, position)?;
|
let value =
|
||||||
|
self.take_or_use_constant(instruction.arguments[0] as usize, position)?;
|
||||||
let negated = value
|
let negated = value
|
||||||
.negate()
|
.negate()
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
.map_err(|error| VmError::Value { error, position })?;
|
||||||
|
|
||||||
self.insert(negated, instruction.to_register as usize, position)?;
|
self.insert(negated, instruction.destination as usize, position)?;
|
||||||
}
|
}
|
||||||
Operation::Return => {
|
Operation::Return => {
|
||||||
let value = self.pop(position)?;
|
let value = self.pop(position)?;
|
||||||
@ -117,21 +125,23 @@ impl Vm {
|
|||||||
if self.register_stack.len() == Self::STACK_LIMIT {
|
if self.register_stack.len() == Self::STACK_LIMIT {
|
||||||
Err(VmError::StackOverflow { position })
|
Err(VmError::StackOverflow { position })
|
||||||
} else {
|
} else {
|
||||||
if index == self.register_stack.len() {
|
while index >= self.register_stack.len() {
|
||||||
self.register_stack.push(Some(value));
|
self.register_stack.push(None);
|
||||||
} else {
|
|
||||||
self.register_stack[index] = Some(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.register_stack[index] = Some(value);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn take(&mut self, index: usize, position: Span) -> Result<Value, VmError> {
|
fn clone(&mut self, index: usize, position: Span) -> Result<Value, VmError> {
|
||||||
if let Some(register) = self.register_stack.get_mut(index) {
|
if let Some(register) = self.register_stack.get_mut(index) {
|
||||||
let value = register
|
let value = register
|
||||||
.clone()
|
.take()
|
||||||
.ok_or(VmError::EmptyRegister { index, position })?;
|
.ok_or(VmError::EmptyRegister { index, position })?
|
||||||
|
.into_reference();
|
||||||
|
let _ = register.insert(value.clone());
|
||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
@ -139,6 +149,16 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn take_or_use_constant(&mut self, index: usize, position: Span) -> Result<Value, VmError> {
|
||||||
|
if let Ok(value) = self.clone(index, position) {
|
||||||
|
Ok(value)
|
||||||
|
} else {
|
||||||
|
let value = self.chunk.use_constant(index, position)?;
|
||||||
|
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn pop(&mut self, position: Span) -> Result<Value, VmError> {
|
fn pop(&mut self, position: Span) -> Result<Value, VmError> {
|
||||||
if let Some(register) = self.register_stack.pop() {
|
if let Some(register) = self.register_stack.pop() {
|
||||||
let value = register.ok_or(VmError::EmptyRegister {
|
let value = register.ok_or(VmError::EmptyRegister {
|
||||||
@ -153,7 +173,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
|
fn read(&mut self, position: Span) -> Result<&(Instruction, Span), VmError> {
|
||||||
let current = self.chunk.get_code(self.ip, position)?;
|
let current = self.chunk.get_instruction(self.ip, position)?;
|
||||||
|
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ fn parse_and_display_errors(source: &str) {
|
|||||||
match parse(source) {
|
match parse(source) {
|
||||||
Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")),
|
Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("{:?}", error);
|
eprintln!("{}", error.report());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user