def pair_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.Pair(items[0], items[1], optional)
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 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(T.Any()), arg0ty) if isinstance(arg0ty.item_type, T.Any): # 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(T.Any()), arg1ty) if isinstance(arg1ty.item_type, T.Any): # TODO: error for 'indeterminate type' raise Error.EmptyArray(expr.arguments[1]) return T.Array( T.Pair(arg0ty.item_type, arg1ty.item_type), nonempty=(arg0ty.nonempty or arg1ty.nonempty), )
def _infer_type(self, type_env: Env.Types) -> T.Base: self.left.infer_type(type_env, self._check_quant) self.right.infer_type(type_env, self._check_quant) return T.Pair(self.left.type, self.right.type)