All Projects → DmytroMitin → AUXify

DmytroMitin / AUXify

Licence: Apache-2.0 license
Introduces macro/meta annotations @ aux, @ self, @ instance, @ apply, @ delegated, @ syntax and String-based type class LabelledGeneric

Programming Languages

scala
5932 projects

Projects that are alternatives of or similar to AUXify

scalagen
WIP - Scalameta powered code generation
Stars: ✭ 38 (+52%)
Mutual labels:  code-generation, scalameta
typeclass-interface-pattern
Ideas, thoughts, and notes on a typeclass/interface based polymorphism pattern for standard C
Stars: ✭ 26 (+4%)
Mutual labels:  typeclass, typeclasses
cog
Command-line utility that makes it easy to organize a project which uses code generation
Stars: ✭ 15 (-40%)
Mutual labels:  code-generation
islpy
Python wrapper for isl, an integer set library
Stars: ✭ 58 (+132%)
Mutual labels:  code-generation
gamma
An Eclipse-based modeling framework for the component-based design and analysis of reactive systems
Stars: ✭ 21 (-16%)
Mutual labels:  code-generation
orm
Go Typed ORM
Stars: ✭ 16 (-36%)
Mutual labels:  code-generation
EasyEE-Auto
EasyEE 自动化代码生成器。EasyEE Automated code generator.
Stars: ✭ 39 (+56%)
Mutual labels:  code-generation
django-code-generator
Generate code from your Django models for faster development
Stars: ✭ 35 (+40%)
Mutual labels:  code-generation
nmodl
Code Generation Framework For NEURON MODeling Language
Stars: ✭ 42 (+68%)
Mutual labels:  code-generation
kube-code-generator
Kubernetes code generator docker image
Stars: ✭ 60 (+140%)
Mutual labels:  code-generation
kobby
Kobby is a codegen plugin of Kotlin DSL Client by GraphQL schema. The generated DSL supports execution of complex GraphQL queries, mutation and subscriptions in Kotlin with syntax similar to native GraphQL syntax.
Stars: ✭ 52 (+108%)
Mutual labels:  code-generation
dynamic.yaml
DEPRECATED: YAML-based data transformations
Stars: ✭ 14 (-44%)
Mutual labels:  code-generation
ParNMPC
A Parallel Optimization Toolkit for Nonlinear Model Predictive Control (NMPC)
Stars: ✭ 173 (+592%)
Mutual labels:  code-generation
qp-arduino
QP real-time embedded frameworks/RTOS for Arduino (AVR and SAM)
Stars: ✭ 37 (+48%)
Mutual labels:  code-generation
1c http
Подсистема 1С для работы с HTTP
Stars: ✭ 48 (+92%)
Mutual labels:  code-generation
oh-migrations
Data migrations through implicit function composition at the type-level
Stars: ✭ 23 (-8%)
Mutual labels:  typelevel-programming
openapi-client
Generate ES6 or Typescript service integration code from an OpenAPI 2 spec
Stars: ✭ 92 (+268%)
Mutual labels:  code-generation
Python3Generator
A toolkit to generate Python 3 source code from Pharo.
Stars: ✭ 25 (+0%)
Mutual labels:  code-generation
freAST
Fast, simple Free Monads using ScalaMeta macro annotations. Port of Freasy-Monad.
Stars: ✭ 14 (-44%)
Mutual labels:  scalameta
Beef
Business Entity Execution Framework
Stars: ✭ 95 (+280%)
Mutual labels:  code-generation

AUXify

Build Status Maven Central Maven Central Sonatype Snapshots javadoc Scaladex Join the chat at https://gitter.im/DmytroMitin/AUXify

mvnrepository repo1.maven

Contents

Using AUXify-Shapeless

Write in build.sbt

scalaVersion := "2.13.3"
//scalaVersion := "2.12.11"
//scalaVersion := "2.11.12"
//scalaVersion := "2.10.7"

resolvers += Resolver.sonatypeRepo("public")

libraryDependencies ++= Seq(
  "com.github.dmytromitin" %% "auxify-shapeless" % [LATEST VERSION],
  "com.github.dmytromitin" %% "shapeless" % (CrossVersion.partialVersion(scalaVersion.value) match {
    case Some((2, v)) if v >= 11 => "2.4.0-M1-30032020-e6c3f71-PATCH"
    case _                       => "2.4.0-SNAPSHOT-18022020-bf55524-PATCH"
  })
)

