Config.scala 3.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 vta.util.config

// taken from https://github.com/vta.roject/rocket-chip

24
abstract class Field[T] private (val default: Option[T]) {
25 26 27 28 29 30 31 32
  def this() = this(None)
  def this(default: T) = this(Some(default))
}

abstract class View {
  final def apply[T](pname: Field[T]): T = apply(pname, this)
  final def apply[T](pname: Field[T], site: View): T = {
    val out = find(pname, site)
33
    require(out.isDefined, s"Key ${pname} is not defined in Parameters")
34 35 36 37
    out.get
  }

  final def lift[T](pname: Field[T]): Option[T] = lift(pname, this)
38 39
  final def lift[T](pname: Field[T], site: View): Option[T] =
    find(pname, site).map(_.asInstanceOf[T])
40 41 42 43 44

  protected[config] def find[T](pname: Field[T], site: View): Option[T]
}

abstract class Parameters extends View {
45
  final def ++(x: Parameters): Parameters =
46 47
    new ChainParameters(this, x)

48 49
  final def alter(
      f: (View, View, View) => PartialFunction[Any, Any]): Parameters =
50 51
    Parameters(f) ++ this

52 53
  final def alterPartial(f: PartialFunction[Any, Any]): Parameters =
    Parameters((_, _, _) => f) ++ this
54

55
  final def alterMap(m: Map[Any, Any]): Parameters =
56 57
    new MapParameters(m) ++ this

58 59 60 61 62
  protected[config] def chain[T](site: View,
                                 tail: View,
                                 pname: Field[T]): Option[T]
  protected[config] def find[T](pname: Field[T], site: View) =
    chain(site, new TerminalView, pname)
63 64 65 66
}

object Parameters {
  def empty: Parameters = new EmptyParameters
67 68
  def apply(f: (View, View, View) => PartialFunction[Any, Any]): Parameters =
    new PartialParameters(f)
69 70 71
}

class Config(p: Parameters) extends Parameters {
72 73
  def this(f: (View, View, View) => PartialFunction[Any, Any]) =
    this(Parameters(f))
74

75 76
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]) =
    p.chain(site, tail, pname)
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
  override def toString = this.getClass.getSimpleName
  def toInstance = this
}

// Internal implementation:

private class TerminalView extends View {
  def find[T](pname: Field[T], site: View): Option[T] = pname.default
}

private class ChainView(head: Parameters, tail: View) extends View {
  def find[T](pname: Field[T], site: View) = head.chain(site, tail, pname)
}

private class ChainParameters(x: Parameters, y: Parameters) extends Parameters {
92 93
  def chain[T](site: View, tail: View, pname: Field[T]) =
    x.chain(site, new ChainView(y, tail), pname)
94 95 96 97 98 99
}

private class EmptyParameters extends Parameters {
  def chain[T](site: View, tail: View, pname: Field[T]) = tail.find(pname, site)
}

100 101 102
private class PartialParameters(
    f: (View, View, View) => PartialFunction[Any, Any])
    extends Parameters {
103 104
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = {
    val g = f(site, this, tail)
105 106
    if (g.isDefinedAt(pname)) Some(g.apply(pname).asInstanceOf[T])
    else tail.find(pname, site)
107 108 109 110 111 112 113 114 115
  }
}

private class MapParameters(map: Map[Any, Any]) extends Parameters {
  protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = {
    val g = map.get(pname)
    if (g.isDefined) Some(g.get.asInstanceOf[T]) else tail.find(pname, site)
  }
}