def variables(self) -> Set[VariableIdentifier]: variables = set() visited, worklist = set(), Queue() worklist.put(self.cfg.in_node) while not worklist.empty(): current = worklist.get() if current.identifier not in visited: visited.add(current.identifier) for stmt in current.stmts: if isinstance(stmt, Assignment) and isinstance(stmt.left, VariableAccess): variable = stmt.left.variable variables.add(variable) if isinstance(variable.typ, (StringLyraType, ListLyraType)): variables.add(LengthIdentifier(variable)) if isinstance(current, Loop): edges = self.cfg.edges.items() conds = [edge.condition for nodes, edge in edges if nodes[0] == current] for cond in [c for c in conds if isinstance(c, Call)]: for arg in [a for a in cond.arguments if isinstance(a, VariableAccess)]: variable = arg.variable variables.add(arg.variable) if isinstance(variable.typ, (StringLyraType, ListLyraType)): variables.add(LengthIdentifier(variable)) for node in self.cfg.successors(current): worklist.put(node) return variables
def visit_Literal(self, expr, state=None, evaluation=None): if expr in evaluation: return evaluation evaluation[expr] = state.lattices[expr.typ].from_literal(expr) if isinstance(expr.typ, StringLyraType): evaluation[LengthIdentifier(expr)] = IntervalLattice(len(expr.val), len(expr.val)) return evaluation
def forget_variable(self, var: VariableIdentifier): if var in self.store.keys(): self.store[var].top() if isinstance(var.typ, SequenceLyraType): length = LengthIdentifier(var) self.store[length] = IntervalLattice(lower=0) else: raise ValueError( f"Variable can only be forgotten if it is abstracted in the store" )
def __init__(self, variables: Set[VariableIdentifier], precursory: InputMixin = None): """Map each program variable to the interval representing its value. :param variables: set of program variables """ lattices = defaultdict(lambda: RangeLattice) super(IntervalStateWithSummarization, self).__init__(variables, lattices) InputMixin.__init__(self, precursory) for v in self.variables: if isinstance(v.typ, SequenceLyraType): self.lengths[LengthIdentifier(v)] = lattices[IntegerLyraType()](lower=0)
def remove_variable(self, var: VariableIdentifier): if var in self.store.keys(): self.variables.remove(var) del self.store[var] if isinstance(var.typ, SequenceLyraType): length = LengthIdentifier(var) self.variables.remove(length) del self.store[length] else: raise ValueError( f"Variable can only be removed from a store if it is already present" )
def add_variable(self, var: VariableIdentifier): if var not in self.store.keys(): self.variables.add(var) self.store[var] = IntervalLattice() # top if isinstance(var.typ, SequenceLyraType): length = LengthIdentifier(var) self.variables.add(length) self.store[length] = IntervalLattice(lower=0) else: raise ValueError( f"Variable can not be added to a store if it is already present" )
def len_call_semantics(self, stmt: Call, state: State) -> State: """Semantics of a call to 'len'. :param stmt: call to 'len' to be executed :param state: state before executing the call statement :return: state modified by the call statement """ assert len(stmt.arguments) == 1 # unary operations have exactly one argument argument = stmt.arguments[0] if isinstance(argument, VariableAccess): variable = argument.variable state.result = {LengthIdentifier(variable)} return state error = f"Semantics for length of {argument} is not yet implemented!" raise NotImplementedError(error)
def visit_LengthIdentifier(self, expr: LengthIdentifier): return LengthIdentifier(expr.variable)
def len_call_semantics(self, stmt: Call, state: State, interpreter: Interpreter) -> State: """Semantics of a call to 'len'. :param stmt: call to 'len' to be executed :param state: state before executing the call statement :return: state modified by the call statement """ assert len( stmt.arguments) == 1 # unary operations have exactly one argument argument = stmt.arguments[0] if isinstance(argument, VariableAccess): variable = argument.variable state.result = {LengthIdentifier(variable)} return state elif isinstance(argument, ListDisplayAccess): items = [ self.semantics(item, state, interpreter).result for item in argument.items ] result = set() for combination in itertools.product(*items): display = ListDisplay(argument.typ, list(combination)) result.add(LengthIdentifier(display)) state.result = result return state elif isinstance(argument, TupleDisplayAccess): items = [ self.semantics(item, state, interpreter).result for item in argument.items ] result = set() for combination in itertools.product(*items): display = TupleDisplay(argument.typ, list(combination)) result.add(LengthIdentifier(display)) state.result = result return state elif isinstance(argument, SetDisplayAccess): items = [ self.semantics(item, state, interpreter).result for item in argument.items ] result = set() for combination in itertools.product(*items): display = SetDisplay(argument.typ, list(combination)) result.add(LengthIdentifier(display)) state.result = result return state elif isinstance(argument, DictDisplayAccess): keys = [ self.semantics(k, state, interpreter).result for k in argument.keys ] values = [ self.semantics(v, state, interpreter).result for v in argument.values ] result = set() if keys: # not empty List[Set[Expression]] for combination in itertools.product( *map(itertools.product, keys, values)): unzip = list(zip(*combination)) display = DictDisplay(argument.typ, list(unzip[0]), list(unzip[1])) result.add(LengthIdentifier(display)) else: result.add( LengthIdentifier(DictDisplay(argument.typ, list(), list()))) state.result = result return state error = f"Semantics for length of {argument} is not yet implemented!" raise NotImplementedError(error)