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 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), ))
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(), }
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 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 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 }, 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()) }
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 } ], ))
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()), },
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)), [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()), },
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(), }
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 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}