use crate::{CliArgs, CompilationTarget, Error, Module, Options, Output, Result};
use clap::Parser;
use log::{debug, info};
use std::path;
mod display;
mod try_from;
#[derive(Debug)]
pub struct Compiler {
pub options: Options,
pub output: Output,
pub(crate) input_filename: path::PathBuf,
}
impl Compiler {
pub fn compile(&self) -> Result<Module> {
debug!("Loading module from file {}", self.input_filename.display());
let mut main_module = Module::try_from(self.input_filename.clone())?;
let relative_to = self
.input_filename
.parent()
.unwrap_or_else(|| path::Path::new(""))
.to_path_buf();
debug!("Loading dependencies for {}", &main_module.module_path);
main_module = main_module.load_dependencies(relative_to)?;
debug!("Compiling module");
let main_module = self.eval(main_module)?;
info!("Compiled main: {}", &main_module);
debug!(
"Writing object file {}",
main_module.source_code.object_code_filename().display()
);
main_module.write_object_file(self)?;
Ok(main_module)
}
pub fn from_cli_args() -> Result<Self> {
Self::try_from(&CliArgs::parse())
}
pub fn target<'a>(&'a self) -> Result<Box<dyn CompilationTarget + 'a>> {
self.output.compilation_target(self)
}
pub(crate) fn output_error<M: Into<String>>(&self, message: M) -> Error {
self.output.clone().into_error(message)
}
fn eval(&self, module: Module) -> Result<Module> {
debug!("Evaluating module");
module
.eval_fills()
.eval_spreadsheet(self.options.key_values.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::*;
#[test]
fn compile_empty() {
let test_file = &TestSourceCode::new("csv", "");
let compiler: Compiler = test_file.into();
let module = compiler.compile();
assert!(module.is_ok());
}
#[test]
fn compile_simple() {
let test_file = &TestSourceCode::new("csv", "---\nfoo,bar,baz\n1,2,3");
let compiler: Compiler = test_file.into();
let module = compiler.compile().unwrap();
assert_eq!(module.spreadsheet.rows.len(), 2);
}
#[test]
fn compile_with_fill_finite() {
let test_file = &TestSourceCode::new("xlsx", "![[fill=10]]foo,bar,baz");
let compiler: Compiler = test_file.into();
let module = compiler.compile().unwrap();
assert_eq!(module.spreadsheet.rows.len(), 10);
}
#[test]
fn compile_with_fill_infinite() {
let test_file = &TestSourceCode::new("xlsx", "![[fill]]foo,bar,baz");
let compiler: Compiler = test_file.into();
let module = compiler.compile().unwrap();
assert_eq!(module.spreadsheet.rows.len(), 1000);
}
#[test]
fn compile_with_fill_multiple() {
let test_file = &TestSourceCode::new("xlsx", "![[f=10]]foo,bar,baz\n![[f]]1,2,3");
let compiler: Compiler = test_file.into();
let module = compiler.compile().unwrap();
assert_eq!(module.spreadsheet.rows.len(), 1000);
}
#[test]
fn compile_with_fill_and_rows() {
let test_file =
&TestSourceCode::new("xlsx", "foo,bar,baz\n![[f=2]]foo,bar,baz\none,last,row\n");
let compiler: Compiler = test_file.into();
let module = compiler.compile().unwrap();
assert_eq!(module.spreadsheet.rows.len(), 4);
}
}