wesnoth/data/tools/wmltest

131 lines
5.1 KiB
Python
Executable File

#!/usr/bin/env python
"""
wmltest -- tool to test the integrity and meaning of WML.
Use --help to see usage.
"""
#TODO:
#-Write function to check dependencies
#List of dependencies to check:
#-defense,movement_costs: keys should be valid terrain
#-resistance: keys should be valid damage types
#-effect: valid keys vary depending on name
#-[attack] type: value should be valid damage types
#-[filter_attack]'s keys' values
import wesnoth.wmldata as wmldata
import wesnoth.wmlparser as wmlparser
import wesnoth.wmlgrammar as wmlgrammar
import re
def print_indent(string, depth, char=' '):
print "%s%s" % (depth * char, string)
class Tester:
"""
The Tester class, this walks the WML tree and checks whether stuff has meaning. (among other things)
"""
def __init__(self, wmltree, verbosity):
self.wmltree = wmltree
self.verbosity = verbosity
self.grammar = wmlgrammar.Grammar().grammar()
def test(self, tag=None, depth=0):
"""Tests whether things have meaning, walks the wml tree."""
if not tag:
tag = self.wmltree
if self.verbosity > 2:
print_indent(tag.name, depth, ' ')
for item in tag.data:
if isinstance(item, wmldata.DataSub):
if item.name in self.grammar[tag.name][0]:
self.test(item, depth + 1)
else:
found = False
for d in filter(lambda x:isinstance(x,dict),self.grammar[tag.name][0]):
# We only check the first key in the dict, as it should only have one
key = d.keys()[0]
if isinstance(key, str) and key == item.name \
or isinstance(key, re._pattern_type) and key.search(item.name):
found = True
item.name = d[key]
self.test(item, depth + 1)
break # Don't recurse into the catch-all
if not found:
print_indent("[%s] (%s:%d) is meaningless in [%s] (%s:%d)" % (item.name, item.file, item.line, tag.name, tag.file, tag.line), depth + 1, '*')
elif isinstance(item, wmldata.DataText):
if item.translatable:
underscore = " _ "
else:
underscore = ""
if item.name in self.grammar[tag.name][1] or any(map(lambda x:(bool)(x.search(item.name)),filter(lambda x:isinstance(x,re._pattern_type),self.grammar[tag.name][1]))):
if self.verbosity > 2:
print_indent("%s=%s\"%s\"" % (item.name, underscore, item.data), depth + 1, ' ')
else:
print_indent("%s=%s\"%s\" (%s:%d) is meaningless in [%s] (%s:%d)" % (item.name, underscore, item.data, item.file, item.line, tag.name, tag.file, tag.line), depth + 1, '*')
else:
raise Exception( "Wmlparser gave us an object of class %s" % (item.__class__,) )
if __name__ == '__main__':
import optparse, subprocess, os, codecs, sys
# Ugly hack to force the output of UTF-8.
# This prevents us from crashing when we're being verbose
# and encounter a non-ascii character.
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
op = optparse.OptionParser()
op.set_usage("Usage: %prog [options] [filename]")
op.add_option("-p", "--path",
help = "Specify Wesnoth's data dir.",
dest = "path")
op.add_option("-u", "--userpath",
help = "Specify user data dir..",
dest = "userpath")
op.add_option("-v", "--verbose",
action = "count",
dest = "verbose",
help = "Increase verbosity, 4 is the maximum.")
op.add_option("-D", "--define",
action = "append",
dest = "defines",
default = [],
help = "Define (empty) preprocessor macros, for campaign/multiplayer inclusion.")
(options, args) = op.parse_args()
if not options.path:
try:
p = subprocess.Popen(["wesnoth", "--path"], stdout = subprocess.PIPE)
path = p.stdout.read().strip()
options.path = os.path.join(path, "data")
sys.stderr.write("No Wesnoth path given.\nAutomatically found '%s'\n" % (options.path, ) )
except OSError:
options.path = '.'
sys.stderr.write("Could not determine Wesnoth path.\nAssuming '%s'\n" % (options.path, ) )
if len(args) < 1:
args.append('%s/_main.cfg' % options.path)
if options.verbose > 1:
print "Options: %s\nArgs: %s\n"% (options, args)
parser = wmlparser.Parser(options.path, options.userpath)
if options.verbose > 3:
parser.verbose = True
if options.userpath:
parser.parse_text("{~campaigns}")
for file in args:
parser.parse_file(file)
for macro in options.defines:
parser.parse_text("#define %s \n#enddef" % (macro, ) )
data = wmldata.DataSub("WML")
parser.parse_top(data)
tester = Tester(data, options.verbose)
tester.test()
# vim: tabstop=4: shiftwidth=4: expandtab: softtabstop=4: autoindent: