85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
|
"""Intermediate representation of modules."""
|
||
|
|
||
|
from typing import List, Tuple, Dict
|
||
|
|
||
|
from mypyc.common import JsonDict
|
||
|
from mypyc.ir.ops import DeserMaps
|
||
|
from mypyc.ir.rtypes import RType, deserialize_type
|
||
|
from mypyc.ir.func_ir import FuncIR, FuncDecl
|
||
|
from mypyc.ir.class_ir import ClassIR
|
||
|
|
||
|
|
||
|
class ModuleIR:
|
||
|
"""Intermediate representation of a module."""
|
||
|
|
||
|
def __init__(
|
||
|
self,
|
||
|
fullname: str,
|
||
|
imports: List[str],
|
||
|
functions: List[FuncIR],
|
||
|
classes: List[ClassIR],
|
||
|
final_names: List[Tuple[str, RType]]) -> None:
|
||
|
self.fullname = fullname
|
||
|
self.imports = imports[:]
|
||
|
self.functions = functions
|
||
|
self.classes = classes
|
||
|
self.final_names = final_names
|
||
|
|
||
|
def serialize(self) -> JsonDict:
|
||
|
return {
|
||
|
'fullname': self.fullname,
|
||
|
'imports': self.imports,
|
||
|
'functions': [f.serialize() for f in self.functions],
|
||
|
'classes': [c.serialize() for c in self.classes],
|
||
|
'final_names': [(k, t.serialize()) for k, t in self.final_names],
|
||
|
}
|
||
|
|
||
|
@classmethod
|
||
|
def deserialize(cls, data: JsonDict, ctx: DeserMaps) -> 'ModuleIR':
|
||
|
return ModuleIR(
|
||
|
data['fullname'],
|
||
|
data['imports'],
|
||
|
[ctx.functions[FuncDecl.get_id_from_json(f)] for f in data['functions']],
|
||
|
[ClassIR.deserialize(c, ctx) for c in data['classes']],
|
||
|
[(k, deserialize_type(t, ctx)) for k, t in data['final_names']],
|
||
|
)
|
||
|
|
||
|
|
||
|
def deserialize_modules(data: Dict[str, JsonDict], ctx: DeserMaps) -> Dict[str, ModuleIR]:
|
||
|
"""Deserialize a collection of modules.
|
||
|
|
||
|
The modules can contain dependencies on each other.
|
||
|
|
||
|
Arguments:
|
||
|
data: A dict containing the modules to deserialize.
|
||
|
ctx: The deserialization maps to use and to populate.
|
||
|
They are populated with information from the deserialized
|
||
|
modules and as a precondition must have been populated by
|
||
|
deserializing any dependencies of the modules being deserialized
|
||
|
(outside of dependencies between the modules themselves).
|
||
|
|
||
|
Returns a map containing the deserialized modules.
|
||
|
"""
|
||
|
for mod in data.values():
|
||
|
# First create ClassIRs for every class so that we can construct types and whatnot
|
||
|
for cls in mod['classes']:
|
||
|
ir = ClassIR(cls['name'], cls['module_name'])
|
||
|
assert ir.fullname not in ctx.classes, "Class %s already in map" % ir.fullname
|
||
|
ctx.classes[ir.fullname] = ir
|
||
|
|
||
|
for mod in data.values():
|
||
|
# Then deserialize all of the functions so that methods are available
|
||
|
# to the class deserialization.
|
||
|
for method in mod['functions']:
|
||
|
func = FuncIR.deserialize(method, ctx)
|
||
|
assert func.decl.id not in ctx.functions, (
|
||
|
"Method %s already in map" % func.decl.fullname)
|
||
|
ctx.functions[func.decl.id] = func
|
||
|
|
||
|
return {k: ModuleIR.deserialize(v, ctx) for k, v in data.items()}
|
||
|
|
||
|
|
||
|
# ModulesIRs should also always be an *OrderedDict*, but if we
|
||
|
# declared it that way we would need to put it in quotes everywhere...
|
||
|
ModuleIRs = Dict[str, ModuleIR]
|