All Downloads are FREE. Search and download functionalities are using the official Maven repository.

shapeless.nat.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2011-16 Miles Sabin
 *
 * 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 shapeless

import scala.language.experimental.macros

import scala.annotation.tailrec
import scala.reflect.macros.whitebox

/**
 * Base trait for type level natural numbers.
 *
 * @author Miles Sabin
 */
trait Nat {
  type N <: Nat
}

/**
 * Encoding of successor.
 *
 * @author Miles Sabin
 */
case class Succ[P <: Nat]() extends Nat {
  type N = Succ[P]
}

/**
 * Encoding of zero.
 *
 * @author Miles Sabin
 */
class _0 extends Nat with Serializable {
  type N = _0
}

/**
 * Type level encoding of the natural numbers.
 *
 * @author Miles Sabin
 */
object Nat extends Nats {
  import ops.nat._
  import syntax.NatOps

  implicit def apply(i: Int): Nat = macro NatMacros.materializeWidened

  /** The natural number 0 */
  type _0 = shapeless._0
  val _0: _0 = new _0

  def toInt[N <: Nat](implicit toIntN : ToInt[N]) = toIntN()

  def toInt(n : Nat)(implicit toIntN : ToInt[n.N]) = toIntN()

  implicit def natOps[N <: Nat](n : N) : NatOps[N] = new NatOps(n)
}

@macrocompat.bundle
class NatMacros(val c: whitebox.Context) extends NatMacroDefns {
  import c.universe._

  def materializeWidened(i: Tree): Tree =
    i match {
      case NatLiteral(n) => mkNatValue(n)
      case _ =>
        c.abort(c.enclosingPosition, s"Expression $i does not evaluate to a non-negative Int literal")
    }
}

@macrocompat.bundle
trait NatMacroDefns {
  val c: whitebox.Context
  import c.universe._

  object NatLiteral {
    def unapply(i: Tree): Option[Int] =
      i match {
        case Literal(Constant(n: Int)) if n >= 0 => Some(n)
        case _ => None
      }
  }

  def mkNatTpt(i: Int): Tree = {
    val succSym = typeOf[Succ[_]].typeConstructor.typeSymbol
    val _0Sym = typeOf[_0].typeSymbol

    @tailrec
    def loop(i: Int, acc: Tree): Tree = {
      if(i == 0) acc
      else loop(i-1, AppliedTypeTree(Ident(succSym), List(acc)))
    }

    loop(i, Ident(_0Sym))
  }

  def mkNatTpe(i: Int): Type = {
    val succTpe = typeOf[Succ[_]].typeConstructor
    val _0Tpe = typeOf[_0]

    @tailrec
    def loop(i: Int, acc: Type): Type = {
      if(i == 0) acc
      else loop(i-1, appliedType(succTpe, acc))
    }

    loop(i, _0Tpe)
  }

  def mkNatValue(i: Int): Tree =
    q""" new ${mkNatTpt(i)} """
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy