Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

lslint - offline code checker for LSL

Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-07-2006 18:06
lslint is a tool to check the syntactic and semantic validity of scripts. It is basically a compiler that doesn't compile, but has helpful error messages, warnings, and checks for some common problems in LSL. It is mainly for use with an external editor.

You can download it or try it online at: http://w-hat.com/lslint/

As an example, consider the following script:
CODE
integer number = 2+2;               // non constant
integer number = 3; // will only pass because above fails
integer number = 4; // already declared

string unused() { // warning: declared but never used
state default; // error: can't change state in function
if (TRUE) {
state default; // warning: hack that corrupts stack
return; // error: returning nothing in int function
}
}

string test(integer a, vector v) {
string q; // warning: declared but never used
return v; // error: returning vector in string function
}

default {

state_entry(integer param) { // state_entry does not take params
integer number = "hello"; // type mismatch, warning: shadow decl
int q; // should point out int->integer typo maybe
number = number-2; // warning: parsed as IDENTIFER INTEGER
number = 2-2; // warning: 2-2 = 2
[1] == [2]; // warning: list == list only compares length
number = number; // warning: (above too) statement with no effect
str = "hi!"; // undeclared
llSay(0, number.x); // number is not a vector
LLsay(0, llListToString([])); // typos; suggest llSay, llList2String
test(1, "hi"); // arg 2 of test should be vector but got string
jump number; // number is not a label
jump label; // warning: when using multiple jumps to the
jump label; // same label, all but the last is ignored
@label;
return number; // returning a value in an event
state default; // warning: switch to current state acts like return
// warning: code is never reached
}

touch_start() { // requires parameters
}

at_target(integer i, vector v, string s) { // third parameter should be vector
}

}


Here's the error output when compiling within SL:
CODE
(0, 18) : ERROR : Syntax error

(repeat basically ad infinitum as you fix or comment out errors)

Here's the output from lslint, in one run:
CODE
ERROR:: (  1, 18): global initializer must be constant.
ERROR:: ( 20, 17): syntax error, unexpected INTEGER, expecting ')'
event prototype must match: "state_entry()"
ERROR:: ( 22, 13): syntax error, unexpected IDENTIFIER
ERROR:: ( 23, 24): expression and constant without operator; are you doing 'foo-2'?
make sure you separate operators with spaces.
see http://secondlife.com/badgeo/wakka.php?wakka=knownbugs
WARN:: ( 24, 18): `2-2' treated as 2; this is probably not what you wanted
make sure you separate operators with spaces
see: http://forums.secondlife.com/showthread.php?t=60257
ERROR:: ( 40, 17): syntax error, unexpected ')', expecting INTEGER
event prototype must match: "touch_start(integer)"
ERROR:: ( 43, 36): syntax error, unexpected STRING, expecting VECTOR
event prototype must match: "at_target(integer, vector, vector)"
ERROR:: ( 3, 1): duplicate declaration of `number'; previously declared at (2, 1)
WARN:: ( 21, 9): declaration of `number' in this scope shadows previous declaration at (2, 1)
ERROR:: ( 6, 5): cannot change state in function
WARN:: ( 8, 9): changing state in a list or string function will corrupt the stack
using the return value from this function will cause a run-time bounds check error.
see http://secondlife.com/badgeo/wakka.php?wakka=FunctionStateChangeHack
ERROR:: ( 9, 9): returning none from string function
ERROR:: ( 15, 5): returning vector from string function
ERROR:: ( 21, 9): `number' declared as integer but assigned string value
ERROR:: ( 27, 9): `str' is undeclared
ERROR:: ( 28, 18): attempting to access member `.x' of variable `number' which is not a vector or rotation
ERROR:: ( 29, 18): `llListToString' is undeclared; did you mean `llList2String'?
ERROR:: ( 29, 9): `LLsay' is undeclared; did you mean `llSay'?
ERROR:: ( 30, 9): Type mismatch: passing value of type string as argument 2 of `test' which is declared as `vector v'ERROR:: ( 31, 14): attempting to use `number' as a label but it is a variable
WARN:: ( 33, 9): !!! multiple jumps for label `label', all but last will be ignored !!!
ERROR:: ( 35, 9): can't return a value from an event handler
WARN:: ( 36, 9): changing state to current state acts the same as `return' (SL1.8.3)
if this is what you intended, consider using return instead
WARN:: ( 25, 9): list == list only compares lengths
see http://secondlife.com/badgeo/wakka.php?wakka=annoyances
WARN:: ( 2, 1): variable `number' declared but never used
WARN:: ( 5, 1): function `unused' declared but never used
WARN:: ( 13, 21): variable `a' declared but never used
WARN:: ( 14, 5): variable `q' declared but never used
WARN:: ( 7, 9): condition is always true
TOTAL:: Errors: 18 Warnings: 11


