Implement better closing for blocks
This commit is contained in:
parent
0a16c5e0ca
commit
fa4c2d48a3
@ -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;
|
||||||
|
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user