aboutsummaryrefslogtreecommitdiff
path: root/pyecsca/ec/op.py
blob: 169f3bb9860ab0a704d773aa824a2267e742b61f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
from ast import Module, walk, Name, BinOp, operator
from types import CodeType
from typing import FrozenSet, Optional

from .mod import Mod


class Op(object):
    result: str
    parameters: FrozenSet[str]
    variables: FrozenSet[str]

    def __call__(self, *args, **kwargs: Mod) -> Mod:
        """Execute this operation with kwargs."""
        raise NotImplementedError


class CodeOp(Op):
    code: Module
    operator: Optional[operator]
    compiled: CodeType

    def __init__(self, code: Module):
        self.code = code
        assign = code.body[0]
        self.result = assign.targets[0].id
        params = set()
        variables = set()
        op = None
        for node in walk(assign.value):
            if isinstance(node, Name):
                name = node.id
                if name.isupper():
                    variables.add(name)
                else:
                    params.add(name)
            elif isinstance(node, BinOp):
                op = node.op
        self.operator = op
        self.parameters = frozenset(params)
        self.variables = frozenset(variables)
        self.compiled = compile(self.code, "", mode="exec")

    def __repr__(self):
        return f"CodeOp({self.result} = f(params={self.parameters}, vars={self.variables}))"

    def __call__(self, *args, **kwargs: Mod) -> Mod:
        loc = dict(kwargs)
        exec(self.compiled, {}, loc)
        return loc[self.result]