<commit_before>package org.mozartoz.bootcompiler
package bytecode

import scala.collection.mutable._

import oz._
import ast._
import symtab._
import util._

class CodeArea(val abstraction: Abstraction) {
  val opCodes = new ArrayBuffer[OpCode]

  private val symbolRegisterAllocs = new HashMap[Symbol, YOrGReg]
  private val constantRegisterAllocs = new HashMap[OzValue, KReg]

  private val YCounter = new RegCounter(YReg)

  val constants = new ArrayBuffer[OzValue]

  def isDefined = !opCodes.isEmpty

  def size = opCodes.map(_.size).sum

  override def toString() = "<CodeArea %s>" format (abstraction.fullName)

  def dump(includeByteCode: Boolean = true) {
    println("constants:")
    for ((constant, index) <- constants.zipWithIndex)
      println("  K(%d) = %s" format (index, constant))

    if (includeByteCode) {
      println()
      for (opCode <- opCodes)
        println(opCode.code)
    }
  }

  def registerFor(symbol: Symbol): YOrGReg = {
    symbolRegisterAllocs.getOrElseUpdate(symbol, {
      if (symbol.isGlobal) GReg(symbol.owner.globals.indexOf(symbol))
      else YCounter.next()
    })
  }

  def registerFor(value: OzValue): KReg = {
    constantRegisterAllocs.getOrElseUpdate(value, {
      constants += value
      KReg(constants.size - 1)
    })
  }

  def registerFor(expr: VarOrConst): Register = expr match {
    case variable:Variable =>
      registerFor(variable.symbol)

    case constant:Constant =>
      registerFor(constant.value)
  }

  def += (opCode: OpCode) =
    opCodes += opCode

  class Hole(index: Int) {
    def fillWith(opCode: OpCode) {
      opCodes(index) = opCode
    }
  }

  def addHole(size: Int = 1) = {
    val index = opCodes.size
    opCodes += OpHole(size)
    new Hole(index)
  }

  def counting(body: => Unit) = {
    val before = opCodes.size
    body
    (before until opCodes.size) map (i => opCodes(i).size) sum
  }

  def computeXCount() = {
    var maxX = 0

    for {
      opCode <- opCodes
      XReg(index) <- opCode.arguments
    } {
      maxX = maxX max index
    }

    maxX + 1
  }

  val ccCodeArea = "codeArea" + abstraction.id.toString()
  val ccCreateMethodName = "createCodeArea" + abstraction.id.toString()

  def produceCC(out: Output) {
    import Output._

    out << """
       |/*
       |""".stripMargin

    Console.withOut(out.underlying) {
      abstraction.dump(includeByteCode = false)
    }

    out << """
       |*/
       |
       |void Program::%s() {
       |  ByteCode codeBlock[] = {
       |""".stripMargin % ccCreateMethodName

    for (opCode <- opCodes)
      out << "    %s,\n" % opCode.code

    out << """
       |  };
       |
       |  %s = CodeArea::build(vm, %d, codeBlock, sizeof(codeBlock), %d);
       |""".stripMargin % (ccCodeArea, constants.size, computeXCount())

    if (!constants.isEmpty) {
      out << """
         |  ArrayInitializer initializer = %s;
         |  UnstableNode temp;
         |""".stripMargin % ccCodeArea

      for ((constant, index) <- constants.zipWithIndex) {
        produceCCInitConstant(out, constant)
        out << "  initializer.initElement(vm, %d, temp);\n" % index
      }
    }

    out << """
       |}
       |""".stripMargin
  }

  private def produceCCInitConstant(out: Output, constant: OzValue) {
    import Output._

    out << "  temp = ";

    constant match {
      case _:OzArity | _:OzRecord | _:OzPatMatOpenRecord =>
        produceCCForConstant(out, constant)

      case _ =>
        out << "build(vm, "
        produceCCForConstant(out, constant)
        out << ")"
    }

    out << ";\n"
  }

