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!(
/// 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)),
/// ]
/// )
/// ```

View File

@ -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 {

View File

@ -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<u8, ParseError> {
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<u8, ParseError> {
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)],

View File

@ -13,6 +13,14 @@ pub fn run(source: &str) -> Result<Option<Value>, 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";

View File

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

View File

@ -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"),