interpreter: Introduce BooleanHolder for the bool primitive

pull/9202/head
Daniel Mensinger 4 years ago
parent 86eda3c812
commit 43302d3296
  1. 3
      mesonbuild/ast/interpreter.py
  2. 2
      mesonbuild/interpreter/__init__.py
  3. 3
      mesonbuild/interpreter/interpreter.py
  4. 2
      mesonbuild/interpreter/primitives/__init__.py
  5. 53
      mesonbuild/interpreter/primitives/boolean.py
  6. 4
      mesonbuild/interpreterbase/baseobjects.py
  7. 4
      mesonbuild/interpreterbase/decorators.py
  8. 126
      mesonbuild/interpreterbase/interpreterbase.py

@ -366,7 +366,8 @@ class AstInterpreter(InterpreterBase):
if isinstance(src, str): if isinstance(src, str):
result = self.string_method_call(src, node.name, margs, mkwargs) result = self.string_method_call(src, node.name, margs, mkwargs)
elif isinstance(src, bool): elif isinstance(src, bool):
result = self.bool_method_call(src, node.name, margs, mkwargs) from ..interpreter import Interpreter, BooleanHolder
result = BooleanHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)
elif isinstance(src, int): elif isinstance(src, int):
from ..interpreter import Interpreter, IntegerHolder from ..interpreter import Interpreter, IntegerHolder
result = IntegerHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs) result = IntegerHolder(src, T.cast(Interpreter, self)).method_call(node.name, margs, mkwargs)

@ -35,6 +35,7 @@ __all__ = [
'ExternalProgramHolder', 'ExternalProgramHolder',
'extract_required_kwarg', 'extract_required_kwarg',
'BooleanHolder',
'IntegerHolder', 'IntegerHolder',
] ]
@ -47,5 +48,6 @@ from .interpreterobjects import (ExecutableHolder, BuildTargetHolder, CustomTarg
extract_required_kwarg) extract_required_kwarg)
from .primitives import ( from .primitives import (
BooleanHolder,
IntegerHolder, IntegerHolder,
) )

