Moved more stuff, can now parse all of common tests.

pull/1103/head
Jussi Pakkanen 8 years ago
parent 7e8872236d
commit c41805f012
  1. 18
      mesonast.py
  2. 54
      mesonbuild/astinterpreter.py
  3. 283
      mesonbuild/interpreter.py
  4. 287
      mesonbuild/interpreterbase.py

@ -24,8 +24,9 @@
# - reindent?
import mesonbuild.astinterpreter
import sys
from mesonbuild.mesonlib import MesonException
from mesonbuild import mlog
import sys, traceback
if __name__ == '__main__':
if len(sys.argv) == 1:
@ -33,4 +34,15 @@ if __name__ == '__main__':
else:
source_root = sys.argv[1]
ast = mesonbuild.astinterpreter.AstInterpreter(source_root, '')
ast.dump()
try:
ast.dump()
except Exception as e:
if isinstance(e, MesonException):
if hasattr(e, 'file') and hasattr(e, 'lineno') and hasattr(e, 'colno'):
mlog.log(mlog.red('\nMeson encountered an error in file %s, line %d, column %d:' % (e.file, e.lineno, e.colno)))
else:
mlog.log(mlog.red('\nMeson encountered an error:'))
mlog.log(e)
else:
traceback.print_exc()
sys.exit(1)

@ -34,22 +34,52 @@ class MockStaticLibrary(interpreterbase.InterpreterObject):
class MockSharedLibrary(interpreterbase.InterpreterObject):
pass
class MockCustomTarget(interpreterbase.InterpreterObject):
pass
class MockRunTarget(interpreterbase.InterpreterObject):
pass
class AstInterpreter(interpreterbase.InterpreterBase):
def __init__(self, source_root, subdir):
super().__init__(source_root, subdir)
self.funcs.update({'project' : self.func_do_nothing,
'test' : self.func_do_nothing,
'benchmark' : self.func_do_nothing,
'install_headers' : self.func_do_nothing,
'install_man' : self.func_do_nothing,
'install_data' : self.func_do_nothing,
'install_subdir' : self.func_do_nothing,
'configuration_data' : self.func_do_nothing,
'configure_file' : self.func_do_nothing,
'find_program' : self.func_do_nothing,
'include_directories' : self.func_do_nothing,
'add_global_arguments' : self.func_do_nothing,
'add_global_link_arguments' : self.func_do_nothing,
'add_project_arguments' : self.func_do_nothing,
'add_project_link_arguments' : self.func_do_nothing,
'message' : self.func_do_nothing,
'generator' : self.func_do_nothing,
'error' : self.func_do_nothing,
'run_command' : self.func_do_nothing,
'assert' : self.func_do_nothing,
'subproject' : self.func_do_nothing,
'dependency' : self.func_do_nothing,
'get_option' : self.func_do_nothing,
'join_paths' : self.func_do_nothing,
'environment' : self.func_do_nothing,
'import' : self.func_do_nothing,
'vcs_tag' : self.func_do_nothing,
'add_languages' : self.func_do_nothing,
'declare_dependency' : self.func_do_nothing,
'files' : self.func_files,
'executable': self.func_executable,
'static_library' : self.func_static_lib,
'shared_library' : self.func_shared_lib,
'library' : self.func_library,
'build_target' : self.func_build_target,
'custom_target' : self.func_custom_target,
'run_target' : self.func_run_target,
'subdir' : self.func_subdir,
'set_variable' : self.func_set_variable,
'get_variable' : self.func_get_variable,
@ -57,7 +87,10 @@ class AstInterpreter(interpreterbase.InterpreterBase):
})
def func_do_nothing(self, *args, **kwargs):
return DontCareObject()
return True
def method_call(self, node):
return True
def func_executable(self, *args, **kwargs):
return MockExecutable()
@ -68,6 +101,15 @@ class AstInterpreter(interpreterbase.InterpreterBase):
def func_shared_lib(self, *args, **kwargs):
return MockSharedLibrary()
def func_library(self, *args, **kwargs):
return self.func_shared_lib(*args, **kwargs)
def func_custom_target(self, *args, **kwargs):
return MockCustomTarget()
def func_run_target(self, *args, **kwargs):
return MockRunTarget()
def func_subdir(self, node, args, kwargs):
prev_subdir = self.subdir
subdir = os.path.join(prev_subdir, args[0])
@ -93,8 +135,14 @@ class AstInterpreter(interpreterbase.InterpreterBase):
return [args]
return args
def method_call(self, node):
return DontCareObject()
def evaluate_arithmeticstatement(self, cur):
return 0
def evaluate_plusassign(self, node):
return 0
def evaluate_indexing(self, node):
return 0
def dump(self):
self.load_root_meson_file()

