diff --git a/build.sbt b/build.sbt index edce76fa..f3545f37 100644 --- a/build.sbt +++ b/build.sbt @@ -21,7 +21,7 @@ name := "aqua-hll" val commons = Seq( version := { val aquaSnapshot = sys.env.getOrElse("SNAPSHOT", "") - if (aquaSnapshot.isEmpty()) aquaVersion else aquaVersion + "-" + aquaSnapshot, + if (aquaSnapshot.isEmpty()) aquaVersion else aquaVersion + "-" + aquaSnapshot }, scalaVersion := scalaV, libraryDependencies ++= Seq( @@ -212,6 +212,11 @@ lazy val compiler = crossProject(JVMPlatform, JSPlatform) .settings(commons) .dependsOn(semantics, linker, backend, transform % "test->test", res % "test->test") +lazy val `compiler-native-lib` = project + .in(file("compiler-native-lib")) + .settings(commons: _*) + .dependsOn(compiler.jvm, io.jvm, transform.jvm, `backend-air`.jvm) + lazy val backend = crossProject(JVMPlatform, JSPlatform) .withoutSuffixFor(JVMPlatform) .crossType(CrossType.Pure) diff --git a/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala b/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala new file mode 100644 index 00000000..f1afa48c --- /dev/null +++ b/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala @@ -0,0 +1,81 @@ +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 cats.effect.unsafe.implicits.global +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 = { + val code = CTypeConversion.toJavaString(codePointer) + + val program = compileF[IO](code, List.empty) + val result = program.unsafeRunSync() + + if (result.isValid) { + 0 + } else { + 1 + } + } + +}