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

scala.scalanative.nir.Show.scala Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
package scala.scalanative
package nir

import java.nio.charset.StandardCharsets
import scala.collection.mutable
import scala.scalanative.util.ShowBuilder.InMemoryShowBuilder
import scalanative.util.{ShowBuilder, unreachable}

object Show {
  def newBuilder: NirShowBuilder = new NirShowBuilder(new InMemoryShowBuilder)
  def debug[T](msg: String)(f: => T): T = {
    val value = f
    println("$msg: " + value)
    value
  }

  def apply(v: Attr): String = { val b = newBuilder; b.attr_(v); b.toString }
  def apply(v: Attrs): String = { val b = newBuilder; b.attrs_(v); b.toString }
  def apply(v: Bin): String = { val b = newBuilder; b.bin_(v); b.toString }
  def apply(v: Comp): String = { val b = newBuilder; b.comp_(v); b.toString }
  def apply(v: Conv): String = { val b = newBuilder; b.conv_(v); b.toString }
  def apply(v: Defn): String = { val b = newBuilder; b.defn_(v); b.toString }
  def apply(v: Global): String = {
    val b = newBuilder; b.global_(v); b.toString
  }
  def apply(v: Sig): String = {
    val b = newBuilder; b.sig_(v); b.toString
  }
  def apply(v: Inst): String = { val b = newBuilder; b.inst_(v); b.toString }
  def apply(v: Local): String = { val b = newBuilder; b.local_(v); b.toString }
  def apply(v: Next): String = { val b = newBuilder; b.next_(v); b.toString }
  def apply(v: Op): String = { val b = newBuilder; b.op_(v); b.toString }
  def apply(v: Type): String = { val b = newBuilder; b.type_(v); b.toString }
  def apply(v: Val): String = { val b = newBuilder; b.val_(v); b.toString }

  type DefnString = (Global, String)

  def dump(defns: Seq[Defn], fileName: String): Unit = {
    val pw = new java.io.PrintWriter(fileName)

    try {
      defns
        .filter(_ != null)
        .sortBy(_.name)
        .foreach { defn =>
          pw.write(defn.show)
          pw.write("\n")
        }
    } finally {
      pw.close()
    }
  }

  final class NirShowBuilder(val builder: ShowBuilder) extends AnyVal {
    import builder._

    def attrs_(attrs: Attrs): Unit =
      if (attrs == Attrs.None) {
        ()
      } else {
        attrs_(attrs.toSeq)
      }

    def attrs_(attrs: Seq[Attr]): Unit = {
      rep(attrs, sep = " ")(attr_)
      str(" ")
    }

    def attr_(attr: Attr): Unit = attr match {
      case Attr.MayInline =>
        str("mayinline")
      case Attr.InlineHint =>
        str("inlinehint")
      case Attr.NoInline =>
        str("noinline")
      case Attr.AlwaysInline =>
        str("alwaysinline")
      case Attr.MaySpecialize =>
        str("mayspecialize")
      case Attr.NoSpecialize =>
        str("nospecialize")
      case Attr.UnOpt =>
        str("unopt")
      case Attr.NoOpt =>
        str("noopt")
      case Attr.DidOpt =>
        str("didopt")
      case Attr.BailOpt(msg) =>
        str("bailopt(\"")
        str(escapeQuotes(msg))
        str("\")")
      case Attr.Dyn =>
        str("dyn")
      case Attr.Stub =>
        str("stub")
      case Attr.Extern =>
        str("extern")
      case Attr.Link(name) =>
        str("link(\"")
        str(escapeQuotes(name))
        str("\")")
      case Attr.Abstract =>
        str("abstract")
      case Attr.LinktimeResolved =>
        str("linktime")
    }

    def next_(next: Next): Unit = next match {
      case Next.Label(name, Seq()) =>
        local_(name)
      case Next.Unwind(exc, next) =>
        str("unwind ")
        val_(exc)
        str(" to ")
        next_(next)
      case Next.Case(v, next) =>
        str("case ")
        val_(v)
        str(" => ")
        next_(next)
      case Next.Label(name, args) =>
        local_(name)
        str("(")
        rep(args, sep = ", ")(val_)
        str(")")
      case Next.None => ()
    }

