예제 #1
0
 def __init__(self, argument_type, break_types):
     self.argument_type = argument_type
     self.break_types = break_types
     if argument_type is None:
         raise FatalError()
     if break_types is None:
         raise FatalError()
예제 #2
0
 def __init__(self, types):
     if len(types) <= 1:
         raise FatalError()
     self.types = types
     for t in types:
         if isinstance(t, OneOfType):
             raise FatalError()
예제 #3
0
def merge_types(types, mode):
    if mode not in ("exact", "super", "sub"):
        raise FatalError()

    for t in types:
        if not isinstance(t, Type):
            raise FatalError()

    to_drop = []
    for i1, t1 in enumerate(types):
        for i2, t2 in enumerate(types):
            if i1 > i2 and t1.is_copyable_from(
                    t2, DUMMY_REASONER) and t2.is_copyable_from(
                        t1, DUMMY_REASONER):
                to_drop.append(i1)

    types = [t for i, t in enumerate(types) if i not in to_drop]

    to_drop = []
    if mode != "exact":
        for i1, t1 in enumerate(types):
            for i2, t2 in enumerate(types):
                if i1 != i2 and t1.is_copyable_from(t2, DUMMY_REASONER):
                    if mode == "super":
                        to_drop.append(i2)
                    elif mode == "sub":
                        to_drop.append(i1)
        types = [t for i, t in enumerate(types) if i not in to_drop]

    if len(types) == 0:
        return NoValueType()
    elif len(types) == 1:
        return types[0]
    else:
        return OneOfType(types)
예제 #4
0
    def __exit__(self, exc_type, exc_value, traceback):
        if isinstance(exc_value, FatalError):
            return

        if get_environment().validate_flow_control and isinstance(
                exc_value,
                BreakException) and self.target.break_types is not None:
            # Verifies that execution is leaving the target opcode at run-time in a way that was forecast
            # at verification time.
            break_types = self.target.break_types.get(
                exc_value.mode, []) + self.target.break_types.get("*", [])

            #            if break_types is MISSING:
            #                raise FatalError("Can not unwind {}: {}, target {} allowed {}".format(exc_value.mode, exc_value.value, self.target, break_types))

            failures = []

            reasoner = Reasoner()

            for allowed_break_type in break_types:
                allowed_out = allowed_break_type["out"]
                allowed_in = allowed_break_type.get("in", None)

                out_is_compatible = does_value_fit_through_type(
                    exc_value.value, allowed_out, reasoner=reasoner)
                in_is_compatible = allowed_in is None or (
                    exc_value.restart_type is not None
                    and exc_value.restart_type.is_copyable_from(
                        allowed_in, reasoner))

                if not out_is_compatible:
                    failures.append(out_is_compatible)

                if out_is_compatible and in_is_compatible:
                    break
            else:
                raise FatalError(
                    "Can not unwind {} {}, target {}, allowed {}: {}".format(
                        exc_value.mode, exc_value.value, self.target,
                        break_types, reasoner.to_message()))

        exc_type_allows_restart = exc_value and isinstance(
            exc_value, BreakException) and exc_value.restart_type is not None

        if get_environment(
        ).validate_flow_control and self.manager.mode == "reset":
            raise FatalError()

        if not exc_type_allows_restart and self.manager.fully_wound():
            self.manager.pop_frame()
        else:
            if get_environment(
            ).validate_flow_control and exc_type_allows_restart:
                if self.manager.mode not in ("shift", ):
                    raise FatalError()

        self.manager.index -= 1
예제 #5
0
 def detach_type(self, remove_type, multiplier=1):
     remove_type_id = id(remove_type)
     if remove_type_id not in self.attached_type_counts:
         raise FatalError()
     self.attached_type_counts[remove_type_id] -= multiplier
     if self.attached_type_counts[remove_type_id] < 0:
         raise FatalError()
     if self.attached_type_counts[remove_type_id] == 0:
         self.cached_effective_composite_type = None
         del self.attached_types[remove_type_id]
         del self.attached_type_counts[remove_type_id]
