Skip to content
Snippets Groups Projects
Commit 3db36b8c authored by pln's avatar pln
Browse files

syntax

parent 59664489
No related branches found
No related tags found
No related merge requests found
...@@ -5,7 +5,7 @@ use std::collections::HashMap; ...@@ -5,7 +5,7 @@ use std::collections::HashMap;
use syn::{Ident, Path}; use syn::{Ident, Path};
use error::*; use error::*;
use {util, Resources, Statics}; use {util, Resources, Statics, Crcs};
/// `$($Ident: { .. },)*` /// `$($Ident: { .. },)*`
pub type Tasks = HashMap<Ident, Task>; pub type Tasks = HashMap<Ident, Task>;
...@@ -65,8 +65,9 @@ pub fn app(app: ::App) -> Result<App> { ...@@ -65,8 +65,9 @@ pub fn app(app: ::App) -> Result<App> {
device: app.device, device: app.device,
idle: ::check::idle(app.idle).chain_err(|| "checking `idle`")?, idle: ::check::idle(app.idle).chain_err(|| "checking `idle`")?,
init: ::check::init(app.init).chain_err(|| "checking `init`")?, init: ::check::init(app.init).chain_err(|| "checking `init`")?,
resources: ::check::statics("resources", app.resources) resources: ::check::statics("resources", app.resources).chain_err(
.chain_err(|| "checking `resources`")?, || "checking `resources`",
)?,
tasks: ::check::tasks(app.tasks).chain_err(|| "checking `tasks`")?, tasks: ::check::tasks(app.tasks).chain_err(|| "checking `tasks`")?,
}) })
} }
...@@ -80,8 +81,9 @@ fn idle(idle: Option<::Idle>) -> Result<Idle> { ...@@ -80,8 +81,9 @@ fn idle(idle: Option<::Idle>) -> Result<Idle> {
Idle { Idle {
_extensible: (), _extensible: (),
path: ::check::path("idle", idle.path) path: ::check::path("idle", idle.path).chain_err(
.chain_err(|| "checking `path`")?, || "checking `path`",
)?,
resources: ::check::resources("resources", idle.resources)?, resources: ::check::resources("resources", idle.resources)?,
} }
} else { } else {
...@@ -98,8 +100,9 @@ fn init(init: Option<::Init>) -> Result<Init> { ...@@ -98,8 +100,9 @@ fn init(init: Option<::Init>) -> Result<Init> {
if let Some(path) = init.path { if let Some(path) = init.path {
Init { Init {
_extensible: (), _extensible: (),
path: ::check::path("init", Some(path)) path: ::check::path("init", Some(path)).chain_err(
.chain_err(|| "checking `path`")?, || "checking `path`",
)?,
} }
} else { } else {
bail!("empty `init` field. It should be removed."); bail!("empty `init` field. It should be removed.");
...@@ -115,8 +118,7 @@ fn init(init: Option<::Init>) -> Result<Init> { ...@@ -115,8 +118,7 @@ fn init(init: Option<::Init>) -> Result<Init> {
fn path(default: &str, path: Option<Path>) -> Result<Path> { fn path(default: &str, path: Option<Path>) -> Result<Path> {
Ok(if let Some(path) = path { Ok(if let Some(path) = path {
ensure!( ensure!(
path.segments.len() != 1 || path.segments.len() != 1 || path.segments[0].ident.as_ref() != default,
path.segments[0].ident.as_ref() != default,
"this is the default value. It should be omitted." "this is the default value. It should be omitted."
); );
...@@ -186,3 +188,15 @@ fn tasks(tasks: Option<::Tasks>) -> Result<Tasks> { ...@@ -186,3 +188,15 @@ fn tasks(tasks: Option<::Tasks>) -> Result<Tasks> {
Tasks::new() Tasks::new()
}) })
} }
/// `crc! { .. }`
#[derive(Debug)]
pub struct Crc {
/// `crcs: Crcs`
pub crcs: Option<Crcs>,
}
/// Checks the syntax of the parsed `app!` macro
pub fn crc(crc: ::Crc) -> Result<Crc> {
Ok(Crc { crcs: crc.crcs })
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
//! framework //! framework
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(warnings)] // #![deny(warnings)]
#[macro_use] #[macro_use]
extern crate error_chain; extern crate error_chain;
...@@ -99,3 +99,37 @@ impl App { ...@@ -99,3 +99,37 @@ impl App {
parse::app(input) parse::app(input)
} }
} }
/// Crc related
/// `$($Ident: $Path,)*`
pub type Crcs = HashMap<Ident, Path>;
pub enum IpTo {
Crc(Path),
Method(Ident),
}
pub struct Ip {
ty: Ty,
to: IpBind,
}
/// `$($Ident: $Ty,)*`
pub type Ips = HashMap<Ident, Ty>;
/// `crc! { .. }`
#[derive(Debug)]
pub struct Crc {
/// Inner Crcs (can be None)
pub crcs: Option<Crcs>,
/// Input ports (should not be None)
pub ips: Option<Ips>,
}
impl Crc {
/// Parses the contents of the `sys! { .. }` macro
pub fn parse(input: &str) -> Result<Self> {
parse::crc(input)
}
}
...@@ -2,11 +2,11 @@ use std::collections::{HashMap, HashSet}; ...@@ -2,11 +2,11 @@ use std::collections::{HashMap, HashSet};
use std::iter::Peekable; use std::iter::Peekable;
use std::slice::Iter; use std::slice::Iter;
use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, TokenTree}; use syn::{self, DelimToken, Ident, IntTy, Lit, Path, Token, TokenTree, Ty};
use error::*; use error::*;
use {App, Idle, Init, Resources, Static, Statics, Task, Tasks}; use {Crc, Crcs, Ips, App, Idle, Init, Resources, Static, Statics, Task, Tasks};
/// Parses the contents of `app! { $App }` /// Parses the contents of `app! { $App }`
pub fn app(input: &str) -> Result<App> { pub fn app(input: &str) -> Result<App> {
...@@ -39,9 +39,9 @@ pub fn app(input: &str) -> Result<App> { ...@@ -39,9 +39,9 @@ pub fn app(input: &str) -> Result<App> {
"resources" => { "resources" => {
ensure!(resources.is_none(), "duplicated `resources` field"); ensure!(resources.is_none(), "duplicated `resources` field");
resources = Some( resources = Some(::parse::statics(tts).chain_err(
::parse::statics(tts).chain_err(|| "parsing `resources`")?, || "parsing `resources`",
); )?);
} }
"tasks" => { "tasks" => {
ensure!(tasks.is_none(), "duplicated `tasks` field"); ensure!(tasks.is_none(), "duplicated `tasks` field");
...@@ -122,7 +122,8 @@ where ...@@ -122,7 +122,8 @@ where
let tt = tts.next(); let tt = tts.next();
match tt { match tt {
None | Some(&TokenTree::Token(Token::Comma)) => {} None |
Some(&TokenTree::Token(Token::Comma)) => {}
_ => bail!("expected Comma, found {:?}", tt), _ => bail!("expected Comma, found {:?}", tt),
} }
} }
...@@ -149,8 +150,9 @@ fn idle(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Idle> { ...@@ -149,8 +150,9 @@ fn idle(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Idle> {
"duplicated `resources` field" "duplicated `resources` field"
); );
resources = Some(::parse::resources(tts) resources = Some(::parse::resources(tts).chain_err(
.chain_err(|| "parsing `resources`")?); || "parsing `resources`",
)?);
} }
_ => bail!("unknown field: `{}`", key), _ => bail!("unknown field: `{}`", key),
} }
...@@ -305,8 +307,9 @@ fn statics(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Statics> { ...@@ -305,8 +307,9 @@ fn statics(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Statics> {
statics.insert( statics.insert(
ident.clone(), ident.clone(),
::parse::static_(&mut tts) ::parse::static_(&mut tts).chain_err(
.chain_err(|| format!("parsing `{}`", ident))?, || format!("parsing `{}`", ident),
)?,
); );
} }
...@@ -331,6 +334,7 @@ fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Path> { ...@@ -331,6 +334,7 @@ fn path(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Path> {
tts.next(); tts.next();
} }
// bail!("in path fragments, {:? }===== {:?}", fragments, tts);
Ok(syn::parse_path(&format!("{}", quote!(#(#fragments)*)))?) Ok(syn::parse_path(&format!("{}", quote!(#(#fragments)*)))?)
} }
...@@ -348,8 +352,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { ...@@ -348,8 +352,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> {
"enabled" => { "enabled" => {
ensure!(enabled.is_none(), "duplicated `enabled` field"); ensure!(enabled.is_none(), "duplicated `enabled` field");
enabled = Some(::parse::bool(tts.next()) enabled = Some(::parse::bool(tts.next()).chain_err(
.chain_err(|| "parsing `enabled`")?); || "parsing `enabled`",
)?);
} }
"path" => { "path" => {
ensure!(path.is_none(), "duplicated `path` field"); ensure!(path.is_none(), "duplicated `path` field");
...@@ -361,8 +366,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { ...@@ -361,8 +366,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> {
"priority" => { "priority" => {
ensure!(priority.is_none(), "duplicated `priority` field"); ensure!(priority.is_none(), "duplicated `priority` field");
priority = Some(::parse::u8(tts.next()) priority = Some(::parse::u8(tts.next()).chain_err(
.chain_err(|| "parsing `priority`")?); || "parsing `priority`",
)?);
} }
"resources" => { "resources" => {
ensure!( ensure!(
...@@ -370,8 +376,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> { ...@@ -370,8 +376,9 @@ fn task(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Task> {
"duplicated `resources` field" "duplicated `resources` field"
); );
resources = Some(::parse::resources(tts) resources = Some(::parse::resources(tts).chain_err(
.chain_err(|| "parsing `resources`")?); || "parsing `resources`",
)?);
} }
_ => bail!("unknown field: `{}`", key), _ => bail!("unknown field: `{}`", key),
} }
...@@ -403,8 +410,9 @@ fn tasks(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Tasks> { ...@@ -403,8 +410,9 @@ fn tasks(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Tasks> {
tasks.insert( tasks.insert(
key.clone(), key.clone(),
::parse::task(tts) ::parse::task(tts).chain_err(
.chain_err(|| format!("parsing task `{}`", key))?, || format!("parsing task `{}`", key),
)?,
); );
Ok(()) Ok(())
...@@ -429,3 +437,121 @@ fn u8(tt: Option<&TokenTree>) -> Result<u8> { ...@@ -429,3 +437,121 @@ fn u8(tt: Option<&TokenTree>) -> Result<u8> {
bail!("expected integer, found {:?}", tt); bail!("expected integer, found {:?}", tt);
} }
} }
/// Parses the contents of `crc! { $Crc }`
pub fn crc(input: &str) -> Result<Crc> {
let tts = syn::parse_token_trees(input)?;
let mut crcs = None;
let mut ips = None;
fields(&tts, |key, tts| {
match key.as_ref() {
"crcs" => {
ensure!(crcs.is_none(), "duplicated `crcs` field");
crcs = Some(::parse::crcs(tts).chain_err(|| "parsing `crcs`")?);
}
"ips" => {
ensure!(ips.is_none(), "duplicated `ips` field");
ips = Some(::parse::ip(tts).chain_err(|| "parsing `ips`")?);
}
_ => bail!("unknown field: `{}`", key),
}
Ok(())
})?;
Ok(Crc { crcs, ips })
}
/// Parses `$($Ident: $Path,)*`
fn crcs(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Crcs> {
::parse::delimited(tts, DelimToken::Brace, |tts| {
let mut crcs = HashMap::new();
let mut tts = tts.iter().peekable();
while let Some(tt) = tts.next() {
let ident = if let &TokenTree::Token(Token::Ident(ref id)) = tt {
id
} else {
bail!("expected Ident, found {:?}", tt);
};
ensure!(
!crcs.contains_key(ident),
"crc {} listed more than once",
ident
);
let tt = tts.next();
if let Some(&TokenTree::Token(Token::Colon)) = tt {
} else {
bail!("expected Colon, found {:?}", tt);
}
let path = ::parse::path(&mut tts).chain_err(|| "parsing `path`")?;
tts.next();
crcs.insert(ident.clone(), path);
}
Ok(crcs)
})
}
/// Parses `$($Ident: $Path,)*`
fn ip(tts: &mut Peekable<Iter<TokenTree>>) -> Result<Ips> {
::parse::delimited(tts, DelimToken::Brace, |tts| {
let mut ips = HashMap::new();
let mut tts = tts.iter();
while let Some(tt) = tts.next() {
let ident = if let &TokenTree::Token(Token::Ident(ref id)) = tt {
id
} else {
bail!("expected Ident, found {:?}", tt);
};
ensure!(
!ips.contains_key(ident),
"ip {} listed more than once",
ident
);
let tt = tts.next();
if let Some(&TokenTree::Token(Token::Colon)) = tt {
} else {
bail!("expected Colon, found {:?}", tt);
}
let ty = ::parse::ty(&mut tts).chain_err(|| {
format!("parsing `type` for {:?}", ident)
})?;
ips.insert(ident.clone(), ty);
}
Ok(ips)
})
}
/// Parses `$Ty `
fn ty(tts: &mut Iter<TokenTree>) -> Result<Ty> {
let mut fragments = vec![];
loop {
if let Some(tt) = tts.next() {
if tt == &TokenTree::Token(Token::Comma) {
break;
} else {
fragments.push(tt);
}
} else {
bail!("expected comma, found end of macro");
}
}
Ok(syn::parse_type(&format!("{}", quote!(#(#fragments)*)))?)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment