mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-02 08:08:20 +00:00
Separate library function optimization into a different file.
No other functional changes. This required quite some reorganization affecting many files. As a side effect, PythonType2LSL and LSLType2Python aren't duplicate anymore.
This commit is contained in:
parent
36947b7b12
commit
6738615360
5 changed files with 359 additions and 329 deletions
|
@ -15,13 +15,15 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Transform function parameters to shorter equivalents where possible.
|
||||
# Optimize calls to LSL library functions and parameters where possible
|
||||
# This is dependent on the LSL function library.
|
||||
|
||||
from lslcommon import Key#, Vector, Quaternion
|
||||
import lslcommon
|
||||
from lslcommon import Key, Vector, Quaternion
|
||||
import lslfuncs
|
||||
|
||||
def OptimizeParams(node, sym):
|
||||
def OptimizeArgs(node, sym):
|
||||
"""Transform function arguments to shorter equivalents where possible."""
|
||||
assert node['nt'] == 'FNCALL'
|
||||
params = node['ch']
|
||||
name = node['name']
|
||||
|
@ -42,3 +44,263 @@ def OptimizeParams(node, sym):
|
|||
if not lslfuncs.cond(Key(params[i]['value'])):
|
||||
params[i]['value'] = u""
|
||||
params[i]['type'] = 'string'
|
||||
|
||||
|
||||
# Type of each entry in llGetObjectDetails. Last: 38.
|
||||
objDetailsTypes = 'issvrvkkkiiififfffkiiiiiiffkiviiksiisii'
|
||||
primParamsTypes = \
|
||||
( False, False # 0 (unassigned) and 1=PRIM_TYPE_LEGACY
|
||||
, 'i' # 2=PRIM_MATERIAL
|
||||
, 'i' # 3=PRIM_PHYSICS
|
||||
, 'i' # 4=PRIM_TEMP_ON_REZ
|
||||
, 'i' # 5=PRIM_PHANTOM
|
||||
, 'v' # 6=PRIM_POSITION
|
||||
, 'v' # 7=PRIM_SIZE
|
||||
, 'r' # 8=PRIM_ROTATION
|
||||
, 'i*' # 9=PRIM_TYPE
|
||||
, False, False, False, False # 10, 11, 12, 13 (unassigned)
|
||||
, False, False, False # 14, 15, 16 (unassigned)
|
||||
, 'svvf' # 17=PRIM_TEXTURE
|
||||
, 'vf' # 18=PRIM_COLOR
|
||||
, 'ii' # 19=PRIM_BUMP_SHINY
|
||||
, 'i' # 20=PRIM_FULLBRIGHT
|
||||
, 'iiffffv' # 21=PRIM_FLEXIBLE
|
||||
, 'i' # 22=PRIM_TEXGEN
|
||||
, 'ivfff' # 23=PRIM_POINT_LIGHT
|
||||
, False # 24 (unassigned)
|
||||
, 'f' # 25=PRIM_GLOW
|
||||
, 'svf' # 26=PRIM_TEXT
|
||||
, 's' # 27=PRIM_NAME
|
||||
, 's' # 28=PRIM_DESC
|
||||
, 'r' # 29=PRIM_ROT_LOCAL
|
||||
, 'i' # 30=PRIM_PHYSICS_SHAPE_TYPE
|
||||
, False # 31 (unassigned)
|
||||
, 'vff' # 32=PRIM_OMEGA
|
||||
, 'v' # 33=PRIM_POS_LOCAL
|
||||
, '' # 34=PRIM_LINK_TARGET
|
||||
, 'v' # 35=PRIM_SLICE
|
||||
, 'svvfvii' # 36=PRIM_SPECULAR
|
||||
, 'svvf' # 37=PRIM_NORMAL
|
||||
, 'ii' # 38=PRIM_ALPHA_MODE
|
||||
, 'i' # 39=PRIM_ALLOW_UNSIT
|
||||
, 'i' # 40=PRIM_SCRIPTED_SIT_ONLY
|
||||
, 'ivv' # 41=PRIM_SIT_TARGET
|
||||
)
|
||||
# Primitive Params with arguments. F=face, L=link.
|
||||
primParamsArgs = \
|
||||
{ 17: 'F' # 17=PRIM_TEXTURE
|
||||
, 18: 'F' # 18=PRIM_COLOR
|
||||
, 19: 'F' # 19=PRIM_BUMP_SHINY
|
||||
, 20: 'F' # 20=PRIM_FULLBRIGHT
|
||||
, 22: 'F' # PRIM_TEXGEN
|
||||
, 25: 'F' # PRIM_GLOW
|
||||
, 34: 'L' # PRIM_LINK_TARGET
|
||||
, 36: 'F' # PRIM_SPECULAR
|
||||
, 37: 'F' # PRIM_NORMAL
|
||||
, 38: 'F' # PRIM_ALPHA_MODE
|
||||
}
|
||||
|
||||
# Compatibility: list extraction function / input type (by type's first
|
||||
# letter), e.g. 'si' means llList2String can extract an integer.
|
||||
listCompat = frozenset({'ss', 'sk', 'si', 'sf', 'sv', 'sr', 'ks', 'kk',
|
||||
'is', 'ii', 'if', 'fs', 'fi', 'ff', 'vv', 'rr'})
|
||||
|
||||
defaultListVals = {'llList2Integer':0, 'llList2Float':0.0,
|
||||
'llList2String':u'',
|
||||
# llList2Key is set programmatically in FoldScript
|
||||
#'llList2Key':Key(u''),
|
||||
'llList2Vector':Vector((0.,0.,0.)),
|
||||
'llList2Rot':Quaternion((0.,0.,0.,1.))}
|
||||
|
||||
# The 'self' parameter here is the constant folding object.
|
||||
def OptimizeFunc(self, parent, index):
|
||||
"""Look for possible optimizations taking advantage of the specific LSL
|
||||
library function semantics.
|
||||
"""
|
||||
node = parent[index]
|
||||
assert node['nt'] == 'FNCALL'
|
||||
name = node['name']
|
||||
child = node['ch']
|
||||
if self.optlistlength and name == 'llGetListLength':
|
||||
# Convert llGetListLength(expr) to (expr != [])
|
||||
node = {'nt':'CONST', 't':'list', 'value':[]}
|
||||
parent[index] = node = {'nt':'!=', 't':'integer',
|
||||
'ch':[child[0], node]}
|
||||
# SEF if the list is
|
||||
node['SEF'] = 'SEF' in child[0]
|
||||
if name == 'llDumpList2String':
|
||||
if (child[1]['nt'] == 'CONST'
|
||||
and child[1]['t'] in ('string', 'key')
|
||||
and child[1]['value'] == u""
|
||||
):
|
||||
# Convert llDumpList2String(expr, "") to (string)(expr)
|
||||
node['nt'] = 'CAST'
|
||||
del child[1]
|
||||
del node['name']
|
||||
return
|
||||
|
||||
if (name in ('llList2String', 'llList2Key', 'llList2Integer',
|
||||
'llList2Float', 'llList2Vector', 'llList2Rot')
|
||||
and child[1]['nt'] == 'CONST'
|
||||
):
|
||||
# 2nd arg to llList2XXXX must be integer
|
||||
assert child[1]['t'] == 'integer'
|
||||
|
||||
listarg = child[0]
|
||||
idx = child[1]['value']
|
||||
value = self.GetListNodeElement(listarg, idx)
|
||||
tvalue = self.TypeFromNodeOrConst(value)
|
||||
const = self.ConstFromNodeOrConst(value)
|
||||
if const is not False and 'SEF' in node:
|
||||
# Managed to get a constant from a list, even if the
|
||||
# list wasn't constant. Handle the type conversion.
|
||||
if (node['t'][0] + tvalue[0]) in listCompat:
|
||||
const = lslfuncs.InternalTypecast(const,
|
||||
lslcommon.LSLType2Python[node['t']],
|
||||
InList=True, f32=True)
|
||||
else:
|
||||
const = defaultListVals[name]
|
||||
|
||||
parent[index] = {'nt':'CONST', 't':node['t'],
|
||||
'value':const, 'SEF':True}
|
||||
return
|
||||
|
||||
if listarg['nt'] == 'FNCALL' \
|
||||
and listarg['name'] == 'llGetObjectDetails':
|
||||
|
||||
listarg = listarg['ch'][1] # make it the list argument of llGetObjectDetails
|
||||
value = self.GetListNodeElement(listarg, idx)
|
||||
tvalue = self.TypeFromNodeOrConst(value)
|
||||
const = self.ConstFromNodeOrConst(value)
|
||||
if type(const) == int and self.GetListNodeLength(listarg) == 1:
|
||||
# Some of these can be handled with a typecast to string.
|
||||
if name == 'llList2String':
|
||||
# turn the node into a cast of arg 0 to string
|
||||
node['nt'] = 'CAST'
|
||||
del child[1]
|
||||
del node['name']
|
||||
return
|
||||
# The other ones that support cast to string then to
|
||||
# the final type in some cases (depending on the
|
||||
# list type, which we know) are key/int/float.
|
||||
finaltype = objDetailsTypes[const:const+1]
|
||||
if (name == 'llList2Key' # checked via listCompat
|
||||
or (name == 'llList2Integer'
|
||||
and finaltype in ('s', 'i')) # won't work for floats
|
||||
or (name == 'llList2Float'
|
||||
and finaltype in ('s', 'i')) # won't work for floats
|
||||
) and (node['t'][0] + finaltype) in listCompat:
|
||||
# -> (key)((string)llGetObjectDetails...)
|
||||
# or (integer)((string)llGetObjectDetails...)
|
||||
node['nt'] = 'CAST'
|
||||
del child[1]
|
||||
del node['name']
|
||||
child[0] = {'nt':'CAST', 't':'string',
|
||||
'ch':[child[0]]}
|
||||
if 'SEF' in child[0]['ch'][0]:
|
||||
child[0]['SEF'] = True
|
||||
return
|
||||
|
||||
# Check for type incompatibility or index out of range
|
||||
# and replace node with a constant if that's the case
|
||||
if (value is False
|
||||
or type(const) == int
|
||||
and (node['t'][0] + objDetailsTypes[const])
|
||||
not in listCompat
|
||||
) and 'SEF' in node:
|
||||
parent[index] = {'nt':'CONST', 't':node['t'],
|
||||
'value':defaultListVals[name],
|
||||
'SEF':True}
|
||||
|
||||
elif listarg['nt'] == 'FNCALL' and listarg['name'] in (
|
||||
'llGetPrimitiveParams', 'llGetLinkPrimitiveParams'):
|
||||
# We're going to work with the primitive params list.
|
||||
listarg = listarg['ch'][
|
||||
0 if listarg['name'] == 'llGetPrimitiveParams'
|
||||
else 1]
|
||||
length = self.GetListNodeLength(listarg)
|
||||
if length is not False:
|
||||
# Construct a list (string) of return types.
|
||||
# A '*' in the list means the type can't be
|
||||
# determined past this point (used with PRIM_TYPE).
|
||||
i = 0
|
||||
returntypes = ''
|
||||
while i < length:
|
||||
param = self.GetListNodeElement(listarg, i)
|
||||
param = self.ConstFromNodeOrConst(param)
|
||||
if (param is False
|
||||
or type(param) != int
|
||||
# Parameters with arguments have
|
||||
# side effects (errors).
|
||||
# We could check whether there's a face
|
||||
# argument and the face is 0, which is
|
||||
# guaranteed to exist, but it's not worth
|
||||
# the effort.
|
||||
or param in primParamsArgs
|
||||
or param < 0
|
||||
or param >= len(primParamsTypes)
|
||||
or primParamsTypes[param] is False
|
||||
):
|
||||
# Can't process this list.
|
||||
returntypes = '!'
|
||||
break
|
||||
returntypes += primParamsTypes[param]
|
||||
i += 1
|
||||
if returntypes != '!':
|
||||
if (len(returntypes) == 1
|
||||
and returntypes != '*'
|
||||
and idx in (0, -1)
|
||||
):
|
||||
if name == 'llList2String':
|
||||
node['nt'] = 'CAST'
|
||||
del child[1]
|
||||
del node['name']
|
||||
return
|
||||
if ((name == 'llList2Key'
|
||||
or name == 'llList2Integer'
|
||||
and returntypes in ('s', 'i')
|
||||
or name == 'llList2Float'
|
||||
and returntypes in ('s', 'i')
|
||||
)
|
||||
and (node['t'][0] + returntypes)
|
||||
in listCompat
|
||||
):
|
||||
node['nt'] = 'CAST'
|
||||
del child[1]
|
||||
del node['name']
|
||||
child[0] = {'nt':'CAST', 't':'string',
|
||||
'ch':[child[0]]}
|
||||
if 'SEF' in child[0]['ch'][0]:
|
||||
child[0]['SEF'] = True
|
||||
return
|
||||
|
||||
if (returntypes.find('*') == -1
|
||||
or idx >= 0 and idx < returntypes.find('*')
|
||||
or idx < 0 and idx > returntypes.rfind('*')
|
||||
- len(returntypes)
|
||||
):
|
||||
# Check for type incompatibility or index
|
||||
# out of range.
|
||||
if idx < 0:
|
||||
# s[-1:0] doesn't return the last char
|
||||
# so we have to compensate
|
||||
idx += len(returntypes)
|
||||
if (node['t'][0] + returntypes[idx:idx+1]) \
|
||||
not in listCompat \
|
||||
and 'SEF' in node:
|
||||
parent[index] = {'nt':'CONST',
|
||||
't':node['t'],
|
||||
'value':defaultListVals[name],
|
||||
'SEF':True}
|
||||
return
|
||||
|
||||
del returntypes
|
||||
|
||||
del listarg, idx, value, tvalue, const
|
||||
|
||||
def FuncOptSetup():
|
||||
# Patch the default values list for LSO
|
||||
if lslcommon.LSO:
|
||||
defaultListVals['llList2Key'] = Key(lslfuncs.NULL_KEY)
|
||||
else:
|
||||
defaultListVals['llList2Key'] = Key(u"")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue