Skip to content

Incorrect push/pop order when combining meta scopes, content scopes and pushing multiple things #51

Closed
@trishume

Description

@trishume

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions