def map_type(self, items, meta): assert len(items) >= 2 assert isinstance(items[0], T.Base) assert isinstance(items[1], T.Base) optional = False if len(items) > 2: if items[2].value == "?": optional = True return T.Map((items[0], items[1]), optional)
def _infer_type(self, type_env: Env.Types) -> T.Base: kty = None vty = None for k, v in self.items: k.infer_type(type_env, self._check_quant) if kty is None: kty = k.type else: k.typecheck(kty) v.infer_type(type_env, self._check_quant) if vty is None or vty == T.Array(None) or vty == T.Map(None): vty = v.type else: v.typecheck(vty) if kty is None: return T.Map(None) assert vty is not None return T.Map((kty, vty))
def type(self, items, meta): quantifiers = set() if len(items) > 1 and isinstance(items[-1], set): quantifiers = items.pop() param = items[1] if len(items) > 1 else None param2 = items[2] if len(items) > 2 else None if items[0].value == "Array": if not param or param2: raise Err.InvalidType(sp(self.filename, meta), "Array must have one type parameter") if quantifiers - set(["optional", "nonempty"]): raise Err.ValidationError( sp(self.filename, meta), "invalid type quantifier(s) for Array") return T.Array(param, "optional" in quantifiers, "nonempty" in quantifiers) if "nonempty" in quantifiers: raise Err.InvalidType( sp(self.filename, meta), "invalid type quantifier(s) for " + items[0].value) atomic_types = { "Int": T.Int, "Float": T.Float, "Boolean": T.Boolean, "String": T.String, "File": T.File, } if items[0].value in atomic_types: if param or param2: raise Err.InvalidType( sp(self.filename, meta), items[0] + " type doesn't accept parameters") return atomic_types[items[0].value]("optional" in quantifiers) if items[0].value == "Map": if not (param and param2): raise Err.InvalidType(sp(self.filename, meta), "Map must have two type parameters") return T.Map((param, param2), "optional" in quantifiers) if items[0].value == "Pair": if not (param and param2): raise Err.InvalidType(sp(self.filename, meta), "Pair must have two type parameters") return T.Pair(param, param2, "optional" in quantifiers) if param or param2: raise Err.InvalidType(sp(self.filename, meta), "Unexpected type parameter(s)") return T.StructInstance(items[0].value, "optional" in quantifiers)
def __init__(self): # language built-ins self._at = _At() self._land = _And() self._lor = _Or() self._negate = StaticFunction( "_negate", [T.Boolean()], T.Boolean(), lambda x: V.Boolean(not x.value) ) self._add = _AddOperator() self._sub = _ArithmeticOperator("-", lambda l, r: l - r) self._mul = _ArithmeticOperator("*", lambda l, r: l * r) self._div = _ArithmeticOperator("/", lambda l, r: l // r) self._rem = StaticFunction( "_rem", [T.Int(), T.Int()], T.Int(), lambda l, r: V.Int(l.value % r.value) ) self._eqeq = _ComparisonOperator("==", lambda l, r: l == r) self._neq = _ComparisonOperator("!=", lambda l, r: l != r) self._lt = _ComparisonOperator("<", lambda l, r: l < r) self._lte = _ComparisonOperator("<=", lambda l, r: l <= r) self._gt = _ComparisonOperator(">", lambda l, r: l > r) self._gte = _ComparisonOperator(">=", lambda l, r: l >= r) # static stdlib functions for (name, argument_types, return_type, F) in [ ("floor", [T.Float()], T.Int(), lambda v: V.Int(math.floor(v.value))), ("ceil", [T.Float()], T.Int(), lambda v: V.Int(math.ceil(v.value))), ("round", [T.Float()], T.Int(), lambda v: V.Int(round(v.value))), ("length", [T.Array(T.Any())], T.Int(), lambda v: V.Int(len(v.value))), ("sub", [T.String(), T.String(), T.String()], T.String(), _sub), ("basename", [T.String(), T.String(optional=True)], T.String(), _basename), ( "defined", [T.Any(optional=True)], T.Boolean(), lambda v: V.Boolean(not isinstance(v, V.Null)), ), # context-dependent: ("write_lines", [T.Array(T.String())], T.File(), _notimpl), ("write_tsv", [T.Array(T.Array(T.String()))], T.File(), _notimpl), ("write_map", [T.Map((T.Any(), T.Any()))], T.File(), _notimpl), ("write_json", [T.Any()], T.File(), _notimpl), ("stdout", [], T.File(), _notimpl), ("stderr", [], T.File(), _notimpl), ("glob", [T.String()], T.Array(T.File()), _notimpl), ("read_int", [T.File()], T.Int(), _notimpl), ("read_boolean", [T.File()], T.Boolean(), _notimpl), ("read_string", [T.File()], T.String(), _notimpl), ("read_float", [T.File()], T.Float(), _notimpl), ("read_array", [T.File()], T.Array(T.Any()), _notimpl), ("read_map", [T.File()], T.Map((T.Any(), T.Any())), _notimpl), ("read_lines", [T.File()], T.Array(T.Any()), _notimpl), ("read_tsv", [T.File()], T.Array(T.Array(T.String())), _notimpl), ("read_json", [T.File()], T.Any(), _notimpl), ]: setattr(self, name, StaticFunction(name, argument_types, return_type, F)) # polymorphically typed stdlib functions which require specialized # infer_type logic self.range = _Range() self.prefix = _Prefix() self.size = _Size() self.select_first = _SelectFirst() self.select_all = _SelectAll() self.zip = _Zip() self.cross = _Zip() # FIXME self.flatten = _Flatten() self.transpose = _Transpose()
lambda l, r: V.Int(l.value % r.value)), # pyre-fixme ("stdout", [], T.File(), _notimpl), ("basename", [T.String(), T.String(optional=True)], T.String(), _notimpl), # note: size() can take an empty value and probably returns 0 in that case. # e.g. https://github.com/DataBiosphere/topmed-workflows/blob/31ba8a714b36ada929044f2ba3d130936e6c740e/CRAM-no-header-md5sum/md5sum/CRAM_md5sum.wdl#L39 ("size", [T.File(optional=True), T.String(optional=True)], T.Float(), _notimpl), ("ceil", [T.Float()], T.Int(), _notimpl), ("round", [T.Float()], T.Int(), _notimpl), ("glob", [T.String()], T.Array(T.File()), _notimpl), ("read_int", [T.String()], T.Int(), _notimpl), ("read_boolean", [T.String()], T.Boolean(), _notimpl), ("read_string", [T.String()], T.String(), _notimpl), ("read_float", [T.String()], T.Float(), _notimpl), ("read_array", [T.String()], T.Array(None), _notimpl), ("read_map", [T.String()], T.Map(None), _notimpl), ("read_lines", [T.String()], T.Array(None), _notimpl), ("read_tsv", [T.String()], T.Array(T.Array(T.String())), _notimpl), ("write_lines", [T.Array(T.String())], T.File(), _notimpl), ("write_tsv", [T.Array(T.Array(T.String()))], T.File(), _notimpl), ("write_map", [T.Map(None)], T.File(), _notimpl), ("range", [T.Int()], T.Array(T.Int()), _notimpl), ("sub", [T.String(), T.String(), T.String()], T.String(), _notimpl), ] for name, argument_types, return_type, F in _static_functions: E._stdlib[name] = _StaticFunction(name, argument_types, return_type, F) # Polymorphic functions # arithmetic infix operators # operands may be Int or Float; return Float iff either operand is Float