pub mod generator;
use crate::model;
use std::ffi::OsString;
use std::io;
use std::path::Path;
use num_bigint::BigUint;
use std::marker::PhantomData;
#[derive(Debug)]
pub enum GeneratorError {
IOError(io::Error),
UnknownLanguage(String),
InvalidOptions(String),
UnmappedPackage(model::PackageName),
CouldNotFind(model::QualifiedName),
CouldNotFindVersion(model::QualifiedName, BigUint),
CouldNotResolveTypeParameter(String),
TypeCannotBeSequence(model::QualifiedName),
TypeDoesNotHaveCase(model::QualifiedName, Option<BigUint>, String),
IncorrectCaseArity(model::QualifiedName, String),
RecordLiteralNotForStruct,
ExternTypeDoesNotHaveRecordLiteral(model::QualifiedName),
CouldNotFindRecordField(model::QualifiedName, Option<BigUint>, String),
CouldNotGenerateType,
InvalidTypeForConstant,
InvalidTypeForCodec,
}
impl From<io::Error> for GeneratorError {
fn from(err: io::Error) -> Self {
GeneratorError::IOError(err)
}
}
pub trait OutputHandler<'state> {
type FileHandle : io::Write;
fn create_file<P: AsRef<Path>>(&'state mut self, path: P) -> Result<Self::FileHandle, GeneratorError>;
}
pub trait Language {
type OptionsBuilder;
type Options;
fn name() -> &'static str;
fn empty_options() -> Self::OptionsBuilder;
fn add_option(builder: &mut Self::OptionsBuilder, name: &str, value: OsString) -> Result<(), GeneratorError>;
fn finalize_options(builder: Self::OptionsBuilder) -> Result<Self::Options, GeneratorError>;
fn generate<Output: for<'output> OutputHandler<'output>>(model: &model::Verilization, options: Self::Options, output: &mut Output) -> Result<(), GeneratorError>;
}
pub trait LanguageHandler {
type Result;
fn run<Lang: Language>(&mut self) -> Self::Result;
}
pub trait LanguageRegistry : Sized {
fn has_language(&self, lang_name: &str) -> bool;
fn handle_language<Handler: LanguageHandler>(&self, lang_name: &str, handler: &mut Handler) -> Option<Handler::Result>;
fn each_language<Handler: LanguageHandler>(&self, handler: &mut Handler) -> Vec<Handler::Result>;
fn add_language<Lang: Language>(self) -> LanguageRegistryCons<Lang, Self> {
LanguageRegistryCons {
prev: self,
dummy_lang: PhantomData {},
}
}
}
pub struct EmptyLanguageRegistry {}
pub struct LanguageRegistryCons<Lang: Language, Prev: LanguageRegistry> {
prev: Prev,
dummy_lang: PhantomData<Lang>,
}
pub fn language_registry_new() -> EmptyLanguageRegistry {
EmptyLanguageRegistry {}
}
impl LanguageRegistry for EmptyLanguageRegistry {
fn has_language(&self, _lang_name: &str) -> bool {
false
}
fn handle_language<Handler: LanguageHandler>(&self, _lang_name: &str, _handler: &mut Handler) -> Option<Handler::Result> {
None
}
fn each_language<Handler: LanguageHandler>(&self, _handler: &mut Handler) -> Vec<Handler::Result> {
Vec::new()
}
}
impl <Lang: Language, Prev: LanguageRegistry> LanguageRegistry for LanguageRegistryCons<Lang, Prev> {
fn has_language(&self, lang_name: &str) -> bool {
lang_name == Lang::name() || self.prev.has_language(lang_name)
}
fn handle_language<Handler: LanguageHandler>(&self, lang_name: &str, handler: &mut Handler) -> Option<Handler::Result> {
if lang_name == Lang::name() {
Some(handler.run::<Lang>())
}
else {
self.prev.handle_language(lang_name, handler)
}
}
fn each_language<Handler: LanguageHandler>(&self, handler: &mut Handler) -> Vec<Handler::Result> {
let mut results = self.prev.each_language(handler);
results.push(handler.run::<Lang>());
results
}
}