doublify_toolkit/filtering/
parser.rs

1// The MIT License (MIT)
2//
3// Copyright (c) 2017 Doublify Technologies
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21// THE SOFTWARE.
22
23use filtering::scanner::{Kind, Token};
24
25use std::boxed::Box;
26use std::fmt::Debug;
27use std::iter::Peekable;
28
29use std::str::FromStr;
30
31/// AST expressions
32#[derive(Debug, PartialEq)]
33pub enum Expression {
34  /// Or expression
35  OrExpression(OrExpression),
36  /// In expression
37  InExpression(InExpression),
38  /// Variable declaration
39  VariableDeclaration(VariableDeclaration),
40  /// Literal expression
41  Literal(Literal),
42  /// Unknown expression
43  Unknown,
44}
45
46/// Or expression data
47#[derive(Debug, PartialEq)]
48pub struct OrExpression {
49  /// Or expression items
50  pub children: Vec<Box<Expression>>,
51}
52
53/// In expression data
54#[derive(Debug, PartialEq)]
55pub struct InExpression {
56  /// In expression items
57  pub children: Vec<Box<Expression>>,
58}
59
60/// Kind of variable declaration
61#[derive(Debug, PartialEq)]
62pub enum VariableDeclarationKind {
63  /// Keyword is true
64  IsKeyword,
65  /// Keyword is false
66  NotKeyword,
67}
68
69/// Variable declaration data
70#[derive(Debug, PartialEq)]
71pub struct VariableDeclaration {
72  /// Kind
73  pub kind: Option<VariableDeclarationKind>,
74  /// Name
75  pub name: Literal,
76  /// Initializer (aka value)
77  pub children: Option<Box<Expression>>,
78}
79
80/// Literal expression data
81#[derive(Clone, Debug, PartialEq)]
82pub enum Literal {
83  /// String
84  String(String),
85  /// Number
86  Integer(f64),
87  /// Boolean
88  Boolean(bool),
89  /// Identifier
90  Identifier(String),
91}
92
93/// Source file
94#[derive(Debug, PartialEq)]
95pub struct SourceFile {
96  /// Nodes of expressions
97  pub body: Vec<Box<Expression>>,
98}
99
100/// Matches identifier name to variable declaration kind
101fn match_keyword(raw_keyword: &str) -> Option<VariableDeclarationKind> {
102  use self::VariableDeclarationKind::{IsKeyword, NotKeyword};
103
104  match raw_keyword {
105    "is" => Some(IsKeyword),
106    "not" => Some(NotKeyword),
107    _ => None,
108  }
109}
110
111/// Parses variable declaration or identifier
112fn parse_identifier<'a, It>(it: &mut Peekable<It>, raw_token: &Token) -> Box<Expression>
113  where It: Iterator<Item = &'a Token> + Clone
114{
115  let ref binding = raw_token.binding;
116  let keyword = match_keyword(binding.as_ref());
117  let next_token = it.peek().map(|c| *c);
118  let identifier = Literal::Identifier(binding.to_owned());
119
120  let expression = match next_token {
121    Some(ref token) if token.kind == Kind::Colon => {
122      it.next();
123      let token = it.next().unwrap();
124      let node = parse_expression(it, token).unwrap();
125
126      let variable_declaration = VariableDeclaration {
127        kind: keyword,
128        name: identifier,
129        children: Some(node),
130      };
131
132      Expression::VariableDeclaration(variable_declaration)
133    }
134    _ => Expression::Literal(identifier),
135  };
136
137  Box::new(expression)
138}
139
140/// Parses Or expression
141fn parse_or_expression<'a, It>(it: &mut Peekable<It>) -> Box<Expression>
142  where It: Iterator<Item = &'a Token> + Clone
143{
144  let mut node = OrExpression { children: vec![] };
145  let predicate_or_expression = &|ref token: &&Token| -> bool {
146                                   (token.kind != Kind::Curly) ||
147                                   (token.kind == Kind::Curly && token.binding != "}")
148                                 };
149
150  while let Some(token) = it.take_while(predicate_or_expression).next() {
151    node.children.push(parse_expression(it, token).unwrap());
152  }
153
154  let expression = Expression::OrExpression(node);
155
156  Box::new(expression)
157}
158
159/// Parses In expression
160fn parse_in_expression<'a, It>(it: &mut Peekable<It>) -> Box<Expression>
161  where It: Iterator<Item = &'a Token> + Clone
162{
163  let mut node = InExpression { children: vec![] };
164  let predicate_in_expression = &|ref token: &&Token| -> bool {
165                                   (token.kind != Kind::Parentheses) ||
166                                   (token.kind == Kind::Parentheses && token.binding != ")")
167                                 };
168
169  while let Some(token) = it.take_while(predicate_in_expression).next() {
170    node.children.push(parse_expression(it, token).unwrap());
171  }
172
173  let expression = Expression::InExpression(node);
174
175  Box::new(expression)
176}
177
178/// Wraps Literal data into Literal variant
179fn parse_literal<T>(kind: fn(T) -> Literal, binding: T) -> Expression {
180  let node = kind(binding);
181  let expr = Expression::Literal(node);
182
183  expr
184}
185
186/// Converts string binding to T
187fn parse_type<T>(kind: fn(T) -> Literal, binding: &String) -> Expression
188  where T: FromStr,
189        <T as FromStr>::Err: Debug
190{
191  parse_literal(kind, binding.parse::<T>().unwrap())
192}
193
194/// Parses string
195fn parse_string(token: &Token) -> Box<Expression> {
196  let node_binding = token
197    .binding
198    .trim_matches('"')
199    .trim_matches('\'')
200    .to_string();
201
202  let expr = parse_literal(Literal::String, node_binding);
203  Box::new(expr)
204}
205
206/// Parses number
207fn parse_integer(token: &Token) -> Box<Expression> {
208  Box::new(parse_type::<f64>(Literal::Integer, &token.binding))
209}
210
211/// Parses boolean
212fn parse_boolean(token: &Token) -> Box<Expression> {
213  Box::new(parse_type::<bool>(Literal::Boolean, &token.binding))
214}
215
216/// Parses any expression
217fn parse_expression<'a, It>(it: &mut Peekable<It>,
218                            token: &Token)
219                            -> Result<Box<Expression>, Box<String>>
220  where It: Iterator<Item = &'a Token> + Clone
221{
222  match token.kind {
223    Kind::String => Ok(parse_string(token)),
224    Kind::Integer => Ok(parse_integer(token)),
225    Kind::Boolean => Ok(parse_boolean(token)),
226    Kind::Identifier => Ok(parse_identifier(it, token)),
227    Kind::Parentheses => Ok(parse_in_expression(it)),
228    Kind::Curly => Ok(parse_or_expression(it)),
229    _ => Err(Box::new(format!("{:?}", token))),
230  }
231}
232
233/// Converts vector of tokens into source file (aka AST)
234pub fn parse(tokens: Vec<Token>) -> SourceFile {
235  let mut ast = SourceFile { body: vec![] };
236  let mut it = tokens.iter().peekable();
237
238  while let Some(token) = it.next() {
239    let expression = parse_expression(&mut it, &token).unwrap();
240
241    ast.body.push(expression);
242  }
243
244  ast
245}