    def inst_(inst: Inst): Unit = inst match {
      case Inst.Label(name, params) =>
        local_(name)
        if (params.isEmpty) {
          ()
        } else {
          str("(")
          rep(params, sep = ", ") {
            case Val.Local(n, ty) =>
              local_(n)
              str(" : ")
              type_(ty)
          }
          str(")")
        }
        str(":")
      case Inst.Let(name, op, unwind) =>
        local_(name)
        str(" = ")
        op_(op)
        if (unwind ne Next.None) {
          str(" ")
          next_(unwind)
        }
      case Inst.Ret(value) =>
        str("ret ")
        val_(value)
      case Inst.Jump(next) =>
        str("jump ")
        next_(next)
      case Inst.If(cond, thenp, elsep) =>
        str("if ")
        val_(cond)
        str(" then ")
        next_(thenp)
        str(" else ")
        next_(elsep)
      case Inst.LinktimeIf(cond, thenp, elsep) =>
        str("linktime if ")
        linktimeCondition(cond)
        str(" then ")
        next_(thenp)
        str(" else ")
        next_(elsep)
      case Inst.Switch(scrut, default, cases) =>
        str("switch ")
        val_(scrut)
        str(" {")
        rep(cases) { next =>
          str(" ")
          next_(next)
        }
        str(" default => ")
        next_(default)
        str(" }")
      case Inst.Throw(v, unwind) =>
        str("throw ")
        val_(v)
        if (unwind ne Next.None) {
          str(" ")
          next_(unwind)
        }
      case Inst.Unreachable(unwind) =>
        str("unreachable")
        if (unwind ne Next.None) {
          str(" ")
          next_(unwind)
        }
    }

    def op_(op: Op): Unit = op match {
      case Op.Call(ty, f, args) =>
        str("call[")
        type_(ty)
        str("] ")
        val_(f)
        str("(")
        rep(args, sep = ", ")(val_)
        str(")")
      case Op.Load(ty, ptr) =>
        str("load[")
        type_(ty)
        str("] ")
        val_(ptr)
      case Op.Store(ty, ptr, value) =>
        str("store[")
        type_(ty)
        str("] ")
        val_(ptr)
        str(", ")
        val_(value)
      case Op.Elem(ty, ptr, indexes) =>
        str("elem[")
        type_(ty)
        str("] ")
        val_(ptr)
        str(", ")
        rep(indexes, sep = ", ")(val_)
      case Op.Extract(aggr, indexes) =>
        str("extract ")
        val_(aggr)
        str(", ")
        rep(indexes, sep = ", ")(str)
      case Op.Insert(aggr, value, indexes) =>
        str("insert ")
        val_(aggr)
        str(", ")
        val_(value)
        str(", ")
        rep(indexes, sep = ", ")(str)
      case Op.Stackalloc(ty, n) =>
        str("stackalloc[")
        type_(ty)
        str("]")
        str(" ")
        val_(n)
      case Op.Bin(bin, ty, l, r) =>
        bin_(bin)
        str("[")
        type_(ty)
        str("] ")
        val_(l)
        str(", ")
        val_(r)
      case Op.Comp(comp, ty, l, r) =>
        comp_(comp)
        str("[")
        type_(ty)
        str("] ")
        val_(l)
        str(", ")
        val_(r)
      case Op.Conv(conv, ty, v) =>
        conv_(conv)
        str("[")
        type_(ty)
        str("] ")
        val_(v)

      case Op.Classalloc(name) =>
        str("classalloc ")
        global_(name)
      case Op.Fieldload(ty, obj, name) =>
        str("fieldload[")
        type_(ty)
        str("] ")
        val_(obj)
        str(", ")
        global_(name)
      case Op.Fieldstore(ty, obj, name, value) =>
        str("fieldstore[")
        type_(ty)
        str("] ")
        val_(obj)
        str(", ")
        global_(name)
        str(", ")
        val_(value)
      case Op.Field(value, name) =>
        str("field ")
        val_(value)
        str(", ")
        global_(name)
      case Op.Method(value, sig) =>
        str("method ")
        val_(value)
        str(", \"")
        str(escapeQuotes(sig.mangle))
        str("\"")
      case Op.Dynmethod(value, sig) =>
        str("dynmethod ")
        val_(value)
        str(", \"")
        str(escapeQuotes(sig.mangle))
        str("\"")
      case Op.Module(name) =>
        str("module ")
        global_(name)
      case Op.As(ty, v) =>
        str("as[")
        type_(ty)
        str("] ")
        val_(v)
      case Op.Is(ty, v) =>
        str("is[")
        type_(ty)
        str("] ")
        val_(v)
      case Op.Copy(value) =>
        str("copy ")
        val_(value)
      case Op.Sizeof(ty) =>
        str("sizeof[")
        type_(ty)
        str("] ")
      case Op.Box(ty, v) =>
        str("box[")
        type_(ty)
        str("] ")
        val_(v)
      case Op.Unbox(ty, v) =>
        str("unbox[")
        type_(ty)
        str("] ")
        val_(v)
      case Op.Var(ty) =>
        str("var[")
        type_(ty)
        str("]")
      case Op.Varload(slot) =>
        str("varload ")
        val_(slot)
      case Op.Varstore(slot, value) =>
        str("varstore ")
        val_(slot)
        str(", ")
        val_(value)
      case Op.Arrayalloc(ty, init) =>
        str("arrayalloc[")
        type_(ty)
        str("] ")
        val_(init)
      case Op.Arrayload(ty, arr, idx) =>
        str("arrayload[")
        type_(ty)
        str("] ")
        val_(arr)
        str(", ")
        val_(idx)
      case Op.Arraystore(ty, arr, idx, value) =>
        str("arraystore[")
        type_(ty)
        str("] ")
        val_(arr)
        str(", ")
        val_(idx)
        str(", ")
        val_(value)
      case Op.Arraylength(arr) =>
        str("arraylength ")
        val_(arr)
    }

