Implement variables in the interpreter
This commit is contained in:
parent
746d567554
commit
fc5a50227f
11 changed files with 106 additions and 34 deletions
|
@ -8,6 +8,7 @@ pub enum ExpressionNode {
|
|||
BinaryExpr(BinaryExpr),
|
||||
GroupingExpr(GroupingExpr),
|
||||
Literal(Literal),
|
||||
Variable(VariableExpr),
|
||||
UnaryExpr(UnaryExpr),
|
||||
}
|
||||
|
||||
|
@ -16,7 +17,12 @@ macro_rules! all_variants {
|
|||
{
|
||||
use match_any::match_any;
|
||||
use $crate::ast::expression::expression_node::*;
|
||||
match_any!($expr, ExpressionNode::BinaryExpr($val_name) | ExpressionNode::GroupingExpr($val_name) | ExpressionNode::Literal($val_name) | ExpressionNode::UnaryExpr($val_name) => $expr_arm)
|
||||
match_any!($expr,
|
||||
ExpressionNode::BinaryExpr($val_name) |
|
||||
ExpressionNode::GroupingExpr($val_name) |
|
||||
ExpressionNode::Literal($val_name) |
|
||||
ExpressionNode::Variable($val_name) |
|
||||
ExpressionNode::UnaryExpr($val_name) => $expr_arm)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -176,6 +182,22 @@ impl Debug for UnaryExpr {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct VariableExpr {
|
||||
pub var_name: String,
|
||||
}
|
||||
|
||||
impl Debug for VariableExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "(variable({}))", self.var_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl VariableExpr {
|
||||
pub fn new(var_name: String) -> Self {
|
||||
Self { var_name }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -116,6 +116,7 @@ impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
|
|||
None => return Err(token.location.wrap(InnerASTParsingError::UnmatchedBrace)),
|
||||
}
|
||||
}
|
||||
TokenType::Identifier(var_name) => VariableExpr::new(var_name).into(),
|
||||
a => return Err(token.location.wrap(InnerASTParsingError::IncorrectToken(a))),
|
||||
};
|
||||
Ok(node)
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
use super::Interpret;
|
||||
use super::{types::Value, RuntimeError};
|
||||
use crate::ast::expression::expression_node;
|
||||
use crate::interpreter::world::World;
|
||||
|
||||
impl Interpret for expression_node::ExpressionNode {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
expression_node::all_variants!(self, n => n.interpret())
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
expression_node::all_variants!(self, n => n.interpret(w))
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for expression_node::Literal {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
fn interpret(&self, _: &mut World) -> Result<Value, RuntimeError> {
|
||||
Ok(self.clone().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for expression_node::BinaryExpr {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
let left_val = self.left.interpret().expect("expected lval");
|
||||
let right_val = self.right.interpret().expect("expected rval");
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
let left_val = self.left.interpret(w).expect("expected lval");
|
||||
let right_val = self.right.interpret(w).expect("expected rval");
|
||||
match self.operator {
|
||||
expression_node::Operator::BangEqual => Ok((left_val != right_val).into()),
|
||||
expression_node::Operator::Less => Ok((left_val < right_val).into()),
|
||||
|
@ -31,8 +32,8 @@ impl Interpret for expression_node::BinaryExpr {
|
|||
}
|
||||
|
||||
impl Interpret for expression_node::UnaryExpr {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
let val = self.right.interpret()?;
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
let val = self.right.interpret(w)?;
|
||||
match self.operator {
|
||||
expression_node::UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
|
||||
expression_node::UnaryOperator::Minus => match val {
|
||||
|
@ -45,7 +46,16 @@ impl Interpret for expression_node::UnaryExpr {
|
|||
}
|
||||
|
||||
impl Interpret for expression_node::GroupingExpr {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
self.0.interpret()
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
self.0.interpret(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for expression_node::VariableExpr {
|
||||
fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError> {
|
||||
match world.get_var(&self.var_name) {
|
||||
Some(v) => Ok(v.clone()),
|
||||
None => Err(RuntimeError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
mod expression_interpreter;
|
||||
mod statement_interpreter;
|
||||
use super::types::Value;
|
||||
pub use super::{error::RuntimeError, types};
|
||||
use super::{types::Value, world::World};
|
||||
|
||||
pub trait Interpret {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError>;
|
||||
fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError>;
|
||||
}
|
||||
|
|
|
@ -1,30 +1,33 @@
|
|||
use super::Interpret;
|
||||
use super::{types::Value, RuntimeError};
|
||||
use crate::ast::statement::statement_node;
|
||||
use crate::interpreter::world::World;
|
||||
|
||||
impl Interpret for statement_node::Statement {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
statement_node::all_variants!(self, n => n.interpret())
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
statement_node::all_variants!(self, n => n.interpret(w))
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for statement_node::PrintStatement {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
let res = self.0.interpret()?;
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
let res = self.0.interpret(w)?;
|
||||
println!("{:?}", res);
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for statement_node::ExpressionStatement {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
self.0.interpret()
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
self.0.interpret(w)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interpret for statement_node::VariableAssignmentStatement {
|
||||
fn interpret(&self) -> Result<Value, RuntimeError> {
|
||||
let expr_val = self.node.interpret()?;
|
||||
fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
|
||||
let expr_val = self.node.interpret(w)?;
|
||||
// Clone for now, later this will use a GC and won't need to clone
|
||||
w.set_var(self.var_name.clone(), expr_val.clone());
|
||||
Ok(expr_val)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod ast_walker;
|
||||
pub mod error;
|
||||
pub mod types;
|
||||
pub mod world;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::ast::expression::expression_node;
|
||||
use from_variants::FromVariants;
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, FromVariants)]
|
||||
#[derive(Debug, PartialEq, PartialOrd, Clone, FromVariants)]
|
||||
pub enum Value {
|
||||
Int(i32),
|
||||
Float(f32),
|
||||
|
|
35
src/interpreter/world.rs
Normal file
35
src/interpreter/world.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::ast::statement::statement_node::Statement;
|
||||
|
||||
use super::{
|
||||
ast_walker::{Interpret, RuntimeError},
|
||||
types::Value,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct World {
|
||||
variables: HashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn set_var(&mut self, name: String, v: Value) -> Option<Value> {
|
||||
self.variables.insert(name, v)
|
||||
}
|
||||
pub fn get_var(&mut self, name: &str) -> Option<&Value> {
|
||||
self.variables.get(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn exec(&mut self, nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
|
||||
let mut last_res = Value::Nil;
|
||||
for statement in nodes {
|
||||
last_res = statement.interpret(self)?;
|
||||
}
|
||||
Ok(last_res)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ use ast::parser::ParseAllResult;
|
|||
use ast::statement::statement_node::Statement;
|
||||
use interpreter::ast_walker::{Interpret, RuntimeError};
|
||||
use interpreter::types::Value;
|
||||
use interpreter::world::World;
|
||||
use lexer::{token::Token, Lexer, LexingError};
|
||||
|
||||
pub fn lex<'a, 'b>(
|
||||
|
@ -25,8 +26,9 @@ pub fn parse(tokens: Vec<Token>) -> ParseAllResult {
|
|||
|
||||
pub fn exec(nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
|
||||
let mut last_res = Value::Nil;
|
||||
let mut world = World::new();
|
||||
for statement in nodes {
|
||||
last_res = statement.interpret()?;
|
||||
last_res = statement.interpret(&mut world)?;
|
||||
}
|
||||
Ok(last_res)
|
||||
}
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -1,5 +1,6 @@
|
|||
use clap::Parser;
|
||||
use crftng_intrprtrs::{exec, lex, parse};
|
||||
use crftng_intrprtrs::interpreter::world::World;
|
||||
use crftng_intrprtrs::{lex, parse};
|
||||
use std::path::PathBuf;
|
||||
use std::{fs, io};
|
||||
use tracing::Level;
|
||||
|
@ -16,7 +17,7 @@ struct Args {
|
|||
no_run: bool,
|
||||
}
|
||||
|
||||
fn run(code: &str, args: &Args) {
|
||||
fn run(code: &str, args: &Args, world: &mut World) {
|
||||
let src_file = args.file.as_ref().map(|f| f.to_string_lossy().to_string());
|
||||
let tokens = match lex(code, src_file.as_deref()) {
|
||||
Ok(v) => v,
|
||||
|
@ -44,19 +45,20 @@ fn run(code: &str, args: &Args) {
|
|||
}
|
||||
|
||||
if !args.no_run {
|
||||
println!("{:?}", exec(ast));
|
||||
println!("{:?}", world.exec(ast));
|
||||
}
|
||||
}
|
||||
|
||||
fn run_file(args: &Args) -> Result<(), io::Error> {
|
||||
let src = fs::read_to_string(args.file.as_ref().unwrap())?;
|
||||
run(&src, args);
|
||||
run(&src, args, &mut World::new());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_repl(args: &Args) {
|
||||
assert!(args.file.is_none());
|
||||
|
||||
let mut world = World::new();
|
||||
let mut line_buf = String::new();
|
||||
loop {
|
||||
match io::stdin().read_line(&mut line_buf) {
|
||||
|
@ -68,7 +70,7 @@ fn run_repl(args: &Args) {
|
|||
|
||||
let line = line_buf.trim();
|
||||
if !line.is_empty() {
|
||||
run(&line_buf, args);
|
||||
run(&line_buf, args, &mut world);
|
||||
line_buf.clear();
|
||||
}
|
||||
}
|
||||
|
|
8
test.lox
8
test.lox
|
@ -1,6 +1,2 @@
|
|||
12 == 1;
|
||||
print 1;
|
||||
print 1.90 == 1.90;
|
||||
print 1.90;
|
||||
print 2;
|
||||
nil;
|
||||
asdf = 1;
|
||||
print asdf;
|
||||
|
|
Loading…
Reference in a new issue