bare-script 4.1.0__tar.gz → 4.1.1__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.
Files changed (45) hide show
  1. {bare_script-4.1.0/src/bare_script.egg-info → bare_script-4.1.1}/PKG-INFO +1 -1
  2. {bare_script-4.1.0 → bare_script-4.1.1}/setup.cfg +1 -1
  3. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/__init__.py +1 -0
  4. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/runtime.py +113 -80
  5. bare_script-4.1.1/src/bare_script/runtime_c.c +1900 -0
  6. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/value.py +56 -37
  7. {bare_script-4.1.0 → bare_script-4.1.1/src/bare_script.egg-info}/PKG-INFO +1 -1
  8. bare_script-4.1.0/src/bare_script/runtime_c.c +0 -1693
  9. {bare_script-4.1.0 → bare_script-4.1.1}/LICENSE +0 -0
  10. {bare_script-4.1.0 → bare_script-4.1.1}/README.md +0 -0
  11. {bare_script-4.1.0 → bare_script-4.1.1}/pyproject.toml +0 -0
  12. {bare_script-4.1.0 → bare_script-4.1.1}/setup.py +0 -0
  13. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/__main__.py +0 -0
  14. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/bare.py +0 -0
  15. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/__init__.py +0 -0
  16. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/args.bare +0 -0
  17. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/baredoc.bare +0 -0
  18. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/baredocCLI.bare +0 -0
  19. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/data.bare +0 -0
  20. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/dataLineChart.bare +0 -0
  21. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/dataTable.bare +0 -0
  22. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/dataUtil.bare +0 -0
  23. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/diff.bare +0 -0
  24. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/draw.bare +0 -0
  25. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/elementModel.bare +0 -0
  26. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/forms.bare +0 -0
  27. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/markdown.bare +0 -0
  28. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/markdownElements.bare +0 -0
  29. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/markdownHighlight.bare +0 -0
  30. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/markdownParser.bare +0 -0
  31. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/markdownUp.bare +0 -0
  32. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/pager.bare +0 -0
  33. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/qrcode.bare +0 -0
  34. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/schemaDoc.bare +0 -0
  35. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/unittest.bare +0 -0
  36. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/include/unittestMock.bare +0 -0
  37. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/library.py +0 -0
  38. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/model.py +0 -0
  39. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/options.py +0 -0
  40. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script/parser.py +0 -0
  41. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script.egg-info/SOURCES.txt +0 -0
  42. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script.egg-info/dependency_links.txt +0 -0
  43. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script.egg-info/entry_points.txt +0 -0
  44. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script.egg-info/requires.txt +0 -0
  45. {bare_script-4.1.0 → bare_script-4.1.1}/src/bare_script.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bare-script
3
- Version: 4.1.0
3
+ Version: 4.1.1
4
4
  Summary: bare-script
5
5
  Home-page: https://github.com/craigahobbs/bare-script
6
6
  Author: Craig A. Hobbs
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = bare-script
3
- version = 4.1.0
3
+ version = 4.1.1
4
4
  url = https://github.com/craigahobbs/bare-script
5
5
  author = Craig A. Hobbs
6
6
  author_email = craigahobbs@gmail.com
@@ -28,6 +28,7 @@ from .parser import \
28
28
 
29
29
  from .runtime import \
30
30
  BareScriptRuntimeError
31
+
31
32
  if not _os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
32
33
  try:
33
34
  from .runtime_c import evaluate_expression, execute_script
@@ -58,6 +58,13 @@ def execute_script(script, options=None):
58
58
 
59
59
  def _execute_script_helper(script, statements, options, locals_):
60
60
  globals_ = options['globals']
61
+ max_statements = options.get('maxStatements', DEFAULT_MAX_STATEMENTS)
62
+ options.setdefault('statementCount', 0)
63
+
64
+ # Coverage configuration is invariant across this helper invocation
65
+ coverage_global = globals_.get(SYSTEM_GLOBAL_COVERAGE_NAME)
66
+ has_coverage = coverage_global is not None and isinstance(coverage_global, dict) and \
67
+ coverage_global.get('enabled') and not script.get('system')
61
68
 
62
69
  # Iterate each script statement
63
70
  label_indexes = None
@@ -65,25 +72,22 @@ def _execute_script_helper(script, statements, options, locals_):
65
72
  ix_statement = 0
66
73
  while ix_statement < statements_length:
67
74
  statement = statements[ix_statement]
68
- statement_key = next(iter(statement.keys()))
69
75
 
70
76
  # Increment the statement counter
71
- options['statementCount'] = options.get('statementCount', 0) + 1
72
- max_statements = options.get('maxStatements', DEFAULT_MAX_STATEMENTS)
77
+ options['statementCount'] += 1
73
78
  if max_statements > 0 and options['statementCount'] > max_statements:
74
79
  raise BareScriptRuntimeError(script, statement, f'Exceeded maximum script statements ({max_statements})')
75
80
 
76
81
  # Record the statement coverage
77
- coverage_global = globals_.get(SYSTEM_GLOBAL_COVERAGE_NAME)
78
- has_coverage = coverage_global is not None and isinstance(coverage_global, dict) and \
79
- coverage_global.get('enabled') and not script.get('system')
80
82
  if has_coverage:
83
+ statement_key = next(iter(statement.keys()))
81
84
  _record_statement_coverage(script, statement, statement_key, coverage_global)
82
85
 
83
86
  # Expression?
84
- if statement_key == 'expr':
85
- expr_value = evaluate_expression(statement['expr']['expr'], options, locals_, False, script, statement)
86
- expr_name = statement['expr'].get('name')
87
+ if 'expr' in statement:
88
+ stmt_expr = statement['expr']
89
+ expr_value = evaluate_expression(stmt_expr['expr'], options, locals_, False, script, statement)
90
+ expr_name = stmt_expr.get('name')
87
91
  if expr_name is not None:
88
92
  if locals_ is not None:
89
93
  locals_[expr_name] = expr_value
@@ -91,24 +95,25 @@ def _execute_script_helper(script, statements, options, locals_):
91
95
  globals_[expr_name] = expr_value
92
96
 
93
97
  # Jump?
94
- elif statement_key == 'jump':
98
+ elif 'jump' in statement:
99
+ stmt_jump = statement['jump']
95
100
  # Evaluate the expression (if any)
96
- if 'expr' not in statement['jump'] or \
97
- value_boolean(evaluate_expression(statement['jump']['expr'], options, locals_, False, script, statement)):
101
+ if 'expr' not in stmt_jump or \
102
+ value_boolean(evaluate_expression(stmt_jump['expr'], options, locals_, False, script, statement)):
98
103
  # Find the label
99
- if label_indexes is not None and statement['jump']['label'] in label_indexes:
100
- ix_statement = label_indexes[statement['jump']['label']]
104
+ jump_label = stmt_jump['label']
105
+ if label_indexes is not None and jump_label in label_indexes:
106
+ ix_statement = label_indexes[jump_label]
101
107
  else:
102
- jump_label = statement['jump']['label']
103
108
  ix_label = next(
104
109
  (ix_stmt for ix_stmt, stmt in enumerate(statements) if 'label' in stmt and stmt['label']['name'] == jump_label),
105
110
  -1
106
111
  )
107
112
  if ix_label == -1:
108
- raise BareScriptRuntimeError(script, statement, f"Unknown jump label \"{statement['jump']['label']}\"")
113
+ raise BareScriptRuntimeError(script, statement, f"Unknown jump label \"{jump_label}\"")
109
114
  if label_indexes is None:
110
115
  label_indexes = {}
111
- label_indexes[statement['jump']['label']] = ix_label
116
+ label_indexes[jump_label] = ix_label
112
117
  ix_statement = ix_label
113
118
 
114
119
  # Record the label statement coverage
@@ -118,17 +123,19 @@ def _execute_script_helper(script, statements, options, locals_):
118
123
  _record_statement_coverage(script, label_statement, label_statement_key, coverage_global)
119
124
 
120
125
  # Return?
