Module opshin.rewrite.rewrite_import_hashlib
Expand source code
from typing import Optional
from enum import Enum, auto
from ..util import CompilingNodeTransformer
from ..typed_ast import *
"""
Checks that there was an import of dataclass if there are any class definitions
"""
@dataclass(frozen=True, unsafe_hash=True)
class HashType(ClassType):
"""A pseudo class that is the result of python hash functions that need a 'digest' call"""
def attribute_type(self, attr) -> "Type":
if attr == "digest":
return InstanceType(FunctionType(frozenlist([]), ByteStringInstanceType))
raise NotImplementedError("HashType only has attribute 'digest'")
def attribute(self, attr) -> plt.AST:
if attr == "digest":
return plt.Lambda(["self"], plt.Var("self"))
raise NotImplementedError("HashType only has attribute 'digest'")
def __ge__(self, other):
return isinstance(other, HashType)
HashInstanceType = InstanceType(HashType())
class PythonHashlib(Enum):
sha256 = auto()
sha3_256 = auto()
blake2b = auto()
PythonHashlibTypes = {
PythonHashlib.sha256: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
PythonHashlib.sha3_256: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
PythonHashlib.blake2b: InstanceType(
FunctionType(
frozenlist([ByteStringInstanceType]),
HashInstanceType,
)
),
}
PythonHashlibImpls = {
PythonHashlib.sha256: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Sha2_256(plt.Var("x"))))
),
PythonHashlib.sha3_256: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Sha3_256(plt.Var("x"))))
),
PythonHashlib.blake2b: force_params(
plt.Lambda(["x"], plt.Lambda(["_"], plt.Blake2b_256(plt.Var("x"))))
),
}
class RewriteImportHashlib(CompilingNodeTransformer):
step = "Resolving imports and usage of hashlib"
imports_hashlib = False
def visit_ImportFrom(self, node: ImportFrom) -> typing.List[AST]:
if node.module != "hashlib":
return node
additional_assigns = []
for n in node.names:
imported_fun = None
for h in PythonHashlib:
if h.name == n.name:
imported_fun = h
assert (
imported_fun is not None
), f"Unsupported function import from hashlib '{n.name}"
typ = PythonHashlibTypes[imported_fun]
imported_name = n.name if n.asname is None else n.asname
additional_assigns.append(
TypedAssign(
targets=[TypedName(id=imported_name, typ=typ, ctx=Store())],
value=RawPlutoExpr(typ=typ, expr=PythonHashlibImpls[imported_fun]),
)
)
return additional_assigns
Classes
class HashType
-
A pseudo class that is the result of python hash functions that need a 'digest' call
Expand source code
@dataclass(frozen=True, unsafe_hash=True) class HashType(ClassType): """A pseudo class that is the result of python hash functions that need a 'digest' call""" def attribute_type(self, attr) -> "Type": if attr == "digest": return InstanceType(FunctionType(frozenlist([]), ByteStringInstanceType)) raise NotImplementedError("HashType only has attribute 'digest'") def attribute(self, attr) -> plt.AST: if attr == "digest": return plt.Lambda(["self"], plt.Var("self")) raise NotImplementedError("HashType only has attribute 'digest'") def __ge__(self, other): return isinstance(other, HashType)
Ancestors
Methods
def attribute(self, attr) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.attribute
The attributes of this class. Needs to be a lambda that expects as first argument the object itself
def attribute_type(self, attr) ‑> Type
-
Inherited from:
ClassType
.attribute_type
The types of the named attributes of this class
def binop(self, binop: ast.operator, other: ast.AST) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.binop
Implements a binary operation between self and other
def binop_type(self, binop: ast.operator, other: Type) ‑> Type
-
Inherited from:
ClassType
.binop_type
Type of a binary operation between self and other.
def cmp(self, op: ast.cmpop, o: Type) ‑> pluthon.pluthon_ast.AST
-
The implementation of comparing this type to type o via operator op. Returns a lambda that expects as first argument the object itself and as second …
def constr(self) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.constr
The constructor for this class
def constr_type(self) ‑> InstanceType
-
Inherited from:
ClassType
.constr_type
The type of the constructor for this class
def copy_only_attributes(self) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.copy_only_attributes
Returns a copy of this type with only the declared attributes (mapped to builtin values, thus checking atomic types too). For anything but record …
def id_map(self, skip_constructor: bool = False) ‑> str
-
Inherited from:
ClassType
.id_map
Returns a map from the constructor id to a descriptive typestring
def stringify(self, recursive: bool = False) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.stringify
Returns a stringified version of the object …
def unop(self, unop: ast.unaryop) ‑> pluthon.pluthon_ast.AST
-
Inherited from:
ClassType
.unop
Implements a unary operation on self
def unop_type(self, unop: ast.unaryop) ‑> Type
-
Inherited from:
ClassType
.unop_type
Type of a unary operation on self.
class PythonHashlib (value, names=None, *, module=None, qualname=None, type=None, start=1)
-
An enumeration.
Expand source code
class PythonHashlib(Enum): sha256 = auto() sha3_256 = auto() blake2b = auto()
Ancestors
- enum.Enum
Class variables
var blake2b
var sha256
var sha3_256
class RewriteImportHashlib
-
A :class:
NodeVisitor
subclass that walks the abstract syntax tree and allows modification of nodes.The
NodeTransformer
will walk the AST and use the return value of the visitor methods to replace or remove the old node. If the return value of the visitor method isNone
, the node will be removed from its location, otherwise it is replaced with the return value. The return value may be the original node in which case no replacement takes place.Here is an example transformer that rewrites all occurrences of name lookups (
foo
) todata['foo']
::class RewriteName(NodeTransformer):
def visit_Name(self, node): return Subscript( value=Name(id='data', ctx=Load()), slice=Constant(value=node.id), ctx=node.ctx )
Keep in mind that if the node you're operating on has child nodes you must either transform the child nodes yourself or call the :meth:
generic_visit
method for the node first.For nodes that were part of a collection of statements (that applies to all statement nodes), the visitor may also return a list of nodes rather than just a single node.
Usually you use the transformer like this::
node = YourTransformer().visit(node)
Expand source code
class RewriteImportHashlib(CompilingNodeTransformer): step = "Resolving imports and usage of hashlib" imports_hashlib = False def visit_ImportFrom(self, node: ImportFrom) -> typing.List[AST]: if node.module != "hashlib": return node additional_assigns = [] for n in node.names: imported_fun = None for h in PythonHashlib: if h.name == n.name: imported_fun = h assert ( imported_fun is not None ), f"Unsupported function import from hashlib '{n.name}" typ = PythonHashlibTypes[imported_fun] imported_name = n.name if n.asname is None else n.asname additional_assigns.append( TypedAssign( targets=[TypedName(id=imported_name, typ=typ, ctx=Store())], value=RawPlutoExpr(typ=typ, expr=PythonHashlibImpls[imported_fun]), ) ) return additional_assigns
Ancestors
- CompilingNodeTransformer
- TypedNodeTransformer
- ast.NodeTransformer
- ast.NodeVisitor
Class variables
var imports_hashlib
var step
Methods
def visit(self, node)
-
Inherited from:
CompilingNodeTransformer
.visit
Visit a node.
def visit_ImportFrom(self, node: ast.ImportFrom) ‑> List[ast.AST]