Skip to content

Commit

Permalink
Merge 91133ed into db617c1
Browse files Browse the repository at this point in the history
  • Loading branch information
mlin committed Nov 1, 2020
2 parents db617c1 + 91133ed commit 2b5c196
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 58 deletions.
68 changes: 56 additions & 12 deletions WDL/Expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Base(SourceNode, ABC):
_type: Optional[Type.Base] = None
_check_quant: bool = True
_stdlib: "Optional[StdLib.Base]" = None
_struct_types: Optional[Env.Bindings[Dict[str, Type.Base]]] = None

@property
def type(self) -> Type.Base:
Expand All @@ -48,6 +49,7 @@ def infer_type(
type_env: Env.Bindings[Type.Base],
stdlib: StdLib.Base,
check_quant: bool = True,
struct_types: Optional[Env.Bindings[Dict[str, Type.Base]]] = None,
) -> "Base":
"""infer_type(self, type_env : Env.Bindings[Type.Base], stdlib : StdLib.Base) -> WDL.Expr.Base
Expand All @@ -69,13 +71,21 @@ def infer_type(
with Error.multi_context() as errors:
for child in self.children:
assert isinstance(child, Base)
errors.try1(lambda child=child: child.infer_type(type_env, stdlib, check_quant))
# invoke derived-class logic. we pass check_quant and stdlib hackily
# through instance variables since only some subclasses use them.
errors.try1(
lambda child=child: child.infer_type(
type_env, stdlib, check_quant, struct_types
)
)
# invoke derived-class logic. we pass check_quant, stdlib, and struct_types hackily through
# instance variables since only some subclasses use them.
self._check_quant = check_quant
self._stdlib = stdlib
self._type = self._infer_type(type_env)
self._stdlib = None
self._struct_types = struct_types
try:
self._type = self._infer_type(type_env)
finally:
self._stdlib = None
self._struct_types = None
assert self._type and isinstance(self.type, Type.Base)
return self

Expand Down Expand Up @@ -619,13 +629,27 @@ class Struct(Base):
can be coerced to a specific struct type during typechecking.
"""

def __init__(self, pos: SourcePosition, members: List[Tuple[str, Base]]):
struct_type_name: Optional[str]
"""
:type: Optional[str]
In WDL 2.0+ each struct literal may specify the intended struct type name.
"""

def __init__(
self,
pos: SourcePosition,
members: List[Tuple[str, Base]],
struct_type_name: Optional[str] = None,
):
super().__init__(pos)
self.members = {}
for (k, v) in members:
if k in self.members:
raise Error.MultipleDefinitions(self.pos, "duplicate keys " + k)
self.members[k] = v
self.struct_type_name = struct_type_name
assert struct_type_name is None or isinstance(struct_type_name, str), str(struct_type_name)

def __str__(self):
members = []
Expand All @@ -639,16 +663,36 @@ def children(self) -> Iterable[SourceNode]:
return self.members.values()

def _infer_type(self, type_env: Env.Bindings[Type.Base]) -> Type.Base:
member_types = {}
for k, v in self.members.items():
member_types[k] = v.type
return Type.Object(member_types)
object_type = Type.Object({k: v.type for k, v in self.members.items()})
if not self.struct_type_name:
# pre-WDL 2.0: object literal with deferred typechecking
return object_type

# resolve struct type
struct_type_members = None
if self._struct_types and self.struct_type_name in self._struct_types:
struct_type_members = self._struct_types[self.struct_type_name]
if struct_type_members is None:
raise Error.InvalidType(self, "Unknown type " + self.struct_type_name)

struct_type = Type.StructInstance(self.struct_type_name)
struct_type.members = struct_type_members

# typecheck members vs struct declaration
if not object_type.coerces(struct_type):
raise Error.StaticTypeMismatch(
self,
struct_type,
object_type,
)

return struct_type

def _eval(self, env: Env.Bindings[Value.Base], stdlib: StdLib.Base) -> Value.Base:
ans = {}
for k, v in self.members.items():
ans[k] = v.eval(env, stdlib)
assert isinstance(self.type, Type.Object)
assert isinstance(self.type, (Type.Object, Type.StructInstance))
return Value.Struct(self.type, ans)

@property
Expand All @@ -660,7 +704,7 @@ def literal(self) -> Optional[Value.Base]:
ans[k] = vl
else:
return None
assert isinstance(self.type, Type.Object)
assert isinstance(self.type, (Type.Object, Type.StructInstance))
return Value.Struct(self.type, ans)


Expand Down
Loading

0 comments on commit 2b5c196

Please sign in to comment.