Компиляция среды выполнения Scala.js в Javascript

Всем привет. Я хочу выяснить, как использовать инструменты Scala.js для компиляции выражений Scala в Javascript во время выполнения. Вот упрощенная установка, в качестве примера.

Скажем, у нас есть простой DSL, состоящий из Ctx => Boolean функций и логических операций над ними, а-ля следующее:

implicit class Simple[Ctx](f: Ctx => Boolean) {
  def &&(g: Ctx => Boolean): Ctx => Boolean = ctx => f(ctx) && g(ctx)
  def ||(g: Ctx => Boolean): Ctx => Boolean = ctx => f(ctx) || g(ctx)
  def unary_!: Ctx => Boolean = ctx => !f(ctx)
}

И давайте предположим, что у нас есть некоторые «строительные блоки», жестко закодированные, скомпилированные в Javascript и экспортированные следующим образом:

@ExportJSTopLevel("foo") def foo[Ctx](ctx: Ctx): Boolean = ???
@ExportJSTopLevel("bar") def bar[Ctx](ctx: Ctx): Boolean = ???
// and so on

Теперь из этих строительных блоков можно собирать простые логические выражения, такие как: foo && bar или foo || !bar и т. д.

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

Я нашел в Интернете несколько ссылок на загадочный класс под названием ScalaJSOptimizer где-то в инструментах Scala.js. Однако ссылки, предоставляемые этому классу, всегда не работают или показывают, что он принадлежит пакету, которого даже нет в последней версии артефакта «scalajs-tools».

Каков наилучший способ выполнить то, что я хочу сделать?


person silverberry    schedule 08.08.2017    source источник
comment
Я не понимаю половины того, чего вы пытаетесь достичь, но замена (давно мертвого) ScalaJSOptimizer StandardLinker, который является фабричным для Linker, важным методом которого является link.   -  person sjrd    schedule 08.08.2017
comment
То, что вы ищете, называется (по крайней мере, в контексте исследования Scala) глубоким внедрением (или его вариантом). Это активная тема исследования, а не что-то решенное. Лучшее, что я могу придумать для вашей конкретной проблемы, это написать небольшой компилятор JavaScript самостоятельно и eval результат.   -  person gzm0    schedule 10.08.2017


Ответы (3)


То, что вы пытаетесь сделать, возможно и было тщательно исследовано на многих языках (глубокое встраивание DSL). Чтобы достичь желаемого, вам нужно:

  1. Найдите или создайте фреймворк глубокого внедрения на Scala, который может выводить JavaScript.
  2. Убедитесь, что фреймворк компилируется с помощью Scala.js.
  3. Создайте свой DSL, используя эту структуру.

Фреймворки, которые я знаю, которые вы могли бы использовать:

  1. Лаборатория БД: я не думаю, что у нее есть серверная часть JS, но ее можно добавить для ваших нужд.
  2. LMS: имеет серверную часть JS, однако вы должны использовать Rep типы в своих DSL.

Вам нужно будет уточнить у авторов, компилируются ли эти фреймворки с помощью Scala.js и в каком состоянии находятся их бэкенды JS.

В вашем предложении делается попытка использовать Scala.js в качестве среды глубокого внедрения, но Scala.js нельзя скомпилировать с помощью Scala.js.

person vjovanov    schedule 10.08.2017
comment
Спасибо! На самом деле я начал пробовать библиотеку js-scala на основе LMS (github.com/js-scala/js-scala), но у меня возникли проблемы с работой с Rep[T], где T — класс case. Примеры, поставляемые с самой библиотекой, тривиальны, только с использованием примитивных типов. Какие еще сложные примеры вам известны? - person silverberry; 10.08.2017
comment
Позвольте мне перефразировать мой вопрос. Как предоставить собственный генератор кода для собственных типов доменов? - person silverberry; 10.08.2017
comment
Думаю, я понял это. - person silverberry; 10.08.2017

Я также не знаю, какова ваша конечная цель, но если вы действительно хотите скомпилировать Scala.js во время выполнения, вам лучше всего посмотреть исходный код для scalafiddle.io, который делает именно это, и начать с копирования что бы он ни делал, и изменить его оттуда.

Вот код, который занимается компиляцией из Javascript в IR Scala.js, а затем из IR в Javascript String:

Здесь интересны методы compile, link (fastOptJS и fullOptJS) и export. Я знаю, что StackOverflow не одобряет внешние ссылки, но код действительно слишком большой и корявый, чтобы его можно было воспроизвести здесь. Лучше всего клонировать этот репозиторий, открыть его в своей среде IDE и просмотреть, как код преобразует Scala.js code: String, поступающий в конструктор этого класса Compiler, через все промежуточные этапы до финального Javascript String, возвращено из метода export

person Li Haoyi    schedule 14.08.2017
comment
Но эта штука по-прежнему JVM, только нет? Или он настолько сильно взламывает scalac, что работает на JS? - person gzm0; 14.08.2017
comment
Да, это все еще JVM. Из первоначального вопроса мне было неясно, имелось ли в виду время выполнения на сервере или на клиенте. Это относится только к серверу - person Li Haoyi; 15.08.2017

Честно говоря, я думаю, что формулировка этого как «компиляция выражений Scala в Javascript во время выполнения» ведет к провалу. Scala.js не может скомпилировать Scala и, вероятно, не сможет этого сделать в ближайшем будущем — слишком большая часть инфраструктуры компилятора ориентирована на JVM.

Поэтому вместо этого я бы рекомендовал переформулировать проблему. Формально определите язык, с которым вы хотите иметь возможность работать во время выполнения. (Это вполне может быть подмножеством Scala.) Используйте синтаксический анализатор Scala.js, например FastParse, чтобы написать парсер для него, который генерирует абстрактные синтаксические деревья, и интерпретатор, который превращает эти синтаксические деревья в JavaScript.

Да, это небольшое усилие. Но это достижимо, а попытка скомпилировать произвольный Scala в JavaScript во время выполнения в Scala.js невозможна...

person Justin du Coeur    schedule 08.08.2017
comment
Спасибо. Но я не пытаюсь компилировать произвольный Scala в Javascript. Только логические операции над строительными блоками, которые уже скомпилированы в Javascript (см. выше). - person silverberry; 08.08.2017
comment
Интересно, можно ли для этого использовать js-scala.... (github.com/js- скала/js-скала) - person silverberry; 09.08.2017