bare-script 4.1.0__tar.gz → 4.1.2__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.2}/PKG-INFO +1 -1
  2. {bare_script-4.1.0 → bare_script-4.1.2}/setup.cfg +1 -1
  3. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/__init__.py +3 -2
  4. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/bare.py +2 -2
  5. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/library.py +2 -2
  6. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/runtime.py +133 -96
  7. bare_script-4.1.2/src/bare_script/runtime_c.c +1916 -0
  8. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/value.py +56 -37
  9. {bare_script-4.1.0 → bare_script-4.1.2/src/bare_script.egg-info}/PKG-INFO +1 -1
  10. bare_script-4.1.0/src/bare_script/runtime_c.c +0 -1693
  11. {bare_script-4.1.0 → bare_script-4.1.2}/LICENSE +0 -0
  12. {bare_script-4.1.0 → bare_script-4.1.2}/README.md +0 -0
  13. {bare_script-4.1.0 → bare_script-4.1.2}/pyproject.toml +0 -0
  14. {bare_script-4.1.0 → bare_script-4.1.2}/setup.py +0 -0
  15. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/__main__.py +0 -0
  16. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/__init__.py +0 -0
  17. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/args.bare +0 -0
  18. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/baredoc.bare +0 -0
  19. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/baredocCLI.bare +0 -0
  20. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/data.bare +0 -0
  21. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/dataLineChart.bare +0 -0
  22. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/dataTable.bare +0 -0
  23. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/dataUtil.bare +0 -0
  24. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/diff.bare +0 -0
  25. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/draw.bare +0 -0
  26. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/elementModel.bare +0 -0
  27. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/forms.bare +0 -0
  28. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/markdown.bare +0 -0
  29. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/markdownElements.bare +0 -0
  30. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/markdownHighlight.bare +0 -0
  31. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/markdownParser.bare +0 -0
  32. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/markdownUp.bare +0 -0
  33. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/pager.bare +0 -0
  34. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/qrcode.bare +0 -0
  35. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/schemaDoc.bare +0 -0
  36. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/unittest.bare +0 -0
  37. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/include/unittestMock.bare +0 -0
  38. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/model.py +0 -0
  39. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/options.py +0 -0
  40. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script/parser.py +0 -0
  41. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script.egg-info/SOURCES.txt +0 -0
  42. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script.egg-info/dependency_links.txt +0 -0
  43. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script.egg-info/entry_points.txt +0 -0
  44. {bare_script-4.1.0 → bare_script-4.1.2}/src/bare_script.egg-info/requires.txt +0 -0
  45. {bare_script-4.1.0 → bare_script-4.1.2}/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.2
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.2
4
4
  url = https://github.com/craigahobbs/bare-script
5
5
  author = Craig A. Hobbs
6
6
  author_email = craigahobbs@gmail.com
@@ -5,7 +5,7 @@
5
5
  bare-script package
