PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/org/charter_project/graph/compile/statement/ForEach.java

https://bitbucket.org/aicas/rdt
Java | 557 lines | 428 code | 52 blank | 77 comment | 35 complexity | 8c00b1d0b180ee415cfec440dd2bc447 MD5 | raw file
  1. package org.charter_project.graph.compile.statement;
  2. import org.charter_project.graph.client.ExpressionType;
  3. import org.charter_project.graph.client.GenerateException;
  4. import org.charter_project.graph.compile.Code.FailCode;
  5. import org.charter_project.graph.compile.LoopCode;
  6. import org.charter_project.graph.compile.Parsed;
  7. import org.charter_project.graph.compile.RuleFile;
  8. import org.charter_project.graph.compile.block.Block;
  9. import org.charter_project.graph.compile.block.Block.BlockType;
  10. import org.charter_project.graph.compile.expression.Cast;
  11. import org.charter_project.graph.compile.expression.Expression;
  12. import org.charter_project.graph.compile.expression.GetSize;
  13. import org.charter_project.graph.compile.expression.Literal;
  14. import org.charter_project.graph.compile.expression.SelectMField;
  15. import org.charter_project.graph.compile.expression.Var;
  16. import org.charter_project.graph.parse.MyTree;
  17. /**
  18. * A <code>ForEach</code> represents the 'foreach' alternative of a
  19. * {@link Statement}.
  20. *
  21. * @author Maarten de Mol
  22. * @version 1.0
  23. */
  24. public class ForEach extends Statement implements AssignRHS
  25. {
  26. // The for variable.
  27. private final Var loopVar;
  28. // The collection expression. May be null.
  29. private final Expression coll;
  30. // The body.
  31. private final Block body;
  32. // The collects expression. May be null.
  33. private final Expression collects;
  34. // Additional flag to disable initial comment line.
  35. private boolean disableComment = false;
  36. /** Constructor for expressions provided by ANTLR. */
  37. public ForEach(MyTree tree, Var loopVar, Expression coll, Block body,
  38. Expression collects)
  39. {
  40. super(tree);
  41. this.loopVar = loopVar;
  42. this.coll = coll;
  43. this.body = body;
  44. this.collects = collects;
  45. }
  46. /** Constructor for custom expressions, created during code generation. */
  47. public ForEach(Parsed source, Var loopVar, Expression coll, Block body,
  48. Expression collects)
  49. {
  50. super(source);
  51. this.loopVar = loopVar;
  52. this.coll = coll;
  53. this.body = body;
  54. this.collects = collects;
  55. }
  56. /** Getter for the loop variable. */
  57. public Var getLoopVar()
  58. {
  59. return this.loopVar;
  60. }
  61. /** Getter for the collection expression. */
  62. public Expression getCollection()
  63. {
  64. return this.coll;
  65. }
  66. /** Getter for the body. */
  67. public Block getBody()
  68. {
  69. return this.body;
  70. }
  71. /** Getter for the return expression. */
  72. public Expression getCollects()
  73. {
  74. return this.collects;
  75. }
  76. /** Setter for the disable comment flag. */
  77. public void disableComment()
  78. {
  79. this.disableComment = true;
  80. }
  81. @Override
  82. public ExpressionType getType()
  83. {
  84. return this.collects.getType();
  85. }
  86. @Override
  87. public void show(Indented builder)
  88. {
  89. builder.write("foreach (");
  90. builder.write(this.loopVar.getType().toString());
  91. builder.write(" ");
  92. builder.write(this.loopVar.getName());
  93. if (this.coll != null)
  94. {
  95. builder.write(" : ");
  96. builder.write(this.coll.show(false));
  97. }
  98. builder.write(") ");
  99. builder.write("{");
  100. builder.incIndent();
  101. builder.newline();
  102. this.body.show(builder, false);
  103. if (this.collects != null)
  104. {
  105. builder.newline();
  106. builder.write("return ");
  107. builder.write(this.collects.show(false));
  108. builder.write(";");
  109. }
  110. builder.decIndent();
  111. builder.newline();
  112. builder.write("}");
  113. }
  114. // ========================================================================
  115. // LOOP CODE
  116. // ========================================================================
  117. /** Generates the {@link LoopCode} for this foreach statement. */
  118. public LoopCode generateLoopCode(RuleFile file)
  119. {
  120. if (this.coll == null)
  121. {
  122. return new LoopAllCode();
  123. }
  124. else if (this.coll instanceof SelectMField &&
  125. file.inBlockType() != BlockType.SEQUENCE)
  126. {
  127. SelectMField select = (SelectMField) this.coll;
  128. return new LoopFieldCode(select);
  129. }
  130. else if (this.coll instanceof GetSize)
  131. {
  132. GetSize getSize = (GetSize) this.coll;
  133. return new LoopIndexCode(getSize);
  134. }
  135. else
  136. {
  137. return new MyLoopCode();
  138. }
  139. }
  140. /**
  141. * Helper method for printing a comment for the 'collects' expression at the
  142. * end of the loop body.
  143. */
  144. private static void writeCollectsComment(Expression collects, RuleFile file)
  145. throws GenerateException
  146. {
  147. if (collects != null)
  148. {
  149. file.newline();
  150. file.write("// collect ");
  151. file.write(collects.show(false));
  152. file.newline();
  153. }
  154. }
  155. /**
  156. * Helper class for writing loop case, for the case that no collection
  157. * expression was provided.
  158. */
  159. private class LoopAllCode implements LoopCode
  160. {
  161. // Loop code for the bare node visitor.
  162. private NodeVisitCode baseLoop;
  163. @Override
  164. public void writeOpen(FailCode fail, RuleFile file)
  165. throws GenerateException
  166. {
  167. this.baseLoop =
  168. new NodeVisitCode(ForEach.this, ForEach.this.loopVar.getType()
  169. .getNode());
  170. if (ForEach.this.collects == null && !ForEach.this.disableComment)
  171. {
  172. generateComment(file);
  173. }
  174. this.baseLoop.writeOpen(fail, file);
  175. ForEach.this.loopVar.writeAssignCode(this.baseLoop.getValue(), file);
  176. ForEach.this.body.write(FailCode.VISITOR_FAIL, file);
  177. writeCollectsComment(ForEach.this.collects, file);
  178. }
  179. @Override
  180. public void writeClose(boolean ruleCall, boolean endReachable,
  181. FailCode fail, RuleFile file)
  182. throws GenerateException
  183. {
  184. this.baseLoop.writeClose(ruleCall || ForEach.this.body.hasRuleCall(),
  185. endReachable, fail, file);
  186. }
  187. @Override
  188. public void writeContinue(RuleFile file)
  189. throws GenerateException
  190. {
  191. this.baseLoop.writeContinue(file);
  192. }
  193. @Override
  194. public void writeBreak(RuleFile file)
  195. throws GenerateException
  196. {
  197. this.baseLoop.writeBreak(file);
  198. }
  199. @Override
  200. public Expression getValue()
  201. {
  202. return ForEach.this.collects;
  203. }
  204. }
  205. /**
  206. * Helper class for writing loop case, for the case that the collection
  207. * expression is a field selection.
  208. */
  209. private class LoopFieldCode implements LoopCode
  210. {
  211. // The select expression, and its generated loop code.
  212. private final SelectMField select;
  213. private LoopCode loop;
  214. /** Default constructor. */
  215. public LoopFieldCode(SelectMField select)
  216. {
  217. this.select = select;
  218. }
  219. @Override
  220. public void writeOpen(FailCode fail, RuleFile file)
  221. throws GenerateException
  222. {
  223. // Comment
  224. if (ForEach.this.collects == null && !ForEach.this.disableComment)
  225. {
  226. generateComment(file);
  227. }
  228. // Create index variable, if necessary.
  229. Var index = null;
  230. if (file.getRule().getVarsWithIndex()
  231. .contains(ForEach.this.loopVar.getName()) &&
  232. select.getType().isList())
  233. {
  234. index = file.generateClassVar(ForEach.this, ExpressionType.INT);
  235. index.writeAssignCode(Literal.MINUS_ONE(ForEach.this).getCode(),
  236. file);
  237. file.getIndexVarMap().put(ForEach.this.loopVar.getName(), index);
  238. }
  239. // Open visitor.
  240. this.loop = select.generateLoopCode();
  241. this.loop.writeOpen(fail, file);
  242. // Body statements (assign loopVar)
  243. this.loop.getValue().writeHelperCode(fail, file);
  244. if (!ForEach.this.loopVar.getType().equals(this.loop.getValue()
  245. .getType()))
  246. {
  247. // type cast before assign
  248. file.write("if (!(");
  249. this.loop.getValue().getCode().write(true, file);
  250. file.write(" instanceof ");
  251. file.write(ForEach.this.loopVar.getType());
  252. file.write(")) ");
  253. file.openBlock();
  254. this.loop.writeContinue(file);
  255. file.closeBlock();
  256. Cast cast =
  257. new Cast(ForEach.this, false, ForEach.this.loopVar.getType(),
  258. this.loop.getValue());
  259. cast.writeHelperCode(FailCode.EMPTY, file);
  260. ForEach.this.loopVar.writeAssignCode(cast.getCode(), file);
  261. }
  262. else
  263. {
  264. // assign as is
  265. ForEach.this.loopVar
  266. .writeAssignCode(this.loop.getValue().getCode(), file);
  267. }
  268. // Body statements (increase indexVar).
  269. if (index != null)
  270. {
  271. file.write(index);
  272. file.write("++;");
  273. file.newline();
  274. }
  275. // Body statements (for body, collects)
  276. ForEach.this.body.write(FailCode.VISITOR_FAIL, file);
  277. writeCollectsComment(ForEach.this.collects, file);
  278. }
  279. @Override
  280. public void writeClose(boolean ruleCall, boolean endReachable,
  281. FailCode fail, RuleFile file)
  282. throws GenerateException
  283. {
  284. this.loop.writeClose(ruleCall || ForEach.this.body.hasRuleCall(),
  285. endReachable, fail, file);
  286. }
  287. @Override
  288. public void writeContinue(RuleFile file)
  289. throws GenerateException
  290. {
  291. this.loop.writeContinue(file);
  292. }
  293. @Override
  294. public void writeBreak(RuleFile file)
  295. throws GenerateException
  296. {
  297. this.loop.writeBreak(file);
  298. }
  299. @Override
  300. public Expression getValue()
  301. {
  302. return ForEach.this.collects;
  303. }
  304. }
  305. /**
  306. * Helper class for writing loop case, for the case that the collection
  307. * expression is a getSize operation. This alternative cannot be reached
  308. * directly, and is only supported for the 'restrict to indexOf' alternative
  309. * in a match block.
  310. */
  311. private class LoopIndexCode implements LoopCode
  312. {
  313. // The getSize expression.
  314. private final GetSize getSize;
  315. // The label of the generated for loop.
  316. private String label;
  317. /** Default constructor. */
  318. public LoopIndexCode(GetSize getSize)
  319. {
  320. this.getSize = getSize;
  321. }
  322. @Override
  323. public void writeOpen(FailCode fail, RuleFile file)
  324. throws GenerateException
  325. {
  326. // Comment
  327. if (ForEach.this.collects == null && !ForEach.this.disableComment)
  328. {
  329. generateComment(file);
  330. }
  331. // Variables.
  332. Var tempVar =
  333. file.generateLocalVar(ForEach.this, ForEach.this.loopVar.getType());
  334. this.getSize.writeHelperCode(fail, file);
  335. // Open for loop.
  336. this.label = file.freshLabel();
  337. file.write(label);
  338. file.write(": for (int ");
  339. file.write(tempVar);
  340. file.write("= 0; ");
  341. file.write(tempVar);
  342. file.write(" < ");
  343. this.getSize.getCode().write(true, file);
  344. file.write("; ");
  345. file.write(tempVar);
  346. file.write("++) ");
  347. file.openBlock();
  348. // Body statements.
  349. ForEach.this.loopVar.writeAssignCode(tempVar, file);
  350. ForEach.this.body.write(FailCode.VISITOR_FAIL, file);
  351. writeCollectsComment(ForEach.this.collects, file);
  352. }
  353. @Override
  354. public void writeClose(boolean ruleCall, boolean endReachable,
  355. FailCode fail, RuleFile file)
  356. throws GenerateException
  357. {
  358. file.closeBlock();
  359. }
  360. @Override
  361. public void writeContinue(RuleFile file)
  362. throws GenerateException
  363. {
  364. file.write("continue ");
  365. file.write(this.label);
  366. file.write(";");
  367. file.newline();
  368. }
  369. @Override
  370. public void writeBreak(RuleFile file)
  371. throws GenerateException
  372. {
  373. file.write("break ");
  374. file.write(this.label);
  375. file.write(";");
  376. file.newline();
  377. }
  378. @Override
  379. public Expression getValue()
  380. {
  381. return ForEach.this.collects;
  382. }
  383. }
  384. /**
  385. * Helper class for writing loop case, for the case that the collection
  386. * expression cannot be decomposed.
  387. */
  388. private class MyLoopCode implements LoopCode
  389. {
  390. // Label of the for loop.
  391. private String label;
  392. @Override
  393. public void writeOpen(FailCode fail, RuleFile file)
  394. throws GenerateException
  395. {
  396. // Comment
  397. if (ForEach.this.collects == null && !ForEach.this.disableComment)
  398. {
  399. generateComment(file);
  400. }
  401. // Variables.
  402. Var tempVar =
  403. file.generateLocalVar(ForEach.this, ForEach.this.coll.getType()
  404. .getElement());
  405. // Helper code.
  406. ForEach.this.coll.writeHelperCode(fail, file);
  407. // Create index variable, if necessary.
  408. Var index = null;
  409. if (file.getRule().getVarsWithIndex()
  410. .contains(ForEach.this.loopVar.getName()) &&
  411. ForEach.this.coll.getType().isList())
  412. {
  413. index = file.generateClassVar(ForEach.this, ExpressionType.INT);
  414. index.writeAssignCode(Literal.MINUS_ONE(ForEach.this).getCode(),
  415. file);
  416. file.getIndexVarMap().put(ForEach.this.loopVar.getName(), index);
  417. }
  418. // Open for loop
  419. this.label = file.freshLabel();
  420. file.write(label);
  421. file.write(": for (");
  422. file.write(tempVar.getType());
  423. file.write(" ");
  424. file.write(tempVar.getName());
  425. file.write(" : ");
  426. ForEach.this.coll.getCode().write(false, file);
  427. file.write(") ");
  428. file.openBlock();
  429. // Body statements (assign loopVar)
  430. if (!ForEach.this.loopVar.getType().equals(tempVar.getType()))
  431. {
  432. // type cast before assign
  433. file.write("if (!(");
  434. file.write(tempVar);
  435. file.write(" instanceof ");
  436. file.write(ForEach.this.loopVar.getType());
  437. file.write(")) ");
  438. file.openBlock();
  439. writeContinue(file);
  440. file.closeBlock();
  441. Cast cast =
  442. new Cast(ForEach.this, false, ForEach.this.loopVar.getType(),
  443. tempVar);
  444. cast.writeHelperCode(FailCode.EMPTY, file);
  445. ForEach.this.loopVar.writeAssignCode(cast.getCode(), file);
  446. }
  447. else
  448. {
  449. ForEach.this.loopVar.writeAssignCode(tempVar, file);
  450. }
  451. // Body statements (increase indexVar).
  452. if (index != null)
  453. {
  454. file.write(index);
  455. file.write("++;");
  456. file.newline();
  457. }
  458. // Body statements (for body, collects)
  459. ForEach.this.body.write(fail, file);
  460. writeCollectsComment(ForEach.this.collects, file);
  461. }
  462. @Override
  463. public void writeClose(boolean ruleCall, boolean endReachable,
  464. FailCode fail, RuleFile file)
  465. throws GenerateException
  466. {
  467. file.closeBlock();
  468. }
  469. @Override
  470. public void writeContinue(RuleFile file)
  471. throws GenerateException
  472. {
  473. file.write("continue ");
  474. file.write(this.label);
  475. file.write(";");
  476. file.newline();
  477. }
  478. @Override
  479. public void writeBreak(RuleFile file)
  480. throws GenerateException
  481. {
  482. file.write("break ");
  483. file.write(this.label);
  484. file.write(";");
  485. file.newline();
  486. }
  487. @Override
  488. public Expression getValue()
  489. {
  490. return ForEach.this.collects;
  491. }
  492. }
  493. // ========================================================================
  494. // CODE GENERATION
  495. // ========================================================================
  496. @Override
  497. public void write(FailCode fail, RuleFile file)
  498. throws GenerateException
  499. {
  500. LoopCode loop = generateLoopCode(file);
  501. loop.writeOpen(fail, file);
  502. // collects is not supported in this mode
  503. loop.writeClose(false, true, fail, file);
  504. }
  505. }