From 70bd28f89ed1b44a5da2810c08dbdf204bd3b35e Mon Sep 17 00:00:00 2001 From: neuralagent Date: Sat, 7 Jan 2017 18:32:49 -0500 Subject: [PATCH] Generalize quantification of measures. Remove redundant code. --- .../skylark/measure/QuantifyAnyMeasure.scala | 97 ------------------- .../skylark/measure/QuantifyMeasure.scala | 43 +++++++- .../quantarray/skylark/measure/package.scala | 2 +- 3 files changed, 40 insertions(+), 102 deletions(-) delete mode 100644 skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyAnyMeasure.scala diff --git a/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyAnyMeasure.scala b/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyAnyMeasure.scala deleted file mode 100644 index a76454a..0000000 --- a/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyAnyMeasure.scala +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Skylark - * http://skylark.io - * - * Copyright 2012-2016 Quantarray, LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.quantarray.skylark.measure - -import scala.annotation.{StaticAnnotation, compileTimeOnly} -import scala.language.experimental.macros -import scala.reflect.macros.blackbox - -@compileTimeOnly("QuantifyAnyMeasure annotation can only be used with classes") -private[measure] class QuantifyAnyMeasure[T, Q](measuresScope: Any) extends StaticAnnotation -{ - def macroTransform(annottees: Any*): Any = macro QuantifyAnyMeasure.macroTransformImpl - -} - -private[measure] object QuantifyAnyMeasure -{ - def macroTransformImpl(c: blackbox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = - { - import c.universe._ - - val targetTraitTree: Tree = c.prefix.tree match - { - case q"new $name[$targetTraitTree, $quantityTree](...$paramss)" => targetTraitTree - } - - val targetTraitTpe: Type = c.typecheck(q"0.asInstanceOf[$targetTraitTree]").tpe - - val measuresScope: List[Tree] = c.prefix.tree match - { - case q"new $name[$targetTraitTpe, $quantityTpe](...$paramss)" if paramss.nonEmpty => paramss.head - case _ => c.abort(c.enclosingPosition, "QuantifyAnyMeasure requires a single constructor parameter pointing to the scope where measures are defined.") - } - - val measureValTermSymbols: List[TermSymbol] = targetTraitTpe.members.collect - { case d if d.isTerm => d.asTerm }.filter(t => t.isStable && t.isVal && t.isFinal).toList.reverse - - val quantityDefs = measureValTermSymbols.map( - { - measureValTermSymbol => - - val quantityIdentifier = TermName(measureValTermSymbol.name.toString.trim) - val measureTermName = TermName(measureValTermSymbol.name.toString.trim) - - val quantityTpeIdentifier = q"""Quantity[Double, AnyMeasure]""" - - q"""def $quantityIdentifier = $quantityTpeIdentifier(value, ${measuresScope.head}.$measureTermName)""" - }) - - val className = annottees.map(_.tree) match - { - case List(q"$mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlyDefs } with ..$parents { $self => ..$stats }") => - - paramss match - { - case List(List(q"$paramAccessor val value: $valueType")) => - case _ => c.abort(c.enclosingPosition, s"$tpname must have a single parameter named 'value'.") - } - - tpname - - case _ => c.abort(c.enclosingPosition, s"QuantifyAnyMeasure annotation can only be used with classes.") - } - - c.Expr( - q""" - implicit class $className(val value: Double) extends AnyVal - { - implicit def qn: QuasiNumeric[Double] = implicitly(QuasiNumeric.doubleQuasiNumeric) - - def apply(measure: AnyMeasure): Quantity[Double, AnyMeasure] = Quantity(value, measure) - - def *(measure: AnyMeasure): Quantity[Double, AnyMeasure] = apply(measure) - - ..$quantityDefs - } - """ - ) - } -} \ No newline at end of file diff --git a/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyMeasure.scala b/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyMeasure.scala index 095239b..8833e53 100644 --- a/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyMeasure.scala +++ b/skylark-measure-macros/src/main/scala/com/quantarray/skylark/measure/QuantifyMeasure.scala @@ -43,6 +43,17 @@ private[measure] object QuantifyMeasure val targetTraitTpe: Type = c.typecheck(q"0.asInstanceOf[$targetTraitTree]").tpe + val quantityTree: Tree = c.prefix.tree match + { + case q"new $name[$targetTraitTree, $quantityTree](...$paramss)" => quantityTree + } + + val isAnyMeasure = quantityTree match + { + case tq"Quantity[$numericType, AnyMeasure]" => true + case _ => false + } + val measuresScope: List[Tree] = c.prefix.tree match { case q"new $name[$targetTraitTpe, $quantityTpe](...$paramss)" if paramss.nonEmpty => paramss.head @@ -59,7 +70,11 @@ private[measure] object QuantifyMeasure val quantityIdentifier = TermName(measureValTermSymbol.name.toString.trim) val measureTermName = TermName(measureValTermSymbol.name.toString.trim) - val quantityTpeIdentifier = q"""Quantity[Double, ${measureValTermSymbol.typeSignature}]""" + val quantityTpeIdentifier = + if (isAnyMeasure) + q"""Quantity[Double, AnyMeasure]""" + else + q"""Quantity[Double, ${measureValTermSymbol.typeSignature}]""" q"""def $quantityIdentifier = $quantityTpeIdentifier(value, ${measuresScope.head}.$measureTermName)""" }) @@ -79,8 +94,27 @@ private[measure] object QuantifyMeasure case _ => c.abort(c.enclosingPosition, s"QuantifyMeasure annotation can only be used with classes.") } - c.Expr( - q""" + if (isAnyMeasure) + { + c.Expr( + q""" + implicit class $className(val value: Double) extends AnyVal + { + implicit def qn: QuasiNumeric[Double] = implicitly(QuasiNumeric.doubleQuasiNumeric) + + def apply(measure: AnyMeasure): Quantity[Double, AnyMeasure] = Quantity(value, measure) + + def *(measure: AnyMeasure): Quantity[Double, AnyMeasure] = apply(measure) + + ..$quantityDefs + } + """ + ) + } + else + { + c.Expr( + q""" implicit class $className(val value: Double) extends AnyVal { implicit def qn: QuasiNumeric[Double] = implicitly(QuasiNumeric.doubleQuasiNumeric) @@ -92,6 +126,7 @@ private[measure] object QuantifyMeasure ..$quantityDefs } """ - ) + ) + } } } \ No newline at end of file diff --git a/skylark-measure/src/main/scala/com/quantarray/skylark/measure/package.scala b/skylark-measure/src/main/scala/com/quantarray/skylark/measure/package.scala index c46cd38..7174f61 100644 --- a/skylark-measure/src/main/scala/com/quantarray/skylark/measure/package.scala +++ b/skylark-measure/src/main/scala/com/quantarray/skylark/measure/package.scala @@ -45,7 +45,7 @@ package object measure extends DefaultDimensions object any { - @QuantifyAnyMeasure[DefaultMeasures, Quantity[Double, AnyMeasure]](measuresScope) + @QuantifyMeasure[DefaultMeasures, Quantity[Double, AnyMeasure]](measuresScope) class QuantifiedAnyMeasures(val value: Double) }