1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use std::path::{Path, PathBuf};

use proc_macro2::Span;
use syn::{
    braced, bracketed,
    parse::{Parse, ParseStream},
    punctuated::Punctuated,
    Error, Ident, LitStr, Result, Token,
};

#[derive(Debug, Clone)]
pub struct Config {
    pub witx: WitxConf,
    pub ctx: CtxConf,
    pub emit_metadata: bool,
}

#[derive(Debug, Clone)]
pub enum ConfigField {
    Witx(WitxConf),
    Ctx(CtxConf),
}

impl ConfigField {
    pub fn parse_pair(ident: &str, value: ParseStream, err_loc: Span) -> Result<Self> {
        match ident {
            "witx" => Ok(ConfigField::Witx(value.parse()?)),
            "ctx" => Ok(ConfigField::Ctx(value.parse()?)),
            _ => Err(Error::new(err_loc, "expected `witx` or `ctx`")),
        }
    }
}

impl Parse for ConfigField {
    fn parse(input: ParseStream) -> Result<Self> {
        let id: Ident = input.parse()?;
        let _colon: Token![:] = input.parse()?;
        Self::parse_pair(id.to_string().as_ref(), input, id.span())
    }
}

impl Config {
    pub fn build(fields: impl Iterator<Item = ConfigField>, err_loc: Span) -> Result<Self> {
        let mut witx = None;
        let mut ctx = None;
        for f in fields {
            match f {
                ConfigField::Witx(c) => {
                    witx = Some(c);
                }
                ConfigField::Ctx(c) => {
                    ctx = Some(c);
                }
            }
        }
        Ok(Config {
            witx: witx
                .take()
                .ok_or_else(|| Error::new(err_loc, "`witx` field required"))?,
            ctx: ctx
                .take()
                .ok_or_else(|| Error::new(err_loc, "`ctx` field required"))?,
            emit_metadata: false,
        })
    }
}

impl Parse for Config {
    fn parse(input: ParseStream) -> Result<Self> {
        let contents;
        let _lbrace = braced!(contents in input);
        let fields: Punctuated<ConfigField, Token![,]> =
            contents.parse_terminated(ConfigField::parse)?;
        Ok(Config::build(fields.into_iter(), input.span())?)
    }
}

#[derive(Debug, Clone)]
pub struct WitxConf {
    pub paths: Vec<PathBuf>,
}

impl WitxConf {
    pub fn make_paths_relative_to<P: AsRef<Path>>(&mut self, root: P) {
        self.paths.iter_mut().for_each(|p| {
            if !p.is_absolute() {
                *p = PathBuf::from(root.as_ref()).join(p.clone());
            }
        });
    }
}

impl Parse for WitxConf {
    fn parse(input: ParseStream) -> Result<Self> {
        let content;
        let _ = bracketed!(content in input);
        let path_lits: Punctuated<LitStr, Token![,]> = content.parse_terminated(Parse::parse)?;
        let paths = path_lits
            .iter()
            .map(|lit| PathBuf::from(lit.value()))
            .collect();
        Ok(WitxConf { paths })
    }
}

#[derive(Debug, Clone)]
pub struct CtxConf {
    pub name: Ident,
}

impl Parse for CtxConf {
    fn parse(input: ParseStream) -> Result<Self> {
        Ok(CtxConf {
            name: input.parse()?,
        })
    }
}