Bug fixes (#127)

This commit is contained in:
Dima 2021-05-24 11:00:45 +03:00 committed by GitHub
parent 720de27f14
commit 9f5c0d64ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 245 additions and 83 deletions

View File

@ -20,4 +20,4 @@ func betterMessage(relay: string):
par on "quray": par on "quray":
Peer.is_connected("qurara") Peer.is_connected("qurara")
if isOnline: if isOnline:
Test.doSomething() Test.doSomething()

View File

@ -12,15 +12,23 @@ val monocleV = "3.0.0-M5"
val scalaTestV = "3.2.7" // TODO update version for scala 3-RC3 val scalaTestV = "3.2.7" // TODO update version for scala 3-RC3
val fs2V = "3.0.2" val fs2V = "3.0.2"
val catsEffectV = "3.1.0" val catsEffectV = "3.1.0"
val airframeLogV = "21.5.4"
val log4catsV = "2.1.1"
val enumeratumV = "1.6.1"
val slf4jV = "1.7.25"
val declineV = "2.0.0-RC1" // Scala3 issue: https://github.com/bkirwi/decline/issues/260 val declineV = "2.0.0-RC1" // Scala3 issue: https://github.com/bkirwi/decline/issues/260
val declineEnumV = "1.3.0"
name := "aqua-hll" name := "aqua-hll"
val commons = Seq( val commons = Seq(
baseAquaVersion := "0.1.1", baseAquaVersion := "0.1.1",
version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"), version := baseAquaVersion.value + "-" + sys.env.getOrElse("BUILD_NUMBER", "SNAPSHOT"),
scalaVersion := dottyVersion, scalaVersion := dottyVersion,
libraryDependencies += "org.scalatest" %% "scalatest" % scalaTestV % Test, libraryDependencies ++= Seq(
"org.typelevel" %% "log4cats-core" % "2.1.1",
"org.scalatest" %% "scalatest" % scalaTestV % Test
),
addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.3" cross CrossVersion.full) addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.11.3" cross CrossVersion.full)
) )
@ -33,11 +41,16 @@ lazy val cli = project
assembly / mainClass := Some("aqua.AquaCli"), assembly / mainClass := Some("aqua.AquaCli"),
assembly / assemblyJarName := "aqua-cli-" + version.value + ".jar", assembly / assemblyJarName := "aqua-cli-" + version.value + ".jar",
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.monovore" %% "decline" % declineV, "com.monovore" %% "decline" % declineV,
"com.monovore" %% "decline-effect" % declineV, "com.monovore" %% "decline-effect" % declineV,
"org.typelevel" %% "cats-effect" % catsEffectV, "org.typelevel" %% "cats-effect" % catsEffectV,
"co.fs2" %% "fs2-core" % fs2V, "co.fs2" %% "fs2-core" % fs2V,
"co.fs2" %% "fs2-io" % fs2V "co.fs2" %% "fs2-io" % fs2V,
"org.typelevel" %% "log4cats-slf4j" % log4catsV,
"org.wvlet.airframe" %% "airframe-log" % airframeLogV,
"com.beachape" %% "enumeratum" % enumeratumV,
"org.slf4j" % "slf4j-jdk14" % slf4jV,
"com.monovore" %% "decline-enumeratum" % declineEnumV
) )
) )
.dependsOn(semantics, `backend-air`, `backend-ts`, linker) .dependsOn(semantics, `backend-air`, `backend-ts`, linker)
@ -63,6 +76,9 @@ lazy val parser = project
lazy val linker = project lazy val linker = project
.settings(commons: _*) .settings(commons: _*)
.settings( .settings(
libraryDependencies ++= Seq(
"org.wvlet.airframe" %% "airframe-log" % airframeLogV
)
) )
.dependsOn(parser) .dependsOn(parser)

View File