It is a command-line program, so you should save it somewhere easy like C:\lsl\. You can run it by hand, but I recommend using SciTE-EZ, or, if you're a super nerd, vim.

To use lslint from SciTE-ez, go to the Options menu, choose "Open lsl.properties" and put something like the following line somewhere, and then hit save. Change the path to match where you downloaded the file. After that you can use Tools -> Compile (CTRL+F7) to check your script, and Tools -> Go (F5) by default to copy it to your clipboard.
CODE
command.compile.*.lsl="C:\lsl\lslint.exe" "$(FileNameExt)"


To use it from vim, create a new file (:enew), paste the following into it, and save as a compiler plugin, (:saveas ~/vimfiles/compiler/lsl.vim). Then type ":compiler lsl" to select it and ":make" to compile the current file.
CODE
set errorformat=%EERROR::\ \(%*\\s%l\\,%*\\s%c\):\ %m,%W\ WARN::\ \(%*\\s%l\\,%*\\s%c\):\ %m ",%+C%*\\s%m
set makeprg=C:\lsl\lslint.exe\ %


I have tested it with random scripts of my own and several from the library and wiki, but there are bound to be things I overlooked. I also cheated for the builtin functions and had it rip them out of SecondLife.exe, which has some mistakes. I fixed a few I ran into but I'm sure there are more. Please please please post here if it does anything weird or if you have any suggestions.

Disclaimer: Nothing that happens ever is my fault no matter what and also I am not affiliated with Linden Lab and anything else I am supposed to write is hereby written right here.
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
02-07-2006 18:29
Assuming this works, I'm impressed! Going to try testing this under Wine.


Two questions come to mind about this item:

1) Mind posting an MD5, since it's a binary? For the paranoid.
2) Any chance we'll see the source for this?

Thanks!
_____________________
---
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
02-07-2006 19:03
Boy have I been waiting for something like this. Such a pain having to compile things over and over again in SL just to catch typos and missing brackets etc. Not only that but SL can be a bit vague about where the errors are sometimes, and only gives u one at a time. I'll be tryin this out as soon as I get home tonight for sure.
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-07-2006 19:03
From: Jeffrey Gomez
1) Mind posting an MD5, since it's a binary? For the paranoid.
Sure, I added it into the first post.
From: Jeffrey Gomez
2) Any chance we'll see the source for this?
I haven't decided.
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-08-2006 10:05
You can now use lslint online without downloading at: http://w-hat.com/lslint/
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-08-2006 11:28
It probably is just a compiled version of the lex and yacc files. It should be noted that LL needs to rewrite them.

Plus function and varraible name handling.

EDIT:
You've sold me, it's telling me about my unused varraibles.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-08-2006 11:41
I've got your first bug report ^_^

CODE

fun(vector a)
{
llOwnerSay((string)a.x);
}


if you compile that, it will say "WARNING:: (xxx, xxx): variable `a' declared but never used"
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
02-08-2006 11:51
Im not sure if this is a bug, but it is surely inconveniant :)
If you try compiling this:
CODE