@ -2277,97 +2277,6 @@ requirements use the version keyword argument instead.''')
if not os.path.isfile(fname):
raise InterpreterException('Tried to add non-existing source file %s.' % s)
def bool_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'to_string':
if len(posargs) == 0:
if obj == True:
return 'true'
else:
return 'false'
elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str):
if obj == True:
return posargs[0]
else:
return posargs[1]
else:
raise InterpreterException('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.')
elif method_name == 'to_int':
if obj == True:
return 1
else:
return 0
else:
raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)
def int_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'is_even':
if len(posargs) == 0:
return obj % 2 == 0
else:
raise InterpreterException('int.is_even() must have no arguments.')
elif method_name == 'is_odd':
if len(posargs) == 0:
return obj % 2 != 0
else:
raise InterpreterException('int.is_odd() must have no arguments.')
else:
raise InterpreterException('Unknown method "%s" for an integer.' % method_name)
def string_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'strip':
return obj.strip()
elif method_name == 'format':
return self.format_string(obj, args)
elif method_name == 'to_upper':
return obj.upper()
elif method_name == 'to_lower':
return obj.lower()
elif method_name == 'underscorify':
return re.sub(r'[^a-zA-Z0-9]', '_', obj)
elif method_name == 'split':
if len(posargs) > 1:
raise InterpreterException('Split() must have at most one argument.')
elif len(posargs) == 1:
s = posargs[0]
if not isinstance(s, str):
raise InterpreterException('Split() argument must be a string')
return obj.split(s)
else:
return obj.split()
elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith':
s = posargs[0]
if not isinstance(s, str):
raise InterpreterException('Argument must be a string.')
if method_name == 'startswith':
return obj.startswith(s)
elif method_name == 'contains':
return obj.find(s) >= 0
return obj.endswith(s)
elif method_name == 'to_int':
try:
return int(obj)
except Exception:
raise InterpreterException('String {!r} cannot be converted to int'.format(obj))
elif method_name == 'join':
if len(posargs) != 1:
raise InterpreterException('Join() takes exactly one argument.')
strlist = posargs[0]
check_stringlist(strlist)
return obj.join(strlist)
elif method_name == 'version_compare':
if len(posargs) != 1:
raise InterpreterException('Version_compare() takes exactly one argument.')
cmpr = posargs[0]
if not isinstance(cmpr, str):
raise InterpreterException('Version_compare() argument must be a string.')
return mesonlib.version_compare(obj, cmpr)
raise InterpreterException('Unknown method "%s" for a string.' % method_name)
def format_string(self, templ, args):
templ = self.to_native(templ)
@ -2380,32 +2289,6 @@ requirements use the version keyword argument instead.''')
templ = templ.replace('@{}@'.format(i), str(arg))
return templ
def method_call(self, node):
invokable = node.source_object
if isinstance(invokable, mparser.IdNode):
object_name = invokable.value
obj = self.get_variable(object_name)
else:
obj = self.evaluate_statement(invokable)
method_name = node.name
args = node.args
if isinstance(obj, mparser.StringNode):
obj = obj.get_value()
if isinstance(obj, str):
return self.string_method_call(obj, method_name, args)
if isinstance(obj, bool):
return self.bool_method_call(obj, method_name, args)
if isinstance(obj, int):
return self.int_method_call(obj, method_name, args)
if isinstance(obj, list):
return self.array_method_call(obj, method_name, self.reduce_arguments(args)[0])
if not isinstance(obj, InterpreterObject):
raise InvalidArguments('Variable "%s" is not callable.' % object_name)
(args, kwargs) = self.reduce_arguments(args)
if method_name == 'extract_objects':
self.validate_extraction(obj.held_object)
return obj.method_call(method_name, self.flatten(args), kwargs)
# Only permit object extraction from the same subproject
def validate_extraction(self, buildtarget):
if not self.subdir.startswith(self.subproject_dir):
@ -2417,20 +2300,6 @@ requirements use the version keyword argument instead.''')
if self.subdir.split('/')[1] != buildtarget.subdir.split('/')[1]:
raise InterpreterException('Tried to extract objects from a different subproject.')
def array_method_call(self, obj, method_name, args):
if method_name == 'contains':
return self.check_contains(obj, args)
elif method_name == 'length':
return len(obj)
elif method_name == 'get':
index = args[0]
if not isinstance(index, int):
raise InvalidArguments('Array index must be a number.')
if index < -len(obj) or index >= len(obj):
raise InvalidArguments('Array index %s is out of bounds for array of size %d.' % (index, len(obj)))
return obj[index]
raise InterpreterException('Arrays do not have a method called "%s".' % method_name)
def check_contains(self, obj, args):
if len(args) != 1:
raise InterpreterException('Contains method takes exactly one argument.')
@ -2447,157 +2316,5 @@ requirements use the version keyword argument instead.''')
pass
return False
def evaluate_ternary(self, node):
assert(isinstance(node, mparser.TernaryNode))
result = self.evaluate_statement(node.condition)
if not isinstance(result, bool):
raise InterpreterException('Ternary condition is not boolean.')
if result:
return self.evaluate_statement(node.trueblock)
else:
return self.evaluate_statement(node.falseblock)
def evaluate_foreach(self, node):
assert(isinstance(node, mparser.ForeachClauseNode))
varname = node.varname.value
items = self.evaluate_statement(node.items)
if not isinstance(items, list):
raise InvalidArguments('Items of foreach loop is not an array')
for item in items:
self.set_variable(varname, item)
self.evaluate_codeblock(node.block)
def evaluate_plusassign(self, node):
assert(isinstance(node, mparser.PlusAssignmentNode))
varname = node.var_name
addition = self.evaluate_statement(node.value)
# Remember that all variables are immutable. We must always create a
# full new variable and then assign it.
old_variable = self.get_variable(varname)
if isinstance(old_variable, str):
if not isinstance(addition, str):
raise InvalidArguments('The += operator requires a string on the right hand side if the variable on the left is a string')
new_value = old_variable + addition
elif isinstance(old_variable, int):
if not isinstance(addition, int):
raise InvalidArguments('The += operator requires an int on the right hand side if the variable on the left is an int')
new_value = old_variable + addition
elif not isinstance(old_variable, list):
raise InvalidArguments('The += operator currently only works with arrays, strings or ints ')
# Add other data types here.
else:
if isinstance(addition, list):
new_value = old_variable + addition
else:
new_value = old_variable + [addition]
self.set_variable(varname, new_value)
def evaluate_indexing(self, node):
assert(isinstance(node, mparser.IndexNode))
iobject = self.evaluate_statement(node.iobject)
if not isinstance(iobject, list):
raise InterpreterException('Tried to index a non-array object.')
index = self.evaluate_statement(node.index)
if not isinstance(index, int):
raise InterpreterException('Index value is not an integer.')
if index < -len(iobject) or index >= len(iobject):
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject)))
return iobject[index]
def is_elementary_type(self, v):
return isinstance(v, (int, float, str, bool, list))
def evaluate_comparison(self, node):
v1 = self.evaluate_statement(node.left)
v2 = self.evaluate_statement(node.right)
if self.is_elementary_type(v1):
val1 = v1
else:
val1 = v1.value
if self.is_elementary_type(v2):
val2 = v2
else:
val2 = v2.value
if node.ctype == '==':
return val1 == val2
elif node.ctype == '!=':
return val1 != val2
elif node.ctype == '<':
return val1 < val2
elif node.ctype == '<=':
return val1 <= val2
elif node.ctype == '>':
return val1 > val2
elif node.ctype == '>=':
return val1 >= val2
else:
raise InvalidCode('You broke my compare eval.')
def evaluate_andstatement(self, cur):
l = self.evaluate_statement(cur.left)
if isinstance(l, mparser.BooleanNode):
l = l.value
if not isinstance(l, bool):
raise InterpreterException('First argument to "and" is not a boolean.')
if not l:
return False
r = self.evaluate_statement(cur.right)
if isinstance(r, mparser.BooleanNode):
r = r.value
if not isinstance(r, bool):
raise InterpreterException('Second argument to "and" is not a boolean.')
return r
def evaluate_orstatement(self, cur):
l = self.evaluate_statement(cur.left)
if isinstance(l, mparser.BooleanNode):
l = l.get_value()
if not isinstance(l, bool):
raise InterpreterException('First argument to "or" is not a boolean.')
if l:
return True
r = self.evaluate_statement(cur.right)
if isinstance(r, mparser.BooleanNode):
r = r.get_value()
if not isinstance(r, bool):
raise InterpreterException('Second argument to "or" is not a boolean.')
return r
def evaluate_uminusstatement(self, cur):
v = self.evaluate_statement(cur.value)
if isinstance(v, mparser.NumberNode):
v = v.value
if not isinstance(v, int):
raise InterpreterException('Argument to negation is not an integer.')
return -v
def evaluate_arithmeticstatement(self, cur):
l = self.to_native(self.evaluate_statement(cur.left))
r = self.to_native(self.evaluate_statement(cur.right))
if cur.operation == 'add':
try:
return l + r
except Exception as e:
raise InvalidCode('Invalid use of addition: ' + str(e))
elif cur.operation == 'sub':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Subtraction works only with integers.')
return l - r
elif cur.operation == 'mul':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Multiplication works only with integers.')
return l * r
elif cur.operation == 'div':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Division works only with integers.')
return l // r
elif cur.operation == 'mod':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Modulo works only with integers.')
return l % r
else:
raise InvalidCode('You broke me.')
def is_subproject(self):
return self.subproject != ''

