Генератор исходника Nemerle из дерева и из C#, а также Peg
От: CodingUnit Россия  
Дата: 22.06.11 14:37
Оценка: 6 (1)
Мы начали с Владом переписку по почте с обсуждением различных вопросов, но Влад предложил вынести обсуждение на форум, чтобы если будут интересные ответы, которые могли бы быть полезны другим. Начали обсуждение с вопроса о Peg, парсере для текстового языка диаграмм состояний, а также проблем генерации исходников в макросах. Сейчас продолжаю задавать вопросы Владу, ребятам создававшим Nemerle.Peg и CSharpParser, и всему сообществу. На обсуждение вопрос о генерации исходника из дерева.
Есть встроенный генератор для отладочных нужд, типа TypeBuilder.DefineWithSource, но он не поддерживает вложенные типы, верхние объявления, которые должны добавляться в TypeBuilder методами DefineNested, но исходника никак не сделать для отладки, за отсутствием метода с приставкой WithSource. Код методов худо бедно генерится PrettyPrint ом.
Поэтому было бы неплохо доделать полноценную генерацию для верхних типов TopDeclaration, вложенных и всего остального, чтобы можно было делать качественные отладочные исходники. А также приятный плюс впридачу к парсингу C# и использованию в проектах Nemerle, конвертить C# в исходник Nemerle, благо большая часть уже готова, то есть PrettyPrint.
За все это я решил взяться, и уже начал работать, потому что потребность назрела, и возник ряд насущных вопросов в связи с этим.
1) При использовании конвертера CSharpToNemerle который получает в результате Ast Nemerle, ему на вход в конструкторе требуется ManagerClass, откуда его взять? Если мы в обычной программе, а не в макросе, Создать самому? Он инициализирует некоторые структуры только при вызове Run, как его инициализировать до этого, чтобы полноценно распарсить C# и получить Ast Nemerle для последующей обработки?

2) Куда все это положить, я начал делать у себя в своей папке, думаю сделать метод PrintBody в TopDeclaration как в методе ClassMember, сам TopDeclaration сделать partial и вынести код печати в отдельный исходник, которому как в ClassMember передается LocatableTextWriter, и он сам себя должен распечатать в него. То есть объединить генерацию исходника Nemerle из C# с генерацией обычного отладочного кода Nemerle, чтобы не делать двойную работу. Может кто придумает вариант с местоположением лучше.

3) Исходник в parsetree ncc будет наверное называться TreePrint.n, или PrintTree.n есть у кого варианты лучше?

4) Ничего если я сделаю открытыми типы LocatableTextWriter и LocatingTextWriter в Nemerle.Compiler чтобы работать из внешнего кода с ними, из своей библиотеки, чтобы тестить код без перекомпиляции всего Nemerle?

5) Также для этого нужен открытым метод ClassMember.PrintBody можно ли его открыть, или это даст брешь в архитектуре компилятора?

6) Встает проблема с генерацией namespace, парсер CSharpToNemerle в результате дает ParseResult в котором есть список TopDeclaration, понятно что каждый из них находиться в своем namespace может в одном а может и в разных. Тут надо как то придумать как создавать пространства имен, как в исходном тексте C#, если есть Location можно как то отсортировать по ним сами пространства, а потом вложить их друг в друга как они должны быть и в них раскрывать TopDeclaration, может кто предложит вариант лучше?

Прошу простить если кого смутит большое навороченное сообщение, с разными частными деталями, я задавал вопрос Владу по почте, но он настоял чтобы вынести на форум, что получилось то получилось. Сам же Влад да не презрит сие начертание.
Re: Генератор исходника Nemerle из дерева и из C#, а также P
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.06.11 15:08
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>1) При использовании конвертера CSharpToNemerle который получает в результате Ast Nemerle, ему на вход в конструкторе требуется ManagerClass, откуда его взять?


Он есть у многих объектов. Например, у тайпера:
def typer = Macros.ImplicitCTX();
typer.Manager



CU>Если мы в обычной программе, а не в макросе, Создать самому?


В обычной программе его взять не откуда, так как это часть компилятора. Только зачем он в обычной программе? Он нужен в интеграции с IDE. Там такой объект есть. Для каждого проекта заводится так называемый Engin. Engin является наследником
ManagerClass.

Если хочется из обычного приложения его получить, то пидется вручную создавать ManagerClass и инициализировать его. Это не очень просто, но возможно.

В прочем, на мой взгляд подобный конвертер должен быть частью интеграции с IDE.

CU>Он инициализирует некоторые структуры только при вызове Run, как его инициализировать до этого, чтобы полноценно распарсить C# и получить Ast Nemerle для последующей обработки?


