kll_compiler/
parser.rs

1use pest_consume::{match_nodes, Error, Parser};
2use std::collections::HashMap;
3use std::ops::Range;
4use std::str::FromStr;
5
6use crate::types::*;
7
8pub type PestError = Error<Rule>;
9type Result<T> = std::result::Result<T, PestError>;
10type Node<'i> = pest_consume::Node<'i, Rule, ()>;
11
12#[derive(Parser)]
13#[grammar = "kll.pest"]
14pub struct KLLParser;
15
16pub fn parse_int(s: &str) -> usize {
17    //dbg!(s);
18    if s.starts_with("0x") {
19        usize::from_str_radix(s.trim_start_matches("0x"), 16).unwrap_or(0)
20    } else {
21        s.parse::<usize>().unwrap_or(0)
22    }
23}
24
25#[pest_consume::parser]
26impl KLLParser {
27    fn EOI(_input: Node) -> Result<()> {
28        Ok(())
29    }
30    fn word(input: Node) -> Result<&str> {
31        Ok(input.as_str())
32    }
33    fn string(input: Node) -> Result<&str> {
34        Ok(input.as_str().trim_matches('"'))
35    }
36    fn unistr(input: Node) -> Result<&str> {
37        Ok(input.as_str().strip_prefix('u').unwrap().trim_matches('"'))
38    }
39    fn number(input: Node) -> Result<usize> {
40        Ok(parse_int(input.as_str()))
41    }
42    fn range(input: Node) -> Result<(usize, usize)> {
43        Ok(match_nodes!(input.into_children();
44            [number(start)] => (start, start),
45            [number(start), number(end)] => (start, end),
46            [string(_name)] => (0, 0), // XXX (What table are we using?)
47        ))
48    }
49    fn ids(input: Node) -> Result<Indices> {
50        Ok(match_nodes!(input.into_children();
51            [range(ranges)..] => ranges.map(|(start, end)| Range { start, end }).collect(),
52        ))
53    }
54
55    fn name(input: Node) -> Result<&str> {
56        Ok(input.as_str())
57    }
58    fn value(input: Node) -> Result<&str> {
59        Ok(input.as_str())
60    }
61    fn array(input: Node) -> Result<(&str, Option<usize>)> {
62        Ok(match_nodes!(input.into_children();
63            [name(n)] => (n, None),
64            [name(n), number(i)] => (n, Some(i)),
65        ))
66    }
67    fn rhs(input: Node) -> Result<&str> {
68        Ok(input.as_str())
69    }
70
71    fn kv(input: Node) -> Result<(&str, &str)> {
72        Ok(match_nodes!(input.into_children();
73            [word(k), word(v)] => (k,v),
74            [word(k), ] => (k,"")
75        ))
76    }
77    fn kvmap(input: Node) -> Result<HashMap<&str, &str>> {
78        Ok(match_nodes!(input.into_children();
79            [kv(kv)..] => kv.collect(),
80        ))
81    }
82
83    fn function(input: Node) -> Result<Capability> {
84        Ok(match_nodes!(input.into_children();
85            [name(n)] => Capability {
86                function: n,
87                args: vec![],
88            },
89            [name(n), kvmap(args)] => Capability {
90                function: n,
91                args: args.keys().copied().collect(), // xxx
92            }
93        ))
94    }
95
96    fn binding(input: Node) -> Result<TriggerMode> {
97        Ok(match input.as_str() {
98            ":" => TriggerMode::Replace,
99            "::" => TriggerMode::SoftReplace,
100            ":+" => TriggerMode::Add,
101            ":-" => TriggerMode::Remove,
102            "i:" => TriggerMode::IsolateReplace,
103            "i::" => TriggerMode::IsolateSoftReplace,
104            "i:+" => TriggerMode::IsolateAdd,
105            "i:-" => TriggerMode::IsolateRemove,
106            _ => unreachable!(),
107        })
108    }
109
110    fn pixel(input: Node) -> Result<Indices> {
111        Ok(match_nodes!(input.into_children();
112            [ids(ranges)] => ranges,
113            [number(index)] => vec![ Range {start: index, end: index } ],
114        ))
115    }
116    fn channel(input: Node) -> Result<PixelColor> {
117        let color = input.as_str();
118        //dbg!(color);
119        if color.len() >= 2 {
120            Ok(match (&color[0..1], &color[1..2]) {
121                ("+", ":") | ("-", ":") => {
122                    PixelColor::RelativeNoRoll(color[2..].parse::<isize>().unwrap())
123                }
124                (">", ">") | ("<", "<") => PixelColor::Shift(color[2..].parse::<isize>().unwrap()),
125                ("+", _) | ("-", _) => PixelColor::Relative(color.parse::<isize>().unwrap()),
126                _ => PixelColor::Rgb(parse_int(color)),
127            })
128        } else {
129            Ok(PixelColor::Rgb(parse_int(color)))
130        }
131    }
132
133    fn pixelval(input: Node) -> Result<Pixel> {
134        Ok(match_nodes!(input.into_children();
135            [usbcode(usbcode), channel(c)..] => {
136                Pixel {
137                    range: PixelRange {
138                        index: None,
139                        row: None,
140                        col: None,
141                        key: Some(usbcode),
142                    },
143                    channel_values: c.collect(),
144                }
145            },
146            [scancode(scancode), channel(c)..] => {
147                Pixel {
148                    range: PixelRange {
149                        index: None,
150                        row: None,
151                        col: None,
152                        key: Some(Key::Scancode(scancode)),
153                    },
154                    channel_values: c.collect(),
155                }
156            },
157            [kvmap(map), channel(c)..] => {
158                // Retrieve range and print a message if there are problems
159                // TODO - Print line number on error
160                Pixel {
161                    range: match PixelRange::from_map(map.clone()) {
162                        Ok(range) => range,
163                        Err(err) => {
164                            panic!("Could not collect PixelRange from map({:?}) - Error({})", map, err);
165                        }
166                    }, // XXX Handle error
167                    channel_values: c.collect(),
168                }
169            }
170        ))
171    }
172
173    fn scancode(input: Node) -> Result<usize> {
174        Ok(parse_int(input.as_str().strip_prefix('S').unwrap()))
175    }
176    fn charcode(input: Node) -> Result<Key> {
177        let charcode = input.as_str().trim_matches('"');
178        Ok(Key::Char(charcode))
179    }
180    fn unicode(input: Node) -> Result<Key> {
181        let unicode = input.as_str().strip_prefix("U+").unwrap();
182        Ok(Key::Char(unicode))
183    }
184    fn usbcode(input: Node) -> Result<Key> {
185        let usbcode = input.as_str().strip_prefix('U').unwrap();
186        Ok(Key::Usb(usbcode.trim_matches('"')))
187    }
188    fn consumer(input: Node) -> Result<Key> {
189        let concode = input.as_str().strip_prefix("CONS").unwrap();
190        Ok(Key::Consumer(concode.trim_matches('"')))
191    }
192    fn system(input: Node) -> Result<Key> {
193        let syscode = input.as_str().strip_prefix("SYS").unwrap();
194        Ok(Key::System(syscode.trim_matches('"')))
195    }
196    fn none(_input: Node) -> Result<&str> {
197        Ok("None")
198    }
199    fn key(input: Node) -> Result<Key> {
200        Ok(match_nodes!(input.into_children();
201                [scancode(s)] => Key::Scancode(s),
202                [charcode(key)] => key,
203                [unicode(key)] => key,
204                [usbcode(key)] => key,
205                [consumer(key)] => key,
206                [system(key)] => key,
207                [none(_)] => Key::None,
208        ))
209    }
210
211    fn layer_type(input: Node) -> Result<LayerMode> {
212        Ok(LayerMode::from_str(input.as_str()).unwrap()) // XXX Handle error
213    }
214
215    fn layer(input: Node) -> Result<(LayerMode, Indices)> {
216        Ok(match_nodes!(input.into_children();
217            [layer_type(mode), ids(indices)] => (mode, indices),
218            [layer_type(mode), number(index)] => (mode, vec![ Range { start: index, end: index } ]),
219        ))
220    }
221
222    fn indicator(input: Node) -> Result<Indices> {
223        Ok(match_nodes!(input.into_children();
224            [ids(indices)] => indices,
225            [number(index)] => vec![ Range { start: index, end: index } ],
226            [string(_name)] => vec![ Range { start: 0, end: 0 } ], // XXX (Need LUT)
227        ))
228    }
229
230    fn trig(input: Node) -> Result<(usize, usize, Option<usize>)> {
231        Ok(match_nodes!(input.into_children();
232            [number(bank), number(index)] => (bank, index, None),
233            [number(bank), number(index), number(arg)] => (bank, index, Some(arg)),
234        ))
235    }
236    fn trigger_type(input: Node) -> Result<TriggerType> {
237        Ok(match_nodes!(input.into_children();
238            [name(name)] => TriggerType::Animation(name),
239            [key(trigger)] => TriggerType::Key(trigger),
240            [layer(trigger)] => TriggerType::Layer(trigger),
241            [indicator(trigger)] => TriggerType::Indicator(trigger),
242            [trig((bank, index, arg))] => TriggerType::Generic((bank, index, arg)),
243        ))
244    }
245    fn trigger(input: Node) -> Result<Trigger> {
246        Ok(match_nodes!(input.into_children();
247            [trigger_type(trigger)] => Trigger {
248                trigger,
249                state: None,
250            },
251            [trigger_type(trigger), kvmap(args)] => Trigger {
252                trigger,
253                state: Some(StateMap::from_map(args).unwrap()), // XXX Handle error
254            },
255        ))
256    }
257
258    fn result_type(input: Node) -> Result<ResultType> {
259        Ok(match_nodes!(input.into_children();
260            [charcode(key)] => ResultType::Output(key),
261            [unicode(key)] => ResultType::Output(key),
262            [usbcode(key)] => ResultType::Output(key),
263            [consumer(key)] => ResultType::Output(key),
264            [system(key)] => ResultType::Output(key),
265            [pixelval(pixel)] => ResultType::Pixel(pixel),
266            [animation_result(anim)] => ResultType::Animation(anim),
267            [function(cap)] => ResultType::Capability((cap, None)), // XXX
268            [layer(layer)] => ResultType::Layer(layer),
269            [string(text)] => ResultType::Text(text),
270            [unistr(text)] => ResultType::UnicodeText(text),
271            [none(_)] => ResultType::NOP,
272        ))
273    }
274    fn result(input: Node) -> Result<Action> {
275        Ok(match_nodes!(input.into_children();
276            [result_type(result)] => Action {
277                result,
278                state: None,
279            },
280            [result_type(result), kvmap(args)] => Action {
281                result,
282                state: Some(StateMap::from_map(args).unwrap()), // XXX Handle error
283            },
284        ))
285    }
286    fn result_group(input: Node) -> Result<Vec<Action>> {
287        Ok(match_nodes!(input.into_children();
288            [result(results)..] => results.collect(),
289        ))
290    }
291    fn results(input: Node) -> Result<Vec<Vec<Action>>> {
292        Ok(match_nodes!(input.into_children();
293            [result_group(groups)..] => groups.collect(),
294        ))
295    }
296
297    fn property(input: Node) -> Result<Statement> {
298        let (name, index, value) = match_nodes!(input.into_children();
299            [name(n), rhs(v)] => (n, None, v),
300            [array((n,i)), rhs(v)] => (n, i, v),
301            [string(n), rhs(v)] => (n, None, v),
302        );
303        Ok(Statement::Variable((name, index, value)))
304    }
305    fn define(input: Node) -> Result<Statement> {
306        Ok(match_nodes!(input.into_children();
307            [name(n), value(v)] => Statement::Define((n, v))
308        ))
309    }
310    fn capability(input: Node) -> Result<Statement> {
311        Ok(match_nodes!(input.into_children();
312            [name(n), function(f)] =>  Statement::Capability((n, f)),
313        ))
314    }
315    fn trigger_group(input: Node) -> Result<Vec<Trigger>> {
316        Ok(match_nodes!(input.into_children();
317            [trigger(triggers)..] => triggers.collect(),
318        ))
319    }
320    fn triggers(input: Node) -> Result<Vec<Vec<Trigger>>> {
321        Ok(match_nodes!(input.into_children();
322            [trigger_group(groups)..] => groups.collect(),
323        ))
324    }
325    fn mapping(input: Node) -> Result<Statement> {
326        Ok(match_nodes!(input.into_children();
327            [triggers(triggers), binding(mode), results(results)] => Statement::Keymap(Mapping(TriggerList(triggers), mode, ResultList(results))),
328        ))
329    }
330    fn position(input: Node) -> Result<Statement> {
331        Ok(match_nodes!(input.into_children();
332            [range((start, end)), kvmap(map)] => {
333                Statement::Position((vec![ Range { start, end } ], Position::from_map(map)))
334            },
335            [scancode(index), kvmap(map)] => {
336                Statement::Position((vec![ Range { start: index, end: index }], Position::from_map(map)))
337            },
338            [pixel(indices), kvmap(map)] => {
339                Statement::Position((indices, Position::from_map(map)))
340            }
341        ))
342    }
343    fn pixelmap(input: Node) -> Result<Statement> {
344        Ok(match_nodes!(input.into_children();
345            [range((start, end)), kvmap(channelmap), scancode(scancode)] => {
346                let pixel = PixelDef::new(channelmap, Some(scancode));
347                Statement::Pixelmap((vec![ Range { start, end } ], pixel))
348            },
349            [pixel(indices), kvmap(channelmap), _none] => {
350                let pixel = PixelDef::new(channelmap, None);
351                Statement::Pixelmap((indices, pixel))
352            },
353            [pixel(indices), kvmap(channelmap), scancode(scancode)] => {
354                let pixel = PixelDef::new(channelmap, Some(scancode));
355                Statement::Pixelmap((indices, pixel))
356            }
357        ))
358    }
359    fn animdef(input: Node) -> Result<Statement> {
360        Ok(match_nodes!(input.into_children();
361            [name(name), kvmap(args)] => {
362                let animation = Animation {
363                    modifiers: args,
364                    frames: vec![],
365                };
366
367                Statement::Animation((name, animation))
368            }
369        ))
370    }
371    fn animation_result(input: Node) -> Result<AnimationResult> {
372        Ok(match_nodes!(input.into_children();
373            [name(name), kvmap(args)] => {
374                AnimationResult {
375                    name,
376                    args: args.keys().copied().collect(), // xxx
377                }
378            }
379        ))
380    }
381    fn animframe(input: Node) -> Result<Statement> {
382        Ok(match_nodes!(input.into_children();
383            [name(name), ids(indices), pixelval(pixels)..] => {
384                Statement::Frame((name, indices, pixels.collect()))
385            },
386            [name(name), number(index), pixelval(pixels)..] => {
387                Statement::Frame((name, vec![ Range { start: index, end: index }], pixels.collect()))
388            }
389        ))
390    }
391    fn statement(input: Node) -> Result<Statement> {
392        //dbg!(input.as_str());
393        //dbg!(&input);
394        //let _ = input.children().single().map(|n| dbg!(n.as_rule()));
395        Ok(match_nodes!(input.into_children();
396                [property(stmt)] => stmt,
397                [define(stmt)] => stmt,
398                [capability(stmt)] => stmt,
399                [mapping(stmt)]=> stmt,
400                [position(stmt)] => stmt,
401                [pixelmap(stmt)] => stmt,
402                [animdef(stmt)] => stmt,
403                [animframe(stmt)] => stmt,
404        ))
405    }
406
407    pub fn file(input: Node) -> Result<Vec<Statement>> {
408        Ok(match_nodes!(input.into_children();
409            [statement(statements).., _] => statements.collect(),
410        ))
411    }
412}
413
414impl<'a> KllFile<'a> {
415    #[allow(clippy::should_implement_trait, clippy::result_large_err)]
416    pub fn from_str(text: &str) -> Result<KllFile> {
417        let inputs = KLLParser::parse(Rule::file, text)?;
418        let input = inputs.single()?;
419
420        let kll = KllFile {
421            statements: KLLParser::file(input)?,
422        };
423
424        Ok(kll)
425    }
426}
427
428#[cfg(test)]
429mod tests {
430    use crate::parser::{KLLParser, Rule};
431    use pest::Parser;
432
433    #[test]
434    fn test_numbers() {
435        let number = KLLParser::parse(Rule::number, "1234");
436        assert!(number.is_ok());
437
438        let number = KLLParser::parse(Rule::number, "0x2f");
439        assert!(number.is_ok());
440
441        let not_number = KLLParser::parse(Rule::number, "this is not a number");
442        assert!(not_number.is_err());
443    }
444}