@ -203,7 +203,6 @@ class InterpreterBase:
raise InterpreterException('Argument to "not" is not a boolean.')
return not v
def evaluate_if(self, node):
assert(isinstance(node, mparser.IfClauseNode))
for i in node.ifs:
@ -216,6 +215,155 @@ class InterpreterBase:
if not isinstance(node.elseblock, mparser.EmptyNode):
self.evaluate_codeblock(node.elseblock)
def evaluate_comparison(self, node):
v1 = self.evaluate_statement(node.left)
v2 = self.evaluate_statement(node.right)
if self.is_elementary_type(v1):
val1 = v1
else:
val1 = v1.value
if self.is_elementary_type(v2):
val2 = v2
else:
val2 = v2.value
if node.ctype == '==':
return val1 == val2
elif node.ctype == '!=':
return val1 != val2
elif node.ctype == '<':
return val1 < val2
elif node.ctype == '<=':
return val1 <= val2
elif node.ctype == '>':
return val1 > val2
elif node.ctype == '>=':
return val1 >= val2
else:
raise InvalidCode('You broke my compare eval.')
def evaluate_andstatement(self, cur):
l = self.evaluate_statement(cur.left)
if isinstance(l, mparser.BooleanNode):
l = l.value
if not isinstance(l, bool):
raise InterpreterException('First argument to "and" is not a boolean.')
if not l:
return False
r = self.evaluate_statement(cur.right)
if isinstance(r, mparser.BooleanNode):
r = r.value
if not isinstance(r, bool):
raise InterpreterException('Second argument to "and" is not a boolean.')
return r
def evaluate_orstatement(self, cur):
l = self.evaluate_statement(cur.left)
if isinstance(l, mparser.BooleanNode):
l = l.get_value()
if not isinstance(l, bool):
raise InterpreterException('First argument to "or" is not a boolean.')
if l:
return True
r = self.evaluate_statement(cur.right)
if isinstance(r, mparser.BooleanNode):
r = r.get_value()
if not isinstance(r, bool):
raise InterpreterException('Second argument to "or" is not a boolean.')
return r
def evaluate_uminusstatement(self, cur):
v = self.evaluate_statement(cur.value)
if isinstance(v, mparser.NumberNode):
v = v.value
if not isinstance(v, int):
raise InterpreterException('Argument to negation is not an integer.')
return -v
def evaluate_arithmeticstatement(self, cur):
l = self.to_native(self.evaluate_statement(cur.left))
r = self.to_native(self.evaluate_statement(cur.right))
if cur.operation == 'add':
try:
return l + r
except Exception as e:
raise InvalidCode('Invalid use of addition: ' + str(e))
elif cur.operation == 'sub':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Subtraction works only with integers.')
return l - r
elif cur.operation == 'mul':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Multiplication works only with integers.')
return l * r
elif cur.operation == 'div':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Division works only with integers.')
return l // r
elif cur.operation == 'mod':
if not isinstance(l, int) or not isinstance(r, int):
raise InvalidCode('Modulo works only with integers.')
return l % r
else:
raise InvalidCode('You broke me.')
def evaluate_ternary(self, node):
assert(isinstance(node, mparser.TernaryNode))
result = self.evaluate_statement(node.condition)
if not isinstance(result, bool):
raise InterpreterException('Ternary condition is not boolean.')
if result:
return self.evaluate_statement(node.trueblock)
else:
return self.evaluate_statement(node.falseblock)
def evaluate_foreach(self, node):
assert(isinstance(node, mparser.ForeachClauseNode))
varname = node.varname.value
items = self.evaluate_statement(node.items)
if not isinstance(items, list):
raise InvalidArguments('Items of foreach loop is not an array')
for item in items:
self.set_variable(varname, item)
self.evaluate_codeblock(node.block)
def evaluate_plusassign(self, node):
assert(isinstance(node, mparser.PlusAssignmentNode))
varname = node.var_name
addition = self.evaluate_statement(node.value)
# Remember that all variables are immutable. We must always create a
# full new variable and then assign it.
old_variable = self.get_variable(varname)
if isinstance(old_variable, str):
if not isinstance(addition, str):
raise InvalidArguments('The += operator requires a string on the right hand side if the variable on the left is a string')
new_value = old_variable + addition
elif isinstance(old_variable, int):
if not isinstance(addition, int):
raise InvalidArguments('The += operator requires an int on the right hand side if the variable on the left is an int')
new_value = old_variable + addition
elif not isinstance(old_variable, list):
raise InvalidArguments('The += operator currently only works with arrays, strings or ints ')
# Add other data types here.
else:
if isinstance(addition, list):
new_value = old_variable + addition
else:
new_value = old_variable + [addition]
self.set_variable(varname, new_value)
def evaluate_indexing(self, node):
assert(isinstance(node, mparser.IndexNode))
iobject = self.evaluate_statement(node.iobject)
if not isinstance(iobject, list):
raise InterpreterException('Tried to index a non-array object.')
index = self.evaluate_statement(node.index)
if not isinstance(index, int):
raise InterpreterException('Index value is not an integer.')
if index < -len(iobject) or index >= len(iobject):
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject)))
return iobject[index]
def function_call(self, node):
func_name = node.func_name
(posargs, kwargs) = self.reduce_arguments(node.args)
@ -224,9 +372,142 @@ class InterpreterBase:
else:
self.unknown_function_called(func_name)
def method_call(self, node):
invokable = node.source_object
if isinstance(invokable, mparser.IdNode):
object_name = invokable.value
obj = self.get_variable(object_name)
else:
obj = self.evaluate_statement(invokable)
method_name = node.name
args = node.args
if isinstance(obj, mparser.StringNode):
obj = obj.get_value()
if isinstance(obj, str):
return self.string_method_call(obj, method_name, args)
if isinstance(obj, bool):
return self.bool_method_call(obj, method_name, args)
if isinstance(obj, int):
return self.int_method_call(obj, method_name, args)
if isinstance(obj, list):
return self.array_method_call(obj, method_name, self.reduce_arguments(args)[0])
if not isinstance(obj, InterpreterObject):
raise InvalidArguments('Variable "%s" is not callable.' % object_name)
(args, kwargs) = self.reduce_arguments(args)
if method_name == 'extract_objects':
self.validate_extraction(obj.held_object)
return obj.method_call(method_name, self.flatten(args), kwargs)
def bool_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'to_string':
if len(posargs) == 0:
if obj == True:
return 'true'
else:
return 'false'
elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str):
if obj == True:
return posargs[0]
else:
return posargs[1]
else:
raise InterpreterException('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.')
elif method_name == 'to_int':
if obj == True:
return 1
else:
return 0
else:
raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)
def int_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'is_even':
if len(posargs) == 0:
return obj % 2 == 0
else:
raise InterpreterException('int.is_even() must have no arguments.')
elif method_name == 'is_odd':
if len(posargs) == 0:
return obj % 2 != 0
else:
raise InterpreterException('int.is_odd() must have no arguments.')
else:
raise InterpreterException('Unknown method "%s" for an integer.' % method_name)
def string_method_call(self, obj, method_name, args):
obj = self.to_native(obj)
(posargs, _) = self.reduce_arguments(args)
if method_name == 'strip':
return obj.strip()
elif method_name == 'format':
return self.format_string(obj, args)
elif method_name == 'to_upper':
return obj.upper()
elif method_name == 'to_lower':
return obj.lower()
elif method_name == 'underscorify':
return re.sub(r'[^a-zA-Z0-9]', '_', obj)
elif method_name == 'split':
if len(posargs) > 1:
raise InterpreterException('Split() must have at most one argument.')
elif len(posargs) == 1:
s = posargs[0]
if not isinstance(s, str):
raise InterpreterException('Split() argument must be a string')
return obj.split(s)
else:
return obj.split()
elif method_name == 'startswith' or method_name == 'contains' or method_name == 'endswith':
s = posargs[0]
if not isinstance(s, str):
raise InterpreterException('Argument must be a string.')
if method_name == 'startswith':
return obj.startswith(s)
elif method_name == 'contains':
return obj.find(s) >= 0
return obj.endswith(s)
elif method_name == 'to_int':
try:
return int(obj)
except Exception:
raise InterpreterException('String {!r} cannot be converted to int'.format(obj))
elif method_name == 'join':
if len(posargs) != 1:
raise InterpreterException('Join() takes exactly one argument.')
strlist = posargs[0]
check_stringlist(strlist)
return obj.join(strlist)
elif method_name == 'version_compare':
if len(posargs) != 1:
raise InterpreterException('Version_compare() takes exactly one argument.')
cmpr = posargs[0]
if not isinstance(cmpr, str):
raise InterpreterException('Version_compare() argument must be a string.')
return mesonlib.version_compare(obj, cmpr)
raise InterpreterException('Unknown method "%s" for a string.' % method_name)
def unknown_function_called(self, func_name):
raise InvalidCode('Unknown function "%s".' % func_name)
def array_method_call(self, obj, method_name, args):
if method_name == 'contains':
return self.check_contains(obj, args)
elif method_name == 'length':
return len(obj)
elif method_name == 'get':
index = args[0]
if not isinstance(index, int):
raise InvalidArguments('Array index must be a number.')
if index < -len(obj) or index >= len(obj):
raise InvalidArguments('Array index %s is out of bounds for array of size %d.' % (index, len(obj)))
return obj[index]
raise InterpreterException('Arrays do not have a method called "%s".' % method_name)
def reduce_arguments(self, args):
assert(isinstance(args, mparser.ArgumentNode))
if args.incorrect_order():
@ -349,3 +630,7 @@ class InterpreterBase:
raise InvalidCode('Is_variable takes two arguments.')
varname = args[0]
return varname in self.variables
def is_elementary_type(self, v):
return isinstance(v, (int, float, str, bool, list))

Loading…
Cancel
Save