default {
}

The program reports:
CODE

ERROR:: (2, 1): parse error, unexpected '}'
Warnings: 0 Errors: 1

That's somewhat unexpected - in this way lslint < SL Editor, SL Editor tells you explicitly "You need at least one event in a state."

I love it though, thank you for putting it online - now I can revise the stuff I post to the forums on any computer connected to the internet :D
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
02-08-2006 12:01
Here's something that may help related to Strife's bug:
CODE

default {
state_entry() {
vector scale;
scale.x = 2;
}
}


Lslint reports that scale is never used.
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
02-08-2006 13:22
From: Christopher Omega
Here's something that may help related to Strife's bug:
CODE

default {
state_entry() {
vector scale;
scale.x = 2;
}
}


Lslint reports that scale is never used.
==Chris


Strife's example is different, but for this example, you could say it's an "optimizing lint" - scale is never used as the RHS of an expression, so yes, in a sense, it is never used, because an optimizing compiler would remove it.

;)
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-08-2006 14:06
if LSL had a real compiler you could do fun stuff with the results of vector functions.

CODE

ERROR:: (268, 37): `llRotateTexture' is undeclared

i think you missed a function.

Could you silence the warning about list comparison when one of the lists has a length of zero?
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-08-2006 14:11
I posted a new version.

0.1.2 2006-02-08:
- fixed "var.x" not counting as reference to var (thanks Strife Onizuka)
- added error message for empty state (thanks Christopher Omega)
- made invalid operator error message meaningful
- check for "state x" within state x
- check for state change statement in functions, warn about using if hack

From: Ziggy Puff
Strife's example is different, but for this example, you could say it's an "optimizing lint" - scale is never used as the RHS of an expression, so yes, in a sense, it is never used, because an optimizing compiler would remove it.
In this case, a better warning might be, "If the compiler removes any part of this event handler, you may want to take Hell's temperature."

Thanks for the bug reports! I'd be interested in feature suggestions as well. Here are a few things I've got planned:
- assignment used in comparison: if (i = 1)
- condition is always true/false: if ( i == i )
- statement with no effect: i == i;
- code is never reached: return; do_thing();
- accidents like this: if (i); do_thing();

From: Strife Onizuka
ERROR:: (268, 37): `llRotateTexture' is undeclared
Argh. Here's the tooltip for it: llOffsetTexture(float rotation, integer face)
Others currently missing for the same reason:
- llGroundContour (tooltip says Countour)
- llSetVehicleRotationParam (tooltip says VectorParam)
They're fixed in the next version.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-08-2006 14:18
just for a matter of conversation i do use if (i = value) this sort of thing every so often though value is almost always another variable or a function.

Don't know if you saw, just edited my post above about zero list length comparisons.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-08-2006 14:28
There is one thing LSL will let you do that is totaly bogus, have multiple states of the same type, i forget exactly which one gets called (i think the first).

Valid LSL
CODE

default
{
state_entry()
{;}
state_entry()
{;}
}


Could you please have the compile spit out a big fat error ^^
This rates up there with
CODE

if(test);
something;


but could you make it so it doesn't falsely identify

if(test);else
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
02-08-2006 14:33
From: someone
just for a matter of conversation i do use if (i = value) this sort of thing every so often though value is almost always another variable or a function.


That's almost always worth a warning though. If for no other reason than the fact that 90% of the places where that occurs is probably a typo. Most compilers I've used will throw in a gentle "Are you sure this is what you want here? Just checking." type of message for that construct.

Here's a feature suggestion, which is something I've run into. If I make a variable and a state have the same name, the LSL editor will put the cursor at the last line of the script and say something about a name declaration/scope conflict. Which isn't very helpful to figure out what conflicted. It would be nice to have a more directed error message for that situation.
Deneria Sholokhov
Leaf on the Wind
Join date: 25 Oct 2005
Posts: 12
02-08-2006 15:03
This is excellent, works well with SlickEdit too. I have just become that much more unproductive at my real job *laughs*
_____________________
Define "disappeared"
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-10-2006 14:52
I posted a new version, you can download or use it online at: http://w-hat.com/lslint/

0.2.0: 2006-02-10
internal:
- rewritten as pure/reentrant parser/lexer
- logging abstracted for later sorting support
- track and propogate constant values
- better location tracking
- fixed list parsing

added options:
-v Be verbose (version changed to -V),
-l Show line/column info as range (ex: (1,4)-(1,18))

fixed bugs:
- llRotateTexture(), llSetVehicleRotationParam(), llGroundContour() (0004, reported by Strife)
- suppress list == list warning when either argument is [] (0005, reported by Strife)

added warnings:
- condition is always true/false
- using = as condition: (a = 1) warns, (b = 1) == c does not
- empty if statement: if (a); do_thing();
- multiple handlers for same event (0006, reported by Strife)

added errors:
- deprecated functions
Haravikk Mistral
Registered User
Join date: 8 Oct 2005
Posts: 2,482
02-10-2006 15:25
What language is this coded in? I'm on Mac and it would be an interesting tool to have! I have some profficiency in c and java so could be able to compile a program and fix anything that seems to be incompatible with the Mac side of things (interface usually).
Essence Lumin
.
Join date: 24 Oct 2003
Posts: 806
02-10-2006 15:35
Reading this thread I think,

I haven't done any sl programming in quite a while but this seems really cool and must have taken a lot of work.

From a w-hat url? Well yay, something good.

As much as people beat up on perl it has the best error messages I have read in any language. LSL definitely does not. Thanks for the program.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-11-2006 21:46
Causes SegFault (program to crash and return -1073741819)
CODE

list commands;
integer tmode;
integer mode;

default
{
state_entry()
{
mode = llList2Integer(commands, tmode + 1)
llOwnerSay("T");
tmode += 3;
}
}
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Folco Boffin
Mad Moo Cow Cultist
Join date: 27 Feb 2005
Posts: 66
02-11-2006 22:48
You beet me to it Strife. Was just coming to post getting error -1073741819 as well.

Running it from command line it gives me:
CODE

ERROR:: (381, 6): syntax error, unexpected ELSE
ERROR:: (388, 5): syntax error, unexpected IF, expecting ';'


Granted I forgot to close an else statement with a } on 382 and forgot a ; to end 387. But that shouldn't have crashed it. It's spit out errors at me before for similar things. Inside SciTE-ez I get nothing but Exit Code -1073741819.

EDIT>>
After closing the ELSE statement on line 380 and terminating line 387 with a ; it goes through with no problem.
_____________________
^-^

Signed,
Gorgarath,
Whom in this game called Second Life,
plays the avatar Folco Boffin,
and in this game called First Life,
plays the avatar John McDonnell.
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-12-2006 10:14
0.2.1: 2006-02-12
- support vector/quaternion constants and (some) operators
- fix crash when recovering from statement with syntax error (0007, reported by Strife)
- log messages sorted by type and line number, use -S to disable

http://w-hat.com/lslint/

Here's a fun script to try: http://w-hat.com/lslint/constprop.lsl.html

From: Haravikk Mistral
What language is this coded in? I'm on Mac and it would be an interesting tool to have!
C++. It doesn't have any extra dependencies and I'm already compiling it on Linux (gcc 3.3.5), FreeBSD (gcc 2.95.4), and Windows (msvc 7.1/8.0), so I don't think there should be any real portability issues.

edit: Howie Lament hooked me up with a Mac shell, so I will post Linux and Mac binaries with the next version. If you see him give him a hug ok
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-12-2006 12:43
CODE

default
{
state_entry()
{
[- <0.004, 0.0, 0.0>];
}
}


ERROR:: (201,106): Invalid operator: vector -
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-13-2006 13:03
another Segmentation fault
I'm not even going to try and figure out what went wrong.

CODE

