зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 10:00
Оценка:
Почему было принято именно такое проектное решение? Как это можно использовать? В каких языках программирования такое применяется и несёт смысловую нагрузку?

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

Абстрактно можено представить себе язык типа Python, в котором количество пробелов перед словом может влиять на его свойства,
но там ведь не одно слово в строке — как поступать с остальными?

Я бы создал два синтаксических узла "ведущие пробелы" и "остальные пробелы строки" и повключал бы всю тривию туда,
а не к смежным узлам.

В WhitePaper по Roslyn написано:

In general, a token owns any trivia after it on the same line up to the next token. Any trivia after that line is associated with the following token. The first token in the source file gets all the initial trivia, and the last sequence of trivia in the file is tacked onto the end-of-file token, which otherwise has zero width.

Спрашивается, почему нельзя (неудобно) было сделать Trivia доступными из обоих смежных токенов (раз уж она между ними находится)?

Чего я не понимаю?
Отредактировано 17.07.2017 10:45 Arsen.Shnurkov . Предыдущая версия .
Re: зачем SyntaxTrivia входит в состав токенов?
От: Mystic Artifact  
Дата: 17.07.17 10:44
Оценка: +1
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Почему было принято именно такое проектное решение? Как это можно использовать? В каких языках программирования такое применяется и несёт смысловую нагрузку?

В C# — xml doc имеет смысловую нагрузку. Leading trivia "кушает" всё, а вот trailing — только до конца строки.

AS>Для меня все пробелы одинаковы, и они могли бы разбираться на отдельном этапе в отдельные узлы-списки в синтаксическом дереве.

Какой ещё отдельный этап? Нам дали текст со всем этим добром, вдобавок оно ж и делает ровно то что ты говоришь — узел будет иметь набор leading и trailing trivia.

AS>Чего я не понимаю?

Вообще просто таков дизайн, который пытается угодить в том числе и редакторам, для которых эти тривиа — важные элементы. + в тривию попадают не только пробелы, комментарии но и директивы препроцессора, если мне неизменяет память. Плюс они достаточно эффективно их хранят и переиспользуют.

PS: Токены это узлы дерева которые не могут иметь детей. Тривиа вообще отлельным лесом по момоему стоит. Но в теле парсера токенизация входного потока — это не совсем тоже самое, там вечно хаки вокруг них.
Re[2]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 10:48
Оценка:
MA> Leading trivia "кушает" всё, а вот trailing — только до конца строки.

Что это даёт? Почему сделано именно так, а не по-другому? Какие требования привели именно к такому решению?
Как это использовать?

MA> но и директивы препроцессора


тогда получается. что в синтаксическом дереве директивы препроцессора не спариваются?
имею в виду
#ifdef
#endif
Или это как-то обрабатывается при помощи structured trivia ?
Отредактировано 17.07.2017 11:11 Arsen.Shnurkov . Предыдущая версия . Еще …
Отредактировано 17.07.2017 10:51 Arsen.Shnurkov . Предыдущая версия .
Re[3]: зачем SyntaxTrivia входит в состав токенов?
От: Mystic Artifact  
Дата: 17.07.17 11:34
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

MA>> Leading trivia "кушает" всё, а вот trailing — только до конца строки.

AS>Что это даёт? Почему сделано именно так, а не по-другому? Какие требования привели именно к такому решению?
AS>Как это использовать?
Это даёт просто унифицированный парсер который может применяться не только для компиляции, но и средами разработки:
— (компилятор) формирование xml документации без хаков (в leading trivia будет блок документации у соответствующего узла);
— автоформатирование;
— переименование параметров -> так же без супер хаков это делает в блоке документации;
— что-нибудь ещё... (редактирование самого текста, но тут вопрос спорный)

Из плюсов их подхода, на мой взгляд то, что автоматически прячутся с глаз долой вот эти "trivia", но с возможностью до них всё таки добраться, когда это действительно необходимо.

Я думаю, толковее описаний, чем документации/вики по Рослину + некоторые посты не будет. Вот например немного про их деревья, если ещё не читал: Persistence, Facades and Roslyn's Red-Green Trees.

Имхо, в Рослине, не требования привели к решениям, а сугубая практика: гуманный для человека API и перфоманс.


MA>> но и директивы препроцессора

