Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

lslint - offline code checker for LSL

Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-15-2006 04:30
Could you make it so that the error ignoring code can ignore warnings without having to use the "-A" switch (then i can pretend i have writen nice code, "see no warning ^_^";). BTW great work, this has saved me alot of time.

Now if it could only handle C style preprocessing...
Example:
CODE

default
{
state_entry()
{
integer e = llGetAttached();
integer f;
if(f = e)//monkey$[E20002]monkey
{
llOwnerSay("hello");
}
}
}
_____________________
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-15-2006 04:43
things get interesting when you use us $[Exxxx] on a line without an error on it.
use the "-A" switch to convert the assertions to errors.
CODE

default
{
state_entry()
{
integer e = llGetAttached();
integer f;//$[E20002]
if(f = e)$[E20002]
{
llOwnerSay("hello");
}
}
}
_____________________
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-15-2006 04:53
wrong error code, right idea. top notch detecting this, i wasn't expecting it.
CODE

default{state_entry(){
vector llTargetOmega_axis = ZERO_VECTOR;
float llTargetOmega_spinrate = 0.0;
float llTargetOmega_gain = 0.0;

if((llTargetOmega_axis != ZERO_VECTOR) || (llTargetOmega_spinrate != 0.0) || (llTargetOmega_gain != 0.0))//returns E20011 should be E20012
llOwnerSay("blah");
}}
_____________________
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-15-2006 05:13
From: Strife Onizuka
Could you make it so that the error ignoring code can ignore warnings without having to use the "-A" switch.
I will probably add a separate switch to just ignore matching assertions without upgrading warnings or generating errors for ones that don't match, and others to control which warnings are generated. I'm also thinking about handling the "if (x=y)" thing gcc's way: make the warning "suggest parentheses around assignment used as truth value" and ignore "if ((x=y))". That way it's not a bother to silence the warning, and it's clearer to other people reading the code that you might have done it on purpose. (and you don't have to litter your code with cryptic comments)

The purpose of the assertions and the -A switch is so that I can automatically run a bunch of test scripts and ensure that nothing has snuck by me, and that the results are consistent across platforms.

From: Strife Onizuka
Now if it could only handle C style preprocessing...
I thought about this, but it seems kind of like a waste of effort since you can easily download a free compiler and use its preprocessor.

I have been playing with the idea of an optimizing LSL->LSL compiler with includes, constants, inline functions, and things like that though.

edit:
From: Strife Onizuka
wrong error code, right idea. top notch detecting this, i wasn't expecting it.
Fixed in the next version. ZERO_VECTOR (and ZERO_ROTATION) weren't initializing their values correctly when used in expressions. Thanks for the kind words and all the bug reports.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-15-2006 19:15
From: Masakazu Kojima

I have been playing with the idea of an optimizing LSL->LSL compiler with includes, constants, inline functions, and things like that though.


I know alot about how LSL works. I can give you tips on what programing methods will result in faster scripts.

like
CODE

while(1)
{}
//should be replaced with
@a;//saves 6 bytes, faster
{}
jump a;

//------
vector c = <0,0,1>;
//should be replaced with
vector c = <0.0,0.0,1.0>; //saves 6 bytes, faster

//------
if(a == ZERO_VECTOR)
{}else if(b == ZERO_VECTOR)
{}else if(c == ZERO_VECTOR)
//should be replaced with
vector zv = ZERO_VECTOR;//saves 7 bytes, with 8 bytes for each aditional refrence to zv
//also using zv instead of ZERO_VECTOR will cause your code to run faster.
if(a == zv)
{}else if(b == zv)
{}else if(c == zv)


EDIT: just to clear up any fears of a memory leak. The result of llGetFreeMemory stabilizes after a couple iterations.
CODE

default
{
state_entry()
{
@a;
llOwnerSay((string)llGetFreeMemory());
string b = "blahblahblahblah";
jump a;
}
}
_____________________
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-15-2006 20:44
Strife: You scare me sometimes. And on that note, how about a thread or a notecard available in world or somewhere that has a giant list of these types of code optimizations so we can start coding like that be default? I know I wouldn't have thought of setting a varible to ZERO_VECTOR for speed and space saving. It would definatly be an aid until we get a optimising LSL -> LSL compiler.

