RSDN Wiki [Nitra] Динамическое расширение синтаксиса
Loading…
 
Loading…
 
39(2)
Ниже перечислены действия которые нужно проделать, чтобы язык созданный на Nitra стал динамически расширяемым, т.е. как в Nemere, добавляем using (или что-то вроде того) и получаем мимическое подключение синтаксических конструкций в конкретном файле или даже в конкретной области видимости (например, в теле метода).

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 должны быть проделаны авторами языка.
39(2)