Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
427a0c2
created a simple example of solver
Feb 14, 2022
be80ab0
Merge remote-tracking branch 'origin/Inliner' into logical_exprs
Feb 15, 2022
0c79018
Merge branch 'Inliner' into logical_exprs
Feb 17, 2022
49fe20a
Merge branch 'Inliner' into logical_exprs
Feb 21, 2022
c50fda6
Merge remote-tracking branch 'upstream/master' into logical_exprs
Feb 22, 2022
bced7d3
refactoring
Feb 22, 2022
3fddabd
Feat(Analysis.LogicalExprs): intermediate AST that can represent logi…
Leosimetti Feb 22, 2022
5eaf64a
Fix(Analysis.LogicalExprs.LogicalAST): proper handling of objects wit…
Leosimetti Feb 22, 2022
e994666
added abstract fold and abstract modify for AST
Feb 23, 2022
645a9d2
rewrote setLocators using new abstractions
Feb 23, 2022
6eca0ee
Merge remote-tracking branch 'misha_fork/generic_obj_tree' into logic…
Leosimetti Feb 23, 2022
743f814
implemented a function which zips method body with its inlined version
Feb 24, 2022
ecc13f4
Merge remote-tracking branch 'misha_fork/generic_obj_tree' into logic…
Leosimetti Feb 24, 2022
7f522e6
added todos
Feb 25, 2022
c359e3f
parsing parent names from objs
Feb 25, 2022
a183705
objects can store ParentInfo
Feb 25, 2022
113add1
it compiled
Feb 25, 2022
38d760f
removed unnecessary evidences
Feb 25, 2022
6d999f6
replaced Object with ObjectTree
Feb 25, 2022
fd6df18
Merge branch 'generic_obj_tree' into logical_exprs
Leosimetti Feb 26, 2022
c3f63f4
parent resolution works only if the decorator and decoratee are on th…
Feb 26, 2022
15df68a
replaced ParentInfo with a link to parent, should work now
Feb 26, 2022
29db24e
Merge branch 'generic_obj_tree' into logical_exprs
Leosimetti Feb 28, 2022
cfb541c
added parent placeholder, to put parent back on inlining
Feb 27, 2022
cd09d18
Merge remote-tracking branch 'origin/logical_exprs' into logical_exprs
Feb 28, 2022
238d7f2
Merge branch 'logical_exprs' of https://github.com/nikololiahim/odin …
Leosimetti Mar 1, 2022
419793f
Basic version of AST
Leosimetti Mar 1, 2022
22647c8
created a funciton to zip indirect methods with their inlined versions
Mar 1, 2022
df4bd12
Merge remote-tracking branch 'origin/logical_exprs' into logical_exprs
Mar 1, 2022
6ef8933
Almost working end-to-end version of logical expression derivation
Leosimetti Mar 2, 2022
da6dc2a
fixed concatenation order of parent methods
Mar 2, 2022
23b698a
bumped scalafmt
Mar 2, 2022
3624ff3
applied scalafmt
Mar 2, 2022
daac172
allow explicit casts in scalafix
Mar 2, 2022
71fb056
more scalafmt
Mar 2, 2022
5456817
small refactoring
Mar 2, 2022
5fc07ff
added facade for unjustified assumption analyzer
Mar 2, 2022
29efb11
integrated new analyzer into Java facade
Mar 2, 2022
c3b49cb
if analyzer fails, silence errors
Mar 4, 2022
b08e8d0
methods from decoratee are inlined too
Mar 4, 2022
cc2351c
seq and assert are recognized as top-level objects even when they are…
Mar 4, 2022
acfdffc
Almost working version of logic extraction
Leosimetti Mar 4, 2022
8f760cb
Properly working version of logic extraction
Leosimetti Mar 4, 2022
9b57c08
Fixed integration with polystat
Leosimetti Mar 4, 2022
fbf8008
scalafix + scalafmt
Leosimetti Mar 4, 2022
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
4 changes: 3 additions & 1 deletion .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ DisableSyntax {
noNulls = true
noReturns = true
noWhileLoops = true
noAsInstanceOf = true

// TODO: set this to true when I find a way to avoid explicit casts
noAsInstanceOf = false
noIsInstanceOf = true
noXml = true
noDefaultArgs = false
Expand Down
9 changes: 7 additions & 2 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
version = 3.0.4
version = 3.4.3
lineEndings = preserve
runner.dialect = scala213

project {
includePaths = [
Expand All @@ -7,7 +9,10 @@ project {
"glob:**.sc",
"glob:**.md",
]
excludePaths = []
excludePaths = [
// TODO: Investigate why this file causes scalafmt to crash
"glob:**/inlining/Inliner.scala"
]
}

fileOverride {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package org.polystat.odin.analysis

import cats.ApplicativeError
import cats.ApplicativeThrow
import cats.data.EitherNel
import cats.effect.Sync
import cats.syntax.either._
import cats.syntax.foldable._
import fs2.Stream
import monix.newtypes.NewtypeWrapped
import org.polystat.odin.analysis.EOOdinAnalyzer.OdinAnalysisError
import org.polystat.odin.analysis.inlining.Inliner
import org.polystat.odin.analysis.logicalexprs.ExtractLogic
import org.polystat.odin.analysis.mutualrec.advanced.Analyzer.analyzeAst
import org.polystat.odin.analysis.mutualrec.naive.findMutualRecursionFromAst
import org.polystat.odin.core.ast.EOProg
Expand Down Expand Up @@ -52,16 +55,14 @@ object EOOdinAnalyzer {

}

def advancedMutualRecursionAnalyzer[F[_]](implicit
F: ApplicativeError[F, Throwable],
): ASTAnalyzer[F] =
def advancedMutualRecursionAnalyzer[F[_]: ApplicativeThrow]: ASTAnalyzer[F] =
new ASTAnalyzer[F] {

override def analyze(
ast: EOProg[EOExprOnly]
): Stream[F, OdinAnalysisError] = for {
errors <- Stream.eval(
F.fromEither(
ApplicativeThrow[F].fromEither(
analyzeAst[Either[String, *]](ast).leftMap(new Exception(_))
)
)
Expand All @@ -70,13 +71,43 @@ object EOOdinAnalyzer {

}

def analyzeSourceCode[EORepr, F[_]](analyzer: ASTAnalyzer[F])(
def unjustifiedAssumptionAnalyzer[F[_]: ApplicativeThrow]: ASTAnalyzer[F] =
new ASTAnalyzer[F] {

private[this] def toThrow[A](eitherNel: EitherNel[String, A]): F[A] = {
ApplicativeThrow[F].fromEither(
eitherNel
.leftMap(_.mkString_(util.Properties.lineSeparator))
.leftMap(new Exception(_))
)
}

override def analyze(
ast: EOProg[EOExprOnly]
): Stream[F, OdinAnalysisError] =
Stream.evals {
toThrow {
for {
tree <- Inliner.zipMethodsWithTheirInlinedVersionsFromParent(ast)
errors <- ExtractLogic.processObjectTree(tree)
} yield errors.map(OdinAnalysisError.apply)
}
}

}

def analyzeSourceCode[EORepr, F[_]](
analyzer: ASTAnalyzer[F]
)(
eoRepr: EORepr
)(implicit
parser: EoParser[EORepr, F, EOProg[EOExprOnly]]
): Stream[F, OdinAnalysisError] = for {
programAst <- Stream.eval(parser.parse(eoRepr))
mutualRecursionErrors <- analyzer.analyze(programAst)
mutualRecursionErrors <-
analyzer
.analyze(programAst)
.handleErrorWith(_ => Stream.empty)
} yield mutualRecursionErrors

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

import cats.syntax.foldable._
import cats.syntax.functor._
import cats.syntax.semigroup._
import cats.{Applicative, Eval, Foldable, Id, Monoid}
import com.github.tarao.nonempty.collection.NonEmpty
import higherkindness.droste.data.Fix
import org.polystat.odin.analysis.inlining.Optics.{lenses, traversals}
import org.polystat.odin.core.ast._
import org.polystat.odin.core.ast.astparams.EOExprOnly

object Abstract {

private type NonEmptyVector[A] = NonEmpty[A, Vector[A]]

implicit private val nonEmptyFoldable: Foldable[NonEmptyVector] =
new Foldable[NonEmptyVector] {

override def foldLeft[A, B](fa: NonEmptyVector[A], b: B)(
f: (B, A) => B
): B =
fa.value.foldLeft(b)(f)

override def foldRight[A, B](fa: NonEmptyVector[A], lb: Eval[B])(
f: (A, Eval[B]) => Eval[B]
): Eval[B] =
f(fa.head, fa.tail.foldRightDefer(lb)(f))

}

def modifyExprWithState[F[_]: Applicative, S](
initialState: S,
initialDepth: BigInt = 0
)(modifyExpr: S => BigInt => EOExprOnly => F[EOExprOnly])(
modifyState: EOExpr[EOExprOnly] => BigInt => S => S
)(expr: EOExprOnly): F[EOExprOnly] = {
def recurse(depth: BigInt)(state: S)(subExpr: EOExprOnly): F[EOExprOnly] = {
Fix.un(subExpr) match {
case obj: EOObj[EOExprOnly] =>
traversals
.eoObjBndAttrExprs
.modifyA(recurse(depth + 1)(modifyState(obj)(depth + 1)(state)))(
obj
)
.map(Fix(_))
case copy: EOCopy[EOExprOnly] =>
traversals
.eoCopy
.modifyA(recurse(depth)(modifyState(copy)(depth)(state)))(copy)
.map(Fix(_))
case dot: EODot[EOExprOnly] =>
lenses
.focusDotSrc
.modifyA(recurse(depth)(modifyState(dot)(depth)(state)))(dot)
.map(Fix(_))
case array: EOArray[EOExprOnly] =>
traversals
.eoArrayElems
.modifyA(recurse(depth)(modifyState(array)(depth)(state)))(array)
.map(Fix(_))
case other => modifyExpr(state)(depth)(Fix(other))
}
}
recurse(initialDepth)(initialState)(expr)
}

def modifyExpr(
modify: BigInt => EOExprOnly => EOExprOnly,
initialDepth: BigInt = 0
)(expr: EOExprOnly): EOExprOnly = {
modifyExprWithState[Id, Unit]((), initialDepth)(_ =>
depth => expr => modify(depth)(expr)
)(_ => _ => identity)(expr)
}

def foldAst[A: Monoid](
binds: Vector[EOBnd[EOExprOnly]]
)(f: PartialFunction[EOExpr[EOExprOnly], A]): A = {
def recurse(bnd: EOBnd[EOExprOnly]): A = {
f.lift(Fix.un(bnd.expr)) match {
case Some(value) => value
case None => Fix.un(bnd.expr) match {
case EOObj(_, _, bndAttrs) => bndAttrs.foldMap(recurse)
case EOCopy(trg, args) =>
recurse(EOAnonExpr(trg)).combine(
Foldable[NonEmptyVector].foldMap(args)(recurse)
)
case EODot(trg, _) => recurse(EOAnonExpr(trg))
case EOArray(elems) => elems.foldMap(recurse)
case _ => Monoid[A].empty
}
}
}
binds.foldMap(recurse)
}

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package org.polystat.odin.analysis.inlining

import cats.data.EitherNel
import cats.syntax.either._
import cats.syntax.traverse._
import cats.data.{EitherNel, NonEmptyList => Nel}
import higherkindness.droste.data.Fix
import org.polystat.odin.analysis.inlining.Optics._
import Abstract.modifyExprWithState
import org.polystat.odin.core.ast._
import org.polystat.odin.core.ast.astparams.EOExprOnly
import cats.data.{NonEmptyList => Nel}

// 0. Resolve explicit locator chains (^.^.aboba) during parsing
// 1. Create the first context that includes names of all top-lvl EOObjs
Expand All @@ -28,86 +27,65 @@ object Context {
ctx: Context,
name: String,
currentDepth: BigInt
): EitherNel[String, EOExprOnly] = {
val result = ctx
): EitherNel[String, EOExprOnly] =
ctx
.get(name)
.map(depth => {
val tmp: EOSimpleAppWithLocator[EOExprOnly] =
EOSimpleAppWithLocator(name, currentDepth - depth)
Fix(tmp)
})

Either.fromOption(
result,
Nel.one(s"Could not set locator for non-existent object with name $name")
)
}
.map(depth =>
Fix[EOExpr](EOSimpleAppWithLocator(name, currentDepth - depth))
)
.toRight(
Nel.one(
s"Could not set locator for non-existent object with name \"$name\""
)
)

def rebuildContext(
ctx: Context,
currentDepth: BigInt,
objs: Vector[EOBnd[EOExprOnly]],
freeAttrs: Option[Vector[LazyName]]
freeAttrs: Vector[LazyName]
): Context = {
val objCtx = objs
.collect { case bndExpr: EOBndExpr[Fix[EOExpr]] => bndExpr }
.map(bnd => bnd.bndName.name.name -> currentDepth)
.map(bnd => (bnd.bndName.name.name, currentDepth))
.toMap
val argCtx = freeAttrs match {
case Some(value) => value.map(lName => lName.name -> currentDepth).toMap
case None => Map.empty
}

val argCtx = freeAttrs.map(lName => (lName.name, currentDepth)).toMap
ctx ++ objCtx ++ argCtx
}

def setLocators(
code: EOProg[EOExprOnly]
): EitherNel[String, EOProg[EOExprOnly]] = {
def recurse(ctx: Context, depth: BigInt)(
expr: EOExprOnly
): EitherNel[String, EOExprOnly] =
Fix.un(expr) match {
case obj @ EOObj(freeAttrs, _, bndAttrs) =>
val newDepth = depth + 1
val newCtx = rebuildContext(ctx, newDepth, bndAttrs, Some(freeAttrs))

Optics
.traversals
.eoObjBndAttrs
.modifyA(recurse(newCtx, newDepth))(obj)
.map(Fix(_))

case app: EOSimpleApp[Fix[EOExpr]] =>
resolveLocator(ctx, app.name, depth)

case copy: EOCopy[EOExprOnly] =>
Optics
.traversals
.eoCopy
.modifyA(recurse(ctx, depth))(copy)
.map(Fix(_))

case dot: EODot[EOExprOnly] =>
Optics
.lenses
.focusDotSrc
.modifyA(recurse(ctx, depth))(dot)
.map(Fix(_))
case other => Right(Fix(other))
}

val initialCtx =
rebuildContext(Map(), 0, code.bnds, None)
val newBnds = code
.bnds
.traverse(bnd =>
for {
newExpr <- recurse(initialCtx, 0)(bnd.expr)
} yield Optics.lenses.focusFromBndToExpr.replace(newExpr)(bnd)
rebuildContext(
Map(
"seq" -> 0,
"assert" -> 0,
),
0,
code.bnds,
Vector()
)

newBnds.map(bnds => code.copy(bnds = bnds))
val modify = modifyExprWithState(initialCtx)(modifyExpr =
ctx =>
depth =>
expr =>
Fix.un(expr) match {
case app: EOSimpleApp[EOExprOnly] =>
resolveLocator(ctx, app.name, depth)
case other => Right(Fix(other))
}
)(modifyState =
expr =>
depth =>
prev =>
expr match {
case EOObj(freeAttrs, _, bndAttrs) =>
rebuildContext(prev, depth, bndAttrs, freeAttrs)
case _ => prev
}
)(_)
traversals.eoProg.modifyA(modify)(code)

}

Expand Down
Loading