Add basic VM

This commit is contained in:
Jeff 2024-08-04 22:15:31 -04:00
parent 0ca443b133
commit f2bfe2ed06
5 changed files with 156 additions and 38 deletions

View File

@ -0,0 +1,23 @@
use crate::{Identifier, Span, Value};
#[derive(Debug, PartialEq, Clone)]
pub struct Instruction {
pub operation: Operation,
pub span: Span,
}
impl Instruction {
pub fn new(operation: Operation, span: Span) -> Self {
Self { operation, span }
}
}
#[derive(Debug, PartialEq, Clone)]
pub enum Operation {
Add(Box<(Instruction, Instruction)>),
Assign(Box<(Instruction, Instruction)>),
Constant(Value),
Identifier(Identifier),
List(Vec<Instruction>),
Multiply(Box<(Instruction, Instruction)>),
}

View File

@ -8,15 +8,21 @@ interpret Dust code. The `interpret` function is a convenience function that cre
`Interpreter` and runs the given source code. `Interpreter` and runs the given source code.
*/ */
pub mod identifier; pub mod identifier;
pub mod instruction;
pub mod lex; pub mod lex;
pub mod parse; pub mod parse;
pub mod token; pub mod token;
pub mod r#type; pub mod r#type;
pub mod value; pub mod value;
pub mod vm;
pub use identifier::Identifier; pub use identifier::Identifier;
pub use instruction::{Instruction, Operation};
pub use lex::{lex, LexError, Lexer};
pub use parse::{parse, ParseError, Parser};
pub use r#type::Type; pub use r#type::Type;
pub use token::Token; pub use token::Token;
pub use value::Value; pub use value::{Value, ValueError};
pub use vm::Vm;
pub type Span = (usize, usize); pub type Span = (usize, usize);

View File

@ -1,36 +1,24 @@
use crate::{ use crate::{
identifier::Identifier,
lex::{LexError, Lexer}, lex::{LexError, Lexer},
Span, Token, Value, Instruction, Operation, Span, Token, Value,
}; };
pub fn parse(input: &str) -> Result<Instruction, ParseError> { pub fn parse(input: &str) -> Result<Vec<Instruction>, ParseError> {
let lexer = Lexer::new(input); let lexer = Lexer::new(input);
let mut parser = Parser::new(lexer); let mut parser = Parser::new(lexer);
let mut instructions = Vec::new();
parser.parse() loop {
} let instruction = parser.parse()?;
#[derive(Debug, PartialEq, Clone)] instructions.push(instruction);
pub struct Instruction {
pub operation: Operation,
pub span: Span,
}
impl Instruction { if let Token::Eof = parser.current.0 {
pub fn new(operation: Operation, span: Span) -> Self { break;
Self { operation, span } }
} }
}
#[derive(Debug, PartialEq, Clone)] Ok(instructions)
pub enum Operation {
Add(Box<(Instruction, Instruction)>),
Assign(Box<(Instruction, Instruction)>),
Constant(Value),
Identifier(Identifier),
List(Vec<Instruction>),
Multiply(Box<(Instruction, Instruction)>),
} }
pub struct Parser<'src> { pub struct Parser<'src> {
@ -205,6 +193,7 @@ impl From<LexError> for ParseError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::Identifier;
use super::*; use super::*;
@ -214,7 +203,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::List(vec![ Operation::List(vec![
Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)), Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)),
Instruction::new( Instruction::new(
@ -245,7 +234,7 @@ mod tests {
) )
]), ]),
(0, 24) (0, 24)
)) )])
); );
} }
@ -255,13 +244,13 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::List(vec![ Operation::List(vec![
Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)), Instruction::new(Operation::Constant(Value::integer(1)), (1, 2)),
Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)),
]), ]),
(0, 6) (0, 6)
)) )])
); );
} }
@ -271,7 +260,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new(Operation::List(vec![]), (0, 2))) Ok(vec![Instruction::new(Operation::List(vec![]), (0, 2))])
); );
} }
@ -281,10 +270,10 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::Constant(Value::float(42.0)), Operation::Constant(Value::float(42.0)),
(0, 4) (0, 4)
)) )])
); );
} }
@ -294,13 +283,13 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::Add(Box::new(( Operation::Add(Box::new((
Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)),
Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)),
))), ))),
(0, 5) (0, 5)
)) )])
); );
} }
@ -310,13 +299,13 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::Multiply(Box::new(( Operation::Multiply(Box::new((
Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)),
Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)), Instruction::new(Operation::Constant(Value::integer(2)), (4, 5)),
))), ))),
(0, 5) (0, 5)
)) )])
); );
} }
@ -326,7 +315,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::Add(Box::new(( Operation::Add(Box::new((
Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)), Instruction::new(Operation::Constant(Value::integer(1)), (0, 1)),
Instruction::new( Instruction::new(
@ -338,7 +327,7 @@ mod tests {
), ),
))), ))),
(0, 9) (0, 9)
)) )])
); );
} }
@ -348,7 +337,7 @@ mod tests {
assert_eq!( assert_eq!(
parse(input), parse(input),
Ok(Instruction::new( Ok(vec![Instruction::new(
Operation::Assign(Box::new(( Operation::Assign(Box::new((
Instruction::new(Operation::Identifier(Identifier::new("a")), (0, 1)), Instruction::new(Operation::Identifier(Identifier::new("a")), (0, 1)),
Instruction::new( Instruction::new(
@ -372,7 +361,7 @@ mod tests {
), ),
))), ))),
(0, 13) (0, 13)
)) )])
); );
} }
} }

