[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__),
}
#----------------------------------------------------------------------