Refactor
This commit is contained in:
parent
259721f6cb
commit
b6c3b1e5ba
@ -3,10 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Type, Value};
|
||||||
value::ValueKind, AnnotatedError, Function, Identifier, Instruction, Operation, Span, Type,
|
|
||||||
Value,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
@ -222,6 +219,14 @@ impl Chunk {
|
|||||||
register_index: u8,
|
register_index: u8,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u8, ChunkError> {
|
) -> Result<u8, ChunkError> {
|
||||||
|
log::debug!(
|
||||||
|
"Declaring local: {:?} {:?} {:?} {:?}",
|
||||||
|
identifier,
|
||||||
|
r#type,
|
||||||
|
is_mutable,
|
||||||
|
register_index
|
||||||
|
);
|
||||||
|
|
||||||
let starting_length = self.locals.len();
|
let starting_length = self.locals.len();
|
||||||
|
|
||||||
if starting_length + 1 > (u8::MAX as usize) {
|
if starting_length + 1 > (u8::MAX as usize) {
|
||||||
|
@ -305,6 +305,39 @@ impl Instruction {
|
|||||||
self
|
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<String>, Option<isize>) {
|
pub fn disassembly_info(&self, chunk: Option<&Chunk>) -> (Option<String>, Option<isize>) {
|
||||||
let format_arguments = || {
|
let format_arguments = || {
|
||||||
let first_argument = if self.b_is_constant() {
|
let first_argument = if self.b_is_constant() {
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
//! - [`lex`], which lexes the entire input and returns a vector of tokens and their positions
|
//! - [`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
|
//! - [`Lexer`], which lexes the input a token at a time
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{dust_error::AnnotatedError, Span, Token};
|
use crate::{dust_error::AnnotatedError, Span, Token};
|
||||||
|
|
||||||
/// Lexes the input and return a vector of tokens and their positions.
|
/// 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> {
|
pub struct Lexer<'src> {
|
||||||
source: &'src str,
|
source: &'src str,
|
||||||
position: usize,
|
position: usize,
|
||||||
@ -543,6 +545,7 @@ impl<'src> Lexer<'src> {
|
|||||||
"loop" => Token::Loop,
|
"loop" => Token::Loop,
|
||||||
"map" => Token::Map,
|
"map" => Token::Map,
|
||||||
"mut" => Token::Mut,
|
"mut" => Token::Mut,
|
||||||
|
"return" => Token::Return,
|
||||||
"str" => Token::Str,
|
"str" => Token::Str,
|
||||||
"struct" => Token::Struct,
|
"struct" => Token::Struct,
|
||||||
"true" => Token::Boolean("true"),
|
"true" => Token::Boolean("true"),
|
||||||
|
@ -82,6 +82,17 @@ impl Operation {
|
|||||||
| Operation::Modulo
|
| 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<u8> for Operation {
|
impl From<u8> for Operation {
|
||||||
|
@ -5,6 +5,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer,
|
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer,
|
||||||
@ -17,18 +18,21 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
|||||||
|
|
||||||
while !parser.is_eof() {
|
while !parser.is_eof() {
|
||||||
parser
|
parser
|
||||||
.parse_statement(Allowed {
|
.parse_statement(
|
||||||
|
Allowed {
|
||||||
assignment: true,
|
assignment: true,
|
||||||
explicit_return: false,
|
explicit_return: false,
|
||||||
implicit_return: true,
|
implicit_return: true,
|
||||||
})
|
},
|
||||||
|
Context::None,
|
||||||
|
)
|
||||||
.map_err(|error| DustError::Parse { error, source })?;
|
.map_err(|error| DustError::Parse { error, source })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(parser.take_chunk())
|
Ok(parser.take_chunk())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize)]
|
||||||
pub struct Parser<'src> {
|
pub struct Parser<'src> {
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
lexer: Lexer<'src>,
|
lexer: Lexer<'src>,
|
||||||
@ -106,7 +110,7 @@ impl<'src> Parser<'src> {
|
|||||||
let (new_token, position) = self.lexer.next_token()?;
|
let (new_token, position) = self.lexer.next_token()?;
|
||||||
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"{} at {}",
|
"Parsing {} at {}",
|
||||||
new_token.to_string().bold(),
|
new_token.to_string().bold(),
|
||||||
position.to_string()
|
position.to_string()
|
||||||
);
|
);
|
||||||
@ -140,6 +144,12 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
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);
|
self.chunk.push_instruction(instruction, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,7 +276,14 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
fn parse_grouped(&mut self, _: Allowed) -> Result<(), ParseError> {
|
fn parse_grouped(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
self.allow(TokenKind::LeftParenthesis)?;
|
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)
|
self.expect(TokenKind::RightParenthesis)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +292,14 @@ impl<'src> Parser<'src> {
|
|||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
|
|
||||||
self.advance()?;
|
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) =
|
let (previous_instruction, previous_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -389,7 +413,14 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.advance()?;
|
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) =
|
let (right_instruction, right_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -495,13 +526,29 @@ impl<'src> Parser<'src> {
|
|||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
let rule = ParseRule::from(&operator.kind());
|
let rule = ParseRule::from(&operator.kind());
|
||||||
let mut instruction = match self.current_token.kind() {
|
|
||||||
TokenKind::DoubleEqual => Instruction::equal(true, left.saturating_sub(1), 0),
|
self.advance()?;
|
||||||
TokenKind::BangEqual => Instruction::equal(false, left.saturating_sub(1), 0),
|
self.parse(
|
||||||
TokenKind::Less => Instruction::less(true, left.saturating_sub(1), 0),
|
rule.precedence.increment(),
|
||||||
TokenKind::LessEqual => Instruction::less_equal(true, left.saturating_sub(1), 0),
|
Allowed {
|
||||||
TokenKind::Greater => Instruction::less_equal(false, left.saturating_sub(1), 0),
|
assignment: false,
|
||||||
TokenKind::GreaterEqual => Instruction::less(false, left.saturating_sub(1), 0),
|
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 {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: &[
|
expected: &[
|
||||||
@ -512,22 +559,12 @@ impl<'src> Parser<'src> {
|
|||||||
TokenKind::Greater,
|
TokenKind::Greater,
|
||||||
TokenKind::GreaterEqual,
|
TokenKind::GreaterEqual,
|
||||||
],
|
],
|
||||||
found: self.current_token.to_owned(),
|
found: operator.to_owned(),
|
||||||
position: self.current_position,
|
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 {
|
if left_is_constant {
|
||||||
instruction.set_b_is_constant();
|
instruction.set_b_is_constant();
|
||||||
}
|
}
|
||||||
@ -572,7 +609,14 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
self.advance()?;
|
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) =
|
let (right_instruction, right_position) =
|
||||||
self.chunk.pop_instruction(self.current_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)?;
|
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
|
let is_mutable = self
|
||||||
.chunk
|
.chunk
|
||||||
.get_local(local_index, start_position)?
|
.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) =
|
let (mut previous_instruction, previous_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
@ -618,7 +676,7 @@ impl<'src> Parser<'src> {
|
|||||||
.register_index;
|
.register_index;
|
||||||
|
|
||||||
if let Some(register_index) = previous_register {
|
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);
|
previous_instruction.set_a(register_index);
|
||||||
self.emit_instruction(previous_instruction, self.current_position);
|
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) {
|
if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) {
|
||||||
Ok(local_index)
|
Ok(local_index)
|
||||||
} else {
|
} else {
|
||||||
Err(ParseError::UndefinedVariable {
|
Err(ParseError::UndeclaredVariable {
|
||||||
identifier,
|
identifier,
|
||||||
position,
|
position,
|
||||||
})
|
})
|
||||||
@ -687,7 +745,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.chunk.begin_scope();
|
self.chunk.begin_scope();
|
||||||
|
|
||||||
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
|
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
|
||||||
self.parse_statement(allowed)?;
|
self.parse_statement(allowed, Context::None)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chunk.end_scope();
|
self.chunk.end_scope();
|
||||||
@ -705,7 +763,14 @@ impl<'src> Parser<'src> {
|
|||||||
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
|
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
|
||||||
let next_register = self.current_register;
|
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()? {
|
if let Operation::LoadConstant = self.chunk.get_last_operation()? {
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
@ -732,12 +797,21 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_if(&mut self, mut allowed: Allowed) -> Result<(), ParseError> {
|
fn parse_if(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
allowed.implicit_return = false;
|
|
||||||
let length = self.chunk.len();
|
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.advance()?;
|
||||||
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
self.parse_statement(expression_allowed, Context::None)?;
|
||||||
|
|
||||||
let is_explicit_boolean =
|
let is_explicit_boolean =
|
||||||
matches!(self.previous_token, Token::Boolean(_)) && length == self.chunk.len() - 1;
|
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 {
|
if let Token::LeftCurlyBrace = self.current_token {
|
||||||
self.parse_block(allowed)?;
|
self.parse_block(block_allowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_operation = self.chunk.get_last_operation()?;
|
let last_operation = self.chunk.get_last_operation()?;
|
||||||
@ -772,21 +846,31 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Token::LeftCurlyBrace = self.current_token {
|
if let Token::LeftCurlyBrace = self.current_token {
|
||||||
self.parse_block(allowed)?;
|
self.parse_block(block_allowed)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_while(&mut self, mut allowed: Allowed) -> Result<(), ParseError> {
|
fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
allowed.implicit_return = false;
|
|
||||||
let jump_start = self.chunk.len();
|
let jump_start = self.chunk.len();
|
||||||
|
|
||||||
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
self.parse_statement(
|
||||||
self.parse_block(allowed)?;
|
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_end = self.chunk.len();
|
||||||
let jump_distance = jump_end.abs_diff(jump_start) as u8;
|
let jump_distance = jump_end.abs_diff(jump_start) as u8;
|
||||||
@ -807,8 +891,8 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expression(&mut self) -> Result<(), ParseError> {
|
fn parse_statement(&mut self, allowed: Allowed, context: Context) -> Result<(), ParseError> {
|
||||||
self.parse(Precedence::None)?;
|
self.parse(Precedence::None, allowed)?;
|
||||||
|
|
||||||
if let [Some((jump, _)), Some((comparison, comparison_position))] =
|
if let [Some((jump, _)), Some((comparison, comparison_position))] =
|
||||||
self.chunk.get_last_n_instructions()
|
self.chunk.get_last_n_instructions()
|
||||||
@ -816,6 +900,7 @@ impl<'src> Parser<'src> {
|
|||||||
if let (Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual) =
|
if let (Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual) =
|
||||||
(jump.operation(), comparison.operation())
|
(jump.operation(), comparison.operation())
|
||||||
{
|
{
|
||||||
|
if matches!(self.current_token, Token::Eof) || context == Context::Assignment {
|
||||||
let comparison_position = *comparison_position;
|
let comparison_position = *comparison_position;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
@ -828,35 +913,42 @@ impl<'src> Parser<'src> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
match self.current_token {
|
if !allowed.explicit_return {
|
||||||
Token::Let => {
|
return Err(ParseError::UnexpectedReturn {
|
||||||
self.parse_let_statement(Allowed {
|
position: self.current_position,
|
||||||
assignment: true,
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.advance()?;
|
||||||
|
|
||||||
|
if !matches!(
|
||||||
|
self.current_token,
|
||||||
|
Token::Semicolon | Token::RightCurlyBrace
|
||||||
|
) {
|
||||||
|
self.parse_statement(
|
||||||
|
Allowed {
|
||||||
|
assignment: false,
|
||||||
explicit_return: false,
|
explicit_return: false,
|
||||||
implicit_return: false,
|
implicit_return: false,
|
||||||
})?;
|
},
|
||||||
self.allow(TokenKind::Semicolon)?;
|
Context::None,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Token::LeftCurlyBrace => {
|
|
||||||
self.parse_block(allowed)?;
|
|
||||||
self.allow(TokenKind::Semicolon)?;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.parse_expression()?;
|
|
||||||
|
|
||||||
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -869,7 +961,7 @@ impl<'src> Parser<'src> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expect(TokenKind::Let)?;
|
self.advance()?;
|
||||||
|
|
||||||
let is_mutable = self.allow(TokenKind::Mut)?;
|
let is_mutable = self.allow(TokenKind::Mut)?;
|
||||||
let position = self.current_position;
|
let position = self.current_position;
|
||||||
@ -881,43 +973,43 @@ impl<'src> Parser<'src> {
|
|||||||
return Err(ParseError::ExpectedToken {
|
return Err(ParseError::ExpectedToken {
|
||||||
expected: TokenKind::Identifier,
|
expected: TokenKind::Identifier,
|
||||||
found: self.current_token.to_owned(),
|
found: self.current_token.to_owned(),
|
||||||
position: self.current_position,
|
position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let explicit_type = if self.allow(TokenKind::Colon)? {
|
let r#type = if self.allow(TokenKind::Colon)? {
|
||||||
Some(self.parse_type_from(self.current_token, self.current_position)?)
|
let r#type = self.parse_type_from(self.current_token, self.current_position)?;
|
||||||
|
|
||||||
|
self.advance()?;
|
||||||
|
|
||||||
|
Some(r#type)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let register = self.current_register;
|
let register = self.current_register;
|
||||||
|
|
||||||
self.expect(TokenKind::Equal)?;
|
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 {
|
if self.current_register == register {
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?;
|
let local_index = self
|
||||||
|
.chunk
|
||||||
if let Operation::LoadConstant | Operation::LoadBoolean | Operation::Add =
|
.declare_local(identifier, r#type, is_mutable, register, position)?;
|
||||||
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(
|
self.emit_instruction(
|
||||||
Instruction::define_local(register, local_index, is_mutable),
|
Instruction::define_local(register, local_index, is_mutable),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -974,11 +1066,14 @@ impl<'src> Parser<'src> {
|
|||||||
function_parser.expect(TokenKind::LeftCurlyBrace)?;
|
function_parser.expect(TokenKind::LeftCurlyBrace)?;
|
||||||
|
|
||||||
while function_parser.current_token != Token::RightCurlyBrace {
|
while function_parser.current_token != Token::RightCurlyBrace {
|
||||||
function_parser.parse_statement(Allowed {
|
function_parser.parse_statement(
|
||||||
|
Allowed {
|
||||||
assignment: true,
|
assignment: true,
|
||||||
explicit_return: true,
|
explicit_return: true,
|
||||||
implicit_return: true,
|
implicit_return: true,
|
||||||
})?;
|
},
|
||||||
|
Context::None,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
function_parser.advance()?;
|
function_parser.advance()?;
|
||||||
@ -997,26 +1092,14 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> {
|
fn parse(&mut self, precedence: Precedence, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
let allow_assignment = precedence < Precedence::Assignment;
|
|
||||||
let allow_return = precedence == Precedence::None;
|
|
||||||
let mut parsed = false;
|
|
||||||
|
|
||||||
if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix {
|
if let Some(prefix_parser) = ParseRule::from(&self.current_token.kind()).prefix {
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"{} is {precedence} prefix",
|
"{} is {precedence} prefix",
|
||||||
self.current_token.to_string().bold(),
|
self.current_token.to_string().bold(),
|
||||||
);
|
);
|
||||||
|
|
||||||
prefix_parser(
|
prefix_parser(self, allowed)?;
|
||||||
self,
|
|
||||||
Allowed {
|
|
||||||
assignment: true,
|
|
||||||
explicit_return: allow_return,
|
|
||||||
implicit_return: allow_return,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
parsed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut infix_rule = ParseRule::from(&self.current_token.kind());
|
let mut infix_rule = ParseRule::from(&self.current_token.kind());
|
||||||
@ -1028,7 +1111,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.current_token.to_string().bold(),
|
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 {
|
return Err(ParseError::InvalidAssignmentTarget {
|
||||||
found: self.current_token.to_owned(),
|
found: self.current_token.to_owned(),
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
@ -1041,38 +1124,9 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
infix_rule = ParseRule::from(&self.current_token.kind());
|
infix_rule = ParseRule::from(&self.current_token.kind());
|
||||||
parsed = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if parsed {
|
|
||||||
Ok(())
|
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct Allowed {
|
struct Allowed {
|
||||||
assignment: bool,
|
pub assignment: bool,
|
||||||
explicit_return: bool,
|
pub explicit_return: bool,
|
||||||
implicit_return: bool,
|
pub implicit_return: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>;
|
type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>;
|
||||||
type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>;
|
type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct ParseRule<'a> {
|
struct ParseRule<'a> {
|
||||||
pub prefix: Option<PrefixFunction<'a>>,
|
pub prefix: Option<PrefixFunction<'a>>,
|
||||||
pub infix: Option<InfixFunction<'a>>,
|
pub infix: Option<InfixFunction<'a>>,
|
||||||
pub precedence: Precedence,
|
pub precedence: Precedence,
|
||||||
@ -1302,6 +1362,11 @@ impl From<&TokenKind> for ParseRule<'_> {
|
|||||||
infix: Some(Parser::parse_math_binary),
|
infix: Some(Parser::parse_math_binary),
|
||||||
precedence: Precedence::Assignment,
|
precedence: Precedence::Assignment,
|
||||||
},
|
},
|
||||||
|
TokenKind::Return => ParseRule {
|
||||||
|
prefix: Some(Parser::parse_return),
|
||||||
|
infix: None,
|
||||||
|
precedence: Precedence::None,
|
||||||
|
},
|
||||||
TokenKind::RightCurlyBrace => ParseRule {
|
TokenKind::RightCurlyBrace => ParseRule {
|
||||||
prefix: None,
|
prefix: None,
|
||||||
infix: None,
|
infix: None,
|
||||||
@ -1386,10 +1451,13 @@ pub enum ParseError {
|
|||||||
found: TokenOwned,
|
found: TokenOwned,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
UndefinedVariable {
|
UndeclaredVariable {
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
UnexpectedReturn {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
RegisterOverflow {
|
RegisterOverflow {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
@ -1429,7 +1497,8 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
|
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
|
||||||
Self::ExpectedMutableVariable { .. } => "Expected a mutable variable",
|
Self::ExpectedMutableVariable { .. } => "Expected a mutable variable",
|
||||||
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
Self::UndeclaredVariable { .. } => "Undeclared variable",
|
||||||
|
Self::UnexpectedReturn { .. } => "Unexpected return",
|
||||||
Self::RegisterOverflow { .. } => "Register overflow",
|
Self::RegisterOverflow { .. } => "Register overflow",
|
||||||
Self::RegisterUnderflow { .. } => "Register underflow",
|
Self::RegisterUnderflow { .. } => "Register underflow",
|
||||||
Self::ParseFloatError { .. } => "Failed to parse float",
|
Self::ParseFloatError { .. } => "Failed to parse float",
|
||||||
@ -1475,9 +1544,10 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::InvalidAssignmentTarget { found, .. } => {
|
Self::InvalidAssignmentTarget { found, .. } => {
|
||||||
Some(format!("Invalid assignment target, found {found}"))
|
Some(format!("Invalid assignment target, found {found}"))
|
||||||
}
|
}
|
||||||
Self::UndefinedVariable { identifier, .. } => {
|
Self::UndeclaredVariable { identifier, .. } => {
|
||||||
Some(format!("Undefined variable {identifier}"))
|
Some(format!("Undeclared variable {identifier}"))
|
||||||
}
|
}
|
||||||
|
Self::UnexpectedReturn { .. } => None,
|
||||||
Self::RegisterOverflow { .. } => None,
|
Self::RegisterOverflow { .. } => None,
|
||||||
Self::RegisterUnderflow { .. } => None,
|
Self::RegisterUnderflow { .. } => None,
|
||||||
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
||||||
@ -1495,7 +1565,8 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::ExpectedTokenMultiple { position, .. } => *position,
|
Self::ExpectedTokenMultiple { position, .. } => *position,
|
||||||
Self::ExpectedMutableVariable { position, .. } => *position,
|
Self::ExpectedMutableVariable { position, .. } => *position,
|
||||||
Self::InvalidAssignmentTarget { position, .. } => *position,
|
Self::InvalidAssignmentTarget { position, .. } => *position,
|
||||||
Self::UndefinedVariable { position, .. } => *position,
|
Self::UndeclaredVariable { position, .. } => *position,
|
||||||
|
Self::UnexpectedReturn { position } => *position,
|
||||||
Self::RegisterOverflow { position } => *position,
|
Self::RegisterOverflow { position } => *position,
|
||||||
Self::RegisterUnderflow { position } => *position,
|
Self::RegisterUnderflow { position } => *position,
|
||||||
Self::ParseFloatError { position, .. } => *position,
|
Self::ParseFloatError { position, .. } => *position,
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
//! Token, TokenOwned and TokenKind types.
|
//! Token, TokenOwned and TokenKind types.
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Source code token.
|
/// Source code token.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum Token<'src> {
|
pub enum Token<'src> {
|
||||||
// End of file
|
// End of file
|
||||||
Eof,
|
Eof,
|
||||||
@ -29,6 +31,7 @@ pub enum Token<'src> {
|
|||||||
Loop,
|
Loop,
|
||||||
Map,
|
Map,
|
||||||
Mut,
|
Mut,
|
||||||
|
Return,
|
||||||
Str,
|
Str,
|
||||||
Struct,
|
Struct,
|
||||||
While,
|
While,
|
||||||
@ -115,6 +118,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::Percent => 1,
|
Token::Percent => 1,
|
||||||
Token::Plus => 1,
|
Token::Plus => 1,
|
||||||
Token::PlusEqual => 2,
|
Token::PlusEqual => 2,
|
||||||
|
Token::Return => 6,
|
||||||
Token::RightCurlyBrace => 1,
|
Token::RightCurlyBrace => 1,
|
||||||
Token::RightParenthesis => 1,
|
Token::RightParenthesis => 1,
|
||||||
Token::RightSquareBrace => 1,
|
Token::RightSquareBrace => 1,
|
||||||
@ -169,6 +173,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::Percent => TokenOwned::Percent,
|
Token::Percent => TokenOwned::Percent,
|
||||||
Token::Plus => TokenOwned::Plus,
|
Token::Plus => TokenOwned::Plus,
|
||||||
Token::PlusEqual => TokenOwned::PlusEqual,
|
Token::PlusEqual => TokenOwned::PlusEqual,
|
||||||
|
Token::Return => TokenOwned::Return,
|
||||||
Token::RightCurlyBrace => TokenOwned::RightCurlyBrace,
|
Token::RightCurlyBrace => TokenOwned::RightCurlyBrace,
|
||||||
Token::RightParenthesis => TokenOwned::RightParenthesis,
|
Token::RightParenthesis => TokenOwned::RightParenthesis,
|
||||||
Token::RightSquareBrace => TokenOwned::RightSquareBrace,
|
Token::RightSquareBrace => TokenOwned::RightSquareBrace,
|
||||||
@ -227,6 +232,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::Percent => TokenKind::Percent,
|
Token::Percent => TokenKind::Percent,
|
||||||
Token::Plus => TokenKind::Plus,
|
Token::Plus => TokenKind::Plus,
|
||||||
Token::PlusEqual => TokenKind::PlusEqual,
|
Token::PlusEqual => TokenKind::PlusEqual,
|
||||||
|
Token::Return => TokenKind::Return,
|
||||||
Token::RightCurlyBrace => TokenKind::RightCurlyBrace,
|
Token::RightCurlyBrace => TokenKind::RightCurlyBrace,
|
||||||
Token::RightParenthesis => TokenKind::RightParenthesis,
|
Token::RightParenthesis => TokenKind::RightParenthesis,
|
||||||
Token::RightSquareBrace => TokenKind::RightSquareBrace,
|
Token::RightSquareBrace => TokenKind::RightSquareBrace,
|
||||||
@ -287,6 +293,7 @@ impl<'src> Display for Token<'src> {
|
|||||||
Token::Percent => write!(f, "%"),
|
Token::Percent => write!(f, "%"),
|
||||||
Token::Plus => write!(f, "+"),
|
Token::Plus => write!(f, "+"),
|
||||||
Token::PlusEqual => write!(f, "+="),
|
Token::PlusEqual => write!(f, "+="),
|
||||||
|
Token::Return => write!(f, "return"),
|
||||||
Token::RightCurlyBrace => write!(f, "}}"),
|
Token::RightCurlyBrace => write!(f, "}}"),
|
||||||
Token::RightParenthesis => write!(f, ")"),
|
Token::RightParenthesis => write!(f, ")"),
|
||||||
Token::RightSquareBrace => write!(f, "]"),
|
Token::RightSquareBrace => write!(f, "]"),
|
||||||
@ -332,6 +339,7 @@ pub enum TokenOwned {
|
|||||||
Loop,
|
Loop,
|
||||||
Map,
|
Map,
|
||||||
Mut,
|
Mut,
|
||||||
|
Return,
|
||||||
Str,
|
Str,
|
||||||
While,
|
While,
|
||||||
|
|
||||||
@ -414,6 +422,7 @@ impl Display for TokenOwned {
|
|||||||
TokenOwned::Percent => Token::Percent.fmt(f),
|
TokenOwned::Percent => Token::Percent.fmt(f),
|
||||||
TokenOwned::Plus => Token::Plus.fmt(f),
|
TokenOwned::Plus => Token::Plus.fmt(f),
|
||||||
TokenOwned::PlusEqual => Token::PlusEqual.fmt(f),
|
TokenOwned::PlusEqual => Token::PlusEqual.fmt(f),
|
||||||
|
TokenOwned::Return => Token::Return.fmt(f),
|
||||||
TokenOwned::RightCurlyBrace => Token::RightCurlyBrace.fmt(f),
|
TokenOwned::RightCurlyBrace => Token::RightCurlyBrace.fmt(f),
|
||||||
TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f),
|
TokenOwned::RightParenthesis => Token::RightParenthesis.fmt(f),
|
||||||
TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
||||||
@ -457,6 +466,7 @@ pub enum TokenKind {
|
|||||||
Let,
|
Let,
|
||||||
Loop,
|
Loop,
|
||||||
Map,
|
Map,
|
||||||
|
Return,
|
||||||
Str,
|
Str,
|
||||||
While,
|
While,
|
||||||
|
|
||||||
@ -539,6 +549,7 @@ impl Display for TokenKind {
|
|||||||
TokenKind::Percent => Token::Percent.fmt(f),
|
TokenKind::Percent => Token::Percent.fmt(f),
|
||||||
TokenKind::Plus => Token::Plus.fmt(f),
|
TokenKind::Plus => Token::Plus.fmt(f),
|
||||||
TokenKind::PlusEqual => Token::PlusEqual.fmt(f),
|
TokenKind::PlusEqual => Token::PlusEqual.fmt(f),
|
||||||
|
TokenKind::Return => Token::Return.fmt(f),
|
||||||
TokenKind::RightCurlyBrace => Token::RightCurlyBrace.fmt(f),
|
TokenKind::RightCurlyBrace => Token::RightCurlyBrace.fmt(f),
|
||||||
TokenKind::RightParenthesis => Token::RightParenthesis.fmt(f),
|
TokenKind::RightParenthesis => Token::RightParenthesis.fmt(f),
|
||||||
TokenKind::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
TokenKind::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
||||||
|
@ -270,7 +270,7 @@ fn equality_assignment_long() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn equality_assignment_short() {
|
fn equality_assignment_short() {
|
||||||
let source = "let a = 4 == 4; a";
|
let source = "let a = 4 == 4 a";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(source),
|
parse(source),
|
||||||
@ -286,8 +286,8 @@ fn equality_assignment_short() {
|
|||||||
(Instruction::load_boolean(0, true, true), Span(10, 12)),
|
(Instruction::load_boolean(0, true, true), Span(10, 12)),
|
||||||
(Instruction::load_boolean(0, false, false), Span(10, 12)),
|
(Instruction::load_boolean(0, false, false), Span(10, 12)),
|
||||||
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
||||||
(Instruction::get_local(1, 0), Span(16, 17)),
|
(Instruction::get_local(1, 0), Span(15, 16)),
|
||||||
(Instruction::r#return(), Span(17, 17)),
|
(Instruction::r#return(), Span(16, 16)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::integer(4)],
|
vec![Value::integer(4), Value::integer(4)],
|
||||||
vec![Local::new(Identifier::new("a"), None, false, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), None, false, 0, Some(0))]
|
||||||
|
Loading…
Reference in New Issue
Block a user