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

raw.compiler.common.Tree.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2023 RAW Labs S.A.
 *
 * Use of this software is governed by the Business Source License
 * included in the file licenses/BSL.txt.
 *
 * As of the Change Date specified in that file, in accordance with
 * the Business Source License, use of this software will be governed
 * by the Apache License, Version 2.0, included in the file
 * licenses/APL.txt.
 */

package raw.compiler.common

import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywhere, everywherebu, query, rewrite, rule}
import raw.compiler.base.source.{RawBridgeImpl, Type}
import raw.compiler.base.{CompilerProvider, NormalizeMap, ProgramContext}
import raw.compiler.common.source.{ErrorType, Eval, Exp, IdnDef, IdnUse, SourceNode, SourceProgram}

abstract class Tree(originalRoot: SourceProgram, ensureTree: Boolean)(implicit programContext: ProgramContext)
    extends raw.compiler.base.Tree[SourceNode, SourceProgram, Exp](originalRoot, ensureTree)
    with source.SourcePrettyPrinter
    with errors.ErrorsPrettyPrinter {

  override def analyzer: SemanticAnalyzer

  override def normalize: SourceProgram = {
    // Recursively rewrite identifiers.
    val map = new NormalizeMap()
    val rewriteIdns = everywhere(
      rule[SourceNode] {
        case n: IdnDef if n.idn.contains("$") => IdnDef(map.newIdnForIdnNode(analyzer.entity(n), n))
        case n: IdnUse if n.idn.contains("$") => IdnUse(map.newIdnForIdnNode(analyzer.entity(n), n))
      }
    )
    val rootWithNewIdns = rewrite(rewriteIdns)(root)
    // Recursively rewrite inner languages of Eval.
    val rewriteInnerLanguages = everywherebu(
      rule[Any] {
        case Eval(RawBridgeImpl(lang, source)) => Eval(
            RawBridgeImpl(lang, CompilerProvider.normalize(lang, source))
          )
      }
    )
    rewrite(rewriteInnerLanguages)(rootWithNewIdns)
  }

  override def isTreeValid: Boolean = {
    val isValid = super.isTreeValid
    if (programContext.settings.onTrainingWheels && isValid) {
      // Check if any ErrorType "accidentally" left in the tree
      val collectBugs = collectNodes[SourceNode, Seq, Exp] {
        case e: Exp if containsErrorType(analyzer.tipe(e)) => e
      }
      val bugs = collectBugs(root)

      if (bugs.nonEmpty) {
        val msg = bugs
          .map { e =>
            val t = analyzer.tipe(e)
            s"""Expression: $e
              |Type: $t""".stripMargin
          }
          .mkString("\n")
        throw new AssertionError(s"""Error types found on tree that has no errors reported!
          |This is the full (broken) tree:
          |$pretty
          |This is the expression(s) that typed with an error type:
          |(just above is a pretty-printed version of the full (broken) tree):
          |$msg""".stripMargin)
        // msb: The following lines are commented but can be useful to uncomment during debugging:
        //      I found that AssertionError was sometimes hard to debug: so I "let it go" by commenting out the assert
        //      and then the plan would fail at some later point (by "chance") and we'd have the pretty printed errors
        //      to help us out. Those pretty printed errors are not available via this assertion mechanism.
        //        logger.error(
        //          s"""Error types found on tree that has no errors reported!
        //             |$msg""".stripMargin)

      }
    }
    isValid
  }
  protected def containsErrorType(t: Type): Boolean = {
    val check = everywhere(query[Type] { case _: ErrorType => return true })
    check(t)
    false
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy