Implement checking of range, span, and filter types in macros.

Show the type signatures in ythe wmlscope error messages for the mismatches.
This commit is contained in:
Eric S. Raymond 2008-02-06 20:22:44 +00:00
parent 8a2db11ceb
commit 7eb3510fca
3 changed files with 43 additions and 27 deletions

View file

@ -47,12 +47,12 @@
villages_per_scout=0
#enddef
#define RANDOM RANGE
#define RANDOM THING
# Macro to quickly pick a random value (in the $random variable, to avoid
# cluttering up savegames with such temporary variables).
[set_variable]
name=random
rand={RANGE}
rand={THING}
[/set_variable]
#enddef

View file

@ -60,37 +60,53 @@ def isresource(filename):
(root, ext) = os.path.splitext(filename)
return ext and ext[1:] in resource_extensions
def formaltype(f):
# Deduce the expected type of the formal
if f in ("SIDE",):
ftype = "numeric"
elif f in ("X", "Y", "SPAN"):
ftype = "span"
elif f in ("RANGE",):
ftype = "range"
elif f in ("TYPE", "DESCRIPTION", "USER_DESCRIPTION", "TERRAIN"):
ftype = "string"
elif f.endswith("IMAGE"):
ftype = "image"
elif f in ("FILTER",):
ftype = "filter"
else:
ftype = None
return ftype
def actualtype(a):
# Deduce the type of the actual
if a.isdigit() or a.startswith("-") and a[1:].isdigit():
atype = "numeric"
elif re.match(r"([0-9]+\-[0-9]+,?|[0-9]+,?)+\Z", a):
atype = "span"
elif a in ("melee", "ranged"):
atype = "range"
elif a.startswith("{") and a.endswith("}") or a.startswith("$"):
atype = None # Can't tell -- it's a macro expansion
elif a.endswith(".png") or a.endswith(".jpg"):
atype = "image"
elif "=" in a:
atype = "filter"
else:
atype = "string"
return atype
def argmatch(formals, actuals):
if len(formals) != len(actuals):
return False
for (f, a) in zip(formals, actuals):
# Deduce the expected type of the formal
if f in ("SIDE",):
ftype = "numeric"
elif f in ("X", "Y"):
ftype = "range"
elif f in ("TYPE", "DESCRIPTION", "USER_DESCRIPTION", "TERRAIN"):
ftype = "string"
elif f.endswith("IMAGE"):
ftype = "image"
else:
ftype = None
# Deduce the type of the actual
if a.isdigit() or a.startswith("-") and a[1:].isdigit():
atype = "numeric"
elif re.search(r"[0-9]+\-[0-9]+", a):
atype = "range"
elif a.startswith("{") and a.endswith("}") or a.startswith("$"):
atype = None # Can't tell -- it's a macro expansion
elif a.endswith(".png") or a.endswith(".jpg"):
atype = "image"
else:
atype = "string"
ftype = formaltype(f)
atype = actualtype(a)
# Here's the compatibility logic. First, we catch the situations
# in which a more restricted actual type matches a more general
# formal one. Then we have a fallback rule checking for type
# equality or wildcarding.
if atype == "numeric" and ftype == "range":
if atype == "numeric" and ftype == "span":
pass
elif atype == "image" and ftype == "string":
pass

View file

@ -139,10 +139,10 @@ class CrossRefLister(CrossRef):
if mismatched:
print "# Mismatched references:"
for (n, m) in mismatched:
print "%s: macro %s(%s) has signature mismatches:" % (m, n, ", ".join(m.args))
print "%s: macro %s(%s) has signature (%s) mismatches:" % (m, n, ", ".join(m.args), ", ".join(map(lambda x: str(formaltype(x)), m.args)))
for (file, refs) in m.references.items():
for (ln, args) in refs:
print '"%s", line %d: %s(%s)' % (file, ln, n, ", ".join(args))
print '"%s", line %d: %s(%s) with signature (%s)' % (file, ln, n, ", ".join(args), ", ".join(map(lambda x: str(actualtype(x)), args)))
def deflist(self, pred=None):
"List all resource definitions."
sorted = self.xref.keys()