6
6
  """
7
7
 
8
- import os as _os
8
+ import os
9
9
 
10
10
  from .model import \
11
11
  lint_script, \
@@ -28,7 +28,8 @@ from .parser import \
28
28
 
29
29
  from .runtime import \
30
30
  BareScriptRuntimeError
31
- if not _os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
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
34
35
  except ImportError:
@@ -7,7 +7,7 @@ bare-script command-line interface (CLI)
7
7
 
8
8
  import argparse
9
9
  from functools import partial
10
- import os as _os
10
+ import os
11
11
  import sys
12
12
  import time
13
13
 
@@ -16,7 +16,7 @@ from .options import FETCH_SYSTEM_PREFIX, fetch_read_write, fetch_system, log_st
16
16
  from .parser import parse_expression, parse_script
17
17
  from .runtime import SYSTEM_GLOBAL_INCLUDES_NAME
18
18
  from .value import value_boolean
19
- if not _os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
19
+ if not os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
20
20
  try:
21
21
  from .runtime_c import evaluate_expression, execute_script
22
22
  except ImportError:
@@ -11,7 +11,7 @@ import functools
11
11
  import importlib
12
12
  import json
13
13
  import math
14
- import os as _os
14
+ import os
15
15
  import random
16
16
  import re
17
17
  import urllib
@@ -28,7 +28,7 @@ from .value import R_NUMBER_CLEANUP, ValueArgsError, value_args_model, value_arg
28
28
  # Helper to dynamically import evaluate_expression to avoid the circular dependency
29
29
  def _import_evaluate_expression():
30
30
  if not _EVALUATE_EXPRESSION:
31
- if not _os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
31
+ if not os.environ.get('BARESCRIPT_RUNTIME_PY'): # pragma: no cover
32
32
  try:
33
33
  _EVALUATE_EXPRESSION.append(importlib.import_module('bare_script.runtime_c').evaluate_expression)
34
34
  except (ImportError, AttributeError):
@@ -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')
@@ -217,13 +224,17 @@ def _script_function(script, function, args, options):
217
224
  if func_args is not None:
218
225
  args_length = len(args)
219
226
  func_args_length = len(func_args)
220
- ix_arg_last = function.get('lastArgArray', None) and (func_args_length - 1)
221
- for ix_arg in range(func_args_length):
222
- arg_name = func_args[ix_arg]
223
- if ix_arg < args_length:
224
- func_locals[arg_name] = args[ix_arg] if ix_arg != ix_arg_last else args[ix_arg:]
225
- else:
226
- func_locals[arg_name] = [] if ix_arg == ix_arg_last else None
227
+ if function.get('lastArgArray'):
228
+ ix_arg_last = func_args_length - 1
229
+ for ix_arg in range(func_args_length):
230
+ arg_name = func_args[ix_arg]
231
+ if ix_arg < args_length:
232
+ func_locals[arg_name] = args[ix_arg] if ix_arg != ix_arg_last else args[ix_arg:]
233
+ else:
234
+ func_locals[arg_name] = [] if ix_arg == ix_arg_last else None
235
+ else:
236
+ for ix_arg in range(func_args_length):
237
+ func_locals[func_args[ix_arg]] = args[ix_arg] if ix_arg < args_length else None
227
238
  return _execute_script_helper(script, function['statements'], options, func_locals)
228
239
 
229
240
 
@@ -243,50 +254,56 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
243
254
  :raises BareScriptRuntimeError: A script runtime error occurred
244
255
  """
245
256
 
246
- expr_key, = expr.keys()
247
257
  globals_ = options.get('globals') if options is not None else None
248
258
 
249
259
  # Number
250
- if expr_key == 'number':
260
+ if 'number' in expr:
251
261
  return expr['number']
252
262
 
253
263
  # String
254
- if expr_key == 'string':
264
+ if 'string' in expr:
255
265
  return expr['string']
256
266
 
257
267
  # Variable
258
- if expr_key == 'variable':
268
+ if 'variable' in expr:
269
+ variable = expr['variable']
270
+
259
271
  # Keywords
260
- if expr['variable'] == 'null':
272
+ if variable == 'null':
261
273
  return None
262
- if expr['variable'] == 'false':
274
+ if variable == 'false':
263
275
  return False
264
- if expr['variable'] == 'true':
276
+ if variable == 'true':
265
277
  return True
266
278
 
267
279
  # 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']]
280
+ if locals_ is not None and variable in locals_:
281
+ return locals_[variable]
270
282
  else:
271
- return globals_.get(expr['variable']) if globals_ is not None else None
283
+ return globals_.get(variable) if globals_ is not None else None
272
284
 
273
285
  # Function
274
- if expr_key == 'function':
286
+ if 'function' in expr:
287
+ func = expr['function']
288
+
275
289
  # "if" built-in function?
276
- func_name = expr['function']['name']
290
+ func_name = func['name']
277
291
  if func_name == 'if':
278
- args_expr = expr['function'].get('args', ())
292
+ args_expr = func.get('args', ())
279
293
  args_expr_length = len(args_expr)
280
294
  value_expr = args_expr[0] if args_expr_length >= 1 else None
281
295
  true_expr = args_expr[1] if args_expr_length >= 2 else None
282
296
  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
297
+ value = evaluate_expression(value_expr, options, locals_, builtins, script, statement) \
298
+ if value_expr is not None else False
284
299
  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
300
+ return evaluate_expression(result_expr, options, locals_, builtins, script, statement) \
301
+ if result_expr is not None else None
286
302
 
