Add --blacklist, to blacklist constants; defauls to NAK,JSON_*

Closes #30, but not the general problem of control characters in the source.
This commit is contained in:
Sei Lisa 2024-05-28 13:24:42 +02:00
parent 5841c2c17a
commit d03de9a6be
3 changed files with 54 additions and 13 deletions

View file

@ -2825,9 +2825,9 @@ list lazy_list_set(list L, integer i, list v)
if lib is None: if lib is None:
lib = self.lib lib = self.lib
self.events = lib[0] self.events = lib[0].copy()
self.constants = lib[1] self.constants = lib[1].copy()
self.funclibrary = lib[2] self.funclibrary = lib[2].copy()
self.TypeToExtractionFunction.clear() self.TypeToExtractionFunction.clear()
for name in self.funclibrary: for name in self.funclibrary:
@ -2966,15 +2966,24 @@ list lazy_list_set(list L, integer i, list v)
self.scopestack = [0] self.scopestack = [0]
if self.prettify: if self.prettify:
# Add the constants as symbol table variables... # Add all constants to the blacklist
for i in self.constants: self.blacklist = list(u2str(i) for i in self.constants.keys())
self.symtab[0][i] = {'Kind':'c', 'Scope':0,
'Type':lslcommon.PythonType2LSL[type(self.constants[i])]}
# ... and remove them as constants.
self.constants = {}
# Remove TRUE and FALSE from keywords # Remove TRUE and FALSE from keywords
self.keywords -= set(('TRUE', 'FALSE')) self.keywords -= set(('TRUE', 'FALSE'))
# Some unit tests that reuse the parser object don't initialize the
# blacklist, so we don't rely on it being set.
if not hasattr(self, 'blacklist'):
self.blacklist = []
for name in self.blacklist:
# Add the blacklisted constants to the symbol table...
self.symtab[0][name] = {'Kind':'c', 'Scope':0, 'W':False,
'Type':lslcommon.PythonType2LSL[type(self.constants[name])]}
# ... and remove them from the list of substitutable constants.
del self.constants[name]
assert not self.prettify or len(self.constants) == 0
# Last preprocessor __FILE__. <stdin> means the current file. # Last preprocessor __FILE__. <stdin> means the current file.
self.lastFILE = '<stdin>' self.lastFILE = '<stdin>'

View file

@ -89,6 +89,8 @@ class renamer(object):
functions.append(name) functions.append(name)
elif kind == 'v': elif kind == 'v':
globalvars.append(name) globalvars.append(name)
elif kind == 'c':
pass
else: else:
assert False, 'Invalid kind at this scope: ' \ assert False, 'Invalid kind at this scope: ' \
+ kind # pragma: no cover + kind # pragma: no cover

38
main.py
View file

@ -214,7 +214,7 @@ u"""LSL optimizer v{version}
version 3. version 3.
Usage: {progname} Usage: {progname}
[-O|--optimizer-options=[+|-]option[,[+|-]option[,...]]] [-O|--optimizer-options=[+|-]<option>[,[+|-]<option>[,...]]]
optimizer options (use '-O help' for help) optimizer options (use '-O help' for help)
[-h|--help] print this help [-h|--help] print this help
[--version] print this program's version [--version] print this program's version
@ -238,7 +238,11 @@ Usage: {progname}
[--avname=<name>] * specify name of avatar saving the script [--avname=<name>] * specify name of avatar saving the script
[--assetid=<UUID>] * specify the asset UUID of the script [--assetid=<UUID>] * specify the asset UUID of the script
[--shortname=<name>] * specify the script's short file name [--shortname=<name>] * specify the script's short file name
[--prettify] Prettify source file. Disables all -O options. [-B|--blacklist=<consts>] Comma-separated list of LSL constants that
should appear verbatim in the source, without
being expanded. Defaults to: NAK,JSON_*
[--prettify] Prettify source file. Disables all -O options
and blacklists all constants.
[--bom] Prefix script with a UTF-8 byte-order mark [--bom] Prefix script with a UTF-8 byte-order mark
[--emap] Output error messages in a format suitable for [--emap] Output error messages in a format suitable for
automated processing automated processing
@ -410,12 +414,12 @@ def main(argv):
% (b"', '".join(options - validoptions)).decode('utf8')) % (b"', '".join(options - validoptions)).decode('utf8'))
try: try:
opts, args = getopt.gnu_getopt(argv[1:], 'hO:o:p:P:HTyb:L:A:', opts, args = getopt.gnu_getopt(argv[1:], 'hO:o:p:P:HTyb:L:A:B:',
('optimizer-options=', 'help', 'version', 'output=', 'header', ('optimizer-options=', 'help', 'version', 'output=', 'header',
'timestamp', 'python-exceptions', 'prettify', 'bom', 'emap', 'timestamp', 'python-exceptions', 'prettify', 'bom', 'emap',
'preproc=', 'precmd=', 'prearg=', 'prenodef', 'preshow', 'preproc=', 'precmd=', 'prearg=', 'prenodef', 'preshow',
'avid=', 'avname=', 'assetid=', 'shortname=', 'builtins=', 'avid=', 'avname=', 'assetid=', 'shortname=', 'builtins=',
'libdata=', 'postarg=', 'preproc-show-cmdline')) 'libdata=', 'postarg=', 'preproc-show-cmdline', 'blacklist='))
except getopt.GetoptError as e: except getopt.GetoptError as e:
Usage(argv[0]) Usage(argv[0])
werr(u"\nError: %s\n" % str2u(str(e), 'utf8')) werr(u"\nError: %s\n" % str2u(str(e), 'utf8'))
@ -441,6 +445,7 @@ def main(argv):
emap = False emap = False
builtins = None builtins = None
libdata = None libdata = None
blacklist = ['NAK','JSON_*']
for opt, arg in opts: for opt, arg in opts:
if opt in ('-O', '--optimizer-options'): if opt in ('-O', '--optimizer-options'):
@ -543,6 +548,9 @@ def main(argv):
elif opt == '--prettify': elif opt == '--prettify':
prettify = True prettify = True
elif opt in {'-B', '--blacklist'}:
blacklist = arg.split(',') if arg != '' else []
elif opt == '--bom': elif opt == '--bom':
bom = True bom = True
@ -727,7 +735,29 @@ def main(argv):
options.add('emap') options.add('emap')
lib = lslopt.lslloadlib.LoadLibrary(builtins, libdata) lib = lslopt.lslloadlib.LoadLibrary(builtins, libdata)
wildcards = re.compile(str2u(r'^\*?[A-Za-z_?][A-Za-z0-9_*?]*$'))
for i in xrange(len(blacklist)-1, -1, -1):
c = blacklist[i]
if not wildcards.search(c):
werr(u"Error: blacklist: \"%s\" contains invalid"
u" characters\n" % c)
return 1
expr = re.compile(c.replace('?', '.').replace('*', '.*') + '$')
matches = [j for j in lib[1].keys() if expr.match(j)]
# if not matches:
# werr(u"Error: blacklist: \"%s\" does not match any constant"
# u"\n" % c)
# return 1
if not matches or matches[0] != c:
blacklist = blacklist[:i] + matches + blacklist[i+1:]
blacklist = list(set(blacklist)) # remove dupes
p = parser(lib) p = parser(lib)
p.blacklist = blacklist
del blacklist
assert type(script) == str assert type(script) == str
try: try:
ts = p.parse(script, options, ts = p.parse(script, options,