1
0

Implement better closing for blocks

This commit is contained in:
Jeff 2024-09-18 07:58:31 -04:00
parent 0a16c5e0ca
commit fa4c2d48a3
3 changed files with 85 additions and 31 deletions

View File

@ -101,6 +101,10 @@ impl Chunk {
} }
} }
pub fn locals(&self) -> &[Local] {
&self.locals
}
pub fn get_local(&self, index: u8, position: Span) -> Result<&Local, ChunkError> { pub fn get_local(&self, index: u8, position: Span) -> Result<&Local, ChunkError> {
let index = index as usize; let index = index as usize;

View File

@ -304,6 +304,12 @@ impl<'src> Parser<'src> {
self.decrement_register()?; self.decrement_register()?;
left_instruction.first_argument() left_instruction.first_argument()
} }
Operation::Close => {
return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
_ => { _ => {
push_back_left = true; push_back_left = true;
@ -311,12 +317,11 @@ impl<'src> Parser<'src> {
} }
}; };
let operator_position = self.current_position;
let operator = self.current_token; let operator = self.current_token;
let operator_position = self.current_position;
let rule = ParseRule::from(&operator.kind()); let rule = ParseRule::from(&operator.kind());
self.advance()?; self.advance()?;
self.parse(rule.precedence.increment())?; self.parse(rule.precedence.increment())?;
let (right_instruction, right_position) = let (right_instruction, right_position) =
@ -334,6 +339,12 @@ impl<'src> Parser<'src> {
self.decrement_register()?; self.decrement_register()?;
right_instruction.first_argument() right_instruction.first_argument()
} }
Operation::Close => {
return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
_ => { _ => {
push_back_right = true; push_back_right = true;
@ -431,7 +442,7 @@ impl<'src> Parser<'src> {
} else { } else {
self.emit_instruction( self.emit_instruction(
Instruction::get_local(self.current_register, local_index), Instruction::get_local(self.current_register, local_index),
self.current_position, self.previous_position,
); );
self.increment_register()?; self.increment_register()?;
} }
@ -468,12 +479,34 @@ impl<'src> Parser<'src> {
self.advance()?; self.advance()?;
self.chunk.begin_scope(); self.chunk.begin_scope();
let start = self.current_position.0;
let start_register = self.current_register;
let mut ends_with_semicolon = false;
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() { while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
self.parse_statement()?; self.parse_statement()?;
if self.previous_token == Token::Semicolon {
ends_with_semicolon = true;
}
} }
self.chunk.end_scope(); self.chunk.end_scope();
if self.current_token == Token::Semicolon {
ends_with_semicolon = true;
}
if ends_with_semicolon {
let end = self.current_position.1;
let end_register = self.current_register;
self.emit_instruction(
Instruction::close(start_register, end_register),
Span(start, end),
);
}
Ok(()) Ok(())
} }
@ -521,30 +554,31 @@ impl<'src> Parser<'src> {
fn parse_statement(&mut self) -> Result<(), ParseError> { fn parse_statement(&mut self) -> Result<(), ParseError> {
let start = self.current_position.0; let start = self.current_position.0;
let (is_expression_statement, contains_block) = match self.current_token { let is_expression = match self.current_token {
Token::Let => { Token::Let => {
self.parse_let_statement(true)?; self.parse_let_statement(true)?;
(false, false) false
} }
Token::LeftCurlyBrace => { Token::LeftCurlyBrace => {
self.parse_block(true)?; self.parse_block(true)?;
(true, true) self.previous_token != Token::Semicolon
} }
_ => { _ => {
self.parse_expression()?; self.parse_expression()?;
(true, false) true
} }
}; };
let has_semicolon = self.allow(TokenKind::Semicolon)?; let has_semicolon = self.allow(TokenKind::Semicolon)?;
if is_expression_statement && !contains_block && !has_semicolon { if (!has_semicolon || is_expression) && self.is_eof() {
let end = self.previous_position.1; let end = self.previous_position.1;
self.emit_instruction(Instruction::r#return(), Span(start, end)) self.emit_instruction(Instruction::r#return(), Span(start, end));
} }
Ok(()) Ok(())
} }
@ -580,6 +614,7 @@ impl<'src> Parser<'src> {
.declare_local(identifier, register, self.current_position)?; .declare_local(identifier, register, self.current_position)?;
self.emit_instruction(Instruction::declare_local(register, local_index), position); self.emit_instruction(Instruction::declare_local(register, local_index), position);
self.allow(TokenKind::Semicolon)?;
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
dust_error::AnnotatedError, parse, Chunk, ChunkError, DustError, Identifier, Instruction, dust_error::AnnotatedError, parse, Chunk, ChunkError, DustError, Identifier, Instruction,
Operation, Span, Value, ValueError, Local, Operation, Span, Value, ValueError,
}; };
pub fn run(source: &str) -> Result<Option<Value>, DustError> { pub fn run(source: &str) -> Result<Option<Value>, DustError> {
@ -49,6 +49,12 @@ impl Vm {
vm.chunk vm.chunk
.take_constant(instruction.second_argument(), position)? .take_constant(instruction.second_argument(), position)?
} else { } else {
if let Operation::GetLocal = instruction.operation() {
println!("GetLocal: {}", instruction);
}
println!("{}", instruction);
vm.clone(instruction.second_argument(), position)? vm.clone(instruction.second_argument(), position)?
}; };
@ -110,15 +116,8 @@ impl Vm {
Operation::GetLocal => { Operation::GetLocal => {
let register_index = instruction.destination(); let register_index = instruction.destination();
let local_index = instruction.first_argument(); let local_index = instruction.first_argument();
let local = self.chunk.get_local(local_index, position)?; let local = self.chunk.get_local(local_index, position)?.clone();
let value = if let Some(value_index) = &local.register_index { let value = self.clone_as_variable(local, position)?;
self.clone(*value_index, position)?
} else {
return Err(VmError::UndefinedVariable {
identifier: local.identifier.clone(),
position,
});
};
self.insert(value, register_index, position)?; self.insert(value, register_index, position)?;
} }
@ -170,19 +169,19 @@ impl Vm {
} }
Operation::And => { Operation::And => {
let (left, right) = take_constants_or_clone(self, instruction, position)?; let (left, right) = take_constants_or_clone(self, instruction, position)?;
let result = left let and = left
.and(&right) .and(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(result, instruction.destination(), position)?; self.insert(and, instruction.destination(), position)?;
} }
Operation::Or => { Operation::Or => {
let (left, right) = take_constants_or_clone(self, instruction, position)?; let (left, right) = take_constants_or_clone(self, instruction, position)?;
let result = left let or = left
.or(&right) .or(&right)
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(result, instruction.destination(), position)?; self.insert(or, instruction.destination(), position)?;
} }
Operation::Negate => { Operation::Negate => {
let value = if instruction.first_argument_is_constant() { let value = if instruction.first_argument_is_constant() {
@ -204,11 +203,11 @@ impl Vm {
} else { } else {
self.clone(instruction.first_argument(), position)? self.clone(instruction.first_argument(), position)?
}; };
let result = value let not = value
.not() .not()
.map_err(|error| VmError::Value { error, position })?; .map_err(|error| VmError::Value { error, position })?;
self.insert(result, instruction.destination(), position)?; self.insert(not, instruction.destination(), position)?;
} }
Operation::Return => { Operation::Return => {
let value = self.pop(position)?; let value = self.pop(position)?;
@ -259,6 +258,27 @@ impl Vm {
} }
} }
fn clone_as_variable(&mut self, local: Local, position: Span) -> Result<Value, VmError> {
let index = if let Some(index) = local.register_index {
index
} else {
return Err(VmError::UndefinedVariable {
identifier: local.identifier.clone(),
position,
});
};
let clone_result = self.clone(index, position);
match clone_result {
Ok(value) => Ok(value),
Err(VmError::EmptyRegister { .. }) => Err(VmError::UndefinedVariable {
identifier: local.identifier,
position,
}),
_ => clone_result,
}
}
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 {
@ -300,9 +320,6 @@ pub enum VmError {
StackUnderflow { StackUnderflow {
position: Span, position: Span,
}, },
UndeclaredVariable {
position: Span,
},
UndefinedVariable { UndefinedVariable {
identifier: Identifier, identifier: Identifier,
position: Span, position: Span,
@ -334,10 +351,9 @@ impl AnnotatedError for VmError {
Self::InvalidInstruction { .. } => "Invalid instruction", Self::InvalidInstruction { .. } => "Invalid instruction",
Self::StackOverflow { .. } => "Stack overflow", Self::StackOverflow { .. } => "Stack overflow",
Self::StackUnderflow { .. } => "Stack underflow", Self::StackUnderflow { .. } => "Stack underflow",
Self::UndeclaredVariable { .. } => "Undeclared variable",
Self::UndefinedVariable { .. } => "Undefined variable", Self::UndefinedVariable { .. } => "Undefined variable",
Self::Chunk(error) => error.description(),
Self::Value { .. } => "Value error", Self::Value { .. } => "Value error",
Self::Chunk(error) => error.description(),
} }
} }
@ -360,7 +376,6 @@ impl AnnotatedError for VmError {
Self::InvalidInstruction { position, .. } => *position, Self::InvalidInstruction { position, .. } => *position,
Self::StackUnderflow { position } => *position, Self::StackUnderflow { position } => *position,
Self::StackOverflow { position } => *position, Self::StackOverflow { position } => *position,
Self::UndeclaredVariable { position } => *position,
Self::UndefinedVariable { position, .. } => *position, Self::UndefinedVariable { position, .. } => *position,
Self::Chunk(error) => error.position(), Self::Chunk(error) => error.position(),
Self::Value { position, .. } => *position, Self::Value { position, .. } => *position,