0

Language definition causing hang on load

Shane Liesegang 5 years ago • updated 5 years ago 12

(I also posted this in the forums; if such duplication is bad form, please let me know which to delete.)


I'm using this language definition for Papyrus (the scripting language for Skyrim). It's worked fine for the last couple years, but at some point (I couldn't tell you when) it started choking on large files.

For instance, when I load this Activator script (a trivial file that just contains the required script header), it processes fine. But when I load up Actor.psc, a larger script with lots of functions, it hangs on the loading progress bar and never renders. Until I reboot Sublime Text, any attempt to load any other Papyrus script will also hang.

Without the language definition in place, all files open just fine. This definition worked well before, so I'm not sure what's changed in the underlying systems. I know it contains a big regex for the built-in functions towards the bottom, but that hasn't caused issues in the past.

I've also experienced ST hanging when loading a syntax definition while I was developing one on my own.


I could sum it down to the \G, \A and \Z matches. If you define a start or end pattern that only consists of one of these anchors ST will hang. You need to define at least one additional character (like ".") or use a lookahead/-behind if you don't want the character to be consumed. (e.g. "\G(?=.)")


Could be a completely different issue, though.

Thanks for the help -- through a painstaking commenting/uncommenting, I've narrowed it down to this portion towards the bottom of the file:


<key>include</key>
<string>$self</string>


If I comment out the part where I include $self, everything works fine. So I guess the question is, is there a better way to pass function parameters through syntax processing? I'm guessing this enters some kind of infinite loop, but this wasn't the case in earlier builds.

How do you want to pass "function parameters"? And what parameters?

Usually a self-include should not result in an infinite loop. It is likely that your regex you are using does not consume any character at all (it matches, but it does not match any character). Thus it would be called again and again without moving forward in the file. An example regex would be ".*?". A self-inclusion of this pattern would result in an infinite loop.

If you take a look at the language definition, towards the bottom is a repository where I deal with function parameters, which gets referenced from the area which matches function declarations. So in the following line:

Function DoTheThing(int numberOne, float numberTwo, Actor target)

The parser would recognize that it's a function declaration, then let the "params" entry in the repository parse the bit in parentheses so that the types there would pick up proper syntax highlighting (with "int" and "float" as base types and "Actor" as a class). So it passes them back through with a self include.

As far as I could tell (and I set this definition up a while ago and haven't looked at it since, so I may be forgetting the logic that brought me here), this seemed like the best way of handling it.

So, yeah, sorry I wasn't clear. I'm not trying to pass function parameters into the syntax processing, I'm wanting to properly process the syntax of function parameters. :-)

Also... it appears to work fine until it's being run over a file with more than 160 functions in it. Without fail, it will hang the moment the last parenthesis is typed on the declaration of the 161st function. Hmmmm.

That behaviour is really weird.

Well, back to your syntax definition. The part you mentioned seems to be
		<key>params</key>
		<dict>
			<key>begin</key>
			<string>\b</string>
			<key>end</key>
			<string>\)</string>
			<key>endCaptures</key>
			<dict>
				<key>1</key>
				<dict>
					<key>name</key>
					<string>variable.parameter.papyrus</string>
				</dict>
			</dict>
			<key>patterns</key>
			<array>
				<dict>
					<key>include</key>
					<string>$self</string>
				</dict>
			</array>
		</dict>

 However, when you look at it it does not seem to do what you intend it to (what would you want to achieve by self-including this pattern?).

Furthermore, it uses an anchor only ("\b"), which is what I mentioned in my first comment.

And the "endCaptures": 1 will never be defined because your "end" regexp does not define any matching group.


Seems like your file got corrupted your something, this makes absolutely no sense.

Heh. It may have gotten "corrupted" by my rambling experiments not knowing what I was doing. :-)

I was also suspicious of the "\b" after your first comment, but it didn't appear to be the culprit here, or at least removing it didn't stop the hangs.

The goal with a self include was to run everything in the pattern through the entire language definition again, so that parameters could be properly colored. If I comment out the contents of that dictionary, function parameters are treated as plain-text. Basically I want to to treat anything in the parentheses of a function declaration as it's own mini-document and run the normal language rules over it. This accomplished that goal, but clearly in some sub-standard way that began choking when something changed in Sublime's internals.


 Managed to at least resolve my own problem, but I think there still might be some bugs in the syntax parser that were not present in previous builds.


Basically, I set my function parameter matcher to stop trying to match at a close parenthesis rather than end of line. Interestingly, it would consistently hang at the 161st function declared in the file. I'm not sure what's magical about that number (it's not a power of two, for instance), but that definitely proved to be the border.


Thanks to FichteFoll for being an excellent sounding board and pointing me in the right direction!

Try this one.

I can also have 416+ lines of "function (type variable, othertype var2)" in a buffer, they are highlighted correctly.

Also highlights invalid characters as "invalid.illegal".

Hey, this is pretty good. Thanks so much for your help! I notice the invalid highlighting doesn't play nicely with default values for parameters, so something like:

Function ModFavorPoints(int iFavorPoints = 1)

Can throw off the highlight for the rest of the file. Any thoughts on that? FWIW, I'm using this file as my test case.

 

Phew, I got that shit working. Was pretty hard because the syntax definition hierarchy did not behave as I wanted it to so I had to use a workaround. However, unless you do not define constants like "none" or "false" as variable identifier or type you should be safe. ;) At least your example file works as expected. If there are other things besides these constants (including numbers) that can be defined as default value, you will know how to implement that.

 

Still the same link, I edited it.

Many thanks and a thousand units of gratitude to you, good sir. I thank you on the behalf of the dev team. :-)