@popov654
Специалист в области веб-технологий

Как грамотно написать интерпретатор?

Здравствуйте,

Я хочу в качестве экспериментальной работы написать на Java базовый интерпретатор JavaScript кода. Без JIT компиляции, без всяких сложных API, самый минимум. Встроенные объекты Math, String, Date, поддержка прототипов, вызов функций, области видимости, основные операторы, работа с переменными, вывод в консоль и алерты.

Но я не идеально знаю Java, и ещё меньше у меня знаний в области проектирования ПО. Прошу подсказать, как грамотно реализовать всё вышеизложенное. Основные вопросы:

1. Как в рантайме правильнее разграничить вызов нативных (реализованных на Java) функций и вызов функций на JavaScript (это весьма разные сущности)?
2. Как оптимальнее хранить scopes? Через Hashtable/HashMap в виде вектора (имитация стека) - нормальное решение?
3. Как правильно организовать поиск функций в цепочке прототипов объекта? Например, мы ищем функцию; она находится в прототипе, ссылку на который мы храним. Но при вызове такая функция должна работать с полями данных исходного объекта, а не прототипа, или прототипа прототипа и т.д. В JavaScript всё будет в такой ситуации работать корректно, а как такое грамотно эмулировать?
4. Эффективный алгоритм разбора выражений тоже не помешал бы. Как быстро разобрать строку, зная приоритеты операторов, корректно выделить все круглые скобки, которые могут быть вложены друг в друга, и т.д. Ссылки на любую литературу, в том числе англоязычную, приветствуются.

Заранее спасибо за советы.
  • Вопрос задан
  • 318 просмотров
Решения вопроса 1
  • 1. Как в рантайме правильнее разграничить вызов нативных (реализованных на Java) функций и вызов функций на JavaScript (это весьма разные сущности)?

    Ну сделай разные классы для разных функций. JS динамически типизированный, так что в основном ты все равно будешь работать с каким-нибудь базовым абстрактным JsValue, от него и унаследуй классы функций. У класса JsValue сделай метод

    JsValue call(scope: JsScope, context: JsValue, args: ArrayList<JsValue>)

    который кидает TypeError: бла-бла-бла is not a function, а в классах функций (JsNativeFunction и JsFunction) переопредели его чтобы возвращал что-то.

    2. Как оптимальнее хранить scopes? Через Hashtable/HashMap в виде вектора (имитация стека) - нормальное решение?

    Я не эксперт, но я делал скоуп в виде хешмапа со ссылкой на родительский скоуп (и так по ссылкам можно было соответственно дойти до глобального скоупа), вроде нормальный вариант.

    3. Как правильно организовать поиск функций в цепочке прототипов объекта? Например, мы ищем функцию; она находится в прототипе, ссылку на который мы храним. Но при вызове такая функция должна работать с полями данных исходного объекта, а не прототипа, или прототипа прототипа и т.д. В JavaScript всё будет в такой ситуации работать корректно, а как такое грамотно эмулировать?

    Не вижу проблемы. x.foo(42) разворачивается во что-то типа этого:

    JsObject xVar = scope.getVar("x");
    xVar
        .attr("foo")    // ищет атрибут в объекте или в прототипе
        .call(scope, xVar, Arrays.asList(JsInt(42)));

    Второй параметр метода call - это и есть контекст, то есть объект у которого вызывается метод.

    4. Эффективный алгоритм разбора выражений тоже не помешал бы. Как быстро разобрать строку, зная приоритеты операторов, корректно выделить все круглые скобки, которые могут быть вложены друг в друга, и т.д. Ссылки на любую литературу, в том числе англоязычную, приветствуются.

    Тут вряд ли что-то толковое подскажу, кроме как посмотреть в сторону ANTLR и аналогов.

    P. S.
    Немного литературы по теме
    Ответ написан
Пригласить эксперта
Ответы на вопрос 4
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы