treescript-interpreter 0.1.1

TreeScript interpreter, with some built-in libraries and API to create more
Documentation
use crate::parse::Parser;
use crate::print::Printer;
use crate::session::{LibrarySpec, Session};
use crate::value::Value;
use std::env;
use std::fmt::Debug;
use std::io;
use std::io::{Read, Write};
use std::path::PathBuf;

pub struct Config<'a> {
  pub session: &'a mut Session,
  pub path: Option<PathBuf>,
}

impl<'a> Config<'a> {
  pub fn read_ast(&self) -> Option<Vec<Value>> {
    return self.path.as_ref().map(|path| {
      Parser {
        input: &mut self.session.read_ast(path.as_path()),
      }
      .collect()
    });
  }
}

pub trait LibProcessError: Debug + From<io::Error> {
  fn unknown_function(name: String) -> Self;
  fn invalid_num_args(fun: String, expected: usize, actual: usize) -> Self;
  fn invalid_arg_types(actual: Vec<Value>, expected: String) -> Self;
  fn not_function(value: Value) -> Self;
  fn unsupported(reason: String) -> Self;
}

pub trait LibProcess {
  type Error: LibProcessError;

  fn dependencies() -> Vec<LibrarySpec>;
  fn configure(&mut self, config: Config);
  fn call_fun(&mut self, fun: String, args: Vec<Value>) -> Result<Value, Self::Error>;

  fn run<R: Read, W: Write>(&mut self, input: &mut R, output: &mut W) -> Result<(), Self::Error> {
    let mut parser = Parser { input: input };
    let mut printer = Printer { output: output };
    while let Some(fun_val) = parser.scan_value() {
      if let Value::Record {
        head: fun,
        props: args,
      } = fun_val
      {
        let res = self.call_fun(fun, args)?;
        printer
          .print_value(res)
          .map_err(|err| Self::Error::from(err))?;
      } else {
        return Err(Self::Error::not_function(fun_val));
      }
    }
    return Ok(());
  }

  fn run_main(&mut self) {
    let args: Vec<String> = env::args().collect();
    let mut session = Session::new(Self::dependencies());
    let path: Option<PathBuf>;
    match args.len() {
      1 => path = None,
      2 => path = Some(PathBuf::from(args[1].clone())),
      _ => panic!(
        "invalid number of arguments - expected 0 or 1, got {}",
        args.len() - 1
      ),
    };

    session.start(&path);
    self.configure(Config {
      session: &mut session,
      path: path,
    });
    self
      .run(&mut io::stdin(), &mut io::stdout())
      .expect("server error");
    session.stop();
  }
}

#[derive(Debug)]
pub enum BasicLibProcessError {
  UnknownFunction(String),
  InvalidNumArgs {
    fun: String,
    expected: usize,
    actual: usize,
  },
  InvalidArgTypes {
    actual: Vec<Value>,
    expected: String,
  },
  NotFunction(Value),
  Unsupported(String),
  IOError(io::Error),
}

impl From<io::Error> for BasicLibProcessError {
  fn from(err: io::Error) -> BasicLibProcessError {
    return BasicLibProcessError::IOError(err);
  }
}

impl LibProcessError for BasicLibProcessError {
  fn unknown_function(name: String) -> BasicLibProcessError {
    return BasicLibProcessError::UnknownFunction(name);
  }

  fn invalid_num_args(fun: String, expected: usize, actual: usize) -> BasicLibProcessError {
    return BasicLibProcessError::InvalidNumArgs {
      fun: fun,
      expected: expected,
      actual: actual,
    };
  }

  fn invalid_arg_types(actual: Vec<Value>, expected: String) -> Self {
    return BasicLibProcessError::InvalidArgTypes {
      actual: actual,
      expected: expected,
    };
  }

  fn not_function(value: Value) -> BasicLibProcessError {
    return BasicLibProcessError::NotFunction(value);
  }

  fn unsupported(reason: String) -> BasicLibProcessError {
    return BasicLibProcessError::Unsupported(reason);
  }
}