diff --git a/src/lib.rs b/src/lib.rs index 77551c9ee9a0538f2fe5214c1a0cb76fb67e046c..283db99b46e74600b6b4120c6b804ac99be5a2ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,8 +69,33 @@ key!{KeyEnabled, "enabled"} #[proc_macro] pub fn app(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let app = parse_app(input); + //let app = check_app(app); + // let v = kv.value.as_ref().right().unwrap(); + // let tokens = quote!(#v); + // panic!("{}", v) + quote!().into() +} + +struct App { + device: Option<Path>, + resources: Vec<ResFields>, + init: Option<Path>, + idle: Vec<IdleFields>, + tasks: Vec<(Ident, Vec<EnumTask>)>, +} + +fn parse_app(input: proc_macro::TokenStream) -> Option<App> { let app: Punct<AppFields, Token![,]> = syn::parse(input).unwrap(); + let mut device: Option<Path> = None; + let mut resources: Vec<ResFields> = Vec::new(); + let mut init: Option<Path> = None; + let mut idle: Vec<IdleFields> = Vec::new(); + let mut tasks: Vec<(Ident, Vec<EnumTask>)> = Vec::new(); + + let mut ok = true; + for AppFields { key, value } in app.data.into_iter() { //println!("k {:?} v {:?}", key, value) match key.as_ref() { @@ -80,6 +105,12 @@ pub fn app(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Some(path) => { println!("path"); println!("path {:?}", path); + if device == None { + device = Some(path.clone()); + } else { + println!("Field `device` multiple defined."); + ok = false; + } } _ => { println!("device should be a path"); @@ -89,87 +120,120 @@ pub fn app(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } "resources" => { println!("resources"); - match value.right() { - Some(ts) => { - println!("ts"); - let _res: Punct<ResFields, Token![;]> = syn::parse2(ts).unwrap(); - } - _ => { - println!("expected list of resource definitions"); - panic!("internal error"); + if resources.is_empty() { + match value.right() { + Some(ts) => { + println!("ts"); + let _res: Punct<ResFields, Token![;]> = syn::parse2(ts).unwrap(); + } + _ => { + println!("expected list of resource definitions"); + panic!("internal error"); + } } + } else { + println!("Field `resource` multiple defined."); + ok = false; } } "init" => { println!("init"); - match value.right() { - Some(ts) => { - println!("ts"); - let _init: Punct<PathField, Token![,]> = syn::parse2(ts).unwrap(); - } - _ => { - println!("expected list of resource definitions"); - panic!("internal error"); + if init == None { + match value.right() { + Some(ts) => { + println!("ts"); + let _init: Punct<PathField, Token![,]> = syn::parse2(ts).unwrap(); + } + _ => { + println!("expected list of resource definitions"); + panic!("internal error"); + } } + } else { + println!("Field `init` multiple defined."); + ok = false; } } "idle" => { println!("idle"); - match value.right() { - Some(ts) => { - println!("ts"); - - let idle: Punct<EnumIdle, Token![,]> = syn::parse2(ts).unwrap(); - for e in idle.data.iter() { - match e { - EnumIdle::IdlePath(path) => println!("path {:?}", path), - EnumIdle::IdleResources(res) => println!("resources {:?}", res), + if idle.is_empty() { + match value.right() { + Some(ts) => { + println!("ts"); + + let idle: Punct<EnumIdle, Token![,]> = syn::parse2(ts).unwrap(); + for e in idle.data.iter() { + match e { + EnumIdle::IdlePath(path) => println!("path {:?}", path), + EnumIdle::IdleResources(res) => println!("resources {:?}", res), + } } } + _ => { + println!("expected list of idle definitions"); + panic!("internal error"); + } } - _ => { - println!("expected list of idle definitions"); - panic!("internal error"); - } + } else { + println!("Field `idle` multiple defined."); + ok = false; } } "tasks" => { println!("tasks"); - match value.right() { - Some(ts) => { - println!("ts"); - - let tasks: Punct<Tasks, Token![,]> = syn::parse2(ts).unwrap(); - - for Tasks { id, task } in tasks.data.into_iter() { - println!("task {}", id.as_ref()); - - let task: Punct<EnumTask, Token![,]> = syn::parse2(task).unwrap(); - for tf in task.data { - match tf { - EnumTask::TaskPrio(prio) => println!("prio"), - EnumTask::TaskPath(path) => println!("path"), - EnumTask::TaskResources(res) => println!("res"), - EnumTask::TaskEnabled(b) => println!("bool"), + if tasks.is_empty() { + match value.right() { + Some(ts) => { + println!("ts"); + + let tasks: Punct<Tasks, Token![,]> = syn::parse2(ts).unwrap(); + + for Tasks { id, task } in tasks.data.into_iter() { + println!("task {}", id.as_ref()); + + let task: Punct< + EnumTask, + Token![,], + > = syn::parse2(task).unwrap(); + for tf in task.data { + match tf { + EnumTask::TaskPrio(prio) => println!("prio"), + EnumTask::TaskPath(path) => println!("path"), + EnumTask::TaskResources(res) => println!("res"), + EnumTask::TaskEnabled(b) => println!("bool"), + } } } } + _ => { + println!("expected list of task definitions"); + panic!("internal error"); + } } - _ => { - println!("expected list of task definitions"); - panic!("internal error"); - } + } else { + println!("Field `tasks` multiple defined."); + ok = false; } } - _ => (), // unimplemented!(), + + _ => { + println!("Illegal field"); + ok = false; + } } - // println!("k {:?} ", key); } - // let v = kv.value.as_ref().right().unwrap(); - // let tokens = quote!(#v); - // panic!("{}", v) - quote!().into() + if ok { + Some(App { + device, + resources, + init, + idle, + tasks, + }) + } else { + None + } } // Vec[T] (or perhaps not quite) @@ -352,3 +416,20 @@ impl Synom for Tasks { (Tasks{id, task: task.1}) )); } + +fn check_app(app: App) -> Option<App> { + let mut ok = true; + + // check device + if app.device == None { + println!("Device field missing"); + ok = false; + } + + // check idle + if ok { + Some(app) + } else { + None + } +}