View File

@ -78,6 +78,16 @@ impl Value {
None None
} }
} }
pub fn add(&self, other: &Value) -> Result<Value, ValueError> {
match (self.inner().as_ref(), other.inner().as_ref()) {
(ValueInner::Float(left), ValueInner::Float(right)) => Ok(Value::float(left + right)),
(ValueInner::Integer(left), ValueInner::Integer(right)) => {
Ok(Value::integer(left + right))
}
_ => Err(ValueError::CannotAdd(self.clone(), other.clone())),
}
}
} }
impl Display for Value { impl Display for Value {
@ -502,3 +512,8 @@ impl Ord for ValueInner {
} }
} }
} }
#[derive(Clone, Debug, PartialEq)]
pub enum ValueError {
CannotAdd(Value, Value),
}

85
dust-lang/src/vm.rs Normal file
View File

@ -0,0 +1,85 @@
use crate::{parse, Instruction, Operation, ParseError, Parser, Value, ValueError};
pub fn run(input: &str) -> Result<Option<Value>, VmError> {
let instructions = parse(input)?;
let vm = Vm::new(instructions);
vm.run()
}
pub struct Vm {
instructions: Vec<Instruction>,
}
impl Vm {
pub fn new(instructions: Vec<Instruction>) -> Self {
Vm { instructions }
}
pub fn run(&self) -> Result<Option<Value>, VmError> {
let mut previous_value = None;
for instruction in &self.instructions {
previous_value = self.run_instruction(instruction)?;
}
Ok(previous_value)
}
fn run_instruction(&self, instruction: &Instruction) -> Result<Option<Value>, VmError> {
match &instruction.operation {
Operation::Add(instructions) => {
let left = if let Some(value) = self.run_instruction(&instructions.0)? {
value
} else {
return Err(VmError::ExpectedValue(instructions.0.operation.clone()));
};
let right = if let Some(value) = self.run_instruction(&instructions.1)? {
value
} else {
return Err(VmError::ExpectedValue(instructions.1.operation.clone()));
};
let sum = left.add(&right)?;
Ok(Some(sum))
}
Operation::Assign(_) => todo!(),
Operation::Constant(value) => Ok(Some(value.clone())),
Operation::Identifier(_) => todo!(),
Operation::List(_) => todo!(),
Operation::Multiply(_) => todo!(),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum VmError {
ExpectedValue(Operation),
InvalidOperation(Operation),
ParseError(ParseError),
ValueError(ValueError),
}
impl From<ParseError> for VmError {
fn from(v: ParseError) -> Self {
Self::ParseError(v)
}
}
impl From<ValueError> for VmError {
fn from(v: ValueError) -> Self {
Self::ValueError(v)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add() {
let input = "1 + 2";
assert_eq!(run(input), Ok(Some(Value::integer(3))));
}
}