[Types-sig] A challenge
Tim Peters
tim_one@email.msn.com
Wed, 15 Dec 1999 22:55:18 -0500
[Guido]
> There seem to be several proposals for type declaration syntaxes
> out there, with (mostly implied) suggestions on how to spell
> various types etc.
>
> I personally am losing track of all the various proposals.
You're not alone <wink>.
> I would encourage the proponents of each approach to sit down with
> some sample code and mark it up using your proposed syntax. Or write
> the corresponding interface file, if that's your fancy.
I like interface files fine, but will stick to inline "decl"s below.
Apparently unlike anyone else here, I think explicit declarations can make
code easier for *human readers* to understand -- so I'm not interested in
hiding them from view.
> I recommend using the sample code that I posted as a case study,
> including some of the imported modules -- this should be a
> reasonable but not extreme challenge.
Sorry, but if we avoid excessive novelty, it's just a finger exercise <0.5
wink>.
Note that you convert this back to Python 1.5.x code simply by commenting
out the decl stmts.
if-it-looks-a-lot-like-every-other-reasonable-declaration-
syntax-you've-ever-seen-it-met-its-goal-ly y'rs - tim
import sys, find
decl main: def() -> None
def main():
decl dir: String, list: [String], name: String
dir = "."
if sys.argv[1:]:
dir = sys.argv[1]
list = find.find("*.py", dir)
list.sort()
for name in list:
print name
if __name__ == "__main__":
main()
----------------------------------------------------
import fnmatch
import os
decl _debug: Int # but Boolean makes more sense; see below
_debug = 0
decl _prune: [String]
_prune = ['(*)']
decl find: def(String, optional dir: String) -> [String]
def find(pattern, dir = os.curdir):
decl list, names: [String], name: String
list = []
names = os.listdir(dir)
names.sort()
for name in names:
decl name, fullname: String
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):
decl p: String
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
#----------------------------------------------------------------------
import re
# Declaring the type of _cache is irritating, because so far
# as current Python is concerned a compiled regexp is of
# type Instance, and that's too inclusive to be interesting.
# I'm giving its class name instead.
decl _cache: {String: RegexObject}
_cache = {}
# Assuming a Boolean "type" exists, if for no other reason
# than to support meaningful (to humans!) type declarations.
# Declaring all the function signatures in a block here, for
# the heck of it. BTW, this is an example of how decls can
# aid human comprehension -- e.g., I had to reverse-engineer
# the code to figure out whether the "pat" arguments were
# supposed to be strings or compiled regexps. They don't
# both work, and the name "pat" doesn't answer it.
decl fnmatch: def(String, String) -> Boolean, \
fnmatchcase: def(String, String) -> Boolean, \
translate: def(String) -> String
def fnmatch(name, pat):
import os
name = os.path.normcase(name)
pat = os.path.normcase(pat)
return fnmatchcase(name, pat)
def fnmatchcase(name, pat):
if not _cache.has_key(pat):
decl res: String
res = translate(pat)
_cache[pat] = re.compile(res)
return _cache[pat].match(name) is not None
def translate(pat):
decl i, n: Int, res: String
i, n = 0, len(pat)
res = ''
while i < n:
decl c: String
c = pat[i]
i = i+1
if c == '*':
res = res + '.*'
elif c == '?':
res = res + '.'
elif c == '[':
decl j: Int
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:
decl stuff: String
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 + "$"