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

Introducing locator functionality to AST #28

Merged
merged 24 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
37b0d4f
initial setup
nikololiahim Jan 24, 2022
f18e026
Feat(Analysis: inliner): Initial version of AST-locator resolver
Leosimetti Jan 25, 2022
3af8a5e
Fix(Analysis: inliner): Added further recursion where necessary
Leosimetti Jan 25, 2022
be9f072
pretty-printer is usable from parser
nikololiahim Jan 25, 2022
35c5595
attempts to fix pprinter
nikololiahim Jan 25, 2022
2a02f6d
moved escape and unescape to utils module
nikololiahim Jan 26, 2022
f3d47c6
pretty-printer fixed (for now)
nikololiahim Jan 26, 2022
464fe3f
moved existing gens to a separate package
nikololiahim Jan 27, 2022
d4a60b8
created gens for AST
nikololiahim Jan 27, 2022
b139de9
pretty-printer displays complex objects in target position of EOCopy …
nikololiahim Jan 27, 2022
84e13ad
Merge remote-tracking branch 'origin/introduce_locators' into introdu…
nikololiahim Jan 27, 2022
3d9448e
removed code duplication
nikololiahim Jan 28, 2022
00780bc
partial support for single-line abstraction
nikololiahim Jan 28, 2022
66dd518
complete support for single-line abstractions
nikololiahim Jan 28, 2022
cef1ed7
added ast->pprint->parse == ast tests
nikololiahim Jan 28, 2022
fc0d30a
scalafmt
nikololiahim Jan 28, 2022
a0f9939
Ref(Analysis. inliner.Context): Removed unnecessary BigInt constructo…
Leosimetti Jan 29, 2022
3770302
Fix(Analysis. inlining.Context): Locator depth calculation
Leosimetti Jan 29, 2022
42752fd
Fix(Analysis. inlining.Context): Locators for freeAttrs
Leosimetti Jan 29, 2022
be55ba9
prog->pretty == prog->pretty->parsed->pretty property is satisfied
nikololiahim Jan 30, 2022
6c400e5
refactored existing tests with ast, added 2 new that ensure #19 is so…
nikololiahim Jan 30, 2022
f71c12d
^ and $ are no longer attributes, locators are now parsed into EOSimp…
nikololiahim Jan 30, 2022
be89632
prog == prog->pretty->parsed doesn't hold anymore
nikololiahim Jan 30, 2022
a48ef6e
fixed xmir-to-ast parser
nikololiahim Jan 30, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package org.polystat.odin.analysis.inlining

import higherkindness.droste.data.Fix
import org.polystat.odin.core.ast._
import org.polystat.odin.parser.eo.Parser
import org.polystat.odin.backend.eolang.ToEO.instances.progToEO
import org.polystat.odin.backend.eolang.ToEO.ops.ToEOOps

// 0. Resolve explicit BigInt chains (^.^.aboba) during parsing
// 1. Create the first context that includes names of all top-lvl EOObjs
// 1.1. Replace All top-level applications (a > b) with application of
// 0-locators ($.a > b)
// [pending approval]
// 2. Recursively explore the AST
// 2.1 Upon meeting an EOSimpleAPP() -> resolve it using the current context
// into EOSimpleAppWithLocator()
// 2.2 Upon meeting a EOObj() -> use its contents to update the context and pass
// it in the next recursive call

object Context {

type Context = Map[String, BigInt]

def resolveLocator(
ctx: Context,
app: EOSimpleApp[Fix[EOExpr]],
currentDepth: BigInt
): EOSimpleAppWithLocator[Fix[EOExpr]] = {
val name: String = app.name
val depth: BigInt = ctx.getOrElse(name, 0)

EOSimpleAppWithLocator(app.name, currentDepth - depth)
}

def rebuildContext(
ctx: Context,
currentDepth: BigInt,
objs: Vector[EOBnd[Fix[EOExpr]]],
freeAttrs: Option[Vector[LazyName]]
): Context = {
val objCtx = objs
.flatMap {
case bndExpr: EOBndExpr[Fix[EOExpr]] => Some(bndExpr)
case _ => None
}
.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
}

ctx ++ objCtx ++ argCtx
}

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

obj.copy(bndAttrs = bndAttrs.map(bndExprHelper(newCtx, newDepth)))

case app: EOSimpleApp[Fix[EOExpr]] => resolveLocator(ctx, app, depth)
case EOCopy(Fix(trg), args) =>
EOCopy(
trg = Fix(exprHelper(ctx, depth)(trg)),
args = args.map(bndHelper(ctx, depth))
)
case dot @ EODot(Fix(src), _) =>
dot.copy(src = Fix(exprHelper(ctx, depth)(src)))
case other => other
}

def bndExprHelper(ctx: Context, depth: BigInt)(
bnd: EOBndExpr[Fix[EOExpr]]
): EOBndExpr[Fix[EOExpr]] =
bnd match {
case bnd @ EOBndExpr(_, Fix(expr)) =>
bnd.copy(expr = Fix(exprHelper(ctx, depth)(expr)))
}

def bndHelper(ctx: Context, depth: BigInt)(
bnd: EOBnd[Fix[EOExpr]]
): EOBnd[Fix[EOExpr]] =
bnd match {
case EOAnonExpr(Fix(expr)) =>
EOAnonExpr(Fix(exprHelper(ctx, depth)(expr)))
case bnd @ EOBndExpr(_, Fix(expr)) =>
bnd.copy(expr = Fix(exprHelper(ctx, depth)(expr)))
}

val initialCtx =
rebuildContext(Map(), 0, code.bnds, None)
code.copy(bnds = code.bnds.map(bndHelper(initialCtx, 0)))
}

def main(args: Array[String]): Unit = {
val code: String =
"""
|[] > outer
| [] > self
| 256 > magic
| [] > dummy
| [outer] > cock
| outer > @
| outer.self > @
| self "yahoo" > @
| [self] > method
| self.magic > @
|
|""".stripMargin

Parser
.parse(code)
.map(setLocators) match {
case Left(value) => println(value)
case Right(value) => println(value.toEOPretty)
}

}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.polystat.odin.backend.eolang

import cats.implicits.toBifunctorOps
import higherkindness.droste.data.Fix
import EOBndRepr.instances._
import ToEO.ops.ToEOOps
Expand All @@ -10,7 +9,7 @@ import inlineorlines._
import inlineorlines.ops._
import org.polystat.odin.core.ast.astparams.EOExprOnly
import org.polystat.odin.core.ast._
import org.polystat.odin.utils.text.indent
import org.polystat.odin.utils.text.{escape, indent}

