Skip to content
Merged
16 changes: 8 additions & 8 deletions effekt/jvm/src/test/scala/effekt/core/CoreTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ trait CoreTests extends munit.FunSuite {
|=====================
|Got:
|----
|${effekt.core.PrettyPrinter.format(obtained).layout}
|${effekt.core.ReparsablePrettyPrinter.format(obtained).layout}
|
|Expected:
|---------
|${effekt.core.PrettyPrinter.format(expected).layout}
|${effekt.core.ReparsablePrettyPrinter.format(expected).layout}
|
|""".stripMargin
})
Expand All @@ -34,11 +34,11 @@ trait CoreTests extends munit.FunSuite {
|=====================
|Got:
|----
|${effekt.core.PrettyPrinter.format(obtained)}
|${effekt.core.ReparsablePrettyPrinter.format(obtained)}
|
|Expected:
|---------
|${effekt.core.PrettyPrinter.format(expected)}
|${effekt.core.ReparsablePrettyPrinter.format(expected)}
|
|""".stripMargin
})
Expand All @@ -47,19 +47,19 @@ trait CoreTests extends munit.FunSuite {
expected: ModuleDecl,
clue: => Any = "values are not alpha-equivalent",
names: Names = Names(defaultNames))(using Location): Unit = {
val renamer = TestRenamer(names)
val renamer = TestRenamer(names, preserveUserAnnotatedPrefix=false)
val obtainedRenamed = renamer(obtained)
val expectedRenamed = renamer(expected)
val obtainedPrinted = effekt.core.PrettyPrinter.format(obtainedRenamed).layout
val expectedPrinted = effekt.core.PrettyPrinter.format(expectedRenamed).layout
val obtainedPrinted = effekt.core.ReparsablePrettyPrinter.format(obtainedRenamed).layout
val expectedPrinted = effekt.core.ReparsablePrettyPrinter.format(expectedRenamed).layout
assertEquals(obtainedPrinted, expectedPrinted)
shouldBeEqual(obtainedRenamed, expectedRenamed, clue)
}
def assertAlphaEquivalentStatements(obtained: Stmt,
expected: Stmt,
clue: => Any = "values are not alpha-equivalent",
names: Names = Names(defaultNames))(using Location): Unit = {
val renamer = TestRenamer(names)
val renamer = TestRenamer(names, preserveUserAnnotatedPrefix=false)
shouldBeEqual(renamer(obtained), renamer(expected), clue)
}
def parse(input: String,
Expand Down
6 changes: 3 additions & 3 deletions effekt/jvm/src/test/scala/effekt/core/ReparseTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class ReparseTests extends CoreTests {
}
val renamer = TestRenamer(Names(defaultNames))
val expectedRenamed = renamer(coreMod)
val printed = core.PrettyPrinter.format(expectedRenamed).layout
val printed = core.ReparsablePrettyPrinter.format(expectedRenamed).layout
val reparsed: ModuleDecl = try { parse(printed)(using Location.empty) } catch {
case e @ TypeError(msg, context) =>
println(e.toString)
Expand All @@ -86,8 +86,8 @@ class ReparseTests extends CoreTests {
throw e
}
val reparsedRenamed = renamer(reparsed)
val reparsedPrinted = core.PrettyPrinter.format(reparsedRenamed).layout
val expectedPrinted = core.PrettyPrinter.format(expectedRenamed).layout
val reparsedPrinted = core.ReparsablePrettyPrinter.format(reparsedRenamed).layout
val expectedPrinted = printed
assertEquals(reparsedPrinted, expectedPrinted)
}

Expand Down
69 changes: 34 additions & 35 deletions effekt/jvm/src/test/scala/effekt/core/TestRenamerTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ class TestRenamerTests extends CoreTests {
names: Names = Names(defaultNames))(using munit.Location) = {
val pInput = parse(input, "input", names)
val pExpected = parse(renamed, "expected", names)
val renamer = new TestRenamer(names, "renamed") // use "renamed" as prefix so we can refer to it
val renamer = new TestRenamer(names, "_renamed_") // use "renamed" as prefix so we can refer to it
val obtained = renamer(pInput)
val obtainedPrinted = effekt.core.PrettyPrinter.format(obtained).layout
val expectedPrinted = effekt.core.PrettyPrinter.format(pExpected).layout
val obtainedPrinted = effekt.core.ReparsablePrettyPrinter.format(obtained).layout
val expectedPrinted = effekt.core.ReparsablePrettyPrinter.format(pExpected).layout
assertEquals(obtainedPrinted, expectedPrinted)
shouldBeEqual(obtained, pExpected, clue)
}
Expand All @@ -31,7 +31,7 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0() = {
|def foo_renamed_0() = {
| return (bar: (Int) => Int @ {})(baz: Int)
|}
|""".stripMargin
Expand All @@ -51,11 +51,11 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0() = {
| val renamed1: Int = {
| renamed0: (Int) => Int @ {}(4)
|def foo_renamed_0() = {
| val x_renamed_1: Int = {
| foo_renamed_0: (Int) => Int @ {}(4)
| };
| return renamed1: Int
| return x_renamed_1: Int
|}
|""".stripMargin
assertRenamedTo(input, expected)
Expand All @@ -73,9 +73,9 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0() = {
| var renamed1 @ global = (renamed0: (Int) => Int @ {})(4);
| return renamed1: Int
|def foo_renamed_0() = {
| var x_renamed_1 @ global = (foo_renamed_0: (Int) => Int @ {})(4);
| return x_renamed_1: Int
|}
|""".stripMargin
assertRenamedTo(input, expected)
Expand All @@ -85,15 +85,15 @@ class TestRenamerTests extends CoreTests {
val input =
"""module main
|
|def renamed0(renamed1: Int) = {
| return renamed1: Int
|def f(x: Int) = {
| return x: Int
|}
|""".stripMargin
val expected =
"""module main
|
|def renamed0(renamed1: Int) = {
| return renamed1: Int
|def f_renamed_0(x_renamed_1: Int) = {
| return x_renamed_1: Int
|}
|""".stripMargin
assertRenamedTo(input, expected)
Expand All @@ -113,18 +113,17 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|type renamed1 {
| renamed0(a: Int, b: Int)
|type Data_renamed_1 {
| X_renamed_0(a: Int, b: Int)
|}
|
|def renamed2() = {
| 12 match [Int] {
| X : { (renamed3: Int, renamed4: Int) =>
| return renamed3: Int
|def foo_renamed_2() = {
| 12 match[Int] {
| X : { (aa_renamed_3: Int, bb_renamed_4: Int) =>
| return aa_renamed_3: Int
| }
| }
|}
|""".stripMargin
|}""".stripMargin
assertRenamedTo(input, expected)
}

Expand All @@ -139,8 +138,8 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0['renamed1](renamed2: Identity[renamed1]) = {
| return renamed2: Identity[renamed1]
|def foo_renamed_0['A_renamed_1](a_renamed_2: Identity[A_renamed_1]) = {
| return a_renamed_2: Identity[A_renamed_1]
|}
|""".stripMargin
assertRenamedTo(input, expected)
Expand All @@ -161,17 +160,17 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0() = {
|def bar_renamed_0() = {
| return 1
|}
|def renamed1() = {
| def renamed2() = {
| renamed0: () => Unit @ {}()
|def main_renamed_1() = {
| def foo_renamed_2() = {
| bar_renamed_0: () => Unit @ {}()
| }
| def renamed3() = {
| def bar_renamed_3() = {
| return 2
| }
| renamed2: () => Unit @ {}()
| foo_renamed_2: () => Unit @ {}()
|}
|""".stripMargin

Expand All @@ -191,10 +190,10 @@ class TestRenamerTests extends CoreTests {
val expected =
"""module main
|
|def renamed0() = {
| let renamed1 = 1
| let renamed2 = 2
| return renamed2: Int
|def main_renamed_0() = {
| let x_renamed_1 = 1
| let x_renamed_2 = 2
| return x_renamed_2: Int
|}
|""".stripMargin

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package effekt.core

import effekt.util.messages.ErrorReporter
import PrettyPrinter.*
import HumanReadablePrettyPrinter.*

/**
* Context for transformations of a [[core.ModuleDecl]] that provides the declarations for this module.
Expand Down
76 changes: 54 additions & 22 deletions effekt/shared/src/main/scala/effekt/core/PrettyPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ package core
import effekt.core.Type.{ PromptSymbol, ResumeSymbol, TChar }
import effekt.source.FeatureFlag
import kiama.output.ParenPrettyPrinter
import kiama.output.PrettyPrinterTypes.Document

import scala.language.implicitConversions
import effekt.symbols.{ Name, Wildcard, builtins }

object PrettyPrinter extends ParenPrettyPrinter {

import kiama.output.PrettyPrinterTypes.Document

class PrettyPrinter(printDetails: Boolean, printInternalIds: Boolean = true) extends ParenPrettyPrinter {
override val defaultIndent = 2

def format(t: ModuleDecl): Document =
Expand Down Expand Up @@ -56,9 +54,9 @@ object PrettyPrinter extends ParenPrettyPrinter {
// The order of toplevel items must match the parser (where the order is currently fixed).
val includes = vsep(m.includes.map { im => "import" <+> im })
val decls = vsep(m.declarations.map(toDoc))
val externs = vsep(m.externs.map(toDoc))
val externs = if printDetails then vsep(m.externs.map(toDoc)) else emptyDoc
val defs = toDoc(m.definitions)
val exports = vsep(m.exports.map { id => "export" <+> toDoc(id) })
val exports = if printDetails then vsep(m.exports.map { id => "export" <+> toDoc(id) }) else emptyDoc

"module" <+> m.path <>
emptyline <>
Expand Down Expand Up @@ -101,7 +99,7 @@ object PrettyPrinter extends ParenPrettyPrinter {

def toDoc(b: Block, preventBraces: Boolean = false): Doc = b match {
case BlockVar(id, tpe, capt) =>
toDoc(id) <> ":" <+> toDoc(tpe) <+> "@" <+> toDoc(capt)
toDoc(id) <> (if printDetails then ":" <+> toDoc(tpe) <+> "@" <+> toDoc(capt) else emptyDoc)
case BlockLit(tps, cps, vps, bps, body) =>
val doc = space <> paramsToDoc(tps, cps, vps, bps) <+> "=>" <+> nest(line <> toDocStmts(body)) <> line
if preventBraces then doc else braces { doc }
Expand All @@ -111,24 +109,37 @@ object PrettyPrinter extends ParenPrettyPrinter {

def toDoc(p: ValueParam): Doc = toDoc(p.id) <> ":" <+> toDoc(p.tpe)
def toDoc(p: BlockParam): Doc = braces(toDoc(p.id) <> ":" <+> toDoc(p.tpe))
def toDoc(cparam: Id, bparam: BlockParam): Doc = braces(toDoc(bparam.id) <+> "@" <+> toDoc(cparam) <> ":" <+> toDoc(bparam.tpe))
def toDoc(cparam: Id, bparam: BlockParam): Doc = {
if printDetails then
braces(toDoc(bparam.id) <+> "@" <+> toDoc(cparam) <> ":" <+> toDoc(bparam.tpe))
else
braces(toDoc(bparam.id) <> ":" <+> toDoc(bparam.tpe))
}

//def toDoc(n: Name): Doc = n.toString

def toDoc(s: symbols.Symbol): Doc =
builtins.coreBuiltinSymbolToString(s).getOrElse(s.name.name)
def toDoc(s: symbols.Symbol): Doc = {
// In human-readable mode, we show the name together with the actual Barendregt id.
// This allows the user to connect the symbol to the internal representation when debugging.
// In reparsable mode, we just show the string part, which should be freshened by the TestRenamer before printing.
// The TestRenamer does not rename the Barendregt id because that would violate the internal invariant of having
// just a single global Barendregt namespace.
builtins.coreBuiltinSymbolToString(s).getOrElse(if printInternalIds then s.show else s.name.name)
}

def toDoc(e: Expr): Doc = e match {
case Literal((), _) => "()"
case Literal(n, Type.TInt) => n.toString
case Literal(n, Type.TChar) => s"'\\${n.toString}'"
case Literal(s: String, _) => stringLiteral(s)
case Literal(value, _) => value.toString
case ValueVar(id, tpe) => toDoc(id) <> ":" <+> toDoc(tpe)

case PureApp(b, targs, vargs) => parens(toDoc(b)) <> argsToDoc(targs, vargs, Nil)
case Make(data, tag, targs, vargs) => "make" <+> toDoc(data) <+> toDoc(tag) <> argsToDoc(targs, vargs, Nil)

case ValueVar(id, tpe) => toDoc(id) <> (if printDetails then ":" <+> toDoc(tpe) else emptyDoc)
case PureApp(b, targs, vargs) => (if printDetails then parens(toDoc(b)) else toDoc(b)) <> argsToDoc(targs, vargs, Nil)
case Make(data, tag, targs, vargs) =>
if printDetails then
"make" <+> toDoc(data) <+> toDoc(tag) <> argsToDoc(targs, vargs, Nil)
else
"make" <+> toDoc(tag) <> argsToDoc(targs, vargs, Nil)
case Box(b, capt) => "box" <+> toDoc(capt) <+> toDoc(b)
}

Expand Down Expand Up @@ -235,7 +246,8 @@ object PrettyPrinter extends ParenPrettyPrinter {
toDoc(b) <> argsToDoc(targs, vargs, bargs)

case Invoke(b, method, methodTpe, targs, vargs, bargs) =>
toDoc(b) <> "." <> toDoc(method) <> ":" <+> toDoc(methodTpe) <> argsToDoc(targs, vargs, bargs)
val pTpe = if printDetails then ":" <+> toDoc(methodTpe) else emptyDoc
toDoc(b) <> "." <> toDoc(method) <> pTpe <> argsToDoc(targs, vargs, bargs)

case If(cond, thn, els) =>
"if" <+> parens(toDoc(cond)) <+> block(toDocStmts(thn)) <+> "else" <+> block(toDocStmts(els))
Expand All @@ -254,16 +266,25 @@ object PrettyPrinter extends ParenPrettyPrinter {
toDocStmts(body)

case Var(ref, init, cap, body) =>
"var" <+> toDoc(ref) <+> "@" <+> toDoc(cap) <+> "=" <+> toDoc(init) <> ";" <> line <>
toDocStmts(body)
if printDetails then
"var" <+> toDoc(ref) <+> "@" <+> toDoc(cap) <+> "=" <+> toDoc(init) <> ";" <> line <> toDocStmts(body)
else
"var" <+> toDoc(ref) <+> "=" <+> toDoc(init) <> ";" <> line <> toDocStmts(body)

case Get(id, tpe, ref, capt, body) =>
"get" <+> toDoc(id) <+> ":" <+> toDoc(tpe) <+> "=" <+> "!" <+> toDoc(ref) <+> "@" <+> toDocSingleCapture(capt) <> ";" <> line <>
toDocStmts(body)
if printDetails then
"get" <+> toDoc(id) <+> ":" <+> toDoc(tpe) <+> "=" <+> "!" <+> toDoc(ref) <+> "@" <+> toDocSingleCapture(capt) <> ";" <> line <>
toDocStmts(body)
else
"get" <+> toDoc(id) <+> "=" <+> "!" <+> toDoc(ref) <> ";" <> line <> toDocStmts(body)

case Put(ref, capt, value, body) =>
"put" <+> toDoc(ref) <+> "@" <+> toDocSingleCapture(capt) <+> "=" <+> toDoc(value) <> ";" <> line <>
toDocStmts(body)
if printDetails then
"put" <+> toDoc(ref) <+> "@" <+> toDocSingleCapture(capt) <+> "=" <+> toDoc(value) <> ";" <> line <>
toDocStmts(body)
else
"put" <+> toDoc(ref) <+> "=" <+> toDoc(value) <> ";" <> line <>
toDocStmts(body)

case Region(body) =>
"region" <+> toDoc(body)
Expand Down Expand Up @@ -346,3 +367,14 @@ object PrettyPrinter extends ParenPrettyPrinter {
multi <> s <> multi
}
}

/**
* Instance of PrettyPrinter that produces output that can be parsed back by the core parser.
*/
object ReparsablePrettyPrinter extends PrettyPrinter(true, false) {}

/**
* Instance of PrettyPrinter that produces less verbose, more human-readable output.
* This is the default behavior for the `--ir-write-all` and `--ir-show` command line flags.
*/
object HumanReadablePrettyPrinter extends PrettyPrinter(false) {}
Loading
Loading