1
0
dust/dust-lang/src/chunk.rs

226 lines
6.4 KiB
Rust
Raw Normal View History

2024-09-10 02:57:14 +00:00
use std::fmt::{self, Debug, Display, Formatter};
2024-09-07 10:38:12 +00:00
use serde::{Deserialize, Serialize};
2024-09-09 23:23:49 +00:00
use crate::{identifier_stack::Local, Identifier, IdentifierStack, Instruction, Span, Value};
2024-09-07 10:38:12 +00:00
2024-09-07 22:48:01 +00:00
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
2024-09-07 10:38:12 +00:00
pub struct Chunk {
code: Vec<(u8, Span)>,
constants: Vec<Value>,
2024-09-09 23:23:49 +00:00
identifiers: IdentifierStack,
2024-09-07 10:38:12 +00:00
}
impl Chunk {
pub fn new() -> Self {
Self {
code: Vec::new(),
constants: Vec::new(),
2024-09-09 23:23:49 +00:00
identifiers: IdentifierStack::new(),
2024-09-07 10:38:12 +00:00
}
}
2024-09-07 16:15:47 +00:00
pub fn with_data(
code: Vec<(u8, Span)>,
constants: Vec<Value>,
2024-09-09 23:23:49 +00:00
identifiers: Vec<Local>,
2024-09-07 16:15:47 +00:00
) -> Self {
Self {
code,
constants,
2024-09-09 23:23:49 +00:00
identifiers: IdentifierStack::with_data(identifiers, 0),
2024-09-07 16:15:47 +00:00
}
2024-09-07 10:38:12 +00:00
}
pub fn len(&self) -> usize {
self.code.len()
}
pub fn is_empty(&self) -> bool {
self.code.is_empty()
}
2024-09-10 02:57:14 +00:00
pub fn get_code(&self, offset: usize) -> Result<&(u8, Span), ChunkError> {
2024-09-07 16:15:47 +00:00
self.code
.get(offset)
2024-09-10 05:04:30 +00:00
.ok_or(ChunkError::CodeIndexOfBounds(offset))
2024-09-07 10:38:12 +00:00
}
2024-09-10 02:57:14 +00:00
pub fn push_code(&mut self, instruction: u8, position: Span) {
2024-09-07 10:38:12 +00:00
self.code.push((instruction, position));
}
2024-09-09 23:23:49 +00:00
pub fn get_constant(&self, index: u8) -> Result<&Value, ChunkError> {
2024-09-07 10:38:12 +00:00
self.constants
2024-09-09 23:23:49 +00:00
.get(index as usize)
2024-09-07 16:15:47 +00:00
.ok_or(ChunkError::ConstantIndexOutOfBounds(index))
2024-09-07 10:38:12 +00:00
}
pub fn remove_constant(&mut self, index: u8) -> Result<Value, ChunkError> {
let index = index as usize;
if index >= self.constants.len() {
Err(ChunkError::ConstantIndexOutOfBounds(index as u8))
} else {
Ok(self.constants.remove(index))
}
}
2024-09-07 10:38:12 +00:00
pub fn push_constant(&mut self, value: Value) -> Result<u8, ChunkError> {
let starting_length = self.constants.len();
if starting_length + 1 > (u8::MAX as usize) {
2024-09-07 16:15:47 +00:00
Err(ChunkError::ConstantOverflow)
2024-09-07 10:38:12 +00:00
} else {
self.constants.push(value);
Ok(starting_length as u8)
}
}
2024-09-09 23:23:49 +00:00
pub fn contains_identifier(&self, identifier: &Identifier) -> bool {
self.identifiers.contains(identifier)
}
pub fn get_identifier(&self, index: u8) -> Result<&Identifier, ChunkError> {
2024-09-07 16:15:47 +00:00
self.identifiers
2024-09-09 23:23:49 +00:00
.get(index as usize)
.map(|local| &local.identifier)
2024-09-07 16:15:47 +00:00
.ok_or(ChunkError::IdentifierIndexOutOfBounds(index))
}
2024-09-09 23:23:49 +00:00
pub fn get_identifier_index(&self, identifier: &Identifier) -> Result<u8, ChunkError> {
self.identifiers
.get_index(identifier)
.ok_or(ChunkError::IdentifierNotFound(identifier.clone()))
}
2024-09-07 16:15:47 +00:00
pub fn push_identifier(&mut self, identifier: Identifier) -> Result<u8, ChunkError> {
2024-09-09 23:23:49 +00:00
let starting_length = self.identifiers.local_count();
2024-09-07 16:15:47 +00:00
if starting_length + 1 > (u8::MAX as usize) {
Err(ChunkError::IdentifierOverflow)
} else {
2024-09-09 23:23:49 +00:00
self.identifiers.declare(identifier);
2024-09-07 16:15:47 +00:00
Ok(starting_length as u8)
}
}
2024-09-07 10:38:12 +00:00
pub fn clear(&mut self) {
self.code.clear();
self.constants.clear();
2024-09-09 23:23:49 +00:00
self.identifiers.clear();
2024-09-07 10:38:12 +00:00
}
pub fn disassemble(&self, name: &str) -> String {
let mut output = String::new();
output.push_str("== ");
output.push_str(name);
2024-09-10 03:24:22 +00:00
output.push_str(" ==\n--Code--\n");
2024-09-10 00:55:00 +00:00
output.push_str("OFFSET INSTRUCTION POSITION\n");
2024-09-07 10:38:12 +00:00
2024-09-07 21:16:14 +00:00
let mut previous = None;
2024-09-07 10:38:12 +00:00
for (offset, (byte, position)) in self.code.iter().enumerate() {
2024-09-07 21:16:14 +00:00
if let Some(
2024-09-10 03:24:22 +00:00
Instruction::Constant
| Instruction::DefineVariable
| Instruction::GetVariable
| Instruction::SetVariable,
2024-09-07 21:16:14 +00:00
) = previous
{
previous = None;
2024-09-07 10:38:12 +00:00
2024-09-07 21:16:14 +00:00
continue;
2024-09-07 10:38:12 +00:00
}
2024-09-07 21:16:14 +00:00
let instruction = Instruction::from_byte(*byte).unwrap();
2024-09-10 00:55:00 +00:00
let display = format!("{offset:04} {}", instruction.disassemble(self, offset));
2024-09-10 02:57:14 +00:00
let display_with_postion = format!("{display:27} {position}\n");
2024-09-10 00:55:00 +00:00
2024-09-07 21:16:14 +00:00
previous = Some(instruction);
2024-09-10 00:55:00 +00:00
output.push_str(&display_with_postion);
}
2024-09-10 03:24:22 +00:00
output.push_str("--Constants--\n");
2024-09-10 00:55:00 +00:00
output.push_str("INDEX KIND VALUE\n");
for (index, value) in self.constants.iter().enumerate() {
let value_kind_display = match value {
Value::Raw(_) => "RAW ",
Value::Reference(_) => "REF ",
Value::Mutable(_) => "MUT ",
};
let display = format!("{index:04} {value_kind_display} {value}\n");
output.push_str(&display);
}
2024-09-10 03:24:22 +00:00
output.push_str("--Identifiers--\n");
2024-09-10 00:55:00 +00:00
output.push_str("INDEX IDENTIFIER DEPTH\n");
for (index, Local { identifier, depth }) in self.identifiers.iter().enumerate() {
let display = format!("{index:04} {:10} {depth}\n", identifier.as_str());
2024-09-07 21:16:14 +00:00
output.push_str(&display);
2024-09-07 10:38:12 +00:00
}
output
}
}
impl Default for Chunk {
fn default() -> Self {
Self::new()
}
}
impl Display for Chunk {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2024-09-10 05:04:30 +00:00
write!(f, "{}", self.disassemble("Chunk Disassembly"))
2024-09-07 10:38:12 +00:00
}
}
2024-09-07 22:48:01 +00:00
impl Debug for Chunk {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
2024-09-10 05:04:30 +00:00
write!(f, "{}", self.disassemble("Chunk Disassembly"))
2024-09-07 22:48:01 +00:00
}
}
2024-09-09 23:23:49 +00:00
#[derive(Debug, Clone, PartialEq)]
2024-09-07 10:38:12 +00:00
pub enum ChunkError {
2024-09-10 05:04:30 +00:00
CodeIndexOfBounds(usize),
2024-09-07 16:15:47 +00:00
ConstantOverflow,
2024-09-09 23:23:49 +00:00
ConstantIndexOutOfBounds(u8),
IdentifierIndexOutOfBounds(u8),
2024-09-07 16:15:47 +00:00
IdentifierOverflow,
2024-09-09 23:23:49 +00:00
IdentifierNotFound(Identifier),
2024-09-07 10:38:12 +00:00
}
2024-09-10 05:04:30 +00:00
impl ChunkError {
pub fn title(&self) -> &'static str {
"Chunk Error"
}
pub fn description(&self) -> String {
match self {
Self::CodeIndexOfBounds(offset) => format!("{offset} is out of bounds",),
Self::ConstantOverflow => "More than 256 constants declared in one chunk".to_string(),
Self::ConstantIndexOutOfBounds(index) => {
format!("{index} is out of bounds")
}
Self::IdentifierIndexOutOfBounds(index) => {
format!("{index} is out of bounds")
}
Self::IdentifierOverflow => {
"More than 256 identifiers declared in one chunk".to_string()
}
Self::IdentifierNotFound(identifier) => {
format!("{} does not exist in this scope", identifier)
}
}
}
}