doublify_toolkit/filtering/
scanner.rs1use std::cell::RefCell;
24use std::iter::Peekable;
25
26#[derive(Clone, Copy, Debug, PartialEq)]
28pub enum Kind {
29 String,
31 Integer,
33 Boolean,
35 Identifier,
37 Curly,
39 Parentheses,
41 Colon,
43}
44
45#[derive(Clone, Debug, PartialEq)]
47pub struct Token {
48 pub kind: Kind,
50 pub binding: String,
52}
53
54impl Token {
55 pub fn new(kind: Kind, binding: &'static str) -> Token {
57 Token {
58 kind,
59 binding: String::from(binding),
60 }
61 }
62
63 pub fn change_kind(&self, kind: Kind) -> Token {
65 Token {
66 kind,
67 binding: self.binding.to_owned(),
68 }
69 }
70}
71
72fn tokenize_string<'a, It>(it: &mut Peekable<It>,
74 buffer: &RefCell<String>,
75 ch: char)
76 -> Result<String, &'a str>
77 where It: Iterator<Item = char>
78{
79 let mut escaped = false;
80 let quote = ch.clone();
81 let quote_str = quote;
82
83 while let Some(ch) = it.peek().map(|c| *c) {
84 if escaped {
85 buffer.borrow_mut().push(ch);
86 escaped = false;
87 } else if ch == '\\' {
88 escaped = true;
89 } else if ch == quote {
90 it.next();
91 let mut result = String::new();
92 result.push(quote_str);
93 result.push_str(buffer.borrow().as_str());
94 result.push(quote_str);
95
96 return Ok(result);
97 } else {
98 buffer.borrow_mut().push(ch);
99 }
100
101 it.next();
102 }
103
104 Err("Can't parse string")
105}
106
107pub fn scan(raw_query: &str) -> Vec<Token> {
109 let query = raw_query.to_owned() + " ";
110 let mut it = query.chars().peekable();
111 let tokens = RefCell::new(vec![]);
112 let buffer = RefCell::new(String::new());
113
114 let bind_identifier = |binding: String| if !binding.is_empty() {
115 tokens
116 .borrow_mut()
117 .push(
118 Token {
119 kind: Kind::Identifier,
120 binding,
121 },
122 );
123
124 buffer.borrow_mut().clear()
125 };
126
127 let consume_token = |token: Token| {
128 bind_identifier(buffer.clone().into_inner());
129
130 tokens.borrow_mut().push(token)
131 };
132
133 while let Some(ch) = it.next() {
134 match ch {
135 '"' | '\'' => {
136 let str = tokenize_string(&mut it, &buffer, ch).unwrap();
137 bind_identifier(str);
138 }
139 ' ' => bind_identifier(buffer.clone().into_inner()),
140 ':' => consume_token(Token::new(Kind::Colon, ":")),
141 '{' => consume_token(Token::new(Kind::Curly, "{")),
142 '}' => consume_token(Token::new(Kind::Curly, "}")),
143 '(' => consume_token(Token::new(Kind::Parentheses, "(")),
144 ')' => consume_token(Token::new(Kind::Parentheses, ")")),
145 _ => buffer.borrow_mut().push(ch),
146 }
147
148 if ch != '"' || ch != '\'' {
149 continue;
150 }
151 }
152
153 tokens.to_owned().into_inner()
154}