    def bin_(bin: Bin): Unit = bin match {
      case Bin.Iadd => str("iadd")
      case Bin.Fadd => str("fadd")
      case Bin.Isub => str("isub")
      case Bin.Fsub => str("fsub")
      case Bin.Imul => str("imul")
      case Bin.Fmul => str("fmul")
      case Bin.Sdiv => str("sdiv")
      case Bin.Udiv => str("udiv")
      case Bin.Fdiv => str("fdiv")
      case Bin.Srem => str("srem")
      case Bin.Urem => str("urem")
      case Bin.Frem => str("frem")
      case Bin.Shl  => str("shl")
      case Bin.Lshr => str("lshr")
      case Bin.Ashr => str("ashr")
      case Bin.And  => str("and")
      case Bin.Or   => str("or")
      case Bin.Xor  => str("xor")
    }

    def comp_(comp: Comp): Unit = comp match {
      case Comp.Ieq => str("ieq")
      case Comp.Ine => str("ine")
      case Comp.Ugt => str("ugt")
      case Comp.Uge => str("uge")
      case Comp.Ult => str("ult")
      case Comp.Ule => str("ule")
      case Comp.Sgt => str("sgt")
      case Comp.Sge => str("sge")
      case Comp.Slt => str("slt")
      case Comp.Sle => str("sle")
      case Comp.Feq => str("feq")
      case Comp.Fne => str("fne")
      case Comp.Fgt => str("fgt")
      case Comp.Fge => str("fge")
      case Comp.Flt => str("flt")
      case Comp.Fle => str("fle")
    }

    def conv_(conv: Conv): Unit = conv match {
      case Conv.Trunc    => str("trunc")
      case Conv.Zext     => str("zext")
      case Conv.Sext     => str("sext")
      case Conv.Fptrunc  => str("fptrunc")
      case Conv.Fpext    => str("fpext")
      case Conv.Fptoui   => str("fptoui")
      case Conv.Fptosi   => str("fptosi")
      case Conv.Uitofp   => str("uitofp")
      case Conv.Sitofp   => str("sitofp")
      case Conv.Ptrtoint => str("ptrtoint")
      case Conv.Inttoptr => str("inttoptr")
      case Conv.Bitcast  => str("bitcast")
    }

    def val_(value: Val): Unit = value match {
      case Val.True =>
        str("true")
      case Val.False =>
        str("false")
      case Val.Null =>
        str("null")
      case Val.Zero(ty) =>
        str("zero[")
        type_(ty)
        str("]")
      case Val.Char(value) =>
        str("char ")
        str(value.toInt)
      case Val.Byte(value) =>
        str("byte ")
        str(value)
      case Val.Short(value) =>
        str("short ")
        str(value)
      case Val.Int(value) =>
        str("int ")
        str(value)
      case Val.Long(value) =>
        str("long ")
        str(value)
      case Val.Float(value) =>
        str("float ")
        str(value)
      case Val.Double(value) =>
        str("double ")
        str(value)
      case Val.StructValue(values) =>
        str("structvalue {")
        rep(values, sep = ", ")(val_)
        str("}")
      case Val.ArrayValue(ty, values) =>
        str("arrayvalue ")
        type_(ty)
        str(" {")
        rep(values, sep = ", ")(val_)
        str("}")
      case v: Val.Chars =>
        str("c\"")
        val stringValue =
          new java.lang.String(v.bytes, StandardCharsets.ISO_8859_1)
        str(escapeNewLine(escapeQuotes(stringValue)))
        str("\"")
      case Val.Local(name, ty) =>
        local_(name)
        str(" : ")
        type_(ty)
      case Val.Global(name, ty) =>
        global_(name)
        str(" : ")
        type_(ty)
      case Val.Unit =>
        str("unit")
      case Val.Const(v) =>
        str("const ")
        val_(v)
      case Val.String(v) =>
        str("\"")
        str(escapeNewLine(escapeQuotes(v)))
        str("\"")
      case Val.Virtual(key) =>
        str("virtual ")
        str(key)
      case Val.ClassOf(cls) =>
        str("classOf[")
        global_(cls)
        str("]")
    }

    def defns_(defns: Seq[Defn]): Unit =
      rep(defns) { defn =>
        newline()
        defn_(defn)
      }

    def defn_(defn: Defn): Unit = defn match {
      case Defn.Var(attrs, name, ty, v) =>
        attrs_(attrs)
        str("var ")
        global_(name)
        str(" : ")
        type_(ty)
        str(" = ")
        val_(v)
      case Defn.Const(attrs, name, ty, v) =>
        attrs_(attrs)
        str("const ")
        global_(name)
        str(" : ")
        type_(ty)
        str(" = ")
        val_(v)
      case Defn.Declare(attrs, name, ty) =>
        attrs_(attrs)
        str("decl ")
        global_(name)
        str(" : ")
        type_(ty)
      case Defn.Define(attrs, name, ty, insts) =>
        attrs_(attrs)
        str("def ")
        global_(name)
        str(" : ")
        type_(ty)
        str(" {")
        rep(insts) {
          case inst: Inst.Label =>
            newline()
            inst_(inst)
          case inst =>
            indent()
            newline()
            inst_(inst)
            unindent()
        }
        newline()
        str("}")
      case Defn.Trait(attrs, name, ifaces) =>
        attrs_(attrs)
        str("trait ")
        global_(name)
        if (ifaces.nonEmpty) {
          str(" : ")
          rep(ifaces, sep = ", ")(global_)
        }
      case Defn.Class(attrs, name, parent, ifaces) =>
        val parents = parent ++: ifaces
        attrs_(attrs)
        str("class ")
        global_(name)
        if (parents.nonEmpty) {
          str(" : ")
          rep(parents, sep = ", ")(global_)
        }
      case Defn.Module(attrs, name, parent, ifaces) =>
        val parents = parent ++: ifaces
        attrs_(attrs)
        str("module ")
        global_(name)
        if (parents.nonEmpty) {
          str(" : ")
          rep(parents, sep = ", ")(global_)
        }
    }

    def type_(ty: Type): Unit = ty match {
      case Type.Vararg => str("...")
      case Type.Bool   => str("bool")
      case Type.Ptr    => str("ptr")
      case Type.Char   => str("char")
      case Type.Byte   => str("byte")
      case Type.Short  => str("short")
      case Type.Int    => str("int")
      case Type.Long   => str("long")
      case Type.Float  => str("float")
      case Type.Double => str("double")

      case Type.ArrayValue(ty, n) =>
        str("[")
        type_(ty)
        str(" x ")
        str(n)
        str("]")
      case Type.Function(args, ret) =>
        str("(")
        rep(args, sep = ", ")(type_)
        str(") => ")
        type_(ret)
      case Type.StructValue(tys) =>
        str("{")
        rep(tys, sep = ", ")(type_)
        str("}")

      case Type.Null    => str("null")
      case Type.Nothing => str("nothing")
      case Type.Virtual => str("virtual")
      case Type.Var(ty) => str("var["); type_(ty); str("]")
      case Type.Unit    => str("unit")
      case Type.Array(ty, nullable) =>
        if (!nullable) {
          str("?")
        }
        str("array[")
        type_(ty)
        str("]")
      case Type.Ref(name, exact, nullable) =>
        if (exact) {
          str("!")
        }
        if (!nullable) {
          str("?")
        }
        global_(name)
    }

    def global_(global: Global): Unit = global match {
      case Global.None =>
        unreachable
      case _ =>
        str("@\"")
        str(escapeQuotes(global.mangle))
        str("\"")
    }

    def sig_(sig: Sig): Unit =
      str(sig.mangle)

    def local_(local: Local): Unit = {
      str("%")
      str(local.id)
    }

    def linktimeCondition(cond: LinktimeCondition): Unit = {
      import LinktimeCondition._
      cond match {
        case SimpleCondition(propertyName, comparison, value) =>
          str(propertyName + " ")
          comp_(comparison)
          str(" ")
          val_(value)
        case ComplexCondition(op, left, right) =>
          linktimeCondition(left)
          str(" ")
          bin_(op)
          str(" ")
          linktimeCondition(right)
      }
    }

    private def escapeNewLine(s: String): String =
      """([^\\]|^)\n""".r.replaceAllIn(
        s,
        _.matched.toSeq match {
          case Seq(sngl)     => raw"\\n"
          case Seq('$', snd) => raw"\$$\\n"
          case Seq(fst, snd) => raw"\${fst}\\n"
        }
      )

    private def escapeQuotes(s: String): String = {
      val chars = s.toArray
      val out = mutable.UnrolledBuffer.empty[Char]
      var i = 0
      var escaped = false
      while (i < chars.length) {
        val char = chars(i)
        char match {
          case '"' =>
            if (!escaped) out += '\\'
            out += char
          case _ =>
            out += char
        }
        escaped = char == '\\'
        i += 1
      }
      new String(out.toArray)
    }

    override def toString: String = builder.toString
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy