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> {
let index = index as usize;

View File

@ -304,6 +304,12 @@ impl<'src> Parser<'src> {
self.decrement_register()?;
left_instruction.first_argument()
}
Operation::Close => {
return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
_ => {
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_position = self.current_position;
let rule = ParseRule::from(&operator.kind());
self.advance()?;
self.parse(rule.precedence.increment())?;
let (right_instruction, right_position) =
@ -334,6 +339,12 @@ impl<'src> Parser<'src> {
self.decrement_register()?;
right_instruction.first_argument()
}
Operation::Close => {
return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
_ => {
push_back_right = true;
@ -431,7 +442,7 @@ impl<'src> Parser<'src> {
} else {
self.emit_instruction(
Instruction::get_local(self.current_register, local_index),
self.current_position,
self.previous_position,
);
self.increment_register()?;
}
@ -468,12 +479,34 @@ impl<'src> Parser<'src> {
self.advance()?;
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() {
self.parse_statement()?;
if self.previous_token == Token::Semicolon {
ends_with_semicolon = true;
}
}
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(())
}
@ -521,30 +554,31 @@ impl<'src> Parser<'src> {
fn parse_statement(&mut self) -> Result<(), ParseError> {
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 => {
self.parse_let_statement(true)?;
(false, false)
false
}
Token::LeftCurlyBrace => {
self.parse_block(true)?;
(true, true)
self.previous_token != Token::Semicolon
}
_ => {
self.parse_expression()?;
(true, false)
true
}
};
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;
self.emit_instruction(Instruction::r#return(), Span(start, end))
self.emit_instruction(Instruction::r#return(), Span(start, end));
}
Ok(())
}
@ -580,6 +614,7 @@ impl<'src> Parser<'src> {
.declare_local(identifier, register, self.current_position)?;
self.emit_instruction(Instruction::declare_local(register, local_index), position);
self.allow(TokenKind::Semicolon)?;
Ok(())
}

View File

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