def get_pedal_type_from_type_literal(value, type_space=None) -> Type: if value == list: return ListType(empty=False) elif value == dict: return DictType(empty=False) elif isinstance(value, list): if value: return ListType(empty=False, subtype=get_pedal_type_from_type_literal( value[0], type_space)) else: return ListType(empty=True) elif isinstance(value, dict): if not value: return DictType(empty=True) if all(isinstance(value, str) for k in value.keys()): return DictType(literals=[LiteralStr(s) for s in value.keys()], values=[ get_pedal_type_from_type_literal( vv, type_space) for vv in value.values() ]) return DictType(keys=[ get_pedal_type_from_type_literal(k, type_space) for k in value.keys() ], values=[ get_pedal_type_from_type_literal(vv, type_space) for vv in value.values() ]) elif isinstance(value, type): return get_pedal_type_from_str(value.__name__) else: return get_pedal_type_from_str(str(value))
def _builtin_zip(tifa, function_type, callee, args, position): """ Definition of the built-in zip function, which consumes a series of sequences and returns a list of tuples, with each tuple composed of the elements of the sequence paired (or rather, tupled) together. """ if args: tupled_types = TupleType(subtypes=[]) for arg in args: tupled_types.subtypes.append(arg.index(0)) return ListType(tupled_types, empty=False) return ListType(empty=True)
def visit_List(self, node): """ Args: node: Returns: """ result_type = ListType() if node.elts: result_type.empty = False # TODO: confirm homogenous subtype for elt in node.elts: result_type.subtype = self.visit(elt) else: result_type.empty = True return result_type
def make_record(a_record) -> Type: if isinstance(a_record, dict): return DictType( literals=[LiteralStr(s) for s in a_record.keys()], values=[make_record(value) for value in a_record.values()]) elif isinstance(a_record, list): return ListType(subtype=make_record(a_record[0])) else: return get_pedal_type_from_str(str(a_record))
def get_pedal_type_from_value(value, type_space=None) -> Type: """ Converts the Python value to a Pedal Type """ if isinstance(value, bool): return BoolType() if isinstance(value, (int, float, complex)): return NumType() if isinstance(value, str): return StrType() if isinstance(value, type(None)): return NoneType() if isinstance(value, tuple): return TupleType( (get_pedal_type_from_value(t, type_space) for t in value)) if isinstance(value, set): return SetType( (get_pedal_type_from_value(t, type_space) for t in value)) if isinstance(value, frozenset): return FrozenSetType( (get_pedal_type_from_value(t, type_space) for t in value)) if isinstance(value, list): if value: return ListType(empty=False, subtype=get_pedal_type_from_value(value[0])) else: return ListType(empty=True) if isinstance(value, dict): if not value: return DictType(empty=True) if all(isinstance(value, str) for k in value.keys()): return DictType(literals=[LiteralStr(s) for s in value.keys()], values=[ get_pedal_type_from_value(vv, type_space) for vv in value.values() ]) return DictType(keys=[ get_pedal_type_from_ast(k, type_space) for k in value.keys() ], values=[ get_pedal_type_from_ast(vv, type_space) for vv in value.values() ]) return UnknownType()
def visit_ListComp(self, node): """ Args: node: Returns: """ # TODO: Handle comprehension scope for generator in node.generators: self.visit(generator) return ListType(self.visit(node.elt))
def get_pedal_type_from_json(val): """ Args: val: Returns: """ if val['type'] == 'DictType': values = [get_pedal_type_from_json(v) for v in val['values']] empty = val.get('empty', None) if 'literals' in val: literals = [ get_pedal_literal_from_json(l) for l in val['literals'] ] return DictType(empty, literals=literals, values=values) else: keys = [get_pedal_type_from_json(k) for k in val['keys']] return DictType(empty, keys=keys, values=values) elif val['type'] == 'ListType': return ListType(get_pedal_type_from_json(val.get('subtype', None)), val.get('empty', None)) elif val['type'] == 'StrType': return StrType(val.get('empty', None)) elif val['type'] == 'BoolType': return BoolType() elif val['type'] == 'NoneType': return NoneType() elif val['type'] == 'NumType': return NumType() elif val['type'] == 'ModuleType': submodules = { name: get_pedal_type_from_json(m) for name, m in val.get('submodules', {}).items() } fields = { name: get_pedal_type_from_json(m) for name, m in val.get('fields', {}).items() } return ModuleType(name=val.get('name'), submodules=submodules, fields=fields) elif val['type'] == 'FunctionType': returns = get_pedal_type_from_json( val.get('returns', {'type': 'NoneType'})) return FunctionType(name=val.get('name'), returns=returns)
def get_builtin_function(name): """ Args: name: Returns: """ # Void Functions if name == "print": return FunctionType(name="print", returns=NoneType()) # Math Functions elif name in ("int", "abs", "float", "len", "ord", "pow", "round", "sum"): return FunctionType(name=name, returns=NumType()) # Boolean Functions elif name in ("bool", "all", "any", "isinstance"): return FunctionType(name=name, returns=BoolType()) # String Functions elif name in ("str", 'chr', 'bin', 'repr', 'input'): return FunctionType(name=name, returns=StrType()) # File Functions elif name == "open": return FunctionType(name="open", returns=FileType()) # List Functions elif name == "map": return FunctionType(name="map", returns=ListType(empty=False)) elif name == "list": return FunctionType(name="list", definition=_builtin_sequence_constructor(ListType)) # Set Functions elif name == "set": return FunctionType(name="set", definition=_builtin_sequence_constructor(SetType)) # Dict Functions elif name == "dict": return FunctionType(name="dict", returns=DictType()) # Pass through elif name == "sorted": return FunctionType(name="sorted", returns='identity') elif name == "reversed": return FunctionType(name="reversed", returns='identity') elif name == "filter": return FunctionType(name="filter", returns='identity') # Special Functions elif name == "type": return FunctionType(name="type", returns=UnknownType()) elif name == "range": return FunctionType(name="range", returns=ListType(NumType(), empty=False)) elif name == "dir": return FunctionType(name="dir", returns=ListType(StrType(), empty=False)) elif name == "max": return FunctionType(name="max", returns='element') elif name == "min": return FunctionType(name="min", returns='element') elif name == "zip": return FunctionType(name="zip", returns=_builtin_zip) elif name == "__import__": return FunctionType(name="__import__", returns=ModuleType()) elif name == "globals": return FunctionType(name="globals", returns=DictType(keys=StrType(), values=UnknownType(), empty=False)) elif name in ("classmethod", "staticmethod"): return FunctionType(name=name, returns='identity') elif name in ("__name__", ): return StrType()
def get_pedal_type_from_ast(value: ast.AST, type_space=None) -> Type: """ Determines the Pedal Type from this ast node. Args: value (ast.AST): An AST node. Returns: Type: A Pedal Type """ try: if isinstance(value, ast.Constant): return get_pedal_type_from_value(value.value, type_space) except AttributeError as e: pass if isinstance(value, ast.Name): return get_pedal_type_from_str(value.id, type_space) elif isinstance(value, ast.Str): return StrType(bool(value.s)) elif isinstance(value, ast.List): return ListType(subtype=(get_pedal_type_from_ast( value.elts[0], type_space) if value.elts else None), empty=not bool(value.elts)) elif isinstance(value, ast.Set): return SetType(subtype=(get_pedal_type_from_ast( value.elts[0], type_space) if value.elts else None), empty=not bool(value.elts)) elif isinstance(value, ast.Tuple): return TupleType(subtypes=[ get_pedal_type_from_ast(e, type_space) for e in value.elts ]) elif isinstance(value, ast.Dict): if not value.keys: return DictType(empty=True) if all(isinstance(k, ast.Str) for k in value.keys): return DictType(literals=[LiteralStr(s.s) for s in value.keys], values=[ get_pedal_type_from_ast(vv, type_space) for vv in value.values ]) return DictType( keys=[get_pedal_type_from_ast(k, type_space) for k in value.keys], values=[ get_pedal_type_from_ast(vv, type_space) for vv in value.values ]) # Support new style subscripts (e.g., ``list[int]``) elif ((IS_PYTHON_39 and isinstance(value, ast.Subscript)) or isinstance(value, ast.Subscript) and isinstance(value.slice, ast.Index)): if IS_PYTHON_39: slice = value.slice else: slice = value.slice.value if isinstance(value.value, ast.Name): if isinstance(slice, ast.Name): subtype = get_pedal_type_from_str(slice.id) if value.value.id == "list": return ListType(subtype=subtype, empty=False) if value.value.id == "set": return SetType(subtype=subtype, empty=False) if value.value.id == "tuple": return TupleType(subtypes=(subtype, )) if value.value.id == "frozenset": return FrozenSetType(subtype=subtype, empty=False) elif isinstance(slice, ast.Tuple): subtypes = [ get_pedal_type_from_ast(e, type_space) for e in slice.elts ] if value.value.id == "tuple": return TupleType(subtypes=subtypes) elif value.value.id == "dict" and len(subtypes) == 2: return DictType(keys=subtypes[0], values=subtypes[1]) # Top-level Module, parse it and get it back if isinstance(value, ast.Module) and value.body: if isinstance(value.body[0], ast.Expr): return get_pedal_type_from_ast(value.body[0].value, type_space) return UnknownType()