@ -26,7 +26,7 @@ from ..programs import ExternalProgram, NonExistingExternalProgram
from ..dependencies import Dependency from ..dependencies import Dependency
from ..depfile import DepFile from ..depfile import DepFile
from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args from ..interpreterbase import ContainerTypeInfo, InterpreterBase, KwargInfo, typed_kwargs, typed_pos_args
from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, permissive_unholder_return from ..interpreterbase import noPosargs, noKwargs, permittedKwargs, noArgsFlattening, noSecondLevelHolderResolving, unholder_return
from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest from ..interpreterbase import InterpreterException, InvalidArguments, InvalidCode, SubdirDoneRequest
from ..interpreterbase import Disabler, disablerIfNotFound from ..interpreterbase import Disabler, disablerIfNotFound
from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs from ..interpreterbase import FeatureNew, FeatureDeprecated, FeatureNewKwargs, FeatureDeprecatedKwargs
@ -381,6 +381,7 @@ class Interpreter(InterpreterBase, HoldableObject):
self.holder_map.update({ self.holder_map.update({
# Primitives # Primitives
int: P_OBJ.IntegerHolder, int: P_OBJ.IntegerHolder,
bool: P_OBJ.BooleanHolder,
# Meson types # Meson types
mesonlib.File: OBJ.FileHolder, mesonlib.File: OBJ.FileHolder,

@ -2,7 +2,9 @@
# SPDX-license-identifier: Apache-2.0 # SPDX-license-identifier: Apache-2.0
__all__ = [ __all__ = [
'BooleanHolder',
'IntegerHolder', 'IntegerHolder',
] ]
from .boolean import BooleanHolder
from .integer import IntegerHolder from .integer import IntegerHolder

@ -0,0 +1,53 @@
# Copyright 2021 The Meson development team
# SPDX-license-identifier: Apache-2.0
from ...interpreterbase import (
ObjectHolder,
MesonOperator,
typed_pos_args,
noKwargs,
noPosargs,
TYPE_var,
TYPE_kwargs,
InvalidArguments
)
import typing as T
if T.TYPE_CHECKING:
# Object holders need the actual interpreter
from ...interpreter import Interpreter
class BooleanHolder(ObjectHolder[bool]):
def __init__(self, obj: bool, interpreter: 'Interpreter') -> None:
super().__init__(obj, interpreter)
self.methods.update({
'to_int': self.to_int_method,
'to_string': self.to_string_method,
})
self.trivial_operators.update({
MesonOperator.BOOL: (None, lambda x: self.held_object),
MesonOperator.NOT: (None, lambda x: not self.held_object),
MesonOperator.EQUALS: (bool, lambda x: self.held_object == x),
MesonOperator.NOT_EQUALS: (bool, lambda x: self.held_object != x),
})
def display_name(self) -> str:
return 'bool'
@noKwargs
@noPosargs
def to_int_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> int:
return 1 if self.held_object else 0
@noKwargs
@typed_pos_args('bool.to_string', optargs=[str, str])
def to_string_method(self, args: T.Tuple[T.Optional[str], T.Optional[str]], kwargs: TYPE_kwargs) -> str:
true_str = args[0] or 'true'
false_str = args[1] or 'false'
if any(x is not None for x in args) and not all(x is not None for x in args):
raise InvalidArguments('bool.to_string() must have either no arguments or exactly two string arguments that signify what values to return for true and false.')
return true_str if self.held_object else false_str

@ -129,8 +129,8 @@ class MesonInterpreterObject(InterpreterObject):
class MutableInterpreterObject: class MutableInterpreterObject:
''' Dummy class to mark the object type as mutable ''' ''' Dummy class to mark the object type as mutable '''
HoldableTypes = (HoldableObject, int) HoldableTypes = (HoldableObject, int, bool)
TYPE_HoldableTypes = T.Union[HoldableObject, int] TYPE_HoldableTypes = T.Union[HoldableObject, int, bool]
InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=TYPE_HoldableTypes) InterpreterObjectTypeVar = T.TypeVar('InterpreterObjectTypeVar', bound=TYPE_HoldableTypes)
class ObjectHolder(InterpreterObject, T.Generic[InterpreterObjectTypeVar]): class ObjectHolder(InterpreterObject, T.Generic[InterpreterObjectTypeVar]):

@ -77,11 +77,11 @@ def noSecondLevelHolderResolving(f: TV_func) -> TV_func:
setattr(f, 'no-second-level-holder-flattening', True) # noqa: B010 setattr(f, 'no-second-level-holder-flattening', True) # noqa: B010
return f return f
def permissive_unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]: def unholder_return(f: TV_func) -> T.Callable[..., TYPE_var]:
@wraps(f) @wraps(f)
def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any: def wrapped(*wrapped_args: T.Any, **wrapped_kwargs: T.Any) -> T.Any:
res = f(*wrapped_args, **wrapped_kwargs) res = f(*wrapped_args, **wrapped_kwargs)
return _unholder(res, permissive=True) return _unholder(res)
return T.cast(T.Callable[..., TYPE_var], wrapped) return T.cast(T.Callable[..., TYPE_var], wrapped)
def disablerIfNotFound(f: TV_func) -> TV_func: def disablerIfNotFound(f: TV_func) -> TV_func:

@ -51,6 +51,7 @@ from ._unholder import _unholder
import os, copy, re, pathlib import os, copy, re, pathlib
import typing as T import typing as T
import textwrap import textwrap
from functools import wraps
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from ..interpreter import Interpreter from ..interpreter import Interpreter
@ -69,11 +70,23 @@ FunctionType = T.Dict[
T.Callable[[mparser.BaseNode, T.List[TYPE_var], T.Dict[str, TYPE_var]], TYPE_var] T.Callable[[mparser.BaseNode, T.List[TYPE_var], T.Dict[str, TYPE_var]], TYPE_var]
] ]
__FN = T.TypeVar('__FN', bound=T.Callable[['InterpreterBase', T.Any], T.Union[TYPE_var, InterpreterObject]])
def _holderify_result(types: T.Union[None, T.Type, T.Tuple[T.Type, ...]] = None) -> T.Callable[[__FN], __FN]:
def inner(f: __FN) -> __FN:
@wraps(f)
def wrapper(self: 'InterpreterBase', node: mparser.BaseNode) -> T.Union[TYPE_var, InterpreterObject]:
res = f(self, node)
if types is not None and not isinstance(res, types):
raise mesonlib.MesonBugException(f'Expected {types} but got object `{res}` of type {type(res).__name__}')
return self._holderify(res)
return T.cast(__FN, wrapper)
return inner
class MesonVersionString(str): class MesonVersionString(str):
pass pass
class InterpreterBase: class InterpreterBase:
elementary_types = (str, bool, list) elementary_types = (str, list)
def __init__(self, source_root: str, subdir: str, subproject: str): def __init__(self, source_root: str, subdir: str, subproject: str):
self.source_root = source_root self.source_root = source_root
@ -190,7 +203,7 @@ class InterpreterBase:
elif isinstance(cur, mparser.StringNode): elif isinstance(cur, mparser.StringNode):
return cur.value return cur.value
elif isinstance(cur, mparser.BooleanNode): elif isinstance(cur, mparser.BooleanNode):
return cur.value return self._holderify(cur.value)
elif isinstance(cur, mparser.IfClauseNode): elif isinstance(cur, mparser.IfClauseNode):
return self.evaluate_if(cur) return self.evaluate_if(cur)
elif isinstance(cur, mparser.IdNode): elif isinstance(cur, mparser.IdNode):
@ -252,13 +265,15 @@ class InterpreterBase:
assert not arguments assert not arguments
return kwargs return kwargs
def evaluate_notstatement(self, cur: mparser.NotNode) -> T.Union[bool, Disabler]: @_holderify_result((bool, Disabler))
def evaluate_notstatement(self, cur: mparser.NotNode) -> T.Union[TYPE_var, InterpreterObject]:
v = self.evaluate_statement(cur.value) v = self.evaluate_statement(cur.value)
if isinstance(v, Disabler): if isinstance(v, Disabler):
return v return v
if not isinstance(v, bool): # TYPING TODO: Remove this check once `evaluate_statement` only returns InterpreterObjects
raise InterpreterException('Argument to "not" is not a boolean.') if not isinstance(v, InterpreterObject):
return not v raise mesonlib.MesonBugException(f'Argument to not ({v}) is not an InterpreterObject but {type(v).__name__}.')
return v.operator_call(MesonOperator.NOT, None)
def evaluate_if(self, node: mparser.IfClauseNode) -> T.Optional[Disabler]: def evaluate_if(self, node: mparser.IfClauseNode) -> T.Optional[Disabler]:
assert isinstance(node, mparser.IfClauseNode) assert isinstance(node, mparser.IfClauseNode)
@ -269,6 +284,9 @@ class InterpreterBase:
result = self.evaluate_statement(i.condition) result = self.evaluate_statement(i.condition)
if isinstance(result, Disabler): if isinstance(result, Disabler):
return result return result
if not isinstance(result, InterpreterObject):
raise mesonlib.MesonBugException(f'Argument to not ({result}) is not an InterpreterObject but {type(result).__name__}.')
result = result.operator_call(MesonOperator.BOOL, None)
if not isinstance(result, bool): if not isinstance(result, bool):
raise InvalidCode(f'If clause {result!r} does not evaluate to true or false.') raise InvalidCode(f'If clause {result!r} does not evaluate to true or false.')
if result: if result:
@ -289,13 +307,14 @@ class InterpreterBase:
return False return False
return True return True
def evaluate_in(self, val1: T.Any, val2: T.Any) -> bool: def _evaluate_in(self, val1: T.Any, val2: T.Any) -> bool:
if not isinstance(val1, (str, int, float, mesonlib.HoldableObject)): if not isinstance(val1, (str, int, float, mesonlib.HoldableObject)):
raise InvalidArguments('lvalue of "in" operator must be a string, integer, float, or object') raise InvalidArguments('lvalue of "in" operator must be a string, integer, float, or object')
if not isinstance(val2, (list, dict)): if not isinstance(val2, (list, dict)):
raise InvalidArguments('rvalue of "in" operator must be an array or a dict') raise InvalidArguments('rvalue of "in" operator must be an array or a dict')
return val1 in val2 return val1 in val2
@_holderify_result((bool, Disabler))
def evaluate_comparison(self, node: mparser.ComparisonNode) -> T.Union[TYPE_var, InterpreterObject]: def evaluate_comparison(self, node: mparser.ComparisonNode) -> T.Union[TYPE_var, InterpreterObject]:
val1 = self.evaluate_statement(node.left) val1 = self.evaluate_statement(node.left)
if isinstance(val1, Disabler): if isinstance(val1, Disabler):
@ -318,11 +337,11 @@ class InterpreterBase:
# Check if the arguments should be reversed for simplicity (this essentially converts `in` to `contains`) # Check if the arguments should be reversed for simplicity (this essentially converts `in` to `contains`)
if operator in (MesonOperator.IN, MesonOperator.NOT_IN) and isinstance(val2, InterpreterObject): if operator in (MesonOperator.IN, MesonOperator.NOT_IN) and isinstance(val2, InterpreterObject):
return self._holderify(val2.operator_call(operator, _unholder(val1))) return val2.operator_call(operator, _unholder(val1))
# Normal evaluation, with the same semantics # Normal evaluation, with the same semantics
elif operator not in (MesonOperator.IN, MesonOperator.NOT_IN) and isinstance(val1, InterpreterObject): elif operator not in (MesonOperator.IN, MesonOperator.NOT_IN) and isinstance(val1, InterpreterObject):
return self._holderify(val1.operator_call(operator, _unholder(val2))) return val1.operator_call(operator, _unholder(val2))
# OLD CODE, based on the builtin types -- remove once we have switched # OLD CODE, based on the builtin types -- remove once we have switched
# over to all ObjectHolders. # over to all ObjectHolders.
@ -331,9 +350,9 @@ class InterpreterBase:
val1 = _unholder(val1) val1 = _unholder(val1)
val2 = _unholder(val2) val2 = _unholder(val2)
if node.ctype == 'in': if node.ctype == 'in':
return self.evaluate_in(val1, val2) return self._evaluate_in(val1, val2)
elif node.ctype == 'notin': elif node.ctype == 'notin':
return not self.evaluate_in(val1, val2) return not self._evaluate_in(val1, val2)
valid = self.validate_comparison_types(val1, val2) valid = self.validate_comparison_types(val1, val2)
# Ordering comparisons of different types isn't allowed since PR #1810 # Ordering comparisons of different types isn't allowed since PR #1810
# (0.41.0). Since PR #2884 we also warn about equality comparisons of # (0.41.0). Since PR #2884 we also warn about equality comparisons of
@ -371,36 +390,41 @@ class InterpreterBase:
else: else:
raise InvalidCode('You broke my compare eval.') raise InvalidCode('You broke my compare eval.')
def evaluate_andstatement(self, cur: mparser.AndNode) -> T.Union[bool, Disabler]: @_holderify_result((bool, Disabler))
def evaluate_andstatement(self, cur: mparser.AndNode) -> T.Union[TYPE_var, InterpreterObject]:
l = self.evaluate_statement(cur.left) l = self.evaluate_statement(cur.left)
if isinstance(l, Disabler): if isinstance(l, Disabler):
return l return l
if not isinstance(l, bool): if not isinstance(l, InterpreterObject):
raise InterpreterException('First argument to "and" is not a boolean.') raise mesonlib.MesonBugException(f'Firtst argument to and ({l}) is not an InterpreterObject but {type(l).__name__}.')
if not l: l_bool = l.operator_call(MesonOperator.BOOL, None)
return False if not l_bool:
return l_bool
r = self.evaluate_statement(cur.right) r = self.evaluate_statement(cur.right)
if isinstance(r, Disabler): if isinstance(r, Disabler):
return r return r
if not isinstance(r, bool): if not isinstance(r, InterpreterObject):
raise InterpreterException('Second argument to "and" is not a boolean.') raise mesonlib.MesonBugException(f'Second argument to and ({r}) is not an InterpreterObject but {type(r).__name__}.')
return r return r.operator_call(MesonOperator.BOOL, None)
def evaluate_orstatement(self, cur: mparser.OrNode) -> T.Union[bool, Disabler]: @_holderify_result((bool, Disabler))
def evaluate_orstatement(self, cur: mparser.OrNode) -> T.Union[TYPE_var, InterpreterObject]:
l = self.evaluate_statement(cur.left) l = self.evaluate_statement(cur.left)
if isinstance(l, Disabler): if isinstance(l, Disabler):
return l return l
if not isinstance(l, bool): if not isinstance(l, InterpreterObject):
raise InterpreterException('First argument to "or" is not a boolean.') raise mesonlib.MesonBugException(f'Firtst argument to or ({l}) is not an InterpreterObject but {type(l).__name__}.')
if l: l_bool = l.operator_call(MesonOperator.BOOL, None)
return True if l_bool:
return l_bool
r = self.evaluate_statement(cur.right) r = self.evaluate_statement(cur.right)
if isinstance(r, Disabler): if isinstance(r, Disabler):
return r return r
if not isinstance(r, bool): if not isinstance(r, InterpreterObject):
raise InterpreterException('Second argument to "or" is not a boolean.') raise mesonlib.MesonBugException(f'Second argument to ot ({r}) is not an InterpreterObject but {type(r).__name__}.')
return r return r.operator_call(MesonOperator.BOOL, None)
@_holderify_result()
def evaluate_uminusstatement(self, cur: mparser.UMinusNode) -> T.Union[TYPE_var, InterpreterObject]: def evaluate_uminusstatement(self, cur: mparser.UMinusNode) -> T.Union[TYPE_var, InterpreterObject]:
v = self.evaluate_statement(cur.value) v = self.evaluate_statement(cur.value)
if isinstance(v, Disabler): if isinstance(v, Disabler):
@ -408,7 +432,7 @@ class InterpreterBase:
# TYPING TODO: Remove this check once `evaluate_statement` only returns InterpreterObjects # TYPING TODO: Remove this check once `evaluate_statement` only returns InterpreterObjects
if not isinstance(v, InterpreterObject): if not isinstance(v, InterpreterObject):
raise InterpreterException(f'Argument to negation ({v}) is not an InterpreterObject but {type(v).__name__}.') raise InterpreterException(f'Argument to negation ({v}) is not an InterpreterObject but {type(v).__name__}.')
return self._holderify(v.operator_call(MesonOperator.UMINUS, None)) return v.operator_call(MesonOperator.UMINUS, None)
@FeatureNew('/ with string arguments', '0.49.0') @FeatureNew('/ with string arguments', '0.49.0')
def evaluate_path_join(self, l: str, r: str) -> str: def evaluate_path_join(self, l: str, r: str) -> str:
@ -473,9 +497,10 @@ class InterpreterBase:
result = self.evaluate_statement(node.condition) result = self.evaluate_statement(node.condition)
if isinstance(result, Disabler): if isinstance(result, Disabler):
return result return result
if not isinstance(result, bool): if not isinstance(result, InterpreterObject):
raise InterpreterException('Ternary condition is not boolean.') raise mesonlib.MesonBugException(f'Ternary condition ({result}) is not an InterpreterObject but {type(result).__name__}.')
if result: result_bool = result.operator_call(MesonOperator.BOOL, None)
if result_bool:
return self.evaluate_statement(node.trueblock) return self.evaluate_statement(node.trueblock)
else: else:
return self.evaluate_statement(node.falseblock) return self.evaluate_statement(node.falseblock)
@ -554,7 +579,7 @@ class InterpreterBase:
new_value = {**old_variable, **addition} new_value = {**old_variable, **addition}
elif isinstance(old_variable, InterpreterObject): elif isinstance(old_variable, InterpreterObject):
# TODO: don't make _unholder permissive # TODO: don't make _unholder permissive
new_value = self._holderify(old_variable.operator_call(MesonOperator.PLUS, _unholder(addition, permissive=True))) new_value = self._holderify(old_variable.operator_call(MesonOperator.PLUS, _unholder(addition)))
# Add other data types here. # Add other data types here.
else: else:
raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints') raise InvalidArguments('The += operator currently only works with arrays, dicts, strings or ints')
@ -596,7 +621,8 @@ class InterpreterBase:
# We are already checking for the existence of __getitem__, so this should be save # We are already checking for the existence of __getitem__, so this should be save
raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject))) # type: ignore raise InterpreterException('Index %d out of bounds of array of size %d.' % (index, len(iobject))) # type: ignore
def function_call(self, node: mparser.FunctionNode) -> T.Optional[T.Union[TYPE_elementary, InterpreterObject]]: @_holderify_result()
def function_call(self, node: mparser.FunctionNode) -> T.Optional[T.Union[TYPE_var, InterpreterObject]]:
func_name = node.func_name func_name = node.func_name
(h_posargs, h_kwargs) = self.reduce_arguments(node.args) (h_posargs, h_kwargs) = self.reduce_arguments(node.args)
(posargs, kwargs) = self._unholder_args(h_posargs, h_kwargs) (posargs, kwargs) = self._unholder_args(h_posargs, h_kwargs)
@ -609,8 +635,7 @@ class InterpreterBase:
func_args = flatten(posargs) func_args = flatten(posargs)
if not getattr(func, 'no-second-level-holder-flattening', False): if not getattr(func, 'no-second-level-holder-flattening', False):
func_args, kwargs = resolve_second_level_holders(func_args, kwargs) func_args, kwargs = resolve_second_level_holders(func_args, kwargs)
res = func(node, func_args, kwargs) return func(node, func_args, kwargs)
return self._holderify(res)
else: else:
self.unknown_function_called(func_name) self.unknown_function_called(func_name)
return None return None
@ -631,7 +656,7 @@ class InterpreterBase:
if isinstance(obj, str): if isinstance(obj, str):
return self._holderify(self.string_method_call(obj, method_name, args, kwargs)) return self._holderify(self.string_method_call(obj, method_name, args, kwargs))
if isinstance(obj, bool): if isinstance(obj, bool):
return self._holderify(self.bool_method_call(obj, method_name, args, kwargs)) raise mesonlib.MesonBugException('Booleans are now wrapped in object holders!')
if isinstance(obj, int): if isinstance(obj, int):
raise mesonlib.MesonBugException('Integers are now wrapped in object holders!') raise mesonlib.MesonBugException('Integers are now wrapped in object holders!')
if isinstance(obj, list): if isinstance(obj, list):
@ -653,7 +678,7 @@ class InterpreterBase:
# TODO: remove `permissive` once all primitives are ObjectHolders # TODO: remove `permissive` once all primitives are ObjectHolders
if res is None: if res is None:
return None return None
if isinstance(res, (bool, str)): if isinstance(res, str):
return res return res
elif isinstance(res, list): elif isinstance(res, list):
return [self._holderify(x, permissive=permissive) for x in res] return [self._holderify(x, permissive=permissive) for x in res]
@ -684,29 +709,6 @@ class InterpreterBase:
kwargs: T.Dict[str, T.Union[TYPE_var, InterpreterObject]]) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]: kwargs: T.Dict[str, T.Union[TYPE_var, InterpreterObject]]) -> T.Tuple[T.List[TYPE_var], TYPE_kwargs]:
return [_unholder(x) for x in args], {k: _unholder(v) for k, v in kwargs.items()} return [_unholder(x) for x in args], {k: _unholder(v) for k, v in kwargs.items()}
@noKwargs
def bool_method_call(self, obj: bool, method_name: str, posargs: T.List[TYPE_var], kwargs: TYPE_kwargs) -> T.Union[str, int]:
if method_name == 'to_string':
if not posargs:
if obj:
return 'true'
else:
return 'false'
elif len(posargs) == 2 and isinstance(posargs[0], str) and isinstance(posargs[1], str):
if obj:
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:
return 1
else:
return 0
else:
raise InterpreterException('Unknown method "%s" for a boolean.' % method_name)
@staticmethod @staticmethod
def _get_one_string_posarg(posargs: T.List[TYPE_var], method_name: str) -> str: def _get_one_string_posarg(posargs: T.List[TYPE_var], method_name: str) -> str:
if len(posargs) > 1: if len(posargs) > 1:
@ -830,7 +832,7 @@ class InterpreterBase:
if element == item: if element == item:
return True return True
return False return False
return check_contains([_unholder(x) for x in obj]) return self._holderify(check_contains([_unholder(x) for x in obj]))
elif method_name == 'length': elif method_name == 'length':
return self._holderify(len(obj)) return self._holderify(len(obj))
elif method_name == 'get': elif method_name == 'get':
@ -876,7 +878,7 @@ class InterpreterBase:
has_key = key in obj has_key = key in obj
if method_name == 'has_key': if method_name == 'has_key':
return has_key return self._holderify(has_key)
if has_key: if has_key:
return obj[key] return obj[key]

Loading…
Cancel
Save