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),
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::*;

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)),
}
}
TokenType::Identifier(var_name) => VariableExpr::new(var_name).into(),
a => return Err(token.location.wrap(InnerASTParsingError::IncorrectToken(a))),
};
Ok(node)

View file

@ -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),
}
}
}

View file

@ -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>;
}

View file

@ -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)
}
}

View file

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

View file

@ -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
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 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)
}

View file

@ -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();
}
}

View file

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