@ -0,0 +1,117 @@
package aqua
import cats.Functor
import cats.data.Validated.{Invalid, Valid}
import cats.data.{Validated, ValidatedNel}
import cats.effect.ExitCode
import cats.effect.std.Console
import cats.syntax.functor._
import cats.syntax.traverse._
import com.monovore.decline.Opts.help
import com.monovore.decline.enumeratum._
import com.monovore.decline.{Opts, Visibility}
import java.nio.file.Path
object AppOps {
val helpOpt: Opts[Unit] =
Opts.flag("help", help = "Display this help text", "h", Visibility.Partial).asHelp.as(())
val versionOpt: Opts[Unit] =
Opts.flag("version", help = "Show version", "v", Visibility.Partial)
val logLevelOpt: Opts[LogLevel] =
Opts.option[LogLevel]("log-level", help = "Set log level").withDefault(LogLevel.Info)
def checkPath: Path => ValidatedNel[String, Path] = { p =>
Validated
.fromEither(Validated.catchNonFatal {
val f = p.toFile
if (f.exists() && f.isDirectory) {
Right(p)
} else {
Left(s"There is no path '${p.toString}' or it is not a directory")
}
}.toEither.left.map(t => s"An error occurred on imports reading: ${t.getMessage}").flatten)
.toValidatedNel
}
val inputOpts: Opts[Path] =
Opts
.option[Path](
"input",
"Path to the input directory that contains your .aqua files. It can only be a directory",
"i"
)
.mapValidated(checkPath)
val outputOpts: Opts[Path] =
Opts.option[Path]("output", "Path to the output directory", "o").mapValidated(checkPath)
val importOpts: Opts[LazyList[Path]] =
Opts
.options[Path]("import", "Path to the directory to import from", "m")
.mapValidated { ps =>
val checked = ps
.map(p => {
Validated.catchNonFatal {
val f = p.toFile
if (f.exists() && f.isDirectory) {
Right(p)
} else {
Left(s"There is no path ${p.toString} or it is not a directory")
}
}
})
.toList
checked.map {
case Validated.Valid(pE) =>
pE match {
case Right(p) =>
Validated.Valid(p)
case Left(e) =>
Validated.Invalid(e)
}
case Validated.Invalid(e) =>
Validated.Invalid(s"Error occurred on imports reading: ${e.getMessage}")
}.traverse {
case Valid(a) => Validated.validNel(a)
case Invalid(e) => Validated.invalidNel(e)
}.map(_.to(LazyList))
}
.withDefault(LazyList.empty)
val compileToAir: Opts[Boolean] =
Opts
.flag("air", "Generate .air file instead of typescript", "a")
.map(_ => true)
.withDefault(false)
val noRelay: Opts[Boolean] =
Opts
.flag("no-relay", "Do not generate a pass through the relay node")
.map(_ => true)
.withDefault(false)
val noXorWrapper: Opts[Boolean] =
Opts
.flag("no-xor", "Do not generate a wrapper that catches and displays errors")
.map(_ => true)
.withDefault(false)
lazy val versionStr: String =
Option(getClass.getPackage.getImplementationVersion).filter(_.nonEmpty).getOrElse("no version")
def versionAndExit[F[_]: Console: Functor]: F[ExitCode] = Console[F]
.println(versionStr)
.as(ExitCode.Success)
def helpAndExit[F[_]: Console: Functor]: F[ExitCode] = Console[F]
.println(help)
.as(ExitCode.Success)
def wrapWithOption[A](opt: Opts[A]): Opts[Option[A]] =
opt.map(v => Some(v)).withDefault(None)
}

View File

@ -2,51 +2,42 @@ package aqua
import aqua.model.transform.BodyConfig import aqua.model.transform.BodyConfig
import cats.data.Validated import cats.data.Validated
import cats.effect.{Concurrent, ExitCode, IO, IOApp} import cats.effect._
import cats.effect.std.Console import cats.effect.std.Console
import com.monovore.decline.Opts
import com.monovore.decline.effect.CommandIOApp
import cats.syntax.apply._ import cats.syntax.apply._
import cats.syntax.functor._ import cats.syntax.functor._
import com.monovore.decline.Opts
import com.monovore.decline.effect.CommandIOApp
import fs2.io.file.Files import fs2.io.file.Files
import org.typelevel.log4cats.slf4j.Slf4jLogger
import org.typelevel.log4cats.{Logger, SelfAwareStructuredLogger}
import wvlet.log.{LogSupport, Logger => WLogger}
import java.nio.file.Path object AquaCli extends IOApp with LogSupport {
import AppOps._
object AquaCli extends IOApp { def main[F[_]: Concurrent: Files: Console: Logger]: Opts[F[ExitCode]] = {
versionOpt
.as(
versionAndExit
) orElse helpOpt.as(
helpAndExit
) orElse (
inputOpts,
importOpts,
outputOpts,
compileToAir,
noRelay,
noXorWrapper,
wrapWithOption(helpOpt),
wrapWithOption(versionOpt),
logLevelOpt
).mapN { case (input, imports, output, toAir, noRelay, noXor, h, v, logLevel) =>
WLogger.setDefaultLogLevel(LogLevel.toLogLevel(logLevel))
val inputOpts: Opts[Path] = // if there is `--help` or `--version` flag - show help and version
Opts.option[Path]("input", "Path to the input directory that contains your .aqua files", "i") // otherwise continue program execution
h.map(_ => helpAndExit) orElse v.map(_ => versionAndExit) getOrElse
val outputOpts: Opts[Path] =
Opts.option[Path]("output", "Path to the output directory", "o")
val importOpts: Opts[LazyList[Path]] =
Opts
.options[Path]("import", "Path to the directory to import from", "m")
.map(_.toList.to(LazyList))
.withDefault(LazyList.empty)
val compileToAir: Opts[Boolean] =
Opts
.flag("air", "Generate .air file instead of typescript", "a")
.map(_ => true)
.withDefault(false)
val noRelay: Opts[Boolean] =
Opts
.flag("no-relay", "Do not generate a pass through the relay node")
.map(_ => true)
.withDefault(false)
val noXorWrapper: Opts[Boolean] =
Opts
.flag("no-xor", "Do not generate a wrapper that catches and displays errors")
.map(_ => true)
.withDefault(false)
def mainOpts[F[_]: Console: Concurrent: Files]: Opts[F[ExitCode]] =
(inputOpts, importOpts, outputOpts, compileToAir, noRelay, noXorWrapper).mapN {
case (input, imports, output, toAir, noRelay, noXor) =>
AquaCompiler AquaCompiler
.compileFilesTo[F]( .compileFilesTo[F](
input, input,
@ -66,21 +57,21 @@ object AquaCli extends IOApp {
ExitCode.Success ExitCode.Success
} }
} }
}
override def run(args: List[String]): IO[ExitCode] = {
implicit def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] =
Slf4jLogger.getLogger[F]
override def run(args: List[String]): IO[ExitCode] =
CommandIOApp.run[IO]( CommandIOApp.run[IO](
"aqua-c", "aqua-c",
"Aquamarine compiler", "Aquamarine compiler",
helpFlag = true, helpFlag = false,
Option(getClass.getPackage.getImplementationVersion).filter(_.nonEmpty) None
)( )(
mainOpts[IO], main[IO],
// Weird ugly hack: in case version flag or help flag is present, ignore other options, args
// be it correct or not
args match {
case _ if args.contains("-v") || args.contains("--version") => "-v" :: Nil
case _ if args.contains("-h") || args.contains("--help") => "-h" :: Nil
case _ => args
}
) )
}
} }

View File

@ -10,13 +10,13 @@ import aqua.parser.lexer.Token
import aqua.parser.lift.FileSpan import aqua.parser.lift.FileSpan
import aqua.semantics.{CompilerState, Semantics} import aqua.semantics.{CompilerState, Semantics}
import cats.Applicative import cats.Applicative
import cats.data.{Chain, EitherT, NonEmptyChain, Validated, ValidatedNec} import cats.data._
import cats.effect.kernel.Concurrent import cats.effect.kernel.Concurrent
import fs2.io.file.Files
import cats.syntax.monoid._
import cats.syntax.functor._
import cats.syntax.flatMap._ import cats.syntax.flatMap._
import cats.syntax.functor._
import cats.syntax.monoid._
import cats.syntax.show._ import cats.syntax.show._
import fs2.io.file.Files
import fs2.text import fs2.text
import java.nio.file.Path import java.nio.file.Path

View File

@ -0,0 +1,30 @@
package aqua
import enumeratum._
import wvlet.log.{LogLevel => WLogLevel}
sealed trait LogLevel extends EnumEntry with EnumEntry.Lowercase
object LogLevel extends Enum[LogLevel] {
case object Debug extends LogLevel
case object Trace extends LogLevel
case object Info extends LogLevel
case object Off extends LogLevel
case object Warn extends LogLevel
case object Error extends LogLevel
case object All extends LogLevel
val values = findValues
def toLogLevel(logLevel: LogLevel): WLogLevel = {
logLevel match {
case LogLevel.Debug => WLogLevel.DEBUG
case LogLevel.Trace => WLogLevel.TRACE
case LogLevel.Info => WLogLevel.INFO
case LogLevel.Off => WLogLevel.OFF
case LogLevel.Warn => WLogLevel.WARN
case LogLevel.Error => WLogLevel.ERROR
case LogLevel.All => WLogLevel.ALL
}
}
}

View File

@ -1,13 +1,18 @@
package aqua package aqua
import aqua.model.transform.BodyConfig import aqua.model.transform.BodyConfig
import cats.effect.{IO, IOApp}
import cats.data.Validated import cats.data.Validated
import cats.effect.{IO, IOApp, Sync}
import org.typelevel.log4cats.SelfAwareStructuredLogger
import org.typelevel.log4cats.slf4j.Slf4jLogger
import java.nio.file.Paths import java.nio.file.Paths
object Test extends IOApp.Simple { object Test extends IOApp.Simple {
implicit def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] =
Slf4jLogger.getLogger[F]
override def run: IO[Unit] = override def run: IO[Unit] =
AquaCompiler AquaCompiler
.compileFilesTo[IO]( .compileFilesTo[IO](

View File

@ -3,10 +3,11 @@ package aqua.linker
import cats.data.{NonEmptyChain, Validated, ValidatedNec} import cats.data.{NonEmptyChain, Validated, ValidatedNec}
import cats.kernel.{Monoid, Semigroup} import cats.kernel.{Monoid, Semigroup}
import cats.syntax.monoid._ import cats.syntax.monoid._
import wvlet.log.LogSupport
import scala.annotation.tailrec import scala.annotation.tailrec
object Linker { object Linker extends LogSupport {
@tailrec @tailrec
def iter[I, E, T: Semigroup]( def iter[I, E, T: Semigroup](
@ -18,29 +19,31 @@ object Linker {
case Nil => Right(proc) case Nil => Right(proc)
case _ => case _ =>
val (canHandle, postpone) = mods.partition(_.dependsOn.keySet.forall(proc.contains)) val (canHandle, postpone) = mods.partition(_.dependsOn.keySet.forall(proc.contains))
println("ITERATE, can handle: " + canHandle.map(_.id)) debug("ITERATE, can handle: " + canHandle.map(_.id))
println(s"proc = ${proc.keySet}") debug(s"proc = ${proc.keySet}")
if (canHandle.isEmpty && postpone.nonEmpty) if (canHandle.isEmpty && postpone.nonEmpty)
Left(cycleError(postpone)) Left(cycleError(postpone))
else else {
val folded = canHandle.foldLeft(proc) { case (acc, m) =>
debug(m.id + " dependsOn " + m.dependsOn.keySet)
val deps: T => T =
m.dependsOn.keySet.map(acc).foldLeft[T => T](identity) { case (fAcc, f) =>
debug("COMBINING ONE TIME ")
t => {
debug(s"call combine ${t}")
fAcc(t) |+| f(t)
}
}
acc + (m.id -> m.body.compose(deps))
}
iter( iter(
postpone, postpone,
// TODO can be done in parallel // TODO can be done in parallel
canHandle.foldLeft(proc) { case (acc, m) => folded,
println(m.id + " dependsOn " + m.dependsOn.keySet)
val deps: T => T =
m.dependsOn.keySet.map(acc).foldLeft[T => T](identity) { case (fAcc, f) =>
println("COMBINING ONE TIME ")
t => {
println(s"call combine ${t}")
fAcc(t) |+| f(t)
}
}
acc + (m.id -> m.body.compose(deps))
},
cycleError cycleError
) )
}
} }
def apply[I, E, T: Monoid]( def apply[I, E, T: Monoid](

View File

@ -1,13 +1,13 @@
package aqua.parser.expr package aqua.parser.expr
import aqua.parser.Ast.Tree import aqua.parser.Ast.Tree
import aqua.parser.lexer.Token.` \n+` import aqua.parser.lexer.Token._
import aqua.parser.{Expr, ParserError}
import aqua.parser.lift.LiftParser import aqua.parser.lift.LiftParser
import cats.{Comonad, Eval} import aqua.parser.{Expr, ParserError}
import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec} import cats.data.{Chain, NonEmptyChain, Validated, ValidatedNec}
import cats.free.Cofree import cats.free.Cofree
import cats.parse.{Parser => P} import cats.parse.{Parser => P}
import cats.{Comonad, Eval}
case class RootExpr[F[_]]() extends Expr[F](RootExpr) case class RootExpr[F[_]]() extends Expr[F](RootExpr)