Even after we get mono, these types of things should still make it run faster and save space compared to not using them correct? Even with the speed boost (and I've heard more memory too) it still doesn't hurt to optimize it further. Bloat is bad even if it still works.
_____________________
^-^

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.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-15-2006 21:07
A good compiler CLI compiler will handle optimization as should the CLR IMHO. Though it cannot hurt to give it a jump start.

Alot of ways to make things run faster result in strange side-effects or very unreadable code.

A tip:
don't call a function more then once if you don't have to, store the results in a temp variable instead. This will be faster and save you memory. Function calls are *expensive*
_____________________
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
Logan Bauer
Inept Adept
Join date: 13 Jun 2004
Posts: 2,237
02-16-2006 09:49
From: Deneria Sholokhov
This is excellent, works well with SlickEdit too. I have just become that much more unproductive at my real job *laughs*


My sentiments exactly. :)
Masakazu I cannot thank you enough for this. :)
Kayla Stonecutter
Scripting Oncalupen
Join date: 9 Sep 2005
Posts: 224
02-17-2006 21:29
Great work on this, very helpful. Love the 'declared but never used' warning. :)

CODE
default
{
state_entry()
{
llSetPayPrice(PAY_HIDE, [10, PAY_DEFAULT, PAY_HIDE, PAY_HIDE]);
}
}

ERROR:: ( 5, 23): `PAY_HIDE' is undeclared.
ERROR:: ( 5, 38): `PAY_DEFAULT' is undeclared.

Also, could lslint give a warning if used in a state without a money() event handler since it has no effect?
_____________________
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
02-18-2006 07:51
0.2.3: 2006-02-18
- added error when exceeding SL's parser's max token stack depth (150)
- fixed ZERO_VECTOR and ZERO_ROTATION expressions (0011, reported by Strife)
- added PAY_HIDE, PAY_DEFAULT, DATA_SIM_RATING constants (0012, reported by Kayla Stonecutter)
- changed to gcc-style if(a=x) warnings; if((a=x)) doesn't warn.

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

Is anyone using the Mac or Linux versions? I've seen them downloaded, but nobody's said anything. I'd really like to hear if they are working, since the only machines I have to test them on are the ones I compiled them on. I am bz2'ing the Mac version now since UPX doesn't work on Macs and the binaries are huge, but if this gives anyone trouble I can switch to another compression format.

From: Kayla Stonecutter
Also, could lslint give a warning if [llSetPayPrice()] used in a state without a money() event handler since it has no effect?
That is an awesome idea.

It could also warn about llSetTimer() in a script with no timer() event, llListen() in a state with no listen(), llGetNotecardLine() and friends with no dataserver(), llOpenRemoteDataChannel() with no remote_data(), and probably lots of others. Maybe even things like using llResetTime() without ever using llGetTime() or llGetAndResetTime() afterward. It could even warn about them when they're buried in functions, and skip some if you eventually change into a state that handles them.

I am making some internal changes for 0.3 that will make it easier to track constants and follow code paths, so I will probably add them to that.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-18-2006 12:42
From: Masakazu Kojima

It could also warn about llSetTimer() in a script with no timer() event...


A warning about llSetTimerEvent() not being zero'ed on state change would probably be a good thing in multi-state scripts. Thread
_____________________
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
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
02-25-2006 21:25
A little bit of oddness going on with one of the warnings. The script below returns...

WARN:: ( 12, 7): condition is always true

Line 12 is the "if (count == 0)" line. Seems like it's assuming the result of llList2Integer will always be zero. I've also seen "condition is always false" raised as a result of the same thing.

CODE
default {
state_entry() {
list lst = [123, 456];

integer count = 0;
integer value = llList2Integer(lst, 0);

if (value != 0) {
count++;
}

if (count == 0) {
llOwnerSay((string)value);
}
}
}
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
02-26-2006 04:00
From: Masakazu Kojima
Is anyone using the Mac or Linux versions? I've seen them downloaded, but nobody's said anything.
How about source? They'd be smaller, even without compression, and Strife would have all your bugs fixed overnight.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
02-26-2006 07:19
Oh btw the compiler doesn't seem to be catching
while(a = b)
so i suspect its also not going to catch
for(;a=b;)
like it does with
if(a=b)
_____________________
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
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
02-26-2006 14:31
From: Masakazu Kojima
It could also warn about ... llGetNotecardLine() and friends with no dataserver(), llOpenRemoteDataChannel() with no remote_data(),


