Implement variables in the interpreter

This commit is contained in:
bad 2022-05-01 19:26:17 +02:00
parent 746d567554
commit fc5a50227f
11 changed files with 106 additions and 34 deletions

View file

@ -8,6 +8,7 @@ pub enum ExpressionNode {
BinaryExpr(BinaryExpr), BinaryExpr(BinaryExpr),
GroupingExpr(GroupingExpr), GroupingExpr(GroupingExpr),
Literal(Literal), Literal(Literal),
Variable(VariableExpr),
UnaryExpr(UnaryExpr), UnaryExpr(UnaryExpr),
} }
@ -16,7 +17,12 @@ macro_rules! all_variants {
{ {
use match_any::match_any; use match_any::match_any;
use $crate::ast::expression::expression_node::*; 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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -116,6 +116,7 @@ impl<'a, T: Iterator<Item = token::Token<'a>>> Parser<'a, T> {
None => return Err(token.location.wrap(InnerASTParsingError::UnmatchedBrace)), 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))), a => return Err(token.location.wrap(InnerASTParsingError::IncorrectToken(a))),
}; };
Ok(node) Ok(node)

View file

@ -1,23 +1,24 @@
use super::Interpret; use super::Interpret;
use super::{types::Value, RuntimeError}; use super::{types::Value, RuntimeError};
use crate::ast::expression::expression_node; use crate::ast::expression::expression_node;
use crate::interpreter::world::World;
impl Interpret for expression_node::ExpressionNode { impl Interpret for expression_node::ExpressionNode {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
expression_node::all_variants!(self, n => n.interpret()) expression_node::all_variants!(self, n => n.interpret(w))
} }
} }
impl Interpret for expression_node::Literal { impl Interpret for expression_node::Literal {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, _: &mut World) -> Result<Value, RuntimeError> {
Ok(self.clone().into()) Ok(self.clone().into())
} }
} }
impl Interpret for expression_node::BinaryExpr { impl Interpret for expression_node::BinaryExpr {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
let left_val = self.left.interpret().expect("expected lval"); let left_val = self.left.interpret(w).expect("expected lval");
let right_val = self.right.interpret().expect("expected rval"); let right_val = self.right.interpret(w).expect("expected rval");
match self.operator { match self.operator {
expression_node::Operator::BangEqual => Ok((left_val != right_val).into()), expression_node::Operator::BangEqual => Ok((left_val != right_val).into()),
expression_node::Operator::Less => 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 { impl Interpret for expression_node::UnaryExpr {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
let val = self.right.interpret()?; let val = self.right.interpret(w)?;
match self.operator { match self.operator {
expression_node::UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())), expression_node::UnaryOperator::Bang => Ok(Value::Bool(!val.truthy())),
expression_node::UnaryOperator::Minus => match val { expression_node::UnaryOperator::Minus => match val {
@ -45,7 +46,16 @@ impl Interpret for expression_node::UnaryExpr {
} }
impl Interpret for expression_node::GroupingExpr { impl Interpret for expression_node::GroupingExpr {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
self.0.interpret() 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),
}
} }
} }

View file

@ -1,8 +1,8 @@
mod expression_interpreter; mod expression_interpreter;
mod statement_interpreter; mod statement_interpreter;
use super::types::Value;
pub use super::{error::RuntimeError, types}; pub use super::{error::RuntimeError, types};
use super::{types::Value, world::World};
pub trait Interpret { pub trait Interpret {
fn interpret(&self) -> Result<Value, RuntimeError>; fn interpret(&self, world: &mut World) -> Result<Value, RuntimeError>;
} }

View file

@ -1,30 +1,33 @@
use super::Interpret; use super::Interpret;
use super::{types::Value, RuntimeError}; use super::{types::Value, RuntimeError};
use crate::ast::statement::statement_node; use crate::ast::statement::statement_node;
use crate::interpreter::world::World;
impl Interpret for statement_node::Statement { impl Interpret for statement_node::Statement {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
statement_node::all_variants!(self, n => n.interpret()) statement_node::all_variants!(self, n => n.interpret(w))
} }
} }
impl Interpret for statement_node::PrintStatement { impl Interpret for statement_node::PrintStatement {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
let res = self.0.interpret()?; let res = self.0.interpret(w)?;
println!("{:?}", res); println!("{:?}", res);
Ok(res) Ok(res)
} }
} }
impl Interpret for statement_node::ExpressionStatement { impl Interpret for statement_node::ExpressionStatement {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
self.0.interpret() self.0.interpret(w)
} }
} }
impl Interpret for statement_node::VariableAssignmentStatement { impl Interpret for statement_node::VariableAssignmentStatement {
fn interpret(&self) -> Result<Value, RuntimeError> { fn interpret(&self, w: &mut World) -> Result<Value, RuntimeError> {
let expr_val = self.node.interpret()?; 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) Ok(expr_val)
} }
} }

View file

@ -1,3 +1,4 @@
pub mod ast_walker; pub mod ast_walker;
pub mod error; pub mod error;
pub mod types; pub mod types;
pub mod world;

View file

@ -1,7 +1,7 @@
use crate::ast::expression::expression_node; use crate::ast::expression::expression_node;
use from_variants::FromVariants; use from_variants::FromVariants;
#[derive(Debug, PartialEq, PartialOrd, FromVariants)] #[derive(Debug, PartialEq, PartialOrd, Clone, FromVariants)]
pub enum Value { pub enum Value {
Int(i32), Int(i32),
Float(f32), Float(f32),

35
src/interpreter/world.rs Normal file
View 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)
}
}

View file

@ -8,6 +8,7 @@ use ast::parser::ParseAllResult;
use ast::statement::statement_node::Statement; use ast::statement::statement_node::Statement;
use interpreter::ast_walker::{Interpret, RuntimeError}; use interpreter::ast_walker::{Interpret, RuntimeError};
use interpreter::types::Value; use interpreter::types::Value;
use interpreter::world::World;
use lexer::{token::Token, Lexer, LexingError}; use lexer::{token::Token, Lexer, LexingError};
pub fn lex<'a, 'b>( 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> { pub fn exec(nodes: Vec<Statement>) -> Result<Value, RuntimeError> {
let mut last_res = Value::Nil; let mut last_res = Value::Nil;
let mut world = World::new();
for statement in nodes { for statement in nodes {
last_res = statement.interpret()?; last_res = statement.interpret(&mut world)?;
} }
Ok(last_res) Ok(last_res)
} }

View file

@ -1,5 +1,6 @@
use clap::Parser; 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::path::PathBuf;
use std::{fs, io}; use std::{fs, io};
use tracing::Level; use tracing::Level;
@ -16,7 +17,7 @@ struct Args {
no_run: bool, 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 src_file = args.file.as_ref().map(|f| f.to_string_lossy().to_string());
let tokens = match lex(code, src_file.as_deref()) { let tokens = match lex(code, src_file.as_deref()) {
Ok(v) => v, Ok(v) => v,
@ -44,19 +45,20 @@ fn run(code: &str, args: &Args) {
} }
if !args.no_run { if !args.no_run {
println!("{:?}", exec(ast)); println!("{:?}", world.exec(ast));
} }
} }
fn run_file(args: &Args) -> Result<(), io::Error> { fn run_file(args: &Args) -> Result<(), io::Error> {
let src = fs::read_to_string(args.file.as_ref().unwrap())?; let src = fs::read_to_string(args.file.as_ref().unwrap())?;
run(&src, args); run(&src, args, &mut World::new());
Ok(()) Ok(())
} }
fn run_repl(args: &Args) { fn run_repl(args: &Args) {
assert!(args.file.is_none()); assert!(args.file.is_none());
let mut world = World::new();
let mut line_buf = String::new(); let mut line_buf = String::new();
loop { loop {
match io::stdin().read_line(&mut line_buf) { match io::stdin().read_line(&mut line_buf) {
@ -68,7 +70,7 @@ fn run_repl(args: &Args) {
let line = line_buf.trim(); let line = line_buf.trim();
if !line.is_empty() { if !line.is_empty() {
run(&line_buf, args); run(&line_buf, args, &mut world);
line_buf.clear(); line_buf.clear();
} }
} }

View file

@ -1,6 +1,2 @@
12 == 1; asdf = 1;
print 1; print asdf;
print 1.90 == 1.90;
print 1.90;
print 2;
nil;