summaryrefslogtreecommitdiff
path: root/examples/scala-js/ir/src/main/scala/scala/scalajs/ir/Transformers.scala
blob: 5e4f40c19596b7415e66bca2c1f9a611359ad201 (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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*                     __                                               *\
**     ________ ___   / /  ___      __ ____  Scala.js IR                **
**    / __/ __// _ | / /  / _ | __ / // __/  (c) 2014, LAMP/EPFL        **
**  __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \    http://scala-js.org/       **
** /____/\___/_/ |_/____/_/ | |__/ /____/                               **
**                          |/____/                                     **
\*                                                                      */


package scala.scalajs.ir

import Trees._

object Transformers {

  abstract class Transformer {
    final def transformStat(tree: Tree): Tree =
      transform(tree, isStat = true)

    final def transformExpr(tree: Tree): Tree =
      transform(tree, isStat = false)

    def transform(tree: Tree, isStat: Boolean): Tree = {
      implicit val pos = tree.pos

      tree match {
        // Definitions

        case VarDef(ident, vtpe, mutable, rhs) =>
          VarDef(ident, vtpe, mutable, transformExpr(rhs))

        // Control flow constructs

        case Block(stats :+ expr) =>
          Block(stats.map(transformStat) :+ transform(expr, isStat))

        case Labeled(label, tpe, body) =>
          Labeled(label, tpe, transform(body, isStat))

        case Assign(lhs, rhs) =>
          Assign(transformExpr(lhs), transformExpr(rhs))

        case Return(expr, label) =>
          Return(transformExpr(expr), label)

        case If(cond, thenp, elsep) =>
          If(transformExpr(cond), transform(thenp, isStat),
              transform(elsep, isStat))(tree.tpe)

        case While(cond, body, label) =>
          While(transformExpr(cond), transformStat(body), label)

        case DoWhile(body, cond, label) =>
          DoWhile(transformStat(body), transformExpr(cond), label)

        case Try(block, errVar, handler, finalizer) =>
          Try(transform(block, isStat), errVar, transform(handler, isStat),
              transformStat(finalizer))(tree.tpe)

        case Throw(expr) =>
          Throw(transformExpr(expr))

        case Match(selector, cases, default) =>
          Match(transformExpr(selector),
              cases map (c => (c._1, transform(c._2, isStat))),
              transform(default, isStat))(tree.tpe)

        // Scala expressions

        case New(cls, ctor, args) =>
          New(cls, ctor, args map transformExpr)

        case StoreModule(cls, value) =>
          StoreModule(cls, transformExpr(value))

        case Select(qualifier, item, mutable) =>
          Select(transformExpr(qualifier), item, mutable)(tree.tpe)

        case Apply(receiver, method, args) =>
          Apply(transformExpr(receiver), method,
              args map transformExpr)(tree.tpe)

        case StaticApply(receiver, cls, method, args) =>
          StaticApply(transformExpr(receiver), cls, method,
              args map transformExpr)(tree.tpe)

        case TraitImplApply(impl, method, args) =>
          TraitImplApply(impl, method, args map transformExpr)(tree.tpe)

        case UnaryOp(op, lhs) =>
          UnaryOp(op, transformExpr(lhs))

        case BinaryOp(op, lhs, rhs) =>
          BinaryOp(op, transformExpr(lhs), transformExpr(rhs))

        case NewArray(tpe, lengths) =>
          NewArray(tpe, lengths map transformExpr)

        case ArrayValue(tpe, elems) =>
          ArrayValue(tpe, elems map transformExpr)

        case ArrayLength(array) =>
          ArrayLength(transformExpr(array))

        case ArraySelect(array, index) =>
          ArraySelect(transformExpr(array), transformExpr(index))(tree.tpe)

        case RecordValue(tpe, elems) =>
          RecordValue(tpe, elems map transformExpr)

        case IsInstanceOf(expr, cls) =>
          IsInstanceOf(transformExpr(expr), cls)

        case AsInstanceOf(expr, cls) =>
          AsInstanceOf(transformExpr(expr), cls)

        case Unbox(expr, charCode) =>
          Unbox(transformExpr(expr), charCode)

        case GetClass(expr) =>
          GetClass(transformExpr(expr))

        case CallHelper(helper, args) =>
          CallHelper(helper, args map transformExpr)(tree.tpe)

        // JavaScript expressions

        case JSNew(ctor, args) =>
          JSNew(transformExpr(ctor), args map transformExpr)

        case JSDotSelect(qualifier, item) =>
          JSDotSelect(transformExpr(qualifier), item)

        case JSBracketSelect(qualifier, item) =>
          JSBracketSelect(transformExpr(qualifier), transformExpr(item))

        case JSFunctionApply(fun, args) =>
          JSFunctionApply(transformExpr(fun), args map transformExpr)

        case JSDotMethodApply(receiver, method, args) =>
          JSDotMethodApply(transformExpr(receiver), method,
              args map transformExpr)

        case JSBracketMethodApply(receiver, method, args) =>
          JSBracketMethodApply(transformExpr(receiver), transformExpr(method),
              args map transformExpr)

        case JSDelete(prop) =>
          JSDelete(transformExpr(prop))

        case JSUnaryOp(op, lhs) =>
          JSUnaryOp(op, transformExpr(lhs))

        case JSBinaryOp(op, lhs, rhs) =>
          JSBinaryOp(op, transformExpr(lhs), transformExpr(rhs))

        case JSArrayConstr(items) =>
          JSArrayConstr(items map transformExpr)

        case JSObjectConstr(fields) =>
          JSObjectConstr(fields map {
            case (name, value) => (name, transformExpr(value))
          })

        // Atomic expressions

        case Closure(captureParams, params, body, captureValues) =>
          Closure(captureParams, params, transformExpr(body),
              captureValues.map(transformExpr))

        // Trees that need not be transformed

        case _:Skip | _:Continue | _:LoadModule | _:JSEnvInfo |
            _:Literal | _:VarRef | _:This | EmptyTree =>
          tree

        case _ =>
          sys.error(s"Invalid tree in transform() of class ${tree.getClass}")
      }
    }
  }

  abstract class ClassTransformer extends Transformer {
    def transformClassDef(tree: ClassDef): ClassDef = {
      val ClassDef(name, kind, parent, ancestors, defs) = tree
      ClassDef(name, kind, parent, ancestors, defs.map(transformDef))(tree.pos)
    }

    def transformDef(tree: Tree): Tree = {
      implicit val pos = tree.pos

      tree match {
        case VarDef(name, vtpe, mutable, rhs) =>
          VarDef(name, vtpe, mutable, transformExpr(rhs))

        case MethodDef(name, args, resultType, body) =>
          MethodDef(name, args, resultType, transformStat(body))(None)

        case PropertyDef(name, getterBody, setterArg, setterBody) =>
          PropertyDef(
              name,
              transformStat(getterBody),
              setterArg,
              transformStat(setterBody))

        case ConstructorExportDef(fullName, args, body) =>
          ConstructorExportDef(fullName, args, transformStat(body))

        case ModuleExportDef(_) =>
          tree

        case _ =>
          sys.error(s"Invalid tree in transformDef() of class ${tree.getClass}")
      }
    }
  }

}