Add side-effect-free information for events.

This commit is contained in:
Sei Lisa 2017-10-25 17:46:50 +02:00
parent 2d823d8eae
commit d5f5ab8b88
3 changed files with 189 additions and 24 deletions

View file

@ -18,11 +18,13 @@
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>. # along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>.
# This file provides information to the optimizer about the behaviour of # This file provides information to the optimizer about the behaviour of
# functions. This knowledge can help perform a better job at optimizing. # functions and events. This knowledge can help perform a better job at
# All functions present in builtins.txt must be here and vice versa. # optimizing. All functions and events present in builtins.txt must be here
# and vice versa.
# Flags are entered with a dash at the beginning of the line, then a space, # Flags are entered with a dash at the beginning of the line, then a space,
# then the flag. Flags apply to the function they are under. # then the flag. Flags apply to the function they are under. There can be none
# before the first function.
# #
# Available flags: # Available flags:
# #
@ -1454,3 +1456,128 @@ string llXorBase64Strings( string str1, string str2 )
string llXorBase64StringsCorrect( string str1, string str2 ) string llXorBase64StringsCorrect( string str1, string str2 )
- SEF - SEF
###################################################################
# Events are SEF if a script with an empty event can't be
# distinguished from a script without that event except for the
# extra CPU and memory consumption.
event at_rot_target( integer tnum, rotation targetrot, rotation ourrot )
- SEF
event at_target( integer tnum, vector targetpos, vector ourpos )
- SEF
event attach( key id )
- SEF
event changed( integer change )
- SEF
event collision( integer num_detected )
# Prevents events in the parent from triggering, depending on llPassCollisions,
# therefore not SEF.
event collision_end( integer num_detected )
# Same as with collision().
event collision_start( integer num_detected )
# Same as with collision().
event control( key id, integer level, integer edge )
- SEF
event dataserver( key queryid, string data )
- SEF
event email( string time, string address, string subj, string message, integer num_left )
- SEF
event experience_permissions( key agent )
- SEF
event experience_permissions_denied( key agent, integer reason )
- SEF
event http_request( key id, string method, string body )
# Since you can't see the URL, you can't notice the difference.
- SEF
event http_response( key request_id, integer status, list metadata, string body )
- SEF
event land_collision( vector pos )
# Same as with collision().
event land_collision_end( vector pos )
# Same as with collision().
event land_collision_start( vector pos )
# Same as with collision().
event link_message( integer sender_num, integer num, string str, key id )
- SEF
event listen( integer channel, string name, key id, string message )
- SEF
event money( key id, integer amount )
# Adds Pay menu option, therefore not SEF.
event moving_end( )
- SEF
event moving_start( )
- SEF
event no_sensor( )
- SEF
event not_at_rot_target( )
- SEF
event not_at_target( )
- SEF
event object_rez( key id )
- SEF
event on_rez( integer start_param )
- SEF
event path_update( integer type, list reserved )
- SEF
event remote_data( integer event_type, key channel, key message_id, string sender, integer idata, string sdata )
- SEF
event run_time_permissions( integer perm )
- SEF
event sensor( integer num_detected )
# There was a time when this was necessary for no_sensor() to trigger, but
# that's no longer the case.
- SEF
event state_entry( )
- SEF
event state_exit( )
- SEF
event timer( )
- SEF
event touch( integer num_detected )
# Adds hand cursor.
event touch_end( integer num_detected )
# Adds hand cursor.
event touch_start( integer num_detected )
# Adds hand cursor.
event transaction_result( key id, integer success, string data )
- SEF

View file

