🔥

Тред (RReverser)


В общем, попробуем таки реализовать кастомный синтаксис для слайсов - a[2:10] -> a.slice(2, 10). Но наверное завтра, большинство уже спит.
Насчет этого - в первую очередь стоит создать папку для проекта и в ней npm i acorn ast-types escodegen twitter.com/jsunderhood/st…

Acorn стал расширяемым относительно недавно, поэтому API-шка пока со странностями, но зато есть возможность добавлять что-то без форка.

В первую очередь создадим плагин для синтаксиса. Для этого идем в сорцы и смотрим куда мы хотим добавить свой метод. github.com/marijnh/acorn/…

(Disclaimer: я плагин для этого синтаксиса еще не писал, всё пишу вместе с вами в риалтайме, поэтому возможны баги :) )

В первую очередь находим parseExpression. Но он покрывает выражения типа a+b,c+d (с запятыми между ними) как одно целое. Не интересно.

Он вызывает parseMaybeAssign, который покрывает как раз элементы - если добавим здесь, то a+b:c+d будет читаться как (a+b):(c+d) а не иначе.

По-моему, такой приоритет нашего оператора вполне интуитивен и лучше чем что-то типа (a)+(b:c)+(d). Поэтому здесь и остановимся.

А нет, подождите (я же говорил, будут баги :) ). На этом уровне мы также покроем a=b:c как (a=b):(c), что уже не очень логично. Идем ниже.

parseMaybeConditional может сработать, но a ? b : c : d получается неоднозначным - или же (a ? b : c) : d или a ? (b : c) : d.

Эта проблема - случай более общей, известной как dangling else и присуща многим языкам. en.wikipedia.org/wiki/Dangling_…

Думаю, на проблему dangling else мы пока можем забить (наверное, так же говорили разработчики C и Pascal) и будем внедряться здесь.

Код в твиттер писать проблематично и можно только по частям, поэтому лучше gist с комментами. gist.github.com/RReverser/359a…

Подозреваю, несмотря на комментарии, некоторые моменты без документации (да-да, знаю :( ) могут быть непонятными. Задавайте вопросы сейчас.

Сам код и правда не сложный, там больше места заняли комменты. Проверить, что парсинг работает, можно в консоли.
notion image

Здесь мы видим структуру ESTree - типы нод, их свойства, позиции начала-конца и - да - ноду, созданную нашими собственными руками.

Жду фидбека, что у кого-то получилось прежде чем продолжать :)

Переходим к трансформеру. Для этого и используем ast-types, хотя можно было бы и любой другой аналог типа esrecurse / estraverse.

Просто в ast-types есть удобные "фабрики" нод вместо того чтобы писать обьекты вручную в виде { type: "QuestionNode", answer: 42 }.

Вот собственно написал скрипт для транспайлинга дерева - опять-таки, не стесняйтесь задавать вопросы: gist.github.com/RReverser/359a…

Принцип простой: 1) регистрируем наш нестандартный тип, чтобы его можно было распознать; 2) ищем его ноды в дереве; 3) заменяем на вызовы.

Всё что остаётся - набросать какой-нибудь CLI, который будет читать файлы, парсить строку, трансформировать AST и генерировать код.

К примеру как-то так: gist.github.com/RReverser/359a… Понятно, что можно развивать, добавить сорс-мапы и т.д., но в целом наш транспайлер готов.

Надеюсь, было более-менее понятно и интересно, но я ещё буду здесь для любых вопросов :)

Ну и да, собственно как проверить транспайлер. Создайте файл test.js, в нём "var a = [1,2,3,4]; var b = a[1:3];". И запустите скрипт :)

В test.out.js должен появиться var a = [1,2,3,4]; var b = a.slice(1, 3);