예제 #6
0
    def chain(self, other, debug_info):
        can_merge_code_blocks = True

        if other is None:
            return self

        if other.argument_type_expression is not MISSING:
            # If the inner function needs an argument, we have no mechanism to provide it
            raise FatalError()
        if other.breaks_types is not MISSING:
            # The newly created function ignores other.breaks_types, so let's fail early if they're provided
            raise FatalError()

        if self.local_variable_type is not MISSING and other.local_variable_type is not MISSING:
            # We can only take local variables from one of the two functions
            can_merge_code_blocks = False
        if self.code_expressions is not MISSING and other.local_variable_type is not MISSING:
            # We have code that should execute before the other functions local variables are declared
            can_merge_code_blocks = False
        if self.extra_statics is not MISSING and other.extra_statics is not MISSING:
            # We can only take extra statics from one of the two functions
            can_merge_code_blocks = False
        if self.extra_statics is not MISSING and other.local_variable_type is not MISSING:
            # The inner local_variable_type might reference something from statics
            can_merge_code_blocks = False

        new_code_expressions = None
        our_code_expressions = default(self.code_expressions, MISSING, [])
        other_code_expressions = default(other.code_expressions, MISSING, [])

        if can_merge_code_blocks:
            new_code_expressions = our_code_expressions + other_code_expressions
            local_variable_type = default(self.local_variable_type, MISSING,
                                          other.local_variable_type)
            local_initializer = default(self.local_initializer, MISSING,
                                        other.local_initializer)
            extra_statics = default(self.extra_statics, MISSING,
                                    other.extra_statics)
        else:
            new_code_expressions = our_code_expressions + [
                other.create("expression", debug_info)
            ]
            local_variable_type = self.local_variable_type
            local_initializer = self.local_initializer
            extra_statics = self.extra_statics

        return CodeBlockBuilder(
            code_expressions=new_code_expressions,
            local_variable_type=local_variable_type,
            local_initializer=local_initializer,
            extra_statics=extra_statics,
            argument_type_expression=self.argument_type_expression,
            breaks_types=self.breaks_types)
예제 #7
0
    def __init__(self, micro_op_types, name, delegate=None):
        if not isinstance(micro_op_types, dict):
            raise FatalError()
        for tag in micro_op_types.keys():
            if not isinstance(tag, tuple):
                raise FatalError()

        self._micro_op_types = micro_op_types
        self.name = name
        self._is_self_consistent = None
        self.is_copyable_cache = WeakIdentityKeyDictionary()
        self.delegate = delegate
예제 #8
0
 def add(self, mode, out_type, in_type=None, opcode=None):
     if not isinstance(out_type, Type):
         raise FatalError()
     if in_type and not isinstance(in_type, Type):
         raise FatalError()
     if opcode:
         out_type.from_opcode = opcode
     break_type = {
         "out": out_type,
     }
     if in_type:
         break_type["in"] = in_type
     self.result[mode].append(break_type)
예제 #9
0
    def __enter__(self):
        if self.manager.fully_wound():
            if self.manager.mode not in ("wind", "reset"):
                raise FatalError()
            self.manager.mode = "wind"
            self.manager.frames.append(self)
        else:
            if self.manager.mode not in ("reset", "shift"):
                raise FatalError()
            self.manager.mode = "reset"

        self.manager.index += 1

        return self
예제 #10
0
def function_lit(*args, **kwargs):
    if len(args) == 1:
        extra_statics = {}
        code, = args
        argument_type = local_type = no_value_type()
        break_types = infer_all()
        local_initializer = nop()
    elif len(args) == 2:
        extra_statics = {}
        argument_type, code = args
        local_type = no_value_type()
        break_types = infer_all()
        local_initializer = nop()
    elif len(args) == 3:
        extra_statics = {}
        argument_type, break_types, code = args
        local_type = no_value_type()
        local_initializer = nop()
    elif len(args) == 5:
        extra_statics = {}
        argument_type, break_types, local_type, local_initializer, code = args
    elif len(args) == 6:
        extra_statics, argument_type, break_types, local_type, local_initializer, code = args
    else:
        raise FatalError()

    check_is_opcode(local_initializer)
    check_is_opcode(argument_type)
    check_is_opcode(local_type)
    check_is_opcode(code)
    if not isinstance(break_types, dict):
        raise FatalError()

    static = spread_dict(
        {
            "argument": argument_type,
            "local": local_type,
            "outer": inferred_type(),
            "break_types": object_template_op(break_types)
        }, extra_statics)

    func = spread_dict(
        {
            "code": code,
            "static": object_template_op(static),
            "local_initializer": local_initializer
        }, **kwargs)

    return PythonObject(func)
예제 #11
0
    def get_next_frame(self, thing):
        if self.fully_wound():
            if get_environment().frame_shortcut and not is_restartable(thing):
                return PASS_THROUGH_FRAME

            if self.mode != "wind":
                raise FatalError()
            return Frame(self, thing)
        else:
            if self.mode not in ("shift", "reset"):
                raise FatalError()
            old_frame = self.frames[self.index]
            if old_frame.target is not thing:
                raise FatalError()
            return old_frame
