diff --git a/fndata.txt b/fndata.txt index 833232f..1c08bd1 100644 --- a/fndata.txt +++ b/fndata.txt @@ -18,11 +18,13 @@ # along with LSL PyOptimizer. If not, see . # This file provides information to the optimizer about the behaviour of -# functions. This knowledge can help perform a better job at optimizing. -# All functions present in builtins.txt must be here and vice versa. +# functions and events. This knowledge can help perform a better job at +# 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, -# 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: # @@ -1454,3 +1456,128 @@ string llXorBase64Strings( string str1, string str2 ) string llXorBase64StringsCorrect( string str1, string str2 ) - 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 diff --git a/lslopt/lslloadlib.py b/lslopt/lslloadlib.py index 237630f..9c2103c 100644 --- a/lslopt/lslloadlib.py +++ b/lslopt/lslloadlib.py @@ -114,7 +114,7 @@ def LoadLibrary(builtins = None, fndata = None): u" overwriting: %s" % (linenum, ubuiltins, uname)) del uname - events[name] = tuple(args) + events[name] = {'pt':tuple(args), 'NeedsData':True} else: # Library functions go to the functions table. If # they are implemented in lslfuncs.*, they get a @@ -243,6 +243,7 @@ def LoadLibrary(builtins = None, fndata = None): try: linenum = 0 curr_fn = None + curr_ty = None skipping = False try: ufndata = fndata.decode(sys.getfilesystemencoding()) @@ -265,30 +266,37 @@ def LoadLibrary(builtins = None, fndata = None): continue 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 name = match_fn.group(2) uname = name.decode('utf8') - if name not in functions: - warning(u"Function %s is not in builtins, in %s line %d," + if (rettype == 'event' and name not in events + or rettype != 'event' and name not in functions + ): + warning(u"%s %s is not in builtins, in %s line %d," u" skipping." - % (uname, ufndata, linenum)) + % (u"Function" if rettype != 'event' else u"Event", + uname, ufndata, linenum)) continue 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," u" skipping." % (uname, ufndata, linenum)) continue argnames = [] arglist = match_fn.group(3) - current_args = functions[name]['ParamTypes'] + current_args = (functions[name]['ParamTypes'] + if rettype != 'event' + else events[name]['pt']) if arglist: arglist = arglist.split(',') if len(current_args) != len(arglist): warning(u"Parameter list mismatch in %s line %d," - u" function %s. Skipping." - % (ufndata, linenum, uname)) + u" %s %s. Skipping." + % (ufndata, linenum, + u"function" if rettype != 'event' + else u"event", uname)) continue bad = False # used to 'continue' at this loop level @@ -298,8 +306,10 @@ def LoadLibrary(builtins = None, fndata = None): argname = argmatch.group(2) if current_args[idx] != argtyp: warning(u"Parameter list mismatch in %s line %d," - u" function %s. Skipping." - % (ufndata, linenum, uname)) + u" %s %s. Skipping." + % (ufndata, linenum, + u"function" if rettype != 'event' + else u"event", uname)) bad = True break argnames.append(argname) @@ -308,22 +318,29 @@ def LoadLibrary(builtins = None, fndata = None): continue del bad - if 'NeedsData' not in functions[name]: - warning(u"Duplicate function %s in %s line %d. Skipping." - % (uname, ufndata, linenum)) + if 'NeedsData' not in (functions[name] if rettype != 'event' + else events[name]): + warning(u"Duplicate %s %s in %s line %d. Skipping." + % (u"function" if rettype != 'event' else u"event", + uname, ufndata, linenum)) continue # passed all tests curr_fn = name + curr_ty = rettype 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: match_flag = parse_flag_re.search(line) if match_flag: if curr_fn is None and not skipping: - warning(u"Flags present before any function in %s" - u" line %d: %s" % (ufndata, linenum, uline)) + warning(u"Flags present before any function or event" + u" in %s line %d: %s" + % (ufndata, linenum, uline)) skipping = True continue if not skipping: @@ -333,8 +350,22 @@ def LoadLibrary(builtins = None, fndata = None): # We don't handle conditions yet. Take the # condition as never met for now (every function # that is conditionally SEF is taken as not SEF) - if not match_flag.group(3): - functions[curr_fn]['SEF'] = True + if curr_ty == 'event' and match_flag.group(3): + 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): pass # return not handled yet elif (match_flag.group(4) @@ -394,7 +425,8 @@ def LoadLibrary(builtins = None, fndata = None): ui = i.decode('utf8') if 'NeedsData' in functions[i]: 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 functions[i]['min'] > functions[i]['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" u" delay. Removing SEF." % ui) 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 diff --git a/lslopt/lslparse.py b/lslopt/lslparse.py index ba5d2ce..d553f9d 100644 --- a/lslopt/lslparse.py +++ b/lslopt/lslparse.py @@ -2208,7 +2208,7 @@ list lazy_list_set(list L, integer i, list v) self.NextToken() # 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(). - if tuple(params[0]) != self.events[name]: + if tuple(params[0]) != self.events[name]['pt']: raise EParseSyntax(self) self.locallabels = set() body = self.Parse_code_block(None)