Skip to content
Snippets Groups Projects
lib.rs 5.75 KiB
#![feature(exact_size_is_empty)]
#![feature(let_chains)]

use std::fs::File;
use std::io::Read;

use lrlex::DefaultLexerTypes;
use lrpar::NonStreamingLexer;

use hercules_ir::ir::*;
use juno_utils::env::Env;
use juno_utils::stringtab::StringTable;

mod parser;
use crate::parser::lexer;

mod compile;
mod default;
pub mod ir;
pub mod labels;
mod pm;

use crate::compile::*;
use crate::default::*;
use crate::ir::*;
use crate::labels::*;
pub use crate::pm::*;

// Given a schedule's filename parse and process the schedule
fn build_schedule(sched_filename: String) -> Result<ScheduleStmt, String> {
    if let Ok(mut file) = File::open(sched_filename) {
        let mut contents = String::new();
        if let Ok(_) = file.read_to_string(&mut contents) {
            let lexerdef = lexer::lexerdef();
            let lexer = lexerdef.lexer(&contents);
            let (res, errs) = parser::parse(&lexer);

            if errs.is_empty() {
                match res {
                    None => Err(format!("No parse errors, but parsing the schedule failed")),
                    Some(schd) => {
                        compile_schedule(schd, &lexer).map_err(|e| format!("Schedule Error: {}", e))
                    }
                }
            } else {
                Err(errs
                    .iter()
                    .map(|e| {
                        format!(
                            "Schedule Syntax Error: {}",
                            e.pp(&lexer, &parser::token_epp)
                        )
                    })
                    .collect::<Vec<_>>()
                    .join("\n"))
            }
        } else {
            Err(format!("Unable to read schedule"))
        }
    } else {
        Err(format!("Unable to open schedule"))
    }
}

pub fn process_schedule(sched_filename: Option<String>) -> Result<ScheduleStmt, String> {
    if let Some(name) = sched_filename {
        build_schedule(name)
    } else {
        Ok(default_schedule())
    }
}

pub fn schedule_juno(
    module: Module,
    juno_info: JunoInfo,
    sched_filename: Option<String>,
    output_dir: String,
    module_name: String,
) -> Result<(), String> {
    let sched = process_schedule(sched_filename)?;

    // Prepare the scheduler's string table and environment
    // For this, we need to put all of the Juno functions into the environment
    // and string table
    let mut strings = StringTable::new();
    let mut env = Env::new();

    env.open_scope();

    let JunoInfo {
        func_names,
        func_info,
    } = juno_info;
    for (func_name, func_id) in func_names {
        let func_name = strings.lookup_string(func_name);
        env.insert(func_name, Value::JunoFunction { func: func_id });
    }

    env.open_scope();
    schedule_codegen(
        module,
        sched,
        strings,
        env,
        func_info,
        output_dir,
        module_name,
    )
    .map_err(|e| format!("Scheduling Error: {}", e))
}

pub fn run_schedule_on_hercules(
    module: Module,
    sched: Option<ScheduleStmt>,
) -> Result<Module, String> {
    let sched = if let Some(sched) = sched {
        sched
    } else {
        default_schedule()
    };

    // Prepare the scheduler's string table and environment
    // For this, we put all of the Hercules function names into the environment
    // and string table
    let mut strings = StringTable::new();
    let mut env = Env::new();

    env.open_scope();

    for (idx, func) in module.functions.iter().enumerate() {
        let func_name = strings.lookup_string(func.name.clone());
        env.insert(
            func_name,
            Value::HerculesFunction {
                func: FunctionID::new(idx),
            },
        );
    }

    env.open_scope();
    schedule_module(
        module,
        sched,
        strings,
        env,
        JunoFunctions { func_ids: vec![] },
    )
    .map_err(|e| format!("Scheduling Error: {}", e))
}

pub fn run_schedule_from_file_on_hercules(
    module: Module,
    sched_filename: Option<String>,
) -> Result<Module, String> {
    let sched = process_schedule(sched_filename)?;

    // Prepare the scheduler's string table and environment
    // For this, we put all of the Hercules function names into the environment
    // and string table
    let mut strings = StringTable::new();
    let mut env = Env::new();

    env.open_scope();

    for (idx, func) in module.functions.iter().enumerate() {
        let func_name = strings.lookup_string(func.name.clone());
        env.insert(
            func_name,
            Value::HerculesFunction {
                func: FunctionID::new(idx),
            },
        );
    }

    env.open_scope();
    schedule_module(
        module,
        sched,
        strings,
        env,
        JunoFunctions { func_ids: vec![] },
    )
    .map_err(|e| format!("Scheduling Error: {}", e))
}

pub fn schedule_hercules(
    module: Module,
    sched_filename: Option<String>,
    output_dir: String,
    module_name: String,
) -> Result<(), String> {
    let sched = process_schedule(sched_filename)?;

    // Prepare the scheduler's string table and environment
    // For this, we put all of the Hercules function names into the environment
    // and string table
    let mut strings = StringTable::new();
    let mut env = Env::new();

    env.open_scope();

    for (idx, func) in module.functions.iter().enumerate() {
        let func_name = strings.lookup_string(func.name.clone());
        env.insert(
            func_name,
            Value::HerculesFunction {
                func: FunctionID::new(idx),
            },
        );
    }

    env.open_scope();
    schedule_codegen(
        module,
        sched,
        strings,
        env,
        JunoFunctions { func_ids: vec![] },
        output_dir,
        module_name,
    )
    .map_err(|e| format!("Scheduling Error: {}", e))
}