Exemple #1
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()
Exemple #2
0
 def _infer_type(self, type_env: Env.Types) -> T.Base:
     self.expr.infer_type(type_env, self._check_quant)
     if isinstance(self.expr.type, T.Array):
         if "sep" not in self.options:
             raise Error.StaticTypeMismatch(
                 self, T.Array(None), self.expr.type,
                 "array command placeholder must have 'sep'")
         # if sum(1 for t in [T.Int, T.Float, T.Boolean, T.String, T.File] if isinstance(self.expr.type.item_type, t)) == 0:
         #    raise Error.StaticTypeMismatch(self, T.Array(None), self.expr.type, "cannot use array of complex types for command placeholder")
     elif "sep" in self.options:
         raise Error.StaticTypeMismatch(
             self,
             T.Array(None),
             self.expr.type,
             "command placeholder has 'sep' option for non-Array expression",
         )
     if "true" in self.options or "false" in self.options:
         if not isinstance(self.expr.type, T.Boolean):
             raise Error.StaticTypeMismatch(
                 self,
                 T.Boolean(),
                 self.expr.type,
                 "command placeholder 'true' and 'false' options used with non-Boolean expression",
             )
         if not ("true" in self.options and "false" in self.options):
             raise Error.StaticTypeMismatch(
                 self,
                 T.Boolean(),
                 self.expr.type,
                 "command placeholder with only one of 'true' and 'false' options",
             )
     return T.String()
Exemple #3
0
 def _infer_type(self, type_env: Env.Types) -> T.Base:
     if not self.items:
         return T.Array(None)
     for item in self.items:
         item.infer_type(type_env, self._check_quant)
     # Start by assuming the type of the first item is the item type
     item_type: T.Base = self.items[0].type
     # Allow a mixture of Int and Float to construct Array[Float]
     if isinstance(item_type, T.Int):
         for item in self.items:
             if isinstance(item.type, T.Float):
                 item_type = T.Float()
     # If any item is String, assume item type is String
     # If any item has optional quantifier, assume item type is optional
     # If all items have nonempty quantifier, assume item type is nonempty
     all_nonempty = len(self.items) > 0
     for item in self.items:
         if isinstance(item.type, T.String):
             item_type = T.String(optional=item_type.optional)
         if item.type.optional:
             item_type = item_type.copy(optional=True)
         if isinstance(item.type, T.Array) and not item.type.nonempty:
             all_nonempty = False
     if isinstance(item_type, T.Array):
         item_type = item_type.copy(nonempty=all_nonempty)
     # Check all items are coercible to item_type
     for item in self.items:
         try:
             item.typecheck(item_type)
         except Error.StaticTypeMismatch:
             self._type = T.Array(item_type, optional=False, nonempty=True)
             raise Error.StaticTypeMismatch(
                 self, item_type, item.type,
                 "(inconsistent types within array)") from None
     return T.Array(item_type, optional=False, nonempty=True)
Exemple #4
0
 def _call_eager(self, expr: E.Apply, arguments: List[V.Base]) -> V.Base:
     ans_type = self.infer_type(expr)
     if not isinstance(ans_type, T.String):
         return super()._call_eager(expr, arguments)
     # TODO: in a command interpolation, return missing if either operand is missing
     ans = self.op(
         str(arguments[0].coerce(T.String()).value), str(arguments[1].coerce(T.String()).value)
     )
     assert isinstance(ans, str)
     return V.String(ans)
Exemple #5
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     if len(expr.arguments) != 2:
         raise Error.WrongArity(expr, 2)
     expr.arguments[0].typecheck(T.String())
     expr.arguments[1].typecheck(T.Array(T.String()))
     return T.Array(
         T.String(),
         nonempty=(
             isinstance(expr.arguments[1].type, T.Array) and expr.arguments[1].type.nonempty
         ),
     )
Exemple #6
0
 def __call__(self, expr: E.Apply, env: E.Env) -> V.Base:
     ans_type = self.infer_type(expr)
     if not isinstance(ans_type, T.String):
         return super().__call__(expr, env)
     # TODO: return missing if either operand is missing
     ans = self.op(
         str(expr.arguments[0].eval(env).coerce(T.String()).value),
         str(expr.arguments[1].eval(env).coerce(T.String()).value),
     )
     assert isinstance(ans, str)
     return V.String(ans)
Exemple #7
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.arguments[0], T.Array(None),
                                        expr.arguments[0].type)
     if expr.arguments[0].type.item_type is None:
         # TODO: error for 'indeterminate type'
         raise Error.EmptyArray(expr.arguments[0])
     ty = expr.arguments[0].type.item_type
     assert isinstance(ty, T.Base)
     return T.Array(ty.copy(optional=False))
Exemple #8
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.Array(None))
     # TODO: won't handle implicit coercion from T to Array[T]
     assert isinstance(expr.arguments[0].type, T.Array)
     if expr.arguments[0].type.item_type is None:
         return T.Array(None)
     if not isinstance(expr.arguments[0].type.item_type, T.Array):
         raise Error.StaticTypeMismatch(expr.arguments[0],
                                        T.Array(T.Array(None)),
                                        expr.arguments[0].type)
     return expr.arguments[0].type
