В общем, попробуем таки реализовать кастомный синтаксис для слайсов - 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…
Подозреваю, несмотря на комментарии, некоторые моменты без документации (да-да, знаю :( ) могут быть непонятными. Задавайте вопросы сейчас.
Сам код и правда не сложный, там больше места заняли комменты. Проверить, что парсинг работает, можно в консоли.
Здесь мы видим структуру 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);