def syn_idx_Unary_Name_constructor(cls, ctx, e, inc_idx): id = e.operand.id if id != "Inf": raise _errors.TyError("Invalid ieee literal.", e) if not isinstance(e.op, (ast.UAdd, ast.USub)): raise _errors.TyError("Invalid unary operator on ieee literal.", e) return ()
def _setup_args(ctx, args, arg_types, tree): # var and kw args are not supported if args.vararg: raise _errors.TyError("Varargs are not supported.", args.vararg) if args.kwarg: raise _errors.TyError("Kwargs are not supported.", args.kwarg) if len(args.defaults) != 0: raise _errors.TyError("Defaults are not supported.", tree) variables = ctx.variables arguments = args.args n_args, n_arg_types = len(arguments), len(arg_types) if n_args != n_arg_types: raise _errors.TyError( "Type specifies {0} arguments but function has {1}.".format( n_arg_types, n_args), tree) for arg, arg_type in zip(arguments, arg_types): if not isinstance(arg, ast.Name): raise _errors.TyError("Argument must be an identifier.", arg) arg_id = arg.id uniq_id = ctx.generate_fresh_id(arg_id) arg.uniq_id = uniq_id variables[arg_id] = (uniq_id, arg_type) yield arg_id
def ana_FunctionDef(self, ctx, tree): if not hasattr(tree, '_post_docstring_body'): self.preprocess_FunctionDef(tree) args = tree.args body = tree._post_docstring_body (arg_types, return_type) = self.idx tree.uniq_id = fn._setup_recursive_fn(ctx, self, tree.name) arg_names = tuple(fn._setup_args(ctx, args, arg_types, tree)) if len(body) > 0: sig_idx = fn._process_function_signature( body[0], arg_names, ctx.fn.static_env) if sig_idx is not None: if (sig_idx[0] != arg_types) \ or (sig_idx[1] != Ellipsis and sig_idx[1] != return_type): raise _errors.TyError( "Function signature and ascription do not match.", body[0]) body = tree._post_sig_body = body[1:] else: tree._post_sig_body = body if len(body) == 0: raise _errors.TyError("Function body is empty.", tree) body_block = tree.body_block = Block.from_stmts(body) body_block.ana(ctx, return_type)
def ana_pat_Dict(self, ctx, pat): keys, values = pat.keys, pat.values idx = self.idx n_keys, n_idx = len(keys), len(idx) if n_keys < n_idx: raise _errors.TyError("Too few elements in pattern.", pat) elif n_keys > n_idx: raise _errors.TyError("Too many elements in pattern.", keys[n_idx]) used_labels = set() bindings = _util.odict() n_bindings = 0 for key, value in zip(keys, values): label = _read_label(key) if label in used_labels: raise _errors.TyError("Duplicate label: " + str(label), key) used_labels.add(label) key.label = label try: ty = idx[label] except KeyError: raise _errors.TyError("Invalid label: " + str(label), key) elt_bindings = ctx.ana_pat(value, ty) n_elt_bindings = len(elt_bindings) bindings.update(elt_bindings) n_bindings_new = len(bindings) if n_bindings_new != n_bindings + n_elt_bindings: raise _errors.TyError("Duplicate variable in pattern.", pat) n_bindings = n_bindings_new return bindings
def ana_pat_Unary_Name_constructor(self, ctx, pat): id = pat.operand.id if id != "Inf": raise _errors.TyError("Invalid ieee literal pattern.", pat) if not isinstance(pat.op, (ast.UAdd, ast.USub)): raise _errors.TyError( "Invalid unary operator on ieee literal pattern.", pat) return _util.odict()
def ana_Name_constructor(self, ctx, e): idx = self.idx lbl = e.id try: ty = idx[lbl] except KeyError: raise _errors.TyError("Label not found in finsum: " + lbl, e) if ty != _product.unit: raise _errors.TyError( "Label has non-unit type but no payload was applied: " + lbl, e)
def ana_Tuple(self, ctx, e): elts = e.elts idx = self.idx n_elts, n_idx = len(elts), len(idx) if n_elts < n_idx: raise _errors.TyError("Too few components provided.", e) elif n_elts > n_idx: raise _errors.TyError("Too many components provided.", elts[n_idx]) for elt, ty in zip(elts, idx.itervalues()): ctx.ana(elt, ty)
def ana_pat_Name_constructor(self, ctx, pat): idx = self.idx lbl = pat.id try: ty = idx[lbl] except KeyError: raise _errors.TyError("Label not found in finsum: " + lbl, pat) if ty != _product.unit: raise _errors.TyError( "Label has non-unit type but no payload pattern was applied: " + lbl, pat) return _util.odict()
def syn_Subscript(self, ctx, e): slice_ = e.slice if not isinstance(slice_, ast.Index): raise _errors.TyError("Must provide a single label.", slice_) value = slice_.value label = _read_label(value) try: ty = self.idx[label] except KeyError: raise _errors.TyError( "Cannot project component labeled " + str(label), e) value.label = label return ty
def syn_idx_FunctionDef(cls, ctx, tree, inc_idx): if not hasattr(tree, '_post_docstring_body'): cls.preprocess_FunctionDef(tree) args = tree.args body = tree._post_docstring_body if len(body) > 0: arg_names = astx._get_arg_names(args) sig_idx = cls._process_function_signature(body[0], arg_names, ctx.fn.static_env) if inc_idx == Ellipsis: if sig_idx is None: if len(arg_names) == 0: inc_idx = ((), Ellipsis) tree._post_sig_body = body else: raise _errors.TyError("Missing argument signature.", tree) else: inc_idx = sig_idx body = tree._post_sig_body = body[1:] else: if sig_idx is None: tree._post_sig_body = body else: if inc_idx[0] != sig_idx[0]: raise _errors.TyError( "Argument signature and ascription do not match.", body[0]) inc_idx = sig_idx body = tree._post_sig_body = body[1:] if len(body) == 0: raise _errors.TyError("Function body is empty.", tree) (arg_types, return_type) = inc_idx if return_type != Ellipsis: fn_ty = cls[arg_types, return_type] else: fn_ty = None tree.uniq_id = cls._setup_recursive_fn(ctx, fn_ty, tree.name) tuple(cls._setup_args(ctx, args, arg_types, tree)) body_block = tree.body_block = Block.from_stmts(body) if return_type == Ellipsis: return_type = body_block.syn(ctx) else: body_block.ana(ctx, return_type) return (arg_types, return_type)
def check_valid_function_def(cls, stmt): if isinstance(stmt, ast.FunctionDef): if cls._check_valid_args(stmt.args): decorator_list = stmt.decorator_list if len(decorator_list) == 0: stmt.asc_ast = None return True elif len(decorator_list) == 1: stmt.asc_ast = decorator_list[0] return True else: raise _errors.TyError( """Too many decorators.""", stmt) raise _errors.TyError("Not a function definition.", stmt)
def syn_BinOp(self, ctx, e): if isinstance( e.op, (ast.LShift, ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd)): raise _errors.TyError( "Cannot use bitwise operators on cplx values.", e) if isinstance(e.op, ast.Mod): raise _errors.TyError( "Cannot take the modulus of a complex number.", e) right = e.right ctx.ana(right, self) return self
def syn_Compare(self, ctx, e): left, ops, comparators = e.left, e.ops, e.comparators for op in ops: if isinstance(op, (ast.Lt, ast.LtE, ast.Gt, ast.GtE)): raise _errors.TyError( "No ordering relation on complex numbers.", e) elif isinstance(op, (ast.In, ast.NotIn)): raise _errors.TyError( "Type complex does not support this operator.", op) for e_ in _util.tpl_cons(left, comparators): if hasattr(e_, 'match'): continue # already synthesized ctx.ana(e_, self) return _boolean.boolean
def syn_UnaryOp(self, ctx, e): if isinstance(e.op, ast.Not): return self else: raise _errors.TyError( """Type bool does not support this unary operator.""", e)
def _check_valid_args(cls, args): if (args.vararg is not None or args.kwarg is not None or len(args.defaults) != 0): raise _errors.TyError( "Invalid function argument format.", args) return True
def syn_BinOp(self, ctx, e): op = e.op if isinstance(op, ast.Add): ctx.ana(e.right, self) return self else: raise _errors.TyError("Invalid binary operator on strings.", e)
def syn_idx_Name_constructor(cls, ctx, e, inc_idx): id = e.id if id != "True" and id != "False": raise _errors.TyError( "Must introduce a value of boolean type with either True or False.", e) return ()
def syn_Compare(self, ctx, e): left, ops, comparators = e.left, e.ops, e.comparators for op in ops: if isinstance(op, (ast.Eq, ast.NotEq)): if not len(self.idx) == 0: raise _errors.TyError( "Can only compare unit values for equality.", e) elif not isinstance(op, (ast.Is, ast.IsNot)): raise _errors.TyError("Invalid comparison operator.", op) for e_ in _util.tpl_cons(left, comparators): if hasattr(e_, "match"): continue # already synthesized ctx.ana(e_, self) return _boolean.boolean
def syn_idx_Num(cls, ctx, e, inc_idx): n = e.n if isinstance(n, (int, long)): return () else: raise _errors.TyError("Expression is not an int or long literal.", e)
def _yield_items(stmts): match_head = None match_rules = None for stmt in stmts: if match_head is not None: if (isinstance(stmt, ast.With) and not BlockWithBinding.is_with_binding(stmt)): if stmt.optional_vars is not None: raise _errors.TyError("Invalid rule form.", stmt) match_rules.append(stmt) continue else: if len(match_rules) == 0: raise _errors.TyError( "No match rules.", match_head) yield BlockMatchExpr(match_head, match_rules) match_head = match_rules = None # falls through below if match_head is None: if isinstance(stmt, ast.Expr): if BlockMatchExpr.is_match_head(stmt): match_head = stmt match_rules = [] else: yield BlockExprExpr(stmt) elif isinstance(stmt, ast.With): if (BlockWithBinding.is_with_binding(stmt)): yield BlockWithBinding(stmt) else: raise _errors.TyError("Invalid with form.", stmt) elif isinstance(stmt, ast.Assign): yield BlockLet(stmt) elif isinstance(stmt, ast.If): yield BlockIfExpr(stmt) elif isinstance(stmt, ast.Pass): yield BlockPassExpr(stmt) elif isinstance(stmt, ast.FunctionDef): if BlockFunctionDefExpr.check_valid_function_def(stmt): yield BlockFunctionDefExpr(stmt) else: raise _errors.TyError("Statement form not supported.", stmt) # finish making match expression at the end of the block if necessary if match_head is not None: if len(match_rules) == 0: raise _errors.TyError( "No match rules.", match_head) yield BlockMatchExpr(match_head, match_rules)
def syn_Attribute(self, ctx, e): attr = e.attr if attr == "real" or attr == "imag": return ieee elif attr == "conjugate": return _fn.fn[(), self] else: raise _errors.TyError("Invalid attribute: " + attr, e)
def syn_Subscript(self, ctx, e): slice_ = e.slice if isinstance(slice_, ast.Ellipsis): raise _errors.TyError("stringing slice cannot be an Ellipsis.", e) elif isinstance(slice_, ast.ExtSlice): raise _errors.TyError("stringing slice can only have one dimension.", e) elif isinstance(slice_, ast.Index): ctx.ana(slice_.value, _numeric.num) else: # if isinstance(slice_, ast.Slice): lower, upper, step = slice_.lower, slice_.upper, slice_.step if lower is not None: ctx.ana(lower, _numeric.num) if upper is not None: ctx.ana(upper, _numeric.num) if not _is_None(step): ctx.ana(step, _numeric.num) return self
def _is_ascribed_match_head(cls, e): if isinstance(e, ast.Subscript): value = e.value if cls._is_unascribed_match_head(value): slice = e.slice if isinstance(slice, ast.Slice): lower, upper, step = slice.lower, slice.upper, slice.step if lower is None and upper is not None and step is None: e.is_match_head = True e.scrutinee = value.scrutinee e.asc_ast = upper return True else: raise _errors.TyError("Invalid ascription format.", slice) else: raise _errors.TyError("Invalid ascription format.", slice) return False
def ana_pat_Tuple(self, ctx, pat): elts = pat.elts if len(elts) != 2: raise _errors.TyError( "Using a tuple pattern for a value of type cplx requires two elements.", pat) rl, im = elts[0], elts[1] rl_bindings = ctx.ana_pat(rl, ieee) im_bindings = ctx.ana_pat(im, ieee) n_rl_bindings = len(rl_bindings) n_im_bindings = len(im_bindings) bindings = _util.odict(rl_bindings) bindings.update(im_bindings) n_bindings = len(bindings) if n_bindings != n_rl_bindings + n_im_bindings: raise _errors.TyError("Duplicated variables in pattern.", pat) return bindings
def syn_BinOp(self, ctx, e): if isinstance( e.op, (ast.LShift, ast.RShift, ast.BitOr, ast.BitXor, ast.BitAnd)): raise _errors.TyError( "Cannot use bitwise operators on ieee values.", e) ctx.ana(e.right, self) return self
def syn_Attribute(self, ctx, e): attr = e.attr if attr == 'f': return ieee elif attr == 'c': return cplx else: raise _errors.TyError("Invalid attribute.", e)
def _read_label(key): if isinstance(key, ast.Name): return key.id elif isinstance(key, ast.Num): n = key.n if isinstance(n, (int, long)) and n >= 0: return n else: raise _errors.TyError("Invalid numeric label.", key) elif isinstance(key, ast.Str): s = key.s if s != "": return s else: raise _errors.TyError("Invalid string label.", key) else: raise _errors.TyError("Invalid label", key)
def syn_Name(cls, ctx, e): id = e.id try: (uniq_id, ty) = ctx.variables[id] except KeyError: raise _errors.TyError( "Variable not found in context: " + id, e) e.uniq_id = uniq_id return ty
def from_stmts(cls, stmts): items = tuple(cls._yield_items(stmts)) first_items = items[0:-1] last_item = items[-1] if not isinstance(last_item, BlockExpr): raise _errors.TyError( "Block ends with a binding.", last_item.stmts[0]) return cls(first_items, last_item)
def syn_Attribute(self, ctx, e): idx = self.idx attr = e.attr try: ty = idx[attr] except KeyError: raise _errors.TyError("Cannot project component labeled " + attr, e) return ty