Fix a [side] malformation in Liberty.

Enhance wmllint to detect it anywhere.
This commit is contained in:
Eric S. Raymond 2007-07-28 16:02:47 +00:00
parent f3a96da57d
commit de3d1856cb
4 changed files with 39 additions and 21 deletions

View file

@ -99,6 +99,7 @@
[/side]
[side]
type=Necromancer
description=Mal-Jarrof
user_description= _ "Mal-Jarrof"
side=3

View file

@ -39,7 +39,7 @@
# The South Guard
[side]
[side] # wmllint: validate-off
side=1
{QUANTITY type (Horseman Commander) (Junior Commander) (Junior Commander)}
description=Deoran
@ -55,7 +55,7 @@
canrecruit=1
recruit=Peasant
[/side]
[/side] # wmllint: validate-on
# The Bandit Armies

View file

@ -57,7 +57,7 @@
# For example we can set side 1 to be a player belonging to team "Good Guys"
# starting with 200g and no income:
#! {SIDE_PLAYER 1 "Good Guys" "Good Guy #1" 200 -2 ()}
[side]
[side] # wmllint: validate-off
user_team_name={DESCRIPTION}
side={SIDE}
team_name={TEAM}
@ -66,7 +66,7 @@
gold={GOLD}
income={INCOME}
{SIDE_PARMS}
[/side]
[/side] # wmllint: validate-on
#enddef
#define SIDE_COMPUTER SIDE TEAM DESCRIPTION GOLD INCOME SIDE_PARMS AI_PARMS
@ -79,7 +79,7 @@
#! aggression=0.95
#! )}
#
[side]
[side] # wmllint: validate-off
user_team_name={DESCRIPTION}
side={SIDE}
team_name={TEAM}
@ -92,5 +92,5 @@
[ai]
{AI_PARMS}
[/ai]
[/side]
[/side] # wmllint: validate-on
#enddef

View file

@ -31,6 +31,8 @@
# Note: You can shut wmllint up about custom terrains by having a comment
# on the same line that includes the string "wmllint: ignore".
# You can also prevent description insertions with "wmllint: no-icon".
# Finally, you can disable stack-based malformation checks with a comment
# containing "wmllint: validate-off" and re-enable with "wmllint: validate-on".
import sys, os, re, getopt, string, copy, difflib, time
from wesnoth.wmltools import *
@ -453,8 +455,16 @@ def validate_stack(stack, filename, lineno):
print '"%s", line %d: %s' % (filename, lineno+1, stack)
pass
def validate_on_pop(tagstack, closer, file, lineno):
def validate_on_pop(tagstack, closer, filename, lineno):
"Validate the stack at the time a new close tag is seen."
(tag, attributes) = tagstack[-1]
ancestors = map(lambda x: x[0], tagstack)
if verbose >= 3:
print '"%s", line %d: closing %s I see %s with %s' % (filename, lineno, closer, tag, attributes)
# Detect a malformation that will cause the game to barf while attempting to
# deserialize an empty unit.
if closer == "side" and "type" not in attributes and ("no_leader" not in attributes or attributes["no_leader"] != "yes") and "multiplayer" not in ancestors:
print '"%s", line %d: [side] without type attribute' % (filename, lineno)
pass
# Syntax transformations
@ -673,6 +683,7 @@ def translator(filename, mapxforms, textxform):
outmap = []
newdata = []
lineno = baseline = 0
validate = True
while mfile:
if not map_only:
line = mfile.pop(0)
@ -751,31 +762,37 @@ def translator(filename, mapxforms, textxform):
if newline != line:
modified = True
# Now do warnings based on the state of the tag stack
trimmed = newline.split("#")[0]
fields = newline.split("#")
trimmed = fields[0]
comment = ""
if len(fields) > 1:
comment = fields[1]
for instance in re.finditer(r"\[\/?\+?([a-z][a-z_]*[a-z])\]", trimmed):
tag = instance.group(1)
while tagstack and tagstack[-1].endswith("="):
tagstack.pop()
attributes = []
closer = instance.group(0)[1] == '/'
if not closer:
tagstack.append(tag)
tagstack.append((tag, {}))
else:
if len(tagstack) == 0:
print '"%s", line %d: closer [/%s] with tag stack empty.' % (filename, lineno+1, tag)
elif tagstack[-1] != tag:
print '"%s", line %d: unbalanced [%s] closed with [/%s].' % (filename, lineno+1, tagstack[-1], tag)
elif tagstack[-1][0] != tag:
print '"%s", line %d: unbalanced [%s] closed with [/%s].' % (filename, lineno+1, tagstack[-1][0], tag)
else:
while tagstack and tagstack[-1].endswith("="):
tagstack.pop()
if validate:
validate_on_pop(tagstack, tag, filename, lineno)
tagstack.pop()
validate_on_pop(tagstack, closer, filename, lineno)
if tagstack:
for instance in re.finditer(r"([a-z][a-z_]*[a-z])\s*=", trimmed):
for instance in re.finditer(r'([a-z][a-z_]*[a-z])\s*=(\w+|"[^"]*")', trimmed):
attribute = instance.group(1)
while tagstack and tagstack[-1].endswith("="):
tagstack.pop()
tagstack.append(attribute + "=")
validate_stack(tagstack, filename, lineno)
value = instance.group(2)
tagstack[-1][1][attribute] = value
if validate:
validate_stack(tagstack, filename, lineno)
if "wmllint: validate-on" in comment:
validate = True
if "wmllint: validate-off" in comment:
validate = False
# It's an error if the tag stack is nonempty at the end of any file:
if tagstack:
print >>sys.stderr, '"%s", line %d: tag stack nonempty (%s) at end of file.' % (filename, lineno, tagstack)