From 3ac15fe70b972a25b52ece11987bab9989d6b72d Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 7 Sep 2024 12:15:47 -0400 Subject: [PATCH] Implement let assignment --- dust-lang/src/chunk.rs | 57 ++++++--- dust-lang/src/dust_error.rs | 7 +- dust-lang/src/lib.rs | 4 +- dust-lang/src/parser.rs | 226 +++++++++++++++++++++++++++++++----- dust-lang/src/run.rs | 31 +++++ dust-lang/src/vm.rs | 195 ++++++++++++++++++++++++------- dust-shell/src/main.rs | 16 ++- 7 files changed, 445 insertions(+), 91 deletions(-) create mode 100644 dust-lang/src/run.rs diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index f686f65..09f3912 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -2,12 +2,13 @@ use std::fmt::{self, Debug, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{Instruction, Span, Value}; +use crate::{Identifier, Instruction, Span, Value}; -#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub struct Chunk { code: Vec<(u8, Span)>, constants: Vec, + identifiers: Vec, } impl Chunk { @@ -15,11 +16,20 @@ impl Chunk { Self { code: Vec::new(), constants: Vec::new(), + identifiers: Vec::new(), } } - pub fn with_data(code: Vec<(u8, Span)>, constants: Vec) -> Self { - Self { code, constants } + pub fn with_data( + code: Vec<(u8, Span)>, + constants: Vec, + identifiers: Vec, + ) -> Self { + Self { + code, + constants, + identifiers, + } } pub fn len(&self) -> usize { @@ -34,8 +44,10 @@ impl Chunk { self.code.capacity() } - pub fn read(&self, offset: usize) -> (u8, Span) { - self.code[offset] + pub fn read(&self, offset: usize) -> Result<&(u8, Span), ChunkError> { + self.code + .get(offset) + .ok_or(ChunkError::CodeIndextOfBounds(offset)) } pub fn write(&mut self, instruction: u8, position: Span) { @@ -45,14 +57,14 @@ impl Chunk { pub fn get_constant(&self, index: usize) -> Result<&Value, ChunkError> { self.constants .get(index) - .ok_or_else(|| ChunkError::ConstantIndexOutOfBounds(index)) + .ok_or(ChunkError::ConstantIndexOutOfBounds(index)) } pub fn push_constant(&mut self, value: Value) -> Result { let starting_length = self.constants.len(); if starting_length + 1 > (u8::MAX as usize) { - Err(ChunkError::Overflow) + Err(ChunkError::ConstantOverflow) } else { self.constants.push(value); @@ -60,6 +72,24 @@ impl Chunk { } } + pub fn get_identifier(&self, index: usize) -> Result<&Identifier, ChunkError> { + self.identifiers + .get(index) + .ok_or(ChunkError::IdentifierIndexOutOfBounds(index)) + } + + pub fn push_identifier(&mut self, identifier: Identifier) -> Result { + let starting_length = self.constants.len(); + + if starting_length + 1 > (u8::MAX as usize) { + Err(ChunkError::IdentifierOverflow) + } else { + self.identifiers.push(identifier); + + Ok(starting_length as u8) + } + } + pub fn clear(&mut self) { self.code.clear(); self.constants.clear(); @@ -112,14 +142,11 @@ impl Display for Chunk { } } -impl Debug for Chunk { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{self}") - } -} - #[derive(Debug, Clone, Copy, PartialEq)] pub enum ChunkError { + CodeIndextOfBounds(usize), + ConstantOverflow, ConstantIndexOutOfBounds(usize), - Overflow, + IdentifierIndexOutOfBounds(usize), + IdentifierOverflow, } diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index 85719dc..eaf2c6c 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -1,15 +1,16 @@ use crate::{vm::VmError, LexError, ParseError}; +#[derive(Debug, PartialEq)] pub enum DustError<'src> { - LexError { + Lex { error: LexError, source: &'src str, }, - ParseError { + Parse { error: ParseError, source: &'src str, }, - VmError { + Runtime { error: VmError, source: &'src str, }, diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 43e4bd7..172254a 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -21,6 +21,7 @@ pub mod dust_error; pub mod identifier; pub mod lexer; pub mod parser; +pub mod run; pub mod token; pub mod r#type; pub mod value; @@ -31,8 +32,9 @@ pub use constructor::{ConstructError, Constructor}; pub use dust_error::DustError; pub use identifier::Identifier; pub use lexer::{LexError, Lexer}; -pub use parser::{ParseError, Parser}; +pub use parser::{parse, ParseError, Parser}; pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict}; +pub use run::run; pub use token::{Token, TokenKind, TokenOwned}; pub use value::{Struct, Value, ValueError}; pub use vm::{Instruction, Vm}; diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index 410988d..e82e2af 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -1,20 +1,22 @@ use std::{ fmt::{self, Display, Formatter}, - mem::{self, swap}, + mem, num::ParseIntError, - ptr::replace, }; use crate::{ - Chunk, ChunkError, Instruction, LexError, Lexer, Span, Token, TokenKind, TokenOwned, Value, + Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer, Span, Token, TokenKind, + TokenOwned, Value, }; -pub fn parse(source: &str) -> Result { +pub fn parse(source: &str) -> Result { let lexer = Lexer::new(source); let mut parser = Parser::new(lexer); while !parser.is_eof() { - parser.parse(Precedence::None)?; + parser + .parse_statement() + .map_err(|error| DustError::Parse { error, source })?; } Ok(parser.chunk) @@ -35,6 +37,8 @@ impl<'src> Parser<'src> { let (current_token, current_position) = lexer.next_token().unwrap_or((Token::Eof, Span(0, 0))); + log::trace!("Starting parser with token {current_token} at {current_position}"); + Parser { lexer, chunk: Chunk::new(), @@ -60,7 +64,17 @@ impl<'src> Parser<'src> { Ok(()) } - fn consume(&mut self, expected: TokenKind) -> Result<(), ParseError> { + fn allow(&mut self, allowed: TokenKind) -> Result { + if self.current_token.kind() == allowed { + self.advance()?; + + Ok(true) + } else { + Ok(false) + } + } + + fn expect(&mut self, expected: TokenKind) -> Result<(), ParseError> { if self.current_token.kind() == expected { self.advance() } else { @@ -97,6 +111,17 @@ impl<'src> Parser<'src> { Ok(()) } + fn parse_float(&mut self) -> Result<(), ParseError> { + if let Token::Float(text) = self.previous_token { + let float = text.parse::().unwrap(); + let value = Value::float(float); + + self.emit_constant(value)?; + } + + Ok(()) + } + fn parse_integer(&mut self) -> Result<(), ParseError> { if let Token::Integer(text) = self.previous_token { let integer = text.parse::().unwrap(); @@ -108,25 +133,36 @@ impl<'src> Parser<'src> { Ok(()) } + fn parse_string(&mut self) -> Result<(), ParseError> { + if let Token::String(text) = self.previous_token { + let value = Value::string(text); + + self.emit_constant(value)?; + } + + Ok(()) + } + fn parse_grouped(&mut self) -> Result<(), ParseError> { self.parse_expression()?; - self.consume(TokenKind::RightParenthesis) + self.expect(TokenKind::RightParenthesis) } fn parse_unary(&mut self) -> Result<(), ParseError> { + let operator_position = self.previous_position; let byte = match self.previous_token.kind() { TokenKind::Minus => Instruction::Negate as u8, _ => { return Err(ParseError::ExpectedTokenMultiple { expected: vec![TokenKind::Minus], found: self.previous_token.to_owned(), - position: self.previous_position, + position: operator_position, }) } }; self.parse_expression()?; - self.emit_byte(byte, self.previous_position); + self.emit_byte(byte, operator_position); Ok(()) } @@ -162,10 +198,73 @@ impl<'src> Parser<'src> { Ok(()) } + fn parse_variable(&mut self) -> Result<(), ParseError> { + todo!() + } + + fn parse_identifier(&mut self) -> Result { + if let Token::Identifier(text) = self.current_token { + self.advance()?; + + let identifier = Identifier::new(text); + let identifier_index = self.chunk.push_identifier(identifier)?; + + Ok(identifier_index) + } else { + Err(ParseError::ExpectedToken { + expected: TokenKind::Identifier, + found: self.current_token.to_owned(), + position: self.current_position, + }) + } + } + fn parse_expression(&mut self) -> Result<(), ParseError> { self.parse(Precedence::None) } + fn parse_statement(&mut self) -> Result<(), ParseError> { + match self.current_token { + Token::Let => self.parse_let_assignment()?, + _ => self.parse_expression_statement()?, + } + + Ok(()) + } + + fn parse_expression_statement(&mut self) -> Result<(), ParseError> { + let start = self.current_position.0; + + self.parse_expression()?; + + if self.allow(TokenKind::Semicolon)? { + let end = self.previous_position.1; + + self.emit_byte(Instruction::Pop as u8, Span(start, end)); + } + + Ok(()) + } + + fn parse_let_assignment(&mut self) -> Result<(), ParseError> { + self.expect(TokenKind::Let)?; + + let position = self.current_position; + let identifier_index = self.parse_identifier()?; + + self.expect(TokenKind::Equal)?; + self.parse_expression()?; + self.expect(TokenKind::Semicolon)?; + self.define_variable(identifier_index, position) + } + + fn define_variable(&mut self, identifier_index: u8, position: Span) -> Result<(), ParseError> { + self.emit_byte(Instruction::DefineGlobal as u8, position); + self.emit_byte(identifier_index, position); + + Ok(()) + } + fn parse(&mut self, precedence: Precedence) -> Result<(), ParseError> { self.advance()?; @@ -183,7 +282,7 @@ impl<'src> Parser<'src> { }); } - while precedence <= ParseRule::from(&self.current_token.kind()).precedence { + while precedence < ParseRule::from(&self.current_token.kind()).precedence { self.advance()?; let infix_rule = ParseRule::from(&self.previous_token.kind()).infix; @@ -266,20 +365,32 @@ impl From<&TokenKind> for ParseRule<'_> { infix: None, precedence: Precedence::None, }, - TokenKind::Identifier => todo!(), + TokenKind::Identifier => ParseRule { + prefix: Some(Parser::parse_variable), + infix: None, + precedence: Precedence::None, + }, TokenKind::Boolean => ParseRule { prefix: Some(Parser::parse_boolean), infix: None, precedence: Precedence::None, }, TokenKind::Character => todo!(), - TokenKind::Float => todo!(), + 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 => todo!(), + TokenKind::String => ParseRule { + prefix: Some(Parser::parse_string), + infix: None, + precedence: Precedence::None, + }, TokenKind::Async => todo!(), TokenKind::Bool => todo!(), TokenKind::Break => todo!(), @@ -334,7 +445,11 @@ impl From<&TokenKind> for ParseRule<'_> { precedence: Precedence::None, }, TokenKind::RightSquareBrace => todo!(), - TokenKind::Semicolon => todo!(), + TokenKind::Semicolon => ParseRule { + prefix: None, + infix: None, + precedence: Precedence::None, + }, TokenKind::Star => ParseRule { prefix: None, infix: Some(Parser::parse_binary), @@ -395,6 +510,41 @@ impl From for ParseError { mod tests { use super::*; + #[test] + fn let_statement() { + let source = "let x = 42;"; + let test_chunk = parse(source); + + assert_eq!( + test_chunk, + Ok(Chunk::with_data( + vec![ + (Instruction::Constant as u8, Span(8, 10)), + (0, Span(8, 10)), + (Instruction::DefineGlobal as u8, Span(4, 5)), + (0, Span(4, 5)) + ], + vec![Value::integer(42)], + vec![Identifier::new("x")] + )) + ); + } + + #[test] + fn string() { + let source = "\"Hello, World!\""; + let test_chunk = parse(source); + + assert_eq!( + test_chunk, + Ok(Chunk::with_data( + vec![(Instruction::Constant as u8, Span(0, 15)), (0, Span(0, 15))], + vec![Value::string("Hello, World!")], + vec![] + )) + ); + } + #[test] fn integer() { let source = "42"; @@ -404,7 +554,8 @@ mod tests { test_chunk, Ok(Chunk::with_data( vec![(Instruction::Constant as u8, Span(0, 2)), (0, Span(0, 2))], - vec![Value::integer(42)] + vec![Value::integer(42)], + vec![] )) ); } @@ -418,15 +569,14 @@ mod tests { test_chunk, Ok(Chunk::with_data( vec![(Instruction::Constant as u8, Span(0, 4)), (0, Span(0, 4))], - vec![Value::boolean(true)] + vec![Value::boolean(true)], + vec![] )) ); } #[test] fn grouping() { - env_logger::builder().is_test(true).try_init().unwrap(); - let source = "(42 + 42) * 2"; let test_chunk = parse(source); @@ -439,11 +589,31 @@ mod tests { (Instruction::Constant as u8, Span(6, 8)), (1, Span(6, 8)), (Instruction::Add as u8, Span(4, 5)), - (Instruction::Constant as u8, Span(11, 12)), - (0, Span(11, 12)), - (Instruction::Multiply as u8, Span(9, 10)), + (Instruction::Constant as u8, Span(12, 13)), + (2, Span(12, 13)), + (Instruction::Multiply as u8, Span(10, 11)), ], - vec![Value::integer(42), Value::integer(42), Value::integer(2)] + vec![Value::integer(42), Value::integer(42), Value::integer(2)], + vec![] + )) + ); + } + + #[test] + fn negation() { + let source = "-(42)"; + let test_chunk = parse(source); + + assert_eq!( + test_chunk, + Ok(Chunk::with_data( + vec![ + (Instruction::Constant as u8, Span(2, 4)), + (0, Span(2, 4)), + (Instruction::Negate as u8, Span(0, 1)), + ], + vec![Value::integer(42)], + vec![] )) ); } @@ -463,7 +633,8 @@ mod tests { (1, Span(5, 7)), (Instruction::Add as u8, Span(3, 4)), ], - vec![Value::integer(42), Value::integer(42)] + vec![Value::integer(42), Value::integer(42)], + vec![] )) ); } @@ -483,7 +654,8 @@ mod tests { (1, Span(5, 7)), (Instruction::Subtract as u8, Span(3, 4)), ], - vec![Value::integer(42), Value::integer(42)] + vec![Value::integer(42), Value::integer(42)], + vec![] )) ); } @@ -503,7 +675,8 @@ mod tests { (1, Span(5, 7)), (Instruction::Multiply as u8, Span(3, 4)), ], - vec![Value::integer(42), Value::integer(42)] + vec![Value::integer(42), Value::integer(42)], + vec![] )) ); } @@ -523,7 +696,8 @@ mod tests { (1, Span(5, 7)), (Instruction::Divide as u8, Span(3, 4)), ], - vec![Value::integer(42), Value::integer(42)] + vec![Value::integer(42), Value::integer(42)], + vec![] )) ); } diff --git a/dust-lang/src/run.rs b/dust-lang/src/run.rs new file mode 100644 index 0000000..16cbbc9 --- /dev/null +++ b/dust-lang/src/run.rs @@ -0,0 +1,31 @@ +use crate::{parse, DustError, Value, Vm}; + +pub fn run(source: &str) -> Result, DustError> { + let chunk = parse(source)?; + + let mut vm = Vm::new(chunk); + + vm.interpret() + .map_err(|error| DustError::Runtime { error, source }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn integer() { + let source = "42"; + let result = run(source); + + assert_eq!(result, Ok(Some(Value::integer(42)))); + } + + #[test] + fn addition() { + let source = "21 + 21"; + let result = run(source); + + assert_eq!(result, Ok(Some(Value::integer(42)))); + } +} diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index fcab81e..5092637 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -1,12 +1,15 @@ +use std::collections::HashMap; + use serde::{Deserialize, Serialize}; -use crate::{Chunk, ChunkError, Span, Value, ValueError}; +use crate::{Chunk, ChunkError, Identifier, Span, Value, ValueError}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Vm { chunk: Chunk, ip: usize, stack: Vec, + globals: HashMap, } impl Vm { @@ -17,18 +20,18 @@ impl Vm { chunk, ip: 0, stack: Vec::with_capacity(Self::STACK_SIZE), + globals: HashMap::new(), } } pub fn interpret(&mut self) -> Result, VmError> { - loop { - let (byte, position) = self.read(); + while let Ok((byte, position)) = self.read().copied() { let instruction = Instruction::from_byte(byte) .ok_or_else(|| VmError::InvalidInstruction(byte, position))?; match instruction { Instruction::Constant => { - let (index, _) = self.read(); + let (index, position) = self.read().copied()?; let value = self.read_constant(index as usize)?; self.stack.push(value); @@ -38,6 +41,16 @@ impl Vm { return Ok(Some(value)); } + Instruction::Pop => { + self.pop()?; + } + Instruction::DefineGlobal => { + let (index, _) = self.read().copied()?; + let identifier = self.chunk.get_identifier(index as usize)?.clone(); + let value = self.pop()?; + + self.globals.insert(identifier, value); + } // Unary Instruction::Negate => { @@ -45,45 +58,104 @@ impl Vm { self.stack.push(negated); } + Instruction::Not => { + let not = self.pop()?.not()?; + + self.stack.push(not); + } // Binary Instruction::Add => { - let b = self.pop()?; - let a = self.pop()?; - - let sum = a.add(&b)?; + let right = self.pop()?; + let left = self.pop()?; + let sum = left.add(&right)?; self.stack.push(sum); } Instruction::Subtract => { - let b = self.pop()?; - let a = self.pop()?; - - let difference = a.subtract(&b)?; + let right = self.pop()?; + let left = self.pop()?; + let difference = left.subtract(&right)?; self.stack.push(difference); } Instruction::Multiply => { - let b = self.pop()?; - let a = self.pop()?; - - let product = a.multiply(&b)?; + let right = self.pop()?; + let left = self.pop()?; + let product = left.multiply(&right)?; self.stack.push(product); } Instruction::Divide => { - let b = self.pop()?; - let a = self.pop()?; - - let quotient = a.divide(&b)?; + let right = self.pop()?; + let left = self.pop()?; + let quotient = left.divide(&right)?; self.stack.push(quotient); } + Instruction::Greater => { + let right = self.pop()?; + let left = self.pop()?; + let greater = left.greater_than(&right)?; + + self.stack.push(greater); + } + Instruction::Less => { + let right = self.pop()?; + let left = self.pop()?; + let less = left.less_than(&right)?; + + self.stack.push(less); + } + Instruction::GreaterEqual => { + let right = self.pop()?; + let left = self.pop()?; + let greater_equal = left.greater_than_or_equal(&right)?; + + self.stack.push(greater_equal); + } + Instruction::LessEqual => { + let right = self.pop()?; + let left = self.pop()?; + let less_equal = left.less_than_or_equal(&right)?; + + self.stack.push(less_equal); + } + Instruction::Equal => { + let right = self.pop()?; + let left = self.pop()?; + let equal = left.equal(&right)?; + + self.stack.push(equal); + } + Instruction::NotEqual => { + let right = self.pop()?; + let left = self.pop()?; + let not_equal = left.not_equal(&right)?; + + self.stack.push(not_equal); + } + Instruction::And => { + let right = self.pop()?; + let left = self.pop()?; + let and = left.and(&right)?; + + self.stack.push(and); + } + Instruction::Or => { + let right = self.pop()?; + let left = self.pop()?; + let or = left.or(&right)?; + + self.stack.push(or); + } } } + + Ok(self.stack.pop()) } - pub fn push(&mut self, value: Value) -> Result<(), VmError> { + fn push(&mut self, value: Value) -> Result<(), VmError> { if self.stack.len() == Self::STACK_SIZE { Err(VmError::StackOverflow) } else { @@ -93,7 +165,7 @@ impl Vm { } } - pub fn pop(&mut self) -> Result { + fn pop(&mut self) -> Result { if let Some(value) = self.stack.pop() { Ok(value) } else { @@ -101,13 +173,15 @@ impl Vm { } } - pub fn read(&mut self) -> (u8, Span) { + fn read(&mut self) -> Result<&(u8, Span), VmError> { + let current = self.chunk.read(self.ip)?; + self.ip += 1; - self.chunk.read(self.ip - 1) + Ok(current) } - pub fn read_constant(&self, index: usize) -> Result { + fn read_constant(&self, index: usize) -> Result { Ok(self.chunk.get_constant(index)?.clone()) } } @@ -138,32 +212,49 @@ impl From for VmError { pub enum Instruction { Constant = 0, Return = 1, + Pop = 2, + DefineGlobal = 3, // Unary - Negate = 2, + Negate = 4, + Not = 5, // Binary - Add = 3, - Subtract = 4, - Multiply = 5, - Divide = 6, + Add = 6, + Subtract = 7, + Multiply = 8, + Divide = 9, + Greater = 10, + Less = 11, + GreaterEqual = 12, + LessEqual = 13, + Equal = 14, + NotEqual = 15, + And = 16, + Or = 17, } impl Instruction { pub fn from_byte(byte: u8) -> Option { match byte { - 0 => Some(Self::Constant), - 1 => Some(Self::Return), - - // Unary - 2 => Some(Self::Negate), - - // Binary - 3 => Some(Self::Add), - 4 => Some(Self::Subtract), - 5 => Some(Self::Multiply), - 6 => Some(Self::Divide), - + 0 => Some(Instruction::Constant), + 1 => Some(Instruction::Return), + 2 => Some(Instruction::Pop), + 3 => Some(Instruction::DefineGlobal), + 4 => Some(Instruction::Negate), + 5 => Some(Instruction::Not), + 6 => Some(Instruction::Add), + 7 => Some(Instruction::Subtract), + 8 => Some(Instruction::Multiply), + 9 => Some(Instruction::Divide), + 10 => Some(Instruction::Greater), + 11 => Some(Instruction::Less), + 12 => Some(Instruction::GreaterEqual), + 13 => Some(Instruction::LessEqual), + 14 => Some(Instruction::Equal), + 15 => Some(Instruction::NotEqual), + 16 => Some(Instruction::And), + 17 => Some(Instruction::Or), _ => None, } } @@ -171,24 +262,40 @@ impl Instruction { pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String { match self { Instruction::Constant => { - let (index, _) = chunk.read(offset + 1); + let (index, _) = chunk.read(offset + 1).unwrap(); let value_display = chunk - .get_constant(index as usize) + .get_constant(*index as usize) .map(|value| value.to_string()) .unwrap_or_else(|error| format!("{:?}", error)); format!("{offset:04} CONSTANT {index} {value_display}") } Instruction::Return => format!("{offset:04} RETURN"), + Instruction::Pop => format!("{offset:04} POP"), + Instruction::DefineGlobal => { + let (index, _) = chunk.read(offset + 1).unwrap(); + let identifier = chunk.get_identifier(*index as usize).unwrap(); + + format!("{offset:04} DEFINE_GLOBAL {identifier}") + } // Unary Instruction::Negate => format!("{offset:04} NEGATE"), + Instruction::Not => format!("{offset:04} NOT"), // Binary Instruction::Add => format!("{offset:04} ADD"), Instruction::Subtract => format!("{offset:04} SUBTRACT"), Instruction::Multiply => format!("{offset:04} MULTIPLY"), Instruction::Divide => format!("{offset:04} DIVIDE"), + Instruction::Greater => format!("{offset:04} GREATER"), + Instruction::Less => format!("{offset:04} LESS"), + Instruction::GreaterEqual => format!("{offset:04} GREATER_EQUAL"), + Instruction::LessEqual => format!("{offset:04} LESS_EQUAL"), + Instruction::Equal => format!("{offset:04} EQUAL"), + Instruction::NotEqual => format!("{offset:04} NOT_EQUAL"), + Instruction::And => format!("{offset:04} AND"), + Instruction::Or => format!("{offset:04} OR"), } } } diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 06dd3f1..1090834 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -1,6 +1,7 @@ use std::fs::read_to_string; use clap::Parser; +use dust_lang::{parse, run}; #[derive(Parser)] struct Cli { @@ -36,9 +37,20 @@ fn main() { } fn parse_and_display_errors(source: &str) { - todo!() + match parse(source) { + Ok(chunk) => println!("{chunk}"), + Err(error) => { + eprintln!("{:?}", error); + } + } } fn run_and_display_errors(source: &str) { - todo!() + match run(source) { + Ok(Some(value)) => println!("{}", value), + Ok(_) => {} + Err(error) => { + eprintln!("{:?}", error); + } + } }