예제 #12
0
 def pop_restart_value(self):
     if not self.has_restart_value():
         raise FatalError()
     restart_value = self.restart_value
     self.restart_value = MISSING
     self.manager.mode = "wind"
     return restart_value
예제 #13
0
 def build(self):
     result = dict(self.result)
     if self.target:
         if getattr(self.target, "break_types", None) is not None:
             raise FatalError()
         self.target.break_types = result
     return result
예제 #14
0
    def __init__(self, frame_manager, frames, callback, restart_type,
                 break_types):
        if not isinstance(frame_manager, FrameManager):
            raise FatalError()
        self.frame_manager = frame_manager
        self.frames = frames
        self.callback = callback
        self.restart_type = restart_type
        self.break_types = break_types

        for frame in frames:
            if frame.has_restart_value():
                raise FatalError()

        if break_types is None:
            raise FatalError()
예제 #15
0
def prepare_piece_of_context(declared_type, suggested_type):
    if suggested_type and not isinstance(suggested_type, Type):
        raise FatalError()

    final_type = prepare_lhs_type(declared_type, suggested_type)

    if not check_dangling_inferred_types(final_type, {}):
        raise PreparationException("Invalid inferred types")

    is_piece_self_consistent_reasoner = Reasoner()
    if isinstance(
            final_type, CompositeType
    ) and not final_type.is_self_consistent(is_piece_self_consistent_reasoner):
        raise FatalError(is_piece_self_consistent_reasoner.to_message())

    return final_type
예제 #16
0
 def is_copyable_to(self, other, reasoner):
     if isinstance(other, OneOfType):
         raise FatalError()
     for t in self.types:
         if not other.is_copyable_from(t, reasoner):
             reasoner.push_not_copyable_type(other, t)
             return False
     return True
예제 #17
0
 def invoke(self, restart_value, frame_manager):
     if not self.restart_type.is_copyable_from(
             get_type_of_value(restart_value), DUMMY_REASONER):
         raise FatalError()
     self.restarted = True
     if self.frame_manager.fully_wound():
         self.frame_manager.prepare_restart(self.frames, restart_value)
     return self.callback()
예제 #18
0
    def prepare_restart(self, frames, restart_value):
        self.mode = "reset"
        self.frames = self.frames + [f.clone() for f in frames]

        for f in self.frames:
            if f.has_restart_value():
                raise FatalError()

        self.frames[-1].restart_value = restart_value
예제 #19
0
    def slice_frames(self):
        if self.fully_wound():
            raise FatalError()

        self.mode = "wind"

        sliced_frames = self.frames[self.index:]
        self.frames = self.frames[:self.index]
        return sliced_frames
예제 #20
0
def unbound_dereference(name, **kwargs):
    if not isinstance(name, basestring):
        raise FatalError()
    return PythonObject(spread_dict(
        {
            "opcode": "unbound_dereference",
            "reference": name
        }, **kwargs),
                        debug_reason="code")
예제 #21
0
def dynamic_dereference_op(reference, **kwargs):
    if not isinstance(reference, basestring):
        raise FatalError()
    return PythonObject(spread_dict(
        {
            "opcode": "dynamic_dereference",
            "reference": reference
        }, **kwargs),
                        debug_reason="code")
예제 #22
0
def wrap_as_statement(node):
    """
    Python ast treats statements and expressions differently. Always returns a ast.stmt
    object, even if passed an ast.expr.
    """
    if isinstance(node, ast.stmt):
        return node
    if isinstance(node, ast.expr):
        return ast.Expr(node)
    raise FatalError()
예제 #23
0
def environment(rtti=MISSING,
                frame_shortcut=MISSING,
                validate_flow_control=MISSING,
                opcode_bindings=MISSING,
                consume_python_objects=MISSING,
                return_value_optimization=MISSING,
                transpile=MISSING,
                base=False):
    environment = get_environment()
    if (environment and environment.transpile or transpile is True
        ) and not (environment and environment.return_value_optimization
                   or return_value_optimization is True):
        raise FatalError("Transpiling has return_value_optomization baked in")

    if base:
        global environment_stack
        if environment_stack is not None:
            raise FatalError()
        environment_stack = []
        new_environment = Environment(
            rtti=rtti,
            frame_shortcut=frame_shortcut,
            validate_flow_control=validate_flow_control,
            opcode_bindings=opcode_bindings,
            consume_python_objects=consume_python_objects,
            return_value_optimization=return_value_optimization,
            transpile=transpile)
    else:
        new_environment = get_environment().clone(
            rtti=rtti,
            frame_shortcut=frame_shortcut,
            validate_flow_control=validate_flow_control,
            opcode_bindings=opcode_bindings,
            consume_python_objects=consume_python_objects,
            return_value_optimization=return_value_optimization,
            transpile=transpile)

    environment_stack.append(new_environment)

    try:
        yield new_environment
    finally:
        environment_stack.pop()
