Ниже перечислены действия которые нужно проделать, чтобы язык созданный на Nitra стал динамически расширяемым, т.е. как в Nemere, добавляем using (или что-то вроде того) и получаем мимическое подключение синтаксических конструкций в конкретном файле или даже в конкретной области видимости (например, в теле метода).
1. Пометить атрибутом DynamicSyntaxExtentionPoint правило в котором будет проводиться расширение.
2. В языке который должен поддерживать расширение синтаксиса нужно добавить что-то вроде:
В том же проекте реализовать обработчик:
В этом обработчике нужно разобрать (к сожалению, на довольно низком уровне) грамматику расширяющего правила и подключить соответствующую ей грамматику (дескриптор грамматики).
3. Нужно написать вот такой файл:
и скомпилировать его в отдельном проекте или в проекте где находится грамматика джейсона. Это, собственно, и есть само языковое расширение. Таких расширений может быть любое число. Получается что-то вроде немерловой синтаксической макры.
4. Далее остается только подсунуть получившуюся на шаге 1 сборку, вместе со сборкой в которой объявлена грамматика JSON-а, в параметр/свойство DynamicExtensions объекта ParseSession (с которого начинается парсинг).
В решарперовском плагине это (п. 4) будет делаться автоматически. Достаточно будет только добавить ссылку на сборку содержащую тировские расширения. Естественно, что пункты 1-3 должны быть проделаны авторами языка.
1. Пометить атрибутом DynamicSyntaxExtentionPoint правило в котором будет проводиться расширение.
[DynamicSyntaxExtentionPoint]
syntax NamespaceMemberDeclaration
{
| Namespace = "namespace" sm NamespaceName outline_begin_before nl "{" inl NamespaceMemberDeclaration* d "}" ";"? nl outline_end_before;
| Type = TypeDeclaration;
| Alias = "using"sm Name sm "=" sm QualifiedName ";" nl;
| Open = "using"sm QualifiedName ";" nl;
| ExternAliasDirective = "extern" sm "alias" sm Name ";"nl;
| GlobalAttributeSection
}
2. В языке который должен поддерживать расширение синтаксиса нужно добавить что-то вроде:
extend syntax NamespaceMemberDeclaration
{
| [DynamicSyntaxExtender] UsingSyntax = "using" sm "syntax" sm QualifiedName ";" nl;
}
В том же проекте реализовать обработчик:
UsingSyntaxHandler(rawTreePtr : int, startPos : int, endPos : int, ruleParser : PrefixRuleParser, parseResult : IParseResult, grammar : CompositeGrammar) : CompositeGrammar
{
def walker = UsingImportDeclarationWalker();
walker.WalkPrefix(rawTreePtr, startPos, endPos, ruleParser, parseResult, 0);
def descriptor = (parseResult :> ParseResult).TryGetDynamicSyntaxExtension(walker.Name.ToString());
if (descriptor != null)
grammar.Add(descriptor);
else
grammar
}
В этом обработчике нужно разобрать (к сожалению, на довольно низком уровне) грамматику расширяющего правила и подключить соответствующую ей грамматику (дескриптор грамматики).
3. Нужно написать вот такой файл:
namespace CSharpJson
{
syntax module Extention
{
using Whitespaces;
using CSharp.Expressions;
using Nitra.Tests.JsonParser;
extend syntax CSharp.Expressions.Expression
{
| Json = "json" ":" Nitra.Tests.JsonParser.Value; // расширяем выражение C# JSON-ом
}
extend syntax Nitra.Tests.JsonParser.Value
{
| CSharpExpr = "cs" ":" CSharp.Expressions.Expression; // расширяем значение JSON-а выражениями C#-а
}
}
}
и скомпилировать его в отдельном проекте или в проекте где находится грамматика джейсона. Это, собственно, и есть само языковое расширение. Таких расширений может быть любое число. Получается что-то вроде немерловой синтаксической макры.
4. Далее остается только подсунуть получившуюся на шаге 1 сборку, вместе со сборкой в которой объявлена грамматика JSON-а, в параметр/свойство DynamicExtensions объекта ParseSession (с которого начинается парсинг).
В решарперовском плагине это (п. 4) будет делаться автоматически. Достаточно будет только добавить ссылку на сборку содержащую тировские расширения. Естественно, что пункты 1-3 должны быть проделаны авторами языка.