AS>тогда получается. что в синтаксическом дереве директивы препроцессора не спариваются? Или это как-то обрабатывается при помощи structured trivia ?
Я полагаю, что препроцессор работает как ему и положено, одако сами директивы/невошедший текст прячутся в тривии, таким образом дальше компилятор о них не заботится. Вместе с тем студия прекрасно будет подсвечивает активный и неактивные блоки препроцессора, на основании дерева разбора, а не кучей костылей сверху.
Ну т.е.:
#if FEATURE_X_PUBLIC
    public
#else
    internal
#endif
    class A {}

Это создаст узел для декларации типа, но лишь с одним модификатором, который будет облеплен соответствующими тривиа.
Хотя конкретно это я не проверял.
Re: зачем SyntaxTrivia входит в состав токенов?
От: Mystic Artifact  
Дата: 17.07.17 11:47
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Я бы создал два синтаксических узла "ведущие пробелы" и "остальные пробелы строки" и повключал бы всю тривию туда,

AS>а не к смежным узлам.
AS>В WhitePaper по Roslyn написано:
AS>

In general, a token owns any trivia after it on the same line up to the next token. Any trivia after that line is associated with the following token. The first token in the source file gets all the initial trivia, and the last sequence of trivia in the file is tacked onto the end-of-file token, which otherwise has zero width.

AS>Спрашивается, почему нельзя (неудобно) было сделать Trivia доступными из обоих смежных токенов (раз уж она между ними находится)?

Я не видел этой редакции вопроса.

Почему нельзя? То, что ты говоришь — сделать то, как раз можно, но это будет, имхо, антигуманно: эти токены являются узлами дерева, что вызовет неоднозначности при попытке найти узел в дереве по локации в тексте или же не совсем обычное поведение с точки зрения пользователей. Удалили узел — а часть trivia которыми он вроде как владел — остались? Ну или наоборот, удалились.
Кроме того, если задача — получить тривиа слева и справа — то можно же всегда получить соседние узлы.
Re[4]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 12:09
Оценка:
MA> Я полагаю, что препроцессор работает как ему и положено

вот! ВОТ!!!

Что именно означает "как положено" ?

то есть, в препроцессоре свой синтаксис, свой парсер, своё дерево.
В этом дереве свои узлы (#region, например, и т.п.) иерархически вложенные друг в друга

А весь остальной текст для препроцессора является Trivia.

И так для каждого этапа разбора, например при разборе концов строк — концы строк — это узлы, всё остальное — Trivia
при разборе XML-комментариев — комментарии это SyntaxNode, всё остальное — Trivia.

Почему они явно не ввели "этапы разбора", чтобы это всё было доступно?

MA> Удалили узел — а часть trivia которыми он вроде как владел — остались? Ну или наоборот, удалились.


При удалении узла Trivia и должна оставаиться. Дерево абстрактное.
Удаление — это алгоритм, он разный для разных грамматик.

Не надо было делать поле Parent у Trivia. Точнее это не тот Parent, который нужен для корректного удаления.

Надо было делать Extension-методы для Trivia вместо этого, для каждой грамматики — свои.
Отредактировано 17.07.2017 13:02 Arsen.Shnurkov . Предыдущая версия .
Re[5]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 13:03
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Почему они явно не ввели "этапы разбора", чтобы это всё было доступно?

Вы забываете простую вещь — Roslyn, это не компилятор, в котором можно выделить достаточно независимые классические фазы компиляции (или этапы разбора, если угодно).
Roslyn — это набор языковых сервисов, которые используются для всего: для создания компилятора, для раскраски синтаксиса в VS, для построения анализаторов, ...

Вот скажите, например, на каком "этапе разбора" должна работать раскраска в VisualStudio? А на каком анализатор наподобие StyleCop (который, например, что XML Doc комментарий содержит примечание по всем параметрам метода)? А на каком автоформатирование или рефакторинг (которые вполне себе могут различать пробелы для Identation и все остальные, хотя для всех остальных разницы нет никакой)?

Так что в приведенной вами цитате вполне нормально всё написано.

Because trivia are not part of the normal language syntax and can appear anywhere between any two tokens, they are not included in the syntax tree as a child of a node. Yet, because they are important when implementing a feature like refactoring and to maintain full fidelity with the source text, they do exist as part of the syntax tree.


Да, это не часть синтаксического дерева, но просто выкинуть или заменить на один узел "whitespace" они тоже не могут (тем более, что там не только whitespace).
Re[6]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 13:22
Оценка:
МР> просто выкинуть или заменить на один узел "whitespace" они тоже не могут (тем более, что там не только whitespace).

Я не говорю, что надо выкидывать совсем.
Я не предлагаю конкатенировать их (там же есть класс SyntaxTriviaList, который как раз конкатенирует)

Я против того, что
1) у Trivia родителем является смежный SyntaxNode (вместо того, чтобы это был узел более высокого уровня);
2) что Trivia разбивается по переводам строк
3) что Trivia не общая для левого и правого узла
Re: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 13:30
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Спрашивается, почему нельзя (неудобно) было сделать Trivia доступными из обоих смежных токенов (раз уж она между ними находится)?

