Add and pass tests
This commit is contained in:
parent
3ac15fe70b
commit
b8957190e0
@ -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)),
|
||||||
/// ]
|
/// ]
|
||||||
/// )
|
/// )
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -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 {
|
||||||
|
@ -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)],
|
||||||
|
@ -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";
|
||||||
|
@ -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!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"),
|
||||||
|
Loading…
Reference in New Issue
Block a user