Dataserver triggers an event on the prim, so other scripts in the prim could receive the information. I believe remote_data probably does the same thing, but I don't have a server to test this with.
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
02-26-2006 15:36
From: Keknehv Psaltery
I believe remote_data probably does the same thing, but I don't have a server to test this with.


Nope, remote_data is triggered on a per-script basis (the channel ID refers to the script specifically). You could have a warning trigger if llSensor is called without either a no_sensor or sensor event (the script would need at least one). The same applies to llTarget/llRotTarget and at_target/not_at_target and at_rot_target/not_at_rot_target, at least one of their associated events should be declared, or a warning issued.
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Kayla Stonecutter
Scripting Oncalupen
Join date: 9 Sep 2005
Posts: 224
03-01-2006 04:17
From: Kermitt Quirk
A little bit of oddness going on with one of the warnings. The script below returns...

WARN:: ( 12, 7): condition is always true

Line 12 is the "if (count == 0)" line. Seems like it's assuming the result of llList2Integer will always be zero. I've also seen "condition is always false" raised as a result of the same thing.

Ran across this in one of my scripts and decided to mess around with it; here's what I found out:
CODE
list testlist = [0.3, 0.2, 0.5];
integer x;
integer test = 0;
float f;
default
{
state_entry()
{
for(x = 0; x < 3; ++x)
{
f = llList2Float(testlist, x);
if((f >= 0) && (f <= 1))
{
++test;
}
}
if(test == 3) llOwnerSay("True");
else llOwnerSay("False");
}
}
returns:

WARN:: ( 17, 12): Condition is always false.

Which is the if(test == 3). But inworld the object says "True" as expected. However, if I don't specify test = 0 in the decleration as such:
CODE
list testlist = [0.3, 0.2, 0.5];
integer x;
integer test;
float f;
default
{
state_entry()
{
for(x = 0; x < 3; ++x)
{
f = llList2Float(testlist, x);
if((f >= 0) && (f <= 1))
{
++test;
}
}
if(test == 3) llOwnerSay("True");
else llOwnerSay("False");
}
}
There is no error :P
_____________________
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
03-01-2006 05:03
It is not counting ++/-- as an assignment when it looks for constants, so if you never assign to a variable normally, it (incorrectly) assumes that its value never changes. This is fixed in 0.3, which is much better at constant propagation in general (using SSA form) and lays the foundation for an optimizing compiler. I will release it in about a week.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
03-01-2006 20:39
ERROR:: (672, 41): Invalid operator: integer + float.

bogus error. LSL supports this.
_____________________
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
03-07-2006 20:33
Another bug, lslint thinks this is valid, it's not. "<<" only works on integer << integer
CODE

mask_b = mask_b << (5 - move_a.s);
_____________________
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
03-08-2006 13:00
0.2.4: 2006-03-08
- fixed ++/-- not counted as assignment
- fixed integer - float and integer + float

http://w-hat.com/lslint/
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
03-09-2006 04:11
Wow! This is fantastic Masakazu !!!

Seems I'm last to discover this has been out :(, but glad I did. I'll start using it immediately with SciTE.

Thanks for making it available
Chris Widget
Widget Isles @ the Edge!
Join date: 22 Jan 2006
Posts: 67
03-09-2006 08:27
This is a great tool thanks so much. I am currently testing the Windows version but I will load it up tonight on my shiny new duo core imac and let you know if there are any issues with that distribution. Thanks again !

-----
Chris Widget
"testing another anti-productivity tool"
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
03-10-2006 18:20
Masakazu,

You don't happen to know whether there is a way in SciTE to arrange it so after compiling if you double click on one of the errors in the bottom pane it could auto-highlight the line of code?

i.e. this works in SciTE when you do something that "find in files", i.e. click on one of the match lines and it opens the file and takes you to the line in quesiton

Greg
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
03-10-2006 18:38
From: Greg Hauptmann
You don't happen to know whether there is a way in SciTE to arrange it so after compiling if you double click on one of the errors in the bottom pane it could auto-highlight the line of code?
I couldn't see any way to when I played with it. The docs say "SciTE partially understands the error messages produced by Python, GCC, Visual C++, Borland C++, PHP and other tools which use the same format as one of these," so I'm guessing you can't make it understand custom error formats, but I can't say for sure.

I will add a switch in 0.3 to set the error format.
1 2 3 4 5 6