[Nitra] Динамическое расширение синтаксиса
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.09.15 19:10
Оценка: 39 (2)
#Имя: Nitra.ExtendSyntax
Ниже перечислены действия которые нужно проделать, чтобы язык созданный на 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 должны быть проделаны авторами языка.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 07.03.2017 12:54 VladD2 . Предыдущая версия .
Re: [Nitra] Динамическое расширение
От: s22  
Дата: 29.09.15 03:05
Оценка:
Здравствуйте, VladD2, Вы писали:

А почему не сделать все точки DynamicSyntaxExtentionPoint?
Re[2]: [Nitra] Динамическое расширение
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.10.15 12:29
Оценка:
Здравствуйте, s22, Вы писали:

s22>А почему не сделать все точки DynamicSyntaxExtentionPoint?


Это замедлит парсер. Более детально Вольфхаунд может ответить. Это он писал.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Nitra] Динамическое расширение
От: _someuser  
Дата: 06.10.15 10:01
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>3. Нужно написать вот такой файл:

VD>
VD>namespace CSharpJson
VD>{
VD>  syntax module Extention
VD>  {
VD>    using Whitespaces;
VD>    using CSharp.Expressions;
VD>    using Nitra.Tests.JsonParser;

VD>    extend syntax CSharp.Expressions.Expression
VD>    {
VD>      | Json = "json" ":" Nitra.Tests.JsonParser.Value; // расширяем выражение C# JSON-ом
VD>    }

VD>    extend syntax Nitra.Tests.JsonParser.Value
VD>    {
VD>      | CSharpExpr = "cs" ":" CSharp.Expressions.Expression; // расширяем значение JSON-а выражениями C#-а
VD>    }
VD>  }
VD>}
VD>


Как дальше с этим работать? Что будет с AST шарпа? Расширять AST шарпа как то неправильно да и, похоже, невозможно по ряду причин. Маппить PT расширения на AST шарпа?
Re[2]: [Nitra] Динамическое расширение
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.10.15 14:47
Оценка:
Здравствуйте, _someuser, Вы писали:

_>Как дальше с этим работать?


Смотря что понимать под словом "работать".


_>Что будет с AST шарпа?


Тут могут быть варианты.

1. Можно просто сделать, так что в АСТ Шарпа будет вкрапления АСТ джейсона. При этом для АСТ-а джейсона придется написать типизацию и продумать интеграцию с хостовым языком.

2. Можно отмапить джейсон в Шарп нужного вида. Это будет что-то вроде упрощенной версии современных макросов Немерла. Гибкость у такого подхода существенно ниже, но зато делается это дело элементарно, так как типизацию и т.п. писать не придется (будет использована шарповая типизация).

_>Расширять AST шарпа как то неправильно да и, похоже, невозможно по ряду причин.


Почему не правильно? Найтра это поддерживает. И это может быть отличным решением. Например, если по джейсовну, в последствии, придется сгенерировать не только код на Шарпе, но и что-то еще, удобнее держать внутри шарповского выражения джейсон-расширение. Его можно будет преобразовать в конкретный код на стадии генерации кода (когда вся модель будет построена). Просто перехватываем генерацию для этого расширения или делаем более сложный паттетрн отлавливающий появление этого типа при инициализации поля (например) и генерируем нужный код.

При типизации джейсона внутри шарпа можно породить специальные символы, а ссылки на них запомнить в расширенном АСТ. По этим символам тоже можно будет генерирование код. Можно даже порождать C#-символы и тогда они будут доступны в интеллисенсе.

В общем, расширение АСТ хостового языка — это вполне себе штатная ситуация.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Nitra] Динамическое расширение
От: _someuser  
Дата: 06.10.15 17:20
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Смотря что понимать под словом "работать".


Имелось ввиду, что пока неясно, как такие ситуации будут выглядеть на уровне АСТ, и как хостовой язык должен обрабатывать расширенный АСТ. Теперь понятно. Не нашел никакого описания расширения языка в найтре на более высоком уровне, чем расширение парсера, потому и всплыл вопрос.

VD>2. Можно отмапить джейсон в Шарп нужного вида.


С этим ясно. И, как понял, уже поддерживается в текущей версии (достаточно вроде маппинг описать).

VD>1. Можно просто сделать, так что в АСТ Шарпа будет вкрапления АСТ джейсона. При этом для АСТ-а джейсона придется написать типизацию и продумать интеграцию с хостовым языком.


А такой подход пока не реализован? Не нашел возможности расширения АСТ аналогичной расширению парсера.

В целом, поигрался с текущим функционалом найтры: мощь и простота использования впечатляют
Re[4]: [Nitra] Динамическое расширение
От: VladD2 Российская Империя www.nemerle.org
Дата: 06.10.15 20:59
Оценка:
Здравствуйте, _someuser, Вы писали:

_>Имелось ввиду, что пока неясно, как такие ситуации будут выглядеть на уровне АСТ, и как хостовой язык должен обрабатывать расширенный АСТ.


Ну, дык это уже не проблема Найтры. Это проблема авторов конкретного языка. Для Шарпа, например, еще можно прикрутить нечто вроде макро-атрибутов. При связывании проверять, что атрибут — это макрос и выполнять его код, например.

