[Types-sig] A challenge

Tim Peters tim_one@email.msn.com
Wed, 15 Dec 1999 22:55:18 -0500

> 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

Note that you convert this back to Python 1.5.x code simply by commenting
out the decl stmts.

    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)
    for name in list:
        print name

if __name__ == "__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)
    for name in names:
        decl name, fullname: String
        if name in (os.curdir, os.pardir):
        fullname = os.path.join(dir, name)
        if fnmatch.fnmatch(name, pattern):
        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`
                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 + '\\['
                decl stuff: String
                stuff = pat[i:j]
                i = j+1
                if stuff[0] == '!':
                    stuff = '[^' + stuff[1:] + ']'
                elif stuff == '^'*len(stuff):
                    stuff = '\\^'
                    while stuff[0] == '^':
                        stuff = stuff[1:] + stuff[0]
                    stuff = '[' + stuff + ']'
                res = res + stuff
            res = res + re.escape(c)
    return res + "$"