XenHat / SublimeLinter-contrib-lslint

LSL linting for Sublime Text 3
MIT License
1 stars 0 forks source link

Multi-Line strings errors out with MCPP support #9

Open XenHat opened 6 years ago

XenHat commented 6 years ago

Offending Code

default {
    state_entry() {
            llSay(0, "
              ____________________________________________________");
    }
}

Output:

ERROR:: (  5,  1): syntax error, unexpected '<', expecting $end
TOTAL:: Errors: 1  Warnings: 0 

Works properly:

default {
    state_entry() {
            llSay(0, "\n"
              +"____________________________________________________");
    }
}

My environment

@Sei-Lisa Do you believe this can be fixed?

Sei-Lisa commented 6 years ago

It surely can. I anticipated this here: https://github.com/XenHat/SublimeLinter-contrib-lslint/issues/6#issuecomment-335920264 and outlined the solution. Note that the spaces at the beginning of the line are significant, therefore the two scripts you've pasted are not equivalent. Even if they were, string concatenation takes code memory even when both strings are constant.

Both FS and LSL-PyOptimizer convert it to this prior to sending it to the preprocessor:

default {
    state_entry() {
            llSay(0, "\n              ____________________________________________________"
                                                                   );
    }
}

The next character immediately after the close quote appears in the same column as in the original script, and as many blank lines are inserted as lines were in the string; this is done to report a possible error after the string at the correct line and column.

For example, this script:

reverse_params_for_the_sake_of_it(string msg, integer channel)
{
    llSay(channel, msg);
}
default{timer(){
    reverse_params_for_the_sake_of_it("a
          b
  c", chan);
}}

is translated to this script:

reverse_params_for_the_sake_of_it(string msg, integer channel)
{
    llSay(channel, msg);
}
default{timer(){
    reverse_params_for_the_sake_of_it("a\n          b\n  c"

    , chan);
}}

This way, the error about the missing identifier chan will correctly be reported at line 8 column 7.

Note however that the license of FS is LGPL2 and my optimizer is GPL3, so just grabbing the code is probably not the best idea unless you want to change the license of yours.

XenHat commented 6 years ago

I'm not sure what Phoenix-Firestorm's license has to do with it, though. I don't work for the Firestorm Viewer Project, nor do I see what connection MCPP has to Firestorm's boost::wave-based preprocessor.

Sei-Lisa commented 6 years ago

Both boost::wave and mcpp (as well as others such as GNU cpp) are standard C and C++ preprocessors. Every C/C++ preprocessor rejects multi-line strings per the standard specification, therefore before feeding the script to any of them, the strings need to be folded into one line, otherwise the preprocessor doesn't treat them properly and it may fail in some situations.

The function that does it in LSL-PyOptimizer is PreparePreproc(), starting here: https://github.com/Sei-Lisa/LSL-PyOptimizer/blob/f492d3e291bd2e004fc03e966e854d18755a9390/main.py#L83

The corresponding code in FS is inlined, not in a separate function. Due to the problems I had with regular expressions, and to the better control that a finite automaton provides, it's implemented as the latter. It begins here:

http://hg.phoenixviewer.com/phoenix-firestorm-lgpl/file/9611841553e6/indra/newview/fslslpreproc.cpp#l1176

Now that I'm reviewing it, it seems that I misremembered. FS apparently doesn't insert spaces before the next token after the closing double quote to match the last line's column. It does insert newlines to match the line counter, though. It wouldn't be too hard to add the column to state 1; all it requires is to count columns and reset the counter after every newline.