287
303
  # 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
304
+ args_expr = func.get('args')
305
+ func_args = [evaluate_expression(arg, options, locals_, builtins, script, statement) for arg in args_expr] \
306
+ if args_expr is not None else None
290
307
 
291
308
  # Global/local function?
292
309
  if locals_ is not None and func_name in locals_:
@@ -304,7 +321,10 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
304
321
  except Exception as error:
305
322
  # Log and return null
306
323
  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}')
324
+ error_message = BareScriptRuntimeError(
325
+ script, statement, f'BareScript: Function "{func_name}" failed with error: {error}'
326
+ )
327
+ options['logFn'](str(error_message))
308
328
  if isinstance(error, ValueArgsError):
309
329
  return error.return_value
310
330
  return None
@@ -312,54 +332,57 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
312
332
  raise BareScriptRuntimeError(script, statement, f'Undefined function "{func_name}"')
313
333
 
314
334
  # 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)
335
+ if 'binary' in expr:
336
+ binary = expr['binary']
337
+ bin_op = binary['op']
338
+ left_value = evaluate_expression(binary['left'], options, locals_, builtins, script, statement)
318
339
 
319
340
  # Short-circuiting "and" binary operator
320
341
  if bin_op == '&&':
321
342
  if not value_boolean(left_value):
322
343
  return left_value
323
- return evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
344
+ return evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
324
345
 
325
346
  # Short-circuiting "or" binary operator
326
347
  elif bin_op == '||':
327
348
  if value_boolean(left_value):
328
349
  return left_value
329
- return evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
350
+ return evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
330
351
 
331
352
  # Non-short-circuiting binary operators
332
- right_value = evaluate_expression(expr['binary']['right'], options, locals_, builtins, script, statement)
353
+ right_value = evaluate_expression(binary['right'], options, locals_, builtins, script, statement)
354
+ left_type = type(left_value)
355
+ right_type = type(right_value)
333
356
  if bin_op == '+':
334
357
  # 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)):
358
+ if ((left_type is int or left_type is float) and
359
+ (right_type is int or right_type is float)):
337
360
  return left_value + right_value
338
361
 
339
362
  # string + string
340
- elif isinstance(left_value, str) and isinstance(right_value, str):
363
+ elif left_type is str and right_type is str:
341
364
  return left_value + right_value
342
365
 
343
366
  # string + <any>
344
- elif isinstance(left_value, str):
367
+ elif left_type is str:
345
368
  return left_value + value_string(right_value)
346
- elif isinstance(right_value, str):
369
+ elif right_type is str:
347
370
  return value_string(left_value) + right_value
348
371
 
349
372
  # datetime + number
350
373
  elif (isinstance(left_value, datetime.date) and
351
- isinstance(right_value, (int, float)) and not isinstance(right_value, bool)):
374
+ (right_type is int or right_type is float)):
352
375
  left_dt = value_normalize_datetime(left_value)
353
376
  return left_dt + datetime.timedelta(milliseconds=right_value)
