Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for imports #72

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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")
)
}

}