inkytonik / kiama

A Scala library for language processing.
Mozilla Public License 2.0
42 stars 14 forks source link

ScalaJS support #2

Open inkytonik opened 4 years ago

inkytonik commented 4 years ago

Originally reported on Google Code with ID 64

It will be great if you would add scalajs support, this will allow to use kiama on the client and in cross scala/scalajs libs

Reported by antonkulaga on 2014-05-06 16:40:58

inkytonik commented 4 years ago

Yes, I agree that this would be good to have. In the past we have not tried to do it since we make some use of macros and ScalaJS didn't support those. However, I notice that there is some support for macros now. We will try when some time becomes available and see how it goes. I will report back here once we have something to say.

inkytonik commented 4 years ago

It appears that we will also have a sticking point over reflection. The Kiama rewriting facility uses Java reflection via getConstructors so it can build a new value with the same class as a value that is being generically rewritten.

The ScalaJS docs say that there is some support for java.lang.Class but It's not clear whether getConstructors is included. Until we get a way to do that on the JS platform, we won't be able to move rewriting over.

inkytonik commented 4 years ago

Without knowing too much about Kiama, but might a type class like CanInstantiate[T] be an appropriate generalization of calling getConstructors directly? On the JVM there could be a default implicit which uses getConstructors whereas for ScalaJS one could create another solution.

Reported by Martin.Mauch on 2015-01-03 21:26:42

inkytonik commented 4 years ago

That might be a way forward. Do you know enough about the ScalaJS platform to suggest whether an implementation of this generic operation would be easy enough to write?

inkytonik commented 4 years ago

TBH, I didn't have the chance to use ScalaJS myself, so I posted the question on the mailing list:

https://groups.google.com/forum/#!topic/scala-js/NnSvK_FmEgc

Reported by Martin.Mauch on 2015-01-28 10:41:19

inkytonik commented 4 years ago

getConstructors() is not support on Scala.js, no, and will never be. Just like getMethods, getFields.

If a purely compile-time implementation via (possibly macro-generated) type-classes or factory methods is not possible, the standard way to instantiate "reflectively" instances of classes in Scala.js is via JS reflection.

With the @JSExport and @JSExportDescendentClasses annotations (see the doc at ttp://www.scala-js.org/api/scalajs-library/0.6.0-RC2/#scala.scalajs.js.annotation.package), one can force a class/constructor, or all the classes inheriting from a class or trait, to be exported to JavaScript under their fully qualified name. This forces these classes to be always emitted in the file .js file, because they cannot be dead-code-eliminated. But in exchange you get the ability to load them via JS interop: (example for Scala.js 0.6.x, currently in RC2)

package foo

import scala.scalajs.js
import js.annotation.JSExport

@JSExport // in 0.5.x, need to write @JSExport("foo.Bar")
class Bar(val x: Int)

val instance = instantiateReflectively(classOf[Bar])(5)

def instantiateReflectively[A](cls: Class[A])(args: Any*): A = {
  val ctor = (js.Dynamic.global /: cls.getName.split("\\.")) { (prev, part) =>
    prev.selectDynamic(part)
  }
  js.Dynamic.newInstance(ctor)(args.asInstanceOf[Seq[js.Any]]: _*).asInstanceOf[A]
}

Reported by sjrdoeraene on 2015-01-28 10:57:39

inkytonik commented 4 years ago

Thanks for taking the time to help us out. Your solution seems to be a good one. I will take a look in more detail when I have a bit more time to investigate the JS direction.

BTW, perhaps you can answer something else for me. Is there a standard approach to publishing ScalaJS compiled libraries. For the JVM version we publish via Maven Central but I'm not aware of the convention for ScalaJS. If we are to make a ScalaJS version of Kiama how would we best make it available to user?

inkytonik commented 4 years ago

You can publish to Maven central without any problems. The only difference is artifact name. Scalajs sbt plugin automatically adds "sjs-0.6.0" (or whatever scalajs version you are using) to the artifact name. Everything else is the same, most of scalajs projects are p suffix publshed either to maven central or to bintray.

In your case it is better to to with 0.6.0 version of ScalaJS as it has some nice features, like CrossProjects (http://www.scala-js.org/api/sbt-scalajs/0.6.0-C2/#org.scalajs.sbtplugin.cross.CrossProject) that make it easy to share source between projects

Reported by antonkulaga on 2015-01-29 01:25:32

inkytonik commented 4 years ago

As was said, you publish Scala.js libraries exactly like Scala/JVM libraries: on Maven Central or on Bintray, or anything you may prefer. The mechanism is exactly the same (publish/publishLocal/publishSigned/etc.). Similarly, you use libraryDependencies to depend on other Scala.js libraries, with the slight variation that you use %%% instead of %% in the module specification.

When publishing a cross-compiling library, it is customary to give the same name setting to both the JVM and JS versions. The moduleName will therefore be the same. The Scala.js sbt plugin will automatically append a Scala.js-specific suffix to the artifact that is published. Just like sbt already appends a Scala-specific suffix such as _2.11. With Scala.js you therefore end up with a suffix like _sjs0.5_2.11. The %%% transparently resolves the appropriate artifacts.

Reported by sjrdoeraene on 2015-01-29 10:42:23

inkytonik commented 4 years ago

What is the status of this issue. I actually have an urgent need to use kiama in the browser. If possible I would like to attempt make the changes. If it proves too difficult is there a subset that would support ScalaJS now

Reported by solomono@mac.com on 2015-05-28 18:45:07

inkytonik commented 4 years ago

No support yet due to resource limitations in our group. Please let us know how we can help if you have a go. If you are willing to contribute the code back under the GPL we'd be happy to integrate ScalaJS support with the main distribution.

inkytonik commented 4 years ago

Myself and a colleague have an immediate requirement for this functionality, so we are willing to have a go. We have found the support in the Scala.js news group to be outstanding so we are hopeful that with your support also we might find success.

We certainly intend to contribute the code back if it meets your standards.

Reported by solomono@mac.com on 2015-06-04 15:11:10

inkytonik commented 4 years ago

Great! Please let us know how we can help. As you'll see from the discussion above, the likely tricky point will be getting the generic rewriting traversals to work, given their reliance on Java reflection at the moment.

inkytonik commented 4 years ago

This issue is a bit closer to some work now that the core project has been split from the extras.

b-studios commented 3 years ago

Just wanted to let you know that I have a fork of Kiama where I stripped out almost everything to make it easily compilable with scala-js:

https://github.com/b-studios/kiama/tree/scala-js

since I mostly use kiama for parsing and pretty printing, this is almost everything that is left :) However, it helped me to compile the Effekt compiler to JS and use it on the Effekt website

inkytonik commented 3 years ago

Thanks @b-studios. At the moment, unfortunately, I don't have time to work on the Scala JS support for the whole of Kiama. But I will check your cut-down version when I get to it.

inkytonik commented 3 years ago

From version 2.4.0 we have removed macro usage from Kiama which should help a JS version.