Пример использования ManagerClass можно подсмотреть в коде интеграции со студией, как я уже говорил, там создан наследник класса ManagerClass — Engin. Еще одним примером может служить проект к статье Разработка простого генератора отчетов с помощью Nemerle и System.Xml.Linq
Автор(ы): Владислав Чистяков aka VladD2
Дата: 17.07.2008
Статья демонстрирует разработку реального приложения на Nemerle на примере создания простого генератора отчетов. Кроме того, в статье показана работа
с XML средствами LINQ to XML.
. В нем я парсил выражения с помощью компилятора немерла.

CU>2) Куда все это положить, я начал делать у себя в своей папке, думаю сделать метод PrintBody в TopDeclaration как в методе ClassMember, сам TopDeclaration сделать partial и вынести код печати в отдельный исходник, которому как в ClassMember передается LocatableTextWriter, и он сам себя должен распечатать в него. То есть объединить генерацию исходника Nemerle из C# с генерацией обычного отладочного кода Nemerle, чтобы не делать двойную работу. Может кто придумает вариант с местоположением лучше.


Мне кажется лучше сделать отдельный файл и модуль (на подобии PrettyPrint.n). Создать рядом еще один файл с именем вроде TopDeclarationsPrettyPrint.n и разместить в нем модуль содержаций по одному методу на каждый тип АСТ-веток.

CU>3) Исходник в parsetree ncc будет наверное называться TreePrint.n, или PrintTree.n есть у кого варианты лучше?


Все АСТ — это дерево. Оно как-то не внятно. Лучше TopDeclarationsPrettyPrint.n.

CU>4) Ничего если я сделаю открытыми типы LocatableTextWriter и LocatingTextWriter в Nemerle.Compiler чтобы работать из внешнего кода с ними, из своей библиотеки, чтобы тестить код без перекомпиляции всего Nemerle?


LocatableTextWriter — можно сделать публичным. Но LocatingTextWriter точно не надо. Это всего лишь подкласс класса LocatableTextWriter с переопределенными методами. Знание о его наличии не даст никаких дивидендов. Нужно грамотно капсулирование его использование и все.

CU>5) Также для этого нужен открытым метод ClassMember.PrintBody можно ли его открыть, или это даст брешь в архитектуре компилятора?


Вот это не нужно. Лучше пусть весь код PrettyPrint-а лежит в отдельном модуле и получает доступ к АСТ через публичный интерфейс.

И дело тут не в бреши (их и так поляки наделали не мало). Дело в группировке кода. Будет лучше, если код выполняющий одну задачу будет лежать в одном месте.

CU>6) Встает проблема с генерацией namespace, парсер CSharpToNemerle в результате дает ParseResult в котором есть список TopDeclaration, понятно что каждый из них находиться в своем namespace может в одном а может и в разных. Тут надо как то придумать как создавать пространства имен, как в исходном тексте C#, если есть Location можно как то отсортировать по ним сами пространства, а потом вложить их друг в друга как они должны быть и в них раскрывать TopDeclaration, может кто предложит вариант лучше?


Это косяк заложенный в компилятор Н еще на самых ранних стадиях его разрботки. Поляки увлеклись оптимизацией и опустили некоторые нужные структуры данных.

Насколько я знаю парсер C#-а выдает АСТ в том виде в котором он был спарсен из файла. При этом там есть и информация об пространствах имен. Наверно имеет смысл вынимать эту информацию из необработанного (C#-ного) АСТ. Конкретнее, из типа NamespaceNode.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Генератор исходника Nemerle из дерева и из C#, а такж
От: hardcase Пират http://nemerle.org
Дата: 22.06.11 15:48
Оценка:
Здравствуйте, VladD2, Вы писали:

А я вот думаю что список TopDeclaration это хорошая отличный кандидат на то, чтобы каждый его элемент превратить в файл.
/* иЗвиНите зА неРовнЫй поЧерК */
Re: Генератор исходника Nemerle из дерева и из C#, а также P
От: catbert  
Дата: 22.06.11 16:48
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>1) При использовании конвертера CSharpToNemerle который получает в результате Ast Nemerle, ему на вход в конструкторе требуется ManagerClass, откуда его взять? Если мы в обычной программе, а не в макросе, Создать самому? Он инициализирует некоторые структуры только при вызове Run, как его инициализировать до этого, чтобы полноценно распарсить C# и получить Ast Nemerle для последующей обработки?


Это почти законченный проект раскраски кода Nemerle и навигации по нему, который работает, используя компилятор Nemerle:
https://bitbucket.org/catbert/projects/src/33d9a8113403/CodeColorizer/

Вам, надеюсь, будут полезны класс-наследник ManagerClass, в котором есть метод LoadSources, который инициализирует компилятор для конкретного проекта, а также класс, который обходит все синтактическое дерево Немерле.

