1use pest::Parser;
2use pest_derive::Parser;
3use thiserror::Error;
4
5#[derive(Parser)]
9#[grammar = "src/grammar.pest"] pub struct MotogarageParser;
11
12#[derive(Error, Debug)]
16pub enum MotoError {
17 #[error("Parsing error: {0}")]
19 ParseError(#[from] pest::error::Error<Rule>),
20
21 #[error("Interp error: {0}")]
23 InterpreterError(String),
24}
25
26#[derive(Debug, Clone, PartialEq)]
33pub enum Command {
34 Definition(Motorcycle), Get(Query), Count(Query), }
38
39#[derive(Debug, Clone, Default, PartialEq)]
41pub struct Motorcycle {
42 pub name: String,
43 pub year: Option<u32>, pub engine_cc: Option<u32>,
45 pub bike_type: Option<String>,
46}
47
48#[derive(Debug, Clone, PartialEq)]
51pub struct Query {
52 pub condition: Option<Condition>,
53}
54
55#[derive(Debug, Clone, PartialEq)]
57pub struct Condition {
58 pub field: String, pub operator: String, pub value: Value, }
62
63#[derive(Debug, Clone, PartialEq)]
65pub enum Value {
66 Number(u32), StringType(String), StringLiteral(String), }
70
71impl Value {
73 pub fn value_as_number(&self) -> u32 {
75 match self {
76 Value::Number(n) => *n,
77 _ => 0,
78 }
79 }
80 pub fn value_as_string(&self) -> String {
82 match self {
83 Value::StringType(s) => s.clone(),
84 Value::StringLiteral(s) => s.clone(),
85 _ => String::new(),
86 }
87 }
88}
89
90#[derive(Debug, Default)]
94pub struct Garage {
95 bikes: Vec<Motorcycle>, }
97
98impl Garage {
99 pub fn new() -> Self {
100 Self::default()
101 }
102
103 pub fn execute(&mut self, program: Vec<Command>) -> Result<Vec<String>, MotoError> {
105 let mut results = Vec::new(); for command in program {
108 match command {
109 Command::Definition(bike) => {
111 self.bikes.push(bike);
112 }
113 Command::Get(query) => {
115 results.extend(self.run_query_get(query));
116 }
117 Command::Count(query) => {
119 let count = self.filter_bikes(&query).count();
120 results.push(format!("Bikes found: {}", count));
121 }
122 }
123 }
124 Ok(results) }
126
127 fn filter_bikes<'a>(&'a self, query: &'a Query) -> impl Iterator<Item = &'a Motorcycle> {
130 self.bikes
131 .iter()
132 .filter(move |bike| query.condition.as_ref().map_or(true, |c| bike.matches(c)))
135 }
136
137 fn run_query_get(&self, query: Query) -> Vec<String> {
139 self.filter_bikes(&query)
140 .map(|bike| bike.name.clone()) .collect() }
143}
144
145impl Motorcycle {
147 fn matches(&self, condition: &Condition) -> bool {
148 match condition.field.as_str() { "type" => self
150 .bike_type
151 .as_ref() .map_or(false, |t| *t == condition.value.value_as_string()),
154 "year" => self.year.map_or(false, |y| { compare(y, &condition.operator, condition.value.value_as_number())
156 }),
157 "engine" => self.engine_cc.map_or(false, |e| { compare(e, &condition.operator, condition.value.value_as_number())
159 }),
160 _ => false, }
162 }
163}
164fn compare(a: u32, op: &str, b: u32) -> bool {
166 match op {
167 "=" => a == b,
168 ">" => a > b,
169 "<" => a < b,
170 _ => false, }
172}
173impl Condition {} pub fn parse_moto_file(input: &str) -> Result<Vec<Command>, MotoError> {
180 let pairs = MotogarageParser::parse(Rule::file, input)?; let mut ast = Vec::new();
183
184 for pair in pairs.into_iter().next().unwrap().into_inner() {
187 match pair.as_rule() {
188 Rule::command => ast.push(parse_command(pair)), Rule::EOI => (), _ => unreachable!(), }
192 }
193 Ok(ast) }
195
196fn parse_command(pair: pest::iterators::Pair<Rule>) -> Command {
198 let inner = pair.into_inner().next().unwrap();
200 match inner.as_rule() {
201 Rule::definition => Command::Definition(parse_definition(inner)),
202 Rule::query_get => Command::Get(parse_query(inner)),
203 Rule::query_count => Command::Count(parse_query(inner)),
204 _ => unreachable!(),
205 }
206}
207
208fn parse_definition(pair: pest::iterators::Pair<Rule>) -> Motorcycle {
210 let mut inner_pairs = pair.into_inner();
211 let name = parse_string_literal(inner_pairs.next().unwrap());
213
214 let mut bike = Motorcycle {
215 name,
216 ..Default::default() };
218
219 let properties_pairs = inner_pairs.next().unwrap().into_inner();
221 for prop_pair in properties_pairs { let mut prop_inner = prop_pair.into_inner();
223 let field_name = prop_inner.next().unwrap().as_str(); let value_pair = prop_inner.next().unwrap(); match field_name {
228 "year" => bike.year = Some(parse_value(value_pair).value_as_number()),
229 "engine" => bike.engine_cc = Some(parse_value(value_pair).value_as_number()),
230 "type" => bike.bike_type = Some(parse_value(value_pair).value_as_string()),
231 _ => {} }
233 }
234 bike
235}
236
237fn parse_query(pair: pest::iterators::Pair<Rule>) -> Query {
240 let where_clause_pair = pair.into_inner().next();
242
243 let condition_pair =
245 where_clause_pair.map(|where_pair| where_pair.into_inner().next().unwrap());
246
247 let condition = condition_pair.map(parse_condition);
249
250 Query { condition } }
252
253fn parse_condition(pair: pest::iterators::Pair<Rule>) -> Condition {
255 let mut inner = pair.into_inner();
257 let field = inner.next().unwrap().as_str().to_string();
258 let operator = inner.next().unwrap().as_str().to_string();
259 let value = parse_value(inner.next().unwrap());
260 Condition {
261 field,
262 operator,
263 value,
264 }
265}
266
267fn parse_value(pair: pest::iterators::Pair<Rule>) -> Value {
269 let inner = pair.into_inner().next().unwrap();
271 match inner.as_rule() {
272 Rule::number => Value::Number(inner.as_str().parse().unwrap_or(0)),
273 Rule::number_with_unit => {
274 Value::Number(inner.as_str().replace("cc", "").parse().unwrap_or(0))
276 }
277 Rule::ident => Value::StringType(inner.as_str().to_string()),
278 Rule::string_literal => Value::StringLiteral(parse_string_literal(inner)),
279 _ => unreachable!(),
280 }
281}
282
283fn parse_string_literal(pair: pest::iterators::Pair<Rule>) -> String {
285 pair.as_str().trim_matches('"').to_string() }