В байткод-компиляторе реализован простой механизм AST-трансформации,
распознающий и подменяющий определенные AST-конструкции. Измененные
конструкции порождают байткод иной, чем изначальные. Исходники преобразований
находятся в lib/compiler/ast/transforms.rb
.
TODO: описать plugin-архитектуру компилятора.
Поскольку базовые (core) библиотеки построены из тех же блоков, что и любой
другой Ruby-код, а Ruby — язык динамический, с открытыми классами и
отложенным связыванием, появляется возможность изменять фундаментальные классы
вроде Fixnum
таким образом, что нарушается семантика, от которой зависят
другие классы. К примеру, представьте себе такое нововведение:
class Fixnum
def +(other)
(self + other) % 5
end
end
Хотя переопределение арифметического_с_фиксированной_точкой_плюса в
остаток_от_деления_на_пять вполне возможно, это действие обязательно
заставит некоторый класс вроде Array
не смочь в нужный момент вычислить,
например, корректную длину. Динамическая натура Ruby — одна из его любимых
черт, но она же в некотором смысле и палка о двух концах.
Одна из стандартных библиотек, mathn
, переопределяет Fixnum#/
в опасной и
несовместимой манере. Библиотека алиасит Fixnum#/
в Fixnum#quo
, который по
умолчанию возвращает Float
.
Из-за этого сделан специальный плагин компилятора, который, встречая #/
,
порождает иное имя метода. Компилятор вместо #/
выдает #divide
. Численные
классы Fixnum, Bignum, Float
и Numeric
все определяют этот метод.
Для запуска плагина безопасная трансформация математики включается в момент
компиляции Core libraries. Когда компилируется обычный «юзер-код», плагин
выключен. Это делает возможной поддержку mathn
без повреждения базовых
библиотек и принуждения к использованию прочих нехороших приемов.