Add and pass tests

This commit is contained in:
Jeff 2024-09-07 13:51:05 -04:00
parent 3ac15fe70b
commit b8957190e0
6 changed files with 107 additions and 70 deletions

View File

@ -18,12 +18,12 @@ use crate::{Span, Token};
/// assert_eq!( /// assert_eq!(
/// tokens, /// tokens,
/// [ /// [
/// (Token::Identifier("x"), (0, 1)), /// (Token::Identifier("x"), Span(0, 1)),
/// (Token::Equal, (2, 3)), /// (Token::Equal, Span(2, 3)),
/// (Token::Integer("1"), (4, 5)), /// (Token::Integer("1"), Span(4, 5)),
/// (Token::Plus, (6, 7)), /// (Token::Plus, Span(6, 7)),
/// (Token::Integer("2"), (8, 9)), /// (Token::Integer("2"), Span(8, 9)),
/// (Token::Eof, (9, 9)), /// (Token::Eof, Span(9, 9)),
/// ] /// ]
/// ); /// );
/// ``` /// ```
@ -70,12 +70,12 @@ pub fn lex<'chars, 'src: 'chars>(
/// assert_eq!( /// assert_eq!(
/// tokens, /// tokens,
/// [ /// [
/// (Token::Identifier("x"), (0, 1)), /// (Token::Identifier("x"), Span(0, 1)),
/// (Token::Equal, (2, 3)), /// (Token::Equal, Span(2, 3)),
/// (Token::Integer("1"), (4, 5)), /// (Token::Integer("1"), Span(4, 5)),
/// (Token::Plus, (6, 7)), /// (Token::Plus, Span(6, 7)),
/// (Token::Integer("2"), (8, 9)), /// (Token::Integer("2"), Span(8, 9)),
/// (Token::Eof, (9, 9)), /// (Token::Eof, Span(9, 9)),
/// ] /// ]
/// ) /// )
/// ``` /// ```

View File