CU>2) Куда все это положить, я начал делать у себя в своей папке, думаю сделать метод PrintBody в TopDeclaration как в методе ClassMember, сам TopDeclaration сделать partial и вынести код печати в отдельный исходник, которому как в ClassMember передается LocatableTextWriter, и он сам себя должен распечатать в него. То есть объединить генерацию исходника Nemerle из C# с генерацией обычного отладочного кода Nemerle, чтобы не делать двойную работу. Может кто придумает вариант с местоположением лучше.


Если вы имеете в виду сделать методы Print*, которые будут генерировать код на одном из языков из расширяемого списка, это хорошая идея. Но может быть стоит рассмотреть вариант отдельной от компилятора сборки.

CU>4) Ничего если я сделаю открытыми типы LocatableTextWriter и LocatingTextWriter в Nemerle.Compiler чтобы работать из внешнего кода с ними, из своей библиотеки, чтобы тестить код без перекомпиляции всего Nemerle?


CU>5) Также для этого нужен открытым метод ClassMember.PrintBody можно ли его открыть, или это даст брешь в архитектуре компилятора?


Да она и так дырявая, эта архитектура. Компилятор не рассчитан на использование в виде библиотеки. Так что открывайте, имхо.

CU>6) Встает проблема с генерацией namespace, парсер CSharpToNemerle в результате дает ParseResult в котором есть список TopDeclaration, понятно что каждый из них находиться в своем namespace может в одном а может и в разных. Тут надо как то придумать как создавать пространства имен, как в исходном тексте C#, если есть Location можно как то отсортировать по ним сами пространства, а потом вложить их друг в друга как они должны быть и в них раскрывать TopDeclaration, может кто предложит вариант лучше?


Вариант хардкейса — каждый TopDeclaration в своем файле со своим неймспейсом и юзингами — мне нравится больше всего.

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


Вам спасибо за работу.
Re[3]: Генератор исходника Nemerle из дерева и из C#, а такж
От: VladD2 Российская Империя www.nemerle.org
Дата: 22.06.11 17:50
Оценка:
Здравствуйте, hardcase, Вы писали:

H>А я вот думаю что список TopDeclaration это хорошая отличный кандидат на то, чтобы каждый его элемент превратить в файл.


Делегаты и энумы тоже? Не все с этим согласятся.

Как опция — это может и было бы хорошо. Но не по умолчанию.

Лучше уж сделать рефакторинг разнесения типов по файлам. Он бы был очень кстати при рефакторинге компилятора.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Генератор исходника Nemerle из дерева и из C#, а такж
От: CodingUnit Россия  
Дата: 23.06.11 12:24
Оценка:
Здравствуйте, VladD2, Вы писали:

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


H>>А я вот думаю что список TopDeclaration это хорошая отличный кандидат на то, чтобы каждый его элемент превратить в файл.


VD>Делегаты и энумы тоже? Не все с этим согласятся.


VD>Как опция — это может и было бы хорошо. Но не по умолчанию.


VD>Лучше уж сделать рефакторинг разнесения типов по файлам. Он бы был очень кстати при рефакторинге компилятора.


Да я с Владом согласен, TopDeclaration там и интерфейсы, альясы, делегаты, помимо больших классов, поэтому их каждый в свой файл как то не красиво. Вариант с обработкой NamespaceNode из CSharpParser мне кажется более похож на реальность. Хотя это годится для конвертера из C#, для обычной печати надо придумывать другой способ, наверное надо обрабатывать NamespaceNode в которых находятся TopDeclaration и сортировать их по позициям, тогда должны быть точно известны позиции Location, они известны при парсинге, но если добавляется член в макросе, то его надо грамотно подключить к текущему пространству. Давайте думу думать
Мне в голову приходит такой алгоритм:

1) Если мы имеем родной Ast C# из парсера то объявления должны быть точно соответствовать файлу С#, чтобы пользователь потом не плакал, говоря, я положил тут класс, оформил красиво два рядом namespace, а они куда то уехали.

