Понять, что такое транспайлеры и какова их роль в программировании, поможет следующий пример. Представим, что вы разрабатываете софт для TV-приставок и вам нужно добавить калькулятор на все приставки определенной фирмы. Есть одно но — некоторые приставки не обновлялись уже 7 лет и могут работать только со старой версией языка, на котором написан калькулятор. Тут появляется выбор:

transpilers, cover

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

Транспиляция — преобразование программы, написанной на одном языке программирования в качестве исходных данных, в эквивалентный код другой версии этого языка или в другой язык программирования того же уровня абстракции.

Когда нужна транспиляция?

Рассмотрим практический пример, в котором пригодится транспайлер. За основу возьмем кейс с обновлением софта в TV-приставках, но дополним его деталями.

Калькулятор запускается на встроенном браузере TV-приставки и написан на JavaScript последней версии. Также учтем, что приставки выпускались каждый год с ограниченным сроком поддержки и сейчас мы имеем множество устройств с разными версиями браузера (а, следовательно, и отличающиеся версии поддерживаемого JS-кода). Кроме того, браузер пользователя давно не обновлялся и код на JS, который может там работать, сильно отличается от текущих версий языка.

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

Как используют транспайлеры?

Тринспайлеры широко используются во многих областях программирования. В целом можно выделить две основных области применения:

Как работают транспайлеры?

В качестве примера рассмотрим работу транспайлера над возведением в квадрат кода на JS:

a ** b

Вот как выглядит то же преобразование, проведенное с помощью объекта Math — он и использовался для операций по возведению в квадрат в старых версиях языка:

Math.pow(a, b)

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

Преобразование исходного кода в абстрактною форму

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

transpilers, tokens

transpilers, AST

Трансформация AST

После преобразования в абстрактную модель происходит трансформация, которая производит все необходимые для дальнейшей работы изменения в AST.

На этом этапе дерево из предыдущего шага изменяется: трансформация меняет текущий код на код на предыдущей версии языка. В данном случае оператор умножения заменяется на вызов выражения, при этом его операнды становятся аргументами выражения (Math.pow):

transpilers, transformedAST

Генерация конечного кода

Когда все изменения внесены, транспайлер берёт трансформированное AST кода и на его основе генерирует новый код.

transpilers, generate

В итоге код из начального состояния проходит ряд преобразований (анализ -> трансформация -> генерация) до конечного состояния — этот процесс и называется транспиляцией.

Обратная связь

После всех преобразований мы получили конечный код, который работает на нужной нам версии языка. Но представим, что после трансилиляции в нашей программе появились ошибки. Как понять, где именно находится ошибка, если она ссылается какое-то место в трансипилированном коде (который может значительно отличаться от того, что мы писали изначально)?

Использование транспайлеров может затруднить отладку, когда нам нужно найти точное место поломки в исходном коде по транспилированному коду. В таких случаях используются различные утилиты, позволяющие сопоставить результат транспиляции с оригинальным кодом. Например, в JS есть утилита SourceMap, которая в процессе создания конечного кода создает файл-маппер — с его помощью можно связать исходный и конечный код.

Инструменты (реализации) транспиляции кода

Для фронтенд-разработки основной инструмент транспиляции — Babel. Он позволяет не только выполнять транспиляцию между версиями, которую мы рассмотрели выше, но и:

Среди транспиляторов, которые трансформируют код на бэкэнд языках программирования в код на других языках, популярностью пользуются:

Итого

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

На данный момент реализовано множество различных транспайлеров (Babel, Vala, Typescript transpiler, Bridge и другие), каждый из них решает свою задачу по-своему, но общий принцип работы транспайлеров похож у всех.

transpilers, scheme

Исходный код преобразуется в абстрактное синтаксическое дерево, далее AST трансформируется в структуру, которая соотносится с конечным кодом, и из этой структуры генерируется необходимый нам код.

Дополнительные материалы