Rewrite library, set up native image

This commit is contained in:
InversionSpaces 2023-06-13 15:48:27 +00:00 committed by Nick Pavlov
parent e3670f8bee
commit e56f5df835
2 changed files with 60 additions and 69 deletions

View File

@ -214,8 +214,21 @@ lazy val compiler = crossProject(JVMPlatform, JSPlatform)
lazy val `compiler-native-lib` = project
.in(file("compiler-native-lib"))
.enablePlugins(GraalVMNativeImagePlugin)
.settings(commons: _*)
.dependsOn(compiler.jvm, io.jvm, transform.jvm, `backend-air`.jvm)
.settings(
Compile / mainClass := Some("aqua.compiler.Library"),
graalVMNativeImageOptions ++= Seq(
"--verbose",
"--no-fallback",
// Uncomment next lines to use llvm backend
// and obtain bitcode files
// "-H:CompilerBackend=llvm",
// "-H:TempDirectory=temp", // Directory with bc files
"--shared" // Produce shared library
)
)
.dependsOn(`aqua-api`.jvm)
lazy val backend = crossProject(JVMPlatform, JSPlatform)
.withoutSuffixFor(JVMPlatform)

View File

@ -1,81 +1,59 @@
package aqua.compiler
import aqua.AquaIO
import org.graalvm.nativeimage.IsolateThread
import org.graalvm.nativeimage.c.function.CEntryPoint
import org.graalvm.nativeimage.c.`type`.CCharPointer
import org.graalvm.nativeimage.c.`type`.CTypeConversion
import aqua.io.AquaFileError
import aqua.files.{AquaFileSources, FileModuleId}
import cats.{Applicative, Functor, Monad}
import cats.data.{Chain, ValidatedNec}
import cats.data.Validated.Valid
import cats.data.Validated.validNec
import cats.effect.IO
import fs2.io.file.{Files, Path}
import cats.implicits.*
import aqua.SpanParser
import aqua.model.transform.TransformConfig
import aqua.model.AquaContext
import aqua.model.transform.Transform
import aqua.backend.Backend
import aqua.backend.AirFunction
import aqua.backend.Generated
import aqua.res.AquaRes
import aqua.parser.lift.FileSpan
import aqua.backend.air.AirBackend
import aqua.files.AquaFilesIO.summon
import org.graalvm.nativeimage.c.`type`.{CCharPointer, CCharPointerPointer, CTypeConversion}
import scala.annotation.static
import cats.effect.unsafe.implicits.global
import aqua.api.{APICompilation, AquaAPIConfig}
import aqua.backend.api.APIBackend
// This is neede for @static to work in object
class Library {}
object Library {
private final val path = Path("")
private class RawAquaSource[F[_] : AquaIO : Monad : Files](input: String, imports: List[String]) extends AquaFileSources[F](path, imports.map(Path.apply)):
override def sources: F[ValidatedNec[AquaFileError, Chain[(FileModuleId, String)]]] = {
Applicative[F].pure(Valid(Chain.one((FileModuleId(path), input))))
}
private class LocalBackendTransform(transformConfig: TransformConfig) extends Backend.Transform:
override def transform(ex: AquaContext): AquaRes =
Transform.contextRes(ex, transformConfig)
override def generate(aqua: AquaRes): Seq[Generated] = AirBackend.generate(aqua)
private class LocalAirValidator[F[_] : Applicative]() extends AirValidator[F]:
override def init(): F[Unit] = Applicative[F].pure(())
override def validate(airs: List[AirFunction]): F[ValidatedNec[String, Unit]] =
Applicative[F].pure(validNec(()))
private def compileF[F[_] : AquaIO : Monad : Files](input: String, imports: List[String]): F[ValidatedNec[AquaError[FileModuleId, AquaFileError, FileSpan.F], Chain[AquaCompiled[FileModuleId]]]] = for {
sources <- new RawAquaSource[F](input, imports).pure
transformConfig <- TransformConfig().pure
backendTransform <- new LocalBackendTransform(transformConfig).pure
validator <- new LocalAirValidator[F]().pure
result <- CompilerAPI
.compile[F, AquaFileError, FileModuleId, FileSpan.F](
sources,
SpanParser.parser,
validator,
backendTransform,
AquaCompilerConf(transformConfig.constantsList))
} yield result
@CEntryPoint(name = "compile") def compile(thread: IsolateThread, codePointer: CCharPointer): Int = {
@CEntryPoint(name = "compile")
@static
def compile(
thread: IsolateThread,
codePointer: CCharPointer,
resultPointer: CCharPointerPointer,
errorsPointer: CCharPointerPointer
): Int = {
val code = CTypeConversion.toJavaString(codePointer)
val program = compileF[IO](code, List.empty)
val result = program.unsafeRunSync()
val result = APICompilation
.compileString(
code,
imports = Nil,
aquaConfig = AquaAPIConfig(),
backend = APIBackend
)
.unsafeRunSync()
if (result.isValid) {
0
} else {
1
}
result.fold(
errors =>
errors.toChain.toList.zipWithIndex.foreach { case (error, i) =>
errorsPointer.write(i, CTypeConversion.toCString(error).get())
}
1
,
compiled =>
compiled.toList.flatMap(_.compiled).flatMap(_.air).map(_.air).zipWithIndex.foreach {
case (air, i) => resultPointer.write(i, CTypeConversion.toCString(code).get())
}
0
)
}
// Without main native-image refuses to work
@static
def main(args: Array[String]): Unit = ()
}