_>Теперь понятно. Не нашел никакого описания расширения языка в найтре на более высоком уровне, чем расширение парсера, потому и всплыл вопрос.


А, как ты себе это видишь?

VD>>1. Можно просто сделать, так что в АСТ Шарпа будет вкрапления АСТ джейсона. При этом для АСТ-а джейсона придется написать типизацию и продумать интеграцию с хостовым языком.


_>А такой подход пока не реализован? Не нашел возможности расширения АСТ аналогичной расширению парсера.


АСТ расширяется обычным наследованием. От любого абстрактного АСТ можно породить наследника и отманить на него синтаксическое расширение.

_>В целом, поигрался с текущим функционалом найтры:


В смысле, собрал из исходников?

_>мощь и простота использования впечатляют


Спасибо за лестную оценку!
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 06.10.2015 21:00 VladD2 . Предыдущая версия .
Re[5]: [Nitra] Динамическое расширение
От: _someuser  
Дата: 07.10.15 18:41
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Здравствуйте, _someuser, Вы писали:


_>>Имелось ввиду, что пока неясно, как такие ситуации будут выглядеть на уровне АСТ, и как хостовой язык должен обрабатывать расширенный АСТ.


VD>Ну, дык это уже не проблема Найтры. Это проблема авторов конкретного языка. Для Шарпа, например, еще можно прикрутить нечто вроде макро-атрибутов. При связывании проверять, что атрибут — это макрос и выполнять его код, например.


Это то ясно. Имел ввиду, как технически с помощью найтры встраивать ast расширения в ast хостового языка. Собственно, вот и ответ:

VD>АСТ расширяется обычным наследованием. От любого абстрактного АСТ можно породить наследника и отманить на него синтаксическое расширение.


Т.е. примерно так? если у шарпа есть абстрактная ветка АСТ типа Expression, можно унаследовать от неё свою ветку, например JsonExpresion и мапить на него PT json'а. Тогда в АСТ шарпа на нужном месте будет именно JsonExpresion.

_>>Теперь понятно. Не нашел никакого описания расширения языка в найтре на более высоком уровне, чем расширение парсера, потому и всплыл вопрос.


VD>А, как ты себе это видишь?


Не совсем понял, что именно вижу?

_>>В целом, поигрался с текущим функционалом найтры:


VD>В смысле, собрал из исходников?


Да. Сделал простой dsl, чтобы разобраться что к чему в найтре. Описал синтаксис, ast, мапинг и связывание, после чего захотелось расширить dsl шарповскими выражениями. Расширение синтаксиса было элементарным, а дальше вопрос. У шарпа свой АСТ (ну, пока для выражений нет, но будет), у меня свой, что делать вообще не понятно. Теперь ясно. Вроде просто, но не сразу дошел.
Отредактировано 07.10.2015 18:44 _someuser . Предыдущая версия .
Re[6]: [Nitra] Динамическое расширение
От: VladD2 Российская Империя www.nemerle.org
Дата: 07.10.15 19:07
Оценка:
Здравствуйте, _someuser, Вы писали:

_>Т.е. примерно так? если у шарпа есть абстрактная ветка АСТ типа Expression, можно унаследовать от неё свою ветку, например JsonExpresion и мапить на него PT json'а. Тогда в АСТ шарпа на нужном месте будет именно JsonExpresion.


Да. Именно так. При этом придется реализовать интерфейс CSharp.Expression, в котором будет, в том числе, тип выражения, например. Это сделает JsonExpresion полноценной веткой расширенного шарпа.

_>>>Теперь понятно. Не нашел никакого описания расширения языка в найтре на более высоком уровне, чем расширение парсера, потому и всплыл вопрос.


VD>>А, как ты себе это видишь?


_>Не совсем понял, что именно вижу?


Ну, "более высокий уровень". Я тоже не понял что имеется в виду под этим.

_>Да. Сделал простой dsl, чтобы разобраться что к чему в найтре. Описал синтаксис, ast, мапинг и связывание, после чего захотелось расширить dsl шарповскими выражениями.


Здорово! Ты один из первых внешних пользователей. Там не так то просто все собрать. Мы сейчас работаем над упрощением этого вопроса. А, тут вдруг, сам собрал и вопросов не возникло. Приятно!

_>Расширение синтаксиса было элементарным, а дальше вопрос. У шарпа свой АСТ (ну, пока для выражений нет, но будет), у меня свой, что делать вообще не понятно. Теперь ясно. Вроде просто, но не сразу дошел.


Тут есть один нюанс. Один и языков должен, все же, знать о том что его расширяют или что он расширяет. Шарп — это скорее хостовый язык. В его выражениях будет типизация в систему типов дотнета. При встраивании Шарпа в свои языки и при встривании своих языков в Шарп нужно это учитывать и передавать ему / брать от него соответствующую информацию. Так для Шарпа нужно будте сформировать Scope в рамках которого будут связываться имена, а при расширении Шарпа нужно будет вернуть тип своего (нового) выражения.

