#![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
#![deny(rust_2018_idioms)]
#![deny(warnings)]
#[allow(unused_extern_crates)]
extern crate proc_macro;
use core::ops;
use proc_macro::TokenStream;
use indexmap::{IndexMap, IndexSet};
use proc_macro2::TokenStream as TokenStream2;
use syn::Ident;
use crate::ast::App;
mod accessors;
pub mod analyze;
pub mod ast;
mod check;
mod optimize;
mod parse;
#[cfg(test)]
mod tests;
pub type Core = u8;
pub type Map<T> = IndexMap<Ident, T>;
pub type Set<T> = IndexSet<T>;
pub struct P<T> {
ptr: Box<T>,
}
impl<T> P<T> {
pub fn new(x: T) -> P<T> {
P { ptr: Box::new(x) }
}
}
impl<T> ops::Deref for P<T> {
type Target = T;
fn deref(&self) -> &T {
&self.ptr
}
}
#[derive(Clone, Copy)]
pub enum Context<'a> {
HardwareTask(&'a Ident),
Idle(Core),
Init(Core),
SoftwareTask(&'a Ident),
}
impl<'a> Context<'a> {
pub fn core(&self, app: &App) -> u8 {
match self {
Context::HardwareTask(name) => app.hardware_tasks[*name].args.core,
Context::Idle(core) => app.idles[core].args.core,
Context::Init(core) => app.inits[core].args.core,
Context::SoftwareTask(name) => app.software_tasks[*name].args.core,
}
}
pub fn ident(&self, app: &'a App) -> &'a Ident {
match self {
Context::HardwareTask(ident) => ident,
Context::Idle(core) => &app.idles[core].name,
Context::Init(core) => &app.inits[core].name,
Context::SoftwareTask(ident) => ident,
}
}
pub fn is_idle(&self) -> bool {
if let Context::Idle(_) = self {
true
} else {
false
}
}
pub fn is_init(&self) -> bool {
if let Context::Init(_) = self {
true
} else {
false
}
}
pub fn runs_once(&self) -> bool {
self.is_init() || self.is_idle()
}
pub fn has_locals(&self, app: &App) -> bool {
match *self {
Context::HardwareTask(name) => !app.hardware_tasks[name].locals.is_empty(),
Context::Idle(core) => !app.idles[&core].locals.is_empty(),
Context::Init(core) => !app.inits[&core].locals.is_empty(),
Context::SoftwareTask(name) => !app.software_tasks[name].locals.is_empty(),
}
}
pub fn has_resources(&self, app: &App) -> bool {
match *self {
Context::HardwareTask(name) => !app.hardware_tasks[name].args.resources.is_empty(),
Context::Idle(core) => !app.idles[&core].args.resources.is_empty(),
Context::Init(core) => !app.inits[&core].args.resources.is_empty(),
Context::SoftwareTask(name) => !app.software_tasks[name].args.resources.is_empty(),
}
}
pub fn uses_schedule(&self, app: &App) -> bool {
match *self {
Context::HardwareTask(name) => !app.hardware_tasks[name].args.schedule.is_empty(),
Context::Idle(core) => !app.idles[&core].args.schedule.is_empty(),
Context::Init(core) => !app.inits[&core].args.schedule.is_empty(),
Context::SoftwareTask(name) => !app.software_tasks[name].args.schedule.is_empty(),
}
}
pub fn uses_spawn(&self, app: &App) -> bool {
match *self {
Context::HardwareTask(name) => !app.hardware_tasks[name].args.spawn.is_empty(),
Context::Idle(core) => !app.idles[&core].args.spawn.is_empty(),
Context::Init(core) => !app.inits[&core].args.spawn.is_empty(),
Context::SoftwareTask(name) => !app.software_tasks[name].args.spawn.is_empty(),
}
}
}
#[derive(Default)]
pub struct Settings {
pub parse_binds: bool,
pub parse_cores: bool,
pub parse_extern_interrupt: bool,
pub parse_schedule: bool,
pub optimize_priorities: bool,
_extensible: (),
}
pub fn parse(
args: TokenStream,
input: TokenStream,
settings: Settings,
) -> Result<(P<ast::App>, P<analyze::Analysis>), syn::parse::Error> {
parse2(args.into(), input.into(), settings)
}
pub fn parse2(
args: TokenStream2,
input: TokenStream2,
ref settings: Settings,
) -> Result<(P<ast::App>, P<analyze::Analysis>), syn::parse::Error> {
let mut app = parse::app(args, input, settings)?;
check::app(&app)?;
optimize::app(&mut app, settings);
let analysis = analyze::app(&app);
Ok((P::new(app), P::new(analysis)))
}
enum Either<A, B> {
Left(A),
Right(B),
}