@@ -22,19 +22,23 @@ import scala.quoted._
22
22
23
23
object DiagrammedExprMacro {
24
24
// Transform the input expression by parsing out the anchor and generate expression that can support diagram rendering
25
- def parse [ T : Type ]( expr : Expr [ T ])( implicit refl : Reflection ): Expr [ DiagrammedExpr [ T ]] = {
25
+ def parse ( refl : Reflection )( expr : refl. Term ): refl. Term = {
26
26
import refl ._
27
27
import util ._
28
28
29
+ type R
30
+ implicit val resTp : quoted.Type [R ] = expr.tpe.seal.asInstanceOf [quoted.Type [R ]]
31
+
29
32
def isXmlSugar (apply : Apply ): Boolean = apply.tpe <:< typeOf[scala.xml.Elem ]
30
33
def isJavaStatic (tree : Tree ): Boolean = tree.symbol.flags.is(Flags .Static )
31
34
32
- def apply (l : Expr [_] , name : String , targs : List [TypeTree ], r : List [Expr [_]] ): Expr [ T ] =
33
- Select .overloaded(l.unseal , name, targs.map(_.tpe), r.map(_.unseal)).seal.cast[ T ]
35
+ def apply (l : Term , name : String , targs : List [TypeTree ], args : List [Term ] ): Term =
36
+ Select .overloaded(l, name, targs.map(_.tpe), args)
34
37
35
- def selectField (o : Expr [_] , name : String ): Expr [ T ] = Select .unique(o.unseal , name).seal.cast[ T ]
38
+ def selectField (o : Term , name : String ): Term = Select .unique(o, name)
36
39
37
- def default : Expr [DiagrammedExpr [T ]] = ' { DiagrammedExpr .simpleExpr($expr, $ { getAnchor(expr) } ) }
40
+ def default : Term =
41
+ ' { DiagrammedExpr .simpleExpr[R ]($ {expr.seal.cast[R ]}, $ { getAnchor(expr) } ) }.unseal
38
42
39
43
def lets (xs : List [Term ])(body : List [Term ] => Term ): Term = {
40
44
def rec (xs : List [Term ], acc : List [Term ]): Term = xs match {
@@ -44,7 +48,22 @@ object DiagrammedExprMacro {
44
48
rec(xs, Nil )
45
49
}
46
50
47
- expr.unseal.underlyingArgument match {
51
+ def getAnchorForSelect (sel : Select ): Expr [Int ] = {
52
+ if (sel.name == " unary_!" )
53
+ (sel.pos.startColumn - rootPosition.startColumn).toExpr
54
+ else {
55
+ val selOffset = sel.pos.endColumn - sel.qualifier.pos.endColumn - sel.name.length
56
+ (sel.qualifier.pos.endColumn + selOffset - rootPosition.startColumn).toExpr
57
+ }
58
+ }
59
+
60
+ def getAnchor (expr : Term ): Expr [Int ] = {
61
+ // -1 to match scala2 position
62
+ // ((expr.unseal.pos.endColumn + expr.unseal.pos.startColumn - 1) / 2 - rootPosition.startColumn).toExpr
63
+ (expr.pos.startColumn - rootPosition.startColumn).toExpr
64
+ }
65
+
66
+ expr match {
48
67
case Apply (Select (New (_), _), _) => default
49
68
50
69
case IsApply (apply) if isXmlSugar(apply) => default
@@ -58,103 +77,98 @@ object DiagrammedExprMacro {
58
77
case IsSelect (x) if isJavaStatic(x) => default
59
78
60
79
case sel @ Select (qual, name) =>
61
- type S
62
- implicit val tpS : quoted.Type [S ] = qual.tpe.seal.asInstanceOf [quoted.Type [S ]]
63
- val obj = parse[ S ]( qual.seal.asInstanceOf [ Expr [ S ]])
64
- val anchor = getAnchorForSelect(refl)( sel.asInstanceOf [Select ])
80
+ type T
81
+ implicit val objTp : quoted.Type [T ] = qual.tpe.seal.asInstanceOf [quoted.Type [T ]]
82
+ val obj = parse(refl)( qual) .seal.cast[ DiagrammedExpr [ T ]]
83
+ val anchor = getAnchorForSelect(sel.asInstanceOf [Select ])
65
84
66
85
' {
67
86
val o = $obj
68
- DiagrammedExpr .selectExpr(o, $ { selectField(' {o.value}, name) }, $anchor)
69
- }
87
+ DiagrammedExpr .selectExpr[ R ] (o, $ { selectField(' {o.value}.unseal , name).seal.cast[ R ] }, $anchor)
88
+ }.unseal
70
89
71
90
case Block (stats, expr) =>
72
- Block (stats, parse(expr.seal.cast[T ]).unseal).seal.cast[DiagrammedExpr [T ]] // call parse recursively using the expr argument if it is a block
91
+ // call parse recursively using the expr argument if it is a block
92
+ Block (stats, parse(refl)(expr))
73
93
74
94
case Apply (sel @ Select (lhs, op), rhs :: Nil ) =>
75
- val anchor = getAnchorForSelect(refl)( sel.asInstanceOf [Select ])
95
+ val anchor = getAnchorForSelect(sel.asInstanceOf [Select ])
76
96
op match {
77
97
case " ||" | " |" =>
78
- val left = parse(lhs.seal.cast[Boolean & T ])
79
- val right = parse(rhs.seal.cast[Boolean & T ])
98
+ val left = parse(refl)( lhs) .seal.cast[DiagrammedExpr [ Boolean ]]
99
+ val right = parse(refl)( rhs) .seal.cast[DiagrammedExpr [ Boolean ]]
80
100
81
101
' {
82
102
val l = $left
83
103
if (l.value) l
84
104
else {
85
105
val r = $right
86
- DiagrammedExpr .applyExpr(l, r :: Nil , r.value, $anchor)
106
+ DiagrammedExpr .applyExpr[ Boolean ] (l, r :: Nil , r.value, $anchor)
87
107
}
88
- }
108
+ }.unseal
89
109
case " &&" | " &" =>
90
- val left = parse(lhs.seal.cast[Boolean & T ])
91
- val right = parse(rhs.seal.cast[Boolean & T ])
110
+ val left = parse(refl)( lhs) .seal.cast[DiagrammedExpr [ Boolean ]]
111
+ val right = parse(refl)( rhs) .seal.cast[DiagrammedExpr [ Boolean ]]
92
112
' {
93
113
val l = $left
94
114
if (! l.value) l
95
115
else {
96
116
val r = $right
97
- DiagrammedExpr .applyExpr(l, r :: Nil , r.value, $anchor)
117
+ DiagrammedExpr .applyExpr[ Boolean ] (l, r :: Nil , r.value, $anchor)
98
118
}
99
- }
119
+ }.unseal
100
120
case _ =>
101
- type S
102
- implicit val tpS : quoted.Type [S ] = lhs.tpe.seal.asInstanceOf [quoted.Type [S ]]
103
- val left = parse[S ](lhs.seal.asInstanceOf [Expr [S ]])
104
-
105
- type V
106
- implicit val tpV : quoted.Type [V ] = rhs.tpe.seal.asInstanceOf [quoted.Type [V ]]
107
- val right = parse[V ](rhs.seal.asInstanceOf [Expr [V ]])
108
- ' {
109
- val l = $left
110
- val r = $right
111
- val res = $ { apply(' {l.value}, op, Nil , ' {r.value} :: Nil ) }
112
- DiagrammedExpr .applyExpr(l, r :: Nil , res, $anchor)
121
+ type T
122
+ implicit val tpT : quoted.Type [T ] = lhs.tpe.seal.asInstanceOf [quoted.Type [T ]]
123
+ val left = parse(refl)(lhs)
124
+
125
+ val right = parse(refl)(rhs)
126
+
127
+ let(left) { l =>
128
+ let(right) { r =>
129
+ val left = l.seal.cast[DiagrammedExpr [T ]]
130
+ val right = r.seal.cast[DiagrammedExpr [_]]
131
+ val res = apply(' {$left.value}.unseal, op, Nil , ' {$right.value}.unseal :: Nil ).seal.cast[R ]
132
+ ' { DiagrammedExpr .applyExpr[R ]($left, $right :: Nil , $res, $anchor) }.unseal
133
+ }
113
134
}
114
135
}
115
136
116
137
case Apply (sel @ Select (lhs, op), args) =>
117
- type S
118
- implicit val tpS : quoted.Type [S ] = lhs.tpe.seal.asInstanceOf [quoted.Type [S ]]
119
- val left = parse[S ](lhs.seal.asInstanceOf [Expr [S ]]).unseal
120
- val anchor = getAnchorForSelect(refl)(sel.asInstanceOf [Select ])
121
-
122
- val rights = args.map { arg =>
123
- type V
124
- implicit val tpV : quoted.Type [V ] = arg.tpe.seal.asInstanceOf [quoted.Type [V ]]
125
- parse[V ](arg.seal.asInstanceOf [Expr [V ]]).unseal
126
- }
138
+ type T
139
+ implicit val tpT : quoted.Type [T ] = lhs.tpe.seal.asInstanceOf [quoted.Type [T ]]
140
+
141
+ val left = parse(refl)(lhs)
142
+ val anchor = getAnchorForSelect(sel.asInstanceOf [Select ])
143
+
144
+ val rights = args.map { arg => parse(refl)(arg) }
127
145
128
146
let(left) { l =>
129
147
lets(rights) { rs =>
130
- val left = l.seal.cast[DiagrammedExpr [_ ]]
148
+ val left = l.seal.cast[DiagrammedExpr [T ]]
131
149
val rights = rs.map(_.seal.cast[DiagrammedExpr [_]])
132
- val res = Select .overloaded(' {$left.value}.unseal, op, Nil , rs).seal.cast[T ]
133
- ' { DiagrammedExpr .applyExpr($left, $ {rights.toExprOfList}, $res, $anchor) }.unseal
150
+ val res = Select .overloaded(' {$left.value}.unseal, op, Nil , rs).seal.cast[R ]
151
+ ' { DiagrammedExpr .applyExpr[ R ] ($left, $ {rights.toExprOfList}, $res, $anchor) }.unseal
134
152
}
135
- }.seal.cast[ DiagrammedExpr [ T ]]
153
+ }
136
154
137
- // TODO: Dotty produces a confusing error message about `let`
138
155
case Apply (TypeApply (sel @ Select (lhs, op), targs), args) =>
139
- type S
140
- implicit val tpS : quoted.Type [S ] = lhs.tpe.seal.asInstanceOf [quoted.Type [S ]]
141
- val left = parse[S ](lhs.seal.asInstanceOf [Expr [S ]]).unseal
142
- val anchor = getAnchorForSelect(refl)(sel.asInstanceOf [Select ])
143
-
144
- val rights = args.map { arg =>
145
- type V
146
- implicit val tpV : quoted.Type [V ] = arg.tpe.seal.asInstanceOf [quoted.Type [V ]]
147
- parse[V ](arg.seal.asInstanceOf [Expr [V ]]).unseal
148
- }
156
+ type T
157
+ implicit val tpT : quoted.Type [T ] = lhs.tpe.seal.asInstanceOf [quoted.Type [T ]]
158
+
159
+ val left = parse(refl)(lhs)
160
+ val anchor = getAnchorForSelect(sel.asInstanceOf [Select ])
161
+
162
+ val rights = args.map { arg => parse(refl)(arg) }
149
163
150
164
let(left) { l =>
151
165
lets(rights) { rs =>
152
- val left = l.seal.cast[DiagrammedExpr [_ ]]
166
+ val left = l.seal.cast[DiagrammedExpr [T ]]
153
167
val rights = rs.map(_.seal.cast[DiagrammedExpr [_]])
154
- val res = Select .overloaded(' {$left.value}.unseal, op, targs.map(_.tpe), rs).seal.cast[T ]
155
- ' { DiagrammedExpr .applyExpr($left, $ {rights.toExprOfList}, $res, $anchor) }.unseal
168
+ val res = Select .overloaded(' {$left.value}.unseal, op, targs.map(_.tpe), rs).seal.cast[R ]
169
+ ' { DiagrammedExpr .applyExpr[ R ] ($left, $ {rights.toExprOfList}, $res, $anchor) }.unseal
156
170
}
157
- }.seal.cast[ DiagrammedExpr [ T ]]
171
+ }
158
172
159
173
case _ =>
160
174
default
@@ -165,24 +179,8 @@ object DiagrammedExprMacro {
165
179
helper : Expr [(DiagrammedExpr [Boolean ], Any , String , source.Position ) => Assertion ],
166
180
condition : Expr [Boolean ], pos : Expr [source.Position ], clue : Expr [Any ], sourceText : String
167
181
)(implicit refl : Reflection ): Expr [Assertion ] = {
168
- val diagExpr = parse(condition)
169
- ' { $helper($diagExpr, $clue, $ {sourceText.toExpr}, $pos) }
170
- }
171
-
172
- def getAnchorForSelect (refl : Reflection )(sel : refl.Select ): Expr [Int ] = {
173
182
import refl ._
174
- if (sel.name == " unary_!" )
175
- (sel.pos.startColumn - rootPosition.startColumn).toExpr
176
- else {
177
- val selOffset = sel.pos.endColumn - sel.qualifier.pos.endColumn - sel.name.length
178
- (sel.qualifier.pos.endColumn + selOffset - rootPosition.startColumn).toExpr
179
- }
180
- }
181
-
182
- def getAnchor (expr : Expr [_])(implicit refl : Reflection ): Expr [Int ] = {
183
- import refl ._
184
- // -1 to match scala2 position
185
- // ((expr.unseal.pos.endColumn + expr.unseal.pos.startColumn - 1) / 2 - rootPosition.startColumn).toExpr
186
- (expr.unseal.pos.startColumn - rootPosition.startColumn).toExpr
183
+ val diagExpr = parse(refl)(condition.unseal.underlyingArgument).seal.cast[DiagrammedExpr [Boolean ]]
184
+ ' { $helper($diagExpr, $clue, $ {sourceText.toExpr}, $pos) }
187
185
}
188
186
}
0 commit comments