При генерации кода нужно будет "научить" хостовый язык генерировать код по своим расширениям.

Еще любые расширения могут порождать символы, которые могут быть использованы в хост-языке. Это еще один путь интеграции в хост-язык. Например, наше расширение может создать классы. Потом можно будет создать их экземпляры.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: [Nitra] Динамическое расширение
От: _someuser  
Дата: 07.10.15 20:49
Оценка:
Здравствуйте, VladD2, Вы писали:

_>>>>Теперь понятно. Не нашел никакого описания расширения языка в найтре на более высоком уровне, чем расширение парсера, потому и всплыл вопрос.


VD>>>А, как ты себе это видишь?


_>>Не совсем понял, что именно вижу?


VD>Ну, "более высокий уровень". Я тоже не понял что имеется в виду под этим.


Всмысле, как уже на уровне АСТ json будет уживаться с шарпом. В общем, уже то понятно, реализация может быть разная.

_>>Да. Сделал простой dsl, чтобы разобраться что к чему в найтре. Описал синтаксис, ast, мапинг и связывание, после чего захотелось расширить dsl шарповскими выражениями.


VD>Здорово! Ты один из первых внешних пользователей. Там не так то просто все собрать. Мы сейчас работаем над упрощением этого вопроса. А, тут вдруг, сам собрал и вопросов не возникло. Приятно!


Ну, более-менее разобрался в том, что нужно было для моего примера. Вопросы, конечно, еще будут Плагин для решарпера так и не удалось собрать, но пока не вникал, в чем там проблема.

VD>Тут есть один нюанс. Один и языков должен, все же, знать о том что его расширяют или что он расширяет. Шарп — это скорее хостовый язык. В его выражениях будет типизация в систему типов дотнета. При встраивании Шарпа в свои языки и при встривании своих языков в Шарп нужно это учитывать и передавать ему / брать от него соответствующую информацию. Так для Шарпа нужно будте сформировать Scope в рамках которого будут связываться имена, а при расширении Шарпа нужно будет вернуть тип своего (нового) выражения.


VD>При генерации кода нужно будет "научить" хостовый язык генерировать код по своим расширениям.


VD>Еще любые расширения могут порождать символы, которые могут быть использованы в хост-языке. Это еще один путь интеграции в хост-язык. Например, наше расширение может создать классы. Потом можно будет создать их экземпляры.


Да, уже понятно. У меня следующая ситуация. Решил попробовать написать простенький dsl для html с си подобным внешним видом. Уж не знаю, насколько такой dsl полезен в жизни, но для примера пойдет. Получилось так:
http://files.rsdn.org/121344/zxc.png


Конечно, после этого захотелось сделать свой razor. Чтобы можно было писать так:

body
{
    foreach (var item in model.Items)
    {
        div(id: @"{item.Id}") { item.Text; }
    }
}


Ну и вот здесь надо подумать. Видимо нужно брать за основу шарп (как хост язык), а dsl делать как расширение. Тогда АСТ расширения должно правильно интегрироваться в АСТ шарпа, т.е. с протаскиванием всех ЗС в ветки АСТ шарповых выражений и statement'ов и т.д. Это даже даст возможность в си-шарп коде использовать расширение. Не совсем пока ясно, как сделать, чтобы можно было писать такой html в своих отдельных файлах со своим расширением (как razor). Выходит, это должен быть отдельный язык, но все равно с тесной интеграцией с шарпом.
Re[8]: [Nitra] Динамическое расширение
От: VladD2 Российская Империя www.nemerle.org
Дата: 08.10.15 21:27
Оценка:
Здравствуйте, _someuser, Вы писали:

_>Ну и вот здесь надо подумать. Видимо нужно брать за основу шарп (как хост язык), а dsl делать как расширение. Тогда АСТ расширения должно правильно интегрироваться в АСТ шарпа, т.е. с протаскиванием всех ЗС в ветки АСТ шарповых выражений и statement'ов и т.д. Это даже даст возможность в си-шарп коде использовать расширение. Не совсем пока ясно, как сделать, чтобы можно было писать такой html в своих отдельных файлах со своим расширением (как razor). Выходит, это должен быть отдельный язык, но все равно с тесной интеграцией с шарпом.


Можно сделать так, чтобы этот ДСЛ был и отдельным форматом, и встраивался в шарп. Нужно только продумать синтаксические все это. Чтобы будучи встроенный в Шарт этот ДСЛ преобразовывался во что-то понятное для шарпа.

Что касается отдельного файла, то для этого нужно описать .nlang-файл. Пока что он используется только для генерации плагина к РеШарперу, но Хардкейс работает над интеграции .nlang-файлов в общий процесс компиляции. Надеюсь на следующей недели он это доделает и займется деплоем. После завершении этой работы можно будет сделать то что ты хочешь. Причем очень просто.

Есть только одна проблема. Типизации для выражений шарпа пока нет. И по уму для этого нужно реализовать фрейморк по типизации. А, это не мало времени. Хотя шарп язык довольно простой. Там вывод типов ограниченный. Так что можно временно рукопашный вывод типов запилить. Но и это требует времени и сил.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.