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

http://github.com/nddrylliog/ooc · Java · 307 lines · 247 code · 55 blank · 5 comment · 59 complexity · cbc7ee8c3ddada27115bf082a86c433b MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import java.util.LinkedHashMap;
  4. import org.ooc.frontend.Visitor;
  5. import org.ooc.frontend.model.OpDecl.OpType;
  6. import org.ooc.frontend.model.interfaces.MustBeResolved;
  7. import org.ooc.frontend.model.tokens.Token;
  8. import org.ooc.middle.OocCompilationError;
  9. import org.ooc.middle.hobgoblins.Resolver;
  10. public class Cast extends Expression implements MustBeResolved {
  11. static enum CastMode {
  12. REGULAR,
  13. ARRAY, // for array literals
  14. MAP, // for map literal
  15. }
  16. protected Expression inner;
  17. protected Type type;
  18. public Cast(Expression expression, Type targetType, Token startToken) {
  19. super(startToken);
  20. this.inner = expression;
  21. setType(targetType);
  22. }
  23. @Override
  24. public Expression getGenericOperand() {
  25. // FIXME: hmm not really correct but fixes more thing than it breaks atm.
  26. return inner.getGenericOperand();
  27. }
  28. @Override
  29. public boolean replace(Node oldie, Node kiddo) {
  30. if(oldie == inner) {
  31. inner = (Expression) kiddo;
  32. return true;
  33. }
  34. if(oldie == type) {
  35. type = (Type) kiddo;
  36. return true;
  37. }
  38. return false;
  39. }
  40. public Type getType() {
  41. return type;
  42. }
  43. public void accept(Visitor visitor) throws IOException {
  44. visitor.visit(this);
  45. }
  46. public void acceptChildren(Visitor visitor) throws IOException {
  47. type.accept(visitor);
  48. inner.accept(visitor);
  49. }
  50. public boolean hasChildren() {
  51. return true;
  52. }
  53. @Override
  54. public Expression getInner() {
  55. return inner;
  56. }
  57. public void setInner(Expression expression) {
  58. this.inner = expression;
  59. }
  60. public void setType(Type newType) {
  61. this.type = newType;
  62. }
  63. @Override
  64. public String toString() {
  65. return "["+inner+" as "+type+"]";
  66. }
  67. @Override
  68. public boolean canBeReferenced() {
  69. return inner.canBeReferenced();
  70. }
  71. public boolean isResolved() {
  72. return false;
  73. }
  74. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  75. Response response;
  76. Expression realExpr = inner.bitchJumpCasts();
  77. if(realExpr.getType() == null) {
  78. if(fatal) {
  79. throw new OocCompilationError(this, stack, "Couldn't resolve type of expression in a cast");
  80. }
  81. return Response.LOOP;
  82. }
  83. //if(realExpr instanceof ArrayLiteral) {
  84. if(realExpr.getType().getPointerLevel() > 0) {
  85. response = tryArrayOverload(stack, res, fatal);
  86. if(response != Response.OK) return response;
  87. }
  88. response = tryRegularOverload(stack, res, fatal);
  89. if(response != Response.OK) return response;
  90. return Response.OK;
  91. }
  92. private Response tryRegularOverload(NodeList<Node> stack, Resolver res, boolean fatal) {
  93. Type leftType = inner.getType();
  94. Type rightType = getType();
  95. if(!leftType.isResolved() || !rightType.isResolved()) {
  96. //System.out.println("Bitch-looping because either "+leftType+" or "+rightType+" isn't resolved");
  97. return Response.LOOP;
  98. }
  99. OpDecl bestOp = null;
  100. int bestScore = 0;
  101. for(OpDecl op: res.module.getOps()) {
  102. int score = getRegularOpScore(stack, OpType.AS, op, res, leftType, rightType);
  103. if(score > bestScore) {
  104. bestScore = score;
  105. bestOp = op;
  106. }
  107. }
  108. for(Import imp: res.module.getAllImports()) { // TODO: really all imports?
  109. for(OpDecl op: imp.getModule().getOps()) {
  110. int score = getRegularOpScore(stack, OpType.AS, op, res, leftType, rightType);
  111. if(score > bestScore) {
  112. bestScore = score;
  113. bestOp = op;
  114. }
  115. }
  116. }
  117. if(bestOp != null) {
  118. FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
  119. call.getArguments().add(inner);
  120. Node parent = stack.peek();
  121. parent.replace(this, call);
  122. call.resolve(stack, res, true);
  123. return Response.LOOP;
  124. }
  125. return Response.OK;
  126. }
  127. private int getRegularOpScore(NodeList<Node> stack, OpType opType, OpDecl op, Resolver res, Type leftType, Type rightType) {
  128. int score = 0;
  129. if(op.getOpType() == opType) {
  130. NodeList<Argument> args = op.getFunc().getArguments();
  131. if(args.size() == 2) return score; // not for us
  132. if(args.size() != 1) {
  133. throw new OocCompilationError(op, stack,
  134. "To overload the "+opType.toPrettyString()+" operator, you need exactly one arguments, not "
  135. +op.getFunc().getArgsRepr());
  136. }
  137. Type firstType = args.get(0).getType();
  138. Type secondType = op.getFunc().getReturnType();
  139. if(firstType.softEquals(leftType, res)) {
  140. if(secondType.softEquals(rightType, res) || isGeneric(secondType, op.getFunc().getTypeParams())) {
  141. score += 10;
  142. if(firstType.equals(leftType)) {
  143. score += 20;
  144. }
  145. if(secondType.equals(rightType)) {
  146. score += 20;
  147. }
  148. }
  149. }
  150. }
  151. return score;
  152. }
  153. private Response tryArrayOverload(NodeList<Node> stack, Resolver res, boolean fatal) {
  154. Type leftType = inner.getType();
  155. Type rightType = getType();
  156. if(!leftType.isResolved() || !rightType.isResolved()) {
  157. //System.out.println("Bitch-looping because either "+leftType+" or "+rightType+" isn't resolved");
  158. return Response.LOOP;
  159. }
  160. OpDecl bestOp = null;
  161. int bestScore = 0;
  162. for(OpDecl op: res.module.getOps()) {
  163. int score = getArrayOpScore(stack, OpType.AS, op, res, leftType, rightType);
  164. if(score > bestScore) {
  165. bestScore = score;
  166. bestOp = op;
  167. }
  168. }
  169. for(Import imp: res.module.getAllImports()) { // TODO: all imports?
  170. for(OpDecl op: imp.getModule().getOps()) {
  171. int score = getArrayOpScore(stack, OpType.AS, op, res, leftType, rightType);
  172. if(score > bestScore) {
  173. bestScore = score;
  174. bestOp = op;
  175. }
  176. }
  177. }
  178. if(bestOp != null) {
  179. Type innerType = inner.getType().dereference();
  180. int numElements = -1;
  181. if(inner instanceof VariableAccess) {
  182. inner = ((VariableAccess) inner).getRef();
  183. if(inner instanceof VariableDecl) {
  184. // TODO: this code looks suspicious.
  185. VariableDecl vdfe = (VariableDecl) inner;
  186. inner = vdfe.getExpression();
  187. }
  188. }
  189. if(inner instanceof ArrayLiteral) {
  190. ArrayLiteral lit = (ArrayLiteral) inner;
  191. if(lit.getInnerType() == null) {
  192. if(fatal) {
  193. throw new OocCompilationError(lit, stack,
  194. "Couldn't resolve inner type of ArrayLiteral, can't correctly call the overloaded cast!");
  195. }
  196. return Response.LOOP;
  197. }
  198. numElements = lit.getElements().size();
  199. } else {
  200. throw new OocCompilationError(inner, stack, "Trying to array-cast to " + getType()
  201. + " an array of which we don't know the size! Try a constructor instead, passing the" +
  202. " size explicitly as an argument.");
  203. }
  204. FunctionCall call = new FunctionCall(bestOp.getFunc(), startToken);
  205. call.getArguments().add(inner);
  206. call.getArguments().add(new IntLiteral(numElements, IntLiteral.Format.DEC, inner.startToken));
  207. TypeAccess typeAccess = new TypeAccess(innerType, inner.startToken);
  208. call.getTypeParams().add(typeAccess);
  209. typeAccess.resolve(stack, res, true);
  210. Node parent = stack.peek();
  211. parent.replace(this, call);
  212. Response resp2 = Response.RESTART;
  213. while(resp2 == Response.RESTART) {
  214. resp2 = call.resolve(stack, res, true);
  215. }
  216. return Response.LOOP;
  217. }
  218. return Response.OK;
  219. }
  220. private int getArrayOpScore(NodeList<Node> stack, OpType opType, OpDecl op, Resolver res, Type leftType, Type rightType) {
  221. int score = 0;
  222. if(op.getOpType() == opType) {
  223. NodeList<Argument> args = op.getFunc().getArguments();
  224. if(args.size() == 1) return score; // not for us
  225. if(args.size() > 2 || args.size() < 1) {
  226. throw new OocCompilationError(op, stack,
  227. "To overload the "+opType.toPrettyString()+" operator from arrays, you need exactly two arguments (T* and size), not "
  228. +op.getFunc().getArgsRepr());
  229. }
  230. Type firstType = args.get(0).getType();
  231. Type secondType = op.getFunc().getReturnType();
  232. if(secondType.softEquals(rightType, res) || isGeneric(secondType, op.getFunc().getTypeParams())) {
  233. score += 10;
  234. if(firstType.equals(leftType)) {
  235. score += 20;
  236. }
  237. if(secondType.equals(rightType)) {
  238. score += 20;
  239. }
  240. }
  241. }
  242. return score;
  243. }
  244. private boolean isGeneric(Type type, LinkedHashMap<String, TypeParam> linkedHashMap) {
  245. return linkedHashMap.containsKey(type.getName());
  246. }
  247. @SuppressWarnings("unchecked")
  248. @Override
  249. public <T extends Node> T bitchJumpCasts() {
  250. return (T) inner;
  251. }
  252. }