/src/org/ooc/frontend/model/ArrayAccess.java

http://github.com/nddrylliog/ooc · Java · 260 lines · 212 code · 48 blank · 0 comment · 63 complexity · 4213a41cdb7e583881fa8a0b40810dfe MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import org.ooc.frontend.Visitor;
  4. import org.ooc.frontend.model.OpDecl.OpType;
  5. import org.ooc.frontend.model.interfaces.MustBeResolved;
  6. import org.ooc.frontend.model.tokens.Token;
  7. import org.ooc.middle.OocCompilationError;
  8. import org.ooc.middle.hobgoblins.Resolver;
  9. public class ArrayAccess extends Access implements MustBeResolved {
  10. Type type;
  11. protected Expression variable;
  12. protected NodeList<Expression> indices;
  13. public ArrayAccess(Expression variable, Token startToken) {
  14. super(startToken);
  15. this.variable = variable;
  16. this.indices = new NodeList<Expression>(startToken);
  17. }
  18. @Override
  19. public Expression getGenericOperand() {
  20. if(getType().isGeneric() && getType().getPointerLevel() == 0) {
  21. MemberAccess sizeAcc = new MemberAccess(new VariableAccess(getType().getName(), startToken), "size", startToken);
  22. ArrayAccess arrAcc = new ArrayAccess(variable, startToken);
  23. arrAcc.indices.add(new Mul(indices.get(0), sizeAcc, arrAcc.startToken));
  24. return new AddressOf(arrAcc, arrAcc.startToken);
  25. }
  26. return super.getGenericOperand();
  27. }
  28. public Expression getVariable() {
  29. return variable;
  30. }
  31. public void setVariable(Expression variable) {
  32. this.variable = variable;
  33. }
  34. public NodeList<Expression> getIndices() {
  35. return indices;
  36. }
  37. public Type getType() {
  38. if(type == null) {
  39. Type exprType = variable.getType();
  40. if(exprType != null) {
  41. Declaration ref = exprType.getRef();
  42. if(ref instanceof CoverDecl) {
  43. Type fromType = ((CoverDecl) ref).getFromType();
  44. if(fromType != null && fromType.getRef() instanceof CoverDecl) {
  45. Type clone = fromType.clone();
  46. clone.setPointerLevel(exprType.getPointerLevel() + fromType.getPointerLevel());
  47. exprType = clone;
  48. }
  49. }
  50. type = new Type(exprType.getName(), exprType.getPointerLevel() - 1, exprType.startToken);
  51. type.setRef(exprType.getRef());
  52. }
  53. }
  54. return type;
  55. }
  56. public void accept(Visitor visitor) throws IOException {
  57. visitor.visit(this);
  58. }
  59. public boolean hasChildren() {
  60. return true;
  61. }
  62. public void acceptChildren(Visitor visitor) throws IOException {
  63. variable.accept(visitor);
  64. indices.accept(visitor);
  65. }
  66. @SuppressWarnings("unchecked")
  67. @Override
  68. public boolean replace(Node oldie, Node kiddo) {
  69. if(oldie == variable) {
  70. variable = (Expression) kiddo;
  71. return true;
  72. }
  73. if(oldie == indices) {
  74. indices = (NodeList<Expression>) kiddo;
  75. return true;
  76. }
  77. return false;
  78. }
  79. public boolean isResolved() {
  80. return false;
  81. }
  82. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  83. int assignIndex = -1;
  84. if(stack.peek() instanceof Assignment) {
  85. Assignment ass = (Assignment) stack.peek();
  86. if(ass.getLeft() == this) {
  87. assignIndex = stack.size() - 1;
  88. } else {
  89. NodeList<Node> copy = new NodeList<Node>();
  90. copy.addAll(stack);
  91. copy.pop();
  92. Response response = ass.resolve(copy, res, fatal);
  93. if(response != Response.OK) {
  94. return response;
  95. }
  96. }
  97. }
  98. OpDecl bestOp = null;
  99. int bestScore = 0;
  100. try {
  101. for(OpDecl op: res.module.getOps()) {
  102. int score = getOpScore(stack, res, assignIndex, op);
  103. if(bestScore < score) {
  104. bestOp = op;
  105. bestScore = score;
  106. }
  107. }
  108. for(Import imp: res.module.getAllImports()) {
  109. for(OpDecl op: imp.getModule().getOps()) {
  110. int score = getOpScore(stack, res, assignIndex, op);
  111. if(bestScore < score) {
  112. bestOp = op;
  113. bestScore = score;
  114. }
  115. }
  116. }
  117. } catch(OocCompilationError ex) {
  118. if(fatal) {
  119. throw ex;
  120. }
  121. return Response.LOOP;
  122. }
  123. if(bestOp != null) {
  124. NodeList<Argument> args = bestOp.getFunc().getArguments();
  125. FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
  126. Argument arg = args.getFirst();
  127. if(arg.getType().getReferenceLevel() == variable.getType().getReferenceLevel() + 1) {
  128. variable = new AddressOf(variable, startToken);
  129. }
  130. call.getArguments().add(variable);
  131. call.getArguments().addAll(indices);
  132. if(assignIndex != -1) {
  133. Assignment ass = (Assignment)stack.get(assignIndex);
  134. call.getArguments().add(ass.getRight());
  135. if(!stack.get(assignIndex - 1).replace(ass, call)) {
  136. System.out.println("stack = "+stack.toString(true));
  137. Thread.dumpStack();
  138. throw new OocCompilationError(this, stack, "Couldn't replace array-access-assign with a function call");
  139. }
  140. } else {
  141. stack.peek().replace(this, call);
  142. }
  143. return Response.LOOP;
  144. }
  145. return Response.OK;
  146. }
  147. private int getOpScore(NodeList<Node> stack, Resolver res, int assignIndex, OpDecl op) throws OocCompilationError {
  148. int score = 0;
  149. OpType opType = assignIndex == -1 ? OpType.IDX : OpType.IDX_ASS;
  150. int numArgs = 1 + indices.size() + (opType == OpType.IDX ? 0 : 1);
  151. NodeList<Argument> args = op.getFunc().getArguments();
  152. if(op.getOpType() != opType || args.size() != numArgs) {
  153. return 0;
  154. }
  155. Argument first = args.getFirst();
  156. if(first.getType().softEquals(variable.getType(), res)) {
  157. if(opType == OpType.IDX && args.size() < 2) {
  158. throw new OocCompilationError(op, stack,
  159. "To overload the indexing operator, you need at least two arguments, not "
  160. +op.getFunc().getArgsRepr());
  161. } else if(opType == OpType.IDX_ASS && args.size() < 3) {
  162. throw new OocCompilationError(op, stack,
  163. "To overload the indexed assign operator, you need exactly three arguments, not "
  164. +op.getFunc().getArgsRepr());
  165. }
  166. score += 10;
  167. if(first.getType().equals(variable.getType())) {
  168. score += 20;
  169. }
  170. if(variable.getType().getReferenceLevel() == first.getType().getReferenceLevel() + 1) {
  171. score += 10;
  172. }
  173. for(int idx = 0; idx < indices.size(); ++idx) {
  174. Expression exp = indices.get(idx);
  175. Argument arg = args.get(idx+1);
  176. if(exp.getType() == null) {
  177. throw new OocCompilationError(exp, stack,
  178. "Unable to determine the type of the expression being used as an index");
  179. }
  180. if(exp.getType().softEquals(arg.getType(), res)) {
  181. score += 10;
  182. if(exp.getType().equals(arg.getType())) {
  183. score += 10;
  184. }
  185. }
  186. }
  187. if(assignIndex != -1) {
  188. Argument last = args.getLast();
  189. Assignment ass = (Assignment)stack.get(assignIndex);
  190. if (ass.getRight().getType() == null) {
  191. throw new OocCompilationError(ass.getRight(), stack,
  192. "Unable to determine the type of the expression being assigned");
  193. }
  194. if(ass.getRight().getType().softEquals(last.getType(), res)) {
  195. score += 10;
  196. if(ass.getRight().getType().equals(last.getType())) {
  197. score += 20;
  198. }
  199. }
  200. }
  201. }
  202. return score;
  203. }
  204. @Override
  205. public String toString() {
  206. return variable.toString() + indices;
  207. }
  208. @Override
  209. public boolean canBeReferenced() {
  210. return true;
  211. }
  212. }