[Types-sig] A challenge

Martijn Faassen m.faassen@vet.uu.nl
Thu, 16 Dec 1999 15:52:12 +0100


Hi there,

Here's my approach towards type annotations. Note that this syntax is
not
be very readable, but it is very powerful as it's Python; readable
syntax
can be developed later. I was lucky because no classes are defined in
any of the modules in Guido's example, this means it's fairly readable.
:)

Type annotations for function locals generally follow under the function
definition, type annotations for the entire module follow at the bottom
of
the module. This order is taken mostly because __types__ uses the other
type 
declarations in itself; the type checker can simply look at __types__
and
find all information in there; the __types_foo__ notation is just for
convenience. All the type annotations could of course also reside in
external interface files. I'm also hinting at a typedef system for
complicated composite types.

Regards,

Martijn

#----------------------------------------------------------------------
import sys, find

# assume static type classes and such are builtin, for this example

def main():
    dir = "."
    if sys.argv[1:]:
        dir = sys.argv[1]
    list = find.find("*.py", dir)
    list.sort()
    for name in list:
        print name

__types_main__ = {
    'dir' : StringType,
    'list' : ListType(StringType),
    'sys.argv' : ListType(StringType) # supply extra types by hand
    # the type checker should look the 'find' module for more type
information
    # automatically
}

if __name__ == "__main__":
    main()

__types__ = {
    'main' : FunctionType(args=None, result=None,
			  local=__types_main__)
    'name' : StringType,
    '__name__' : StringType # might already be defined somewhere else
}

#----------------------------------------------------------------------


#----------------------------------------------------------------------
import fnmatch
import os

_debug = 0

_prune = ['(*)']

def find(pattern, dir = os.curdir):
    list = []
    names = os.listdir(dir)
    names.sort()
    for name in names:
        if name in (os.curdir, os.pardir):
            continue
        fullname = os.path.join(dir, name)
        if fnmatch.fnmatch(name, pattern):
            list.append(fullname)
        if os.path.isdir(fullname) and not os.path.islink(fullname):
            for p in _prune:
                if fnmatch.fnmatch(name, p):
                    if _debug: print "skip", `fullname`
                    break
            else:
                if _debug: print "descend into", `fullname`
                list = list + find(pattern, fullname)
    return list

__types_find__ = {
    'list' : ListType(StringType),
    'names' : ListType(StringType),
    'name' : StringType,
    'os.curdir' : StringType,
    'os.pardir' : StringType,
    'fullname' : StringType,
    'os.path.isdir' : ImpFunctionType(args=(StringType,),
result=IntegerType),
    'os.path.islink' : ImpFunctionType(args=(StringType,),
result=IntegerType),
    'p' : StringType,
}

__types__ = {
    '_debug' : IntegerType,
    '_prune' : ListType(StringType),
    'find' : FunctionType(args=(StringType, StringType),
			  result=ListType(StringType),
			  local=__types_find__)
}


#----------------------------------------------------------------------

#----------------------------------------------------------------------
import re

_cache = {}

def fnmatch(name, pat):
        import os
        name = os.path.normcase(name)
        pat = os.path.normcase(pat)
        return fnmatchcase(name, pat)

__types_fnmatch__ = {
    'os.path.normcase' : ImpFunctionType(args=(StringType,), 
					 result=StringType),
    }

def fnmatchcase(name, pat):
        if not _cache.has_key(pat):
                res = translate(pat)
                _cache[pat] = re.compile(res)
        return _cache[pat].match(name) is not None


__types_fnmatchcase__ = {
    'res' : StringType,
    }

def translate(pat):
        i, n = 0, len(pat)
        res = ''
        while i < n:
                c = pat[i]
                i = i+1
                if c == '*':
                        res = res + '.*'
                elif c == '?':
                        res = res + '.'
                elif c == '[':
                        j = i
                        if j < n and pat[j] == '!':
                                j = j+1
                        if j < n and pat[j] == ']':
                                j = j+1
                        while j < n and pat[j] != ']':
                                j = j+1
                        if j >= n:
                                res = res + '\\['
                        else:
                                stuff = pat[i:j]
                                i = j+1
                                if stuff[0] == '!':
                                        stuff = '[^' + stuff[1:] + ']'
                                elif stuff == '^'*len(stuff):
                                        stuff = '\\^'
                                else:
                                        while stuff[0] == '^':
                                                stuff = stuff[1:] +
stuff[0]
                                        stuff = '[' + stuff + ']'
                                res = res + stuff
                else:
                        res = res + re.escape(c)
        return res + "$"


__types_translate__ = {
    'i' : IntegerType,
    'n' : IntegerType,
    'res' : StringType,
    'c' : StringType, # or CharType ?
    'j' : IntegerType,
    'stuff' : StringType,
    }

__types__ = {
    # cheating; I'm assuming re has a ReObjectType defined somewhere
    # this is probably a very complicated construction
    # we're also assuming re functions are defined in re
    '_cache' : DictType(key=StringType,
value=re.__typedefs__['ReObjectType']),
    'fnmatch' : FunctionType(args=(StringType, StringType),
result=IntegerType,
			     local=__types_fnmatch__),
    'fnmatchcase' : FunctionType(args=(StringType, StringType), 
				 result=IntegerType,
				 local=__types_fnmatchcase__),
    'translate' : FunctionType(args=(StringType,), result=StringType,
			       local=__types_translate__),
    }

#----------------------------------------------------------------------