Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.polystat.odin.analysis.EOOdinAnalyzer._
import org.polystat.odin.analysis.liskov.Analyzer
import org.polystat.odin.analysis.mutualrec.advanced.Analyzer.analyzeAst
import org.polystat.odin.analysis.stateaccess.DetectStateAccess
import org.polystat.odin.analysis.utils.ImportProcessing.prependImports
import org.polystat.odin.analysis.utils.inlining.Inliner
import org.polystat.odin.analysis.utils.j2eo
import org.polystat.odin.core.ast.EOBndExpr
Expand Down Expand Up @@ -172,10 +173,27 @@ object EOOdinAnalyzer {
): F[OdinAnalysisResult] = for {
programAst <- parser.parse(eoRepr)
astWithPredef = addPredef(programAst)
mutualRecursionErrors <-
analysisError <-
analyzer
.analyze(astWithPredef)
// .handleErrorWith(_ => Stream.empty)
} yield mutualRecursionErrors
} yield analysisError

def analyzeSourceCodeDir[EORepr, F[_]](
analyzer: ASTAnalyzer[F]
)(
fileToEoRepr: Map[String, EORepr]
)(implicit
m: MonadError[F, Throwable],
parser: EoParser[EORepr, F, EOProg[EOExprOnly]],
): F[Map[String, OdinAnalysisResult]] = for {

programAsts <- fileToEoRepr.values.toList.traverse(parser.parse)
fileToAst = fileToEoRepr.keys.zip(programAsts).toMap
fileToAstImported <- prependImports[F](fileToAst)
analyzedAsts <- fileToAstImported.values.toList.traverse(analyzer.analyze)
analysisResults = fileToAstImported.keys.zip(analyzedAsts).toMap

} yield analysisResults

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package org.polystat.odin.analysis.utils

import cats.ApplicativeError
import cats.data.NonEmptyList
import cats.syntax.all._
import higherkindness.droste.data.Fix
import org.polystat.odin.core.ast._
import org.polystat.odin.core.ast.astparams.EOExprOnly

object ImportProcessing {

case class Importable(
pkg: Option[String],
path: NonEmptyList[String],
content: EOExprOnly,
srcFile: String
) {
val fullSrc: NonEmptyList[String] = pkg.map(path.prepend).getOrElse(path)
val isTopLvl: Boolean = path.length == 1

def toBndExpr(alias: Option[String] = None): EOBndExpr[EOExprOnly] = {
val name = alias.getOrElse(path.last)
EOBndExpr(EOAnyNameBnd(LazyName(name)), content)
}

}

def fetchAvailableImportables(src: List[String])(
bnd: EOBndExpr[EOExprOnly]
)(implicit pkg: Option[String], sourceFile: String): List[Importable] = {
val newPath =
NonEmptyList.ofInitLast(src, bnd.bndName.name.name)

bnd.expr match {
case obj @ Fix(EOObj(_, _, bndAttrs)) =>
List(
Importable(pkg, newPath, obj, sourceFile)
) ++ bndAttrs.flatMap(fetchAvailableImportables(newPath.toList))
case other => List(Importable(pkg, newPath, other, sourceFile))
}
}

def fetchImports(
availableImports: List[Importable]
)(meta: EOMetas): Option[Vector[EOBndExpr[EOExprOnly]]] = {
val currentPkg = meta.pack

val pkgImports = availableImports.collect {
case imp @ Importable(pkg, _, _, _)
if pkg == currentPkg && imp.isTopLvl => imp.toBndExpr()
}

val nonPkgImports =
meta
.metas
.filter {
// Todo: check a special case where the pkg name eq the import name
case EOAliasMeta(_, src) if !currentPkg.contains(src.head) => true
case _ => false
}
.traverse {
case EOAliasMeta(alias, src) =>
for {
imp <-
availableImports
.find(imp => imp.fullSrc == src)
} yield imp.toBndExpr(alias)
case _ => None
}

nonPkgImports.map(_ ++ pkgImports)
}

def prependImports[F[_]](
fileToAst: Map[String, EOProg[EOExprOnly]]
)(implicit
ae: ApplicativeError[F, Throwable]
): F[Map[String, EOProg[EOExprOnly]]] = {
val availableImports = for {
(file, prog) <- fileToAst.toList
pkg = prog.metas.pack
importable <- prog
.bnds
.collect { case bnd @ EOBndExpr(_, _) => bnd }
.flatMap(bnd => fetchAvailableImportables(List())(bnd)(pkg, file))
} yield importable

ae.fromOption(
fileToAst
.toList
.traverse { case (fileName, prog @ EOProg(meta, _)) =>
fetchImports(availableImports)(meta)
.map(importBnds =>
(fileName, prog.copy(bnds = prog.bnds.prependedAll(importBnds)))
)
}
.map(_.toMap),
new Exception("Could not find necessary imports after parsing")
)
}

}