| /* |
| * 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 |
| |
| abstract class Field[T] private (val default: Option[T]) { |
| 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) |
| require(out.isDefined, s"Key ${pname} is not defined in Parameters") |
| out.get |
| } |
| |
| final def lift[T](pname: Field[T]): Option[T] = lift(pname, this) |
| final def lift[T](pname: Field[T], site: View): Option[T] = |
| find(pname, site).map(_.asInstanceOf[T]) |
| |
| protected[config] def find[T](pname: Field[T], site: View): Option[T] |
| } |
| |
| abstract class Parameters extends View { |
| final def ++(x: Parameters): Parameters = |
| new ChainParameters(this, x) |
| |
| final def alter( |
| f: (View, View, View) => PartialFunction[Any, Any]): Parameters = |
| Parameters(f) ++ this |
| |
| final def alterPartial(f: PartialFunction[Any, Any]): Parameters = |
| Parameters((_, _, _) => f) ++ this |
| |
| final def alterMap(m: Map[Any, Any]): Parameters = |
| new MapParameters(m) ++ this |
| |
| 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) |
| } |
| |
| object Parameters { |
| def empty: Parameters = new EmptyParameters |
| def apply(f: (View, View, View) => PartialFunction[Any, Any]): Parameters = |
| new PartialParameters(f) |
| } |
| |
| class Config(p: Parameters) extends Parameters { |
| def this(f: (View, View, View) => PartialFunction[Any, Any]) = |
| this(Parameters(f)) |
| |
| protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = |
| p.chain(site, tail, pname) |
| 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 { |
| def chain[T](site: View, tail: View, pname: Field[T]) = |
| x.chain(site, new ChainView(y, tail), pname) |
| } |
| |
| private class EmptyParameters extends Parameters { |
| def chain[T](site: View, tail: View, pname: Field[T]) = tail.find(pname, site) |
| } |
| |
| private class PartialParameters( |
| f: (View, View, View) => PartialFunction[Any, Any]) |
| extends Parameters { |
| protected[config] def chain[T](site: View, tail: View, pname: Field[T]) = { |
| val g = f(site, this, tail) |
| if (g.isDefinedAt(pname)) Some(g.apply(pname).asInstanceOf[T]) |
| else tail.find(pname, site) |
| } |
| } |
| |
| 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) |
| } |
| } |