📜 Add better documentation across the compiler. (#3)

These changes pay particular attention to API endpoints, to try to
ensure that any rustdocs generated are detailed and sensible. A good
next step, eventually, might be to include doctest examples, as well.
For the moment, it's not clear that they would provide a lot of value,
though.

In addition, this does a couple refactors to simplify the code base in
ways that make things clearer or, at least, briefer.
This commit is contained in:
2023-05-13 14:34:48 -05:00
parent f4594bf2cc
commit 1fbfd0c2d2
28 changed files with 1550 additions and 432 deletions

View File

@@ -4,11 +4,23 @@ use crate::eval::{EvalEnvironment, EvalError, Value};
use crate::syntax::{Expression, Program, Statement};
impl Program {
/// Evaluate the program, returning either an error or what it prints out when run.
///
/// Doing this evaluation is particularly useful for testing, to ensure that if we
/// modify a program in some way it does the same thing on both sides of the
/// transformation. It's also sometimes just nice to know what a program will be
/// doing.
///
/// Note that the errors here are slightly more strict that we enforce at runtime.
/// For example, we check for overflow and underflow errors during evaluation, and
/// we don't check for those in the compiled code.
pub fn eval(&self) -> Result<String, EvalError> {
let mut env = EvalEnvironment::empty();
let mut stdout = String::new();
for stmt in self.statements.iter() {
// at this point, evaluation is pretty simple. just walk through each
// statement, in order, and record printouts as we come to them.
match stmt {
Statement::Binding(_, name, value) => {
let actual_value = value.eval(&env)?;
@@ -40,6 +52,7 @@ impl Expression {
let mut arg_values = Vec::with_capacity(args.len());
for arg in args.iter() {
// yay, recursion! makes this pretty straightforward
arg_values.push(arg.eval(env)?);
}