diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index ff23333..175ac35 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -3,10 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter}; use colored::Colorize; use serde::{Deserialize, Serialize}; -use crate::{ - value::ValueKind, AnnotatedError, Function, Identifier, Instruction, Operation, Span, Type, - Value, -}; +use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Type, Value}; #[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)] pub struct Chunk { @@ -222,6 +219,14 @@ impl Chunk { register_index: u8, position: Span, ) -> Result { + log::debug!( + "Declaring local: {:?} {:?} {:?} {:?}", + identifier, + r#type, + is_mutable, + register_index + ); + let starting_length = self.locals.len(); if starting_length + 1 > (u8::MAX as usize) { diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index dfde385..7bb6a04 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -305,6 +305,39 @@ impl Instruction { self } + pub fn is_expression(&self) -> bool { + let operation = self.operation(); + + if operation.is_math() { + return if !self.b_is_constant() { + self.a() != self.b() + } else if !self.c_is_constant() { + self.a() != self.c() + } else { + true + }; + } + + matches!( + operation, + Operation::Not + | Operation::Negate + | Operation::Equal + | Operation::Less + | Operation::LessEqual + | Operation::Add + | Operation::Subtract + | Operation::Multiply + | Operation::Divide + | Operation::Modulo + | Operation::Test + | Operation::GetLocal + | Operation::LoadBoolean + | Operation::LoadConstant + | Operation::LoadList + ) + } + pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> (Option, Option) { let format_arguments = || { let first_argument = if self.b_is_constant() { diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index d1bed95..3b4c086 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -4,6 +4,8 @@ //! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions //! - [`Lexer`], which lexes the input a token at a time +use serde::{Deserialize, Serialize}; + use crate::{dust_error::AnnotatedError, Span, Token}; /// Lexes the input and return a vector of tokens and their positions. @@ -78,7 +80,7 @@ pub fn lex<'chars, 'src: 'chars>( /// ] /// ) /// ``` -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Lexer<'src> { source: &'src str, position: usize, @@ -543,6 +545,7 @@ impl<'src> Lexer<'src> { "loop" => Token::Loop, "map" => Token::Map, "mut" => Token::Mut, + "return" => Token::Return, "str" => Token::Str, "struct" => Token::Struct, "true" => Token::Boolean("true"), diff --git a/dust-lang/src/operation.rs b/dust-lang/src/operation.rs index 6343f69..cf43bff 100644 --- a/dust-lang/src/operation.rs +++ b/dust-lang/src/operation.rs @@ -82,6 +82,17 @@ impl Operation { | Operation::Modulo ) } + + pub fn is_comparison(&self) -> bool { + matches!( + self, + Operation::Equal | Operation::Less | Operation::LessEqual + ) + } + + pub fn is_test(&self) -> bool { + matches!(self, Operation::Test | Operation::TestSet) + } } impl From for Operation { diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 6a15202..6759dfe 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -5,6 +5,7 @@ use std::{ }; use colored::Colorize; +use serde::{Deserialize, Serialize}; use crate::{ AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer, @@ -17,18 +18,21 @@ pub fn parse(source: &str) -> Result { while !parser.is_eof() { parser - .parse_statement(Allowed { - assignment: true, - explicit_return: false, - implicit_return: true, - }) + .parse_statement( + Allowed { + assignment: true, + explicit_return: false, + implicit_return: true, + }, + Context::None, + ) .map_err(|error| DustError::Parse { error, source })?; } Ok(parser.take_chunk()) } -#[derive(Debug)] +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize)] pub struct Parser<'src> { chunk: Chunk, lexer: Lexer<'src>, @@ -106,7 +110,7 @@ impl<'src> Parser<'src> { let (new_token, position) = self.lexer.next_token()?; log::info!( - "{} at {}", + "Parsing {} at {}", new_token.to_string().bold(), position.to_string() ); @@ -140,6 +144,12 @@ impl<'src> Parser<'src> { } fn emit_instruction(&mut self, instruction: Instruction, position: Span) { + log::debug!( + "Emitting {} at {}", + instruction.operation().to_string().bold(), + position.to_string() + ); + self.chunk.push_instruction(instruction, position); } @@ -266,7 +276,14 @@ impl<'src> Parser<'src> { fn parse_grouped(&mut self, _: Allowed) -> Result<(), ParseError> { self.allow(TokenKind::LeftParenthesis)?; - self.parse(Precedence::Assignment)?; // Do not allow assignment + self.parse_statement( + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + Context::None, + )?; self.expect(TokenKind::RightParenthesis) } @@ -275,7 +292,14 @@ impl<'src> Parser<'src> { let operator_position = self.current_position; self.advance()?; - self.parse(Precedence::Assignment)?; // Do not allow assignment + self.parse_statement( + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + Context::None, + )?; let (previous_instruction, previous_position) = self.chunk.pop_instruction(self.current_position)?; @@ -389,7 +413,14 @@ impl<'src> Parser<'src> { } self.advance()?; - self.parse(rule.precedence.increment())?; + self.parse( + rule.precedence.increment(), + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + )?; let (right_instruction, right_position) = self.chunk.pop_instruction(self.current_position)?; @@ -495,13 +526,29 @@ impl<'src> Parser<'src> { let operator = self.current_token; let operator_position = self.current_position; let rule = ParseRule::from(&operator.kind()); - let mut instruction = match self.current_token.kind() { - TokenKind::DoubleEqual => Instruction::equal(true, left.saturating_sub(1), 0), - TokenKind::BangEqual => Instruction::equal(false, left.saturating_sub(1), 0), - TokenKind::Less => Instruction::less(true, left.saturating_sub(1), 0), - TokenKind::LessEqual => Instruction::less_equal(true, left.saturating_sub(1), 0), - TokenKind::Greater => Instruction::less_equal(false, left.saturating_sub(1), 0), - TokenKind::GreaterEqual => Instruction::less(false, left.saturating_sub(1), 0), + + self.advance()?; + self.parse( + rule.precedence.increment(), + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + )?; + + let (right_instruction, right_position) = + self.chunk.pop_instruction(self.current_position)?; + let (push_back_right, right_is_constant, _, right) = + self.handle_binary_argument(&right_instruction)?; + + let mut instruction = match operator { + Token::DoubleEqual => Instruction::equal(true, left.saturating_sub(1), right), + Token::BangEqual => Instruction::equal(false, left.saturating_sub(1), right), + Token::Less => Instruction::less(true, left.saturating_sub(1), right), + Token::LessEqual => Instruction::less_equal(true, left.saturating_sub(1), right), + Token::Greater => Instruction::less_equal(false, left.saturating_sub(1), right), + Token::GreaterEqual => Instruction::less(false, left.saturating_sub(1), right), _ => { return Err(ParseError::ExpectedTokenMultiple { expected: &[ @@ -512,22 +559,12 @@ impl<'src> Parser<'src> { TokenKind::Greater, TokenKind::GreaterEqual, ], - found: self.current_token.to_owned(), - position: self.current_position, + found: operator.to_owned(), + position: operator_position, }) } }; - self.advance()?; - self.parse(rule.precedence.increment())?; - - let (right_instruction, right_position) = - self.chunk.pop_instruction(self.current_position)?; - let (push_back_right, right_is_constant, _, right) = - self.handle_binary_argument(&right_instruction)?; - - instruction.set_c(right); - if left_is_constant { instruction.set_b_is_constant(); } @@ -572,7 +609,14 @@ impl<'src> Parser<'src> { self.increment_register()?; self.advance()?; - self.parse(rule.precedence.increment())?; + self.parse( + rule.precedence.increment(), + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + )?; let (right_instruction, right_position) = self.chunk.pop_instruction(self.current_position)?; @@ -593,7 +637,14 @@ impl<'src> Parser<'src> { let local_index = self.parse_identifier_from(token, start_position)?; - if allowed.assignment && self.allow(TokenKind::Equal)? { + if self.allow(TokenKind::Equal)? { + if !allowed.assignment { + return Err(ParseError::InvalidAssignmentTarget { + found: self.current_token.to_owned(), + position: self.current_position, + }); + } + let is_mutable = self .chunk .get_local(local_index, start_position)? @@ -606,7 +657,14 @@ impl<'src> Parser<'src> { }); } - self.parse(Precedence::Assignment)?; // Do not allow assignment + self.parse_statement( + Allowed { + assignment: false, + explicit_return: true, + implicit_return: false, + }, + Context::Assignment, + )?; let (mut previous_instruction, previous_position) = self.chunk.pop_instruction(self.current_position)?; @@ -618,7 +676,7 @@ impl<'src> Parser<'src> { .register_index; if let Some(register_index) = previous_register { - log::trace!("Condensing SET_LOCAL to binary expression"); + log::trace!("Condensing SET_LOCAL to binary math expression"); previous_instruction.set_a(register_index); self.emit_instruction(previous_instruction, self.current_position); @@ -649,7 +707,7 @@ impl<'src> Parser<'src> { if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) { Ok(local_index) } else { - Err(ParseError::UndefinedVariable { + Err(ParseError::UndeclaredVariable { identifier, position, }) @@ -687,7 +745,7 @@ impl<'src> Parser<'src> { self.chunk.begin_scope(); while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() { - self.parse_statement(allowed)?; + self.parse_statement(allowed, Context::None)?; } self.chunk.end_scope(); @@ -705,7 +763,14 @@ impl<'src> Parser<'src> { while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() { let next_register = self.current_register; - self.parse(Precedence::Assignment)?; // Do not allow assignment + self.parse_statement( + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + Context::None, + )?; if let Operation::LoadConstant = self.chunk.get_last_operation()? { self.increment_register()?; @@ -732,12 +797,21 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_if(&mut self, mut allowed: Allowed) -> Result<(), ParseError> { - allowed.implicit_return = false; + fn parse_if(&mut self, allowed: Allowed) -> Result<(), ParseError> { let length = self.chunk.len(); + let expression_allowed = Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }; + let block_allowed = Allowed { + assignment: allowed.assignment, + explicit_return: allowed.explicit_return, + implicit_return: false, + }; self.advance()?; - self.parse(Precedence::Assignment)?; // Do not allow assignment + self.parse_statement(expression_allowed, Context::None)?; let is_explicit_boolean = matches!(self.previous_token, Token::Boolean(_)) && length == self.chunk.len() - 1; @@ -750,7 +824,7 @@ impl<'src> Parser<'src> { } if let Token::LeftCurlyBrace = self.current_token { - self.parse_block(allowed)?; + self.parse_block(block_allowed)?; } let last_operation = self.chunk.get_last_operation()?; @@ -772,21 +846,31 @@ impl<'src> Parser<'src> { } if let Token::LeftCurlyBrace = self.current_token { - self.parse_block(allowed)?; + self.parse_block(block_allowed)?; } } Ok(()) } - fn parse_while(&mut self, mut allowed: Allowed) -> Result<(), ParseError> { + fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> { self.advance()?; - allowed.implicit_return = false; let jump_start = self.chunk.len(); - self.parse(Precedence::Assignment)?; // Do not allow assignment - self.parse_block(allowed)?; + self.parse_statement( + Allowed { + assignment: false, + explicit_return: false, + implicit_return: false, + }, + Context::None, + )?; + self.parse_block(Allowed { + assignment: true, + explicit_return: allowed.explicit_return, + implicit_return: false, + })?; let jump_end = self.chunk.len(); let jump_distance = jump_end.abs_diff(jump_start) as u8; @@ -807,8 +891,8 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse_expression(&mut self) -> Result<(), ParseError> { - self.parse(Precedence::None)?; + fn parse_statement(&mut self, allowed: Allowed, context: Context) -> Result<(), ParseError> { + self.parse(Precedence::None, allowed)?; if let [Some((jump, _)), Some((comparison, comparison_position))] = self.chunk.get_last_n_instructions() @@ -816,47 +900,55 @@ impl<'src> Parser<'src> { if let (Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual) = (jump.operation(), comparison.operation()) { - let comparison_position = *comparison_position; + if matches!(self.current_token, Token::Eof) || context == Context::Assignment { + let comparison_position = *comparison_position; - self.emit_instruction( - Instruction::load_boolean(self.current_register, true, true), - comparison_position, - ); - self.emit_instruction( - Instruction::load_boolean(self.current_register, false, false), - comparison_position, - ); + self.emit_instruction( + Instruction::load_boolean(self.current_register, true, true), + comparison_position, + ); + self.emit_instruction( + Instruction::load_boolean(self.current_register, false, false), + comparison_position, + ); + } } } + let is_expression = self.chunk.get_last_instruction()?.0.is_expression(); + let has_semicolon = self.allow(TokenKind::Semicolon)?; + + if !has_semicolon && is_expression && allowed.implicit_return { + self.emit_instruction(Instruction::r#return(), self.current_position); + } + Ok(()) } - fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> { - match self.current_token { - Token::Let => { - self.parse_let_statement(Allowed { - assignment: true, + fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> { + if !allowed.explicit_return { + return Err(ParseError::UnexpectedReturn { + position: self.current_position, + }); + } + + self.advance()?; + + if !matches!( + self.current_token, + Token::Semicolon | Token::RightCurlyBrace + ) { + self.parse_statement( + Allowed { + assignment: false, explicit_return: false, implicit_return: false, - })?; - self.allow(TokenKind::Semicolon)?; - } - Token::LeftCurlyBrace => { - self.parse_block(allowed)?; - self.allow(TokenKind::Semicolon)?; - } - _ => { - self.parse_expression()?; + }, + Context::None, + )?; + } - if allowed.implicit_return - && !self.allow(TokenKind::Semicolon)? - && (self.is_eof() || matches!(self.current_token, Token::RightCurlyBrace)) - { - self.emit_instruction(Instruction::r#return(), self.current_position); - } - } - }; + self.emit_instruction(Instruction::r#return(), self.current_position); Ok(()) } @@ -869,7 +961,7 @@ impl<'src> Parser<'src> { }); } - self.expect(TokenKind::Let)?; + self.advance()?; let is_mutable = self.allow(TokenKind::Mut)?; let position = self.current_position; @@ -881,43 +973,43 @@ impl<'src> Parser<'src> { return Err(ParseError::ExpectedToken { expected: TokenKind::Identifier, found: self.current_token.to_owned(), - position: self.current_position, + position, }); }; - let explicit_type = if self.allow(TokenKind::Colon)? { - Some(self.parse_type_from(self.current_token, self.current_position)?) + let r#type = if self.allow(TokenKind::Colon)? { + let r#type = self.parse_type_from(self.current_token, self.current_position)?; + + self.advance()?; + + Some(r#type) } else { None }; - let register = self.current_register; self.expect(TokenKind::Equal)?; - self.parse_expression()?; + + self.parse_statement( + Allowed { + assignment: false, + explicit_return: true, + implicit_return: false, + }, + Context::Assignment, + )?; if self.current_register == register { self.increment_register()?; } - let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?; + let local_index = self + .chunk + .declare_local(identifier, r#type, is_mutable, register, position)?; - if let Operation::LoadConstant | Operation::LoadBoolean | Operation::Add = - previous_instruction.operation() - { - let register = previous_instruction.a(); - let local_index = self.chunk.declare_local( - identifier, - explicit_type, - is_mutable, - register, - *previous_position, - )?; - - self.emit_instruction( - Instruction::define_local(register, local_index, is_mutable), - position, - ); - } + self.emit_instruction( + Instruction::define_local(register, local_index, is_mutable), + position, + ); Ok(()) } @@ -974,11 +1066,14 @@ impl<'src> Parser<'src> { function_parser.expect(TokenKind::LeftCurlyBrace)?; while function_parser.current_token != Token::RightCurlyBrace { - function_parser.parse_statement(Allowed { - assignment: true, - explicit_return: true, - implicit_return: true, - })?; + function_parser.parse_statement( + Allowed { + assignment: true, + explicit_return: true, + implicit_return: true, + }, + Context::None, + )?; } function_parser.advance()?; @@ -997,26 +1092,14 @@ impl<'src> Parser<'src> { Ok(()) } - fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> { - let allow_assignment = precedence < Precedence::Assignment; - let allow_return = precedence == Precedence::None; - let mut parsed = false; - + fn parse(&mut self, precedence: Precedence, allowed: Allowed) -> Result<(), ParseError> { if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix { log::debug!( "{} is {precedence} prefix", self.current_token.to_string().bold(), ); - prefix_parser( - self, - Allowed { - assignment: true, - explicit_return: allow_return, - implicit_return: allow_return, - }, - )?; - parsed = true; + prefix_parser(self, allowed)?; } let mut infix_rule = ParseRule::from(&self.current_token.kind()); @@ -1028,7 +1111,7 @@ impl<'src> Parser<'src> { self.current_token.to_string().bold(), ); - if allow_assignment && self.current_token == Token::Equal { + if !allowed.assignment && self.current_token == Token::Equal { return Err(ParseError::InvalidAssignmentTarget { found: self.current_token.to_owned(), position: self.current_position, @@ -1041,38 +1124,9 @@ impl<'src> Parser<'src> { } infix_rule = ParseRule::from(&self.current_token.kind()); - parsed = true; } - if parsed { - Ok(()) - } else { - Err(ParseError::ExpectedTokenMultiple { - expected: &[ - // This should list all infix operators and the semicolon token - TokenKind::BangEqual, - TokenKind::DoubleAmpersand, - TokenKind::DoublePipe, - TokenKind::DoubleEqual, - TokenKind::Greater, - TokenKind::GreaterEqual, - TokenKind::Less, - TokenKind::LessEqual, - TokenKind::Minus, - TokenKind::MinusEqual, - TokenKind::Percent, - TokenKind::Plus, - TokenKind::PlusEqual, - TokenKind::Star, - TokenKind::StarEqual, - TokenKind::Semicolon, - TokenKind::Slash, - TokenKind::SlashEqual, - ], - found: self.current_token.to_owned(), - position: self.current_position, - }) - } + Ok(()) } } @@ -1117,18 +1171,24 @@ impl Display for Precedence { } } +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum Context { + None, + Assignment, +} + #[derive(Debug, Clone, Copy)] struct Allowed { - assignment: bool, - explicit_return: bool, - implicit_return: bool, + pub assignment: bool, + pub explicit_return: bool, + pub implicit_return: bool, } type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>; type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>; #[derive(Debug, Clone, Copy)] -pub struct ParseRule<'a> { +struct ParseRule<'a> { pub prefix: Option>, pub infix: Option>, pub precedence: Precedence, @@ -1302,6 +1362,11 @@ impl From<&TokenKind> for ParseRule<'_> { infix: Some(Parser::parse_math_binary), precedence: Precedence::Assignment, }, + TokenKind::Return => ParseRule { + prefix: Some(Parser::parse_return), + infix: None, + precedence: Precedence::None, + }, TokenKind::RightCurlyBrace => ParseRule { prefix: None, infix: None, @@ -1386,10 +1451,13 @@ pub enum ParseError { found: TokenOwned, position: Span, }, - UndefinedVariable { + UndeclaredVariable { identifier: Identifier, position: Span, }, + UnexpectedReturn { + position: Span, + }, RegisterOverflow { position: Span, }, @@ -1429,7 +1497,8 @@ impl AnnotatedError for ParseError { Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens", Self::ExpectedMutableVariable { .. } => "Expected a mutable variable", Self::InvalidAssignmentTarget { .. } => "Invalid assignment target", - Self::UndefinedVariable { .. } => "Undefined variable", + Self::UndeclaredVariable { .. } => "Undeclared variable", + Self::UnexpectedReturn { .. } => "Unexpected return", Self::RegisterOverflow { .. } => "Register overflow", Self::RegisterUnderflow { .. } => "Register underflow", Self::ParseFloatError { .. } => "Failed to parse float", @@ -1475,9 +1544,10 @@ impl AnnotatedError for ParseError { Self::InvalidAssignmentTarget { found, .. } => { Some(format!("Invalid assignment target, found {found}")) } - Self::UndefinedVariable { identifier, .. } => { - Some(format!("Undefined variable {identifier}")) + Self::UndeclaredVariable { identifier, .. } => { + Some(format!("Undeclared variable {identifier}")) } + Self::UnexpectedReturn { .. } => None, Self::RegisterOverflow { .. } => None, Self::RegisterUnderflow { .. } => None, Self::ParseFloatError { error, .. } => Some(error.to_string()), @@ -1495,7 +1565,8 @@ impl AnnotatedError for ParseError { Self::ExpectedTokenMultiple { position, .. } => *position, Self::ExpectedMutableVariable { position, .. } => *position, Self::InvalidAssignmentTarget { position, .. } => *position, - Self::UndefinedVariable { position, .. } => *position, + Self::UndeclaredVariable { position, .. } => *position, + Self::UnexpectedReturn { position } => *position, Self::RegisterOverflow { position } => *position, Self::RegisterUnderflow { position } => *position, Self::ParseFloatError { position, .. } => *position, diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index 0728ff5..936be11 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -1,8 +1,10 @@ //! Token, TokenOwned and TokenKind types. use std::fmt::{self, Display, Formatter}; +use serde::{Deserialize, Serialize}; + /// Source code token. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum Token<'src> { // End of file Eof, @@ -29,6 +31,7 @@ pub enum Token<'src> { Loop, Map, Mut, + Return, Str, Struct, While, @@ -115,6 +118,7 @@ impl<'src> Token<'src> { Token::Percent => 1, Token::Plus => 1, Token::PlusEqual => 2, + Token::Return => 6, Token::RightCurlyBrace => 1, Token::RightParenthesis => 1, Token::RightSquareBrace => 1, @@ -169,6 +173,7 @@ impl<'src> Token<'src> { Token::Percent => TokenOwned::Percent, Token::Plus => TokenOwned::Plus, Token::PlusEqual => TokenOwned::PlusEqual, + Token::Return => TokenOwned::Return, Token::RightCurlyBrace => TokenOwned::RightCurlyBrace, Token::RightParenthesis => TokenOwned::RightParenthesis, Token::RightSquareBrace => TokenOwned::RightSquareBrace, @@ -227,6 +232,7 @@ impl<'src> Token<'src> { Token::Percent => TokenKind::Percent, Token::Plus => TokenKind::Plus, Token::PlusEqual => TokenKind::PlusEqual, + Token::Return => TokenKind::Return, Token::RightCurlyBrace => TokenKind::RightCurlyBrace, Token::RightParenthesis => TokenKind::RightParenthesis, Token::RightSquareBrace => TokenKind::RightSquareBrace, @@ -287,6 +293,7 @@ impl<'src> Display for Token<'src> { Token::Percent => write!(f, "%"), Token::Plus => write!(f, "+"), Token::PlusEqual => write!(f, "+="), + Token::Return => write!(f, "return"), Token::RightCurlyBrace => write!(f, "}}"), Token::RightParenthesis => write!(f, ")"), Token::RightSquareBrace => write!(f, "]"), @@ -332,6 +339,7 @@ pub enum TokenOwned { Loop, Map, Mut, + Return, Str, While, @@ -414,6 +422,7 @@ impl Display for TokenOwned { TokenOwned::Percent => Token::Percent.fmt(f), TokenOwned::Plus => Token::Plus.fmt(f), TokenOwned::PlusEqual => Token::PlusEqual.fmt(f), + TokenOwned::Return => Token::Return.fmt(f), TokenOwned::RightCurlyBrace => Token::RightCurlyBrace.fmt(f), TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f), TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f), @@ -457,6 +466,7 @@ pub enum TokenKind { Let, Loop, Map, + Return, Str, While, @@ -539,6 +549,7 @@ impl Display for TokenKind { TokenKind::Percent => Token::Percent.fmt(f), TokenKind::Plus => Token::Plus.fmt(f), TokenKind::PlusEqual => Token::PlusEqual.fmt(f), + TokenKind::Return => Token::Return.fmt(f), TokenKind::RightCurlyBrace => Token::RightCurlyBrace.fmt(f), TokenKind::RightParenthesis => Token::RightParenthesis.fmt(f), TokenKind::RightSquareBrace => Token::RightSquareBrace.fmt(f), diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs index 2b5d2b1..7516cc1 100644 --- a/dust-lang/tests/expressions.rs +++ b/dust-lang/tests/expressions.rs @@ -270,7 +270,7 @@ fn equality_assignment_long() { #[test] fn equality_assignment_short() { - let source = "let a = 4 == 4; a"; + let source = "let a = 4 == 4 a"; assert_eq!( parse(source), @@ -286,8 +286,8 @@ fn equality_assignment_short() { (Instruction::load_boolean(0, true, true), Span(10, 12)), (Instruction::load_boolean(0, false, false), Span(10, 12)), (Instruction::define_local(0, 0, false), Span(4, 5)), - (Instruction::get_local(1, 0), Span(16, 17)), - (Instruction::r#return(), Span(17, 17)), + (Instruction::get_local(1, 0), Span(15, 16)), + (Instruction::r#return(), Span(16, 16)), ], vec![Value::integer(4), Value::integer(4)], vec![Local::new(Identifier::new("a"), None, false, 0, Some(0))]