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

dfhdl.core.DFError.scala Maven / Gradle / Ivy

package dfhdl.core
import dfhdl.compiler.ir
import dfhdl.internals.*

import scala.annotation.targetName
import dfhdl.options.OnError

sealed abstract class DFError(
    val dfMsg: String
) extends Exception(dfMsg) derives CanEqual

object DFError:
  class Basic(
      val opName: String,
      val iae: IllegalArgumentException
  )(using dfc: DFC)
      extends DFError(iae.getMessage):
    import dfc.getSet
    val designName = dfc.ownerOption match
      case Some(owner) => owner.asIR.getThisOrOwnerDesign.getFullName
      case None        => ""
    val fullName =
      if (dfc.isAnonymous) designName
      else if (designName.nonEmpty) s"$designName.${dfc.name}"
      else dfc.name
    val position = dfc.position
    override def toString: String =
      s"""|DFiant HDL elaboration error!
          |Position:  ${position}
          |Hierarchy: ${fullName}
          |Operation: `${opName}`
          |Message:   ${dfMsg}""".stripMargin
  end Basic
  object FakeEnum extends DFError("This value of enum is no meant to be accessed.")
  final class Derived(from: DFError) extends DFError(from.dfMsg)
  final class REG_DIN[T <: DFTypeAny](val dfVar: DFVarOf[T])(using dfc: DFC)
      extends Basic(
        "Read access",
        new IllegalArgumentException(
          """|Cannot read from DIN of a register.
             |If you are committing a partial assignment through range or field selection, make sure you apply `.din` after the selection. E.g.:
             |* Instead of `x.din(5, 0)` write `x(5, 0).din`.
             |* Instead of `pixel.din.x` write `pixel.x.din`.
          """.stripMargin
        )
      ):
    var firstTime: Boolean = true

  extension (dfErr: DFError)
    inline def asNet: DFNet = new DFNet(dfErr)
    inline def asFE[T <: DFTypeAny]: T = DFType(dfErr).asInstanceOf[T]
    inline def asValOf[T <: DFTypeAny]: DFValOf[T] = DFVal[T, ModifierAny, DFError](dfErr)
    inline def asVal[T <: DFTypeAny, M <: ModifierAny]: DFVal[T, M] = DFVal[T, M, DFError](dfErr)
    inline def asOwner: DFOwnerAny = DFOwner[ir.DFOwner](dfErr)
end DFError

class Logger:
  private[Logger] var errors: List[DFError] = Nil
  def logError(err: DFError): Unit =
    errors = err :: errors
  def injectErrors(fromLogger: Logger): Unit =
    errors = fromLogger.errors ++ errors
  def getErrors: List[DFError] = errors.reverse
  def clearErrors(): Unit = errors = Nil

def trydfSpecific[T](
    block: => T
)(finale: DFError => T)(using dfc: DFC, ctName: CTName): T =
  if (dfc.inMetaProgramming) block
  else
    try block
    catch
      case e: Exception =>
        val dfErr = e match
          case e: IllegalArgumentException => DFError.Basic(ctName.value, e)
          case e: DFError                  => e
          case e                           => throw e
        if (dfc.ownerOption.isEmpty)
          exitWithError(dfErr.toString())
        dfc.logError(dfErr)
        finale(dfErr)

@targetName("tryDFType")
@metaContextForward(0)
def trydf[T <: DFTypeAny](block: => T)(using DFC, CTName): T =
  trydfSpecific(block)(dfErr => new DFTypeAny(dfErr).asInstanceOf[T])

@targetName("tryDFVal")
@metaContextForward(0)
def trydf[V <: DFValAny](block: => V)(using DFC, CTName): V =
  trydfSpecific(block)(_.asVal[DFTypeAny, ModifierAny].asInstanceOf[V])

@targetName("tryDFNet")
@metaContextForward(0)
def trydf(block: => Unit)(using DFC, CTName): Unit =
  trydfSpecific(block)(_ => ())

@targetName("tryDFOwner")
@metaContextForward(0)
def trydf[V <: DFOwnerAny](block: => V)(using DFC, CTName): V =
  trydfSpecific(block)(_.asOwner.asInstanceOf[V])

def exitWithError(msg: String)(using DFC): Nothing =
  dfc.elaborationOptions.onError match
    case OnError.Exit =>
      println(msg)
      sys.exit(1)
    case _ =>
      throw new IllegalArgumentException(s"Elaboration errors found!\n$msg")




© 2015 - 2024 Weber Informatics LLC | Privacy Policy