Refactor and clean up

This commit is contained in:
Jeff 2024-09-07 17:16:14 -04:00
parent b8957190e0
commit e9ec838b25
4 changed files with 142 additions and 75 deletions

View File

@ -102,28 +102,35 @@ impl Chunk {
output.push_str(name); output.push_str(name);
output.push_str(" ==\n"); output.push_str(" ==\n");
let mut next_is_index = false; let mut previous = None;
for (offset, (byte, position)) in self.code.iter().enumerate() { for (offset, (byte, position)) in self.code.iter().enumerate() {
if next_is_index { if let Some(Instruction::Constant) = previous {
let index_display = format!("{position} {offset:04} INDEX {byte}\n"); let display = format!("{position} {offset:04} CONSTANT_INDEX {byte}\n");
previous = None;
output.push_str(&index_display); output.push_str(&display);
next_is_index = false; continue;
}
if let Some(
Instruction::DefineGlobal | Instruction::GetGlobal | Instruction::SetGlobal,
) = previous
{
let display = format!("{position} {offset:04} IDENTIFIER_INDEX {byte}\n");
previous = None;
output.push_str(&display);
continue; continue;
} }
let instruction = Instruction::from_byte(*byte).unwrap(); let instruction = Instruction::from_byte(*byte).unwrap();
let instruction_display = let display = format!("{} {}\n", position, instruction.disassemble(self, offset));
format!("{} {}\n", position, instruction.disassemble(self, offset)); previous = Some(instruction);
output.push_str(&instruction_display); output.push_str(&display);
if let Instruction::Constant = instruction {
next_is_index = true;
}
} }
output output

View File

@ -100,7 +100,7 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_boolean(&mut self) -> Result<(), ParseError> { fn parse_boolean(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
if let Token::Boolean(text) = self.previous_token { if let Token::Boolean(text) = self.previous_token {
let boolean = text.parse::<bool>().unwrap(); let boolean = text.parse::<bool>().unwrap();
let value = Value::boolean(boolean); let value = Value::boolean(boolean);
@ -111,7 +111,7 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_float(&mut self) -> Result<(), ParseError> { fn parse_float(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
if let Token::Float(text) = self.previous_token { if let Token::Float(text) = self.previous_token {
let float = text.parse::<f64>().unwrap(); let float = text.parse::<f64>().unwrap();
let value = Value::float(float); let value = Value::float(float);
@ -122,7 +122,7 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_integer(&mut self) -> Result<(), ParseError> { fn parse_integer(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
if let Token::Integer(text) = self.previous_token { if let Token::Integer(text) = self.previous_token {
let integer = text.parse::<i64>().unwrap(); let integer = text.parse::<i64>().unwrap();
let value = Value::integer(integer); let value = Value::integer(integer);
@ -133,7 +133,7 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_string(&mut self) -> Result<(), ParseError> { fn parse_string(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
if let Token::String(text) = self.previous_token { if let Token::String(text) = self.previous_token {
let value = Value::string(text); let value = Value::string(text);
@ -143,12 +143,12 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_grouped(&mut self) -> Result<(), ParseError> { fn parse_grouped(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
self.parse_expression()?; self.parse_expression()?;
self.expect(TokenKind::RightParenthesis) self.expect(TokenKind::RightParenthesis)
} }
fn parse_unary(&mut self) -> Result<(), ParseError> { fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
let operator_position = self.previous_position; let operator_position = self.previous_position;
let byte = match self.previous_token.kind() { let byte = match self.previous_token.kind() {
TokenKind::Minus => Instruction::Negate as u8, TokenKind::Minus => Instruction::Negate as u8,
@ -198,15 +198,25 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_variable(&mut self) -> Result<(), ParseError> { fn parse_variable(&mut self, allow_assignment: bool) -> Result<(), ParseError> {
self.parse_named_variable_from(self.previous_token.to_owned()) self.parse_named_variable_from(self.previous_token.to_owned(), allow_assignment)
} }
fn parse_named_variable_from(&mut self, token: TokenOwned) -> Result<(), ParseError> { fn parse_named_variable_from(
&mut self,
token: TokenOwned,
allow_assignment: bool,
) -> Result<(), ParseError> {
let identifier_index = self.parse_identifier_from(token)?; let identifier_index = self.parse_identifier_from(token)?;
self.emit_byte(Instruction::GetGlobal as u8, self.previous_position); if allow_assignment && self.allow(TokenKind::Equal)? {
self.emit_byte(identifier_index, self.previous_position); self.parse_expression()?;
self.emit_byte(Instruction::SetGlobal as u8, self.previous_position);
self.emit_byte(identifier_index, self.previous_position);
} else {
self.emit_byte(Instruction::GetGlobal as u8, self.previous_position);
self.emit_byte(identifier_index, self.previous_position);
}
Ok(()) Ok(())
} }
@ -268,7 +278,7 @@ impl<'src> Parser<'src> {
} }
fn define_variable(&mut self, identifier_index: u8, position: Span) -> Result<(), ParseError> { fn define_variable(&mut self, identifier_index: u8, position: Span) -> Result<(), ParseError> {
self.emit_byte(Instruction::SetGlobal as u8, position); self.emit_byte(Instruction::DefineGlobal as u8, position);
self.emit_byte(identifier_index, position); self.emit_byte(identifier_index, position);
Ok(()) Ok(())
@ -277,19 +287,24 @@ impl<'src> Parser<'src> {
fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> { fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> {
self.advance()?; self.advance()?;
if let Some(prefix) = ParseRule::from(&self.previous_token.kind()).prefix { let prefix_rule = if let Some(prefix) = ParseRule::from(&self.previous_token.kind()).prefix
{
log::trace!( log::trace!(
"Parsing {} as prefix with precedence {precedence}", "Parsing {} as prefix with precedence {precedence}",
self.previous_token, self.previous_token,
); );
prefix(self)?; prefix
} else { } else {
return Err(ParseError::ExpectedExpression { return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: self.previous_position, position: self.previous_position,
}); });
} };
let allow_assignment = precedence <= Precedence::Assignment;
prefix_rule(self, allow_assignment)?;
while precedence < ParseRule::from(&self.current_token.kind()).precedence { while precedence < ParseRule::from(&self.current_token.kind()).precedence {
self.advance()?; self.advance()?;
@ -302,6 +317,13 @@ impl<'src> Parser<'src> {
self.previous_token, self.previous_token,
); );
if allow_assignment && self.allow(TokenKind::Equal)? {
return Err(ParseError::InvalidAssignmentTarget {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
infix(self)?; infix(self)?;
} else { } else {
break; break;
@ -357,12 +379,13 @@ impl Display for Precedence {
} }
} }
type ParserFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>; type PrefixFunction<'a> = fn(&mut Parser<'a>, bool) -> Result<(), ParseError>;
type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ParseRule<'a> { pub struct ParseRule<'a> {
pub prefix: Option<ParserFunction<'a>>, pub prefix: Option<PrefixFunction<'a>>,
pub infix: Option<ParserFunction<'a>>, pub infix: Option<InfixFunction<'a>>,
pub precedence: Precedence, pub precedence: Precedence,
} }
@ -490,6 +513,10 @@ pub enum ParseError {
found: TokenOwned, found: TokenOwned,
position: Span, position: Span,
}, },
InvalidAssignmentTarget {
found: TokenOwned,
position: Span,
},
// Wrappers around foreign errors // Wrappers around foreign errors
Chunk(ChunkError), Chunk(ChunkError),
@ -530,7 +557,7 @@ mod tests {
vec![ vec![
(Instruction::Constant as u8, Span(8, 10)), (Instruction::Constant as u8, Span(8, 10)),
(0, Span(8, 10)), (0, Span(8, 10)),
(Instruction::SetGlobal as u8, Span(4, 5)), (Instruction::DefineGlobal as u8, Span(4, 5)),
(0, Span(4, 5)) (0, Span(4, 5))
], ],
vec![Value::integer(42)], vec![Value::integer(42)],

View File

@ -5,7 +5,7 @@ pub fn run(source: &str) -> Result<Option<Value>, DustError> {
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
vm.interpret() vm.run()
.map_err(|error| DustError::Runtime { error, source }) .map_err(|error| DustError::Runtime { error, source })
} }

View File

@ -24,7 +24,7 @@ impl Vm {
} }
} }
pub fn interpret(&mut self) -> Result<Option<Value>, VmError> { pub fn run(&mut self) -> Result<Option<Value>, VmError> {
while let Ok((byte, position)) = self.read().copied() { while let Ok((byte, position)) = self.read().copied() {
let instruction = Instruction::from_byte(byte) let instruction = Instruction::from_byte(byte)
.ok_or_else(|| VmError::InvalidInstruction(byte, position))?; .ok_or_else(|| VmError::InvalidInstruction(byte, position))?;
@ -44,7 +44,9 @@ impl Vm {
Instruction::Pop => { Instruction::Pop => {
self.pop()?; self.pop()?;
} }
Instruction::SetGlobal => {
// Variables
Instruction::DefineGlobal => {
let (index, _) = self.read().copied()?; let (index, _) = self.read().copied()?;
let identifier = self.chunk.get_identifier(index as usize)?.clone(); let identifier = self.chunk.get_identifier(index as usize)?.clone();
let value = self.pop()?; let value = self.pop()?;
@ -61,6 +63,18 @@ impl Vm {
self.push(value)?; self.push(value)?;
} }
Instruction::SetGlobal => {
let (index, _) = self.read().copied()?;
let identifier = self.chunk.get_identifier(index as usize)?.clone();
if !self.globals.contains_key(&identifier) {
return Err(VmError::UndefinedGlobal(identifier, position));
}
let value = self.pop()?;
self.globals.insert(identifier, value);
}
// Unary // Unary
Instruction::Negate => { Instruction::Negate => {
@ -225,26 +239,29 @@ pub enum Instruction {
Constant = 0, Constant = 0,
Return = 1, Return = 1,
Pop = 2, Pop = 2,
SetGlobal = 3,
// Variables
DefineGlobal = 3,
GetGlobal = 4, GetGlobal = 4,
SetGlobal = 5,
// Unary // Unary
Negate = 5, Negate = 6,
Not = 6, Not = 7,
// Binary // Binary
Add = 7, Add = 8,
Subtract = 8, Subtract = 9,
Multiply = 9, Multiply = 10,
Divide = 10, Divide = 11,
Greater = 11, Greater = 12,
Less = 12, Less = 13,
GreaterEqual = 13, GreaterEqual = 14,
LessEqual = 14, LessEqual = 15,
Equal = 15, Equal = 16,
NotEqual = 16, NotEqual = 17,
And = 17, And = 18,
Or = 18, Or = 19,
} }
impl Instruction { impl Instruction {
@ -253,22 +270,23 @@ impl Instruction {
0 => Some(Instruction::Constant), 0 => Some(Instruction::Constant),
1 => Some(Instruction::Return), 1 => Some(Instruction::Return),
2 => Some(Instruction::Pop), 2 => Some(Instruction::Pop),
3 => Some(Instruction::SetGlobal), 3 => Some(Instruction::DefineGlobal),
4 => Some(Instruction::GetGlobal), 4 => Some(Instruction::GetGlobal),
5 => Some(Instruction::Negate), 5 => Some(Instruction::SetGlobal),
6 => Some(Instruction::Not), 6 => Some(Instruction::Negate),
7 => Some(Instruction::Add), 7 => Some(Instruction::Not),
8 => Some(Instruction::Subtract), 8 => Some(Instruction::Add),
9 => Some(Instruction::Multiply), 9 => Some(Instruction::Subtract),
10 => Some(Instruction::Divide), 10 => Some(Instruction::Multiply),
11 => Some(Instruction::Greater), 11 => Some(Instruction::Divide),
12 => Some(Instruction::Less), 12 => Some(Instruction::Greater),
13 => Some(Instruction::GreaterEqual), 13 => Some(Instruction::Less),
14 => Some(Instruction::LessEqual), 14 => Some(Instruction::GreaterEqual),
15 => Some(Instruction::Equal), 15 => Some(Instruction::LessEqual),
16 => Some(Instruction::NotEqual), 16 => Some(Instruction::Equal),
17 => Some(Instruction::And), 17 => Some(Instruction::NotEqual),
18 => Some(Instruction::Or), 18 => Some(Instruction::And),
19 => Some(Instruction::Or),
_ => None, _ => None,
} }
} }
@ -286,17 +304,32 @@ impl Instruction {
} }
Instruction::Return => format!("{offset:04} RETURN"), Instruction::Return => format!("{offset:04} RETURN"),
Instruction::Pop => format!("{offset:04} POP"), Instruction::Pop => format!("{offset:04} POP"),
Instruction::SetGlobal => {
let (index, _) = chunk.read(offset + 1).unwrap();
let identifier = chunk.get_identifier(*index as usize).unwrap();
format!("{offset:04} DEFINE_GLOBAL {identifier}") // Variables
Instruction::DefineGlobal => {
let (index, _) = chunk.read(offset + 1).unwrap();
let index = *index as usize;
let identifier = chunk.get_identifier(index).unwrap();
let value = chunk.get_constant(index).unwrap();
format!("{offset:04} DEFINE_GLOBAL {identifier} {value}")
} }
Instruction::GetGlobal => { Instruction::GetGlobal => {
let (index, _) = chunk.read(offset + 1).unwrap(); let (index, _) = chunk.read(offset + 1).unwrap();
let identifier = chunk.get_identifier(*index as usize).unwrap(); let index = *index as usize;
let identifier = chunk.get_identifier(index).unwrap();
let value = chunk.get_constant(index).unwrap();
format!("{offset:04} GET_GLOBAL {identifier}") format!("{offset:04} GET_GLOBAL {identifier} {value}")
}
Instruction::SetGlobal => {
let (index, _) = chunk.read(offset + 1).unwrap();
let index = *index as usize;
let identifier = chunk.get_identifier(index).unwrap();
let value = chunk.get_constant(index).unwrap();
format!("{offset:04} SET_GLOBAL {identifier} {value}")
} }
// Unary // Unary
@ -335,7 +368,7 @@ pub mod tests {
chunk.write(Instruction::Return as u8, Span(2, 3)); chunk.write(Instruction::Return as u8, Span(2, 3));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.interpret(); let result = vm.run();
assert_eq!(result, Ok(Some(Value::integer(-42)))); assert_eq!(result, Ok(Some(Value::integer(-42))));
} }
@ -354,7 +387,7 @@ pub mod tests {
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.write(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.interpret(); let result = vm.run();
assert_eq!(result, Ok(Some(Value::integer(65)))); assert_eq!(result, Ok(Some(Value::integer(65))));
} }
@ -373,7 +406,7 @@ pub mod tests {
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.write(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.interpret(); let result = vm.run();
assert_eq!(result, Ok(Some(Value::integer(19)))); assert_eq!(result, Ok(Some(Value::integer(19))));
} }
@ -392,7 +425,7 @@ pub mod tests {
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.write(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.interpret(); let result = vm.run();
assert_eq!(result, Ok(Some(Value::integer(966)))); assert_eq!(result, Ok(Some(Value::integer(966))));
} }
@ -412,7 +445,7 @@ pub mod tests {
chunk.write(Instruction::Return as u8, Span(10, 11)); chunk.write(Instruction::Return as u8, Span(10, 11));
let mut vm = Vm::new(chunk); let mut vm = Vm::new(chunk);
let result = vm.interpret(); let result = vm.run();
assert_eq!(result, Ok(Some(Value::integer(1)))); assert_eq!(result, Ok(Some(Value::integer(1))));
} }