Exemple #9
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)
Exemple #10
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
Exemple #11
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     if (
         (
             expr._check_quant
             and expr.arguments[0].type.optional != expr.arguments[1].type.optional
         )
         or (
             self.name not in ["==", "!="]
             and (expr.arguments[0].type.optional or expr.arguments[1].type.optional)
         )
         or (
             not (
                 expr.arguments[0].type.copy(optional=False)
                 == expr.arguments[1].type.copy(optional=False)
                 or (
                     isinstance(expr.arguments[0].type, T.Int)
                     and isinstance(expr.arguments[1].type, T.Float)
                 )
                 or (
                     isinstance(expr.arguments[0].type, T.Float)
                     and isinstance(expr.arguments[1].type, T.Int)
                 )
             )
         )
     ):
         raise Error.IncompatibleOperand(
             expr,
             "Cannot compare {} and {}".format(
                 str(expr.arguments[0].type), str(expr.arguments[1].type)
             ),
         )
     return T.Boolean()
Exemple #12
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
Exemple #13
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     t2 = None
     if isinstance(expr.arguments[0].type, T.String):
         t2 = expr.arguments[1].type
     elif isinstance(expr.arguments[1].type, T.String):
         t2 = expr.arguments[0].type
     if t2 is None:
         # neither operand is a string; defer to _ArithmeticOperator
         return super().infer_type(expr)
     if not t2.coerces(T.String(optional=True)):
         raise Error.IncompatibleOperand(
             expr,
             "Cannot add/concatenate {} and {}".format(
                 str(expr.arguments[0].type), str(expr.arguments[1].type)),
         )
     return T.String()
Exemple #14
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     assert len(expr.arguments) == 2
     for arg in expr.arguments:
         if not isinstance(arg.type, T.Boolean):
             raise Error.IncompatibleOperand(arg, "non-Boolean operand to ||")
         if expr._check_quant and arg.type.optional:
             raise Error.IncompatibleOperand(arg, "optional Boolean? operand to ||")
     return T.Boolean()
Exemple #15
0
 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))
Exemple #16
0
 def eval(self, env: Env.Values) -> V.Base:
     ""
     try:
         if self.condition.eval(env).expect(T.Boolean()).value:
             ans = self.consequent.eval(env)
         else:
             ans = self.alternative.eval(env)
         return ans
     except ReferenceError:
         raise Error.NullValue(self) from None
Exemple #17
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     if len(expr.arguments) != 2:
         raise Error.WrongArity(expr, 2)
     arg0ty: T.Base = expr.arguments[0].type
     if not isinstance(arg0ty, T.Array) or (expr._check_quant
                                            and arg0ty.optional):
         raise Error.StaticTypeMismatch(expr.arguments[0], T.Array(None),
                                        arg0ty)
     if arg0ty.item_type is None:
         # TODO: error for 'indeterminate type'
         raise Error.EmptyArray(expr.arguments[0])
     arg1ty: T.Base = expr.arguments[1].type
     if not isinstance(arg1ty, T.Array) or (expr._check_quant
                                            and arg1ty.optional):
         raise Error.StaticTypeMismatch(expr.arguments[1], T.Array(None),
                                        arg1ty)
     if arg1ty.item_type is None:
         # TODO: error for 'indeterminate type'
         raise Error.EmptyArray(expr.arguments[1])
     return T.Array(T.Pair(arg0ty.item_type, arg1ty.item_type))
Exemple #18
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)
Exemple #19
0
 def _infer_type(self, type_env: Env.Types) -> T.Base:
     # check for Boolean condition
     if self.condition.infer_type(type_env,
                                  self._check_quant).type != T.Boolean():
         raise Error.StaticTypeMismatch(self, T.Boolean(),
                                        self.condition.type,
                                        "in if condition")
     # Unify consequent & alternative types. Subtleties:
     # 1. If either is optional, unify to optional
     # 2. If one is Int and the other is Float, unify to Float
     # 3. If one is a nonempty array and the other is a possibly empty
     #    array, unify to possibly empty array
     self_type = self.consequent.infer_type(type_env,
                                            self._check_quant).type
     assert isinstance(self_type, T.Base)
     self.alternative.infer_type(type_env, self._check_quant)
     if isinstance(self_type, T.Int) and isinstance(self.alternative.type,
                                                    T.Float):
         self_type = T.Float(optional=self_type.optional)
     if self.alternative.type.optional:
         self_type = self_type.copy(optional=True)
     if (isinstance(self_type, T.Array)
             and isinstance(self.consequent.type, T.Array)
             and isinstance(self.alternative.type, T.Array)):
         self_type = self_type.copy(nonempty=(  # pyre-ignore
             self.consequent.type.nonempty
             and self.alternative.type.nonempty  # pyre-ignore
         ))
     try:
         self.consequent.typecheck(self_type)
         self.alternative.typecheck(self_type)
     except Error.StaticTypeMismatch:
         raise Error.StaticTypeMismatch(
             self,
             self.consequent.type,  # pyre-ignore
             self.alternative.type,
             " (if consequent & alternative must have the same type)",
         ) from None
     return self_type
Exemple #20
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)
Exemple #21
0
 def infer_type(self, expr: E.Apply) -> T.Base:
     if not expr.arguments:
         raise Error.WrongArity(expr, 1)
     if not expr.arguments[0].type.coerces(T.File(optional=True)):
         if isinstance(expr.arguments[0].type, T.Array):
             if expr.arguments[0].type.optional or not expr.arguments[0].type.item_type.coerces(
                 T.File(optional=True)
             ):
                 raise Error.StaticTypeMismatch(
                     expr.arguments[0], T.Array(T.File(optional=True)), expr.arguments[0].type
                 )
         else:
             raise Error.StaticTypeMismatch(
                 expr.arguments[0], T.File(optional=True), expr.arguments[0].type
             )
     if len(expr.arguments) == 2:
         if expr.arguments[1].type != T.String():
             raise Error.StaticTypeMismatch(
                 expr.arguments[1], T.String(), expr.arguments[1].type
             )
     elif len(expr.arguments) > 2:
         raise Error.WrongArity(expr, 2)
     return T.Float()