// TLML Exporter v0.12, drop in a page's prim to get the corresponding TLML code

// ===How to get unicode characters in your llSetText_text===
// "\uxxxx" where xxxx are 4 hex characters, unicode character 0000xxxx
// "\Uxxxxxxxx" where xxxxxxxx are 8 hex characters, unicode character xxxxxxxx
// "\rXxxx" where X is a hex character giving the number of xxxxx hex character pairs
// if X equals 2 then 4 hex characters follows. This is useful when multiple
// unicode characters are needed. Be sure to break up your UTF-8 string on a
// character boundry or the character will not be included.

string llSetText_text = "";
vector llSetText_color = <1.0,1.0,1.0>;
float llSetText_alpha = 1.0;

vector llTargetOmega_axis = ZERO_VECTOR;
float llTargetOmega_spinrate = 0.0;
float llTargetOmega_gain = 0.0;

//ANIM_ON == 0x01
//LOOP == 0x02
//REVERSE == 0x04
//PING_PONG == 0x08
//SMOOTH == 0x10
//ROTATE == 0x20
//SCALE == 0x40

integer llSetTextureAnim_mode = 0;
integer llSetTextureAnim_face = ALL_SIDES;
integer llSetTextureAnim_x_frames = 2;
integer llSetTextureAnim_y_frames = 2;
float llSetTextureAnim_start_frame = 0;
float llSetTextureAnim_end_frame = 3;
float llSetTextureAnim_rate = 0.1;

list llParticleSystem_list = [];

string TLML_URL = "url";

//////////////////////////////////////////////////////////////
// DO NOT MODIFY ANYTHING BELOW //
//////////////////////////////////////////////////////////////
//This script is a nightmare, only the brave should venture deeper
//adding support for new features is pretty easy
//but don't touch the structure of the script
//because of the complexities of TLML, the data layout is complex
//the *right* was to do this would be with 3 passes
//1) determin the mask
//2) parse the masks and filling in the data
//Instead we do it with basicly a single pass
//Then as the masks become aparent we fill insert them into the stream.
//This saves alot of time with minimal expense
//Unfortunately it's horribly complex

//{
string byte2hex(integer x)
{//Helper function for use with unicode characters.
integer x0 = (x & 0xF);
return llGetSubString(hexc, x0 = ((x >> 4) & 0xF), x0) + llGetSubString(hexc, x0, x0);
}

string Unescape(string a)
{
string b = a;
integer c = -1;
integer d;
integer e;
integer f = 0;
string g;
while(d = llSubStringIndex(b, "\\") + 1)
{
g = llGetSubString(b,d,d);
c += d;

if((g == "\"") || (g == "\\"))
a = llDeleteSubString(a,c,c);
else if(g == "n")
a = llInsertString(llDeleteSubString(a,c,c+1), c, "\n");
else if(g == "t")
a = llInsertString(llDeleteSubString(a,c,c+1), c, "\t");
else if(g == "r")//rx[11,22,33,44,55,66,77,88,99,AA,BB,CC,DD,EE,FF]
{
g = "";
if(d+(e = (integer)("0x"+llGetSubString(b,d+1,d+1)) * 2)+1 >= (f = llStringLength(b)))
e = (f - d - 2) & -2;
if(f = e)//this may look like a mistake, it's not
{
do
g = "%"+llGetSubString(b,d + e,d + e + 1) + g;
while((e-=2) > 0);
}
a = llInsertString(llDeleteSubString(a,c, c + 2 + f),c, g = llUnescapeURL(g));
c += llStringLength(g);//add to c so we don't accidentily unescape result
}
else if(g == "u" || (e = (g == "U")))// \uXXXX or \UXXXXXXXX
{
a = llDeleteSubString(a, c, c + 5 + e *= 4);
if(0 < e = (integer)("0x"+llGetSubString(b,d +1, d +4 + e)))
{
if (e >= 0x4000000)
f = 5;
else if (e >= 0x200000)
f = 4;
else if (e >= 0x10000)
f = 3;
else if (e >= 0x800)
f = 2;
else if (e >= 0x80)
f = 1;
g = "%" + byte2hex((e >> (6 * f)) | ((0x3F80 >> f) * (0 != f)));
while(f)
g += "%" + byte2hex((((e >> (6 * --f)) | 0x80) & 0xBF));
a = llInsertString(a, c++, llUnescapeURL(g));
}
}
b = llDeleteSubString(a,0,c);
}
return a;
}

string flo(float a)
{
string b = (string)a;
while(llGetSubString(b,-1,-1) == "0")
b=llDeleteSubString(b,-1,-1);
if(llGetSubString(b,-1,-1) == ".")
return llDeleteSubString(b,-1,-1);
if(llGetSubString(b,(a<0),(a<0)+1)=="0.")
return llDeleteSubString(b,(a<0),(a<0));
return b;
}

string vec(vector a)
{
if(a == ZERO_VECTOR) return "";
return "<"+flo(a.x)+","+flo(a.y)+","+flo(a.z)+">";
}

string rot(rotation a)
{
if(a == ZERO_ROTATION) return "";
return "<"+flo(a.x)+","+flo(a.y)+","+flo(a.z)+","+flo(a.s)+">";
}

string int(integer a)
{
if(a == 0) return "";
return (string)a;
}

string TightListDump(list a, string b)
{
string c = (string)a;
if(llStringLength(b)==1)
if(llSubStringIndex(c,b) == -1)
jump end;
integer d = -llStringLength(b += "|\\/?!@#$%^&*()_=:;~{}[],\n\" qQxXzZ");
while(1+llSubStringIndex(c,llGetSubString(b,d,d)) && d)
++d;
b = llGetSubString(b,d,d);
@end;
c = "";//save memory
return b + llDumpList2String(a, b);
}

list lis(list a)
{
integer b = -llGetListLength(a) - 1;
list c;
integer d;
while(++b)
{
if((d = llGetListEntryType(a,b)) == TYPE_FLOAT)
{
float e = llList2Float(a,b);
if(e != 0.0)
c += flo(e);
else
c += "";
}
else if(d == TYPE_VECTOR)
c += vec(llList2Vector(a,b));
else if(d == TYPE_ROTATION)
c += rot(llList2Rot(a,b));
else if(d == TYPE_INTEGER)
c += int(llList2Integer(a,b));
else
c += llList2String(a,b);
}
return c;
}

string hex(integer x)
{
integer x0 = x & 0xF;
string res = llGetSubString(hexc, x0, x0);
x = (x >> 4) & 0x0FFFFFFF; //otherwise we get infinite loop on negatives.
while( x != 0 )
{
x0 = x & 0xF;
res = llGetSubString(hexc, x0, x0) + res;
x = x >> 4;
}
return res;
}
//}
add(list value, integer mask)
{
if(llStringLength(llDumpList2String(header+params+value," ")) > 240)
{
store();
mode = mask | (mode & 0x101);
}
else
mode = mode | mask;
params += value;
}

store()
{
integer a;
integer b = 0;
if(llList2String(params,-1) != sep)//it's possible we might be on a boarder already.
params += mode;
else
params = llDeleteSubList(params,-1,-1);
// llOwnerSay(TightListDump(params,""));
@loop;
if(1 + (a = b))
if(b = 1 + llListFindList(llList2List(params + [sep],a + 1,200),[sep]))
{
b += a;
// llOwnerSay(llList2CSV([a,b] + llList2List(params,b - 1, b)));
params = llListInsertList(llDeleteSubList(params,b - 1, b),[hex(llList2Integer(params, b - 1) | (!a << 5))], a);
jump loop;
}
params = [TightListDump(params,"")];
// llOwnerSay(llList2CSV(params));
commands += params;
params = [sep];
if(mode & 0x100)
params += cface;
recycle_mask = recycle_mask | mode;
}

