diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index dde75c3..1916ac9 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -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; diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index d1cdfe6..90871bd 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -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(()) } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index b71c86d..906135d 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -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, 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 { + 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 { 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,