From 3615d1948512272ba69421964ab399c23d631eae Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Fri, 21 Apr 2023 20:40:25 -0700 Subject: [PATCH] Document some of the IR; not much to say, actually. --- src/ir/ast.rs | 19 ++++++++++++++++--- src/ir/eval.rs | 9 +++++++++ src/ir/strings.rs | 4 ++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/ir/ast.rs b/src/ir/ast.rs index 6e46538..4abe3bd 100644 --- a/src/ir/ast.rs +++ b/src/ir/ast.rs @@ -1,3 +1,4 @@ +use crate::syntax::Location; use internment::ArcIntern; use pretty::{DocAllocator, Pretty}; use proptest::{ @@ -5,13 +6,18 @@ use proptest::{ strategy::{BoxedStrategy, Strategy}, }; -use crate::syntax::Location; - +/// We're going to represent variables as interned strings. +/// +/// These should be fast enough for comparison that it's OK, since it's going to end up +/// being pretty much the pointer to the string. type Variable = ArcIntern; +/// The representation of a program within our IR. For now, this is exactly one file. #[derive(Debug)] pub struct Program { - pub statements: Vec, + // For now, a program is just a vector of statements. In the future, we'll probably + // extend this to include a bunch of other information, but for now: just a list. + pub(crate) statements: Vec, } impl<'a, 'b, D, A> Pretty<'a, D, A> for &'b Program @@ -23,6 +29,8 @@ where let mut result = allocator.nil(); for stmt in self.statements.iter() { + // there's probably a better way to do this, rather than constantly + // adding to the end, but this works. result = result .append(stmt.pretty(allocator)) .append(allocator.text(";")) @@ -44,6 +52,10 @@ impl Arbitrary for Program { } } +/// The representation of a statement in the language. +/// +/// For now, this is either a binding site (`x = 4`) or a print statement +/// (`print x`). Someday, though, more! #[derive(Debug)] pub enum Statement { Binding(Location, Variable, Expression), @@ -71,6 +83,7 @@ where } } +/// The representation of an expression. #[derive(Debug)] pub enum Expression { Value(Location, Value), diff --git a/src/ir/eval.rs b/src/ir/eval.rs index d7c4135..097e836 100644 --- a/src/ir/eval.rs +++ b/src/ir/eval.rs @@ -4,6 +4,10 @@ use crate::ir::{Expression, Program, Statement}; use super::{Primitive, ValueOrRef}; impl Program { + /// Evaluate the program, returning either an error or a string containing everything + /// the program printed out. + /// + /// The print outs will be newline separated, with one print out per line. pub fn eval(&self) -> Result { let mut env = EvalEnvironment::empty(); let mut stdout = String::new(); @@ -39,6 +43,9 @@ impl Expression { Expression::Primitive(_, op, args) => { let mut arg_values = Vec::with_capacity(args.len()); + // we implement primitive operations by first evaluating each of the + // arguments to the function, and then gathering up all the values + // produced. for arg in args.iter() { match arg { ValueOrRef::Ref(_, n) => arg_values.push(env.lookup(n.clone())?), @@ -48,6 +55,8 @@ impl Expression { } } + // and then finally we call `calculate` to run them. trust me, it's nice + // to not have to deal with all the nonsense hidden under `calculate`. match op { Primitive::Plus => Ok(Value::calculate("+", arg_values)?), Primitive::Minus => Ok(Value::calculate("-", arg_values)?), diff --git a/src/ir/strings.rs b/src/ir/strings.rs index d0e57a2..777f8ee 100644 --- a/src/ir/strings.rs +++ b/src/ir/strings.rs @@ -3,6 +3,10 @@ use internment::ArcIntern; use std::collections::HashSet; impl Program { + /// Get the complete list of strings used within the program. + /// + /// For the purposes of this function, strings are the variables used in + /// `print` statements. pub fn strings(&self) -> HashSet> { let mut result = HashSet::new();