Helps to overcome Shapeless limitation that shapeless.LabelledGeneric is Symbol-based rather than String-based.

Introduces type classes SymbolToString, StringToSymbol to convert between symbol singleton type and string singleton type

implicitly[StringToSymbol.Aux["a", Symbol @@ "a"]]
implicitly[SymbolToString.Aux[Symbol @@ "a", "a"]]
stringToSymbol("a") // returns Symbol("a") of type Symbol @@ "a"
symbolToString(Symbol("a")) // returns "a" of type "a"

and String-based type class com.github.dmytromitin.auxify.shapeless.LabelledGeneric

case class A(i: Int, s: String, b: Boolean)
implicitly[LabelledGeneric.Aux[A, Record.`"i" -> Int, "s" -> String, "b" -> Boolean`.T]]
LabelledGeneric[A].to(A(1, "a", true)) // field["i"](1) :: field["s"]("a") :: field["b"](true) :: HNil
LabelledGeneric[A].from(field["i"](1) :: field["s"]("a") :: field["b"](true) :: HNil) // A(1, "a", true)

Also there are convenient syntaxes

import com.github.dmytromitin.auxify.shapeless.hlist._
import StringsToSymbols.syntax._
("a".narrow :: "b".narrow :: "c".narrow :: HNil).stringsToSymbols // 'a.narrow :: 'b.narrow :: 'c.narrow :: HNil
import SymbolsToStrings.syntax._
('a.narrow :: 'b.narrow :: 'c.narrow :: HNil).symbolsToStrings // "a".narrow :: "b".narrow :: "c".narrow :: HNil

import com.github.dmytromitin.auxify.shapeless.coproduct._
import StringsToSymbols.syntax._
(Inr(Inr(Inl("c".narrow))) : "a" :+: "b" :+: "c" :+: CNil).stringsToSymbols // Inr(Inr(Inl('c.narrow))) : (Symbol @@ "a") :+: (Symbol @@ "b") :+: (Symbol @@ "c") :+: CNil
import SymbolsToStrings.syntax._
(Inr(Inr(Inl('c.narrow))) : (Symbol @@ "a") :+: (Symbol @@ "b") :+: (Symbol @@ "c") :+: CNil).symbolsToStrings // Inr(Inr(Inl("c".narrow))) : "a" :+: "b" :+: "c" :+: CNil

import com.github.dmytromitin.auxify.shapeless.record._
import StringsToSymbols.syntax._
(field["a"](1) :: field["b"]("s") :: field["c"](true) :: HNil).stringsToSymbols // field[Symbol @@ "a"](1) :: field[Symbol @@ "b"]("s") :: field[Symbol @@ "c"](true) :: HNil
import SymbolsToStrings.syntax._
(field[Symbol @@ "a"](1) :: field[Symbol @@ "b"]("s") :: field[Symbol @@ "c"](true) :: HNil).symbolsToStrings // field["a"](1) :: field["b"]("s") :: field["c"](true) :: HNil

import com.github.dmytromitin.auxify.shapeless.union._
import StringsToSymbols.syntax._
(Inr(Inr(Inl(field["c"](true)))): Union.`"a" -> Int, "b" -> String, "c" -> Boolean`.T).stringsToSymbols // Inr(Inr(Inl(field[Witness.`'c`.T](true)))): Union.`'a -> Int, 'b -> String, 'c -> Boolean`.T
import SymbolsToStrings.syntax._
(Inr(Inr(Inl(field[Symbol @@ "c"](true)))): Union.`'a -> Int, 'b -> String, 'c -> Boolean`.T).symbolsToStrings // Inr(Inr(Inl(field[Witness.`"c"`.T](true)))): Union.`"a" -> Int, "b" -> String, "c" -> Boolean`.T

You can play with AUXify online at Scastie: https://scastie.scala-lang.org/r52fCgloRc2VVM5FnNmbsQ

Using AUXify-Macros

Write in build.sbt

scalaVersion := "2.13.3"
//scalaVersion := "2.12.11"
//scalaVersion := "2.11.12"
//scalaVersion := "2.10.7"

resolvers += Resolver.sonatypeRepo("public")

libraryDependencies += "com.github.dmytromitin" %% "auxify-macros" % [LATEST VERSION]

scalacOptions += "-Ymacro-annotations" // in Scala >= 2.13
//addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full) // in Scala <= 2.12

@aux (helper for type refinement)

Transforms

@aux
trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

into

trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

object Add {
  type Aux[N <: Nat, M <: Nat, Out0 <: Nat] = Add[N, M] { type Out = Out0 }
}

So it can be used:

implicitly[Add.Aux[_2, _3, _5]]

Convenient for type-level programming.

@self

Transforms

@self
sealed trait Nat {
  type ++ = Succ[Self]
}

@self
case object _0 extends Nat 

type _0 = _0.type

@self
case class Succ[N <: Nat](n: N) extends Nat

into

sealed trait Nat { self =>
  type Self >: self.type <: Nat { type Self = self.Self }
  type ++ = Succ[Self]
}

case object _0 extends Nat {
  override type Self = _0
}

type _0 = _0.type

case class Succ[N <: Nat](n: N) extends Nat {
  override type Self = Succ[N]
}

Convenient for type-level programming.

Generating lower bound >: self.type and/or F-bound type Self = self.Self for trait can be switched off

@self(lowerBound = false, fBound = false)

@instance (constructor)

Transforms

@instance
trait Monoid[A] {
  def empty: A
  def combine(a: A, a1: A): A
}

into

trait Monoid[A] {
  def empty: A
  def combine(a: A, a1: A): A
}

object Monoid {
  def instance[A](f: => A, f1: (A, A) => A): Monoid[A] = new Monoid[A] {
    override def empty: A = f
    override def combine(a: A, a1: A): A = f1(a, a1)
  }
}

So it can be used

implicit val intMonoid: Monoid[Int] = instance(0, _ + _)

Polymorphic methods are not supported (since Scala 2 lacks polymorphic functions).

@apply (materializer)

Transforms

@apply
trait Show[A] {
  def show(a: A): String
}

into

trait Show[A] {
  def show(a: A): String
}

object Show {
  def apply[A](implicit inst: Show[A]): Show[A] = inst
}

So it can be used

Show[Int].show(10)

Method materializing type class can return more precise type than the one of implicit to be found (like the in Shapeless or summon in Dotty). For example

@apply
trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

is transformed into

trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

object Add {
  def apply[N <: Nat, M <: Nat](implicit inst: Add[N, M]): Add[N, M] { type Out = inst.Out } = inst
}

Simulacrum annotation @typeclass also generates, among other, materializer but doesn't support type classes with multiple type parameters.

@delegated

Generates methods in companion object delegating to implicit instance of trait (type class).

Transforms

@delegated
trait Show[A] {
  def show(a: A): String
}

into

trait Show[A] {
  def show(a: A): String
}

object Show {
  def show[A](a: A)(implicit inst: Show[A]): String = inst.show(a)
}

So it can be used

Show.show(10)

@syntax

Transforms

@syntax
trait Monoid[A] {
  def empty: A
  def combine(a: A, a1: A): A
}

into

trait Monoid[A] {
  def empty: A
  def combine(a: A, a1: A): A
}

object Monoid {
  object syntax {
    implicit class Ops[A](a: A) {
      def combine(a1: A)(implicit inst: Monoid[A]): A = inst.combine(a, a1)
    }
  }
}

So it can be used

import Monoid.syntax._
2 combine 3

Simulacrum annotation @typeclass also generates syntax but doesn't support type classes with multiple type parameters.

Inheritance of type classes is not supported (anyway it's broken).

@poly

Transforms

@poly
trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

into

trait Add[N <: Nat, M <: Nat] {
  type Out <: Nat
  def apply(n: N, m: M): Out
}

object Add {
  object addPoly extends Poly2 {
    implicit def cse[N <: Nat, M <: Nat](implicit add: Add[N, M]): Case.Aux[N, M, add.Out] = at((n, m) => add(n, m)) 
  }
}

@poly is not implemented yet. See issue.

Using AUXify-Meta

Currently only @aux is implemented as Scalafix rewriting rule. It's a semantic rule since we need companion object.

Meta annotation @aux works only with classes on contrary to macro annotation @aux working only with traits. This will be fixed.

Code generation with Scalafix

For code generation with Scalameta + SemanticDB + Scalafix write in project/plugins.sbt

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.18")

and in build.sbt

import com.geirsson.coursiersmall.{Repository => R}

lazy val V = _root_.scalafix.sbt.BuildInfo

inThisBuild(Seq(
  scalaVersion := V.scala213,
  addCompilerPlugin(scalafixSemanticdb),
  scalafixResolvers in ThisBuild += new R.Maven("https://oss.sonatype.org/content/groups/public/"),
  // brings rewriting rules
  scalafixDependencies in ThisBuild += "com.github.dmytromitin" %% "auxify-meta" % [LATEST VERSION],
  scalacOptions += "-Yrangepos" // for SemanticDB
))

lazy val in = project
  .settings(
    // brings meta annotations
    libraryDependencies += "com.github.dmytromitin" %% "auxify-meta-core" % [LATEST VERSION]
  )

lazy val out = project
  .settings(
    sourceGenerators.in(Compile) += Def.taskDyn {
      val root = baseDirectory.in(ThisBuild).value.toURI.toString
      val from = sourceDirectory.in(in, Compile).value
      val to = sourceManaged.in(Compile).value
      val outFrom = from.toURI.toString.stripSuffix("/").stripPrefix(root)
      val outTo = to.toURI.toString.stripSuffix("/").stripPrefix(root)
      Def.task {
        scalafix
          .in(in, Compile)
          .toTask(s" AuxRule --out-from=$outFrom --out-to=$outTo")
          .value
        (to ** "*.scala").get
      }
    }.taskValue,
    
    // for import statement and if meta annotation is not expanded
    libraryDependencies += "com.github.dmytromitin" %% "auxify-meta-core" % [LATEST VERSION]
  )

Annotated code should be placed in in/src/main/scala. Code generation in out/target/scala-2.13/src_managed/main/scala can be run with sbt out/compile.

Example project is here.

Rewriting with Scalafix

For using rewriting rules with Scalameta + SemanticDB + Scalafix write in project/plugins.sbt

addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.18")

and in build.sbt

// on the top
import com.geirsson.coursiersmall.{Repository => R}
scalafixResolvers in ThisBuild += new R.Maven("https://oss.sonatype.org/content/groups/public/")
scalafixDependencies in ThisBuild += "com.github.dmytromitin" %% "auxify-meta" % [LATEST VERSION]

scalaVersion := "2.13.3"
//scalaVersion := "2.12.11"
//scalaVersion := "2.11.12"

libraryDependencies += "com.github.dmytromitin" %% "auxify-meta-core" % [LATEST VERSION]

addCompilerPlugin(scalafixSemanticdb)

scalacOptions += "-Yrangepos" // for SemanticDB

Rewriting can be run with sbt "scalafix AuxRule" (details are here).

Code generation with Scalameta

For code generating syntacticly with pure Scalameta (without SemanticDB and Scalafix) write in project/build.sbt

resolvers += Resolver.sonatypeRepo("public")
libraryDependencies += "com.github.dmytromitin" %% "auxify-syntactic-meta" % [LATEST VERSION]

and in build.sbt

inThisBuild(Seq(
  scalaVersion := "2.13.3"
  //scalaVersion := "2.12.11"
  //scalaVersion := "2.11.12"
))

lazy val in = project
  .settings(
    libraryDependencies += "com.github.dmytromitin" %% "auxify-meta-core" % [LATEST VERSION]
  )

lazy val out = project
  .settings(
    sourceGenerators in Compile += Def.task {
      import com.github.dmytromitin.auxify.meta.syntactic.ScalametaTransformer
      
      val finder: PathFinder = sourceDirectory.in(in, Compile).value ** "*.scala"
  
      for(inputFile <- finder.get) yield {
        val inputStr = IO.read(inputFile)
        val outputFile = sourceManaged.in(Compile).value / inputFile.name
        val outputStr = ScalametaTransformer.transform(inputStr)
        IO.write(outputFile, outputStr)
        outputFile
      }
    }.taskValue,
    
    // for import statement and if meta annotation is not expanded
    libraryDependencies += "com.github.dmytromitin" %% "auxify-meta-core" % [LATEST VERSION]
  )

Annotated code should be placed in in/src/main/scala. Code generation in out/target/scala-2.13/src_managed/main can be run with sbt out/compile.

Example project is here.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].