1
0

Extend parsing

This commit is contained in:
Jeff 2024-09-22 18:17:21 -04:00
parent 573e5ae470
commit 57edf48e36
7 changed files with 494 additions and 139 deletions

View File

@ -58,6 +58,10 @@ impl Chunk {
.ok_or(ChunkError::CodeIndexOfBounds { offset, position })
}
pub fn remove_instruction(&mut self, index: usize) -> (Instruction, Span) {
self.instructions.remove(index)
}
pub fn push_instruction(&mut self, instruction: Instruction, position: Span) {
self.instructions.push((instruction, position));
}
@ -72,17 +76,32 @@ impl Chunk {
.ok_or(ChunkError::InstructionUnderflow { position })
}
pub fn get_previous(&self, position: Span) -> Result<&(Instruction, Span), ChunkError> {
self.instructions
.last()
.ok_or(ChunkError::InstructionUnderflow { position })
pub fn get_previous(&self) -> Option<&(Instruction, Span)> {
self.instructions.last()
}
pub fn get_last_operation(&self, position: Span) -> Result<Operation, ChunkError> {
self.get_previous(position)
pub fn get_last_operation(&self) -> Option<Operation> {
self.get_previous()
.map(|(instruction, _)| instruction.operation())
}
pub fn get_last_n_operations<const N: usize>(&self) -> [Option<Operation>; N] {
let mut operations = [None; N];
for i in 0..N {
let index = self.instructions.len().saturating_sub(i + 1);
let operation = self
.instructions
.get(index)
.map(|(instruction, _)| instruction.operation());
operations[i] = operation;
}
operations
}
pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> {
let index = index as usize;

View File

@ -160,6 +160,26 @@ impl Instruction {
instruction
}
pub fn less(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Less as u32);
instruction.set_destination(if comparison_boolean { 1 } else { 0 });
instruction.set_first_argument(left_index);
instruction.set_second_argument(right_index);
instruction
}
pub fn less_equal(comparison_boolean: bool, left_index: u8, right_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::LessEqual as u32);
instruction.set_destination(if comparison_boolean { 1 } else { 0 });
instruction.set_first_argument(left_index);
instruction.set_second_argument(right_index);
instruction
}
pub fn negate(to_register: u8, from_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::Negate as u32);

View File

@ -309,7 +309,13 @@ impl<'src> Lexer<'src> {
'!' => {
self.position += 1;
(Token::Bang, Span(self.position - 1, self.position))
if let Some('=') = self.peek_char() {
self.position += 1;
(Token::BangEqual, Span(self.position - 2, self.position))
} else {
(Token::Bang, Span(self.position - 1, self.position))
}
}
':' => {
self.position += 1;
@ -969,6 +975,21 @@ mod tests {
)
}
#[test]
fn not_equal() {
let input = "42 != 42";
assert_eq!(
lex(input),
Ok(vec![
(Token::Integer("42"), Span(0, 2)),
(Token::BangEqual, Span(3, 5)),
(Token::Integer("42"), Span(6, 8)),
(Token::Eof, Span(8, 8)),
])
)
}
#[test]
fn equal() {
let input = "42 == 42";

View File

@ -8,8 +8,8 @@ use std::{
};
use crate::{
dust_error::AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError,
Lexer, Operation, Span, Token, TokenKind, TokenOwned, Value,
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer,
Operation, Span, Token, TokenKind, TokenOwned, Value,
};
pub fn parse(source: &str) -> Result<Chunk, DustError> {
@ -150,26 +150,52 @@ impl<'src> Parser<'src> {
) -> Result<(), ParseError> {
if let Token::Boolean(text) = self.current_token {
let position = self.current_position;
let boolean = text.parse::<bool>().unwrap();
self.advance()?;
let boolean = text.parse::<bool>().unwrap();
let previous_operations = self.chunk.get_last_n_operations::<2>();
if let Ok((last_instruction, _)) =
self.chunk.get_previous(self.current_position).copied()
if let [Some(Operation::LoadBoolean), Some(Operation::LoadBoolean)] =
previous_operations
{
let skip = last_instruction.operation() == Operation::Jump;
let (second_boolean, second_position) =
self.chunk.pop_instruction(self.current_position)?;
let (first_boolean, first_position) =
self.chunk.pop_instruction(self.current_position)?;
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, skip),
position,
);
} else {
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, false),
position,
);
if first_boolean.first_argument_as_boolean() == boolean {
let skip = first_boolean.second_argument_as_boolean();
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, skip),
position,
);
return Ok(());
}
if second_boolean.first_argument_as_boolean() == boolean {
let skip = second_boolean.second_argument_as_boolean();
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, skip),
position,
);
return Ok(());
}
self.emit_instruction(first_boolean, first_position);
self.emit_instruction(second_boolean, second_position);
}
let skip = previous_operations[0] == Some(Operation::Jump);
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, skip),
position,
);
}
Ok(())
@ -390,11 +416,21 @@ impl<'src> Parser<'src> {
TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), false),
TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), false),
TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), true),
TokenKind::BangEqual => (Instruction::equal(false, left, 0), true),
TokenKind::Less => (Instruction::less(true, left, 0), true),
TokenKind::LessEqual => (Instruction::less_equal(true, left, 0), true),
TokenKind::Greater => (Instruction::less_equal(false, left, 0), true),
TokenKind::GreaterEqual => (Instruction::less(false, left, 0), true),
TokenKind::DoubleAmpersand => {
let and_test = Instruction::test(self.current_register, false);
(and_test, true)
}
TokenKind::DoublePipe => {
let or_test = Instruction::test(self.current_register, true);
(or_test, true)
}
_ => {
return Err(ParseError::ExpectedTokenMultiple {
expected: &[
@ -403,9 +439,14 @@ impl<'src> Parser<'src> {
TokenKind::Star,
TokenKind::Slash,
TokenKind::Percent,
TokenKind::DoubleEqual,
TokenKind::BangEqual,
TokenKind::Less,
TokenKind::LessEqual,
TokenKind::Greater,
TokenKind::GreaterEqual,
TokenKind::DoubleAmpersand,
TokenKind::DoublePipe,
TokenKind::DoubleEqual,
],
found: operator.to_owned(),
position: operator_position,
@ -466,6 +507,21 @@ impl<'src> Parser<'src> {
if push_back_right {
self.emit_instruction(right_instruction, right_position);
}
if !push_back_left && !push_back_right {
if self.current_register > 0 {
self.decrement_register()?;
}
self.emit_instruction(
Instruction::load_boolean(self.current_register, true, true),
operator_position,
);
self.emit_instruction(
Instruction::load_boolean(self.current_register, false, false),
operator_position,
);
}
}
Ok(())
@ -482,16 +538,17 @@ impl<'src> Parser<'src> {
self.advance()?;
let local_index = self.parse_identifier_from(token, start_position)?;
let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable;
if !is_mutable {
return Err(ParseError::CannotMutateImmutableVariable {
identifier: self.chunk.get_identifier(local_index).cloned().unwrap(),
position: start_position,
});
}
if allow_assignment && self.allow(TokenKind::Equal)? {
let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable;
if !is_mutable {
return Err(ParseError::CannotMutateImmutableVariable {
identifier: self.chunk.get_identifier(local_index).cloned().unwrap(),
position: start_position,
});
}
self.parse_expression()?;
let (mut previous_instruction, previous_position) =
@ -614,6 +671,13 @@ impl<'src> Parser<'src> {
fn parse_if(&mut self, allow_assignment: bool, allow_return: bool) -> Result<(), ParseError> {
self.advance()?;
self.parse_expression()?;
let (second_load_boolean, second_position) =
self.chunk.pop_instruction(self.current_position)?;
let (first_load_boolean, first_position) =
self.chunk.pop_instruction(self.current_position)?;
let length_after_expression = self.chunk.len();
self.parse_block(allow_assignment, allow_return)?;
let jump_start = self.current_register;
@ -627,12 +691,22 @@ impl<'src> Parser<'src> {
}
}
let jump_end = self.current_register;
let jump_distance = (jump_end - jump_start).max(1);
let jump = Instruction::jump(jump_distance, true);
if self.chunk.len() == length_after_expression {
self.emit_instruction(first_load_boolean, first_position);
self.emit_instruction(second_load_boolean, second_position);
}
self.chunk
.insert_instruction(jump_index, jump, self.current_position);
if let Some(Operation::LoadBoolean) = self.chunk.get_last_operation() {
// Skip the jump if the last instruction was a LoadBoolean operation. A LoadBoolean can
// skip the following instruction, so a jump is unnecessary.
} else {
let jump_end = self.current_register;
let jump_distance = (jump_end - jump_start).max(1);
let jump = Instruction::jump(jump_distance, true);
self.chunk
.insert_instruction(jump_index, jump, self.current_position);
}
Ok(())
}
@ -702,35 +776,37 @@ impl<'src> Parser<'src> {
self.expect(TokenKind::Equal)?;
self.parse_expression()?;
let (previous_instruction, previous_position) = *self.chunk.get_previous(position)?;
let (previous_instruction, previous_position) =
*self
.chunk
.get_previous()
.ok_or_else(|| ParseError::ExpectedExpression {
found: self.current_token.to_owned(),
position,
})?;
let register = previous_instruction.destination();
let local_index =
self.chunk
.declare_local(identifier, is_mutable, register, previous_position)?;
// Optimize for assignment to a comparison
if let Operation::Jump = previous_instruction.operation() {
let (jump, jump_position) = self.chunk.pop_instruction(self.current_position)?;
// if let Operation::Jump = previous_instruction.operation() {
// let (jump, jump_position) = self.chunk.pop_instruction(self.current_position)?;
if let Operation::Equal = self
.chunk
.get_previous(self.current_position)?
.0
.operation()
{
self.emit_instruction(jump, jump_position);
self.emit_instruction(
Instruction::load_boolean(self.current_register, true, true),
self.current_position,
);
self.emit_instruction(
Instruction::load_boolean(self.current_register, false, false),
self.current_position,
);
} else {
self.emit_instruction(jump, jump_position);
}
}
// if let Some(Operation::Equal) = self.chunk.get_last_operation() {
// self.emit_instruction(jump, jump_position);
// self.emit_instruction(
// Instruction::load_boolean(self.current_register, true, true),
// self.current_position,
// );
// self.emit_instruction(
// Instruction::load_boolean(self.current_register, false, false),
// self.current_position,
// );
// } else {
// self.emit_instruction(jump, jump_position);
// }
// }
self.emit_instruction(
Instruction::define_local(register, local_index, is_mutable),
@ -836,21 +912,24 @@ pub struct ParseRule<'a> {
impl From<&TokenKind> for ParseRule<'_> {
fn from(token_kind: &TokenKind) -> Self {
match token_kind {
TokenKind::Eof => ParseRule {
TokenKind::Async => todo!(),
TokenKind::Bang => ParseRule {
prefix: Some(Parser::parse_unary),
infix: None,
precedence: Precedence::Unary,
},
TokenKind::BangEqual => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::Identifier => ParseRule {
prefix: Some(Parser::parse_variable),
infix: None,
precedence: Precedence::None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Equality,
},
TokenKind::Bool => todo!(),
TokenKind::Boolean => ParseRule {
prefix: Some(Parser::parse_boolean),
infix: None,
precedence: Precedence::None,
},
TokenKind::Break => todo!(),
TokenKind::Byte => ParseRule {
prefix: Some(Parser::parse_byte),
infix: None,
@ -861,55 +940,6 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
TokenKind::Float => ParseRule {
prefix: Some(Parser::parse_float),
infix: None,
precedence: Precedence::None,
},
TokenKind::Integer => ParseRule {
prefix: Some(Parser::parse_integer),
infix: None,
precedence: Precedence::None,
},
TokenKind::String => ParseRule {
prefix: Some(Parser::parse_string),
infix: None,
precedence: Precedence::None,
},
TokenKind::Async => todo!(),
TokenKind::Bool => todo!(),
TokenKind::Break => todo!(),
TokenKind::Else => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::FloatKeyword => todo!(),
TokenKind::If => ParseRule {
prefix: Some(Parser::parse_if),
infix: None,
precedence: Precedence::None,
},
TokenKind::Int => todo!(),
TokenKind::Let => ParseRule {
prefix: Some(Parser::parse_let_statement),
infix: None,
precedence: Precedence::None,
},
TokenKind::Loop => todo!(),
TokenKind::Map => todo!(),
TokenKind::Str => todo!(),
TokenKind::While => ParseRule {
prefix: Some(Parser::parse_while),
infix: None,
precedence: Precedence::None,
},
TokenKind::BangEqual => todo!(),
TokenKind::Bang => ParseRule {
prefix: Some(Parser::parse_unary),
infix: None,
precedence: Precedence::Unary,
},
TokenKind::Colon => todo!(),
TokenKind::Comma => ParseRule {
prefix: None,
@ -922,7 +952,6 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: Some(Parser::parse_binary),
precedence: Precedence::LogicalAnd,
},
TokenKind::DoubleDot => todo!(),
TokenKind::DoubleEqual => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
@ -933,13 +962,54 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: Some(Parser::parse_binary),
precedence: Precedence::LogicalOr,
},
TokenKind::DoubleDot => todo!(),
TokenKind::Eof => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::Equal => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::Assignment,
},
TokenKind::Greater => todo!(),
TokenKind::GreaterOrEqual => todo!(),
TokenKind::Else => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::Float => ParseRule {
prefix: Some(Parser::parse_float),
infix: None,
precedence: Precedence::None,
},
TokenKind::FloatKeyword => todo!(),
TokenKind::Greater => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Comparison,
},
TokenKind::GreaterEqual => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Comparison,
},
TokenKind::Identifier => ParseRule {
prefix: Some(Parser::parse_variable),
infix: None,
precedence: Precedence::None,
},
TokenKind::If => ParseRule {
prefix: Some(Parser::parse_if),
infix: None,
precedence: Precedence::None,
},
TokenKind::Int => todo!(),
TokenKind::Integer => ParseRule {
prefix: Some(Parser::parse_integer),
infix: None,
precedence: Precedence::None,
},
TokenKind::LeftCurlyBrace => ParseRule {
prefix: Some(Parser::parse_block),
infix: None,
@ -955,8 +1025,23 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
TokenKind::Less => todo!(),
TokenKind::LessOrEqual => todo!(),
TokenKind::Less => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Comparison,
},
TokenKind::LessEqual => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Comparison,
},
TokenKind::Let => ParseRule {
prefix: Some(Parser::parse_let_statement),
infix: None,
precedence: Precedence::None,
},
TokenKind::Loop => todo!(),
TokenKind::Map => todo!(),
TokenKind::Minus => ParseRule {
prefix: Some(Parser::parse_unary),
infix: Some(Parser::parse_binary),
@ -999,16 +1084,27 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
TokenKind::Slash => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Factor,
},
TokenKind::Star => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Factor,
},
TokenKind::Str => todo!(),
TokenKind::String => ParseRule {
prefix: Some(Parser::parse_string),
infix: None,
precedence: Precedence::None,
},
TokenKind::Struct => todo!(),
TokenKind::Slash => ParseRule {
prefix: None,
infix: Some(Parser::parse_binary),
precedence: Precedence::Factor,
TokenKind::While => ParseRule {
prefix: Some(Parser::parse_while),
infix: None,
precedence: Precedence::None,
},
}
}

View File

@ -2,6 +2,184 @@ use crate::Local;
use super::*;
#[test]
fn not() {
let source = "!true";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(Instruction::load_boolean(0, true, true), Span(1, 5)),
(Instruction::not(0, 0), Span(1, 5)),
],
vec![],
vec![]
)),
);
}
#[test]
fn negate() {
let source = "-(42)";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(Instruction::load_constant(0, 0), Span(2, 4)),
(Instruction::negate(0, 0), Span(1, 5)),
],
vec![Value::integer(42),],
vec![]
)),
);
}
#[test]
fn greater_than_or_equal() {
let source = "1 >= 2;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::less(false, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn greater() {
let source = "1 > 2;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::less_equal(false, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 3)
),
(Instruction::jump(1, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn less_than_or_equal() {
let source = "1 <= 2;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::less_equal(true, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn less_than() {
let source = "1 < 2;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::less(true, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 3)
),
(Instruction::jump(1, true), Span(2, 3)),
(Instruction::load_boolean(0, true, true), Span(2, 3)),
(Instruction::load_boolean(0, false, false), Span(2, 3)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn not_equal() {
let source = "1 != 2;";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::equal(false, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn equal() {
let source = "1 == 2";
assert_eq!(
parse(source),
Ok(Chunk::with_data(
vec![
(
*Instruction::equal(true, 0, 1)
.set_first_argument_to_constant()
.set_second_argument_to_constant(),
Span(2, 4)
),
(Instruction::jump(1, true), Span(2, 4)),
(Instruction::load_boolean(0, true, true), Span(2, 4)),
(Instruction::load_boolean(0, false, false), Span(2, 4)),
],
vec![Value::integer(1), Value::integer(2)],
vec![]
)),
);
}
#[test]
fn equality_assignment_long() {
let source = "let a = if 4 == 4 { true } else { false };";
@ -18,12 +196,11 @@ fn equality_assignment_long() {
),
(Instruction::jump(1, true), Span(13, 15)),
(Instruction::load_boolean(0, true, true), Span(20, 24)),
(Instruction::jump(1, true), Span(41, 42)),
(Instruction::load_boolean(0, false, false), Span(34, 39)),
(Instruction::define_local(0, 0, false), Span(4, 5)),
],
vec![Value::integer(4), Value::integer(4),],
vec![Local::new(Identifier::new("a"), false, 0, Some(0)),]
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
)),
);
}
@ -43,12 +220,12 @@ fn equality_assignment_short() {
Span(10, 12)
),
(Instruction::jump(1, true), Span(10, 12)),
(Instruction::load_boolean(0, true, true), Span(14, 15)),
(Instruction::load_boolean(0, false, false), Span(14, 15)),
(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)),
],
vec![Value::integer(4), Value::integer(4),],
vec![Local::new(Identifier::new("a"), false, 0, Some(0)),]
vec![Value::integer(4), Value::integer(4)],
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
)),
);
}
@ -274,13 +451,34 @@ fn declare_local() {
);
}
#[test]
fn or() {
assert_eq!(
parse("true || false"),
Ok(Chunk::with_data(
vec![
(
*Instruction::test(0, false)
.set_second_argument_to_constant()
.set_first_argument_to_constant(),
Span(5, 7)
),
(Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
],
vec![],
vec![]
))
);
}
#[test]
fn and() {
assert_eq!(
parse("true && false"),
Ok(Chunk::with_data(
vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(
*Instruction::test(0, true)
.set_second_argument_to_constant()
@ -288,6 +486,7 @@ fn and() {
Span(5, 7)
),
(Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::load_boolean(1, false, false), Span(8, 13)),
],
vec![],

View File

@ -198,7 +198,7 @@ impl<'src> Token<'src> {
Token::Float(_) => TokenKind::Float,
Token::FloatKeyword => TokenKind::FloatKeyword,
Token::Greater => TokenKind::Greater,
Token::GreaterEqual => TokenKind::GreaterOrEqual,
Token::GreaterEqual => TokenKind::GreaterEqual,
Token::Identifier(_) => TokenKind::Identifier,
Token::If => TokenKind::If,
Token::Int => TokenKind::Int,
@ -208,7 +208,7 @@ impl<'src> Token<'src> {
Token::LeftSquareBrace => TokenKind::LeftSquareBrace,
Token::Let => TokenKind::Let,
Token::Less => TokenKind::Less,
Token::LessEqual => TokenKind::LessOrEqual,
Token::LessEqual => TokenKind::LessEqual,
Token::Loop => TokenKind::Loop,
Token::Map => TokenKind::Map,
Token::Minus => TokenKind::Minus,
@ -450,12 +450,12 @@ pub enum TokenKind {
DoublePipe,
Equal,
Greater,
GreaterOrEqual,
GreaterEqual,
LeftCurlyBrace,
LeftParenthesis,
LeftSquareBrace,
Less,
LessOrEqual,
LessEqual,
Minus,
MinusEqual,
Mut,
@ -495,7 +495,7 @@ impl Display for TokenKind {
TokenKind::Float => write!(f, "float value"),
TokenKind::FloatKeyword => Token::FloatKeyword.fmt(f),
TokenKind::Greater => Token::Greater.fmt(f),
TokenKind::GreaterOrEqual => Token::GreaterEqual.fmt(f),
TokenKind::GreaterEqual => Token::GreaterEqual.fmt(f),
TokenKind::Identifier => write!(f, "identifier"),
TokenKind::If => Token::If.fmt(f),
TokenKind::Int => Token::Int.fmt(f),
@ -505,7 +505,7 @@ impl Display for TokenKind {
TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
TokenKind::Let => Token::Let.fmt(f),
TokenKind::Less => Token::Less.fmt(f),
TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
TokenKind::LessEqual => Token::LessEqual.fmt(f),
TokenKind::Loop => Token::Loop.fmt(f),
TokenKind::Map => Token::Map.fmt(f),
TokenKind::Minus => Token::Minus.fmt(f),

View File

@ -60,7 +60,7 @@ impl Vm {
}
while let Ok((instruction, position)) = self.read(Span(0, 0)).copied() {
log::trace!("Running instruction {instruction} at {position}");
log::trace!("Running IP {} {instruction} at {position}", self.ip);
match instruction.operation() {
Operation::Move => {