@ -31,7 +31,7 @@ pub use chunk::{Chunk, ChunkError};
pub use constructor::{ConstructError, Constructor}; pub use constructor::{ConstructError, Constructor};
pub use dust_error::DustError; pub use dust_error::DustError;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};
pub use parser::{parse, ParseError, Parser}; pub use parser::{parse, ParseError, Parser};
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict}; pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
pub use run::run; pub use run::run;
@ -44,7 +44,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[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 { impl Display for Span {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {

View File

@ -199,11 +199,20 @@ impl<'src> Parser<'src> {
} }
fn parse_variable(&mut self) -> Result<(), ParseError> { fn parse_variable(&mut self) -> Result<(), ParseError> {
todo!() self.parse_named_variable_from(self.previous_token.to_owned())
} }
fn parse_identifier(&mut self) -> Result<u8, ParseError> { fn parse_named_variable_from(&mut self, token: TokenOwned) -> Result<(), ParseError> {
if let Token::Identifier(text) = self.current_token { 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<u8, ParseError> {
if let TokenOwned::Identifier(text) = token {
self.advance()?; self.advance()?;
let identifier = Identifier::new(text); let identifier = Identifier::new(text);
@ -250,7 +259,7 @@ impl<'src> Parser<'src> {
self.expect(TokenKind::Let)?; self.expect(TokenKind::Let)?;
let position = self.current_position; 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.expect(TokenKind::Equal)?;
self.parse_expression()?; self.parse_expression()?;
@ -259,7 +268,7 @@ impl<'src> Parser<'src> {
} }
fn define_variable(&mut self, identifier_index: u8, position: Span) -> Result<(), ParseError> { 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); self.emit_byte(identifier_index, position);
Ok(()) Ok(())
@ -521,7 +530,7 @@ mod tests {
vec![ vec![
(Instruction::Constant as u8, Span(8, 10)), (Instruction::Constant as u8, Span(8, 10)),
(0, 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)) (0, Span(4, 5))
], ],
vec![Value::integer(42)], vec![Value::integer(42)],

View File

@ -13,6 +13,14 @@ pub fn run(source: &str) -> Result<Option<Value>, DustError> {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn variable() {
let source = "let foo = 42; foo";
let result = run(source);
assert_eq!(result, Ok(Some(Value::integer(42))));
}
#[test] #[test]
fn integer() { fn integer() {
let source = "42"; let source = "42";

View File

@ -1370,8 +1370,8 @@ impl Function {
pub fn call( pub fn call(
self, self,
_type_arguments: Option<Vec<Type>>, _type_arguments: Option<Vec<Type>>,
value_arguments: Option<Vec<Value>>, _value_arguments: Option<Vec<Value>>,
) -> Result<Option<Value>, ()> { ) -> Result<Option<Value>, String> {
todo!() todo!()
} }
} }

View File

@ -31,10 +31,10 @@ impl Vm {
match instruction { match instruction {
Instruction::Constant => { Instruction::Constant => {
let (index, position) = self.read().copied()?; let (index, _) = self.read().copied()?;
let value = self.read_constant(index as usize)?; let value = self.read_constant(index as usize)?;
self.stack.push(value); self.push(value)?;
} }
Instruction::Return => { Instruction::Return => {
let value = self.pop()?; let value = self.pop()?;
@ -44,24 +44,34 @@ impl Vm {
Instruction::Pop => { Instruction::Pop => {
self.pop()?; self.pop()?;
} }
Instruction::DefineGlobal => { Instruction::SetGlobal => {
let (index, _) = self.read().copied()?; let (index, _) = self.read().copied()?;
let identifier = self.chunk.get_identifier(index as usize)?.clone(); let identifier = self.chunk.get_identifier(index as usize)?.clone();
let value = self.pop()?; let value = self.pop()?;
self.globals.insert(identifier, value); 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 // Unary
Instruction::Negate => { Instruction::Negate => {
let negated = self.pop()?.negate()?; let negated = self.pop()?.negate()?;
self.stack.push(negated); self.push(negated)?;
} }
Instruction::Not => { Instruction::Not => {
let not = self.pop()?.not()?; let not = self.pop()?.not()?;
self.stack.push(not); self.push(not)?;
} }
// Binary // Binary
@ -70,84 +80,84 @@ impl Vm {
let left = self.pop()?; let left = self.pop()?;
let sum = left.add(&right)?; let sum = left.add(&right)?;
self.stack.push(sum); self.push(sum)?;
} }
Instruction::Subtract => { Instruction::Subtract => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let difference = left.subtract(&right)?; let difference = left.subtract(&right)?;
self.stack.push(difference); self.push(difference)?;
} }
Instruction::Multiply => { Instruction::Multiply => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let product = left.multiply(&right)?; let product = left.multiply(&right)?;
self.stack.push(product); self.push(product)?;
} }
Instruction::Divide => { Instruction::Divide => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let quotient = left.divide(&right)?; let quotient = left.divide(&right)?;
self.stack.push(quotient); self.push(quotient)?;
} }
Instruction::Greater => { Instruction::Greater => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let greater = left.greater_than(&right)?; let greater = left.greater_than(&right)?;
self.stack.push(greater); self.push(greater)?;
} }
Instruction::Less => { Instruction::Less => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let less = left.less_than(&right)?; let less = left.less_than(&right)?;
self.stack.push(less); self.push(less)?;
} }
Instruction::GreaterEqual => { Instruction::GreaterEqual => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let greater_equal = left.greater_than_or_equal(&right)?; let greater_equal = left.greater_than_or_equal(&right)?;
self.stack.push(greater_equal); self.push(greater_equal)?;
} }
Instruction::LessEqual => { Instruction::LessEqual => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let less_equal = left.less_than_or_equal(&right)?; let less_equal = left.less_than_or_equal(&right)?;
self.stack.push(less_equal); self.push(less_equal)?;
} }
Instruction::Equal => { Instruction::Equal => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let equal = left.equal(&right)?; let equal = left.equal(&right)?;
self.stack.push(equal); self.push(equal)?;
} }
Instruction::NotEqual => { Instruction::NotEqual => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let not_equal = left.not_equal(&right)?; let not_equal = left.not_equal(&right)?;
self.stack.push(not_equal); self.push(not_equal)?;
} }
Instruction::And => { Instruction::And => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let and = left.and(&right)?; let and = left.and(&right)?;
self.stack.push(and); self.push(and)?;
} }
Instruction::Or => { Instruction::Or => {
let right = self.pop()?; let right = self.pop()?;
let left = self.pop()?; let left = self.pop()?;
let or = left.or(&right)?; let or = left.or(&right)?;
self.stack.push(or); self.push(or)?;
} }
} }
} }
@ -191,7 +201,9 @@ pub enum VmError {
InvalidInstruction(u8, Span), InvalidInstruction(u8, Span),
StackUnderflow, StackUnderflow,
StackOverflow, StackOverflow,
UndefinedGlobal(Identifier, Span),
// Wrappers for foreign errors
Chunk(ChunkError), Chunk(ChunkError),
Value(ValueError), Value(ValueError),
} }
@ -213,25 +225,26 @@ pub enum Instruction {
Constant = 0, Constant = 0,
Return = 1, Return = 1,
Pop = 2, Pop = 2,
DefineGlobal = 3, SetGlobal = 3,
GetGlobal = 4,
// Unary // Unary
Negate = 4, Negate = 5,
Not = 5, Not = 6,
// Binary // Binary
Add = 6, Add = 7,
Subtract = 7, Subtract = 8,
Multiply = 8, Multiply = 9,
Divide = 9, Divide = 10,
Greater = 10, Greater = 11,
Less = 11, Less = 12,
GreaterEqual = 12, GreaterEqual = 13,
LessEqual = 13, LessEqual = 14,
Equal = 14, Equal = 15,
NotEqual = 15, NotEqual = 16,
And = 16, And = 17,
Or = 17, Or = 18,
} }
impl Instruction { impl Instruction {
@ -240,21 +253,22 @@ impl Instruction {
0 => Some(Instruction::Constant), 0 => Some(Instruction::Constant),
1 => Some(Instruction::Return), 1 => Some(Instruction::Return),
2 => Some(Instruction::Pop), 2 => Some(Instruction::Pop),
3 => Some(Instruction::DefineGlobal), 3 => Some(Instruction::SetGlobal),
4 => Some(Instruction::Negate), 4 => Some(Instruction::GetGlobal),
5 => Some(Instruction::Not), 5 => Some(Instruction::Negate),
6 => Some(Instruction::Add), 6 => Some(Instruction::Not),
7 => Some(Instruction::Subtract), 7 => Some(Instruction::Add),
8 => Some(Instruction::Multiply), 8 => Some(Instruction::Subtract),
9 => Some(Instruction::Divide), 9 => Some(Instruction::Multiply),
10 => Some(Instruction::Greater), 10 => Some(Instruction::Divide),
11 => Some(Instruction::Less), 11 => Some(Instruction::Greater),
12 => Some(Instruction::GreaterEqual), 12 => Some(Instruction::Less),
13 => Some(Instruction::LessEqual), 13 => Some(Instruction::GreaterEqual),
14 => Some(Instruction::Equal), 14 => Some(Instruction::LessEqual),
15 => Some(Instruction::NotEqual), 15 => Some(Instruction::Equal),
16 => Some(Instruction::And), 16 => Some(Instruction::NotEqual),
17 => Some(Instruction::Or), 17 => Some(Instruction::And),
18 => Some(Instruction::Or),
_ => None, _ => None,
} }
} }
@ -272,12 +286,18 @@ impl Instruction {
} }
Instruction::Return => format!("{offset:04} RETURN"), Instruction::Return => format!("{offset:04} RETURN"),
Instruction::Pop => format!("{offset:04} POP"), Instruction::Pop => format!("{offset:04} POP"),
Instruction::DefineGlobal => { Instruction::SetGlobal => {
let (index, _) = chunk.read(offset + 1).unwrap(); let (index, _) = chunk.read(offset + 1).unwrap();
let identifier = chunk.get_identifier(*index as usize).unwrap(); let identifier = chunk.get_identifier(*index as usize).unwrap();
format!("{offset:04} DEFINE_GLOBAL {identifier}") 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 // Unary
Instruction::Negate => format!("{offset:04} NEGATE"), Instruction::Negate => format!("{offset:04} NEGATE"),