mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-28 20:00:46 +00:00
131 lines
5.1 KiB
Python
Executable File
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:
|