Сложность написания статического компилятора JavaScript заключается в том, что в общем неразрешимо трудно определить, на какие объекты ссылаются в любой программной точке или какие функции вызываются.Я мог бы использовать тот факт, что JavaScript является динамическим, чтобы решить, какую функцию вызывать, основываясь на выводе некоторой машины Тьюринга.Например:
var functionName = RunTuringMachineAndReportOutputOnTape(myTM, myInput);
eval(functionName + "();");
На данный момент, если у вас нет предварительных знаний о том, что такое myTM
и myInput
, доказуемо невозможно решить, какая функция будет вызыватьсявызов eval
, поскольку невозможно определить, что находится на ленте машины Тьюринга, если она останавливается (вы можете уменьшить проблему остановки до этой проблемы).Следовательно, независимо от того, насколько вы умны, и независимо от того, насколько хороши статические анализаторы, которые вы создаете, вы никогда не сможете корректно статически разрешать все вызовы функций.Вы даже не можете ограничить набор функций, которые могут быть вызваны здесь, поскольку выходные данные машины Тьюринга могут определять некоторую функцию, которая затем выполняется вышеуказанным кодом.
Что вы можете сделать, это скомпилировать код, который всякий раз, когдафункция вызывается, включает дополнительную логику для разрешения вызова и, возможно, использует такие методы, как встроенное кэширование , чтобы ускорить процесс.Кроме того, в некоторых случаях вы можете доказать, что вызывается определенная функция (или что будет вызываться одна из небольшого числа функций), а затем жестко закодировать в этих вызовах.Вы также можете скомпилировать несколько версий фрагмента кода, по одной для каждого общего типа (объектный, числовой и т. Д.), А затем выдать код для перехода к соответствующей скомпилированной трассе на основе динамического типа.