Первыми задачами (при разработке Nemerle 2) являются выбор нового бэкэнда для компилятора (в замен System.Reflection + System.Reflection.Emit), и реализация на его базе следующих классов (расположенных сейчас здесь):
1. LibraryManager — управляет загрузкой типов и макросов из внешних библиотек.
2. LibraryReference — описывает библиотеку (сборку).
3. ExternalTypeInfo и его наследников — описывают тип внутри компилятора.
4. ExternalMemberInfo и его наследников — описывают члены типов внутри компилятора.
В процессе работы нужно произвести рефакторинг указанных классов и полностью удалить из кода все ссылки на System.Reflection.*.
Собственно первая подзадача сформировать небольшую команду тех кому было бы интересно этим заниматься.
Почему-то (к сожалению) работа с метаданными и генерацией кода не очень популярна. Но она нужна не менее других (даже более, так как она нужна с самого начала). Кроме того это не хилый опыт который пригодится в жизни.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Первыми задачами (при разработке Nemerle 2) являются выбор нового бэкэнда для компилятора (в замен System.Reflection + System.Reflection.Emit), и реализация на его базе следующих классов (расположенных сейчас здесь): VD>1. LibraryManager — управляет загрузкой типов и макросов из внешних библиотек. VD>2. LibraryReference — описывает библиотеку (сборку). VD>3. ExternalTypeInfo и его наследников — описывают тип внутри компилятора. VD>4. ExternalMemberInfo и его наследников — описывают члены типов внутри компилятора.
VD>В процессе работы нужно произвести рефакторинг указанных классов и полностью удалить из кода все ссылки на System.Reflection.*.
VD>Надо попытаться реализовать указанные классы на базе CCI Metadata и AbstractIL
из F#-а.
VD>PS
VD>Собственно первая подзадача сформировать небольшую команду тех кому было бы интересно этим заниматься.
VD>Почему-то (к сожалению) работа с метаданными и генерацией кода не очень популярна. Но она нужна не менее других (даже более, так как она нужна с самого начала). Кроме того это не хилый опыт который пригодится в жизни.
Вкратце описание типов которые нужно реализовать:
TypeInfo — описвает базовый абстрактный тип представляющий описание типа в компиляторе. TypeInfo описывает невоплощенный тип, т.е. тип без параметров типов. Его часто так же называют Type Constructor, от чего в компиляторе он частенько появляется в полях с именем tycon.
У этого класса есть ряд наследников в том числе наследники с префиксом "External": ExternalNemerleTypeInfo, ExternalPrimitiveTypeInfo, ExternalTypeInfo. Названия говорят сами за себя. ExternalTypeInfo — базовый тип описывающий загружаемые из сборок типы. ExternalNemerleTypeInfo — уточнеение предыдущего класса описывающие типы немерла (варианты и т.п.). ExternalPrimitiveTypeInfo — описывает примитивы и прибилднутые типы.
Задача этих типов получать общую информацию о типах:
* Имя типа.
* Пространство имен в котором объявлен тип.
* Полное имя (с пространством имен и внешними классами, если такие есть).
* Список параметров типов.
* Список членов (в отложенном режиме, чтобы на тратить время на разбор сигнатур которые могут никогда не понадобиться в программе, кроме приватных).
* Список вложенных типов.
* Список кастом-атрибутов. Тут все сложнее. Нужно уметь читать значение простых свойств атрибутов (прибилднутых типов). Как понимаешь читать их придется в режиме декомпиляции, так как сборку на исполнение поднимать нельзя (она может быть не того рантайма). CCI позволяет решить эту задачу на ура (я проверял).
* Модификаторы доступа (public/internal).
ExternalNemerleTypeInfo должен разбирать дополнительную информацию запакованную в виде спец.атрибутов. и воссоздавать информацию об определенных во внешних сборках вариантных типах и их вхождениях. Для рабора этой фигни есть тип TyCodec, который так же нужно переименовать, отрефакторить и приспособить к новым условиям.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
При реализации указанных классов нужно избавиться ото все типов из System.Reflection.
Так же нужно продумать как обеспечить инкапсуляцию типов из базовых API (CCI, AbsIL, ...).
Сейчас System.Reflection торчит из-зо всех дыр. В новой версии этих классов все детали базовых API должны быть скрыты. Однако эти детали обязательно потребуются при генерации сборок (IL-а и метаданных). По сему нужно продумать четкий интефейс между этими модулями при обеспечении инкапсуляции для остального кода.
Нам нужно выделить код отвечающий за загрузку типов в отдельную сборку. Все базовые типы при этом должны находиться в другой сборке, которая будет импортироваться сборкой чтения метаданных и другими сборками компилятора.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Ребят, приветствую всех с окончанием года! У нас появились свободные деньки (до 5-го), хотел приобщить руки к делу.
Немного почитав про начинания с N2, создалось ощущение, что все уже всё знают. (я про кишки компилера, структуры, язык) А так как у меня практики особой не было, сижу как пенёк.
Но наверное это к лучшему, потому что у меня возник вполне резонный вопрос: а нет ли смысла начать с конца? Т.е. сначала определить язык, его типы, как они будут совмещаться с дотнетовскими, вообще подробно расписать _существенные_различия_ Немерли с дотентом, а потом уже придумывать утилитные классы, читалки метаатрибутов и т.п.
Вот уже Влад ввёл ExternalTypeInfo — почему экстернал? Разве в дотнете есть понятие "внешний тип"? Я бы сказал ровно наоборот: есть типы дотнета и какие-то специфичные для Немерли типы (варианты?), которые всё равно никакими "внешними" не будут — будут точно так же загружаться из сборок как string или Dictionary. Т.е. со всеми типами дотнетины мы будем работать одинаковым образом (ради чего дотнет и придумывался). Это правильное предположение?
Затем, хорошо бы как-то набросать схемок (вплоть до скана карандашного рисунка) того, из чего будет состоять компилятор — абстрактные "парсер", "лексер" мы все знаем, а нужна именно наглядная схема кто и что делает, какими данными обменивается, где хранит внутренние данные и вход/выход. Без общего понимания нет смысла бросаться кодить даже тем, кто понимает внутренности Немерли-1.
VD>Почему-то (к сожалению) работа с метаданными и генерацией кода не очень популярна.
Да пофиг, это ничуть не скучнее, чем хвостовая рекурсия — для такой нетривиальной задачи как компилер всегда найдутся интересные в реализации моменты. BLToolkit тоже в своём роде "стотыщный скучный маппер БД-объекты", а кода написано немало!
Вобщем, наверное все мою мысль поняли — для включения любого члена в работу, нужен фундамент — он же потом будет наглядной документацией.
На самом деле интересного там мало. Это слишком высокоуровневый АПИ. Как я понимаю он "гвоздями" пришит к семантике Шарпа и Васика. Так что нам он вряд ли подойдет.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, matumba, Вы писали:
M>Но наверное это к лучшему, потому что у меня возник вполне резонный вопрос: а нет ли смысла начать с конца? Т.е. сначала определить язык, его типы, как они будут совмещаться с дотнетовскими, вообще подробно расписать _существенные_различия_ Немерли с дотентом, а потом уже придумывать утилитные классы, читалки метаатрибутов и т.п.
Да в глобальном плане, насколько я понимаю, все удовлетворены немерле-1. Немерле-2 решает главные проблемы немерле-1, а это страшноватый код, использование System.Reflection и (дальше каждый пусть вставит свое).
M>Вот уже Влад ввёл ExternalTypeInfo — почему экстернал? Разве в дотнете есть понятие "внешний тип"?
В дотнете и нет, есть в наверное в любом достаточно продвинутом компиляторе. "Внешний тип" — тип, определенный не в сборке, которая компилируется в данный момент, вот и все
M>Затем, хорошо бы как-то набросать схемок (вплоть до скана карандашного рисунка) того, из чего будет состоять компилятор — абстрактные "парсер", "лексер" мы все знаем, а нужна именно наглядная схема кто и что делает, какими данными обменивается, где хранит внутренние данные и вход/выход. Без общего понимания нет смысла бросаться кодить даже тем, кто понимает внутренности Немерли-1.
Это бы конечно надо, но задача кодогенерации довольно изолированная, ее можно начать решать до общей концепции компилятора... С другой стороны, надо выбрать API кодогенерации до начала основной работы, потому-то и спешка такая.
M>Вобщем, наверное все мою мысль поняли — для включения любого члена в работу, нужен фундамент — он же потом будет наглядной документацией.
Здравствуйте, catbert, Вы писали:
C>Да в глобальном плане, насколько я понимаю, все удовлетворены немерле-1. Немерле-2 решает главные проблемы немерле-1, а это страшноватый код
Тогда вопрос: компилер будет переписываться полностью или у существующего немного подпилят код в сторону модульности?
M>>Вот уже Влад ввёл ExternalTypeInfo — почему экстернал? Разве в дотнете есть понятие "внешний тип"?
C>В дотнете и нет, есть в наверное в любом достаточно продвинутом компиляторе. "Внешний тип" — тип, определенный не в сборке, которая компилируется в данный момент, вот и все C> у Builder-ов, по определению, методов должно быть больше (ведь мы можем изменять билдеры в процессе компиляции/исполнения макросов, а External* иммутабельны по природе).
Я не вижу каких-то особых причин разделять практически единую сущность. Ну будет больше методов, лишнюю память же они не съедят! Да и extension methods вроде бы есть.
C>Это бы конечно надо, но задача кодогенерации довольно изолированная, ее можно начать решать до общей концепции компилятора...
Как я понял, Влад уже попробовал CCI и его возможностей достаточно. На форуме уже бросаются заготовки классов для метаданных, хотя как и где они будут использоваться — вопрос (думаю, не только для меня? ). Мне кажется, такой "быстропрактический" подход слишком быстрый. По сути, даже непонятно, что в компиляторе будет переписываться (см. вопрос выше).
В этом проекте собраны базовые типы (в основном абстрактные и интерфейсы) описывающие систему типов немерла.
Тем кто занимается проектом чтения метаданных нужно реализовать наследника абстрактного типа NTypeInfo и приведенные там интерфейсы, так чтобы вся информация бралась из внешних сборок.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, matumba, Вы писали:
VD>>Завел соответствующий issues.
M>Я там перевод поставил комментом, но последние 2 пункта требуют пояснений — постороннему человеку не понять.
В последнем предложении я пропустил слово "называемую". Там должно было быть "так называемую логику подстановки параметров типов".
Поясню, что это значит на примере. Предположим у нас есть тип:
class A[T] { }
и его наследник:
class B[X] : A[X] { }
Если мы захотим получить тип A[X], то нам потребуется подставить вместо параметра типов T тип X. Это осуществляется путем рекурсивной замены. Тип Subst снабжается информацией о том какие параметры типов нужно заменять на какие. О методах возвращающих Subst и шала речь в том пункте. Но возможно этот пункт вообще лучше удалить. Дойдет дело до этим методов, тогда и будем отдельно объяснять.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, matumba, Вы писали:
M>Я там перевод поставил комментом, но последние 2 пункта требуют пояснений — постороннему человеку не понять.
Пункт 3:
"3. Указанные классы (и их наследники) должны хранить ссылку на соответствующие объекты низлежащих API, но эта ссыла не должна быть доступна через публичный интерфейс."
Речь идет о классах о которых речь велась выше. Низлежащие API это: CCI Metadata, Mono Cecil, AbsIL из F#.
Короче должно быть что-тол вроде:
"3. This classes must keep reference to corresponding classes of underlying API and these references must not be visible outside."
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, matumba, Вы писали:
M>Но наверное это к лучшему, потому что у меня возник вполне резонный вопрос: а нет ли смысла начать с конца? Т.е. сначала определить язык, его типы, как они будут совмещаться с дотнетовскими, вообще подробно расписать _существенные_различия_ Немерли с дотентом, а потом уже придумывать утилитные классы, читалки метаатрибутов и т.п.
Язык уже определен в первой версии. Во второй версии мы хотим сосредоточиться на следующих главных аспектах:
1. Снятие ограничений на расширение синтаксиса и семантики.
2. Упрощении создания собственных DSL-ей (как внутренних, так и внешних).
3. Качестве реализации.
4. Качестве API макросов.
5. Сделать компилятор и интеграцию независимыми от конкретной версии фрэймворка.
Отсюда все что касается системы типов и языка в общем-то известно.
M>Вот уже Влад ввёл ExternalTypeInfo — почему экстернал? Разве в дотнете есть понятие "внешний тип"?
Оно есть в компиляторах. Есть типы которые получаются путем парсинга исходников и типизации полученного AST, а есть типы из внешних сборок (подключенных к проекту).
M>Я бы сказал ровно наоборот: есть типы дотнета и какие-то специфичные для Немерли типы (варианты?),
Это не то. Такие типы назывались "Nemerle". Например, был тип "ExternalNemerleTypeInfo" — наследник ExternalTypeInfo".
M>которые всё равно никакими "внешними" не будут — будут точно так же загружаться из сборок как string или Dictionary.
Вот тип загружаемый из сборки и называется внешним. Причем вне зависимости от того немерловый он или дотнетный.
M>Затем, хорошо бы как-то набросать схемок (вплоть до скана карандашного рисунка) того, из чего будет состоять компилятор — абстрактные "парсер", "лексер" мы все знаем, а нужна именно наглядная схема кто и что делает, какими данными обменивается, где хранит внутренние данные и вход/выход. Без общего понимания нет смысла бросаться кодить даже тем, кто понимает внутренности Немерли-1.
Как раз парсера и лексера не будет . Бдут вездесущие PEG-макросы. Весь язык будет строиться из них. По сути это и есть парсер. Но компонентный и модульный.
VD>>Почему-то (к сожалению) работа с метаданными и генерацией кода не очень популярна.
M>Да пофиг, это ничуть не скучнее, чем хвостовая рекурсия — для такой нетривиальной задачи как компилер всегда найдутся интересные в реализации моменты. BLToolkit тоже в своём роде "стотыщный скучный маппер БД-объекты", а кода написано немало! M>Вобщем, наверное все мою мысль поняли — для включения любого члена в работу, нужен фундамент — он же потом будет наглядной документацией.
ОК, попробуем. Что касается системы типов, то я недавно залил базовые описания для ее интерфейсов и ключевых классов. Сейчас их можно наблюдать здесь.
Думаю, что их изучение может о многом рассказать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, matumba, Вы писали:
M>Тогда вопрос: компилер будет переписываться полностью или у существующего немного подпилят код в сторону модульности?
С начало планировалось идти методом глубокого рефаторинга. Но одна из проблем текущей версии компилятора — черезмерная связанность, нарушение многих принципов ОО-дизайна. Как результат в компилятор стало очень сложно вносить изменения. Плюс компилятор довольно медленно компилируется, что так же усложняет его развитие.
Таким образом на сегодня решено все же переписывать компилятор использую его части в качестве основы и заготовок.
C>> у Builder-ов, по определению, методов должно быть больше (ведь мы можем изменять билдеры в процессе компиляции/исполнения макросов, а External* иммутабельны по природе).
M>Я не вижу каких-то особых причин разделять практически единую сущность. Ну будет больше методов, лишнюю память же они не съедят! Да и extension methods вроде бы есть.
Это разные сущности которые в определенный момент времени должны предоставлять одинаковый интерфейс (общий поднабор). Но задачи у них совсем разные. External* только скрывают детали реализации АПИ работы с метаданными и генерации ИЛ-а. А вот *Builder-ы предоставляют дополнительную функциональность. Они позволяют работать с АСТ и в то же время предоставляют интерфейс типов.
Сливать их не стоит. Будет туча методов которые будут файлить в одних условиях и работать в других. А это совсем плохо. Лучше иметь два типа имеющих общий базовый класс и при этом предоставляют разные возможности.
При этом вместо External* можно будет использовать *Builder если для *Builder-ов завершен этап предварительной типизации (выведены типы параметров методов и проведено построение иерархии типов). Это же позволит нам вместо ссылок на внешние сборки использовать ссылки на другие проекты того же солюшена.
C>>Это бы конечно надо, но задача кодогенерации довольно изолированная, ее можно начать решать до общей концепции компилятора...
M>Как я понял, Влад уже попробовал CCI и его возможностей достаточно.
Попробовать то попробовал. Но черт всегда кроется в деталях. А детали выявляются только в процессе реального использования.
M> На форуме уже бросаются заготовки классов для метаданных, хотя как и где они будут использоваться — вопрос (думаю, не только для меня? ). Мне кажется, такой "быстропрактический" подход слишком быстрый. По сути, даже непонятно, что в компиляторе будет переписываться (см. вопрос выше).
Дык мы имеем рабочий компилятор. Можно сказать что это прототип. Из него и берутся заведомо рабочие решения. Зачем же нам еще раз проползать на пузе все препятствия? Мы используем полученный опыт.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.