summaryrefslogtreecommitdiff
path: root/lib/python/qmk/c_parse.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python/qmk/c_parse.py')
-rw-r--r--lib/python/qmk/c_parse.py118
1 files changed, 118 insertions, 0 deletions
diff --git a/lib/python/qmk/c_parse.py b/lib/python/qmk/c_parse.py
index 72be690019..359aaccbbc 100644
--- a/lib/python/qmk/c_parse.py
+++ b/lib/python/qmk/c_parse.py
@@ -1,5 +1,9 @@
1"""Functions for working with config.h files. 1"""Functions for working with config.h files.
2""" 2"""
3from pygments.lexers.c_cpp import CLexer
4from pygments.token import Token
5from pygments import lex
6from itertools import islice
3from pathlib import Path 7from pathlib import Path
4import re 8import re
5 9
@@ -13,6 +17,13 @@ multi_comment_regex = re.compile(r'/\*(.|\n)*?\*/', re.MULTILINE)
13layout_macro_define_regex = re.compile(r'^#\s*define') 17layout_macro_define_regex = re.compile(r'^#\s*define')
14 18
15 19
20def _get_chunks(it, size):
21 """Break down a collection into smaller parts
22 """
23 it = iter(it)
24 return iter(lambda: tuple(islice(it, size)), ())
25
26
16def strip_line_comment(string): 27def strip_line_comment(string):
17 """Removes comments from a single line string. 28 """Removes comments from a single line string.
18 """ 29 """
@@ -170,3 +181,110 @@ def _parse_matrix_locations(matrix, file, macro_name):
170 matrix_locations[identifier] = [row_num, col_num] 181 matrix_locations[identifier] = [row_num, col_num]
171 182
172 return matrix_locations 183 return matrix_locations
184
185
186def _coerce_led_token(_type, value):
187 """ Convert token to valid info.json content
188 """
189 value_map = {
190 'NO_LED': None,
191 'LED_FLAG_ALL': 0xFF,
192 'LED_FLAG_NONE': 0x00,
193 'LED_FLAG_MODIFIER': 0x01,
194 'LED_FLAG_UNDERGLOW': 0x02,
195 'LED_FLAG_KEYLIGHT': 0x04,
196 'LED_FLAG_INDICATOR': 0x08,
197 }
198 if _type is Token.Literal.Number.Integer:
199 return int(value)
200 if _type is Token.Literal.Number.Float:
201 return float(value)
202 if _type is Token.Literal.Number.Hex:
203 return int(value, 0)
204 if _type is Token.Name and value in value_map.keys():
205 return value_map[value]
206
207
208def _parse_led_config(file, matrix_cols, matrix_rows):
209 """Return any 'raw' led/rgb matrix config
210 """
211 file_contents = file.read_text(encoding='utf-8')
212 file_contents = comment_remover(file_contents)
213 file_contents = file_contents.replace('\\\n', '')
214
215 matrix_raw = []
216 position_raw = []
217 flags = []
218
219 found_led_config = False
220 bracket_count = 0
221 section = 0
222 for _type, value in lex(file_contents, CLexer()):
223 # Assume g_led_config..stuff..;
224 if value == 'g_led_config':
225 found_led_config = True
226 elif value == ';':
227 found_led_config = False
228 elif found_led_config:
229 # Assume bracket count hints to section of config we are within
230 if value == '{':
231 bracket_count += 1
232 if bracket_count == 2:
233 section += 1
234 elif value == '}':
235 bracket_count -= 1
236 else:
237 # Assume any non whitespace value here is important enough to stash
238 if _type in [Token.Literal.Number.Integer, Token.Literal.Number.Float, Token.Literal.Number.Hex, Token.Name]:
239 if section == 1 and bracket_count == 3:
240 matrix_raw.append(_coerce_led_token(_type, value))
241 if section == 2 and bracket_count == 3:
242 position_raw.append(_coerce_led_token(_type, value))
243 if section == 3 and bracket_count == 2:
244 flags.append(_coerce_led_token(_type, value))
245
246 # Slightly better intrim format
247 matrix = list(_get_chunks(matrix_raw, matrix_cols))
248 position = list(_get_chunks(position_raw, 2))
249 matrix_indexes = list(filter(lambda x: x is not None, matrix_raw))
250
251 # If we have not found anything - bail
252 if not section:
253 return None
254
255 # TODO: Improve crude parsing/validation
256 if len(matrix) != matrix_rows and len(matrix) != (matrix_rows / 2):
257 raise ValueError("Unable to parse g_led_config matrix data")
258 if len(position) != len(flags):
259 raise ValueError("Unable to parse g_led_config position data")
260 if len(matrix_indexes) and (max(matrix_indexes) >= len(flags)):
261 raise ValueError("OOB within g_led_config matrix data")
262
263 return (matrix, position, flags)
264
265
266def find_led_config(file, matrix_cols, matrix_rows):
267 """Search file for led/rgb matrix config
268 """
269 found = _parse_led_config(file, matrix_cols, matrix_rows)
270 if not found:
271 return None
272
273 # Expand collected content
274 (matrix, position, flags) = found
275
276 # Align to output format
277 led_config = []
278 for index, item in enumerate(position, start=0):
279 led_config.append({
280 'x': item[0],
281 'y': item[1],
282 'flags': flags[index],
283 })
284 for r in range(len(matrix)):
285 for c in range(len(matrix[r])):
286 index = matrix[r][c]
287 if index is not None:
288 led_config[index]['matrix'] = [r, c]
289
290 return led_config