diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index 70b082a..557a6e2 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -18,12 +18,12 @@ use crate::{Span, Token}; /// assert_eq!( /// tokens, /// [ -/// (Token::Identifier("x"), (0, 1)), -/// (Token::Equal, (2, 3)), -/// (Token::Integer("1"), (4, 5)), -/// (Token::Plus, (6, 7)), -/// (Token::Integer("2"), (8, 9)), -/// (Token::Eof, (9, 9)), +/// (Token::Identifier("x"), Span(0, 1)), +/// (Token::Equal, Span(2, 3)), +/// (Token::Integer("1"), Span(4, 5)), +/// (Token::Plus, Span(6, 7)), +/// (Token::Integer("2"), Span(8, 9)), +/// (Token::Eof, Span(9, 9)), /// ] /// ); /// ``` @@ -70,12 +70,12 @@ pub fn lex<'chars, 'src: 'chars>( /// assert_eq!( /// tokens, /// [ -/// (Token::Identifier("x"), (0, 1)), -/// (Token::Equal, (2, 3)), -/// (Token::Integer("1"), (4, 5)), -/// (Token::Plus, (6, 7)), -/// (Token::Integer("2"), (8, 9)), -/// (Token::Eof, (9, 9)), +/// (Token::Identifier("x"), Span(0, 1)), +/// (Token::Equal, Span(2, 3)), +/// (Token::Integer("1"), Span(4, 5)), +/// (Token::Plus, Span(6, 7)), +/// (Token::Integer("2"), Span(8, 9)), +/// (Token::Eof, Span(9, 9)), /// ] /// ) /// ``` diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 172254a..34156e5 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -31,7 +31,7 @@ pub use chunk::{Chunk, ChunkError}; pub use constructor::{ConstructError, Constructor}; pub use dust_error::DustError; pub use identifier::Identifier; -pub use lexer::{LexError, Lexer}; +pub use lexer::{lex, LexError, Lexer}; pub use parser::{parse, ParseError, Parser}; pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict}; pub use run::run; @@ -44,7 +44,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Span(usize, usize); +pub struct Span(pub usize, pub usize); impl Display for Span { fn fmt(&self, f: &mut Formatter) -> fmt::Result { diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser.rs index e82e2af..78d0765 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser.rs @@ -199,11 +199,20 @@ impl<'src> Parser<'src> { } fn parse_variable(&mut self) -> Result<(), ParseError> { - todo!() + self.parse_named_variable_from(self.previous_token.to_owned()) } - fn parse_identifier(&mut self) -> Result { - if let Token::Identifier(text) = self.current_token { + fn parse_named_variable_from(&mut self, token: TokenOwned) -> Result<(), ParseError> { + let identifier_index = self.parse_identifier_from(token)?; + + self.emit_byte(Instruction::GetGlobal as u8, self.previous_position); + self.emit_byte(identifier_index, self.previous_position); + + Ok(()) + } + + fn parse_identifier_from(&mut self, token: TokenOwned) -> Result { + if let TokenOwned::Identifier(text) = token { self.advance()?; let identifier = Identifier::new(text); @@ -250,7 +259,7 @@ impl<'src> Parser<'src> { self.expect(TokenKind::Let)?; let position = self.current_position; - let identifier_index = self.parse_identifier()?; + let identifier_index = self.parse_identifier_from(self.current_token.to_owned())?; self.expect(TokenKind::Equal)?; self.parse_expression()?; @@ -259,7 +268,7 @@ impl<'src> Parser<'src> { } fn define_variable(&mut self, identifier_index: u8, position: Span) -> Result<(), ParseError> { - self.emit_byte(Instruction::DefineGlobal as u8, position); + self.emit_byte(Instruction::SetGlobal as u8, position); self.emit_byte(identifier_index, position); Ok(()) @@ -521,7 +530,7 @@ mod tests { vec![ (Instruction::Constant as u8, Span(8, 10)), (0, Span(8, 10)), - (Instruction::DefineGlobal as u8, Span(4, 5)), + (Instruction::SetGlobal as u8, Span(4, 5)), (0, Span(4, 5)) ], vec![Value::integer(42)], diff --git a/dust-lang/src/run.rs b/dust-lang/src/run.rs index 16cbbc9..85e42de 100644 --- a/dust-lang/src/run.rs +++ b/dust-lang/src/run.rs @@ -13,6 +13,14 @@ pub fn run(source: &str) -> Result, DustError> { mod tests { use super::*; + #[test] + fn variable() { + let source = "let foo = 42; foo"; + let result = run(source); + + assert_eq!(result, Ok(Some(Value::integer(42)))); + } + #[test] fn integer() { let source = "42"; diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index c2b8a3a..1fac1b4 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -1370,8 +1370,8 @@ impl Function { pub fn call( self, _type_arguments: Option>, - value_arguments: Option>, - ) -> Result, ()> { + _value_arguments: Option>, + ) -> Result, String> { todo!() } } diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs index 5092637..e91e473 100644 --- a/dust-lang/src/vm.rs +++ b/dust-lang/src/vm.rs @@ -31,10 +31,10 @@ impl Vm { match instruction { Instruction::Constant => { - let (index, position) = self.read().copied()?; + let (index, _) = self.read().copied()?; let value = self.read_constant(index as usize)?; - self.stack.push(value); + self.push(value)?; } Instruction::Return => { let value = self.pop()?; @@ -44,24 +44,34 @@ impl Vm { Instruction::Pop => { self.pop()?; } - Instruction::DefineGlobal => { + Instruction::SetGlobal => { let (index, _) = self.read().copied()?; let identifier = self.chunk.get_identifier(index as usize)?.clone(); let value = self.pop()?; self.globals.insert(identifier, value); } + Instruction::GetGlobal => { + let (index, _) = self.read().copied()?; + let identifier = self.chunk.get_identifier(index as usize)?; + let value = + self.globals.get(identifier).cloned().ok_or_else(|| { + VmError::UndefinedGlobal(identifier.clone(), position) + })?; + + self.push(value)?; + } // Unary Instruction::Negate => { let negated = self.pop()?.negate()?; - self.stack.push(negated); + self.push(negated)?; } Instruction::Not => { let not = self.pop()?.not()?; - self.stack.push(not); + self.push(not)?; } // Binary @@ -70,84 +80,84 @@ impl Vm { let left = self.pop()?; let sum = left.add(&right)?; - self.stack.push(sum); + self.push(sum)?; } Instruction::Subtract => { let right = self.pop()?; let left = self.pop()?; let difference = left.subtract(&right)?; - self.stack.push(difference); + self.push(difference)?; } Instruction::Multiply => { let right = self.pop()?; let left = self.pop()?; let product = left.multiply(&right)?; - self.stack.push(product); + self.push(product)?; } Instruction::Divide => { let right = self.pop()?; let left = self.pop()?; let quotient = left.divide(&right)?; - self.stack.push(quotient); + self.push(quotient)?; } Instruction::Greater => { let right = self.pop()?; let left = self.pop()?; let greater = left.greater_than(&right)?; - self.stack.push(greater); + self.push(greater)?; } Instruction::Less => { let right = self.pop()?; let left = self.pop()?; let less = left.less_than(&right)?; - self.stack.push(less); + self.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); + self.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); + self.push(less_equal)?; } Instruction::Equal => { let right = self.pop()?; let left = self.pop()?; let equal = left.equal(&right)?; - self.stack.push(equal); + self.push(equal)?; } Instruction::NotEqual => { let right = self.pop()?; let left = self.pop()?; let not_equal = left.not_equal(&right)?; - self.stack.push(not_equal); + self.push(not_equal)?; } Instruction::And => { let right = self.pop()?; let left = self.pop()?; let and = left.and(&right)?; - self.stack.push(and); + self.push(and)?; } Instruction::Or => { let right = self.pop()?; let left = self.pop()?; let or = left.or(&right)?; - self.stack.push(or); + self.push(or)?; } } } @@ -191,7 +201,9 @@ pub enum VmError { InvalidInstruction(u8, Span), StackUnderflow, StackOverflow, + UndefinedGlobal(Identifier, Span), + // Wrappers for foreign errors Chunk(ChunkError), Value(ValueError), } @@ -213,25 +225,26 @@ pub enum Instruction { Constant = 0, Return = 1, Pop = 2, - DefineGlobal = 3, + SetGlobal = 3, + GetGlobal = 4, // Unary - Negate = 4, - Not = 5, + Negate = 5, + Not = 6, // Binary - Add = 6, - Subtract = 7, - Multiply = 8, - Divide = 9, - Greater = 10, - Less = 11, - GreaterEqual = 12, - LessEqual = 13, - Equal = 14, - NotEqual = 15, - And = 16, - Or = 17, + Add = 7, + Subtract = 8, + Multiply = 9, + Divide = 10, + Greater = 11, + Less = 12, + GreaterEqual = 13, + LessEqual = 14, + Equal = 15, + NotEqual = 16, + And = 17, + Or = 18, } impl Instruction { @@ -240,21 +253,22 @@ impl Instruction { 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), + 3 => Some(Instruction::SetGlobal), + 4 => Some(Instruction::GetGlobal), + 5 => Some(Instruction::Negate), + 6 => Some(Instruction::Not), + 7 => Some(Instruction::Add), + 8 => Some(Instruction::Subtract), + 9 => Some(Instruction::Multiply), + 10 => Some(Instruction::Divide), + 11 => Some(Instruction::Greater), + 12 => Some(Instruction::Less), + 13 => Some(Instruction::GreaterEqual), + 14 => Some(Instruction::LessEqual), + 15 => Some(Instruction::Equal), + 16 => Some(Instruction::NotEqual), + 17 => Some(Instruction::And), + 18 => Some(Instruction::Or), _ => None, } } @@ -272,12 +286,18 @@ impl Instruction { } Instruction::Return => format!("{offset:04} RETURN"), Instruction::Pop => format!("{offset:04} POP"), - Instruction::DefineGlobal => { + Instruction::SetGlobal => { let (index, _) = chunk.read(offset + 1).unwrap(); let identifier = chunk.get_identifier(*index as usize).unwrap(); format!("{offset:04} DEFINE_GLOBAL {identifier}") } + Instruction::GetGlobal => { + let (index, _) = chunk.read(offset + 1).unwrap(); + let identifier = chunk.get_identifier(*index as usize).unwrap(); + + format!("{offset:04} GET_GLOBAL {identifier}") + } // Unary Instruction::Negate => format!("{offset:04} NEGATE"),