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

hu.bme.mit.theta.xcfa.cli.utils.XcfaParser.kt Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright 2024 Budapest University of Technology and Economics
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package hu.bme.mit.theta.xcfa.cli.utils

import hu.bme.mit.theta.c2xcfa.getXcfaFromC
import hu.bme.mit.theta.common.logging.Logger
import hu.bme.mit.theta.frontend.ParseContext
import hu.bme.mit.theta.frontend.chc.ChcFrontend
import hu.bme.mit.theta.frontend.litmus2xcfa.LitmusInterpreter
import hu.bme.mit.theta.frontend.transformation.ArchitectureConfig
import hu.bme.mit.theta.frontend.transformation.grammar.preprocess.ArithmeticTrait
import hu.bme.mit.theta.llvm2xcfa.ArithmeticType
import hu.bme.mit.theta.llvm2xcfa.XcfaUtils
import hu.bme.mit.theta.xcfa.analysis.ErrorDetection
import hu.bme.mit.theta.xcfa.cli.params.CHCFrontendConfig
import hu.bme.mit.theta.xcfa.cli.params.ExitCodes
import hu.bme.mit.theta.xcfa.cli.params.InputType
import hu.bme.mit.theta.xcfa.cli.params.XcfaConfig
import hu.bme.mit.theta.xcfa.model.XCFA
import hu.bme.mit.theta.xcfa.passes.ChcPasses
import java.io.File
import java.io.FileInputStream
import java.io.FileReader
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import kotlin.system.exitProcess
import org.antlr.v4.runtime.CharStreams

fun getXcfa(
  config: XcfaConfig<*, *>,
  parseContext: ParseContext,
  logger: Logger,
  uniqueWarningLogger: Logger,
) =
  try {
    when (config.frontendConfig.inputType) {
      InputType.CHC -> {
        val chcConfig = config.frontendConfig.specConfig as CHCFrontendConfig
        parseChc(
          config.inputConfig.input!!,
          chcConfig.chcTransformation,
          parseContext,
          logger,
          uniqueWarningLogger,
        )
      }

      InputType.C -> {
        parseC(
          config.inputConfig.input!!,
          config.inputConfig.property,
          parseContext,
          logger,
          uniqueWarningLogger,
        )
      }

      InputType.LLVM -> XcfaUtils.fromFile(config.inputConfig.input!!, ArithmeticType.efficient)

      InputType.LITMUS -> LitmusInterpreter.getXcfa(config.inputConfig.input!!)

      InputType.JSON -> {
        val gson = getGson()
        gson.fromJson(config.inputConfig.input!!.readText(), XCFA::class.java)
      }

      InputType.DSL -> {
        val kotlinEngine: ScriptEngine = ScriptEngineManager().getEngineByExtension("kts")
        kotlinEngine.eval(FileReader(config.inputConfig.input!!)) as XCFA
      }
    }
  } catch (e: Exception) {
    if (config.debugConfig.stacktrace) e.printStackTrace()
    val location =
      e.stackTrace.filter { it.className.startsWith("hu.bme.mit.theta") }.first().toString()
    logger.write(Logger.Level.RESULT, "Frontend failed! ($location, $e)\n")
    exitProcess(ExitCodes.FRONTEND_FAILED.code)
  }

private fun parseC(
  input: File,
  explicitProperty: ErrorDetection,
  parseContext: ParseContext,
  logger: Logger,
  uniqueWarningLogger: Logger,
): XCFA {
  val xcfaFromC =
    try {
      val stream = FileInputStream(input)
      getXcfaFromC(
          stream,
          parseContext,
          false,
          explicitProperty == ErrorDetection.OVERFLOW,
          uniqueWarningLogger,
        )
        .first
    } catch (e: Throwable) {
      if (parseContext.arithmetic == ArchitectureConfig.ArithmeticType.efficient) {
        parseContext.arithmetic = ArchitectureConfig.ArithmeticType.bitvector
        logger.write(Logger.Level.INFO, "Retrying parsing with bitvector arithmetic...\n")
        val stream = FileInputStream(input)
        val xcfa =
          getXcfaFromC(
              stream,
              parseContext,
              false,
              explicitProperty == ErrorDetection.OVERFLOW,
              uniqueWarningLogger,
            )
            .first
        parseContext.addArithmeticTrait(ArithmeticTrait.BITWISE)
        xcfa
      } else {
        throw e
      }
    }
  logger.write(Logger.Level.RESULT, "Arithmetic: ${parseContext.arithmeticTraits}\n")
  return xcfaFromC
}

private fun parseChc(
  input: File,
  chcTransformation: ChcFrontend.ChcTransformation,
  parseContext: ParseContext,
  logger: Logger,
  uniqueWarningLogger: Logger,
): XCFA {
  var chcFrontend: ChcFrontend
  val xcfaBuilder =
    if (
      chcTransformation == ChcFrontend.ChcTransformation.PORTFOLIO
    ) { // try forward, fallback to backward
      chcFrontend = ChcFrontend(ChcFrontend.ChcTransformation.FORWARD)
      try {
        chcFrontend.buildXcfa(
          CharStreams.fromStream(FileInputStream(input)),
          ChcPasses(parseContext, uniqueWarningLogger),
        )
      } catch (e: UnsupportedOperationException) {
        logger.write(
          Logger.Level.INFO,
          "Non-linear CHC found, retrying using backward transformation...\n",
        )
        chcFrontend = ChcFrontend(ChcFrontend.ChcTransformation.BACKWARD)
        chcFrontend.buildXcfa(
          CharStreams.fromStream(FileInputStream(input)),
          ChcPasses(parseContext, uniqueWarningLogger),
        )
      }
    } else {
      chcFrontend = ChcFrontend(chcTransformation)
      chcFrontend.buildXcfa(
        CharStreams.fromStream(FileInputStream(input)),
        ChcPasses(parseContext, uniqueWarningLogger),
      )
    }
  return xcfaBuilder.build()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy