rtic/macros/src/check.rs

140 lines
3.1 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
2017-07-18 23:49:59 +02:00
use syn::{Ident, Path};
use syntax::check::{self, Idle, Init};
2017-07-29 07:34:00 +02:00
use syntax::{self, Resources, Statics};
use syntax::error::*;
pub struct App {
2017-07-18 23:49:59 +02:00
pub device: Path,
pub idle: Idle,
pub init: Init,
pub resources: Statics,
pub tasks: Tasks,
}
pub type Tasks = HashMap<Ident, Task>;
#[allow(non_camel_case_types)]
pub enum Exception {
PENDSV,
SVCALL,
SYS_TICK,
}
impl Exception {
pub fn from(s: &str) -> Option<Self> {
Some(match s {
"PENDSV" => Exception::PENDSV,
"SVCALL" => Exception::SVCALL,
"SYS_TICK" => Exception::SYS_TICK,
_ => return None,
})
}
pub fn nr(&self) -> usize {
match *self {
Exception::PENDSV => 14,
Exception::SVCALL => 11,
Exception::SYS_TICK => 15,
}
}
}
pub enum Kind {
Exception(Exception),
Interrupt { enabled: bool },
}
pub struct Task {
pub kind: Kind,
2017-07-28 02:39:18 +02:00
pub path: Path,
pub priority: u8,
2017-07-29 07:34:00 +02:00
pub resources: Resources,
}
pub fn app(app: check::App) -> Result<App> {
let app = App {
device: app.device,
idle: app.idle,
init: app.init,
resources: app.resources,
tasks: app.tasks
.into_iter()
.map(|(k, v)| {
2017-11-20 05:11:25 +01:00
let v =
::check::task(k.as_ref(), v).chain_err(|| format!("checking task `{}`", k))?;
Ok((k, v))
})
.collect::<Result<_>>()?,
};
2017-11-20 05:11:25 +01:00
::check::resources(&app).chain_err(|| "checking `resources`")?;
Ok(app)
}
fn resources(app: &App) -> Result<()> {
for resource in app.resources.keys() {
if app.idle.resources.contains(resource) {
continue;
}
if app.tasks
.values()
.any(|task| task.resources.contains(resource))
{
continue;
}
bail!("resource `{}` is unused", resource);
}
2017-11-20 05:11:25 +01:00
for (name, task) in &app.tasks {
for resource in &task.resources {
ensure!(
app.resources.contains_key(&resource),
"task {} contains an undeclared resource with name {}",
name,
resource
);
}
}
Ok(())
}
fn task(name: &str, task: syntax::check::Task) -> Result<Task> {
let kind = match Exception::from(name) {
Some(e) => {
ensure!(
task.enabled.is_none(),
"`enabled` field is not valid for exceptions"
);
Kind::Exception(e)
}
None => {
if task.enabled == Some(true) {
bail!(
"`enabled: true` is the default value; this line can be \
omitted"
);
}
Kind::Interrupt {
enabled: task.enabled.unwrap_or(true),
}
}
};
Ok(Task {
kind,
2017-07-28 02:39:18 +02:00
path: task.path.ok_or("`path` field is missing")?,
priority: task.priority.unwrap_or(1),
resources: task.resources,
})
2017-07-04 18:26:11 +02:00
}