Pull to refresh
8
0
Роман Ивонин @ivoninroman

Программист

Send message

Приходите к нам работать, когда будем нанимать разработчиков, и это будет одним из приятных бонусов

Исходники на гитхабе, просто в приватном репозитории!


Если коротко — выход в опен-сорс это дополнительные затраты, и разовые, и фоновые. Вроде и клёво, а вроде и пока не готовы. Но смотрим в этом направлении.


Если будем опенсорсить — разумеется, напишем здесь

Смертные, когда нужно сделать что-то минимально сложное и из реальной жизни, в sql пишут if exists () begin...


Я понимаю мысль, да. Но клиенты приходят и говорят "мы хотим иметь в письмах условия Если-Иначе, и циклы". Наш язык даёт им это в таких терминах, а Mustashe требует форматирования мозга для начала.


Но в любом случае, красота, понятность и прочие хараектеристики синтаксиса бесконечно далеки от объективности, так что тут спора интересного не выйдет.

В процессе, когда выработались паттерны, я понял, что F# подходит идеально примерно для 80% того, что надо написать!


Но факторы типа сжатых сроков разработки, отсутствия опыта написания enterprise-кода на F# и того, что у нас вся разработка на C#, победили, увы

Инопланетный синтаксис и отсутствие возможности исследования параметров в шаблоне, как и везде

Да, про него! На самом деле, конечно, потом я разобрался. Но есть ощущение, что не зная хорошо синтаксиса и фиолософию, ничего в шаблоне по мелочи подправить/дополнить простому смертному нельзя.