2) Если производится печать по готовому дереву из парсера N из некоего источника и известны Location, то стараемся максимально приблизиться к оригиналу, при этом:
1. Можно печатать некий список TopDeclaration, тогда мы можем их отсортировать в памяти так:
а) Берем всю структуру и создаем типа Hashtable[namespace,list[TopDeclaration]], в одном пространстве может быть группа
б) Для типов лежащих в одном пространстве принимается решение класть их в отдельный файл или в разные. На основе Location, если известно то определяется по нему, если его нет значит на основе некоего критерия. Я предлагаю следующее, делегаты, интерфейсы, альясы объединяются в одну группу и лежат в одном файле, классы могут разделяться на разные файлы, по одному для класса. partial всегда в разные
в) Можно также некиими аттрибутами декларативно указать, если нет реального источника в коде в какой файл должен сгенериться после печати, что и куда
д) Потом все сортируется по Location если есть, или по порядку их в исходном списке и выдается в файлы. Разные пространства всегда лучше писать в разные файлы
2) Если печатаем только один TopDeclaration например методом DefineWithSource в GlobalEnv, то он пишется в своем пространстве, файл можно указать перегрузкой методов, один генерирует имена сам, другой можно задать самому, если находятся декларативные аттрибуты в коде (например можно пометить в цитате [PrintTo("testclass.n")] класс) то используются они.

Просьба писать комментарии, пожелания, кто что думает по этому поводу, проект открытый и будет использоваться в самом Nemerle поэтому просьба сообществу координировать его для верного его развития.
Re[2]: Генератор исходника Nemerle из дерева и из C#, а такж
От: CodingUnit Россия  
Дата: 23.06.11 12:32
Оценка:
Здравствуйте, catbert, Вы писали:

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


CU>>1) При использовании конвертера CSharpToNemerle который получает в результате Ast Nemerle, ему на вход в конструкторе требуется ManagerClass, откуда его взять? Если мы в обычной программе, а не в макросе, Создать самому? Он инициализирует некоторые структуры только при вызове Run, как его инициализировать до этого, чтобы полноценно распарсить C# и получить Ast Nemerle для последующей обработки?


C>Это почти законченный проект раскраски кода Nemerle и навигации по нему, который работает, используя компилятор Nemerle:

C>https://bitbucket.org/catbert/projects/src/33d9a8113403/CodeColorizer/

C>Вам, надеюсь, будут полезны класс-наследник ManagerClass, в котором есть метод LoadSources, который инициализирует компилятор для конкретного проекта, а также класс, который обходит все синтактическое дерево Немерле.


Спасибо за ссылочку, особо хочу сказать спасибо за игру в точки на N, очень полезная штука, в детстве особенно любили в нее играть

CU>>5) Также для этого нужен открытым метод ClassMember.PrintBody можно ли его открыть, или это даст брешь в архитектуре компилятора?


C>Да она и так дырявая, эта архитектура. Компилятор не рассчитан на использование в виде библиотеки. Так что открывайте, имхо.


Еще проблема в том что сам ClassMember.PrintBody придется модифицировать потому что он не поддерживает сейчас всего что нужно, сейчас помоему только методы и свойства, надо еще вложенные типы, поля, события и остальное, все это доделать в нем же и вызывать при печати TopDeclaration для каждого ClassMember PrintBody или вынести вообще все во вне и сделать заново, мб скопировав код из PrintBody?
Re[5]: Генератор исходника Nemerle из дерева и из C#, а такж
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.06.11 15:32
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Да я с Владом согласен, TopDeclaration там и интерфейсы, альясы, делегаты, помимо больших классов, поэтому их каждый в свой файл как то не красиво. Вариант с обработкой NamespaceNode из CSharpParser мне кажется более похож на реальность. Хотя это годится для конвертера из C#, для обычной печати надо придумывать другой способ, наверное надо обрабатывать NamespaceNode в которых находятся TopDeclaration и сортировать их по позициям, тогда должны быть точно известны позиции Location, они известны при парсинге, но если добавляется член в макросе, то его надо грамотно подключить к текущему пространству.


"Обычная" печать одна для чего нужна? Я так понимаю только для отладки. А для отладки совершенно по фигу где лижит тип. Можно каждый тип сувать в отдельный файл. А алиасы печатать для отладки просто нет смысла.

CU>Давайте думу думать

CU>Мне в голову приходит такой алгоритм:

CU>1) Если мы имеем родной Ast C# из парсера то объявления должны быть точно соответствовать файлу С#, чтобы пользователь потом не плакал, говоря, я положил тут класс, оформил красиво два рядом namespace, а они куда то уехали.


+1 Если только, конечно, пользователь сам не хочет разложить все поп полочкам. А это можно некой настройкой сделать.

CU>2) Если производится печать по готовому дереву из парсера N из некоего источника и известны Location, то стараемся максимально приблизиться к оригиналу, при этом:


А зачем печатать то для чего есть реальные Location-ы? Если они есть, значит исходник тоже есть. А вот если код генерирован макросом, то может они и есть, но это будут черт знает что за локейшоны и сортировать по ним просто бесполезно.

Так что при дебажной печати раскладываем типы по отдельным файлам и все.

CU> ...в) Можно также некиими аттрибутами декларативно указать,


Это все слишком сложно и никому не нужно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.