@@ -7,6 +7,7 @@ import effekt.symbols.{ Symbol, TermSymbol }
7
7
import effekt .symbols .builtins .TState
8
8
import effekt .util .messages .ErrorReporter
9
9
import effekt .symbols .ErrorMessageInterpolator
10
+ import scala .annotation .tailrec
10
11
11
12
12
13
object Transformer {
@@ -315,15 +316,15 @@ object Transformer {
315
316
def transformBlockArg (block : core.Block )(using BPC : BlocksParamsContext , DC : DeclarationContext , E : ErrorReporter ): Binding [Variable ] = block match {
316
317
case core.BlockVar (id, tpe, _) if BPC .globals contains id =>
317
318
val variable = Variable (transform(id), transform(tpe))
318
- Binding { k =>
319
+ shift { k =>
319
320
PushFrame (Clause (List (variable), k(variable)), Jump (BPC .globals(id)))
320
321
}
321
322
case core.BlockVar (id, tpe, capt) => getBlockInfo(id) match {
322
323
case BlockInfo .Definition (_, parameters) =>
323
324
// Passing a top-level function directly, so we need to eta-expand turning it into a closure
324
325
// TODO cache the closure somehow to prevent it from being created on every call
325
326
val variable = Variable (freshName(id.name.name ++ " $closure" ), Negative ())
326
- Binding { k =>
327
+ shift { k =>
327
328
New (variable, List (Clause (parameters,
328
329
// conceptually: Substitute(parameters zip parameters, Jump(...)) but the Substitute is a no-op here
329
330
Jump (transformLabel(id))
@@ -337,13 +338,13 @@ object Transformer {
337
338
noteParameters(bparams)
338
339
val parameters = vparams.map(transform) ++ bparams.map(transform);
339
340
val variable = Variable (freshName(" blockLit" ), Negative ())
340
- Binding { k =>
341
+ shift { k =>
341
342
New (variable, List (Clause (parameters, transform(body))), k(variable))
342
343
}
343
344
344
345
case core.New (impl) =>
345
346
val variable = Variable (freshName(" new" ), Negative ())
346
- Binding { k =>
347
+ shift { k =>
347
348
New (variable, transform(impl), k(variable))
348
349
}
349
350
@@ -355,7 +356,7 @@ object Transformer {
355
356
356
357
case core.ValueVar (id, tpe) if BC .globals contains id =>
357
358
val variable = Variable (freshName(" run" ), transform(tpe))
358
- Binding { k =>
359
+ shift { k =>
359
360
// TODO this might introduce too many pushes.
360
361
PushFrame (Clause (List (variable), k(variable)),
361
362
Substitute (Nil , Jump (BC .globals(id))))
@@ -366,38 +367,38 @@ object Transformer {
366
367
367
368
case core.Literal ((), _) =>
368
369
val variable = Variable (freshName(" unitLiteral" ), Positive ());
369
- Binding { k =>
370
+ shift { k =>
370
371
Construct (variable, builtins.Unit , List (), k(variable))
371
372
}
372
373
373
374
case core.Literal (value : Long , _) =>
374
375
val variable = Variable (freshName(" longLiteral" ), Type .Int ());
375
- Binding { k =>
376
+ shift { k =>
376
377
LiteralInt (variable, value, k(variable))
377
378
}
378
379
379
380
// for characters
380
381
case core.Literal (value : Int , _) =>
381
382
val variable = Variable (freshName(" intLiteral" ), Type .Int ());
382
- Binding { k =>
383
+ shift { k =>
383
384
LiteralInt (variable, value, k(variable))
384
385
}
385
386
386
387
case core.Literal (value : Boolean , _) =>
387
388
val variable = Variable (freshName(" booleanLiteral" ), Positive ())
388
- Binding { k =>
389
+ shift { k =>
389
390
Construct (variable, if (value) builtins.True else builtins.False , List (), k(variable))
390
391
}
391
392
392
393
case core.Literal (v : Double , _) =>
393
394
val literal_binding = Variable (freshName(" doubleLiteral" ), Type .Double ());
394
- Binding { k =>
395
+ shift { k =>
395
396
LiteralDouble (literal_binding, v, k(literal_binding))
396
397
}
397
398
398
399
case core.Literal (javastring : String , _) =>
399
400
val literal_binding = Variable (freshName(" utf8StringLiteral" ), builtins.StringType );
400
- Binding { k =>
401
+ shift { k =>
401
402
LiteralUTF8String (literal_binding, javastring.getBytes(" utf-8" ), k(literal_binding))
402
403
}
403
404
@@ -406,7 +407,7 @@ object Transformer {
406
407
407
408
val variable = Variable (freshName(" pureApp" ), transform(tpe.result))
408
409
transform(vargs, Nil ).flatMap { (values, blocks) =>
409
- Binding { k =>
410
+ shift { k =>
410
411
ForeignCall (variable, transform(blockName), values ++ blocks, k(variable))
411
412
}
412
413
}
@@ -416,7 +417,7 @@ object Transformer {
416
417
417
418
val variable = Variable (freshName(" pureApp" ), transform(tpe.result))
418
419
transform(vargs, bargs).flatMap { (values, blocks) =>
419
- Binding { k =>
420
+ shift { k =>
420
421
ForeignCall (variable, transform(blockName), values ++ blocks, k(variable))
421
422
}
422
423
}
@@ -428,14 +429,14 @@ object Transformer {
428
429
val tag = DeclarationContext .getConstructorTag(constructor)
429
430
430
431
transform(vargs, Nil ).flatMap { (values, blocks) =>
431
- Binding { k =>
432
+ shift { k =>
432
433
Construct (variable, tag, values ++ blocks, k(variable))
433
434
}
434
435
}
435
436
436
437
case core.Box (block, annot) =>
437
438
transformBlockArg(block).flatMap { unboxed =>
438
- Binding { k =>
439
+ shift { k =>
439
440
val boxed = Variable (freshName(unboxed.name), Type .Positive ())
440
441
ForeignCall (boxed, " box" , List (unboxed), k(boxed))
441
442
}
@@ -564,13 +565,28 @@ object Transformer {
564
565
def getBlockInfo (id : Id )(using BPC : BlocksParamsContext ): BlockInfo =
565
566
BPC .info.getOrElse(id, sys error s " No block info for ${util.show(id)}" )
566
567
567
- case class Binding [A ](run : (A => Statement ) => Statement ) {
568
+ def shift [A ](body : (A => Statement ) => Statement ): Binding [A ] =
569
+ Binding { k => Trampoline .Done (body { x => trampoline(k(x)) }) }
570
+
571
+ case class Binding [A ](body : (A => Trampoline [Statement ]) => Trampoline [Statement ]) {
568
572
def flatMap [B ](rest : A => Binding [B ]): Binding [B ] = {
569
- Binding (k => run( a => rest(a).run (k)) )
573
+ Binding (k => Trampoline . More { () => body( a => Trampoline . More { () => rest(a).body (k) }) } )
570
574
}
575
+ def run (k : A => Statement ): Statement = trampoline(body { x => Trampoline .Done (k(x)) })
571
576
def map [B ](f : A => B ): Binding [B ] = flatMap { a => pure(f(a)) }
572
577
}
573
578
579
+ enum Trampoline [A ] {
580
+ case Done (value : A )
581
+ case More (thunk : () => Trampoline [A ])
582
+ }
583
+
584
+ @ tailrec
585
+ def trampoline [A ](body : Trampoline [A ]): A = body match {
586
+ case Trampoline .Done (value) => value
587
+ case Trampoline .More (thunk) => trampoline(thunk())
588
+ }
589
+
574
590
def traverse [S , T ](l : List [S ])(f : S => Binding [T ]): Binding [List [T ]] =
575
591
l match {
576
592
case Nil => pure(Nil )
0 commit comments