LSL-PyOptimizer/main.py

180 lines
7.8 KiB
Python
Raw Normal View History

#!/usr/bin/env python2
# (C) Copyright 2015 Sei Lisa. All rights reserved.
#
# This file is part of LSL PyOptimizer.
#
# LSL PyOptimizer is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# LSL PyOptimizer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>.
# This is the main executable program that imports the libraries.
from lslopt.lslparse import parser,EParse
from lslopt.lsloutput import outscript
from lslopt.lsloptimizer import optimizer
import sys
import os
import lslopt.lslcommon
def main():
if len(sys.argv) < 2:
2015-03-05 12:45:38 -07:00
sys.stderr.write(
r'''LSL optimizer v0.1
(C) Copyright 2015 Sei Lisa. All rights reserved.
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it
under certain conditions; see the file COPYING for details.
This program is licensed under the GNU General Public License
version 3.
Usage: %s [-O [+|-]option[,[+|-]option[,...]]] filename
2014-07-28 08:28:12 -07:00
That's an upper case o, not the number zero.
2014-07-28 08:28:12 -07:00
If filename is a dash (-) then standard input is used.
Options (+ means active by default, - means inactive by default):
Syntax extensions options:
extendedglobalexpr + Enables arbitrary expressions in globals (as opposed to
dull simple expressions allowed by regular LSL). Needs
the optimizer to run for the result to be compilable.
breakcont - Allow break/continue statements for loops. Note that
when active, 'break' and 'continue' become reserved
words, but when inactive they can be used as variables.
extendedtypecast + Allows extended typecast syntax e.g. (string)(integer)a
is valid with this option.
extendedassignment + Enables &=, |=, ^=, <<=, >>= assignment operators.
allowkeyconcat + Allow string + key and key + string (both return string)
allowmultistrings + Allow C-like string juxtaposition, e.g. "ab" "cd" means
"abcd", no concatenation involved. Very useful when used
with a preprocessor. Similar to addstrings, but this one
is not an optimization, it introduces new syntax.
duplabels - Normally, a duplicate label within a function is allowed
by the syntax by using {} blocks; however, the server
will just refuse to save the script (under Mono) or do
something completely unexpected (under LSO: all jumps
will go to the last label with that name). This flag
works around that limitation by replacing the names of
the labels in the output with unique ones.
2015-03-07 14:55:25 -07:00
Deprecated / compatibility syntax extensions options:
lazylists - Support syntax like mylist[index] = 5; rather than using
llListReplaceList. Only assignment supported. The list
is extended when the argument is greater than the list
length, by inserting integer zeros. This is implemented
for compatibility with Firestorm, but its use is not
recommended, as it adds a new function, wasting memory
against the very spirit of this program.
2015-03-05 12:45:38 -07:00
enableswitch - Support C-like switch() syntax, with some limitations.
Like lazylists, it's implemented for compatibility with
Firestorm, but not recommended. Note that the operand to
switch() may be evaluated more than once.
Optimization options
optimize + Runs the optimizer.
optsigns + Optimize signs in float and integer constants.
optfloats + Optimize floats that represent an integral value.
constfold + Fold constant expressions to their values, and simplify
2015-03-05 12:45:38 -07:00
some expressions and statements.
dcr + Dead code removal. This option removes several instances
of code that will never execute, and performs other
optimizations like removal of unused variables,
functions or expressions.
shrinknames - Reduces script memory by shrinking identifiers. In the
process, it turns the script into unreadable gibberish,
hard to debug, but this gets big savings for complex
scripts.
addstrings - Concatenate strings together when possible. Note that
such an optimization can be counter-productive in some
2015-03-05 12:45:38 -07:00
cases, that's why it's disabled by default. For example:
string a="a"+"longstring"; string b="b"+"longstring";
would keep a single copy of "longstring", while if the
strings are added, both "alongstring" and "blongstring"
take memory.
Miscellaneous options
foldtabs - Tabs can't be copy-pasted, so expressions that produce
2015-03-05 12:45:38 -07:00
tabs, e.g. llUnescapeURL("%%09"), aren't optimized by
default. This option overrides that check, enabling
2015-03-05 12:45:38 -07:00
expansion of functions that produce strings with tabs.
The resulting source isn't guaranteed to be
copy-paste-able to the viewer.
skippreproc + Skip preprocessor directives in the source as if they
were comments. Not useful unless the script is itself
the output of a preprocessor like cpp, which inserts
directives like: # 123 "filename".
explicitcast - Add explicit casts where they are implicit. This option
is useless with 'optimize' and 'optsigns', and is of
basically no use in general, other than to see where
automatic casts happen.
''' % sys.argv[0])
return 1
options = set(('extendedglobalexpr','extendedtypecast','extendedassignment',
'allowkeyconcat','allowmultistrings','skippreproc','optimize',
'optsigns','optfloats','constfold','dcr'
))
# If it's good to append the basename to it, it's good to append the
# auxiliary files' names to it.
lslopt.lslcommon.DataPath = __file__[:-len(os.path.basename(__file__))]
2014-07-28 08:28:12 -07:00
if sys.argv[1] == '-O':
if len(sys.argv) < 4:
sys.stderr.write('Command line: Not enough parameters\n')
return 1
optchanges = sys.argv[2].split(',')
for chg in optchanges:
if chg[0:1] not in ('+', '-'):
chg = '+' + chg
if chg[0] == '-':
options.discard(chg[1:])
else:
options.add(chg[1:])
fname = sys.argv[3]
else:
fname = sys.argv[1]
p = parser()
try:
2014-07-28 08:28:12 -07:00
if fname == '-':
script = sys.stdin.read()
ts = p.parse(script, options)
2014-07-28 08:28:12 -07:00
else:
ts = p.parsefile(fname, options)
except EParse as e:
print e.message
return 1
del p
opt = optimizer()
ts = opt.optimize(ts, options)
del opt
outs = outscript()
script = outs.output(ts, options)
del outs
del ts
sys.stdout.write(script)
return 0
ret = main()
if ret:
sys.exit(ret)