Add basic VM
This commit is contained in:
parent
0ca443b133
commit
f2bfe2ed06
23
dust-lang/src/instruction.rs
Normal file
23
dust-lang/src/instruction.rs
Normal 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)>),
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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)
|
||||||
))
|
)])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
85
dust-lang/src/vm.rs
Normal 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))));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user