aboutsummaryrefslogtreecommitdiff
path: root/sjs/backend/sjs/ScopedVar.scala
blob: 0e47f7b7946bb7b4dbabdf6bac9ada9a5eef6eb8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package dotty.tools.backend.sjs

import language.implicitConversions

class ScopedVar[A](init: A) {
  import ScopedVar.Assignment

  private var value = init

  def this()(implicit ev: Null <:< A) = this(ev(null))

  def get: A = value
  def :=(newValue: A): Assignment[A] = new Assignment(this, newValue)
}

object ScopedVar {
  class Assignment[T](scVar: ScopedVar[T], value: T) {
    private[ScopedVar] def push(): AssignmentStackElement[T] = {
      val stack = new AssignmentStackElement(scVar, scVar.value)
      scVar.value = value
      stack
    }
  }

  private class AssignmentStackElement[T](scVar: ScopedVar[T], oldValue: T) {
    private[ScopedVar] def pop(): Unit = {
      scVar.value = oldValue
    }
  }

  implicit def toValue[T](scVar: ScopedVar[T]): T = scVar.get

  def withScopedVars[T](ass: Assignment[_]*)(body: => T): T = {
    val stack = ass.map(_.push())
    try body
    finally stack.reverse.foreach(_.pop())
  }
}