Здравствуйте!
Я тут пытаюсь написать hrc-правила для подсветки компактного синтаксиса
Relax NG, и что-то как-то уж очень трудно дело идет. Я заранее прошу прощения за некоторую занудность описания, но я привык писать так, чтобы по возможности исключать ошибочное толкование.
Проблем, которые я могу сформулировать, на данный момент две:
- в языке (в relax ng) отсутствует обозначение концов строк, и я просто не знаю, что указывать в атрибуте end оператора block; пока что остановился на выражении /\M(\s*)\S/ , т.е.блок заканчивается на любом непробельном символе (при этом и этот символ, и предваряющие его пробелы, если есть, оставляются для последующего анализа);
- после возврата из блока схема повторяется заново, что приводит к подсветке синтаксически неверных конструкций типа namespace ns ns (повтор идентификатора ns) как верных.
Вот пример фрагмента текста (он искусственный, синтаксису языка не соответствует, но пока и с этим проблемы).
Вариант 1
Вариант 2
Ввиду того, что Colorer работает с отдельными строками, а идентификатор пространства имен не обязан находиться на той же строке, что и ключевое слово namespace, после распознавания namespace я переключаю контекст:
<scheme name="decl">
<block start="/(^|\s+)(namespace)(\s*$\M|\M\s+)/" end="/\M(\s*)\S/"
region02="keyword" scheme="decl.namespace"/>
</scheme>
Во вложенной схеме я разбираю идентификатор пространства имен (сущность NCName взята из XML):
<scheme name="decl.namespace">
<block start="/(^|\s+)(%NCName;)(\s*$\M|\M\s*)/" end="/\M(\s*)\S/"
region02="identifier"
scheme="decl.namespace.identifier"/>
</scheme>
Схема decl.namespace.identifier на данный момент пустая. По идее в ней должна разбираться оставшаяся часть конструкции namespace, но пока что я решил остановиться на более простой задаче (однако с прицелом на реализацию подсветки всего синтаксиса).
Топовая схема не содержит ничего интересного:
<scheme name="relaxng-compact">
<inherit scheme="documentation"/>
<inherit scheme="comment"/>
<inherit scheme="decl"/>
<block start="/\M(^|\s+)\S/" end="/$never^/" scheme="invalidContent"/>
</scheme>
Схемы documentation и comment разбирают комментарии, схема invalidContent подсвечивает неразобранные остатки файла как ошибку.
Вышеизложенного должно быть достаточно для понимания, как я действую, но на всякий случай я прикреплю к сообщению находящийся в разработке вариант правил подсветки. Прошу сильно за него не бить - он, разумеется, еще очень и очень сырой.
Теперь вопросы:
- после удачного распознавания идентификатора пространства имен в схеме decl.namespace происходит возврат к началу схемы; поэтому, если я пишу namespace ns1 ns2, то ns2 воспринимается тем же блоком как еще один идентификатор (и когда после идентификатора появится знак равно и uri пространства имен, то будет происходить повторный разбор всей конструкции);
вопрос: каким образом сделать так, чтобы после удачного выполнения блока схемы происходил возврат в родительскую схему (в схему, вызвавшую данную), а не возврат к началу схемы? если для этих целей использовать "безвозвратные" переключения схем, т.е. оператором блок с заведомо невыполнимым регулярным выражением, то такой подход будет есть ресурсы и замедлять работу? будет ли Colorer проверять все эти условия? или будет проверять лишь первое из них? будет ли на самом деле осуществляться рекурсия на программном уровне, или в таком случае будет происходить лишь замена контекста?
- каким еще образом можно организовать переключение схемы "навсегда", без возврата в родительскую схему? я для этого использую end="/$never^/" в операторе block, но подозреваю, что такой подход кушает ресурсы и замедляет работу Colorer'а;
необходимость переключения схемы возникает, т.к. верхний уровень синтаксиса Relax NG описывается как
topLevel | ::= | decl* (pattern | grammarContent*) |
т.е. сначала определения пространств имен и типов данных (decl), а потом паттерны и словарь; во второй части определения пространств имен недопустимы