354
- elif (isinstance(left_value, (int, float)) and not isinstance(left_value, bool) and
377
+ elif ((left_type is int or left_type is float) and
355
378
  isinstance(right_value, datetime.date)):
356
379
  right_dt = value_normalize_datetime(right_value)
357
380
  return right_dt + datetime.timedelta(milliseconds=left_value)
358
381
 
359
382
  elif bin_op == '-':
360
383
  # 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)):
384
+ if ((left_type is int or left_type is float) and
385
+ (right_type is int or right_type is float)):
363
386
  return left_value - right_value
364
387
 
365
388
  # datetime - datetime
@@ -370,90 +393,104 @@ def evaluate_expression(expr, options=None, locals_=None, builtins=True, script=
370
393
 
371
394
  elif bin_op == '*':
372
395
  # 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)):
396
+ if ((left_type is int or left_type is float) and
397
+ (right_type is int or right_type is float)):
375
398
  return left_value * right_value
376
399
 
377
400
  elif bin_op == '/':
378
401
  # 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)):
402
+ if ((left_type is int or left_type is float) and
403
+ (right_type is int or right_type is float)):
381
404
  return left_value / right_value
382
405
 
383
- elif bin_op == '==':
384
- return value_compare(left_value, right_value) == 0
385
-
386
- elif bin_op == '!=':
387
- return value_compare(left_value, right_value) != 0
406
+ elif bin_op == '<':
407
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
408
+ return left_value < right_value
409
+ return value_compare(left_value, right_value) < 0
388
410
 
389
411
  elif bin_op == '<=':
412
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
413
+ return left_value <= right_value
390
414
  return value_compare(left_value, right_value) <= 0
391
415
 
392
- elif bin_op == '<':
393
- return value_compare(left_value, right_value) < 0
416
+ elif bin_op == '>':
417
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
418
+ return left_value > right_value
419
+ return value_compare(left_value, right_value) > 0
394
420
 
395
421
  elif bin_op == '>=':
422
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
423
+ return left_value >= right_value
396
424
  return value_compare(left_value, right_value) >= 0
397
425
 
398
- elif bin_op == '>':
399
- return value_compare(left_value, right_value) > 0
426
+ elif bin_op == '==':
427
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
428
+ return left_value == right_value
429
+ return value_compare(left_value, right_value) == 0
430
+
431
+ elif bin_op == '!=':
432
+ if (left_type is int or left_type is float) and (right_type is int or right_type is float):
433
+ return left_value != right_value
434
+ return value_compare(left_value, right_value) != 0
400
435
 
401
436
  elif bin_op == '%':
402
437
  # 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)):
438
+ if ((left_type is int or left_type is float) and
439
+ (right_type is int or right_type is float)):
405
440
  return left_value % right_value
406
441
 
407
442
  elif bin_op == '**':
408
443
  # 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)):
444
+ if ((left_type is int or left_type is float) and
445
+ (right_type is int or right_type is float)):
411
446
  return left_value ** right_value
412
447
 
413
448
  elif bin_op == '&':
414
449
  # 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):
450
+ if ((left_type is int or (left_type is float and left_value.is_integer())) and
451
+ (right_type is int or (right_type is float and right_value.is_integer()))):
417
452
  return int(left_value) & int(right_value)
418
453
 
419
454
  elif bin_op == '|':
420
455
  # 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):
456
+ if ((left_type is int or (left_type is float and left_value.is_integer())) and
457
+ (right_type is int or (right_type is float and right_value.is_integer()))):
423
458
  return int(left_value) | int(right_value)
424
459
 
425
460
  elif bin_op == '^':
426
461
  # 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):
462
+ if ((left_type is int or (left_type is float and left_value.is_integer())) and
463
+ (right_type is int or (right_type is float and right_value.is_integer()))):
429
464
  return int(left_value) ^ int(right_value)
430
465
 
431
466
  elif bin_op == '<<':
432
467
  # 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):
468
+ if ((left_type is int or (left_type is float and left_value.is_integer())) and
469
+ (right_type is int or (right_type is float and right_value.is_integer()))):
435
470
  return int(left_value) << int(right_value)
436
471
 
437
472
  else: # bin_op == '>>':
438
473
  # 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):
474
+ if ((left_type is int or (left_type is float and left_value.is_integer())) and
475
+ (right_type is int or (right_type is float and right_value.is_integer()))):
441
476
  return int(left_value) >> int(right_value)
442
477
 
443
478
  # Invalid operation values
444
479
  return None
445
480
 
446
481
  # 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)
482
+ if 'unary' in expr:
483
+ unary = expr['unary']
484
+ unary_op = unary['op']
485
+ value = evaluate_expression(unary['expr'], options, locals_, builtins, script, statement)
450
486
  if unary_op == '!':
451
487
  return not value_boolean(value)
452
- elif unary_op == '-':
453
- if isinstance(value, (int, float)) and not isinstance(value, bool):
488
+ val_type = type(value)
489
+ if unary_op == '-':
490
+ if val_type is int or val_type is float:
454
491
  return -value
455
492
  else: # unary_op == '~':
456
- if isinstance(value, (int, float)) and not isinstance(value, bool) and int(value) == value:
493
+ if val_type is int or (val_type is float and value.is_integer()):
457
494
  return ~int(value)
458
495
 
459
496
  # Invalid operation value