Beispiel #1
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     if len(expr.arguments) != 1:
         raise Error.WrongArity(expr, 1)
     expr.arguments[0].typecheck(T.Int())
     nonempty = False
     arg0 = expr.arguments[0]
     if isinstance(arg0, E.Int) and arg0.value > 0:
         nonempty = True
     if isinstance(arg0, E.Apply) and arg0.function_name == "length":
         arg00ty = arg0.arguments[0].type
         if isinstance(arg00ty, T.Array) and arg00ty.nonempty:
             nonempty = True
     return T.Array(T.Int(), nonempty=nonempty)
Beispiel #2
0
 def __call__(self, expr: E.Apply, env: E.Env) -> V.Base:
     assert len(expr.arguments) == 2
     lhs = expr.arguments[0]
     rhs = expr.arguments[1]
     if isinstance(lhs.type, T.Array):
         arr = lhs.eval(env)
         assert isinstance(arr, V.Array)
         assert isinstance(arr.type, T.Array)
         assert isinstance(arr.value, list)
         idx = rhs.eval(env).expect(T.Int()).value
         if idx < 0 or idx >= len(arr.value):
             raise Error.OutOfBounds(rhs)
         return arr.value[idx]  # pyre-fixme
     if isinstance(lhs.type, T.Map):
         mp = lhs.eval(env)
         assert isinstance(mp, V.Map)
         assert isinstance(mp.type, T.Map)
         assert mp.type.item_type is not None
         assert isinstance(mp.value, list)
         ans = None
         key = rhs.eval(env).expect(mp.type.item_type[0])
         for k, v in mp.value:
             if key == k:
                 ans = v.expect(mp.type.item_type[1])
         if ans is None:
             raise Error.OutOfBounds(rhs)  # TODO: KeyNotFound
         return ans  # pyre-fixme
     assert False  # pyre-fixme
Beispiel #3
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     if len(expr.arguments) != 1:
         raise Error.WrongArity(expr, 1)
     if not isinstance(expr.arguments[0].type, T.Array):
         raise Error.StaticTypeMismatch(expr, T.Array(None),
                                        expr.arguments[0].type)
     return T.Int()
Beispiel #4
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     ans_type = self.infer_type(expr)
     try:
         ans = self.op(arguments[0].coerce(ans_type).value, arguments[1].coerce(ans_type).value)
     except ZeroDivisionError:
         # TODO: different runtime error?
         raise Error.IncompatibleOperand(expr.arguments[1], "Division by zero") from None
     if ans_type == T.Int():
         assert isinstance(ans, int)
         return V.Int(ans)
     assert isinstance(ans, float)
     return V.Float(ans)
Beispiel #5
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     rt = T.Int()
     if isinstance(expr.arguments[0].type, T.Float) or isinstance(
             expr.arguments[1].type, T.Float):
         rt = T.Float()
     try:
         expr.arguments[0].typecheck(rt)
         expr.arguments[1].typecheck(rt)
     except Error.StaticTypeMismatch:
         raise Error.IncompatibleOperand(
             expr,
             "Non-numeric operand to " + self.name + " operator") from None
     return rt
Beispiel #6
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     lhs = expr.arguments[0]
     rhs = expr.arguments[1]
     if isinstance(lhs.type, T.Array):
         if isinstance(lhs, E.Array) and not lhs.items:
             # the user wrote: [][idx]
             raise Error.OutOfBounds(expr)
         try:
             rhs.typecheck(T.Int())
         except Error.StaticTypeMismatch:
             raise Error.StaticTypeMismatch(rhs, T.Int(), rhs.type, "Array index") from None
         return lhs.type.item_type
     if isinstance(lhs.type, T.Map):
         if lhs.type.item_type is None:
             raise Error.OutOfBounds(expr)
         try:
             rhs.typecheck(lhs.type.item_type[0])
         except Error.StaticTypeMismatch:
             raise Error.StaticTypeMismatch(
                 rhs, lhs.type.item_type[0], rhs.type, "Map key"
             ) from None
         return lhs.type.item_type[1]
     raise Error.NotAnArray(lhs)
Beispiel #7
0
 def __init__(self, value: int) -> None:
     super().__init__(T.Int(), value)
Beispiel #8
0
 def int_type(self, items, meta):
     optional = False
     if items and items[0].value == "?":
         optional = True
     return T.Int(optional)
Beispiel #9
0
 def _infer_type(self, type_env: Env.Types) -> T.Base:
     return T.Int()
Beispiel #10
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     arg0 = arguments[0]
     assert isinstance(arg0, V.Int)
     if arg0.value < 0:
         raise Error.EvalError(expr, "range() got negative argument")
     return V.Array(T.Array(T.Int()), [V.Int(x) for x in range(arg0.value)])
Beispiel #11
0
    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()
Beispiel #12
0
        argument_values = [
            arg.eval(env).coerce(ty)
            for arg, ty in zip(expr.arguments, self.argument_types)
        ]
        ans: V.Base = self.F(*argument_values)
        return ans.coerce(self.return_type)


def _notimpl(one: Any = None, two: Any = None) -> None:
    exec("raise NotImplementedError()")


_static_functions: List[Tuple[str, List[T.Base], T.Base, Any]] = [
    ("_negate", [T.Boolean()], T.Boolean(),
     lambda x: V.Boolean(not x.value)),  # pyre-fixme
    ("_rem", [T.Int(), T.Int()], T.Int(),
     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),