-
Notifications
You must be signed in to change notification settings - Fork 2
Annotation macros #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: macros
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,7 @@ | ||
| /RUNNING_PID | ||
| /logs/ | ||
| /project/*-shim.sbt | ||
| /project/project/ | ||
| /project/target/ | ||
| /target/ | ||
| project/*-shim.sbt | ||
| project/project/ | ||
| project/target/ | ||
| target/ | ||
| /.idea/ | ||
| /choices/target/ | ||
| /predicates/target/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| package com.wheaties.predicate | ||
|
|
||
| import annotation.{compileTimeOnly, StaticAnnotation} | ||
| import scala.reflect.macros.whitebox | ||
| import scala.reflect.macros._ | ||
| import scala.language.experimental.macros | ||
|
|
||
| object Macros { | ||
|
|
||
| @compileTimeOnly("GeneratePredicate must be called during compilation") | ||
| class GeneratePredicate extends StaticAnnotation { | ||
| def macroTransform(annottees: Any*): Any = macro GeneratePredicate.impl | ||
| } | ||
|
|
||
| object GeneratePredicate { | ||
| def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = { | ||
| import c.universe._ | ||
|
|
||
| println("bazinga") | ||
|
|
||
| def modifiedClass(classDecl: ClassDef) = { | ||
| println(s"bazinga ${classDecl.name}") | ||
| c.Expr( | ||
| q""" | ||
| trait ${classDecl.name}[T1] extends Function1[T1, Boolean]{ | ||
| self => | ||
|
|
||
| def or[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = self(arg1) || that(arg1) | ||
| } | ||
| def and[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = self(arg1) && that(arg1) | ||
| } | ||
| def xor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = if(self(arg1)) !that(arg1) else that(arg1) | ||
| } | ||
| def nor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = !(self(arg1) || that(arg1)) | ||
| } | ||
| def nand[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = !(self(arg1) && that(arg1)) | ||
| } | ||
| def nxor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = if(self(arg1)) that(arg1) else !that(arg1) | ||
| } | ||
| def not = new Predicate1[T1]{ | ||
| def apply(arg1: T1) = !self(arg1) | ||
| } | ||
| override def toString() = "<predicate1>" | ||
|
|
||
| } | ||
|
|
||
| object ${classDecl.name.toTermName} { | ||
| object Always extends ${classDecl.name}[Any]{ | ||
| def apply(arg1: Any) = true | ||
| } | ||
|
|
||
| val always = Always | ||
|
|
||
| object Never extends ${classDecl.name}[Any]{ | ||
| def apply(arg1: Any) = false | ||
| } | ||
|
|
||
| val never = Never | ||
| } | ||
| """) | ||
| } | ||
|
|
||
| annottees.map(_.tree) match { | ||
| case (classDecl: ClassDef) :: Nil => modifiedClass(classDecl) | ||
| case _ => c.abort(c.enclosingPosition, "Invalid annottee") | ||
| } | ||
| } | ||
|
|
||
| } | ||
| } | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,41 +1,6 @@ | ||
| package com.wheaties.predicate | ||
|
|
||
| import com.wheaties.logical._ | ||
| import com.wheaties.predicate.Macros.GeneratePredicate | ||
|
|
||
| trait Predicate1[T1] extends Function1[T1, Boolean]{ | ||
| self => | ||
|
|
||
| def or[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = self(arg1) || that(arg1) | ||
| } | ||
| def and[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = self(arg1) && that(arg1) | ||
| } | ||
| def xor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = if(self(arg1)) !that(arg1) else that(arg1) | ||
| } | ||
| def nor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = !(self(arg1) || that(arg1)) | ||
| } | ||
| def nand[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = !(self(arg1) && that(arg1)) | ||
| } | ||
| def nxor[TT1 <: T1](that: Function1[TT1, Boolean]) = new Predicate1[TT1]{ | ||
| def apply(arg1: TT1) = if(self(arg1)) that(arg1) else !that(arg1) | ||
| } | ||
| override def toString() = "<predicate1>" | ||
|
|
||
| } | ||
| object Predicate1{ | ||
| implicit def not[T1] = new Negation[Predicate1[T1]]{ | ||
| def not(pred: Predicate1[T1]) = new Predicate1[T1]{ | ||
| def apply(arg1: T1) = !pred(arg1) | ||
| } | ||
| } | ||
| } | ||
| object Always1 extends Predicate1[Any]{ | ||
| def apply(arg1: Any) = true | ||
| } | ||
| object Never1 extends Predicate1[Any]{ | ||
| def apply(arg1: Any) = false | ||
| } | ||
| @GeneratePredicate | ||
| trait Predicate1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,6 +61,24 @@ class PredicateSpec extends WordSpecLike | |
| val filtered = sampleList.filter(Modulo(2, 0) or (Modulo(3, 0) and LessThen(6))) | ||
| filtered should equal(List(2, 3, 4, 6)) | ||
| } | ||
|
|
||
| "have implicit `not` method" in new SpecExamples { | ||
| // val filtered = sampleList.filter(Predicate1.not.not(Modulo(2, 0))) | ||
| val filtered = sampleList.filter(Modulo(2, 0).not) | ||
| filtered should equal(List(3, 5)) | ||
| } | ||
|
|
||
| "have accompanying Always" in new SpecExamples { | ||
| // val filtered = sampleList.filter(Modulo(2, 0) or Always1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented out line worked with old API. Such API is impossible to achieve using just macro annotation because it may return just annotated type and its companion object (no other top level objects). So instead I create inner Object which is then available via field |
||
| val filtered = sampleList.filter(Modulo(2, 0) or Predicate1.always) | ||
| filtered should equal(sampleList) | ||
| } | ||
|
|
||
| "have accompanying Never" in new SpecExamples { | ||
| // val filtered = sampleList.filter(Modulo(2, 0) and Never1) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same thing as with |
||
| val filtered = sampleList.filter(Modulo(2, 0) and Predicate1.never) | ||
| filtered should equal(List.empty) | ||
| } | ||
| } | ||
|
|
||
| trait SpecExamples { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented out line worked with old API.
Predicate.not.notlooked weird so I simply changed it to a method. Maybe I was missing something - how it was intended to be used?