2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 module gaem
.parser
.astools
is aliced
;
20 import gaem
.parser
.lexer
;
21 import gaem
.parser
.tokens
;
22 import gaem
.parser
.utils
;
23 import gaem
.parser
.ast
;
26 // ////////////////////////////////////////////////////////////////////////// //
27 enum VisitRes
{ Continue
, Stop
, SkipChildren
}
29 private final class NodeSkipChildren
: Node
{}
30 private __gshared NodeSkipChildren nnc
;
31 shared static this () { nnc
= new NodeSkipChildren(); }
34 Node
visitNodes (Node nn
, VisitRes
delegate (Node n
) dg
) {
35 if (nn
is null) return null;
36 if (auto r
= dg(nn
)) return (r
== VisitRes
.Stop ? nn
: null);
38 if (cast(NodeStatement
)nn
) {
39 res
= selectNode
!(Node
)(nn
,
40 (NodeVarDecl n
) => null,
42 foreach (Node st
; n
.stats
) if (auto r
= visitNodes(st
, dg
)) return r
;
45 (NodeStatementEmpty n
) => null,
46 (NodeStatementExpr n
) => visitNodes(n
.e
, dg
),
47 (NodeReturn n
) => visitNodes(n
.e
, dg
),
49 if (auto r
= visitNodes(n
.e
, dg
)) return r
;
50 return visitNodes(n
.ebody
, dg
);
53 if (auto r
= visitNodes(n
.ec
, dg
)) return r
;
54 if (auto r
= visitNodes(n
.et
, dg
)) return r
;
55 return visitNodes(n
.ef
, dg
);
57 (NodeStatementBreak n
) => null,
58 (NodeStatementContinue n
) => null,
60 if (auto r
= visitNodes(n
.einit
, dg
)) return r
;
61 if (auto r
= visitNodes(n
.econd
, dg
)) return r
;
62 if (auto r
= visitNodes(n
.enext
, dg
)) return r
;
63 return visitNodes(n
.ebody
, dg
);
66 if (auto r
= visitNodes(n
.econd
, dg
)) return r
;
67 return visitNodes(n
.ebody
, dg
);
70 if (auto r
= visitNodes(n
.econd
, dg
)) return r
;
71 return visitNodes(n
.ebody
, dg
);
74 if (auto r
= visitNodes(n
.ecount
, dg
)) return r
;
75 return visitNodes(n
.ebody
, dg
);
78 if (auto r
= visitNodes(n
.e
, dg
)) return r
;
79 foreach (ref ci
; n
.cases
) {
80 if (auto r
= visitNodes(ci
.e
, dg
)) return r
;
81 if (auto r
= visitNodes(ci
.st
, dg
)) return r
;
85 () { assert(0, "unimplemented node: "~typeid(nn
).name
); },
88 res
= selectNode
!(Node
)(nn
,
89 (NodeLiteral n
) => null,
90 (NodeUnary n
) => visitNodes(n
.e
, dg
),
92 if (auto r
= visitNodes(n
.el
, dg
)) return r
;
93 return visitNodes(n
.er
, dg
);
96 if (auto r
= visitNodes(n
.fe
, dg
)) return r
;
97 foreach (immutable idx
, Node a
; n
.args
) if (auto r
= visitNodes(a
, dg
)) return r
;
101 (NodeDot n
) => visitNodes(n
.e
, dg
),
103 if (auto r
= visitNodes(n
.ei0
, dg
)) return r
;
104 if (auto r
= visitNodes(n
.ei1
, dg
)) return r
;
105 return visitNodes(n
.e
, dg
);
107 (NodeFunc n
) => visitNodes(n
.ebody
, dg
),
108 () { assert(0, "unimplemented node: "~typeid(nn
).name
); },
111 if (res
is nnc
) res
= null;
116 // ////////////////////////////////////////////////////////////////////////// //
117 bool isEmpty (Node nn
) {
118 if (nn
is null) return true;
119 if (auto n
= cast(NodeFunc
)nn
) return isEmpty(n
.ebody
);
120 if (cast(NodeStatement
)nn
) {
121 if (cast(NodeStatementEmpty
)nn
) return true;
122 if (auto n
= cast(NodeBlock
)nn
) {
123 foreach (Node st
; n
.stats
) if (!isEmpty(st
)) return false;
131 // ////////////////////////////////////////////////////////////////////////// //
132 bool hasReturn (Node nn
) {
133 if (nn
is null) return false;
134 if (cast(NodeStatement
)nn
) {
135 return selectNode
!(bool)(nn
,
136 (NodeVarDecl n
) => false,
138 foreach (Node st
; n
.stats
) if (hasReturn(st
)) return true;
141 (NodeStatementEmpty n
) => false,
142 (NodeStatementExpr n
) => hasReturn(n
.e
),
143 (NodeReturn n
) => true,
144 (NodeWith n
) => (hasReturn(n
.e
) ||
hasReturn(n
.ebody
)),
145 (NodeIf n
) => (hasReturn(n
.ec
) ||
hasReturn(n
.et
) ||
hasReturn(n
.ef
)),
146 (NodeStatementBreak n
) => false,
147 (NodeStatementContinue n
) => false,
148 (NodeFor n
) => (hasReturn(n
.einit
) ||
hasReturn(n
.econd
) ||
hasReturn(n
.enext
) ||
hasReturn(n
.ebody
)),
149 (NodeWhile n
) => (hasReturn(n
.econd
) ||
hasReturn(n
.ebody
)),
150 (NodeDoUntil n
) => (hasReturn(n
.econd
) ||
hasReturn(n
.ebody
)),
151 (NodeRepeat n
) => (hasReturn(n
.ecount
) ||
hasReturn(n
.ebody
)),
153 if (hasReturn(n
.e
)) return true;
154 foreach (ref ci
; n
.cases
) if (hasReturn(ci
.e
) ||
hasReturn(ci
.st
)) return true;
157 () { assert(0, "unimplemented node: "~typeid(nn
).name
); },
160 return selectNode
!(bool)(nn
,
161 (NodeLiteral n
) => false,
162 (NodeUnary n
) => hasReturn(n
.e
),
163 (NodeBinary n
) => hasReturn(n
.el
) ||
hasReturn(n
.er
),
165 if (hasReturn(n
.fe
)) return true;
166 foreach (immutable idx
, Node a
; n
.args
) if (hasReturn(a
)) return true;
170 (NodeDot n
) => hasReturn(n
.e
),
171 (NodeIndex n
) => (hasReturn(n
.e
) ||
hasReturn(n
.ei0
) ||
hasReturn(n
.ei1
)),
172 (NodeFunc n
) => hasReturn(n
.ebody
),
173 () { assert(0, "unimplemented node: "~typeid(nn
).name
); },
179 // ////////////////////////////////////////////////////////////////////////// //
180 //x > view_xview[0]-16 && x < view_xview[0]+view_wview[0]+16 &&
181 //y > view_yview[0]-16 && y < view_yview[0]+view_hview[0]+16
187 void findFrozenChecks (ref Node
[] cn
, Node nn
) {
189 import std
.string
: replace
;
191 static bool isViewAccess (Node nn
, char what
) {
192 if (auto n
= cast(NodeIndex
)nn
) {
194 if (n
.ei1
!is null) return false;
196 if (auto id
= cast(NodeId
)n
.e
) {
197 if (id
.name
.length
!= 10) return false;
198 if (id
.name
.ptr
[5] != what
) return false;
199 if (id
.name
[0..5] != "view_") return false;
200 if (id
.name
[6..$] != "view") return false;
205 if (auto l
= cast(NodeLiteralNum
)n
.ei0
) {
206 if (l
.val
!= 0) return false;
215 static bool isXYStartExpr (Node nn
, char what
) {
216 if (auto n
= cast(NodeBinary
)nn
) {
217 if (!isViewAccess(n
.el
, what
)) return false;
218 if (cast(NodeBinaryAdd
)nn
is null && cast(NodeBinarySub
)nn
is null) return false;
219 if (cast(NodeLiteralNum
)n
.er
is null) return false;
221 } else if (isViewAccess(nn
, what
)) {
227 static bool isXYEndExpr (Node nn
, char what
) {
228 if (auto n
= cast(NodeBinary
)nn
) {
229 //TODO: check for "+"
230 if (isViewAccess(n
.el
, (what
== 'w' ?
'x' : 'y')) && isViewAccess(n
.er
, what
)) return true;
232 if (auto n
= cast(NodeBinaryAdd
)nn
) {
233 //writeln("x00(", what, "): ", nn.toString.replace("\n", " "), " : ", typeid(n.el).name);
234 //writeln("x01(", what, "): ", n.el.toString.replace("\n", " "), " : ", typeid(n.el).name);
235 if (cast(NodeBinaryAdd
)n
.el
is null && cast(NodeBinarySub
)n
.el
is null) return false;
236 //writeln("x02(", what, "): ", n.el.toString.replace("\n", " "), " : ", typeid(n.el).name);
237 auto x
= cast(NodeBinary
)n
.el
;
239 if (!isViewAccess(x
.el
, (what
== 'w' ?
'x' : 'y'))) return false;
240 //writeln("x03(", what, "): ", n.el.toString.replace("\n", " "), " : ", typeid(n.el).name);
241 if (!isViewAccess(x
.er
, what
)) return false;
242 //writeln("x04(", what, "): ", n.el.toString.replace("\n", " "), " : ", typeid(n.el).name);
248 static bool isCompare(alias exprcheck
) (Node nn
, char what
) {
249 if (auto n
= cast(NodeBinaryCmp
)nn
) {
250 if (auto id
= cast(NodeId
)n
.el
) {
251 if (id
.name
!= "x" && id
.name
!= "y") return false;
252 //writeln("cmp(", what, "): ", n.er.toString.replace("\n", " "));
253 return exprcheck(n
.er
, what
);
254 } else if (auto id
= cast(NodeId
)n
.er
) {
255 if (id
.name
!= "x" && id
.name
!= "y") return false;
256 return exprcheck(n
.el
, what
);
262 static bool isFrozenExpr3 (Node nn
) {
263 if (auto a3
= cast(NodeBinaryLogAnd
)nn
) {
264 //writeln("fe3: ", nn.toString.replace("\n", " "));
265 //writeln("fe3.l: ", a3.el.toString.replace("\n", " "));
266 //writeln("fe3.r: ", a3.er.toString.replace("\n", " "));
267 //writeln(" : ", isCompare!isXYStartExpr(a3.el, 'x'));
268 //writeln(" : ", isCompare!isXYEndExpr(a3.er, 'w'));
270 isCompare
!isXYStartExpr(a3
.el
, 'x') &&
271 isCompare
!isXYEndExpr(a3
.er
, 'w');
276 static bool isFrozenExpr2 (Node nn
) {
277 if (auto a2
= cast(NodeBinaryLogAnd
)nn
) {
278 //writeln("fe2: ", nn.toString.replace("\n", " "));
279 //writeln("fe2.l: ", a2.el.toString.replace("\n", " "));
280 //writeln("fe2.r: ", a2.er.toString.replace("\n", " "));
281 //writeln(" : ", isCompare!isXYStartExpr(a2.er, 'y'));
283 isFrozenExpr3(a2
.el
) &&
284 isCompare
!isXYStartExpr(a2
.er
, 'y');
289 static bool isFrozenExpr1 (Node nn
) {
290 if (auto a1
= cast(NodeBinaryLogAnd
)nn
) {
291 //writeln("fe1: ", nn.toString.replace("\n", " "));
292 //writeln("fe1.l: ", a1.el.toString.replace("\n", " "));
293 //writeln("fe1.r: ", a1.er.toString.replace("\n", " "));
294 //writeln(" : ", isCompare!isXYEndExpr(a1.er, 'y'));
296 isFrozenExpr2(a1
.el
) &&
297 isCompare
!isXYEndExpr(a1
.er
, 'h');
302 bool isFrozenExpr (Node nn
) {
303 auto res
= visitNodes(nn
, (n
) {
304 if (isFrozenExpr1(n
)) return VisitRes
.Stop
;
305 if (auto id
= cast(NodeId
)n
) {
306 if (id
.name
== "isNotFrozen") return VisitRes
.Stop
;
308 return VisitRes
.Continue
;
310 return (res
!is null);
313 visitNodes(nn
, (nn
) {
314 if (auto n
= cast(NodeIf
)nn
) {
315 if (isFrozenExpr(n
.ec
)) cn
~= n
;
317 return VisitRes
.Continue
;