Description
This is the bug that is causing at least some, probably most to all of the ASP tests to fail (cc @keith-hall).
The model of the parser outputting only the pushes and pops doesn't hold up to well in some cases. @keith-hall fixed the case of the weird behaviour of set
, but I found another.
Consider the following section of the ASP syntax:
class_definitions:
- match: '\b(?i:Class)\s'
scope: storage.type.asp
push: [inside_class, class_name]
class_name:
- meta_scope: meta.class.asp meta.class.identifier.asp
# ...
- match: '{{identifier}}'
scope: entity.name.class.asp
pop: true
# ...
inside_class:
- meta_content_scope: meta.class.asp meta.class.body.asp
Sublime Text passes the following test:
' SYNTAX TEST "Packages/ASP/ASP.sublime-syntax"
Class TestClass2 Public Sub TestSub () Response.Write("wow") End Sub End Class
'^^^^^ meta.class.asp meta.class.identifier.asp storage.type.asp
' ^ meta.class.asp meta.class.body.asp meta.class.asp meta.class.identifier.asp
' ^ meta.class.asp meta.class.body.asp
Notice how when the meta_content_scope
of inside_class
is introduced after Class
, it is introduced under meta.class.asp meta.class.identifier.asp
.
syntect
does not do this. It pushes the inside_class
meta_content_scope
on top, but then after TestClass2
when it pops the class_name
context it pops 2 scopes, thinking it is popping the meta_scope
of class_name
, but actually the inside_class
scopes are on top of the stack.
I see two ways of approaching this:
- Make pushes like
set
is in Keith's set branch where they pop the early meta scopes and then re-apply them in the right order. - Make a breaking change to the API and scrap the idea of the parser outputting operations. Have stacks be linked lists instead of vectors, and have the parser output regions of text with a scope stack, where the scope stacks share tails. Unfortunately this would require a bunch of reference counting. It may be faster, it may be slower, I'm not sure. It would also be a bunch of work.
I'm inclined to take the first route. My worry is that if done simply it will lead to a bunch of redundant popping and pushing the same thing again in the case when only one item is pushed. It's probably a good idea to have a fast path for that case, although it would probably require a bunch more code.