bare-script 4.1.2__tar.gz → 4.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {bare_script-4.1.2/src/bare_script.egg-info → bare_script-4.1.3}/PKG-INFO +1 -1
- {bare_script-4.1.2 → bare_script-4.1.3}/setup.cfg +1 -1
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/parser.py +179 -156
- {bare_script-4.1.2 → bare_script-4.1.3/src/bare_script.egg-info}/PKG-INFO +1 -1
- {bare_script-4.1.2 → bare_script-4.1.3}/LICENSE +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/README.md +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/pyproject.toml +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/setup.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/__init__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/__main__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/bare.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/__init__.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/args.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/baredoc.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/baredocCLI.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/data.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/dataLineChart.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/dataTable.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/dataUtil.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/diff.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/draw.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/elementModel.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/forms.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/markdown.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/markdownElements.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/markdownHighlight.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/markdownParser.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/markdownUp.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/pager.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/qrcode.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/schemaDoc.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/unittest.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/include/unittestMock.bare +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/library.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/model.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/options.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/runtime.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/runtime_c.c +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script/value.py +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script.egg-info/SOURCES.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script.egg-info/dependency_links.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script.egg-info/entry_points.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script.egg-info/requires.txt +0 -0
- {bare_script-4.1.2 → bare_script-4.1.3}/src/bare_script.egg-info/top_level.txt +0 -0
|
@@ -44,8 +44,9 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
44
44
|
for ix_line_part, line_part in enumerate(lines):
|
|
45
45
|
statements = function_def['function']['statements'] if function_def is not None else script['statements']
|
|
46
46
|
|
|
47
|
-
# Comment?
|
|
48
|
-
|
|
47
|
+
# Comment or empty line?
|
|
48
|
+
line_part_trimmed = line_part.lstrip()
|
|
49
|
+
if not line_part_trimmed or line_part_trimmed[0] == '#':
|
|
49
50
|
continue
|
|
50
51
|
|
|
51
52
|
# Set the line index
|
|
@@ -74,29 +75,12 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
74
75
|
if ix_line != ix_line_part:
|
|
75
76
|
statement_base['lineCount'] = (ix_line_part - ix_line) + 1
|
|
76
77
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
if
|
|
80
|
-
# Parse the expression
|
|
81
|
-
try:
|
|
82
|
-
assignment_expr = parse_expression(match_assignment.group('expr'), line_number, script_name, True)
|
|
83
|
-
except BareScriptParserError as error:
|
|
84
|
-
column_number = len(line) - len(match_assignment.group('expr')) + error.column_number
|
|
85
|
-
raise BareScriptParserError(error.error, line, column_number, start_line_number + ix_line, script_name)
|
|
86
|
-
|
|
87
|
-
# Add the expression statement
|
|
88
|
-
expr_statement = {
|
|
89
|
-
'expr': {
|
|
90
|
-
'name': match_assignment.group('name'),
|
|
91
|
-
'expr': assignment_expr,
|
|
92
|
-
**statement_base
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
statements.append(expr_statement)
|
|
96
|
-
continue
|
|
78
|
+
# Determine the line's leading keyword for dispatch
|
|
79
|
+
match_keyword = _R_SCRIPT_KEYWORD.match(line)
|
|
80
|
+
keyword = match_keyword.group(1) if match_keyword else None
|
|
97
81
|
|
|
98
82
|
# Function definition begin?
|
|
99
|
-
match_function_begin = _R_SCRIPT_FUNCTION_BEGIN.match(line)
|
|
83
|
+
match_function_begin = _R_SCRIPT_FUNCTION_BEGIN.match(line) if keyword in ('function', 'async') else None
|
|
100
84
|
if match_function_begin:
|
|
101
85
|
# Nested function definitions are not allowed
|
|
102
86
|
if function_def is not None:
|
|
@@ -121,7 +105,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
121
105
|
continue
|
|
122
106
|
|
|
123
107
|
# Function definition end?
|
|
124
|
-
match_function_end = _R_SCRIPT_FUNCTION_END.match(line)
|
|
108
|
+
match_function_end = _R_SCRIPT_FUNCTION_END.match(line) if keyword == 'endfunction' else None
|
|
125
109
|
if match_function_end:
|
|
126
110
|
if function_def is None:
|
|
127
111
|
raise BareScriptParserError('No matching function definition', line, 1, start_line_number + ix_line, script_name)
|
|
@@ -138,7 +122,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
138
122
|
continue
|
|
139
123
|
|
|
140
124
|
# If-then begin?
|
|
141
|
-
match_if_begin = _R_SCRIPT_IF_BEGIN.match(line)
|
|
125
|
+
match_if_begin = _R_SCRIPT_IF_BEGIN.match(line) if keyword == 'if' else None
|
|
142
126
|
if match_if_begin:
|
|
143
127
|
# Parse the if-then expression
|
|
144
128
|
try:
|
|
@@ -167,7 +151,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
167
151
|
continue
|
|
168
152
|
|
|
169
153
|
# Else-if-then?
|
|
170
|
-
match_if_else_if = _R_SCRIPT_IF_ELSE_IF.match(line)
|
|
154
|
+
match_if_else_if = _R_SCRIPT_IF_ELSE_IF.match(line) if keyword == 'elif' else None
|
|
171
155
|
if match_if_else_if:
|
|
172
156
|
# Get the else-if-then definition
|
|
173
157
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -177,7 +161,9 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
177
161
|
|
|
178
162
|
# Cannot come after the else-then statement
|
|
179
163
|
if ifthen['hasElse']:
|
|
180
|
-
raise BareScriptParserError(
|
|
164
|
+
raise BareScriptParserError(
|
|
165
|
+
'Elif statement following else statement', line, 1, start_line_number + ix_line, script_name
|
|
166
|
+
)
|
|
181
167
|
|
|
182
168
|
# Parse teh else-if-then expression
|
|
183
169
|
try:
|
|
@@ -204,7 +190,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
204
190
|
continue
|
|
205
191
|
|
|
206
192
|
# Else-then?
|
|
207
|
-
match_if_else = _R_SCRIPT_IF_ELSE.match(line)
|
|
193
|
+
match_if_else = _R_SCRIPT_IF_ELSE.match(line) if keyword == 'else' else None
|
|
208
194
|
if match_if_else:
|
|
209
195
|
# Get the if-then definition
|
|
210
196
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -225,7 +211,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
225
211
|
continue
|
|
226
212
|
|
|
227
213
|
# If-then end?
|
|
228
|
-
match_if_end = _R_SCRIPT_IF_END.match(line)
|
|
214
|
+
match_if_end = _R_SCRIPT_IF_END.match(line) if keyword == 'endif' else None
|
|
229
215
|
if match_if_end:
|
|
230
216
|
# Pop the if-then definition
|
|
231
217
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -242,7 +228,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
242
228
|
continue
|
|
243
229
|
|
|
244
230
|
# While-do begin?
|
|
245
|
-
match_while_begin = _R_SCRIPT_WHILE_BEGIN.match(line)
|
|
231
|
+
match_while_begin = _R_SCRIPT_WHILE_BEGIN.match(line) if keyword == 'while' else None
|
|
246
232
|
if match_while_begin:
|
|
247
233
|
# Parse the while-do expression
|
|
248
234
|
try:
|
|
@@ -271,7 +257,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
271
257
|
continue
|
|
272
258
|
|
|
273
259
|
# While-do end?
|
|
274
|
-
match_while_end = _R_SCRIPT_WHILE_END.match(line)
|
|
260
|
+
match_while_end = _R_SCRIPT_WHILE_END.match(line) if keyword == 'endwhile' else None
|
|
275
261
|
if match_while_end:
|
|
276
262
|
# Pop the while-do definition
|
|
277
263
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -290,7 +276,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
290
276
|
continue
|
|
291
277
|
|
|
292
278
|
# For-each begin?
|
|
293
|
-
match_for_begin = _R_SCRIPT_FOR_BEGIN.match(line)
|
|
279
|
+
match_for_begin = _R_SCRIPT_FOR_BEGIN.match(line) if keyword == 'for' else None
|
|
294
280
|
if match_for_begin:
|
|
295
281
|
# Add the for-each label
|
|
296
282
|
foreach = {
|
|
@@ -335,14 +321,19 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
335
321
|
{'label': {'name': foreach['loop'], **statement_base}},
|
|
336
322
|
{'expr': {
|
|
337
323
|
'name': foreach['value'],
|
|
338
|
-
'expr': {
|
|
324
|
+
'expr': {
|
|
325
|
+
'function': {
|
|
326
|
+
'name': 'arrayGet',
|
|
327
|
+
'args': [{'variable': foreach['values']}, {'variable': foreach['index']}]
|
|
328
|
+
}
|
|
329
|
+
},
|
|
339
330
|
**statement_base
|
|
340
331
|
}}
|
|
341
332
|
])
|
|
342
333
|
continue
|
|
343
334
|
|
|
344
335
|
# For-each end?
|
|
345
|
-
match_for_end = _R_SCRIPT_FOR_END.match(line)
|
|
336
|
+
match_for_end = _R_SCRIPT_FOR_END.match(line) if keyword == 'endfor' else None
|
|
346
337
|
if match_for_end:
|
|
347
338
|
# Pop the foreach definition
|
|
348
339
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -364,7 +355,9 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
364
355
|
}},
|
|
365
356
|
{'jump': {
|
|
366
357
|
'label': foreach['loop'],
|
|
367
|
-
'expr': {
|
|
358
|
+
'expr': {
|
|
359
|
+
'binary': {'op': '<', 'left': {'variable': foreach['index']}, 'right': {'variable': foreach['length']}}
|
|
360
|
+
},
|
|
368
361
|
**statement_base
|
|
369
362
|
}},
|
|
370
363
|
{'label': {'name': foreach['done'], **statement_base}}
|
|
@@ -372,7 +365,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
372
365
|
continue
|
|
373
366
|
|
|
374
367
|
# Break statement?
|
|
375
|
-
match_break = _R_SCRIPT_BREAK.match(line)
|
|
368
|
+
match_break = _R_SCRIPT_BREAK.match(line) if keyword == 'break' else None
|
|
376
369
|
if match_break:
|
|
377
370
|
# Get the loop definition
|
|
378
371
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
@@ -388,13 +381,15 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
388
381
|
continue
|
|
389
382
|
|
|
390
383
|
# Continue statement?
|
|
391
|
-
match_continue = _R_SCRIPT_CONTINUE.match(line)
|
|
384
|
+
match_continue = _R_SCRIPT_CONTINUE.match(line) if keyword == 'continue' else None
|
|
392
385
|
if match_continue:
|
|
393
386
|
# Get the loop definition
|
|
394
387
|
label_def_depth = function_label_def_depth if function_def is not None else 0
|
|
395
388
|
ix_label_def = next((i for i, d in reversed(list(enumerate(label_defs))) if 'if' not in d), -1)
|
|
396
389
|
if ix_label_def < label_def_depth:
|
|
397
|
-
raise BareScriptParserError(
|
|
390
|
+
raise BareScriptParserError(
|
|
391
|
+
'Continue statement outside of loop', line, 1, start_line_number + ix_line, script_name
|
|
392
|
+
)
|
|
398
393
|
label_def = label_defs[ix_label_def]
|
|
399
394
|
label_key = next(iter(label_def))
|
|
400
395
|
loop_def = label_def[label_key]
|
|
@@ -404,14 +399,8 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
404
399
|
statements.append({'jump': {'label': loop_def['continue'], **statement_base}})
|
|
405
400
|
continue
|
|
406
401
|
|
|
407
|
-
# Label definition?
|
|
408
|
-
match_label = _R_SCRIPT_LABEL.match(line)
|
|
409
|
-
if match_label:
|
|
410
|
-
statements.append({'label': {'name': match_label.group('name'), **statement_base}})
|
|
411
|
-
continue
|
|
412
|
-
|
|
413
402
|
# Jump definition?
|
|
414
|
-
match_jump = _R_SCRIPT_JUMP.match(line)
|
|
403
|
+
match_jump = _R_SCRIPT_JUMP.match(line) if keyword in ('jump', 'jumpif') else None
|
|
415
404
|
if match_jump:
|
|
416
405
|
jump_statement = {'jump': {'label': match_jump.group('name'), **statement_base}}
|
|
417
406
|
if match_jump.group('expr'):
|
|
@@ -424,12 +413,14 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
424
413
|
continue
|
|
425
414
|
|
|
426
415
|
# Return definition?
|
|
427
|
-
match_return = _R_SCRIPT_RETURN.match(line)
|
|
416
|
+
match_return = _R_SCRIPT_RETURN.match(line) if keyword == 'return' else None
|
|
428
417
|
if match_return:
|
|
429
418
|
return_statement = {'return': {**statement_base}}
|
|
430
419
|
if match_return.group('expr'):
|
|
431
420
|
try:
|
|
432
|
-
return_statement['return']['expr'] = parse_expression(
|
|
421
|
+
return_statement['return']['expr'] = parse_expression(
|
|
422
|
+
match_return.group('expr'), line_number, script_name, True
|
|
423
|
+
)
|
|
433
424
|
except BareScriptParserError as error:
|
|
434
425
|
column_number = len(match_return.group('return')) - len(match_return.group('expr')) + error.column_number
|
|
435
426
|
raise BareScriptParserError(error.error, line, column_number, start_line_number + ix_line, script_name)
|
|
@@ -437,7 +428,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
437
428
|
continue
|
|
438
429
|
|
|
439
430
|
# Include definition?
|
|
440
|
-
match_include = _R_SCRIPT_INCLUDE.match(line) or _R_SCRIPT_INCLUDE_SYSTEM.match(line)
|
|
431
|
+
match_include = _R_SCRIPT_INCLUDE.match(line) or _R_SCRIPT_INCLUDE_SYSTEM.match(line) if keyword == 'include' else None
|
|
441
432
|
if match_include:
|
|
442
433
|
delim = match_include.group('delim')
|
|
443
434
|
url = match_include.group('url') if delim == '<' else \
|
|
@@ -451,6 +442,35 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
451
442
|
include_statement['include']['includes'].append({'url': url, 'system': True} if delim == '<' else {'url': url})
|
|
452
443
|
continue
|
|
453
444
|
|
|
445
|
+
# Catch-all (line starts with an identifier but isn't a recognized control statement)
|
|
446
|
+
if keyword is not None:
|
|
447
|
+
# Assignment?
|
|
448
|
+
match_assignment = _R_SCRIPT_ASSIGNMENT.match(line)
|
|
449
|
+
if match_assignment:
|
|
450
|
+
# Parse the expression
|
|
451
|
+
try:
|
|
452
|
+
assignment_expr = parse_expression(match_assignment.group('expr'), line_number, script_name, True)
|
|
453
|
+
except BareScriptParserError as error:
|
|
454
|
+
column_number = len(line) - len(match_assignment.group('expr')) + error.column_number
|
|
455
|
+
raise BareScriptParserError(error.error, line, column_number, start_line_number + ix_line, script_name)
|
|
456
|
+
|
|
457
|
+
# Add the expression statement
|
|
458
|
+
expr_statement = {
|
|
459
|
+
'expr': {
|
|
460
|
+
'name': match_assignment.group('name'),
|
|
461
|
+
'expr': assignment_expr,
|
|
462
|
+
**statement_base
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
statements.append(expr_statement)
|
|
466
|
+
continue
|
|
467
|
+
|
|
468
|
+
# Label definition?
|
|
469
|
+
match_label = _R_SCRIPT_LABEL.match(line)
|
|
470
|
+
if match_label:
|
|
471
|
+
statements.append({'label': {'name': match_label.group('name'), **statement_base}})
|
|
472
|
+
continue
|
|
473
|
+
|
|
454
474
|
# Expression
|
|
455
475
|
try:
|
|
456
476
|
expr_statement = {'expr': {'expr': parse_expression(line, line_number, script_name, True), **statement_base}}
|
|
@@ -471,7 +491,7 @@ def parse_script(script_text, start_line_number=1, script_name=None):
|
|
|
471
491
|
# BareScript regex
|
|
472
492
|
_R_SCRIPT_LINE_SPLIT = re.compile(r'\r?\n')
|
|
473
493
|
_R_SCRIPT_CONTINUATION = re.compile(r'\\\s*$')
|
|
474
|
-
|
|
494
|
+
_R_SCRIPT_KEYWORD = re.compile(r'^\s*([A-Za-z_]\w*)')
|
|
475
495
|
_R_SCRIPT_ASSIGNMENT = re.compile(r'^\s*(?P<name>[A-Za-z_]\w*)\s*=\s*(?P<expr>.+)$')
|
|
476
496
|
_R_PART_COMMENT = r'\s*(#.*)?$'
|
|
477
497
|
_R_SCRIPT_FUNCTION_BEGIN = re.compile(
|
|
@@ -516,7 +536,7 @@ def parse_expression(expr_text, line_number=None, script_name=None, array_litera
|
|
|
516
536
|
:raises BareScriptParserError: A parsing error occurred
|
|
517
537
|
"""
|
|
518
538
|
try:
|
|
519
|
-
expr, next_text = _parse_binary_expression(expr_text,
|
|
539
|
+
expr, next_text = _parse_binary_expression(expr_text, array_literals)
|
|
520
540
|
if next_text.strip() != '':
|
|
521
541
|
raise BareScriptParserError('Syntax error', next_text, 1, line_number, script_name)
|
|
522
542
|
return expr
|
|
@@ -526,42 +546,47 @@ def parse_expression(expr_text, line_number=None, script_name=None, array_litera
|
|
|
526
546
|
|
|
527
547
|
|
|
528
548
|
# Helper function to parse a binary operator expression chain
|
|
529
|
-
def _parse_binary_expression(expr_text,
|
|
530
|
-
# Parse the binary operator's left unary expression
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
549
|
+
def _parse_binary_expression(expr_text, array_literals):
|
|
550
|
+
# Parse the binary operator's left unary expression
|
|
551
|
+
left_expr, bin_text = _parse_unary_expression(expr_text, array_literals)
|
|
552
|
+
|
|
553
|
+
# Consume binary operators while present, building up the binary expression tree
|
|
554
|
+
while True:
|
|
555
|
+
# Skip leading whitespace to find the first dispatch char
|
|
556
|
+
pos = 0
|
|
557
|
+
n = len(bin_text)
|
|
558
|
+
while pos < n and bin_text[pos] in ' \t\r\n\v\f':
|
|
559
|
+
pos += 1
|
|
560
|
+
|
|
561
|
+
# End of binary expression (empty, whitespace-only, or end-of-line comment)?
|
|
562
|
+
if pos >= n or bin_text[pos] == '#':
|
|
563
|
+
return [left_expr, '']
|
|
564
|
+
|
|
565
|
+
# Binary operator? First char must be one of "!%&*+-/<=>^|"
|
|
566
|
+
is_binary_op_start = bin_text[pos] in '!%&*+-/<=>^|'
|
|
567
|
+
match_binary_op = _R_EXPR_BINARY_OP.match(bin_text) if is_binary_op_start else None
|
|
568
|
+
if match_binary_op is None:
|
|
569
|
+
return [left_expr, bin_text]
|
|
570
|
+
bin_op = match_binary_op.group(1)
|
|
571
|
+
right_text = bin_text[len(match_binary_op.group(0)):]
|
|
572
|
+
|
|
573
|
+
# Parse the right sub-expression
|
|
574
|
+
right_expr, next_text = _parse_unary_expression(right_text, array_literals)
|
|
575
|
+
|
|
576
|
+
# Create the binary expression - re-order for binary operators as necessary
|
|
577
|
+
if 'binary' in left_expr and bin_op in BINARY_REORDER and left_expr['binary']['op'] in BINARY_REORDER[bin_op]:
|
|
578
|
+
# Left expression has lower precedence - find where to put this expression within the left expression
|
|
579
|
+
reorder_expr = left_expr
|
|
580
|
+
while ('binary' in reorder_expr['binary']['right']
|
|
581
|
+
and reorder_expr['binary']['right']['binary']['op'] in BINARY_REORDER[bin_op]):
|
|
582
|
+
reorder_expr = reorder_expr['binary']['right']
|
|
583
|
+
reorder_expr['binary']['right'] = {
|
|
584
|
+
'binary': {'op': bin_op, 'left': reorder_expr['binary']['right'], 'right': right_expr}
|
|
585
|
+
}
|
|
586
|
+
else:
|
|
587
|
+
left_expr = {'binary': {'op': bin_op, 'left': left_expr, 'right': right_expr}}
|
|
562
588
|
|
|
563
|
-
|
|
564
|
-
return _parse_binary_expression(next_text, bin_expr, array_literals)
|
|
589
|
+
bin_text = next_text
|
|
565
590
|
|
|
566
591
|
|
|
567
592
|
# Binary operator re-order map
|
|
@@ -590,48 +615,54 @@ BINARY_REORDER = {
|
|
|
590
615
|
|
|
591
616
|
# Helper function to parse a unary expression
|
|
592
617
|
def _parse_unary_expression(expr_text, array_literals):
|
|
593
|
-
#
|
|
594
|
-
|
|
618
|
+
# Skip leading whitespace to find the first dispatch char
|
|
619
|
+
pos = 0
|
|
620
|
+
n = len(expr_text)
|
|
621
|
+
while pos < n and expr_text[pos] in ' \t\r\n\v\f':
|
|
622
|
+
pos += 1
|
|
623
|
+
if pos >= n:
|
|
624
|
+
raise BareScriptParserError('Syntax error', expr_text, 1, None, None)
|
|
625
|
+
c = expr_text[pos]
|
|
626
|
+
|
|
627
|
+
# Group? '('
|
|
628
|
+
match_group_open = _R_EXPR_GROUP_OPEN.match(expr_text) if c == '(' else None
|
|
595
629
|
if match_group_open:
|
|
596
630
|
group_text = expr_text[len(match_group_open.group(0)):]
|
|
597
|
-
expr, next_text = _parse_binary_expression(group_text,
|
|
631
|
+
expr, next_text = _parse_binary_expression(group_text, array_literals)
|
|
598
632
|
match_group_close = _R_EXPR_GROUP_CLOSE.match(next_text)
|
|
599
633
|
if match_group_close is None:
|
|
600
634
|
raise BareScriptParserError('Unmatched parenthesis', expr_text, 1, None, None)
|
|
601
635
|
return [{'group': expr}, next_text[len(match_group_close.group(0)):]]
|
|
602
636
|
|
|
603
|
-
# Number?
|
|
604
|
-
match_number = _R_EXPR_NUMBER.match(expr_text)
|
|
637
|
+
# Number? digit, '+', or '-' (the '-' falls through to unary below if no number matches)
|
|
638
|
+
match_number = _R_EXPR_NUMBER.match(expr_text) if c.isdigit() or c in '+-' else None
|
|
605
639
|
if match_number:
|
|
606
640
|
number_str = match_number.group(1)
|
|
607
641
|
number = float(int(number_str, base=16)) if number_str.startswith('0x') else float(number_str)
|
|
608
|
-
|
|
609
|
-
return [expr, expr_text[len(match_number.group(0)):]]
|
|
642
|
+
return [{'number': number}, expr_text[len(match_number.group(0)):]]
|
|
610
643
|
|
|
611
|
-
# String?
|
|
612
|
-
match_string = _R_EXPR_STRING.match(expr_text)
|
|
644
|
+
# String? '\''
|
|
645
|
+
match_string = _R_EXPR_STRING.match(expr_text) if c == "'" else None
|
|
613
646
|
if match_string:
|
|
614
647
|
string = _R_EXPR_STRING_ESCAPES.sub(_replace_string_escape, match_string.group(1))
|
|
615
|
-
|
|
616
|
-
return [expr, expr_text[len(match_string.group(0)):]]
|
|
648
|
+
return [{'string': string}, expr_text[len(match_string.group(0)):]]
|
|
617
649
|
|
|
618
|
-
# String (double quotes)?
|
|
619
|
-
match_string_double = _R_EXPR_STRING_DOUBLE.match(expr_text)
|
|
650
|
+
# String (double quotes)? '"'
|
|
651
|
+
match_string_double = _R_EXPR_STRING_DOUBLE.match(expr_text) if c == '"' else None
|
|
620
652
|
if match_string_double:
|
|
621
653
|
string = _R_EXPR_STRING_ESCAPES.sub(_replace_string_escape, match_string_double.group(1))
|
|
622
|
-
|
|
623
|
-
return [expr, expr_text[len(match_string_double.group(0)):]]
|
|
654
|
+
return [{'string': string}, expr_text[len(match_string_double.group(0)):]]
|
|
624
655
|
|
|
625
|
-
# Unary operator?
|
|
626
|
-
match_unary = _R_EXPR_UNARY_OP.match(expr_text)
|
|
656
|
+
# Unary operator? '!', '-', '~'
|
|
657
|
+
match_unary = _R_EXPR_UNARY_OP.match(expr_text) if c in '!-~' else None
|
|
627
658
|
if match_unary:
|
|
628
659
|
unary_text = expr_text[len(match_unary.group(0)):]
|
|
629
660
|
expr, next_text = _parse_unary_expression(unary_text, array_literals)
|
|
630
|
-
|
|
631
|
-
return [unary_expr, next_text]
|
|
661
|
+
return [{'unary': {'op': match_unary.group(1), 'expr': expr}}, next_text]
|
|
632
662
|
|
|
633
|
-
# Function?
|
|
634
|
-
|
|
663
|
+
# Function call? identifier followed by '('
|
|
664
|
+
is_ident = c.isalpha() or c == '_'
|
|
665
|
+
match_function_open = _R_EXPR_FUNCTION_OPEN.match(expr_text) if is_ident else None
|
|
635
666
|
if match_function_open:
|
|
636
667
|
arg_text = expr_text[len(match_function_open.group(0)):]
|
|
637
668
|
args = []
|
|
@@ -650,15 +681,19 @@ def _parse_unary_expression(expr_text, array_literals):
|
|
|
650
681
|
arg_text = arg_text[len(match_function_separator.group(0)):]
|
|
651
682
|
|
|
652
683
|
# Get the argument
|
|
653
|
-
arg_expr, next_arg_text = _parse_binary_expression(arg_text,
|
|
684
|
+
arg_expr, next_arg_text = _parse_binary_expression(arg_text, array_literals)
|
|
654
685
|
args.append(arg_expr)
|
|
655
686
|
arg_text = next_arg_text
|
|
656
687
|
|
|
657
|
-
|
|
658
|
-
return [fn_expr, arg_text]
|
|
688
|
+
return [{'function': {'name': match_function_open.group(1), 'args': args}}, arg_text]
|
|
659
689
|
|
|
660
|
-
#
|
|
661
|
-
|
|
690
|
+
# Variable
|
|
691
|
+
match_variable = _R_EXPR_VARIABLE.match(expr_text) if is_ident else None
|
|
692
|
+
if match_variable:
|
|
693
|
+
return [{'variable': match_variable.group(1)}, expr_text[len(match_variable.group(0)):]]
|
|
694
|
+
|
|
695
|
+
# Object creation? '{'
|
|
696
|
+
match_object_open = _R_EXPR_OBJECT_OPEN.match(expr_text) if c == '{' else None
|
|
662
697
|
if match_object_open:
|
|
663
698
|
arg_text = expr_text[len(match_object_open.group(0)):]
|
|
664
699
|
args = []
|
|
@@ -677,7 +712,7 @@ def _parse_unary_expression(expr_text, array_literals):
|
|
|
677
712
|
arg_text = arg_text[len(match_object_separator.group(0)):]
|
|
678
713
|
|
|
679
714
|
# Get the key
|
|
680
|
-
arg_key, arg_text = _parse_binary_expression(arg_text,
|
|
715
|
+
arg_key, arg_text = _parse_binary_expression(arg_text, array_literals)
|
|
681
716
|
args.append(arg_key)
|
|
682
717
|
|
|
683
718
|
# Key/value separator
|
|
@@ -687,58 +722,46 @@ def _parse_unary_expression(expr_text, array_literals):
|
|
|
687
722
|
arg_text = arg_text[len(match_object_separator_key.group(0)):]
|
|
688
723
|
|
|
689
724
|
# Get the value
|
|
690
|
-
arg_value, arg_text = _parse_binary_expression(arg_text,
|
|
725
|
+
arg_value, arg_text = _parse_binary_expression(arg_text, array_literals)
|
|
691
726
|
args.append(arg_value)
|
|
692
727
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
if
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
if
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
fn_expr = {'function': {'name': 'arrayNew', 'args': args}}
|
|
721
|
-
return [fn_expr, arg_text]
|
|
722
|
-
|
|
723
|
-
# Variable?
|
|
724
|
-
match_variable = _R_EXPR_VARIABLE.match(expr_text)
|
|
725
|
-
if match_variable:
|
|
726
|
-
expr = {'variable': match_variable.group(1)}
|
|
727
|
-
return [expr, expr_text[len(match_variable.group(0)):]]
|
|
728
|
+
return [{'function': {'name': 'objectNew', 'args': args}}, arg_text]
|
|
729
|
+
|
|
730
|
+
# Array creation? '['
|
|
731
|
+
match_array_open = _R_EXPR_ARRAY_OPEN.match(expr_text) if c == '[' and array_literals else None
|
|
732
|
+
if match_array_open:
|
|
733
|
+
arg_text = expr_text[len(match_array_open.group(0)):]
|
|
734
|
+
args = []
|
|
735
|
+
while True:
|
|
736
|
+
# Array close?
|
|
737
|
+
match_array_close = _R_EXPR_ARRAY_CLOSE.match(arg_text)
|
|
738
|
+
if match_array_close:
|
|
739
|
+
arg_text = arg_text[len(match_array_close.group(0)):]
|
|
740
|
+
break
|
|
741
|
+
|
|
742
|
+
# Array key separator
|
|
743
|
+
if args:
|
|
744
|
+
match_array_separator = _R_EXPR_ARRAY_SEPARATOR.match(arg_text)
|
|
745
|
+
if match_array_separator is None:
|
|
746
|
+
raise BareScriptParserError('Syntax error', arg_text, 1, None, None)
|
|
747
|
+
arg_text = arg_text[len(match_array_separator.group(0)):]
|
|
748
|
+
|
|
749
|
+
# Get the value
|
|
750
|
+
arg_value, arg_text = _parse_binary_expression(arg_text, array_literals)
|
|
751
|
+
args.append(arg_value)
|
|
752
|
+
|
|
753
|
+
return [{'function': {'name': 'arrayNew', 'args': args}}, arg_text]
|
|
728
754
|
|
|
729
|
-
# Variable (brackets)?
|
|
730
|
-
if not array_literals
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
expr = {'variable': variable_name}
|
|
735
|
-
return [expr, expr_text[len(match_variable_ex.group(0)):]]
|
|
755
|
+
# Variable (brackets)? '['
|
|
756
|
+
match_variable_ex = _R_EXPR_VARIABLE_EX.match(expr_text) if c == '[' and not array_literals else None
|
|
757
|
+
if match_variable_ex:
|
|
758
|
+
variable_name = _R_EXPR_VARIABLE_EX_ESCAPE.sub('\\1', match_variable_ex.group(1))
|
|
759
|
+
return [{'variable': variable_name}, expr_text[len(match_variable_ex.group(0)):]]
|
|
736
760
|
|
|
737
761
|
raise BareScriptParserError('Syntax error', expr_text, 1, None, None)
|
|
738
762
|
|
|
739
763
|
|
|
740
764
|
# BareScript expression regex
|
|
741
|
-
_R_EXPR_COMMENT = re.compile(r'^\s*#.*$')
|
|
742
765
|
_R_EXPR_BINARY_OP = re.compile(r'^\s*(\*\*|\*|\/|%|\+|-|<<|>>|<=|<|>=|>|==|!=|&&|\|\||&|\^|\|)')
|
|
743
766
|
_R_EXPR_UNARY_OP = re.compile(r'^\s*(!|-|~)')
|
|
744
767
|
_R_EXPR_FUNCTION_OPEN = re.compile(r'^\s*([A-Za-z_]\w+)\s*\(')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|