예제 #24
0
def unwrap_expr(node):
    """
    Returns an ast.expr from a statement, but throws an exception if the statement
    can not be converted to an expression.
    """
    if isinstance(node, ast.Expr):
        return node.value
    if isinstance(node, ast.expr):
        return node
    raise FatalError()
예제 #25
0
def function_type(argument_type, break_types):
    if not isinstance(break_types, dict):
        raise FatalError()
    return object_template_op(
        {
            "type": literal_op("Function"),
            "argument": argument_type,
            "break_types": object_template_op(break_types)
        },
        debug_reason="type-literal")
예제 #26
0
def unbound_assignment(name, rvalue):
    if not isinstance(name, basestring):
        raise FatalError()
    check_is_opcode(rvalue)
    return PythonObject(
        {
            "opcode": "unbound_assignment",
            "reference": name,
            "rvalue": rvalue
        },
        debug_reason="code")
예제 #27
0
def build_closed_function_type(data):
    if not isinstance(data._get("break_types"), Universal):
        raise FatalError()
    for mode, break_types in data._get("break_types")._items():
        if not isinstance(mode, basestring):
            raise FatalError()
        if not isinstance(break_types, Universal):
            raise FatalError()
        for break_type in break_types._values():
            if not isinstance(break_type, Universal):
                raise FatalError(break_type)

    return ClosedFunctionType(
        enrich_type(data._get("argument")),
        PythonDict(
            {
                mode: PythonList(
                    [enrich_break_type(b) for b in break_types._values()])
                for mode, break_types in data._get("break_types")._items()
            },
            bind=DEFAULT_READONLY_COMPOSITE_TYPE,
            debug_reason="type"))
예제 #28
0
def transform_op(*args, **kwargs):
    if len(args) == 1:
        output, = args
        input = code = None
    elif len(args) == 3:
        input, output, code = args
    else:
        raise FatalError()
    if code:
        check_is_opcode(code)
    if input and not isinstance(input, basestring):
        raise FatalError()
    if not isinstance(output, basestring):
        raise FatalError()
    op = {
        "opcode": "transform",
        "output": output,
    }
    if input:
        op["input"] = input
        op["code"] = code
    return PythonObject(spread_dict(op, **kwargs), debug_reason="code")
예제 #29
0
def enrich_type(data):
    from lockdown.type_system.managers import get_manager
    if not isinstance(data, Universal):
        raise PreparationException("Unknown type data {}, {}".format(
            data, type(data)))
    if not data._contains("type"):
        raise PreparationException("Missing type in data {}".format(data))
    if data._get("type") not in TYPES:
        raise PreparationException("Unknown type {}".format(data.type))

    new_type = TYPES[data._get("type")](data)
    if not isinstance(new_type, Type):
        raise FatalError(data)

    return new_type
예제 #30
0
    def __init__(self, data, code, prepare_context, static, argument_type,
                 outer_type, local_type, local_initializer, break_types):
        self.data = data
        self.code = code
        self.prepare_context = prepare_context
        self.static = static
        self.argument_type = argument_type
        self.outer_type = outer_type
        self.local_type = local_type
        self.local_initializer = local_initializer
        self.break_types = break_types

        self.types_context = Universal(
            True,
            initial_wrapped={
                "outer": self.outer_type,
                "argument": self.argument_type
            },
            debug_reason="local-initialization-context")

        self.local_initialization_context_type = UniversalObjectType(
            {
                "outer": self.outer_type,
                "argument": self.argument_type,
                #            "types": readonly_rich_composite_type
            },
            wildcard_type=AnyType(),
            name="local-initialization-context-type")

        self.execution_context_type = UniversalObjectType(
            {
                #            "prepare": readonly_rich_composite_type,
                "outer": self.outer_type,
                "argument": self.argument_type,
                #            "static": readonly_rich_composite_type,
                "local": self.local_type,
                #            "types": readonly_rich_composite_type
            },
            wildcard_type=AnyType(),
            name="code-execution-context-type")

        if not self.execution_context_type.is_self_consistent(DUMMY_REASONER):
            raise FatalError()

        self.compiled_ast = None