121
- elif statement_key == 'return':
122
- if 'expr' in statement['return']:
123
- return evaluate_expression(statement['return']['expr'], options, locals_, False, script, statement)
126
+ elif 'return' in statement:
127
+ stmt_return = statement['return']
128
+ if 'expr' in stmt_return:
129
+ return evaluate_expression(stmt_return['expr'], options, locals_, False, script, statement)
124
130
  return None
125
131
 
126
132
  # Function?
127
- elif statement_key == 'function':
128
- globals_[statement['function']['name']] = functools.partial(_script_function, script, statement['function'])
133
+ elif 'function' in statement:
134
+ stmt_function = statement['function']
135
+ globals_[stmt_function['name']] = functools.partial(_script_function, script, stmt_function)
129
136
 
130
137
  # Include?
131
- elif statement_key == 'include':
138
+ elif 'include' in statement:
132
139
  system_prefix = options.get('systemPrefix')
133
140
  fetch_fn = options.get('fetchFn')
134
141
  log_fn = options.get('logFn')
@@ -243,50 +250,56 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
243
250
  :raises BareScriptRuntimeError: A script runtime error occurred
244
251
  """
245
252
 
246
- expr_key, = expr.keys()
247
253
  globals_ = options.get('globals') if options is not None else None
248
254
 
249
255
  # Number
250
- if expr_key == 'number':
256
+ if 'number' in expr:
251
257
  return expr['number']
252
258
 
253
259
  # String
254
- if expr_key == 'string':
260
+ if 'string' in expr:
255
261
  return expr['string']
256
262
 
257
263
  # Variable
258
- if expr_key == 'variable':
264
+ if 'variable' in expr:
265
+ variable = expr['variable']
266
+
259
267
  # Keywords
260
- if expr['variable'] == 'null':
268
+ if variable == 'null':
261
269
  return None
262
- if expr['variable'] == 'false':
270
+ if variable == 'false':
263
271
  return False
264
- if expr['variable'] == 'true':
272
+ if variable == 'true':
265
273
  return True
266
274
 
267
275
  # Get the local or global variable value or None if undefined
268
- if locals_ is not None and expr['variable'] in locals_:
269
- return locals_[expr['variable']]
276
+ if locals_ is not None and variable in locals_:
277
+ return locals_[variable]
270
278
  else:
271
- return globals_.get(expr['variable']) if globals_ is not None else None
279
+ return globals_.get(variable) if globals_ is not None else None
272
280
 
273
281
  # Function
274
- if expr_key == 'function':
282
+ if 'function' in expr:
283
+ func = expr['function']
284
+
275
285
  # "if" built-in function?
276
- func_name = expr['function']['name']
286
+ func_name = func['name']
277
287
  if func_name == 'if':
278
- args_expr = expr['function'].get('args', ())
288
+ args_expr = func.get('args', ())
279
289
  args_expr_length = len(args_expr)
280
290
  value_expr = args_expr[0] if args_expr_length >= 1 else None
281
291
  true_expr = args_expr[1] if args_expr_length >= 2 else None
282
292
  false_expr = args_expr[2] if args_expr_length >= 3 else None
283
- value = evaluate_expression(value_expr, options, locals_, builtins, script, statement) if value_expr else False
293
+ value = evaluate_expression(value_expr, options, locals_, builtins, script, statement) \
294
+ if value_expr is not None else False
284
295
  result_expr = true_expr if value_boolean(value) else false_expr
285
- return evaluate_expression(result_expr, options, locals_, builtins, script, statement) if result_expr else None
296
+ return evaluate_expression(result_expr, options, locals_, builtins, script, statement) \
297
+ if result_expr is not None else None
286
298
 
287
299
  # Compute the function arguments
288
- func_args = [evaluate_expression(arg, options, locals_, builtins, script, statement) for arg in expr['function']['args']] \
289
- if 'args' in expr['function'] else None
300
+ args_expr = func.get('args')
301
+ func_args = [evaluate_expression(arg, options, locals_, builtins, script, statement) for arg in args_expr] \
302
+ if args_expr is not None else None
290
303
 
291
304
  # Global/local function?
292
305
  if locals_ is not None and func_name in locals_:
@@ -304,7 +317,10 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
304
317
  except Exception as error:
305
318
  # Log and return null
306
319
  if options is not None and 'logFn' in options and options.get('debug'):
307
- options['logFn'](f'BareScript: Function "{func_name}" failed with error: {error}')
320
+ error_message = BareScriptRuntimeError(
321
+ script, statement, f'BareScript: Function "{func_name}" failed with error: {error}'
322
+ )
323
+ options['logFn'](str(error_message))
308
324
  if isinstance(error, ValueArgsError):
309
325
  return error.return_value
310
326
  return None
@@ -312,54 +328,57 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
312
328
  raise BareScriptRuntimeError(script, statement, f'Undefined function "{func_name}"')
313
329
 
314
330
  # Binary expression
315
- if expr_key == 'binary':
316
- bin_op = expr['binary']['op']
317
- left_value = evaluate_expression(expr['binary']['left'], options, locals_, builtins, script, statement)
331
+ if 'binary' in expr:
332
+ binary = expr['binary']
333
+ bin_op = binary['op']
334
+ left_value = evaluate_expression(binary['left'], options, locals_, builtins, script, statement)
318
335
 
319
336
  # Short-circuiting "and" binary operator
320
337
  if bin_op == '&&':
321
338
  if not value_boolean(left_value):
322
339
  return left_value
323
- return evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
340
+ return evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
324
341
 
325
342
  # Short-circuiting "or" binary operator
326
343
  elif bin_op == '||':
327
344
  if value_boolean(left_value):
328
345
  return left_value
329
- return evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
346
+ return evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
330
347
 
331
348
  # Non-short-circuiting binary operators
332
- right_value = evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
349
+ right_value = evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
350
+ left_type = type(left_value)
351
+ right_type = type(right_value)
333
352
  if bin_op == '+':
334
353
  # number + number
335
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
336
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
354
+ if ((left_type is int or left_type is float) and
355
+ (right_type is int or right_type is float)):
337
356
  return left_value + right_value
338
357
 
339
358
  # string + string
340
- elif isinstance(left_value, str) and isinstance(right_value, str):
359
+ elif left_type is str and right_type is str:
341
360
  return left_value + right_value
342
361
 
343
362
  # string + <any>
344
- elif isinstance(left_value, str):
363
+ elif left_type is str:
345
364
  return left_value + value_string(right_value)
346
- elif isinstance(right_value, str):
365
+ elif right_type is str:
347
366
  return value_string(left_value) + right_value
348
367
 
349
368
  # datetime + number
350
369
  elif (isinstance(left_value, datetime.date) and
351
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
370
+ (right_type is int or right_type is float)):
352
371
  left_dt = value_normalize_datetime(left_value)
353
372
  return left_dt + datetime.timedelta(milliseconds=right_value)
354
- elif (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
373
+ elif ((left_type is int or left_type is float) and
355
374
  isinstance(right_value, datetime.date)):
356
375
  right_dt = value_normalize_datetime(right_value)
357
376
  return right_dt + datetime.timedelta(milliseconds=left_value)
358
377
 
359
378
  elif bin_op == '-':
360
379
  # number - number
361
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
362
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
380
+ if ((left_type is int or left_type is float) and
381
+ (right_type is int or right_type is float)):
363
382
  return left_value - right_value
364
383
 
365
384
  # datetime - datetime
@@ -370,90 +389,104 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
370
389
 
371
390
  elif bin_op == '*':
372
391
  # number * number
373
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
374
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
392
+ if ((left_type is int or left_type is float) and
393
+ (right_type is int or right_type is float)):
375
394
  return left_value * right_value
376
395
 
377
396
  elif bin_op == '/':
378
397
  # number / number
379
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
380
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
398
+ if ((left_type is int or left_type is float) and
399
+ (right_type is int or right_type is float)):
381
400
  return left_value / right_value
382
401
 
383
402
  elif bin_op == '==':
403
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
404
+ return left_value == right_value
384
405
  return value_compare(left_value, right_value) == 0
385
406
 
386
407
  elif bin_op == '!=':
408
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
409
+ return left_value != right_value
387
410
  return value_compare(left_value, right_value) != 0
388
411
 
389
412
  elif bin_op == '<=':
413
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
414
+ return left_value <= right_value
390
415
  return value_compare(left_value, right_value) <= 0
391
416
 
392
417
  elif bin_op == '<':
418
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
419
+ return left_value < right_value
393
420
  return value_compare(left_value, right_value) < 0
394
421
 
395
422
  elif bin_op == '>=':
423
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
424
+ return left_value >= right_value
396
425
  return value_compare(left_value, right_value) >= 0
397
426
 
398
427
  elif bin_op == '>':
428
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
429
+ return left_value > right_value
399
430
  return value_compare(left_value, right_value) > 0
400
431
 
401
432
  elif bin_op == '%':
402
433
  # number % number
403
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
404
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
434
+ if ((left_type is int or left_type is float) and
435
+ (right_type is int or right_type is float)):
405
436
  return left_value % right_value
406
437
 
407
438
  elif bin_op == '**':
408
439
  # number ** number
409
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
410
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
440
+ if ((left_type is int or left_type is float) and
441
+ (right_type is int or right_type is float)):
411
442
  return left_value ** right_value
412
443
 
413
444
  elif bin_op == '&':
414
445
  # int & int
415
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and int(left_value) == left_value and
416
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool) and int(right_value) == right_value):
446
+ if ((left_type is int or left_type is float) and int(left_value) == left_value and
447
+ (right_type is int or right_type is float) and int(right_value) == right_value):
417
448
  return int(left_value) & int(right_value)
418
449
 
419
450
  elif bin_op == '|':
420
451
  # int & int
421
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and int(left_value) == left_value and
422
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool) and int(right_value) == right_value):
452
+ if ((left_type is int or left_type is float) and int(left_value) == left_value and
453
+ (right_type is int or right_type is float) and int(right_value) == right_value):
423
454
  return int(left_value) | int(right_value)
424
455
 
425
456
  elif bin_op == '^':
426
457
  # int & int
427
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and int(left_value) == left_value and
428
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool) and int(right_value) == right_value):
458
+ if ((left_type is int or left_type is float) and int(left_value) == left_value and
459
+ (right_type is int or right_type is float) and int(right_value) == right_value):
429
460
  return int(left_value) ^ int(right_value)
430
461
 
431
462
  elif bin_op == '<<':
432
463
  # int & int
433
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and int(left_value) == left_value and
434
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool) and int(right_value) == right_value):
464
+ if ((left_type is int or left_type is float) and int(left_value) == left_value and
465
+ (right_type is int or right_type is float) and int(right_value) == right_value):
435
466
  return int(left_value) << int(right_value)
436
467
 
437
468
  else: # bin_op == '>>':
438
469
  # int & int
439
- if (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and int(left_value) == left_value and
440
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool) and int(right_value) == right_value):
470
+ if ((left_type is int or left_type is float) and int(left_value) == left_value and
471
+ (right_type is int or right_type is float) and int(right_value) == right_value):
441
472
  return int(left_value) >> int(right_value)
442
473
 
443
474
  # Invalid operation values
444
475
  return None
445
476
 
446
477
  # Unary expression
447
- if expr_key == 'unary':
448
- unary_op = expr['unary']['op']
449
- value = evaluate_expression(expr['unary']['expr'], options, locals_, builtins, script, statement)
478
+ if 'unary' in expr:
479
+ unary = expr['unary']
480
+ unary_op = unary['op']
481
+ value = evaluate_expression(unary['expr'], options, locals_, builtins, script, statement)
450
482
  if unary_op == '!':
451
483
  return not value_boolean(value)
452
- elif unary_op == '-':
453
- if isinstance(value, (int, float)) and not isinstance(value, bool):
484
+ val_type = type(value)
485
+ if unary_op == '-':
486
+ if val_type is int or val_type is float:
454
487
  return -value
455
488
  else: # unary_op == '~':
456
- if isinstance(value, (int, float)) and not isinstance(value, bool) and int(value) == value:
489
+ if (val_type is int or val_type is float) and int(value) == value:
457
490
  return ~int(value)
458
491
 
459
492
  # Invalid operation value