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:
Sei Lisa 2017-08-25 20:11:16 +02:00
parent 36947b7b12
commit 6738615360
5 changed files with 359 additions and 329 deletions

View file

@ -45,3 +45,13 @@ LSO = False
IsCalc = False IsCalc = False
DataPath = '' DataPath = ''
# Conversion of LSL types to Python types and vice versa.
PythonType2LSL = {int: 'integer', float: 'float',
unicode: 'string', Key: 'key', Vector: 'vector',
Quaternion: 'rotation', list: 'list'}
LSLType2Python = {'integer':int, 'float':float,
'string':unicode, 'key':Key, 'vector':Vector,
'rotation':Quaternion, 'list':list}

View file

@ -18,89 +18,15 @@
# Constant folding and simplification of expressions and statements. # Constant folding and simplification of expressions and statements.
import lslcommon import lslcommon
from lslcommon import Key, Vector, Quaternion from lslcommon import Vector, Quaternion
import lslfuncs import lslfuncs
from lslfuncs import NULL_KEY, ZERO_VECTOR, ZERO_ROTATION from lslfuncs import ZERO_VECTOR, ZERO_ROTATION
import math import math
from lslparse import warning from lslparse import warning
from lslfuncopt import OptimizeParams from lslfuncopt import OptimizeFunc, OptimizeArgs, FuncOptSetup
class foldconst(object): class foldconst(object):
# 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.))}
PythonType2LSL = {int: 'integer', float: 'float',
unicode: 'string', Key: 'key', Vector: 'vector',
Quaternion: 'rotation', list: 'list'}
LSLType2Python = {'integer':int, 'float':float,
'string':unicode, 'key':Key, 'vector':Vector,
'rotation':Quaternion, 'list':list}
def isLocalVar(self, node): def isLocalVar(self, node):
name = node['name'] name = node['name']
scope = node['scope'] scope = node['scope']
@ -166,7 +92,7 @@ class foldconst(object):
return False return False
if type(nodeOrConst) == dict: if type(nodeOrConst) == dict:
return nodeOrConst['t'] return nodeOrConst['t']
return self.PythonType2LSL[type(nodeOrConst)] return lslcommon.PythonType2LSL[type(nodeOrConst)]
def FoldAndRemoveEmptyStmts(self, lst): def FoldAndRemoveEmptyStmts(self, lst):
"""Utility function for elimination of useless expressions in FOR""" """Utility function for elimination of useless expressions in FOR"""
@ -478,7 +404,7 @@ class foldconst(object):
parent[index] = {'nt':'CONST', 't':node['t'], 'SEF':True, parent[index] = {'nt':'CONST', 't':node['t'], 'SEF':True,
'value':lslfuncs.typecast( 'value':lslfuncs.typecast(
child[0]['value'], self.LSL2PythonType[node['t']])} child[0]['value'], lslcommon.LSLType2Python[node['t']])}
# Remove casts of a type to the same type (NOP in Mono) # Remove casts of a type to the same type (NOP in Mono)
# This is not an optimization by itself, but it simplifies the job, # This is not an optimization by itself, but it simplifies the job,
@ -770,7 +696,7 @@ class foldconst(object):
if rnt == 'CONST' and len(rval['value']) == 1: if rnt == 'CONST' and len(rval['value']) == 1:
# list + [constant] -> list + constant # list + [constant] -> list + constant
rval['value'] = rval['value'][0] rval['value'] = rval['value'][0]
rtype = rval['t'] = self.PythonType2LSL[type(rval['value'])] rtype = rval['t'] = lslcommon.PythonType2LSL[type(rval['value'])]
return return
if (lnt == 'LIST' and len(lval['ch']) == 1 if (lnt == 'LIST' and len(lval['ch']) == 1
@ -786,7 +712,7 @@ class foldconst(object):
if lnt == 'CONST' and len(lval['value']) == 1: if lnt == 'CONST' and len(lval['value']) == 1:
# [constant] + list -> constant + list # [constant] + list -> constant + list
lval['value'] = lval['value'][0] lval['value'] = lval['value'][0]
ltype = lval['t'] = self.PythonType2LSL[type(lval['value'])] ltype = lval['t'] = lslcommon.PythonType2LSL[type(lval['value'])]
return return
return return
@ -1178,8 +1104,9 @@ class foldconst(object):
CONSTargs = False CONSTargs = False
sym = self.symtab[0][name] sym = self.symtab[0][name]
OptimizeParams(node, sym) OptimizeArgs(node, sym)
if 'Fn' in sym and ('SEF' in sym and sym['SEF'] or lslcommon.IsCalc): try:
if 'Fn' in sym and ('SEF' in sym or lslcommon.IsCalc):
# It's side-effect free if the children are and the function # It's side-effect free if the children are and the function
# is marked as SEF. # is marked as SEF.
if SEFargs: if SEFargs:
@ -1215,204 +1142,49 @@ class foldconst(object):
args[argnum][i] = lslfuncs.v2f(args[argnum][i]) args[argnum][i] = lslfuncs.v2f(args[argnum][i])
del argtypes del argtypes
try: try:
# May raise ELSLCantCompute
if name[:10] == 'llDetected': if name[:10] == 'llDetected':
value = fn(*args, event=self.CurEvent) value = fn(*args, event=self.CurEvent)
else: else:
value = fn(*args) value = fn(*args)
except lslfuncs.ELSLCantCompute: finally:
# Don't transform the tree if function is not computable
return
del args del args
if not self.foldtabs: if not self.foldtabs:
generatesTabs = ( generatesTabs = (
isinstance(value, unicode) and '\t' in value isinstance(value, unicode) and '\t' in value
or type(value) == list and any(isinstance(x, unicode) and '\t' in x for x in value) or type(value) == list
and any(isinstance(x, unicode)
and '\t' in x for x in value)
) )
if generatesTabs: if generatesTabs:
if self.warntabs: if self.warntabs:
warning(u"Can't optimize call to %s because it would generate a tab character (you can force the optimization with the 'foldtabs' option, or disable this warning by disabling the 'warntabs' option)." % name.decode('utf8')) warning(u"Can't optimize call to %s"
return u" because it would generate a tab"
parent[index] = {'nt':'CONST', 't':node['t'], 'value':value, 'SEF':True} u" character (you can force the "
elif self.optlistlength and name == 'llGetListLength': u" optimization with the 'foldtabs'"
# Convert llGetListLength(expr) to (expr != []) u" option, or disable this warning by"
node = {'nt':'CONST', 't':'list', 'value':[]} u" disabling the 'warntabs' option)."
parent[index] = node = {'nt':'!=', 't':'integer', % name.decode('utf8'))
'ch':[child[0], node]} raise lslfuncs.ELSLCantCompute()
# SEF if the list is # Replace with a constant
node['SEF'] = 'SEF' in child[0]
elif (name == 'llDumpList2String'
and 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']
elif (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 self.listCompat:
const = lslfuncs.InternalTypecast(const,
self.LSLType2Python[node['t']],
InList=True, f32=True)
else:
const = self.defaultListVals[name]
parent[index] = {'nt':'CONST', 't':node['t'], parent[index] = {'nt':'CONST', 't':node['t'],
'value':const, 'SEF':True} 'value':value, 'SEF':True}
return 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.
if (name == 'llList2Key' # checked via listCompat
or (name == 'llList2Integer'
and self.objDetailsTypes[const:const+1]
in ('s', 'i')) # won't work for floats
or (name == 'llList2Float'
and self.objDetailsTypes[const:const+1]
in ('s', 'i')) # won't work for floats
) and (node['t'][0]
+ self.objDetailsTypes[const:const+1]
) in self.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] + self.objDetailsTypes[const])
not in self.listCompat
) and 'SEF' in node:
parent[index] = {'nt':'CONST', 't':node['t'],
'value':self.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 self.primParamsArgs
or param < 0
or param >= len(self.primParamsTypes)
or self.primParamsTypes[param] is False
):
# Can't process this list.
returntypes = '!'
break
returntypes += self.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 self.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 self.listCompat \
and 'SEF' in node:
parent[index] = {'nt':'CONST',
't':node['t'],
'value':self.defaultListVals[name],
'SEF':True}
return
del returntypes
del listarg, idx, value, tvalue, const
elif SEFargs and 'SEF' in self.symtab[0][name]: elif SEFargs and 'SEF' in self.symtab[0][name]:
# The function is marked as SEF in the symbol table, and the # The function is marked as SEF in the symbol table, and the
# arguments are all side-effect-free. The result is SEF. # arguments are all side-effect-free. The result is SEF.
node['SEF'] = True node['SEF'] = True
except lslfuncs.ELSLCantCompute:
# Don't transform the tree if function is not computable
pass
# At this point, we have resolved whether the function is SEF,
# or whether the function resolves to a constant.
OptimizeFunc(self, parent, index)
return return
if nt == 'PRINT': if nt == 'PRINT':
@ -1754,11 +1526,7 @@ class foldconst(object):
tree = self.tree tree = self.tree
self.CurEvent = None self.CurEvent = None
# Patch the default values list for LSO FuncOptSetup()
if lslcommon.LSO:
self.defaultListVals['llList2Key'] = Key(NULL_KEY)
else:
self.defaultListVals['llList2Key'] = Key(u"")
# Constant folding pass. It does some other optimizations along the way. # Constant folding pass. It does some other optimizations along the way.
for idx in xrange(len(tree)): for idx in xrange(len(tree)):

View file

@ -15,13 +15,15 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>. # 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. # This is dependent on the LSL function library.
from lslcommon import Key#, Vector, Quaternion import lslcommon
from lslcommon import Key, Vector, Quaternion
import lslfuncs import lslfuncs
def OptimizeParams(node, sym): def OptimizeArgs(node, sym):
"""Transform function arguments to shorter equivalents where possible."""
assert node['nt'] == 'FNCALL' assert node['nt'] == 'FNCALL'
params = node['ch'] params = node['ch']
name = node['name'] name = node['name']
@ -42,3 +44,263 @@ def OptimizeParams(node, sym):
if not lslfuncs.cond(Key(params[i]['value'])): if not lslfuncs.cond(Key(params[i]['value'])):
params[i]['value'] = u"" params[i]['value'] = u""
params[i]['type'] = 'string' 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"")

