diff --git a/fndata.txt b/fndata.txt
new file mode 100644
index 0000000..c96f34f
--- /dev/null
+++ b/fndata.txt
@@ -0,0 +1,1455 @@
+# Function properties table
+#
+# Copyright © 2015-2017 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 .
+
+# 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.
+
+# 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.
+#
+# Available flags:
+#
+# stable:
+# Two successive calls with the same parameters are assumed to return
+# the same results in most reasonable cases. When it's stable and SEF
+# it's posible to simplify two identical calls into one. Example:
+# llGetPermissions(). Counterexample: llFrand(). This is the default;
+# unstable functions must be marked as such. Does not apply to void
+# functions.
+#
+# unstable:
+# Not stable.
+#
+# variable:
+# Not stable. Alias for unstable.
+#
+# delay :
+# Function has a delay.
+#
+# SEF [if ]:
+# Side-effect free. The function has no side effects when executed,
+# which means that when used in a situation where it does nothing,
+# it can be removed without affecting execution. Example:
+# llGetNumberOfPrims(). All functions with delay have a side effect
+# (the delay itself).
+#
+# With if , the function is SEF if the parameters are
+# found to meet the condition. Syntax of is explained below.
+#
+# min:
+# Applied to functions that return integer or float. Specifies the
+# minimum value it may return. If not present, assume the minimum
+# possible (-inf for floats, -2147483648 for integers). Use like this:
+#
+# - min
+#
+# max:
+# Like min, but for the maximum value.
+#
+# return [if ]:
+# Self-explanatory. There can be several; they are evaluated in order.
+# can be a parameter or a LSL constant. is explaned
+# below.
+#
+#
+# Subset of LSL expressions using only (, ), ==, !=, <, <=, >, >=,
+# &&, ||, constants, function parameters and one function. As an extension,
+# Python-like operator chaining works, e.g. a < b < c or a == b == c.
+# && has more priority than ||.
+# The type of comparisons is bool and can't be used as integer.
+# Lists are compared for equal. Elements in lists, vectors and
+# rotations must be constants.
+#
+# ['<' and '>' need spaces around them when they are comparisons;
+# vectors need to have no space after '<' or before '>'.] -> Let's not,
+# and see what happens.
+#
+# Strings are automatically type cast to key when necessary, and integers
+# to floats, but not vice versa. Function bool nulluuid(key k) is allowed.
+#
+# There's a pseudo-parameter of type string that is always available:
+# event (the event where the function is called, if known; else "")
+
+# A comment like this:
+#
+# physics caveat
+#
+# means that tests show it's apparently stable because physics are
+# recomputed every frame, and the frame doesn't change that often.
+
+integer llAbs( integer val )
+- SEF
+- min 0
+
+float llAcos( float val )
+- SEF
+
+void llAddToLandBanList( key avatar, float hours )
+- delay 0.1
+
+void llAddToLandPassList( key avatar, float hours )
+- delay 0.1
+
+void llAdjustSoundVolume( float volume )
+- delay 0.1
+
+integer llAgentInExperience( key agent )
+- SEF
+- min 0
+- max 1
+
+void llAllowInventoryDrop( integer add )
+
+float llAngleBetween( rotation a, rotation b )
+- SEF
+
+void llApplyImpulse( vector force, integer local )
+
+void llApplyRotationalImpulse( vector force, integer local )
+
+float llAsin( float val )
+- SEF
+
+float llAtan2( float y, float x )
+- SEF
+
+void llAttachToAvatar( integer attach_point )
+
+void llAttachToAvatarTemp( integer attach_point )
+
+key llAvatarOnLinkSitTarget( integer link )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if link < -2147483647 || link > 256
+
+key llAvatarOnSitTarget( )
+- SEF
+
+rotation llAxes2Rot( vector fwd, vector left, vector up )
+- SEF
+
+rotation llAxisAngle2Rot( vector axis, float angle )
+- SEF
+
+integer llBase64ToInteger( string str )
+# While it's unstable for some strings, we ignore that part.
+- SEF
+
+string llBase64ToString( string str )
+- SEF
+
+void llBreakAllLinks( )
+
+void llBreakLink( integer linknum )
+- SEF if linknum > 256
+
+list llCSV2List( string src )
+- SEF
+
+list llCastRay( vector start, vector end, list params )
+- SEF
+
+integer llCeil( float val )
+- SEF
+
+void llClearCameraParams( )
+
+void llClearExperiencePermissions( key agent )
+
+integer llClearLinkMedia( integer link, integer face )
+- min 0
+- max 2001
+- SEF if link > 256 || link < -2147483647
+- return 0 if link < -2147483647 || link > 256
+
+integer llClearPrimMedia( integer face )
+- delay 1.0
+- min 0
+- max 2001
+
+void llCloseRemoteDataChannel( key channel )
+- delay 1.0
+
+float llCloud( vector offset )
+- SEF
+- min 0
+- max 0
+- return 0
+
+void llCollisionFilter( string name, key id, integer accept )
+
+void llCollisionSound( string impact_sound, float impact_volume )
+
+void llCollisionSprite( string impact_sprite )
+- SEF
+
+float llCos( float theta )
+- SEF
+- min -1
+- max 1
+
+void llCreateCharacter( list options )
+
+key llCreateKeyValue( string k, string v )
+- unstable
+
+void llCreateLink( key target, integer parent )
+- delay 1.0
+
+key llDataSizeKeyValue( )
+- unstable
+
+void llDeleteCharacter( )
+
+key llDeleteKeyValue( string k )
+- unstable
+
+list llDeleteSubList( list src, integer start, integer end )
+- SEF
+
+string llDeleteSubString( string src, integer start, integer end )
+- SEF
+
+void llDetachFromAvatar( )
+
+vector llDetectedGrab( integer number )
+- SEF
+# llDetectedGrab() only works for touch(), not for touch_start() etc.
+- return <0,0,0> if event != "" && event != "touch" || number < 0 || number > 15
+integer llDetectedGroup( integer number )
+- SEF
+- min 0
+- max 1
+- return 0 if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+key llDetectedKey( integer number )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+integer llDetectedLinkNumber( integer number )
+- SEF
+- min 0
+- max 256
+- return 0 if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+string llDetectedName( integer number )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+key llDetectedOwner( integer number )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+vector llDetectedPos( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+rotation llDetectedRot( integer number )
+- SEF
+- return <0,0,0,1> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+vector llDetectedTouchBinormal( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" || number < 0 || number > 15
+
+integer llDetectedTouchFace( integer number )
+- SEF
+- min -1
+- max 8
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" || number < 0 || number > 15
+
+vector llDetectedTouchNormal( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" || number < 0 || number > 15
+
+vector llDetectedTouchPos( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" || number < 0 || number > 15
+
+vector llDetectedTouchST( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+- return <-1,-1,0> if (event == "collision" || event == "collision_start" || event == "collision_end" || event == "sensor") && number == 0
+
+vector llDetectedTouchUV( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+- return <-1,-1,0> if (event == "collision" || event == "collision_start" || event == "collision_end" || event == "sensor") && number == 0
+
+integer llDetectedType( integer number )
+- SEF
+- min 0
+- max 15
+- return 0 if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+vector llDetectedVel( integer number )
+- SEF
+- return <0,0,0> if event != "" && event != "touch" && event != "touch_start" && event != "touch_end" && event != "collision" && event != "collision_start" && event != "collision_end" && event != "sensor" || number < 0 || number > 15
+
+void llDialog( key avatar, string message, list buttons, integer chat_channel )
+- delay 1.0
+
+void llDie( )
+
+string llDumpList2String( list src, string separator )
+- SEF
+
+integer llEdgeOfWorld( vector pos, vector dir )
+- SEF
+
+void llEjectFromLand( key avatar )
+
+void llEmail( string address, string subject, string message )
+- delay 20.0
+
+string llEscapeURL( string url )
+- SEF
+
+rotation llEuler2Rot( vector v )
+- SEF
+
+void llEvade( key target, list options )
+
+void llExecCharacterCmd( integer cmd, list options )
+
+float llFabs( float val )
+- SEF
+- min 0
+
+void llFleeFrom( vector source, float radius, list options )
+
+integer llFloor( float val )
+- SEF
+
+void llForceMouselook( integer mouselook )
+
+float llFrand( float mag )
+- unstable
+- SEF
+
+key llGenerateKey( )
+- unstable
+- SEF
+
+vector llGetAccel( )
+# physics caveat
+#- unstable
+- SEF
+
+integer llGetAgentInfo( key id )
+- SEF
+- return 0 if nulluuid(id)
+
+string llGetAgentLanguage( key avatar )
+- SEF
+- return "" if nulluuid(id)
+
+list llGetAgentList( integer scope, list options )
+- SEF
+- return "INVALID_SCOPE" if scope != 1 && scope != 2 && scope != 4
+
+vector llGetAgentSize( key id )
+- SEF
+- return <0,0,0> if nulluuid(id)
+
+float llGetAlpha( integer face )
+- SEF
+- return 1 if face > 8
+
+float llGetAndResetTime( )
+- unstable
+
+string llGetAnimation( key id )
+- SEF
+- return "" if nulluuid(id)
+
+list llGetAnimationList( key id )
+- SEF
+- return "" if nulluuid(id)
+
+string llGetAnimationOverride( string anim_state )
+# may err, therefore not SEF
+
+integer llGetAttached( )
+- SEF
+- min 0
+- max 55
+
+list llGetAttachedList( key agent )
+- SEF
+- return ["NOT FOUND"] if nulluuid(agent)
+
+list llGetBoundingBox( key object )
+- SEF
+- return [] if nulluuid(object)
+
+vector llGetCameraPos( )
+# it errs therefore not SEF
+
+rotation llGetCameraRot( )
+# it errs therefore not SEF
+
+vector llGetCenterOfMass( )
+- SEF
+
+list llGetClosestNavPoint( vector point, list options )
+# Claimed to have a delay, but such delay is 1 frame (?)
+- SEF
+
+vector llGetColor( integer face )
+- SEF
+- return <1,1,1> if face > 8
+
+key llGetCreator( )
+- SEF
+
+string llGetDate( )
+- SEF
+
+string llGetDisplayName( key id )
+- SEF
+- return "" if nulluuid(id)
+
+float llGetEnergy( )
+# physics caveat
+#- unstable
+- SEF
+- min 0
+- max 1
+
+string llGetEnv( string name )
+- SEF
+- return "" if name == ""
+
+list llGetExperienceDetails( key experience_id )
+- SEF
+
+string llGetExperienceErrorMessage( integer value )
+- SEF
+- return "no error" if value == 0
+- return "exceeded throttle" if value == 1
+- return "experiences are disabled" if value == 2
+- return "invalid parameters" if value == 3
+- return "operation not permitted" if value == 4
+- return "script not associated with an experience" if value == 5
+- return "not found" if value == 6
+- return "invalid experience" if value == 7
+- return "experience is disabled" if value == 8
+- return "experience is suspended" if value == 9
+- return "unknown error" if value == 10
+- return "experience data quota exceeded" if value == 11
+- return "key-value store is disabled" if value == 12
+- return "key-value store communication failed" if value == 13
+- return "key doesn't exist" if value == 14
+- return "retry update" if value == 15
+- return "experience content rating too high" if value == 16
+- return "not allowed to run in current location" if value == 17
+- return "experience permissions request timed out" if value == 18
+- return "unknown error id"
+
+list llGetExperienceList( key agent )
+- SEF
+- return []
+
+vector llGetForce( )
+- SEF
+
+integer llGetFreeMemory( )
+- SEF
+- min 0
+- max 65536
+
+integer llGetFreeURLs( )
+- SEF
+- min 0
+- max 65536
+
+float llGetGMTclock( )
+- SEF
+- min 0
+- max 86399
+
+vector llGetGeometricCenter( )
+- SEF
+
+string llGetHTTPHeader( key request_id, string header )
+- SEF
+- return "" if nulluuid(request_id)
+
+key llGetInventoryCreator( string item )
+- SEF
+
+key llGetInventoryKey( string name )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if name == ""
+
+string llGetInventoryName( integer type, integer number )
+- SEF
+- return "" if type != -1 && type != 0 && type != 1 && type != 3 && type != 5 && type != 6 && type != 7 && type != 10 && type != 13 && type != 20 && type != 21 || number < 0
+
+integer llGetInventoryNumber( integer type )
+- SEF
+- return 0 if type != -1 && type != 0 && type != 1 && type != 3 && type != 5 && type != 6 && type != 7 && type != 10 && type != 13 && type != 20 && type != 21
+
+integer llGetInventoryPermMask( string item, integer mask )
+- SEF
+- return 0 if mask < 0 || mask > 4 || item == ""
+
+# we've completed up to here
+
+integer llGetInventoryType( string name )
+- SEF
+
+key llGetKey( )
+- SEF
+
+key llGetLandOwnerAt( vector pos )
+- SEF
+
+key llGetLinkKey( integer linknumber )
+- SEF
+
+list llGetLinkMedia( integer link, integer face, list params )
+- SEF
+
+string llGetLinkName( integer linknumber )
+- SEF
+
+integer llGetLinkNumber( )
+- SEF
+
+integer llGetLinkNumberOfSides( integer link )
+- SEF
+
+list llGetLinkPrimitiveParams( integer linknumber, list rules )
+- SEF
+
+integer llGetListEntryType( list src, integer index )
+- SEF
+
+integer llGetListLength( list src )
+- SEF
+
+vector llGetLocalPos( )
+# physics caveat
+#- unstable
+- SEF
+
+rotation llGetLocalRot( )
+# physics caveat
+#- unstable
+- SEF
+
+float llGetMass( )
+- SEF
+
+float llGetMassMKS( )
+- SEF
+
+float llGetMaxScaleFactor( )
+- SEF
+
+integer llGetMemoryLimit( )
+- SEF
+
+float llGetMinScaleFactor( )
+- SEF
+
+void llGetNextEmail( string address, string subject )
+
+key llGetNotecardLine( string name, integer line )
+- unstable
+- delay 0.1
+
+key llGetNumberOfNotecardLines( string name )
+- unstable
+- delay 0.1
+
+integer llGetNumberOfPrims( )
+- SEF
+
+integer llGetNumberOfSides( )
+- SEF
+
+string llGetObjectDesc( )
+- SEF
+
+list llGetObjectDetails( key id, list params )
+# physics caveat
+#- unstable
+- SEF
+
+float llGetObjectMass( key id )
+- SEF
+
+string llGetObjectName( )
+- SEF
+
+integer llGetObjectPermMask( integer mask )
+- SEF
+
+integer llGetObjectPrimCount( key object_id )
+- SEF
+
+vector llGetOmega( )
+# physics caveat
+#- unstable
+- SEF
+
+key llGetOwner( )
+- SEF
+
+key llGetOwnerKey( key id )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if nulluuid(id)
+
+list llGetParcelDetails( vector pos, list params )
+- SEF
+
+integer llGetParcelFlags( vector pos )
+- SEF
+
+integer llGetParcelMaxPrims( vector pos, integer sim_wide )
+- SEF
+
+string llGetParcelMusicURL( )
+- SEF
+
+integer llGetParcelPrimCount( vector pos, integer category, integer sim_wide )
+- SEF
+
+list llGetParcelPrimOwners( vector pos )
+- delay 2.0
+
+integer llGetPermissions( )
+- SEF
+
+key llGetPermissionsKey( )
+- SEF
+
+list llGetPhysicsMaterial( )
+- SEF
+
+vector llGetPos( )
+# physics caveat
+#- unstable
+- SEF
+
+list llGetPrimMediaParams( integer face, list params )
+- delay 1.0
+
+list llGetPrimitiveParams( list params )
+- delay 0.2
+
+integer llGetRegionAgentCount( )
+- SEF
+
+vector llGetRegionCorner( )
+- SEF
+
+float llGetRegionFPS( )
+- SEF
+
+integer llGetRegionFlags( )
+- SEF
+
+string llGetRegionName( )
+- SEF
+
+float llGetRegionTimeDilation( )
+- SEF
+
+vector llGetRootPosition( )
+# physics caveat
+#- unstable
+- SEF
+
+rotation llGetRootRotation( )
+# physics caveat
+#- unstable
+- SEF
+
+rotation llGetRot( )
+# physics caveat
+#- unstable
+- SEF
+
+integer llGetSPMaxMemory( )
+- SEF
+
+vector llGetScale( )
+- SEF
+
+string llGetScriptName( )
+- SEF
+
+integer llGetScriptState( string name )
+- SEF
+
+float llGetSimStats( integer stat_type )
+- SEF
+
+string llGetSimulatorHostname( )
+- delay 10.0
+
+integer llGetStartParameter( )
+- SEF
+
+list llGetStaticPath( vector start, vector end, float radius, list params )
+# believed to be side-effect free
+- SEF
+
+integer llGetStatus( integer status )
+- SEF
+- min 0
+- max 1
+
+string llGetSubString( string src, integer start, integer end )
+- SEF
+
+vector llGetSunDirection( )
+- SEF
+
+string llGetTexture( integer face )
+- SEF
+- return "00000000-0000-0000-0000-000000000000" if face > 8
+
+vector llGetTextureOffset( integer face )
+- SEF
+- return <0,0,0> if face > 8
+
+float llGetTextureRot( integer side )
+- SEF
+- return 0 if side > 8
+
+vector llGetTextureScale( integer side )
+- SEF
+- return <0,0,0> if side > 8
+
+float llGetTime( )
+- SEF
+# It's stable within the same frame.
+
+float llGetTimeOfDay( )
+- unstable
+- SEF
+
+string llGetTimestamp( )
+- unstable
+- SEF
+
+vector llGetTorque( )
+- SEF
+
+integer llGetUnixTime( )
+- SEF
+
+integer llGetUsedMemory( )
+- unstable
+- SEF
+
+string llGetUsername( key id )
+- SEF
+
+vector llGetVel( )
+# physics caveat
+#- unstable
+- SEF
+
+float llGetWallclock( )
+- SEF
+- min 0
+- max 86399
+
+void llGiveInventory( key destination, string inventory )
+# delay only applies if giving to avatars
+# (delay is not important because it's not applied when SEF)
+#- delay 2.0
+- SEF if nulluuid(destination)
+
+void llGiveInventoryList( key target, string folder, list inventory )
+- delay 3.0
+
+integer llGiveMoney( key destination, integer amount )
+- min 0
+- max 0
+
+void llGodLikeRezObject( key inventory, vector pos )
+
+float llGround( vector offset )
+- SEF
+- min 0
+
+vector llGroundContour( vector offset )
+- SEF
+
+vector llGroundNormal( vector offset )
+- SEF
+
+void llGroundRepel( float height, integer water, float tau )
+
+vector llGroundSlope( vector offset )
+- SEF
+
+key llHTTPRequest( string url, list parameters, string body )
+- unstable
+
+void llHTTPResponse( key request_id, integer status, string body )
+
+string llInsertString( string dst, integer position, string src )
+- SEF
+
+void llInstantMessage( key user, string message )
+- delay 2.0
+
+string llIntegerToBase64( integer number )
+- SEF
+
+list llJson2List( string json )
+- SEF
+
+string llJsonGetValue( string json, list specifiers )
+- SEF
+
+string llJsonSetValue( string json, list specifiers, string value )
+- SEF
+
+string llJsonValueType( string json, list specifiers )
+- SEF
+
+string llKey2Name( key id )
+- SEF
+
+key llKeyCountKeyValue( )
+- unstable
+
+key llKeysKeyValue( integer start, integer count )
+- unstable
+
+void llLinkParticleSystem( integer linknumber, list rules )
+- SEF if linknumber > 256
+
+void llLinkSitTarget( integer link, vector offset, rotation rot )
+- SEF if link > 256
+
+string llList2CSV( list src )
+- SEF
+
+float llList2Float( list src, integer index )
+- SEF
+
+integer llList2Integer( list src, integer index )
+- SEF
+
+string llList2Json( string type, list values )
+- SEF
+
+key llList2Key( list src, integer index )
+- SEF
+
+list llList2List( list src, integer start, integer end )
+- SEF
+
+list llList2ListStrided( list src, integer start, integer end, integer stride )
+- SEF
+
+rotation llList2Rot( list src, integer index )
+- SEF
+
+string llList2String( list src, integer index )
+- SEF
+
+vector llList2Vector( list src, integer index )
+- SEF
+
+integer llListFindList( list src, list test )
+- SEF
+
+list llListInsertList( list dest, list src, integer start )
+- SEF
+
+list llListRandomize( list src, integer stride )
+- unstable
+- SEF
+
+list llListReplaceList( list dest, list src, integer start, integer end )
+- SEF
+
+list llListSort( list src, integer stride, integer ascending )
+- SEF
+
+float llListStatistics( integer operation, list src )
+- SEF
+
+integer llListen( integer channel, string name, key id, string msg )
+
+void llListenControl( integer number, integer active )
+- SEF if number == 0
+
+void llListenRemove( integer number )
+- SEF if number == 0
+
+void llLoadURL( key avatar, string message, string url )
+- delay 0.1
+
+float llLog( float val )
+- SEF
+
+float llLog10( float val )
+- SEF
+
+void llLookAt( vector target, float strength, float damping )
+
+void llLoopSound( string sound, float volume )
+
+void llLoopSoundMaster( string sound, float volume )
+
+void llLoopSoundSlave( string sound, float volume )
+
+string llMD5String( string src, integer nonce )
+- SEF
+
+void llMakeExplosion( integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset )
+- delay 0.1
+
+void llMakeFire( integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset )
+- delay 0.1
+
+void llMakeFountain( integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset )
+- delay 0.1
+
+void llMakeSmoke( integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset )
+- delay 0.1
+
+integer llManageEstateAccess( integer action, key id )
+# TODO: Find what happens on invalid action codes, to see if they are SEF.
+- min 0
+- max 1
+
+void llMapDestination( string simname, vector pos, vector look_at )
+- delay 1.0
+
+void llMessageLinked( integer linknum, integer num, string str, key id )
+- SEF if linknum > 256
+
+void llMinEventDelay( float delay )
+
+integer llModPow( integer a, integer b, integer c )
+- delay 1.0
+
+void llModifyLand( integer action, integer brush )
+
+void llMoveToTarget( vector target, float tau )
+
+void llNavigateTo( vector point, list options )
+
+void llOffsetTexture( float u, float v, integer face )
+- delay 0.2
+
+void llOpenRemoteDataChannel( )
+- delay 1.0
+
+integer llOverMyLand( key id )
+- SEF
+- min 0
+- max 1
+# assumed:
+- return 0 if nulluuid(id)
+
+void llOwnerSay( string msg )
+
+void llParcelMediaCommandList( list command )
+- delay 2.0
+
+list llParcelMediaQuery( list query )
+- delay 2.0
+
+list llParseString2List( string src, list separators, list spacers )
+- SEF
+
+list llParseStringKeepNulls( string src, list separators, list spacers )
+- SEF
+
+void llParticleSystem( list rules )
+
+void llPassCollisions( integer pass )
+
+void llPassTouches( integer pass )
+
+void llPatrolPoints( list points, list options )
+
+void llPlaySound( string sound, float volume )
+
+void llPlaySoundSlave( string sound, float volume )
+
+void llPointAt( vector pos )
+- SEF
+
+float llPow( float base, float exponent )
+- SEF
+
+void llPreloadSound( string sound )
+- delay 1.0
+
+void llPursue( key target, list options )
+
+void llPushObject( key id, vector impulse, vector ang_impulse, integer local )
+
+key llReadKeyValue( string k )
+- unstable
+
+void llRefreshPrimURL( )
+# emits an error -> has side effects
+- delay 20.0
+
+void llRegionSay( integer channel, string msg )
+# channel 0 emits an error -> not SEF
+
+void llRegionSayTo( key target, integer channel, string msg )
+
+void llReleaseCamera( key avatar )
+- SEF
+
+void llReleaseControls( )
+
+void llReleaseURL( string url )
+- SEF if url == ""
+
+void llRemoteDataReply( key channel, key message_id, string sdata, integer idata )
+- delay 3.0
+
+void llRemoteDataSetRegion( )
+
+void llRemoteLoadScript( key target, string name, integer running, integer start_param )
+# emits an error -> has side effects
+- delay 3.0
+
+void llRemoteLoadScriptPin( key target, string name, integer pin, integer running, integer start_param )
+- delay 3.0
+
+void llRemoveFromLandBanList( key avatar )
+- delay 0.1
+
+void llRemoveFromLandPassList( key avatar )
+- delay 0.1
+
+void llRemoveInventory( string item )
+
+void llRemoveVehicleFlags( integer flags )
+
+key llRequestAgentData( key id, integer data )
+- unstable
+- delay 0.1
+
+key llRequestDisplayName( key id )
+- unstable
+- SEF if nulluuid(id)
+
+void llRequestExperiencePermissions( key agent, string name )
+
+key llRequestInventoryData( string name )
+- unstable
+- delay 1.0
+
+void llRequestPermissions( key agent, integer perm )
+- SEF if perm == 0
+
+key llRequestSecureURL( )
+- unstable
+
+key llRequestSimulatorData( string simulator, integer data )
+- unstable
+- delay 1.0
+
+key llRequestURL( )
+- unstable
+
+key llRequestUsername( key id )
+- unstable
+
+void llResetAnimationOverride( string anim_state )
+
+void llResetLandBanList( )
+- delay 0.1
+
+void llResetLandPassList( )
+- delay 0.1
+
+void llResetOtherScript( string name )
+
+void llResetScript( )
+- stop
+
+void llResetTime( )
+
+integer llReturnObjectsByID( list objects )
+- min -5
+- max 65536
+
+integer llReturnObjectsByOwner( key owner, integer scope )
+# assumed unstable
+- unstable
+- min -5
+- max 65536
+
+void llRezAtRoot( string inventory, vector pos, vector vel, rotation rot, integer param )
+- delay 0.1
+
+void llRezObject( string inventory, vector pos, vector vel, rotation rot, integer param )
+- delay 0.1
+
+float llRot2Angle( rotation rot )
+- SEF
+
+vector llRot2Axis( rotation rot )
+- SEF
+
+vector llRot2Euler( rotation q )
+- SEF
+
+vector llRot2Fwd( rotation q )
+- SEF
+
+vector llRot2Left( rotation q )
+- SEF
+
+vector llRot2Up( rotation q )
+- SEF
+
+rotation llRotBetween( vector v1, vector v2 )
+- SEF
+
+void llRotLookAt( rotation target, float strength, float damping )
+
+integer llRotTarget( rotation rot, float error )
+- unstable
+
+void llRotTargetRemove( integer number )
+
+void llRotateTexture( float angle, integer face )
+- delay 0.2
+
+integer llRound( float val )
+- SEF
+
+string llSHA1String( string src )
+- SEF
+
+integer llSameGroup( key id )
+- SEF
+- min 0
+- max 1
+
+void llSay( integer channel, string msg )
+
+integer llScaleByFactor( float scaling_factor )
+- unstable
+- min 0
+- max 1
+
+void llScaleTexture( float u, float v, integer face )
+- delay 0.2
+
+integer llScriptDanger( vector pos )
+- SEF
+- min 0
+- max 1
+
+void llScriptProfiler( integer flags )
+
+key llSendRemoteData( key channel, string dest, integer idata, string sdata )
+- unstable
+- delay 3.0
+
+void llSensor( string name, key id, integer type, float range, float arc )
+# type == 0 || range == 0 cancels a sensor in this frame.
+
+void llSensorRemove( )
+
+void llSensorRepeat( string name, key id, integer type, float range, float arc, float rate )
+
+void llSetAlpha( float alpha, integer face )
+- SEF if face > 8
+
+void llSetAngularVelocity( vector angular_velocity, integer local )
+
+void llSetAnimationOverride( string anim_state, string anim )
+
+void llSetBuoyancy( float buoyancy )
+
+void llSetCameraAtOffset( vector offset )
+
+void llSetCameraEyeOffset( vector offset )
+
+void llSetCameraParams( list rules )
+
+void llSetClickAction( integer action )
+
+void llSetColor( vector color, integer face )
+- SEF if face > 8
+
+void llSetContentType( key request_id, integer content_type )
+- SEF if nulluuid(request_id)
+
+void llSetDamage( float damage )
+
+void llSetForce( vector force, integer local )
+
+void llSetForceAndTorque( vector force, vector torque, integer local )
+
+void llSetHoverHeight( float height, integer water, float tau )
+
+void llSetInventoryPermMask( string item, integer mask, integer value )
+
+void llSetKeyframedMotion( list keyframes, list options )
+
+void llSetLinkAlpha( integer linknumber, float alpha, integer face )
+- SEF if linknumber > 256 || face > 8
+
+void llSetLinkCamera( integer link, vector eye, vector at )
+- SEF if link > 256
+
+void llSetLinkColor( integer linknumber, vector color, integer face )
+- SEF if linknumber > 256 || face > 8
+
+integer llSetLinkMedia( integer link, integer face, list params )
+- SEF if link > 256
+
+void llSetLinkPrimitiveParams( integer linknumber, list rules )
+- delay 0.2
+
+void llSetLinkPrimitiveParamsFast( integer linknumber, list rules )
+- SEF if linknumber > 256
+
+void llSetLinkTexture( integer linknumber, string texture, integer face )
+- delay 0.2
+
+void llSetLinkTextureAnim( integer link, integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate )
+- SEF if linknumber > 256
+
+void llSetLocalRot( rotation rot )
+- delay 0.2
+
+integer llSetMemoryLimit( integer limit )
+- SEF if limit <= 0
+- min 0
+- max 1
+
+void llSetObjectDesc( string desc )
+
+void llSetObjectName( string name )
+
+void llSetObjectPermMask( integer mask, integer value )
+
+void llSetParcelMusicURL( string url )
+- delay 2.0
+
+void llSetPayPrice( integer price, list quick_pay_buttons )
+
+void llSetPhysicsMaterial( integer flags, float gravity_multiplier, float restitution, float friction, float density )
+- SEF if flags == 0
+
+void llSetPos( vector pos )
+- delay 0.2
+
+integer llSetPrimMediaParams( integer face, list params )
+- delay 1.0
+
+void llSetPrimURL( string url )
+# emits an error -> has side effects
+- delay 20.0
+
+void llSetPrimitiveParams( list rules )
+- delay 0.2
+
+integer llSetRegionPos( vector pos )
+# unstable because it may fail when becoming more accurate and positioning
+# over an invalid parcel
+- unstable
+- min 0
+- max 1
+
+void llSetRemoteScriptAccessPin( integer pin )
+- delay 0.2
+
+void llSetRot( rotation rot )
+- delay 0.2
+
+void llSetScale( vector scale )
+
+void llSetScriptState( string name, integer run )
+
+void llSetSitText( string text )
+
+void llSetSoundQueueing( integer queue )
+
+void llSetSoundRadius( float radius )
+
+void llSetStatus( integer status, integer value )
+
+void llSetText( string text, vector color, float alpha )
+
+void llSetTexture( string texture, integer face )
+- delay 0.2
+
+void llSetTextureAnim( integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate )
+
+void llSetTimerEvent( float sec )
+
+void llSetTorque( vector torque, integer local )
+
+void llSetTouchText( string text )
+
+void llSetVehicleFlags( integer flags )
+
+void llSetVehicleFloatParam( integer param, float value )
+
+void llSetVehicleRotationParam( integer param, rotation rot )
+
+void llSetVehicleType( integer type )
+
+void llSetVehicleVectorParam( integer param, vector vec )
+
+void llSetVelocity( vector velocity, integer local )
+
+void llShout( integer channel, string msg )
+
+float llSin( float theta )
+- SEF
+
+integer llSitOnLink( key agent_id, integer link )
+- min -7
+- max 1
+
+void llSitTarget( vector offset, rotation rot )
+
+void llSleep( float sec )
+
+void llSound( string sound, float volume, integer queue, integer loop )
+
+void llSoundPreload( string sound )
+
+float llSqrt( float val )
+- SEF
+
+void llStartAnimation( string anim )
+
+void llStopAnimation( string anim )
+
+void llStopHover( )
+
+void llStopLookAt( )
+
+void llStopMoveToTarget( )
+
+void llStopPointAt( )
+
+void llStopSound( )
+
+integer llStringLength( string str )
+- SEF
+
+string llStringToBase64( string str )
+- SEF
+
+string llStringTrim( string src, integer trim_type )
+- SEF
+
+integer llSubStringIndex( string source, string pattern )
+- SEF
+
+void llTakeCamera( key avatar )
+- SEF
+
+void llTakeControls( integer controls, integer accept, integer pass_on )
+
+float llTan( float theta )
+- SEF
+
+integer llTarget( vector position, float range )
+- unstable
+
+void llTargetOmega( vector axis, float spinrate, float gain )
+
+void llTargetRemove( integer number )
+- SEF if number == 0
+
+void llTeleportAgent( key avatar, string landmark, vector position, vector look_at )
+
+void llTeleportAgentGlobalCoords( key agent, vector global_coordinates, vector region_coordinates, vector look_at )
+
+void llTeleportAgentHome( key id )
+- delay 5.0
+
+void llTextBox( key avatar, string message, integer chat_channel )
+- delay 1.0
+
+string llToLower( string src )
+- SEF
+
+string llToUpper( string src )
+- SEF
+
+key llTransferLindenDollars( key destination, integer amount )
+- unstable
+
+void llTriggerSound( string sound, float volume )
+
+void llTriggerSoundLimited( string sound, float volume, vector top_north_east, vector bottom_south_west )
+
+void llUnSit( key id )
+
+string llUnescapeURL( string url )
+- SEF
+
+void llUpdateCharacter( list options )
+
+key llUpdateKeyValue( string k, string v, integer checked, string original_value )
+- unstable
+
+float llVecDist( vector v1, vector v2 )
+- SEF
+
+float llVecMag( vector v )
+- SEF
+
+vector llVecNorm( vector v )
+- SEF
+
+void llVolumeDetect( integer detect )
+
+void llWanderWithin( vector center, vector radius, list options )
+
+float llWater( vector offset )
+- SEF
+- min 0
+
+void llWhisper( integer channel, string msg )
+
+vector llWind( vector offset )
+- SEF
+
+string llXorBase64( string str1, string str2 )
+- SEF
+
+string llXorBase64Strings( string str1, string str2 )
+- delay 0.3
+
+string llXorBase64StringsCorrect( string str1, string str2 )
+- SEF
diff --git a/lslopt/lslloadlib.py b/lslopt/lslloadlib.py
index 079abb0..8ed438c 100644
--- a/lslopt/lslloadlib.py
+++ b/lslopt/lslloadlib.py
@@ -21,16 +21,16 @@ import sys, re
from lslcommon import types, warning, Vector, Quaternion
import lslcommon, lslfuncs
-def LoadLibrary(builtins = None, seftable = None):
- """Load builtins.txt and seftable.txt (or the given filenames) and return
+def LoadLibrary(builtins = None, fndata = None):
+ """Load builtins.txt and fndata.txt (or the given filenames) and return
a tuple with the events, constants and functions, each in a dict.
"""
if builtins is None:
builtins = lslcommon.DataPath + 'builtins.txt'
- if seftable is None:
- seftable = lslcommon.DataPath + 'seftable.txt'
+ if fndata is None:
+ fndata = lslcommon.DataPath + 'fndata.txt'
events = {}
constants = {}
@@ -50,8 +50,10 @@ def LoadLibrary(builtins = None, seftable = None):
r'\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*?)\s*$'
r'|'
r'^\s*(?:#.*|//.*)?$')
- parse_arg_re = re.compile(r'^\s*([a-z]+)\s+[a-zA-Z_][a-zA-Z0-9_]*\s*$')
- parse_num_re = re.compile(r'^\s*(-?(?=[0-9]|\.[0-9])[0-9]*((?:\.[0-9]*)?(?:[Ee][+-]?[0-9]+)?))\s*$')
+ parse_arg_re = re.compile(r'^\s*([a-z]+)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*$')
+ parse_fp_re = re.compile(r'^\s*(-?(?=[0-9]|\.[0-9])[0-9]*'
+ r'((?:\.[0-9]*)?(?:[Ee][+-]?[0-9]+)?))\s*$')
+ parse_int_re = re.compile(r'^\s*(-?0x[0-9A-Fa-f]+|-?[0-9]+)\s*$')
parse_str_re = re.compile(ur'^"((?:[^"\\]|\\.)*)"$')
f = open(builtins, 'rb')
@@ -84,7 +86,8 @@ def LoadLibrary(builtins = None, seftable = None):
if typ == 'void':
typ = None
elif typ != 'event' and typ not in types:
- warning(u"Invalid type in %s, line %d: %s" % (ubuiltins, linenum, typ))
+ warning(u"Invalid type in %s, line %d: %s"
+ % (ubuiltins, linenum, typ))
continue
args = []
arglist = match.group(3)
@@ -95,7 +98,8 @@ def LoadLibrary(builtins = None, seftable = None):
argtyp = parse_arg_re.search(arg).group(1)
if argtyp not in types:
uargtyp = argtyp.decode('utf8')
- warning(u"Invalid type in %s, line %d: %s" % (ubuiltins, linenum, uargtyp))
+ warning(u"Invalid type in %s, line %d: %s"
+ % (ubuiltins, linenum, uargtyp))
del uargtyp
bad = True
break
@@ -118,7 +122,8 @@ def LoadLibrary(builtins = None, seftable = None):
warning(u"Function at line %d was already defined in %s, overwriting: %s" % (linenum, ubuiltins, uname))
del uname
fn = getattr(lslfuncs, name, None)
- functions[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args}
+ functions[name] = {'Kind':'f', 'Type':typ,
+ 'ParamTypes':args, 'NeedsData':True}
if fn is not None:
functions[name]['Fn'] = fn
elif match.group(4):
@@ -174,22 +179,22 @@ def LoadLibrary(builtins = None, seftable = None):
value = value[1:-1].split(',')
if len(value) != (3 if typ == 'vector' else 4):
raise ValueError
- num = parse_num_re.search(value[0])
+ num = parse_fp_re.search(value[0])
if not num:
raise ValueError
value[0] = lslfuncs.F32(float(num.group(1)))
- num = parse_num_re.search(value[1])
+ num = parse_fp_re.search(value[1])
if not num:
raise ValueError
value[1] = lslfuncs.F32(float(num.group(1)))
- num = parse_num_re.search(value[2])
+ num = parse_fp_re.search(value[2])
if not num:
raise ValueError
value[2] = lslfuncs.F32(float(num.group(1)))
if typ == 'vector':
value = Vector(value)
else:
- num = parse_num_re.search(value[3])
+ num = parse_fp_re.search(value[3])
if not num:
raise ValueError
value[3] = lslfuncs.F32(float(num.group(1)))
@@ -211,20 +216,200 @@ def LoadLibrary(builtins = None, seftable = None):
finally:
f.close()
- # Load the side-effect-free table as well.
- # TODO: Transform the SEF Table into a function properties table
- # that includes domain data (min, max) and stability data
- # (whether multiple successive calls return the same result)
- f = open(seftable, 'rb')
+ # Load the function data table as well.
+
+ parse_flag_re = re.compile(r'^\s*-\s+(?:(?:(sef)|return\s+'
+ r'("(?:\\.|[^"])*"|<[^>]+>|[-+0-9x.e]+' # strings, vectors, numbers
+ r'|\[(?:[^]"]|"(?:\\.|[^"])*")*\]))' # lists
+ r'(?:\s+if\s+(.*\S))?'
+ r'|(unstable|stop)|(min|max|delay)\s+([-0-9.]+))\s*$', re.I)
+
+ # TODO: "quaternion" doesn't compare equal to "rotation" even if they are
+ # equivalent. Canonicalize it before comparison, to avoid false
+ # reports of mismatches.
+ f = open(fndata, 'rb')
+ try:
+ linenum = 0
+ curr_fn = None
+ skipping = False
+ try:
+ ufndata = fndata.decode(sys.getfilesystemencoding())
+ except UnicodeDecodeError:
+ # This is just a guess at the filename encoding.
+ ufndata = fndata.decode('iso-8859-15')
+ while True:
+ linenum += 1
+ line = f.readline()
+ if not line: break
+ if line[-1] == '\n': line = line[:-1]
+ try:
+ uline = line.decode('utf8')
+ except UnicodeDecodeError:
+ warning(u"Bad Unicode in %s line %d" % (ufndata, linenum))
+ continue
+ match_fn = parse_lin_re.search(line)
+ if match_fn and not match_fn.group(4) and not match_fn.group(1):
+ # comment or empty
+ continue
+
+ rettype = match_fn.group(1) if match_fn else None
+ if match_fn and (rettype == 'void' 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,"
+ u" skipping."
+ % (uname, ufndata, linenum))
+ continue
+ rettype = rettype if rettype != 'void' else None
+ if 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']
+ 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))
+ continue
+
+ bad = False # used to 'continue' at this loop level
+ for idx, arg in enumerate(arglist):
+ argmatch = parse_arg_re.search(arg)
+ argtyp = argmatch.group(1)
+ 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))
+ bad = True
+ break
+ argnames.append(argname)
+ if bad:
+ del bad
+ continue
+ del bad
+
+ if 'NeedsData' not in functions[name]:
+ warning(u"Duplicate function %s in %s line %d. Skipping."
+ % (uname, ufndata, linenum))
+ continue
+
+ # passed all tests
+ curr_fn = name
+ skipping = False
+ del functions[name]['NeedsData']
+
+ 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))
+ skipping = True
+ continue
+ if not skipping:
+ ucurr_fn = curr_fn.decode('utf8')
+ if match_flag.group(1):
+ # SEF
+ # 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
+ elif match_flag.group(2):
+ pass # return not handled yet
+ elif (match_flag.group(4)
+ and match_flag.group(4).lower() == 'unstable'
+ ):
+ functions[curr_fn]['uns'] = True
+ elif match_flag.group(4): # must be stop
+ functions[curr_fn]['stop'] = True
+ elif match_flag.group(5).lower() in ('min', 'max'):
+ minmax = match_flag.group(5).lower()
+ value = match_flag.group(6)
+ typ = functions[curr_fn]['Type']
+ if typ == 'integer':
+ good = parse_int_re.search(value)
+ if good:
+ value = lslfuncs.S32(int(good.group(1), 0))
+ elif typ == 'float':
+ good = parse_fp_re.search(value)
+ if good:
+ value = lslfuncs.F32(float(good.group(1)))
+ else:
+ good = False
+ if good:
+ functions[curr_fn][minmax] = value
+ else:
+ warning(u"Type mismatch or value error in %s"
+ u" line %d: %s"
+ % (ufndata, linenum, uline))
+ continue
+ else: # delay
+ value = parse_fp_re.search(match_flag.group(6))
+ if not value:
+ warning(u"Invalid delay value in %s"
+ u" line %d: %s"
+ % (ufndata, linenum, uline))
+ continue
+
+ value = float(value.group(1)) # no need to F32
+ if value != 0 and 'SEF' in functions[curr_fn]:
+ warning(u"Side-effect-free function"
+ u" %s contradicts delay, in %s"
+ u" line %d"
+ % (ucurr_fn, ufndata, linenum))
+ continue
+
+ functions[curr_fn]['delay'] = value
+ #word = match_flag.group(1) or match_flag.group(2) or match_flag.group(4) or match_flag.group(5)
+ #print curr_fn, repr(word)
+ else:
+ warning(u"Syntax error in %s line %d, skipping: %s"
+ % (ufndata, linenum, uline))
+ continue
+
+ finally:
+ f.close()
+
+ # Post-checks
+ for i in functions:
+ ui = i.decode('utf8')
+ if 'NeedsData' in functions[i]:
+ del functions[i]['NeedsData']
+ warning(u"Function %s has no data" % i)
+ if 'min' in functions[i] and 'max' in functions[i]:
+ if functions[i]['min'] > functions[i]['max']:
+ warning(u"Function %s has min > max: min=%s max=%s"
+ % (ui, repr(functions[i]['min']).decode('utf8'),
+ repr(functions[i]['max'])))
+ if 'SEF' in functions[i] and 'delay' in functions[i]:
+ warning(u"Side-effect-free function %s contradicts delay" % ui)
+
+ # FIXME: Temp: Load the seftable to compare it with the ftable.
+ f = open('seftable.txt', 'rb')
try:
while True:
line = f.readline()
if line == '':
break
line = line.strip()
- if line and line[0] != '#' and line in functions:
- functions[line]['SEF'] = True
+ if line and line[0] != '#':# and line in functions:
+ #if 'SEF' not in functions[line]:
+ # warning(u"Function %s SEF mismatch" % line)
+ #functions[line]['SEF2'] = True
+ pass
finally:
f.close()
+ for line in functions:
+ if 'SEF' in functions[line] and 'SEF2' not in functions[line]:
+ pass#warning(u"Function %s SEF mismatch2" % line)
return events, constants, functions
diff --git a/main.py b/main.py
index 5f988d6..3a1eb1d 100755
--- a/main.py
+++ b/main.py
@@ -203,7 +203,7 @@ Usage: {progname}
[--version] print this program's version
[-o|--output=] output to file rather than stdout
[-b|--builtins=] use a builtins file other than builtins.txt
- [-S|--seftable=] use a SEF table file other than seftable.txt
+ [-L|--libdata=] use a function data file other than fndata.txt
[-H|--header] add the script as a comment in Firestorm format
[-T|--timestamp] add a timestamp as a comment at the beginning
[-y|--python-exceptions] when an exception is raised, show a stack trace
@@ -380,12 +380,12 @@ def main(argv):
% (b"', '".join(options - validoptions)).decode('utf8'))
try:
- opts, args = getopt.gnu_getopt(argv[1:], 'hO:o:p:P:HTyb:S:',
+ opts, args = getopt.gnu_getopt(argv[1:], 'hO:o:p:P:HTyb:L:',
('optimizer-options=', 'help', 'version', 'output=', 'header',
'timestamp','python-exceptions',
'preproc=', 'precmd=', 'prearg=', 'prenodef', 'preshow',
'avid=', 'avname=', 'assetid=', 'shortname=', 'builtins='
- 'seftable='))
+ 'libdata='))
except getopt.GetoptError as e:
Usage(argv[0])
sys.stderr.write(u"\nError: " + str(e).decode('utf8') + u"\n")
@@ -405,7 +405,7 @@ def main(argv):
preshow = False
raise_exception = False
builtins = None
- seftable = None
+ libdata = None
for opt, arg in opts:
if type(opt) is unicode:
@@ -452,8 +452,8 @@ def main(argv):
elif opt in ('-b', '--builtins'):
builtins = arg
- elif opt in ('-S', '--seftable'):
- seftable = arg
+ elif opt in ('-L', '--libdata'):
+ libdata = arg
elif opt in ('-y', '--python-exceptions'):
raise_exception = True
@@ -652,7 +652,7 @@ def main(argv):
if not preshow:
- lib = lslopt.lslloadlib.LoadLibrary(builtins, seftable)
+ lib = lslopt.lslloadlib.LoadLibrary(builtins, libdata)
p = parser(lib)
try:
ts = p.parse(script, options,