Мы используем Standard, и вообще-то у него же владелец — сам создатель Antlr (https://www.nuget.org/profiles/parrt), куда еще больше доверия-то? Да и Харвеллд в авторах там тоже есть.


Я так понимаю, Харвелловский рантайм подходит, если использовать alternate C# target от него же, а мы исторически на стандартном.


Есть где-то почитать про сравнение таргетов? Это всегда интересовало, хотя сейчас уже, конечно, сложно представить мотивацию перейти с одного на другой.

Вроде, NuGet тогда сильно запаздывал: antlr был уже 4.6, а пакет еще 4.5.x или что-то такое. Не самое важное, в общем, но точно помню, что не могли использовать пакет.

Про регистронезависимый стрим осознал, записал себе попробовать в пресловутовый список доработок, спасибо, полезно.


Тут я не очень понял. Да, можно использовать состояние, а можно передавать контекст у визиторов, в котором и будет состояние. Приведите пример, в котором в вашем случае состояние не будет использоваться, а в случае большого визитора — будет. И чем обращение к parent плохо?

Я называю этот паттерн parent.parent.parent.parent, думаю, он каждому разработчику на WinForms/javascript знаком, как и удовольствие от поддержки такого кода. Это не совсем тот случай, но мне кажется идеологически правильным, чтобы разбор правила был контекстно-независимым, как и грамматика.


Сложно привести пример, не углубляясь в нашу специфику — скорее всего, не для каждой грамматики это актуально. Предположим, у нас есть правило, описывающее доступ к переменной, что-то вроде variable { Identifier }. В зависимости от контекста это может быть логическим выражением (в конструкции A and B) или арифметическим выражением (A + B). Удобно в ArithmeticExpressionVisitor и BooleanExpressionVisitor иметь по правилу, VisitVariable, которые обернут использование переменных в соответствующие классы для работы с выражениями нужного типа.


Тут, наверное, всё упирается в специфику грамматики и использований результата разбора. Как минимум, наш подход тоже отлично работает и имеет плюсы. По ощущениям — очень понятно, атомарно и логично так работать (плюс за типизацию я сильно топлю, и generic-проверки на этапе компиляции котирую выше обработок исключений). Думаю, кому-то может эта идея пригодиться.


На какой диаграмме? Почему усложнение? По-моему наоборот упрощение: нужно просто описать алфавит из 26 букв и использовать как-то так: ABC: A B C. Фрагменты в лексере преобразуются в литералы, так что на уровне обработки вообще разницы не будет.

Мы генерируем синтаксические диаграммы как дополнительную документацию о грамматике, получается наглядно. Надо проверить, как это отразится на них, но почти уверен, что как-нибудь эти лишние кусочные псевдоправила и лишний уровень сложности в описании лексем будет виден. Если нет — прекрасно, но в любом случае, подход со стримом больше понравился.

Разработка движка — осень 2015-го, потом первые 90% статьи случились зимой 2016-го, потом "я включил Алдан и немножко поработал", и вот мы в весне 2017-го.


Тогда еще не было Antlr.Runtime как nuget-пакета, и приходилось его как dll подкладывать, книжка не совсем соответствовала реализации ANTLR 4.5, ну и по мелочи радости. И статей вроде вашей вот находилось гораздо меньше.

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


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

Автоматически html не экранируем, хотя концептуально хотим.
Одно из препятствий — наличие у клиентов старых рассылок, где, собственно, куски вёрстки подставляются параметром. Это не нравится и ставит под вопрос смысл шаблонизатора для этих рассылок, так что пытаемся это изжить.

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

Спасибо за комментарий, приятно обсудить всё это с кем-то предметно.


Я бы рекомендовал все же использовать фрагментные лексемы, чтобы грамматика не выглядела так ужасно. Если язык полностью регистронезависимый, то лучше использовать свой регистронезависимый поток

Регистронезависимый поток не нравится тем, что когда захочется вывести ошибку с именем переменной или, тем более, использовать строковую константу — они будут не в том виде, в котором написал автор шаблона. Собственно, как у вас и написано — сложно сделать выборочную регистронезависимость.


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


Код упростился, а также избавился от лишних аллокаций других визиторов как у вас

Ну, насчет аллокаций мы особо не паримся, потому что каждый инстанс визитора очень легковесный, а время его жини очень короткое, и даже при сложном дереве шаблона это всё абсолютно теряется на фоне кусков "payload" — собственно html-вёрстки, которая внутри блоков.


Да и в принципе вопрос перформанса на этапе компиляции шаблона для нас пока не стоит, потому что у нас режим работы "одна компиляция, миллионы рендеров".


А мы в Swiftify наоборот отказались от такого разбиения и пришли как раз к гиганскому визитору. Код упростился

Интересно! Но попробую отстоять свой подход:


  • наши визиторы больше про single responsibility principle — согласитесь, что partial class это не совсем то
  • один визитор не даёт возможности по-разному разбирать одно синтаксическое правило в разных контекстах (без введения какого-то состояния или обращения к parent разбираемого нода)
  • пожалуй, самое важное — все методы визитора возвращают один тип. Это значит, что результат придётся рано или поздно кастить, а это, мы же понимаем, потенциальная ошибка в рантайме. В вашей статье так и написано — var first = (Expression)VisitExpression(context.expression(0));. А у нас визитор, разбирающий выражения, возвращает IExpression, визитор про вызову функций — FunctionCallExprsession. При этом никаких кастов не требуется, и неправильное использование визиторов просто не компилируется. Это, пожалуй, и есть ключевой принцип, по которому я решаю, отдельный это визитор или нет: какой тип он должен в итоге возвращать.

Про опасность VisitChildren (равно как и дефолтного AggregateResult) мы в курсе, это, пожалуй, самое неприятное поведение в базовой реализации. У меня есть желание в нашем базовом визиторе переопределить их, чтобы бросали исключение — тогда мы гарантируем, что всё. что есть в грамматике, покрыто набором визиторов. Пока руки не дошли.


Жалко, что вашей статьи не было на момент, когда писалась львиная доля описанного в статье, очень бы пригодилась при разработке. Про внутренний кэш antlr runtime, кстати, узнал только сейчас — очень любопытно. Попробую замерить эффект от него у нас на продакшне.

Словоформы — через функцию-расширение: ${ forms(ProductCount, 'Товар', 'Товара', 'Товаров') }


Настройкой экранирования не заморочились пока, поскольку


  • крайне редкие последовательности в любом из известных видов текста (не случайно выбрано два символа, а не один)
  • основной медиум — html, где доступно энкодирование через амперсанд-значения, если очень приспичит.

Понимаю идею, но всё равно не могу пожалеть, что мы так не сделали. Впрочем, возможно, для каких-то задач это подходит, почему нет.

Прочитал, интересно, и боль знакомая местами прямо сквозит. Нам повезло в том плане, что сами придумывали грамматику и сразу в очень формальном виде, это свело неприятности на этапе общения с ANTLR к минимуму.

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

Я правильно понимаю, что каждому шаблону соответствует отдельная dll?


В принципе, звучит работоспособно, но:


  • слегка на костылях, всё-таки. Неочевидный код, ошибка в котором — серьезная security-уязвимость
  • у нас одновременно в работе бывает несколько тысяч шаблонов, каждую минуту некоторые из них меняются другими. Сложно оценить перформанс этой системы со сборками и рефлексией

А нового разора, когда анализировали существующие варианты, по-моему, вообще ещё не существовало.


В общем, не топлю за то, что однозначно Razor плохо, просто вот по совокупности много всем стало казаться, что слишком много "но".

Liquid рассматривали очень плотно, не понравился тем, что почти не поддерживается (видно по гитхабу) и, насколько помню, туго расширяется в тех местах, где нам надо.

1

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity