Skip to content

Commit

Permalink
Merge pull request #187 from VirtusLab/js-again
Browse files Browse the repository at this point in the history
Js again + other stuff
  • Loading branch information
KacperFKorban authored Jun 28, 2021
2 parents 014b433 + 375b38a commit 68d1e0b
Show file tree
Hide file tree
Showing 33 changed files with 528 additions and 99 deletions.
20 changes: 17 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ val http4sVersion = "0.21.0"
val catsVersion = "2.2.0"
val circeVersion = "0.13.0"

lazy val engineCommon = crossProject(JVMPlatform)
lazy val engineCommon = crossProject(JSPlatform, JVMPlatform)
.in(file("engineCommon"))
.settings(
name := "inkuire-engine-common",
Expand All @@ -54,9 +54,9 @@ lazy val engineCommon = crossProject(JVMPlatform)
)

lazy val engineHttp = project
.in(file("engineHttp"))
.in(file("./engineHttp"))
.settings(
name := "inkuire-engine-http",
name := "engine-http",
libraryDependencies ++= Seq(
"org.http4s" %% "http4s-dsl" % http4sVersion,
"org.http4s" %% "http4s-server" % http4sVersion,
Expand All @@ -67,3 +67,17 @@ lazy val engineHttp = project
assembly / mainClass := Some("org.virtuslab.inkuire.engine.http.Main")
)
.dependsOn(engineCommon.jvm)

lazy val engineJS = project
.in(file("./engineJs"))
.enablePlugins(ScalaJSPlugin)
.settings(
name := "engine-js",
libraryDependencies ++= Seq(
"com.softwaremill.sttp.client" %%% "core" % "2.2.9",
"io.monix" %%% "monix" % "3.2.2",
"io.monix" %%% "monix-reactive" % "3.2.2"
),
scalaJSUseMainModuleInitializer := true,
)
.dependsOn(engineCommon.js)
1 change: 0 additions & 1 deletion engineCommon/project/build.properties

This file was deleted.

2 changes: 0 additions & 2 deletions engineCommon/project/plugins.sbt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,39 @@ package org.virtuslab.inkuire.engine.common.model

import org.virtuslab.inkuire.engine.common.utils.syntax._
import cats.implicits._
import cats.kernel.Monoid

case class AppConfig(
address: Address,
port: Port,
inkuirePaths: Seq[InkuirePath]
)
address: Option[String],
port: Option[Int],
inkuirePaths: Seq[String]
) {
def getAddress = address.getOrElse("0.0.0.0")
def getPort = port.getOrElse(8080)
}

object AppConfig {
def create(args: List[AppParam]): Either[String, AppConfig] = {
val address = args.collectFirst { case a: Address => a }.toRight(noConfigFoundString("address"))
val port = args.collectFirst { case p: Port => p }.toRight(noConfigFoundString("port"))
val inkuirePaths = Right(args.collect { case i: InkuirePath => i })
(address, port, inkuirePaths).mapN(AppConfig.apply)
implicit val appConfigMonoid = new Monoid[AppConfig] {
def empty: AppConfig = AppConfig(
address = None,
port = None,
inkuirePaths = Seq.empty
)
def combine(x: AppConfig, y: AppConfig): AppConfig =
AppConfig(
address = x.address.orElse(y.address),
port = x.port.orElse(y.port),
inkuirePaths = x.inkuirePaths ++ y.inkuirePaths
)
}

private def noConfigFoundString(paramName: String) =
s"No value for config parameter '$paramName' found"
}

trait AppParam extends Any
case class Address(address: String) extends AnyVal with AppParam
case class Port(port: Int) extends AnyVal with AppParam
case class InkuirePath(path: String) extends AnyVal with AppParam

object AppParam {
def parseCliOption(opt: String, v: String): Either[String, AppParam] =
def parseCliOption(opt: String, v: String): AppConfig =
opt match {
case "-a" | "--address" => Address(v).right
case "-p" | "--port" => Port(v.toInt).right
case "-i" | "--inkuire" => InkuirePath(v).right
case _ => s"Wrong option $opt".left
case "-a" | "--address" => Monoid.empty[AppConfig].copy(address = Some(v))
case "-p" | "--port" => Monoid.empty[AppConfig].copy(port = Some(v.toInt))
case "-i" | "--inkuire" => Monoid.empty[AppConfig].copy(inkuirePaths = Seq(v))
case o =>
println(s"Inkuire ignored wrong option: $o")
Monoid.empty[AppConfig]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@ import io.circe.parser._
import io.circe.generic.auto._
import io.circe.syntax._
import com.softwaremill.quicklens._
import cats.kernel.Monoid

case class InkuireDb(
functions: Seq[ExternalSignature],
types: Map[ITID, (Type, Seq[Type])]
)
functions: Seq[ExternalSignature],
types: Map[ITID, (Type, Seq[Type])],
implicitConversions: Seq[(ITID, Type)]
) {
val conversions: Map[ITID, Seq[Type]] = implicitConversions.groupBy(_._1).view.mapValues(_.map(_._2)).toMap
}

object InkuireDb {
implicit val inkuireDbMonoid = new Monoid[InkuireDb] {
override def combine(x: InkuireDb, y: InkuireDb): InkuireDb =
InkuireDb(
functions = (x.functions ++ y.functions).distinct,
types = x.types ++ y.types,
implicitConversions = x.implicitConversions ++ y.implicitConversions
)

override def empty: InkuireDb = InkuireDb(Seq.empty, Map.empty, Seq.empty)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ case class Match(
pageLocation: String
)

case class OutputFormat(
sealed trait OutputFormat

case class ResultFormat(
query: String,
matches: List[Match]
)
) extends OutputFormat

case object EndFormat extends OutputFormat
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ case class Signature(
result: Covariance,
context: SignatureContext
) {
def typesWithVariances: Seq[Variance] = receiver.toSeq ++ arguments ++ Seq(result)
def typesWithVariances: Seq[Variance] = receiver.toSeq ++ arguments :+ result
}

object Signature {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ object Type {
def concreteType: Type = Type(str)
def typeVariable: Type = Type(str, isVariable = true)
}
val StarProjection = Type(TypeName("_"), isStarProjection = true)
val StarProjection = Type(TypeName("_"), itid = Some(ITID("_", isParsed = true)), isStarProjection = true)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ import org.virtuslab.inkuire.engine.common.model.Signature

trait BaseSignatureParserService {
def parse(str: String): Either[String, Signature]

def parseError(msg: String): String = s"Parsing error: $msg"
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,14 @@ class ScalaSignatureParserService extends BaseSignatureParserService {
override def parse(str: String): Either[String, Signature] =
doParse(str) >>= convert >>= validate

val parsingErrorGenericMessage =
"Could not parse provided signature. Example signature looks like this: List[Int] => (Int => Boolean) => Int"

private def doParse(str: String): Either[String, Signature] = {
import scalaSignatureParser._
scalaSignatureParser.parseAll(signature, str) match {
case Success(matched, _) => Right(matched)
case Failure(msg, _) => Left(msg)
case Failure(msg, _) => Left(parseError(parsingErrorGenericMessage))
case Error(msg, _) => Left(msg)
}
}
Expand Down Expand Up @@ -164,36 +167,15 @@ class ScalaSignatureParserService extends BaseSignatureParserService {
}
}

private def validate(sgn: Signature): Either[String, Signature] = {
private def validate(sgn: Signature): Either[String, Signature] =
for {
_ <- validateConstraintsForNonVariables(sgn)
} yield sgn
}

private def validateConstraintsForNonVariables(sgn: Signature): Either[String, Unit] =
Either.cond(
sgn.context.constraints.keySet.subsetOf(sgn.context.vars),
(),
"Constraints can only be defined for declared variables"
)

private def validateTypeParamsArgs(sgn: Signature): Either[String, Unit] = {
sgn.receiver.map(doValidateVariance).getOrElse(().right) >>
sgn.arguments.map(doValidateVariance).foldLeft[Either[String, Unit]](().right)(_ >> _) >>
doValidateVariance(sgn.result) >>
sgn.context.constraints.values.toSeq.flatten
.map(doValidateTypeParamsArgs)
.foldLeft[Either[String, Unit]](().right)(_ >> _)
}

private def doValidateVariance(v: Variance): Either[String, Unit] = doValidateTypeParamsArgs(v.typ)

private def doValidateTypeParamsArgs(t: Type): Either[String, Unit] = {
t match {
case t: Type if t.params.nonEmpty =>
Either.cond(!t.isVariable, (), "Type arguments are not allowed for type parameters") >>
t.params.map(x => doValidateTypeParamsArgs(x.typ)).foldLeft[Either[String, Unit]](().right)(_ >> _)
case _ => ().right
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ package org.virtuslab.inkuire.engine.common.service
import org.virtuslab.inkuire.engine.common.model.{ResolveResult, Signature}

trait BaseSignatureResolver {
//Can be changed to Either[String, ResolveResult] to report resolve errors (unknown types etc.)
def resolve(parsed: Signature): ResolveResult
def resolve(parsed: Signature): Either[String, ResolveResult]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,53 @@ package org.virtuslab.inkuire.engine.common.service
import org.virtuslab.inkuire.engine.common.model._
import com.softwaremill.quicklens._
import cats.implicits._
import cats.Contravariant

class DefaultSignatureResolver(ancestryGraph: Map[ITID, (Type, Seq[Type])])
class DefaultSignatureResolver(ancestryGraph: Map[ITID, (Type, Seq[Type])], implicitConversions: Map[ITID, Seq[Type]])
extends BaseSignatureResolver
with VarianceOps {

val ag = AncestryGraph(ancestryGraph)
val ag = AncestryGraph(ancestryGraph, implicitConversions)

override def resolve(parsed: Signature): ResolveResult =
ResolveResult {
resolveAllPossibleSignatures(parsed).toList.flatMap { sgn => permutateParams(sgn).toList }.distinct
override def resolve(parsed: Signature): Either[String, ResolveResult] = {
val signatures = resolveAllPossibleSignatures(parsed).toList
.map(moveToReceiverIfPossible)
.flatMap { sgn => convertReceivers(sgn).toList }
.flatMap { sgn => permutateParams(sgn).toList }
.distinct
signatures match {
//TODO change to sth more informative, actual unresolved types
case List() => Left(resolveError("Could not resolve types in provided signature"))
case _ => Right(ResolveResult(signatures))
}
}

def resolveError(msg: String): String = s"Resolving error: $msg"

private def moveToReceiverIfPossible(signature: Signature): Signature = {
if (signature.receiver.nonEmpty) signature
else if (signature.arguments.isEmpty) signature
else
signature
.modify(_.receiver)
.setTo(Some(signature.arguments.head))
.modify(_.arguments)
.using(_.drop(1))
}

private def convertReceivers(signature: Signature): Seq[Signature] = {
if (signature.receiver.isEmpty) List(signature)
else {
signature.receiver.toSeq
.flatMap { rcvrVar =>
rcvrVar.typ.itid.toSeq.flatMap { rcvrITID =>
implicitConversions.get(rcvrITID).toSeq.flatten
}
}
.map { rcvrType =>
signature.modify(_.receiver.each.typ).setTo(rcvrType)
} :+ signature
}
}

private def permutateParams(signature: Signature): Seq[Signature] = {
(signature.receiver ++ signature.arguments).toList.permutations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import cats.implicits._

class FluffMatchService(val inkuireDb: InkuireDb) extends BaseMatchService with VarianceOps {

val ancestryGraph: AncestryGraph = AncestryGraph(inkuireDb.types)
val ancestryGraph: AncestryGraph = AncestryGraph(inkuireDb.types, inkuireDb.conversions)

implicit class TypeOps(sgn: Signature) {
def canSubstituteFor(supr: Signature): Boolean = {
Expand Down Expand Up @@ -55,12 +55,12 @@ class FluffMatchService(val inkuireDb: InkuireDb) extends BaseMatchService with
}

case class TypeVariablesGraph(variableBindings: VariableBindings) {
val dependencyGraph: Map[ITID, Seq[ITID]] = variableBindings.bindings.view
.mapValues(_.flatMap {
val dependencyGraph: Map[ITID, Seq[ITID]] = variableBindings.bindings.view.mapValues {
_.flatMap {
case g: Type if g.params.nonEmpty => retrieveVariables(g)
case _ => Seq()
}.distinct)
.toMap
}.distinct
}.toMap

private def retrieveVariables(t: Type): Seq[ITID] =
t match {
Expand Down Expand Up @@ -102,7 +102,8 @@ case class TypeVariablesGraph(variableBindings: VariableBindings) {
}
}

case class AncestryGraph(nodes: Map[ITID, (Type, Seq[Type])]) extends VarianceOps {
case class AncestryGraph(nodes: Map[ITID, (Type, Seq[Type])], implicitConversions: Map[ITID, Seq[Type]])
extends VarianceOps {

var tab = ""
implicit class TypeOps(typ: Type) {
Expand Down Expand Up @@ -241,7 +242,7 @@ case class AncestryGraph(nodes: Map[ITID, (Type, Seq[Type])]) extends VarianceOp
): State[VariableBindings, Boolean] = {
((typ, supr): @unchecked) match {
case (typ, supr) if typ.typ.isStarProjection || supr.typ.isStarProjection =>
State.pure[VariableBindings, Boolean](true)
State.pure(true)
case (Covariance(typParam), Covariance(suprParam)) =>
typParam.isSubTypeOf(suprParam)(context)
case (Contravariance(typParam), Contravariance(suprParam)) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package org.virtuslab.inkuire.engine.http.http

import org.virtuslab.inkuire.engine.common.model.ExternalSignature
import org.virtuslab.inkuire.engine.common.service.SignaturePrettifier
import org.virtuslab.inkuire.engine.common.model.{Match, OutputFormat}
import org.virtuslab.inkuire.engine.common.model.{Match, ResultFormat}

import collection.JavaConverters._

class OutputFormatter(prettifier: SignaturePrettifier) {
def createOutput(query: String, signatures: Seq[ExternalSignature]): OutputFormat =
OutputFormat(
def createOutput(query: String, signatures: Seq[ExternalSignature]): ResultFormat =
ResultFormat(
query,
fromSignatures(signatures).toList
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ScalaExternalSignaturePrettifier extends SignaturePrettifier {
private def doPrettify(esgn: ExternalSignature): String =
s"${prettifySignature(esgn.signature)}"

private def prettifySignature(sgn: Signature): String = {
def prettifySignature(sgn: Signature): String = {
s"${prettifyTypeVariables(sgn.context)}" +
s"${prettifyArgs(sgn.typesWithVariances, " => ")}"
}
Expand All @@ -26,7 +26,7 @@ class ScalaExternalSignaturePrettifier extends SignaturePrettifier {
private def prettifyArgs(args: Seq[Variance], sep: String = ", "): String =
args.map(_.typ).map(prettifyType).mkString(sep)

private def prettifyType(t: Type): String = t match {
def prettifyType(t: Type): String = t match {
case t: Type if t.isStarProjection => "*"
case t: Type if t.isGeneric && !t.isVariable && t.name.name.matches("Function.*") =>
s"(${prettifyArgs(t.params, " => ")})"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,12 @@ import cats.effect.IO
trait IOHelpers {
def putStrLn(str: String): IO[Unit] = IO { println(str) }
def putStr(str: String): IO[Unit] = IO { print(str) }

val ANSI_RESET = "\u001B[0m";
val ANSI_RED = "\u001B[31m";
val ANSI_BLUE = "\u001B[34m";
val ANSI_GREEN = "\u001B[32m";
def red(str: String): String = ANSI_RED + str + ANSI_RESET
def blue(str: String): String = ANSI_BLUE + str + ANSI_RESET
def green(str: String): String = ANSI_GREEN + str + ANSI_RESET
}
1 change: 0 additions & 1 deletion engineHttp/project/build.properties

This file was deleted.

1 change: 0 additions & 1 deletion engineHttp/project/plugins.sbt

This file was deleted.

Loading

0 comments on commit 68d1e0b

Please sign in to comment.