А что вы от этого выиграете?
А у текущей схемы есть один достаточно четкий плюс — у каждой Trivia есть только один токен-владелец, а значит, у двух соседних токенов (вместе с их Trivia) не будет не будут пересекаться Spans.

Возможно, были еще какие-то иные соображения, почему сделано именно так — надо спрашивать у непосредственных разработчиков.
Re[2]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 13:40
Оценка:
МР> четкий плюс — у каждой Trivia есть только один токен-владелец

У моей схемы точно такой же (но другой) "плюс" — у каждой Trivia только один узел-владелец.

Так что этот аргумент ниочём.

МР> значит, у двух соседних токенов (вместе с их Trivia) не будет не будут пересекаться Spans.


И без Trivia у них не будут пересекаться TextSpan, и что?

Так что этот аргумент ниочём.


МР>Возможно, были еще какие-то иные соображения


да. какие?
Re[7]: зачем SyntaxTrivia входит в состав токенов?
От: Mystic Artifact  
Дата: 17.07.17 13:45
Оценка: +1
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>2) что Trivia разбивается по переводам строк

Дак в том то и вся прелесть: хомячим слева всё подряд, а справа — до перевода строки. Таким образом комменты сверху сами лепятся нужному узлу.
Re[7]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 13:48
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Я против того, что

Ок, я понял.
Не могу сказать точно, ибо не разработчик, поэтому только предположения:

AS>1) у Trivia родителем является смежный SyntaxNode (вместо того, чтобы это был узел более высокого уровня);

Я так понимаю, задача исходно была убрать из непосредственно из дерева все, не относящиеся к анализу элементы, т.е. Trivia. Значит делать Trivia просто одним из типов Node — не вариант
Можно ли их было "спрятать" внутри родительского Node? Наверняка. Только тогда мы не сможем для хранения Trivia использовать простой список, т.к. нам нужно будет хранить набор списков с указанием между какими двумя дочерними узлами они расположены.
С привязкой к дочерним узлам это решается просто.

AS>2) что Trivia разбивается по переводам строк

AS>3) что Trivia не общая для левого и правого узла
Как я уже писал в соседнем ответе, наличие ровного одного узла-владельца, дает нам отсутствие пересекающихся подстрок текста (Span).
А как разбивать — выбрали самый простой вариант.

Кстати, разбивка идет не всегда по переводу строки. Например, многострочный комментарий, может начаться сразу за последним токеном в строки, но владельцем будет следующий за ним токен (либо токен-признак конца файла)
Re[3]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 13:52
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>У моей схемы точно такой же (но другой) "плюс" — у каждой Trivia только один узел-владелец.

В вашей схеме явно присутствует узел Trivia, который может быть, а может не быть.
В схеме Roslyn такого узла нет никогда.

AS>И без Trivia у них не будут пересекаться TextSpan, и что?

А с Trivia, если владельцами будут 2 соседних токена, как вы предлагали в первом сообщении, они пересекаться будут.

AS>да. какие?

Не знаю, но вы можете задать вопрос разработчикам (или поискать среди Issues, может быть кто-то уже интересовался).
Re[8]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 13:56
Оценка:
МР> делать Trivia просто одним из типов Node — не вариант

Я не предлагаю делать Trivia подтипом SyntaxNode. Я не предлагаю вставлять Trivia в ChildNodeList

МР> нам нужно будет хранить набор списков с указанием между какими двумя дочерними узлами они расположены.

Зачем? Я же не предлагаю убирать свойства получаения правой и левой Trivia у SyntaxNode.
Поэтому хранить ДРУГИМ списком — вполне нормально.