break()
{
if(mode & 0xFFFffFB0)
{
params += mode;
recycle_mask = recycle_mask | mode;
mode = 1;
params += sep;
}
}
//{
theFace(integer f)
{
if (multiplefaces)
add([f], 0x100);

if (llList2Integer(llGetPrimitiveParams([PRIM_FULLBRIGHT, f]), 0))
mode = mode | 0x10;

if (llGetTexture(f) != "5748decc-f629-461c-9a36-a35a221fe21f")
add([llGetTexture(f)], 0x200);

vector t_v = llGetTextureScale(f);
if (t_v != <1.0, 1.0, 0.0>)
add([vec(t_v)], 0x400);

t_v = llGetTextureOffset(f);
if (t_v != ZERO_VECTOR)
add([vec(t_v)], 0x800);
else
mode = mode | 0x2;

float t_f = llGetTextureRot(f);
if (t_f != 0.0)
add([flo(t_f)], 0x1000);
else
mode = mode | 0x2;


t_v = llGetColor(f);
if (t_v != <1.0, 1.0, 1.0>)
add([vec(t_v)], 0x2000);
else
mode = mode | 0x4;

t_f = llGetAlpha(f);
if (f != 1.0)
add([flo(t_f)], 0x4000);
else
mode = mode | 0x4;

list t_l = llGetPrimitiveParams([PRIM_BUMP_SHINY, f]);
integer t_i = llList2Integer(t_l, 0);
if (t_i != PRIM_SHINY_NONE)
add([t_i], 0x8000);
else
mode = mode | 0x8;

t_i = llList2Integer(t_l, 1);
if (t_i != PRIM_BUMP_NONE)
add([t_i], 0x10000);
else
mode = mode | 0x8;
}

checkFaces()
{
integer max = llGetNumberOfSides();
multiplefaces = FALSE;
string texture = llGetTexture(0);
vector color = llGetColor(0);
float alpha = llGetAlpha(0);
list fullbrights = llGetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES]);
integer fullbright = llList2Integer(fullbrights, 0);
list bump_shiny = llGetPrimitiveParams([PRIM_BUMP_SHINY, ALL_SIDES]);
integer bump = llList2Integer(bump_shiny,1);
integer shiny = llList2Integer(bump_shiny,0);

integer i = 1;
for (; i<max && !multiplefaces; ++i)
{
if (llGetTexture(i) != texture)
multiplefaces = TRUE;

if (llGetColor(i) != color)
multiplefaces = TRUE;

if (llGetAlpha(i) != alpha)
multiplefaces = TRUE;

if (llList2Integer(fullbrights, i) != fullbright)
multiplefaces = TRUE;

if (llList2Integer(bump_shiny, i* 2 + 1) != bump)
multiplefaces = TRUE;

if (llList2Integer(bump_shiny, i* 2) != shiny)
multiplefaces = TRUE;
}
if(!multiplefaces)
{
mode = mode | 0x1;
cface = ALL_SIDES;
} else {
cface = 0;
}

theFace(0);
}

checkPrim()
{
list type = llGetPrimitiveParams([PRIM_TYPE]);

if (llList2Integer(type, 0) == 0)
{
if (llList2Integer(type, 1) == 0)
{
if (llList2Vector(type, 2) == <0.0, 1.0, 0.0>)
{
if (llList2Float(type, 3) == 0.0)
{
if (llList2Vector(type, 4) == ZERO_VECTOR)
{
if (llList2Vector(type, 5) == <1.0, 1.0, 0.0>)
{
if (llList2Vector(type, 6) == ZERO_VECTOR)
{
return;
}
}
}
}
}
}
}
add(lis(type), 0x4000000);
}
//}
string sep;

integer mode;

integer cface;
integer multiplefaces;

list params;
list header;

integer recycle_mask;

list commands;

string hexc="0123456789ABCDEF";