View file

@ -37,13 +37,6 @@ class optimizer(foldconst, renamer, deadcode):
'==','!=','|','^','&','||','&&')) '==','!=','|','^','&','||','&&'))
assign_ops = frozenset(('=','+=','-=','*=','/=','%=','&=','|=','^=','<<=','>>=')) assign_ops = frozenset(('=','+=','-=','*=','/=','%=','&=','|=','^=','<<=','>>='))
LSL2PythonType = {'integer':int, 'float':float, 'string':unicode, 'key':lslfuncs.Key,
'vector':lslfuncs.Vector, 'rotation':lslfuncs.Quaternion, 'list':list}
PythonType2LSL = {int: 'integer', float: 'float',
unicode: 'string', Key: 'key', Vector: 'vector',
Quaternion: 'rotation', list: 'list'}
def Cast(self, value, newtype): def Cast(self, value, newtype):
"""Return a CAST node if the types are not equal, otherwise the """Return a CAST node if the types are not equal, otherwise the
value unchanged. value unchanged.

View file

@ -199,10 +199,6 @@ class parser(object):
switch_keywords = frozenset(('switch', 'case', 'break', 'default')) switch_keywords = frozenset(('switch', 'case', 'break', 'default'))
types = frozenset(('integer','float','string','key','vector', types = frozenset(('integer','float','string','key','vector',
'quaternion','rotation','list')) 'quaternion','rotation','list'))
PythonType2LSL = {int: 'integer', float: 'float',
unicode: 'string', Key: 'key', Vector: 'vector',
Quaternion: 'rotation', list: 'list'}
PythonType2LSLToken = {int:'INTEGER_VALUE', float:'FLOAT_VALUE', PythonType2LSLToken = {int:'INTEGER_VALUE', float:'FLOAT_VALUE',
unicode:'STRING_VALUE', Key:'KEY_VALUE', Vector:'VECTOR_VALUE', unicode:'STRING_VALUE', Key:'KEY_VALUE', Vector:'VECTOR_VALUE',
Quaternion:'ROTATION_VALUE', list:'LIST_VALUE'} Quaternion:'ROTATION_VALUE', list:'LIST_VALUE'}
@ -2069,7 +2065,8 @@ list lazy_list_set(list L, integer i, list v)
while self.tok[0] == 'STRING_VALUE': while self.tok[0] == 'STRING_VALUE':
val += self.tok[1] val += self.tok[1]
self.NextToken() self.NextToken()
return {'nt':'CONST', 't':self.PythonType2LSL[type(val)], 'value':val} return {'nt':'CONST', 't':lslcommon.PythonType2LSL[type(val)],
'value':val}
if tok[0] == 'IDENT': if tok[0] == 'IDENT':
sym = self.FindSymbolPartial(tok[1]) sym = self.FindSymbolPartial(tok[1])
if sym is None or sym['Kind'] != 'v': if sym is None or sym['Kind'] != 'v':