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
118
119
120
121
122
123
124
125
126
127
128
use std::collections::HashMap;
use std::collections::HashSet;

use extension::{ Extension, CoreExtension };
use operator::{ Operator, OperatorKind, OperatorOptions };
use function::Function;
use nodes::{ TokenParser, TokenParserExtension };

/// Environment configuration.
pub struct Config {
    pub autoescape: String,
}

impl Config {
    pub fn default() -> Config {
        Config {
            autoescape: "html".into()
        }
    }

    pub fn from_hashmap(map: HashMap<String, String>) -> Config {
        let default = Config::default();

        Config {
            autoescape: map.get("autoescape").cloned().unwrap_or(default.autoescape),
        }
    }
}

/// Project configuration container.
#[derive(Debug)]
pub struct Environment {
    pub operators: Vec<Operator>,
    pub token_parsers: Vec<TokenParser>,
    pub functions: Vec<Function>,
}

impl Environment {

    pub fn new(config: Config) -> Environment {
        let mut staged = Environment {
            operators: Vec::new(),
            token_parsers: Vec::new(),
            functions: Vec::new(),
        };

        CoreExtension::apply(&mut staged);

        staged
    }

    pub fn default() -> Environment {
        Environment::new(Config::default())
    }

    pub fn init_all(self) -> CompiledEnvironment {
        CompiledEnvironment {
            lexing: LexingEnvironment {
                operators: {
                    self.operators.iter()
                        .filter_map(|i| match i.options.kind {
                            OperatorKind::Unary { value, .. } => Some(value),
                            OperatorKind::Binary { value, .. } => Some(value),
                            OperatorKind::Other => None,
                        })
                        .collect()
                },
            },
            parsing: ParsingEnvironment {
                operators: {
                    self.operators.into_iter()
                        .filter_map(|i| match i.options.kind {
                            OperatorKind::Unary { value, .. } => Some((value, i.options)),
                            OperatorKind::Binary { value, .. } => Some((value, i.options)),
                            OperatorKind::Other => None,
                        })
                        .collect()
                },
                handlers: {
                    self.token_parsers.into_iter()
                        .map(|i| (i.tag, i.extension))
                        .collect()
                },
                functions: {
                    self.functions.iter()
                        .map(|f| f.name)
                        .collect()
                }
            },
        }
    }

    pub fn push_operators<I: IntoIterator<Item=Operator>>(&mut self, ops: I) {
        self.operators.extend(ops);
    }

    pub fn push_token_parsers<I: IntoIterator<Item=TokenParser>>(&mut self, ops: I) {
        self.token_parsers.extend(ops);
    }

    pub fn push_functions<I: IntoIterator<Item=Function>>(&mut self, funs: I) {
        self.functions.extend(funs);
    }
}

pub struct LexingEnvironment {
    pub operators: HashSet<&'static str>,
}

pub struct ParsingEnvironment {
    pub operators: HashMap<&'static str, OperatorOptions>,
    pub handlers: HashMap<&'static str, Box<TokenParserExtension>>,
    pub functions: HashSet<&'static str>,
}

/// Project configuration container with all extensions applied.
pub struct CompiledEnvironment {
    pub lexing: LexingEnvironment,
    pub parsing: ParsingEnvironment,
}

impl CompiledEnvironment {

    pub fn default() -> CompiledEnvironment {
        Environment::default()
            .init_all()
    }
}