Skip to content

Commit

Permalink
Make EClo capture expressions rather than names (#253)
Browse files Browse the repository at this point in the history
  • Loading branch information
stonechoe authored Sep 2, 2024
1 parent c09d6c7 commit 360dafc
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 18 deletions.
10 changes: 7 additions & 3 deletions src/main/scala/esmeta/analyzer/AbsTransfer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,13 @@ trait AbsTransferDecl { self: Analyzer =>
cfg.fnameMap.get(fname) match {
case Some(f) =>
for {
st <- get
captured = cap.map(x => x -> st.lookupLocal(x)).toMap
} yield AbsValue(AClo(f, captured))
captured <- join(cap.map {
case (x, e) =>
for {
v <- transfer(e)
} yield (x, v)
})
} yield AbsValue(AClo(f, captured.toMap))
case None =>
for { _ <- put(AbsState.Bot) } yield AbsValue.Bot
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/esmeta/compiler/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -676,7 +676,10 @@ class Compiler(
body = body,
prefix = prefix,
)
EClo(cn, captured.map(compile))
EClo(
cn,
captured.map(x => { val n = compile(x); (n, ERef(n)) }),
)
case XRefExpression(XRefExpressionOperator.Algo, id) =>
EClo(spec.getAlgoById(id).head.fname, Nil)
case XRefExpression(XRefExpressionOperator.ParamLength, id) =>
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/esmeta/interpreter/Interpreter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ class Interpreter(
)
case EClo(fname, captured) =>
val func = cfg.fnameMap.getOrElse(fname, throw UnknownFunc(fname))
Clo(func, Map.from(captured.map(x => x -> st(x))))
Clo(func, Map.from(captured.map { (x, e) => x -> eval(e) }))
case ECont(fname) =>
val func = cfg.fnameMap.getOrElse(fname, throw UnknownFunc(fname))
val captured = st.context.locals.collect { case (x: Name, v) => x -> v }
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/esmeta/ir/Expr.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ case class EMathOp(mop: MOp, args: List[Expr]) extends Expr
case class EConvert(cop: COp, expr: Expr) extends Expr
case class ETypeOf(base: Expr) extends Expr
case class ETypeCheck(base: Expr, tyExpr: Expr) extends Expr
case class EClo(fname: String, captured: List[Name]) extends Expr
case class EClo(fname: String, captured: List[(Name, Expr)]) extends Expr
case class ECont(fname: String) extends Expr

// debugging expressions
Expand Down
12 changes: 10 additions & 2 deletions src/main/scala/esmeta/ir/util/Parser.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,16 @@ trait Parsers extends TyParsers {
case e => ETypeOf(e)
} | "(" ~ "?" ~> expr ~ (":" ~> expr) <~ ")" ^^ {
case e ~ t => ETypeCheck(e, t)
} | "clo<" ~> fname ~ opt("," ~ "[" ~> repsep(name, ",") <~ "]") <~ ">" ^^ {
case s ~ cs => EClo(s, cs.getOrElse(Nil))
} | "clo<" ~> fname ~ opt(
"," ~ "{" ~> repsep(name ~ opt(":" ~> expr), ",") <~ "}",
) <~ ">" ^^ {
case s ~ cs =>
EClo(
s,
cs.map(lst =>
lst.map { case x ~ eopt => x -> eopt.getOrElse(ERef(x)) },
).getOrElse(Nil),
)
} | ("cont<" ~> fname <~ ">") ^^ {
case s => ECont(s)
} | "(" ~ "debug" ~> expr <~ ")" ^^ {
Expand Down
10 changes: 8 additions & 2 deletions src/main/scala/esmeta/ir/util/Stringifier.scala
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,15 @@ class Stringifier(detail: Boolean, location: Boolean) {
case ETypeCheck(expr, ty) =>
app >> "(? " >> expr >> ": " >> ty >> ")"
case EClo(fname, captured) =>
given Rule[Iterable[Name]] = iterableRule("[", ", ", "]")
given Rule[Iterable[(Name, Expr)]] = iterableRule("{", ", ", "}")
given Rule[(Name, Expr)] = {
case (app, (name, expr)) =>
expr match
case ERef(`name`) => app >> name
case _ => app >> name >> " : " >> expr
}
app >> "clo<" >> fname
if (!captured.isEmpty) app >> ", " >> captured
if (!captured.isEmpty) then app >> ", " >> captured
app >> ">"
case ECont(fname) =>
app >> "cont<" >> fname >> ">"
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/esmeta/ir/util/UnitWalker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ trait UnitWalker extends BasicUnitWalker {
case ETypeCheck(expr, ty) =>
walk(expr); walk(ty)
case EClo(fname, captured) =>
walk(fname); walkList(captured, walk)
walk(fname); walkList(captured, { case (n, e) => (walk(n), walk(e)) })
case ECont(fname) =>
walk(fname)
case EDebug(expr) =>
Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/esmeta/ir/util/Walker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ trait Walker extends BasicWalker {
case ETypeCheck(expr, ty) =>
ETypeCheck(walk(expr), walk(ty))
case EClo(fname, captured) =>
EClo(walk(fname), walkList(captured, walk))
EClo(
walk(fname),
walkList(captured, { case (n, e) => (walk(n), walk(e)) }),
)
case ECont(fname) =>
ECont(walk(fname))
case EDebug(expr) =>
Expand Down
4 changes: 3 additions & 1 deletion src/test/scala/esmeta/ir/IRTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ object IRTest {
lazy val normal = EEnum("normal")
lazy val empty = EEnum("empty")
lazy val clo = EClo("f", Nil)
lazy val cloWithCaptured = EClo("f", List(x))
lazy val cloWithCaptured = EClo("f", List((x -> ERef(x))))
lazy val cloWithCapturedComplex =
EClo("f", List((x -> EBinary(BOp.Add, ERef(y), EMath(1)))))
lazy val cont = ECont("g")

// references
Expand Down
3 changes: 2 additions & 1 deletion src/test/scala/esmeta/ir/JsonTinyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class JsonTinyTest extends IRTest {
normal -> "~normal~",
empty -> "~empty~",
clo -> "clo<f>",
cloWithCaptured -> "clo<f, [x]>",
cloWithCaptured -> "clo<f, {x}>",
cloWithCapturedComplex -> "clo<f, {x : (+ y 1)}>",
cont -> "cont<g>",
)

Expand Down
3 changes: 2 additions & 1 deletion src/test/scala/esmeta/ir/StringifyTinyTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ class StringifyTinyTest extends IRTest {
normal -> "~normal~",
empty -> "~empty~",
clo -> "clo<f>",
cloWithCaptured -> "clo<f, [x]>",
cloWithCaptured -> "clo<f, {x}>",
cloWithCapturedComplex -> "clo<f, {x : (+ y 1)}>",
cont -> "cont<g>",
)

Expand Down
6 changes: 3 additions & 3 deletions tests/ir/expr/binary-equal.ir
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ def h() = { }
assert (= clo<g> clo<g>)
assert (! (= clo<g> clo<h>)) // because different fids
let a = 0
let clo1 = clo<g, [a]>
let clo2 = clo<g, [a]>
let clo1 = clo<g, {a}>
let clo2 = clo<g, {a}>
assert (= clo1 clo2)
a = 1
let clo3 = clo<g, [a]>
let clo3 = clo<g, {a}>
assert (! (= clo1 clo3)) // becuase `a` points to 0 in clo1 but 1 in clo3
// continuations
assert (= cont<g> cont<g>)
Expand Down

0 comments on commit 360dafc

Please sign in to comment.