@ -114,7 +114,7 @@ def LoadLibrary(builtins = None, fndata = None):
u" overwriting: %s" u" overwriting: %s"
% (linenum, ubuiltins, uname)) % (linenum, ubuiltins, uname))
del uname del uname
events[name] = tuple(args) events[name] = {'pt':tuple(args), 'NeedsData':True}
else: else:
# Library functions go to the functions table. If # Library functions go to the functions table. If
# they are implemented in lslfuncs.*, they get a # they are implemented in lslfuncs.*, they get a
@ -243,6 +243,7 @@ def LoadLibrary(builtins = None, fndata = None):
try: try:
linenum = 0 linenum = 0
curr_fn = None curr_fn = None
curr_ty = None
skipping = False skipping = False
try: try:
ufndata = fndata.decode(sys.getfilesystemencoding()) ufndata = fndata.decode(sys.getfilesystemencoding())
@ -265,30 +266,37 @@ def LoadLibrary(builtins = None, fndata = None):
continue continue
rettype = match_fn.group(1) if match_fn else None rettype = match_fn.group(1) if match_fn else None
if match_fn and (rettype == 'void' or rettype in types): if match_fn and (rettype in ('void', 'event') or rettype in types):
skipping = True # until proven otherwise skipping = True # until proven otherwise
name = match_fn.group(2) name = match_fn.group(2)
uname = name.decode('utf8') uname = name.decode('utf8')
if name not in functions: if (rettype == 'event' and name not in events
warning(u"Function %s is not in builtins, in %s line %d," or rettype != 'event' and name not in functions
):
warning(u"%s %s is not in builtins, in %s line %d,"
u" skipping." u" skipping."
% (uname, ufndata, linenum)) % (u"Function" if rettype != 'event' else u"Event",
uname, ufndata, linenum))
continue continue
rettype = rettype if rettype != 'void' else None rettype = rettype if rettype != 'void' else None
if rettype != functions[name]['Type']: if 'event' != rettype != functions[name]['Type']:
warning(u"Function %s returns invalid type, in %s line %d," warning(u"Function %s returns invalid type, in %s line %d,"
u" skipping." u" skipping."
% (uname, ufndata, linenum)) % (uname, ufndata, linenum))
continue continue
argnames = [] argnames = []
arglist = match_fn.group(3) arglist = match_fn.group(3)
current_args = functions[name]['ParamTypes'] current_args = (functions[name]['ParamTypes']
if rettype != 'event'
else events[name]['pt'])
if arglist: if arglist:
arglist = arglist.split(',') arglist = arglist.split(',')
if len(current_args) != len(arglist): if len(current_args) != len(arglist):
warning(u"Parameter list mismatch in %s line %d," warning(u"Parameter list mismatch in %s line %d,"
u" function %s. Skipping." u" %s %s. Skipping."
% (ufndata, linenum, uname)) % (ufndata, linenum,
u"function" if rettype != 'event'
else u"event", uname))
continue continue
bad = False # used to 'continue' at this loop level bad = False # used to 'continue' at this loop level
@ -298,8 +306,10 @@ def LoadLibrary(builtins = None, fndata = None):
argname = argmatch.group(2) argname = argmatch.group(2)
if current_args[idx] != argtyp: if current_args[idx] != argtyp:
warning(u"Parameter list mismatch in %s line %d," warning(u"Parameter list mismatch in %s line %d,"
u" function %s. Skipping." u" %s %s. Skipping."
% (ufndata, linenum, uname)) % (ufndata, linenum,
u"function" if rettype != 'event'
else u"event", uname))
bad = True bad = True
break break
argnames.append(argname) argnames.append(argname)
@ -308,22 +318,29 @@ def LoadLibrary(builtins = None, fndata = None):
continue continue
del bad del bad
if 'NeedsData' not in functions[name]: if 'NeedsData' not in (functions[name] if rettype != 'event'
warning(u"Duplicate function %s in %s line %d. Skipping." else events[name]):
% (uname, ufndata, linenum)) warning(u"Duplicate %s %s in %s line %d. Skipping."
% (u"function" if rettype != 'event' else u"event",
uname, ufndata, linenum))
continue continue
# passed all tests # passed all tests
curr_fn = name curr_fn = name
curr_ty = rettype
skipping = False skipping = False
del functions[name]['NeedsData'], functions[name]['uns'] if curr_ty == 'event':
del events[name]['NeedsData']
else:
del functions[name]['NeedsData'], functions[name]['uns']
else: else:
match_flag = parse_flag_re.search(line) match_flag = parse_flag_re.search(line)
if match_flag: if match_flag:
if curr_fn is None and not skipping: if curr_fn is None and not skipping:
warning(u"Flags present before any function in %s" warning(u"Flags present before any function or event"
u" line %d: %s" % (ufndata, linenum, uline)) u" in %s line %d: %s"
% (ufndata, linenum, uline))
skipping = True skipping = True
continue continue
if not skipping: if not skipping:
@ -333,8 +350,22 @@ def LoadLibrary(builtins = None, fndata = None):
# We don't handle conditions yet. Take the # We don't handle conditions yet. Take the
# condition as never met for now (every function # condition as never met for now (every function
# that is conditionally SEF is taken as not SEF) # that is conditionally SEF is taken as not SEF)
if not match_flag.group(3): if curr_ty == 'event' and match_flag.group(3):
functions[curr_fn]['SEF'] = True warning(u"Events do not support conditions"
u" in SEF flags, in line %d, event %s"
% (ufndata, linenum, ucurr_fn))
continue
elif curr_ty == 'event':
events[curr_fn]['SEF'] = True
else:
if not match_flag.group(3):
functions[curr_fn]['SEF'] = True
elif curr_ty == 'event':
warning(u"Events only support bare SEF flags"
u", in line %d, event %s. Omitting %s."
% (ufndata, linenum, ucurr_fn, uline))
continue
elif match_flag.group(2): elif match_flag.group(2):
pass # return not handled yet pass # return not handled yet
elif (match_flag.group(4) elif (match_flag.group(4)
@ -394,7 +425,8 @@ def LoadLibrary(builtins = None, fndata = None):
ui = i.decode('utf8') ui = i.decode('utf8')
if 'NeedsData' in functions[i]: if 'NeedsData' in functions[i]:
del functions[i]['NeedsData'] del functions[i]['NeedsData']
warning(u"Library data: Function %s has no data." % ui) warning(u"Library data, file %s: Function %s has no data."
% (ufndata, ui))
if 'min' in functions[i] and 'max' in functions[i]: if 'min' in functions[i] and 'max' in functions[i]:
if functions[i]['min'] > functions[i]['max']: if functions[i]['min'] > functions[i]['max']:
warning(u"Library data: Function %s has min > max:" warning(u"Library data: Function %s has min > max:"
@ -406,5 +438,11 @@ def LoadLibrary(builtins = None, fndata = None):
warning(u"Library data: Side-effect-free function %s contradicts" warning(u"Library data: Side-effect-free function %s contradicts"
u" delay. Removing SEF." % ui) u" delay. Removing SEF." % ui)
del functions[i]['SEF'] del functions[i]['SEF']
for i in events:
ui = i.decode('utf8')
if 'NeedsData' in events[i]:
del events[i]['NeedsData']
warning(u"Library data, file %s: Event %s has no data."
% (ufndata, ui))
return events, constants, functions return events, constants, functions

View file

@ -2208,7 +2208,7 @@ list lazy_list_set(list L, integer i, list v)
self.NextToken() self.NextToken()
# NOTE: Parse_events: This is a bit crude, as the error is given at the end of the param list. # NOTE: Parse_events: This is a bit crude, as the error is given at the end of the param list.
# To do it correctly, we can pass the parameter list to Parse_optional_param_list(). # To do it correctly, we can pass the parameter list to Parse_optional_param_list().
if tuple(params[0]) != self.events[name]: if tuple(params[0]) != self.events[name]['pt']:
raise EParseSyntax(self) raise EParseSyntax(self)
self.locallabels = set() self.locallabels = set()
body = self.Parse_code_block(None) body = self.Parse_code_block(None)