def _check_expr(self, s, expr_kind, typ, expected): """Typechecks the string C{s} as an C{expr_type} expression.""" a = ast.parse(s).body[0].value f = expr_template % expr_kind if expected == "pass" or expected == "fail": t = PType.from_str(typ) if expected == "pass": self.assertEqual(True, call_function(f, a, t, {}), "%s should typecheck as %s but does not." % (s,t)) elif expected == "fail": self.assertEqual(False, call_function(f, a, t, {}), "%s shouldn't typecheck as %s but does." % (s, t)) elif issubclass(eval(expected), Exception): # if the expected value is an error, then make sure it # raises the right error. try: t = PType.from_str(typ) call_function(f, a, t, {}) except eval(expected): pass else: self.fail("Should have raised error %s, but does not. (%s)." % (expected, s)) else: raise TestFileFormatError("Expression tests can only be" + \ " specified as passing, failing, or raising an error " + \ " specified in errors.py, but this test was specified " + \ " as expecting: " + expected)
def test_is_tuple(self): true = self.assertTrue true( PType.from_str("(float,bool,int)").is_tuple() ) true( PType.from_str("(bool,)").is_tuple() ) true( PType.from_str("(bool,float,int,bool)").is_tuple() ) true( PType.from_str("([int],[bool])").is_tuple() ) true( PType.from_str("({int:float},{float:int})").is_tuple() )
def test_quantify(self): equal = self.assertEqual equal( str(PType.from_str("'a").quantify()), "V'a.'a" ) equal( str(PType.from_str("'a -> 'a").quantify()), "V'a.'a -> 'a" ) equal( str(PType.from_str("'a -> 'b").quantify()), "V'a.V'b.'a -> 'b" ) equal( str(PType.from_str("{'g : ('a, int)}").quantify()), "V'a.V'g.{'g: ('a, int)}" )
def test_is_set(self): true = self.assertTrue true( PType.from_str("{bool}").is_set() ) true( PType.from_str("{unit}").is_set() ) true( PType.from_str("{(int, bool, float)}").is_set() ) true( PType.from_str("{ int -> bool }").is_set() ) true( PType.from_str("{{str: bool}}").is_set() )
def _check_expr(self, s, expr_kind, typ, expected): """Typechecks the string C{s} as an C{expr_type} expression.""" a = ast.parse(s).body[0].value f = expr_template % expr_kind if expected == "pass" or expected == "fail": t = PType.from_str(typ) if expected == "pass": self.assertEqual( True, call_function(f, a, t, {}), "%s should typecheck as %s but does not." % (s, t)) elif expected == "fail": self.assertEqual(False, call_function(f, a, t, {}), "%s shouldn't typecheck as %s but does." % (s, t)) elif issubclass(eval(expected), Exception): # if the expected value is an error, then make sure it # raises the right error. try: t = PType.from_str(typ) call_function(f, a, t, {}) except eval(expected): pass else: self.fail("Should have raised error %s, but does not. (%s)." % (expected, s)) else: raise TestFileFormatError("Expression tests can only be" + \ " specified as passing, failing, or raising an error " + \ " specified in errors.py, but this test was specified " + \ " as expecting: " + expected)
def parse_type_dec(line, lineno, var_name, type_spec): """Constructs a L{ast_extensions.TypeDec} from the type declaration in the provided line. The name of the variable and the name of the type are passed since they are stored when matching the typedec regex against the line and it would be wasteful to discard that information. @type line: str @param line: the line of source code containing the type declaration. @type lineno: int @param lineno: the index of this line in the orginial source code file. @type var_name: str @param var_name: the name of the identifier whose type is being declared. @type type_name: str @param type_name: the name of the type which is being declared. @rtype: L{ast_extensions.TypeDec} @return: a L{ast_extensions.TypeDec} node for the declaration in the given line. """ col = line.index(var_name) name_node = ast.Name(ctx=TypeStore(), id=var_name, lineno=lineno, col_offset=col) col_offset = line.index("#:") return TypeDec([name_node], PType.from_str(type_spec), lineno, col_offset)
def __init__(self, targets, t, line, col=None): """ Create a `TypeDec` node with the supplied parameters. #### Parameters - `targets`: list of identifiers (as `ast.Name` objects) having their types declared. - `t`: the type being assigned, as a PType or string. If a string is provided, it is parsed into the appropriate PType. - `line`: the (int) line number of the declaration in the source code. - `col`: [optional] the (int) column number of the declaration in the source code. If not provided, then the column number will just be set as `None`. """ self.targets = targets self.lineno = line if col is not None: self.col_offset = col if type(t) == str: self.t = PType.from_str(t) assert self.t.__class__ == PType, \ ("Got a %s back from TypeSpecParser.parse, not a PType" % cname(self.t.__class__)) elif t.__class__ == PType: self.t = t else: assert False, ("t needs to be specified as str or PType, not " + cname(t)) # these are instance variables provided by AST nodes to allow traversal # / parsing of the nodes. self._fields = ("targets", "t") self._attributes = ("lineno", "col_offset")
def test_free_vars(self): equal = self.assertEqual alpha = PType.from_str("'a") beta = PType.from_str("'b") gamma = PType.from_str("'g") equal( PType.from_str("'a").free_type_vars(), {alpha} ) equal( PType.from_str("'a -> 'a").free_type_vars(), {alpha} ) equal( PType.from_str("'a -> 'b").free_type_vars(), {alpha, beta} ) equal( PType.from_str("{'g : ('a, int)}").free_type_vars(), {alpha, gamma} )
def test_is_basetype(self): true = self.assertTrue true( int_t.is_base() ) true( float_t.is_base() ) true( str_t.is_base() ) true( unicode_t.is_base() ) true( bool_t.is_base() ) true( unit_t.is_base() ) equal = self.assertEqual equal( PType.int(), int_t ) equal( PType.float(), float_t ) equal( PType.string(), str_t ) equal( PType.unicode(), unicode_t ) equal( PType.bool(), bool_t ) equal( PType.unit(), unit_t ) all(equal(PType.from_str(k), v) for (k,v) in base_ts.iteritems())
def __init__(self, targets, t, line, col = None): """ Create a `TypeDec` node with the supplied parameters. #### Parameters - `targets`: list of identifiers (as `ast.Name` objects) having their types declared. - `t`: the type being assigned, as a PType or string. If a string is provided, it is parsed into the appropriate PType. - `line`: the (int) line number of the declaration in the source code. - `col`: [optional] the (int) column number of the declaration in the source code. If not provided, then the column number will just be set as `None`. """ self.targets = targets self.lineno = line if col is not None: self.col_offset = col if type(t) == str: self.t = PType.from_str(t) assert self.t.__class__ == PType, \ ("Got a %s back from TypeSpecParser.parse, not a PType" % cname(self.t.__class__)) elif t.__class__ == PType: self.t = t else: assert False, ("t needs to be specified as str or PType, not " + cname(t)) # these are instance variables provided by AST nodes to allow traversal # / parsing of the nodes. self._fields = ("targets", "t") self._attributes = ("lineno", "col_offset")
# FIXME: this is copied from unit_test_core, should be abstracted # away somewhere, but don't know the best way to deal with logging. with open(file_name, 'r') as f: text = f.read() untyped_ast = ast.parse(text) typedecs = parse_type_decs(file_name) typed_ast = TypeDecASTModule(untyped_ast, typedecs) if check_mod(typed_ast.tree): print "Typechecked correctly!" else: print "Did not typecheck." except IOError as e: print "File not found: %s" % e.filename elif opt.expr and opt.type and not opt.filename and not opt.infer_expr: e = ast.parse(opt.expr).body[0].value t = PType.from_str(opt.type) template = ("YES! -- %s typechecks as type %s" if check_expr(e, t, {}) else "NO! --- %s does not typecheck as type %s") print template % (opt.expr, t) elif opt.infer_expr and not opt.filename and not opt.expr and not opt.type: e = ast.parse(opt.infer_expr).body[0].value print "%s -- is the inferred type of %s" % (infer_expr(e, {}), opt.infer_expr) else: parser.print_help()
def test_is_var(self): true = self.assertTrue true( PType.from_str("'a").is_var() ) true( PType.from_str("'alpha").is_var() ) true( PType.from_str("'Yothere").is_var() ) true( PType.from_str("'hiB9").is_var() )
def test_is_arrow(self): true = self.assertTrue true( PType.from_str("int -> float").is_arrow() ) true( PType.from_str("unicode -> {int:float}").is_arrow() ) true( PType.from_str("unicode -> str -> int").is_arrow() ) true( PType.from_str("(unicode -> str) -> int").is_arrow() )
def test_is_map(self): true = self.assertTrue true( PType.from_str("{int:float}").is_map() ) true( PType.from_str("{float -> str:int}").is_map() ) true( PType.from_str("{int:unicode}").is_map() ) true( PType.from_str("{(int,int):float}").is_map() )
def test_is_list(self): true = self.assertTrue true( PType.from_str("[int]").is_list() ) true( PType.from_str("[float]").is_list() ) true( PType.from_str("[{float:str}]").is_list() )
try: # FIXME: this is copied from unit_test_core, should be abstracted # away somewhere, but don't know the best way to deal with logging. with open(file_name, 'r') as f: text = f.read() untyped_ast = ast.parse(text) typedecs = parse_type_decs(file_name) typed_ast = TypeDecASTModule(untyped_ast, typedecs) if check_mod(typed_ast.tree): print "Typechecked correctly!" else: print "Did not typecheck." except IOError as e: print "File not found: %s" % e.filename elif opt.expr and opt.type and not opt.filename and not opt.infer_expr: e = ast.parse(opt.expr).body[0].value t = PType.from_str(opt.type) template = ("YES! -- %s typechecks as type %s" if check_expr(e, t, {}) else "NO! --- %s does not typecheck as type %s") print template % (opt.expr, t) elif opt.infer_expr and not opt.filename and not opt.expr and not opt.type: e = ast.parse(opt.infer_expr).body[0].value print "%s -- is the inferred type of %s" % (infer_expr(e, {}), opt.infer_expr) else: parser.print_help()