rested 0.11.0

Language/Interpreter for easily defining and running requests to an http server.
Documentation
mod attributes;
mod builtin;
pub mod environment;
pub mod error;
mod eval;
pub mod ir;
pub mod runner;
pub mod ureq_runner;
pub mod value;

use std::io::{stdin, Read};

use anyhow::anyhow;
use environment::Environment;
use error::InterpreterError;

use crate::error::ColoredMetaError;
use crate::parser::ast::{self};

use crate::parser::error::ParserErrors;

impl<'source> ast::Program<'source> {
    pub fn interpret(
        &self,
        env: &Environment,
    ) -> std::result::Result<ir::Program<'source>, InterpreterError<'source>> {
        let parse_errors = self.errors();

        if !parse_errors.is_empty() {
            return Err(ParserErrors::new(parse_errors).into());
        }

        let mut interpreter = eval::Evaluator::new(self, env);

        let items = interpreter
            .evaluate()
            .map_err(InterpreterError::EvalErrors)?;

        Ok(ir::Program::new(
            self.source,
            items.into(),
            interpreter
                .let_bindings
                .into_iter()
                .map(|(key, value)| (key.into(), value))
                .collect(),
        ))
    }
}

pub fn interpret_program(code: &str, env: Environment) -> anyhow::Result<ir::Program<'_>> {
    let program = ast::Program::from(code);

    let program = program.interpret(&env).map_err(|value| match value {
        InterpreterError::ParseErrors(p) => {
            let error_string: String = p
                .errors
                .iter()
                .map(|e| ColoredMetaError(e).to_string())
                .collect();

            return anyhow!(error_string);
        }
        InterpreterError::EvalErrors(errors) => {
            let error_string: String = errors
                .iter()
                .map(|e| ColoredMetaError(e).to_string())
                .collect();

            return anyhow!(error_string);
        }
    })?;

    Ok(program)
}

pub fn read_program_text(file: Option<std::path::PathBuf>) -> anyhow::Result<String> {
    let code = file.map(std::fs::read_to_string).unwrap_or_else(|| {
        let mut buf = String::new();
        stdin().read_to_string(&mut buf)?;
        Ok(buf)
    })?;

    Ok(code)
}