  private def produceCCForConstant(out: Output, constant: OzValue) {
    import Output._

    constant match {
      case OzBuiltin(builtin) =>
        out << "::%s::builtin()" % builtin.ccFullName

      case OzCodeArea(codeArea) =>
        out << "%s" % codeArea.ccCodeArea

      case OzInt(value) =>
        out << value.toString()

      case OzFloat(value) =>
        out << value.toString()

      case OzAtom(value) =>
        out << "MOZART_STR(\"%s\")" % (value map {
          case '\\' => "\\\\"<commit_msg>Fixed code emission for atoms with newlines and the like.<commit_after>package org.mozartoz.bootcompiler
package bytecode

import scala.collection.mutable._

import oz._
import ast._
import symtab._
import util._

class CodeArea(val abstraction: Abstraction) {
  val opCodes = new ArrayBuffer[OpCode]

  private val symbolRegisterAllocs = new HashMap[Symbol, YOrGReg]
  private val constantRegisterAllocs = new HashMap[OzValue, KReg]

  private val YCounter = new RegCounter(YReg)

  val constants = new ArrayBuffer[OzValue]

  def isDefined = !opCodes.isEmpty

  def size = opCodes.map(_.size).sum

  override def toString() = "<CodeArea %s>" format (abstraction.fullName)

  def dump(includeByteCode: Boolean = true) {
    println("constants:")
    for ((constant, index) <- constants.zipWithIndex)
      println("  K(%d) = %s" format (index, constant))

    if (includeByteCode) {
      println()
      for (opCode <- opCodes)
        println(opCode.code)
    }
  }

  def registerFor(symbol: Symbol): YOrGReg = {
    symbolRegisterAllocs.getOrElseUpdate(symbol, {
      if (symbol.isGlobal) GReg(symbol.owner.globals.indexOf(symbol))
      else YCounter.next()
    })
  }

  def registerFor(value: OzValue): KReg = {
    constantRegisterAllocs.getOrElseUpdate(value, {
      constants += value
      KReg(constants.size - 1)
    })
  }

  def registerFor(expr: VarOrConst): Register = expr match {
    case variable:Variable =>
      registerFor(variable.symbol)

    case constant:Constant =>
      registerFor(constant.value)
  }

  def += (opCode: OpCode) =
    opCodes += opCode

  class Hole(index: Int) {
    def fillWith(opCode: OpCode) {
      opCodes(index) = opCode
    }
  }

  def addHole(size: Int = 1) = {
    val index = opCodes.size
    opCodes += OpHole(size)
    new Hole(index)
  }

  def counting(body: => Unit) = {
    val before = opCodes.size
    body
    (before until opCodes.size) map (i => opCodes(i).size) sum
  }

  def computeXCount() = {
    var maxX = 0

    for {
      opCode <- opCodes
      XReg(index) <- opCode.arguments
    } {
      maxX = maxX max index
    }

    maxX + 1
  }

  val ccCodeArea = "codeArea" + abstraction.id.toString()
  val ccCreateMethodName = "createCodeArea" + abstraction.id.toString()

  def produceCC(out: Output) {
    import Output._

    out << """
       |/*
       |""".stripMargin

    Console.withOut(out.underlying) {
      abstraction.dump(includeByteCode = false)
    }

    out << """
       |*/
       |
       |void Program::%s() {
       |  ByteCode codeBlock[] = {
       |""".stripMargin % ccCreateMethodName

    for (opCode <- opCodes)
      out << "    %s,\n" % opCode.code

    out << """
       |  };
       |
       |  %s = CodeArea::build(vm, %d, codeBlock, sizeof(codeBlock), %d);
       |""".stripMargin % (ccCodeArea, constants.size, computeXCount())

    if (!constants.isEmpty) {
      out << """
         |  ArrayInitializer initializer = %s;
         |  UnstableNode temp;
         |""".stripMargin % ccCodeArea

      for ((constant, index) <- constants.zipWithIndex) {
        produceCCInitConstant(out, constant)
        out << "  initializer.initElement(vm, %d, temp);\n" % index
      }
    }

    out << """
       |}
       |""".stripMargin
  }

  private def produceCCInitConstant(out: Output, constant: OzValue) {
    import Output._

    out << "  temp = ";

    constant match {
      case _:OzArity | _:OzRecord | _:OzPatMatOpenRecord =>
        produceCCForConstant(out, constant)

      case _ =>
        out << "build(vm, "
        produceCCForConstant(out, constant)
        out << ")"
    }

    out << ";\n"
  }

  private def produceCCForConstant(out: Output, constant: OzValue) {
    import Output._

    constant match {
      case OzBuiltin(builtin) =>
        out << "::%s::builtin()" % builtin.ccFullName

      case OzCodeArea(codeArea) =>
        out << "%s" % codeArea.ccCodeArea

      case OzInt(value) =>
        out << value.toString()

      case OzFloat(value) =>
        out << value.toString()

      case OzAtom(value) =>
        out << "MOZART_STR(\"%s\")" % (value map {
          case '\\' => "\\\\"
          case '"' => "\\\""
          case '\u0007' => "\\a"
          case '\u0008' => "\\b"
          case '\u0009' => "\\t"
          case '\u000A' => "\\n"
          case '\u000B' => "\\v"
          case '\u000C' => "\\f"
          case '\u000D' => "\\r"
{'fraction_non_alphanumeric': 0.1388365520489873, 'fraction_numerical': 0.0037682524729156855, 'mean_word_length': 2.409474106784424, 'pattern_counts': {'":': 2, '<': 81, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '421500', 'n_tokens_mistral': 2864, 'n_tokens_neox': 2752, 'n_words': 609}