use std::io;
use std::path::{Path, PathBuf};
use proc_macro2::TokenStream;
use crate::build::relation::gen_input_module;
use crate::codegen::Features;
use crate::common::{BoxError, Config, SourceMap};
use crate::optimizer::Optimizer;
use crate::parser::Program;
use crate::planner::StratumPlanner;
use crate::profiler::Profiler;
use crate::stratifier::Stratifier;
use crate::{BuildError, Builder, CodeGen, CodeParts};
pub(crate) struct Pipeline {
pub(crate) config: Config,
pub(crate) parts: CodeParts,
pub(crate) program: Program,
pub(crate) relations: TokenStream,
pub(crate) features: Features,
}
impl Pipeline {
pub(crate) fn build(
builder: &Builder,
program_path: &Path,
sm: &mut SourceMap,
) -> Result<Self, BoxError> {
let program_str = program_path.to_str().ok_or_else(|| {
BuildError::from(io::Error::new(
io::ErrorKind::InvalidInput,
format!("non-UTF-8 program path: {}", program_path.display()),
))
})?;
let config = build_config(builder, program_str);
let mut program = parse(&config, &builder.include_dirs, sm)?;
crate::typechecker::check_program(&mut program)?;
let mut profiler = config
.profiling_enabled()
.then(|| Profiler::new(config.mode()));
let strata = plan(&config, &program, &mut profiler)?;
let mut cg = CodeGen::new(config.clone(), program.clone());
let parts = cg.generate(&strata, &mut profiler)?;
let features = cg.features().clone();
let relations = gen_input_module(&program, &features)?;
Ok(Self {
config,
parts,
program,
relations,
features,
})
}
}
fn parse(
config: &Config,
include_dirs: &[PathBuf],
sm: &mut SourceMap,
) -> Result<Program, BoxError> {
let include_refs: Vec<&Path> = include_dirs.iter().map(PathBuf::as_path).collect();
Program::parse_with_includes(config.program(), config.is_extended(), &include_refs, sm)
.map_err(Into::into)
}
fn plan(
config: &Config,
program: &Program,
profiler: &mut Option<Profiler>,
) -> Result<Vec<StratumPlanner>, BoxError> {
let stratifier = Stratifier::from_program(program, config.is_extended())?;
let mut optimizer = Optimizer::new();
stratifier
.stratum()
.iter()
.enumerate()
.map(|(idx, rule_refs)| {
let rules: Vec<_> = rule_refs.iter().copied().cloned().collect();
StratumPlanner::from_rules(config, &rules, &mut optimizer, profiler, &stratifier, idx)
.map_err(Into::into)
})
.collect()
}
fn build_config(builder: &Builder, program: &str) -> Config {
Config {
program: program.to_string(),
fact_dir: None,
executable_path: None,
output_dir: None,
mode: builder.mode,
profile: builder.profile,
sip: builder.sip,
str_intern: builder.string_intern,
udf_file: builder
.udf_file
.as_ref()
.map(|p| p.to_string_lossy().into_owned()),
save_temps: false,
include_dirs: builder
.include_dirs
.iter()
.map(|p| p.to_string_lossy().into_owned())
.collect(),
}
}