default
{
state_entry()
{
llSetText(Unescape(llSetText_text), llSetText_color, llSetText_alpha);
llTargetOmega(llTargetOmega_axis, llTargetOmega_spinrate, llTargetOmega_gain);
llParticleSystem(llParticleSystem_list);
llSetTextureAnim(llSetTextureAnim_mode, llSetTextureAnim_face, llSetTextureAnim_x_frames, llSetTextureAnim_y_frames,
llSetTextureAnim_start_frame,llSetTextureAnim_end_frame,llSetTextureAnim_rate);

llOwnerSay("--------------------------------------");

sep = llUnescapeURL("%01");
// sep = "~~~~";

if((llGetObjectPermMask(MASK_OWNER) & 0x0000E000) != 0x0000E000)
{//If you remove this check the script will not function any better.
//Many of the functions used to gather information do the same permissions check internaly
//Those functions will cause error messages and an invalid TLML stream.
//YOU HAVE BEEN WARNED.
llOwnerSay("You cannot clone an object you do not have full permission on");
return;
}

header = [llGetLinkNumber(), TLML_URL];

params = [sep];

checkFaces();// 0x100 -> 0x10000

add([vec(llGetScale())], 0x20000);
if (llGetLinkNumber() >= 2)
add([vec(llGetLocalPos())], 0x40000);

rotation local = llGetLocalRot();
if (local != ZERO_ROTATION)
add([rot(llGetLocalRot())], 0x100000);


if(llSetText_text != "")
add([llSetText_text], 0x800000);
if(llSetText_color != <1.0,1.0,1.0> || llSetText_alpha != 1.0)
add([vec(llSetText_color),flo(llSetText_alpha)], 0x1000000);

if(llTargetOmega_axis != ZERO_VECTOR || llTargetOmega_spinrate != 0.0 | llTargetOmega_gain != 0.0)
add([vec(llTargetOmega_axis),flo(llTargetOmega_spinrate),flo(llTargetOmega_gain)], 0x2000000);

checkPrim();//0x4000000

if(llParticleSystem_list != [])
add([TightListDump(lis(llParticleSystem_list),"*")], 0x10000000);

integer t;
if(multiplefaces)
{
t = llGetNumberOfSides();
cface = 1;
while(cface < t)
{
break();
theFace(cface);
++cface;
}
}
if(llSetTextureAnim_mode)
{
break();
add([llSetTextureAnim_face, llSetTextureAnim_mode, llSetTextureAnim_x_frames, llSetTextureAnim_y_frames,
llSetTextureAnim_start_frame,llSetTextureAnim_end_frame,llSetTextureAnim_rate], 0x200100);
}
store();
t = llGetListLength(commands);

integer c;
string d;
string e;
string f;
if(t > 1)
d = hex(recycle_mask);

// llOwnerSay("-----------------------");
while(c < t)
{
e = llDumpList2String(llParseString2List(llList2String(commands,c),[sep],[]),d);
f = TightListDump(header,llGetSubString(e,0,0));
llOwnerSay("T"+f+e);
if(++c == 1)
header = [llGetLinkNumber(), ""];
}

// llRemoveInventory(llGetScriptName());
}
}
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-14-2006 05:37
0.2.2: 2006-02-14
- add missing vector/rotation operators (0008, reported by Strife)
- fix crash when using global vectors/rotations in operations (0009, reported by Strife)
- fix crash when using -v
- fix vector.s, vector.qqq, vector.1, etc (0010)
- when a warning or error has extra lines of information, they will only be shown once
- exit status is the number of errors in the script (negative or >128 for program errors)
- added options: -# (show error numbers), -A (check error assertions)

The new command line options are for debugging/regression testing, but you can use them to ignore warning messages. Use -# to get the error number, and then add a comment like $[E12345] on the line you want to ignore that error number on. Note that when using -A, warnings are treated as errors.

I've posted Linux and Mac binaries with this one as well, please let me know if you have any problems with them.

http://w-hat.com/lslint/
1 2 3 4 5 6