МР> многострочный комментарий, может начаться сразу за последним токеном в строки, но владельцем будет следующий за ним токен (либо токен-признак конца файла)


Не верю:

int a = 0; ///<summary>
///</summary>
int b = 0;
Re[4]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 13:59
Оценка:
МР> если владельцами будут 2 соседних токена, как вы предлагали в первом сообщении, они пересекаться будут.

Это в том случае, если возвращая границы SyntaxNode всегда добавлять левую и правую Trivia.
А не надо этого делать!

Надо просто возвращать границы SyntaxNode. А если нужно с комментарием — то это уже специфика грамматики, которая должна быть видна в более высоком узле AST
Отредактировано 17.07.2017 14:00 Arsen.Shnurkov . Предыдущая версия .
Re[8]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 14:06
Оценка: 4 (1)
Здравствуйте, Mystic Artifact, Вы писали:

MA>Здравствуйте, Arsen.Shnurkov, Вы писали:


AS>>2) что Trivia разбивается по переводам строк

MA> Дак в том то и вся прелесть: хомячим слева всё подряд, а справа — до перевода строки. Таким образом комменты сверху сами лепятся нужному узлу.
Там чуть сложнее: если до перевода строки найдется элемент, который является многострочным (тот же многострочный комментарий, который реально располагается на нескольких строках), он относится к следующему токену.

Вообще, конечно, вопрос — почему бы их просто без разбора не прицеплять или к тому, или к тому токену. Не знаю.
Re[9]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 14:18
Оценка:
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Я не предлагаю делать Trivia подтипом SyntaxNode. Я не предлагаю вставлять Trivia в ChildNodeList

А что принципиально поменяется? При разборе вам всё равно их придется пропускать. Так зачем они там? Что вы выиграете?

МР>> нам нужно будет хранить набор списков с указанием между какими двумя дочерними узлами они расположены.

AS>Зачем? Я же не предлагаю убирать свойства получаения правой и левой Trivia у SyntaxNode.
AS>Поэтому хранить ДРУГИМ списком — вполне нормально.
В смысле хранить сразу в двух списках? Или как?

Вот у вас есть узел представляющий арифметическое выражение. Там может быть сколько угодно пробелов, табуляций и переводов строк между элементами.
Сейчас их в дереве нет вообще — там только токены. А что будет в вашей схеме?

AS>Не верю:

AS>int a = 0; ///<summary>
AS>///</summary>
AS>int b = 0;

Проверьте — возьмите визуализатор и посмотрите. Весь комментарий будет leading для "int" второго объявления переменной. А у точки запятой в первой строке trailing будет только пробел.
Причем ничего не изменится и если вы сократите до
int a = 0; ///<summary>
int b = 0;


— все, что начинается с "///" — будет leading у int из второй строчки.
Re[9]: зачем SyntaxTrivia входит в состав токенов?
От: Arsen.Shnurkov  
Дата: 17.07.17 14:21
Оценка:
МР>Там чуть сложнее: если до перевода строки найдется элемент, который является многострочным (тот же многострочный комментарий, который реально располагается на нескольких строках), он относится к следующему токену.

Это противоречит WhitePaper (хотя она, конечно, оговаривается, что не финальная спецификация).

Вообще, глядя на этот красно-зелёный маркетинговый хайп
в голову приходит, что GreenNode — это недоделанный узел из SPPF — http://www.bramvandersanden.com/post/2014/06/shared-packed-parse-forest/
разделим его на два — одна часть с длинной, другая часть с индексом и списком собранных нетерминалов.

Покрасим новые узлы в три цвета (в цвета русского флага, естественно) и будем громко орать что ещё эффективнее в парсинге, чем у MS
Re[10]: зачем SyntaxTrivia входит в состав токенов?
От: Михаил Романов Удмуртия https://mihailromanov.wordpress.com/
Дата: 17.07.17 14:28
Оценка: 2 (1)
Здравствуйте, Arsen.Shnurkov, Вы писали:

AS>Вообще, глядя на этот красно-зелёный маркетинговый хайп

Я окончательно перестал вас понимать. Причем здесь маркетинг?
Не нравится название, присоединяйтесь к обсуждению https://github.com/dotnet/roslyn/issues/19985 — возможно переименуют.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.