trait ToEO[T, R] {
def toEO(node: T): R
Expand Down Expand Up @@ -66,7 +65,7 @@ object ToEO {

override def toEO(node: EOMetas): Lines = Lines(
node.pack.map(p => s"${Constants.SYMBS.META_PREFIX}package $p") ++
node.metas.map(_.toEO.value)
node.metas.map(_.toEO.value).appended("\n")
)

}
Expand Down Expand Up @@ -194,8 +193,9 @@ object ToEO {

override def toEO(node: EOApp[EOExprOnly]): InlineOrLines = node match {
case n: EOSimpleApp[EOExprOnly] => n.toEO: Inline
case n: EODot[EOExprOnly] => n.toEO
case n: EOCopy[EOExprOnly] => n.toEO: Lines
case n: EOSimpleAppWithLocator[EOExprOnly] => n.toEO: Inline
case n: EODot[EOExprOnly] => n.toEO: Inline
case n: EOCopy[EOExprOnly] => n.toEO
}

}
Expand All @@ -208,51 +208,154 @@ object ToEO {

}

implicit val dotToEO: ToEO[EODot[EOExprOnly], InlineOrLines] =
new ToEO[EODot[EOExprOnly], InlineOrLines] {
def usualDotNotation(n: String)(s: String): String = s"$s.$n"
implicit val simpleAppWithLocatorToEO: ToEO[EOSimpleAppWithLocator[EOExprOnly], Inline] =
new ToEO[EOSimpleAppWithLocator[EOExprOnly], Inline] {

def reverseDotNotation(n: String)(
ls: Iterable[String]
): Iterable[String] =
Vector(s"$n.") ++ ls.map(indent)
override def toEO(node: EOSimpleAppWithLocator[EOExprOnly]): Inline =
Inline(
if (node.locator == 0) s"$$.${node.name}"
else List
.fill(node.locator.toInt)("^")
.appended(node.name)
.mkString(".")
)

}

implicit val dotToEO: ToEO[EODot[EOExprOnly], Inline] =
new ToEO[EODot[EOExprOnly], Inline] {

def dotNotation(n: String)(eoExpr: InlineOrLines): InlineOrLines =
eoExpr.bimap(
usualDotNotation(n),
reverseDotNotation(n)
override def toEO(node: EODot[EOExprOnly]): Inline = {
Inline(
List[String](
renderArgSingleLine(EOAnonExpr(node.src)),
node.name
).mkString(".")
)
}

def objCases(name: String)(obj: EOObj[EOExprOnly]): InlineOrLines =
dotNotation(name)(obj.toEO)
}

def appCases(name: String)(app: EOApp[EOExprOnly]): InlineOrLines =
app match {
case n: EOSimpleApp[EOExprOnly] => dotNotation(name)(n.toEO: Inline)
case n: EODot[EOExprOnly] => dotNotation(name)(n.src.toEO)
case n: EOCopy[EOExprOnly] => dotNotation(name)(n.toEO: Lines)
}
def renderObjSingleLine(obj: EOObj[EOExprOnly]): Inline = {
val params: String = Constants.SYMBS.FREE_ATTR_DECL_ST +
obj.freeAttrs.map(_.name).mkString(" ") +
obj
.varargAttr
.fold[String]("") { vararg =>
val prefix = if (obj.freeAttrs.isEmpty) "" else " "
prefix + vararg.name + Constants.SYMBS.VARARG_MOD
} +
Constants.SYMBS.FREE_ATTR_DECL_ED

val bndAttrs: String =
if (obj.bndAttrs.isEmpty)
""
else {
" " +
obj
.bndAttrs
.map(bnd => s"(${renderEOBndSingleLine(bnd).value})")
.mkString(" ")
}

def dataCases(name: String)(data: EOData[EOExprOnly]): InlineOrLines =
dotNotation(name)(data.toEO)
Inline(List(params, bndAttrs).mkString)
}

override def toEO(node: EODot[EOExprOnly]): InlineOrLines = {
Fix.un(node.src) match {
case n: EOObj[EOExprOnly] => objCases(node.name)(n)
case n: EOApp[EOExprOnly] => appCases(node.name)(n)
case n: EOData[EOExprOnly] => dataCases(node.name)(n)
def renderAppSingleLine(app: EOApp[EOExprOnly]): Inline = {
app match {
case app: EOSimpleApp[EOExprOnly] => simpleAppToEO.toEO(app)
case awl: EOSimpleAppWithLocator[EOExprOnly] =>
simpleAppWithLocatorToEO.toEO(awl)
case dot: EODot[EOExprOnly] => dotToEO.toEO(dot)
case cp: EOCopy[EOExprOnly] => renderCopySingleLine(cp)
}
}

def renderEOExprSingleLine(expr: EOExprOnly): Inline = {
Fix.un(expr) match {
case obj: EOObj[EOExprOnly] => renderObjSingleLine(obj)
case app: EOApp[EOExprOnly] => renderAppSingleLine(app)
case data: EOData[EOExprOnly] => renderDataSingleLine(data)
}
}

def renderNamedBndSingleLine(name: EONamedBnd): String = {
name match {
case EOAnyNameBnd(name) => name match {
case LazyName(name) => name
case ConstName(name) => name + Constants.SYMBS.CONST_MOD
}
}
case EODecoration => Constants.ATTRS.DECORATION
}
}

def renderEOBndSingleLine(bnd: EOBnd[EOExprOnly]): Inline = {
bnd match {
case EOAnonExpr(expr) => renderEOExprSingleLine(expr)
case EOBndExpr(bndName, expr) =>
Inline(
List[String](
renderEOExprSingleLine(expr).value,
Constants.SYMBS.BINDING,
renderNamedBndSingleLine(bndName)
).mkString(" ")
)
}
}

def renderArraySingleLine(arr: EOArray[EOExprOnly]): Inline = {
val elems: String = arr.elems.map(renderArgSingleLine).mkString(" ")
Inline(s"${Constants.SYMBS.ARRAY_START} $elems")
}

def renderDataSingleLine(data: EOData[EOExprOnly]): Inline = {
data match {
case arr: EOArray[EOExprOnly] => renderArraySingleLine(arr)
case d: EORegexData[EOExprOnly] => d.toEO
case d: EOStrData[EOExprOnly] => d.toEO
case d: EOIntData[EOExprOnly] => d.toEO
case d: EOCharData[EOExprOnly] => d.toEO
case d: EOBoolData[EOExprOnly] => d.toEO
case d: EOFloatData[EOExprOnly] => d.toEO
case d: EOBytesData[EOExprOnly] => d.toEO
}
}

def renderArgSingleLine(arg: EOBnd[EOExprOnly]): String =
arg match {
case bnd: EOBndExpr[EOExprOnly] =>
"(" + renderEOBndSingleLine(bnd).value + ")"
case eoCopy @ EOAnonExpr(_ @Fix(EOCopy(_, _))) =>
"(" + renderEOBndSingleLine(eoCopy).value + ")"
case array @ EOAnonExpr(_ @Fix(EOArray(_))) =>
"(" + renderEOBndSingleLine(array).value + ")"
case array @ EOAnonExpr(_ @Fix(EOObj(_, _, _))) =>
"(" + renderEOBndSingleLine(array).value + ")"
case other => renderEOBndSingleLine(other).value
}

def renderCopySingleLine(copy: EOCopy[EOExprOnly]): Inline = {
val trg: String = renderArgSingleLine(EOAnonExpr(copy.trg))
val args: String = copy.args.map(renderArgSingleLine).mkString(" ")

implicit val copyToEO: ToEO[EOCopy[EOExprOnly], Lines] =
new ToEO[EOCopy[EOExprOnly], Lines] {
Inline(List(trg, args).mkString(" "))
}

implicit val copyToEO: ToEO[EOCopy[EOExprOnly], InlineOrLines] =
new ToEO[EOCopy[EOExprOnly], InlineOrLines] {

override def toEO(node: EOCopy[EOExprOnly]): Lines = Lines(
node.trg.toEO.toIterable ++
override def toEO(node: EOCopy[EOExprOnly]): InlineOrLines = {
val outerArgsString =
node.args.flatMap(_.toEO.toIterable).map(indent)
)

Fix.un(node.trg) match {
case EOObj(_, _, _) => renderCopySingleLine(node)
case trg =>
Lines(
renderArgSingleLine(EOAnonExpr(Fix(trg))) +: outerArgsString
)
}
}

}

Expand Down Expand Up @@ -294,7 +397,9 @@ object ToEO {
new ToEO[EOStrData[EOExprOnly], Inline] {

override def toEO(node: EOStrData[EOExprOnly]): Inline =
Inline(s"\"${node.str}\"")
Inline(
"\"" + escape('"', node.str) + "\""
)

}

Expand Down Expand Up @@ -327,7 +432,9 @@ object ToEO {
new ToEO[EOCharData[EOExprOnly], Inline] {

override def toEO(node: EOCharData[EOExprOnly]): Inline =
Inline(s"'${node.char}'")
Inline(
"\'" + escape('\'', node.char.toString) + "\'"
)

}

Expand Down
5 changes: 4 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,10 @@ lazy val core = project
lazy val parser = project
.settings(commonSettings)
.settings(publishSettings)
.dependsOn(core)
.dependsOn(
core,
`eolang-backend`
)
.settings(
name := "parser",
libraryDependencies ++= Dependencies.parser
Expand Down
Loading