<commit_before>package org.mozartoz.bootcompiler
package transform

import scala.collection.mutable.ListBuffer

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

object DesugarFunctor extends Transformer with TreeDSL {
  override def transformExpr(expression: Expression) = expression match {
    case functor @ FunctorExpression(name, require, prepare,
        imports, define, exports) if (!require.isEmpty || !prepare.isEmpty) =>
      /* In the boot compiler, require/prepare is no different than
       * import/define.
       * -> merge them
       */

      val mergedRequireImport = require ++ imports

      val mergedPrepareDefine = {
        if (prepare.isEmpty) define
        else if (define.isEmpty) prepare
        else {
          val LocalStatement(prepareDecls, prepareStat) = prepare.get
          val LocalStatement(defineDecls, defineStat) = define.get
          Some(LocalStatement(prepareDecls ++ defineDecls,
              prepareStat ~ defineStat)(Node.extend(prepare.get, define.get)))
        }
      }

      transformExpr {
        FunctorExpression(name, Nil, None, mergedRequireImport,
            mergedPrepareDefine, exports)(functor)
      }

    case functor @ FunctorExpression(name, Nil, None,
        imports, define, exports) =>

      val importsRec = makeImportsRec(functor, imports)
      val exportsRec = makeExportsRec(functor, exports)
      val applyFun = makeApplyFun(functor, define, imports, exports)

      val functorRec = Record(OzAtom("functor"), Seq(
        RecordField(OzAtom("import"), importsRec)(importsRec),
        RecordField(OzAtom("export"), exportsRec)(exportsRec),
        RecordField(OzAtom("apply"), applyFun)(applyFun)))(functor)

      transformExpr(functorRec)

    case _ =>
      super.transformExpr(expression)
  }

  def makeImportsRec(functor: FunctorExpression, imports: Seq[FunctorImport]): Expression = {
    val resultFields = for {
      fimport @ FunctorImport(Variable(module), aliases, location) <- imports
    } yield {
      val modName = module.name

      val typeField = {
        val requiredFeatures =
          for (AliasedFeature(feat, _) <- aliases)
            yield feat.value

        RecordField(OzAtom("type"), OzList(requiredFeatures))(fimport)
      }

      val fromField = {
        val loc = {
          if (location.isDefined) location.get
          else if (!SystemModules.isSystemModule(modName)) modName + ".ozf"
          else "x-oz://system/" + modName + ".ozf"
        }
        RecordField(OzAtom("from"), OzAtom(loc))(fimport)
      }

      val info = Record(OzAtom("info"), Seq(typeField, fromField))(fimport)

      RecordField(OzAtom(modName), info)(info)
    }

    Record(OzAtom("import"), resultFields)(Node.posFromSeq(resultFields, functor))
  }

  def makeExportsRec(functor: FunctorExpression, exports: Seq[FunctorExport]): Expression = {
    val resultFields = for {
      export @ FunctorExport(Constant(feature:OzFeature), _) <- exports
    } yield {
      RecordField(feature, OzAtom("value"))(export)
    }

    Record(OzAtom("export"), resultFields)(Node.posFromSeq(resultFields, functor))
  }

  def makeApplyFun(functor: FunctorExpression,
      define: Option[LocalStatementOrRaw],
      imports: Seq[FunctorImport],
      exports: Seq[FunctorExport]): Expression = {
    val importsParam = Variable.newSynthetic("<Imports>", formal = true)(functor)

    val importedDecls = extractAllImportedDecls(imports)
<commit_msg>Functor imports might not be in source order<commit_after>package org.mozartoz.bootcompiler
package transform

import scala.collection.mutable.ListBuffer

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

object DesugarFunctor extends Transformer with TreeDSL {
  override def transformExpr(expression: Expression) = expression match {
    case functor @ FunctorExpression(name, require, prepare,
        imports, define, exports) if (!require.isEmpty || !prepare.isEmpty) =>
      /* In the boot compiler, require/prepare is no different than
       * import/define.
       * -> merge them
       */

      val mergedRequireImport = require ++ imports

      val mergedPrepareDefine = {
        if (prepare.isEmpty) define
        else if (define.isEmpty) prepare
        else {
          val LocalStatement(prepareDecls, prepareStat) = prepare.get
          val LocalStatement(defineDecls, defineStat) = define.get
          Some(LocalStatement(prepareDecls ++ defineDecls,
              prepareStat ~ defineStat)(Node.extend(prepare.get, define.get)))
        }
      }

      transformExpr {
        FunctorExpression(name, Nil, None, mergedRequireImport,
            mergedPrepareDefine, exports)(functor)
      }

    case functor @ FunctorExpression(name, Nil, None,
        imports, define, exports) =>

      val importsRec = makeImportsRec(functor, imports)
      val exportsRec = makeExportsRec(functor, exports)
      val applyFun = makeApplyFun(functor, define, imports, exports)

      val functorRec = Record(OzAtom("functor"), Seq(
        RecordField(OzAtom("import"), importsRec)(importsRec),
        RecordField(OzAtom("export"), exportsRec)(exportsRec),
        RecordField(OzAtom("apply"), applyFun)(applyFun)))(functor)

      transformExpr(functorRec)

    case _ =>
      super.transformExpr(expression)
  }

  def makeImportsRec(functor: FunctorExpression, imports: Seq[FunctorImport]): Expression = {
    val resultFields = for {
      fimport @ FunctorImport(Variable(module), aliases, location) <- imports
    } yield {
      val modName = module.name

      val typeField = {
        val requiredFeatures =
          for (AliasedFeature(feat, _) <- aliases)
            yield feat.value

        RecordField(OzAtom("type"), OzList(requiredFeatures))(fimport)
      }

      val fromField = {
        val loc = {
          if (location.isDefined) location.get
          else if (!SystemModules.isSystemModule(modName)) modName + ".ozf"
          else "x-oz://system/" + modName + ".ozf"
        }
        RecordField(OzAtom("from"), OzAtom(loc))(fimport)
      }

      val info = Record(OzAtom("info"), Seq(typeField, fromField))(fimport)

      RecordField(OzAtom(modName), info)(info)
    }

    Record(OzAtom("import"), resultFields)(functor)
  }

  def makeExportsRec(functor: FunctorExpression, exports: Seq[FunctorExport]): Expression = {
    val resultFields = for {
      export @ FunctorExport(Constant(feature:OzFeature), _) <- exports
    } yield {
      RecordField(feature, OzAtom("value"))(export)
    }

    Record(OzAtom("export"), resultFields)(Node.posFromSeq(resultFields, functor))
  }

  def makeApplyFun(functor: FunctorExpression,
      define: Option[LocalStatementOrRaw],
      imports: Seq[FunctorImport],
      exports: Seq[FunctorExport]): Expression = {
    val importsParam = Variable.newSynthetic("<Imports>", formal = true)(functor)

    val importedDecls = extractAllImportedDecls(imports)

{'fraction_non_alphanumeric': 0.10888501742160278, 'fraction_numerical': 0.0, 'mean_word_length': 3.221200980392157, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, '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': '683419', 'n_tokens_mistral': 2010, 'n_tokens_neox': 1928, 'n_words': 424}