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

http://github.com/nddrylliog/ooc · Java · 229 lines · 181 code · 41 blank · 7 comment · 57 complexity · 57a860c5147ed4fa3f2d4c90730d63eb MD5 · raw file

  1. package org.ooc.frontend.model;
  2. import java.io.IOException;
  3. import java.util.Iterator;
  4. import org.ooc.frontend.Visitor;
  5. import org.ooc.frontend.model.interfaces.MustBeUnwrapped;
  6. import org.ooc.frontend.model.tokens.Token;
  7. import org.ooc.middle.OocCompilationError;
  8. import org.ooc.middle.hobgoblins.Resolver;
  9. public class ArrayLiteral extends Literal implements MustBeUnwrapped {
  10. private FunctionCall outerCall = null;
  11. private int outerArgIndex = -1;
  12. //private static Type defaultType = NullLiteral.type;
  13. private static Type defaultType = null;
  14. private Type innerType = null;
  15. private Type type = defaultType;
  16. protected NodeList<Expression> elements;
  17. public ArrayLiteral(Token startToken) {
  18. super(startToken);
  19. elements = new NodeList<Expression>(startToken);
  20. }
  21. @Override
  22. public Expression getGenericOperand() {
  23. System.out.println("Should get genericOperand of arrlit "+this);
  24. return super.getGenericOperand();
  25. }
  26. public int getDepth() {
  27. if(elements.isEmpty() || !(elements.getFirst() instanceof ArrayLiteral)) return 1;
  28. return 1 + ((ArrayLiteral) elements.getFirst()).getDepth();
  29. }
  30. @Override
  31. public boolean replace(Node oldie, Node kiddo) {
  32. if(oldie == type) {
  33. type = (Type) kiddo;
  34. return true;
  35. } else if(oldie == innerType) {
  36. innerType = (Type) kiddo;
  37. return true;
  38. }
  39. return false;
  40. }
  41. public Type getType() {
  42. return type;
  43. }
  44. public Type getInnerType() {
  45. return innerType;
  46. }
  47. public NodeList<Expression> getElements() {
  48. return elements;
  49. }
  50. public void accept(Visitor visitor) throws IOException {
  51. visitor.visit(this);
  52. }
  53. public void acceptChildren(Visitor visitor) throws IOException {
  54. if(type != null) type.accept(visitor);
  55. elements.accept(visitor);
  56. }
  57. public boolean hasChildren() {
  58. return true;
  59. }
  60. @Override
  61. public boolean isResolved() {
  62. return type != defaultType && super.isResolved();
  63. }
  64. @Override
  65. public Response resolve(NodeList<Node> stack, Resolver res, boolean fatal) {
  66. if(type != defaultType) return Response.OK;
  67. if(!elements.isEmpty()) {
  68. Iterator<Expression> iter = elements.iterator();
  69. // try to determine the innerType from an outer call
  70. if(outerCall != null && outerArgIndex != -1) {
  71. FunctionDecl impl = outerCall.getImpl();
  72. if(impl == null) {
  73. if(fatal) {
  74. throw new OocCompilationError(this, stack, "Couldn't resolve type of an array literal because" +
  75. " the function call it's in hasn't been resolved.");
  76. }
  77. return Response.LOOP;
  78. }
  79. Argument arg = impl.getArguments().get(outerArgIndex);
  80. ArrayLiteral lit = this;
  81. int pointerLevel = 0;
  82. while(lit != null) {
  83. Node first = lit.getElements().getFirst();
  84. if(first instanceof ArrayLiteral) {
  85. lit = (ArrayLiteral) first;
  86. pointerLevel++;
  87. } else {
  88. lit = null;
  89. }
  90. }
  91. innerType = new Type(arg.getType().getName(), arg.getType().startToken);
  92. innerType.setPointerLevel(pointerLevel);
  93. }
  94. // try to determine the innerType from the first element
  95. if(innerType == null) {
  96. Expression first = iter.next();
  97. innerType = first.getType();
  98. }
  99. // if we didn't resolve it && fatal, we're screwed :/
  100. if(innerType == null) {
  101. if(fatal) {
  102. throw new OocCompilationError(this, stack, "Couldn't resolve type of an array literal");
  103. }
  104. return Response.LOOP;
  105. }
  106. while(iter.hasNext()) {
  107. Expression element = iter.next();
  108. if(element.getType() == null) {
  109. if(fatal) {
  110. throw new OocCompilationError(element, stack, "Couldn't resolve type of "
  111. +element+" in an "+innerType+" array literal");
  112. }
  113. return Response.LOOP;
  114. }
  115. if(!element.getType().fitsIn(innerType)) {
  116. throw new OocCompilationError(element, stack, "Encountered a "
  117. +element.getType()+" in a "+innerType+"[] array literal.");
  118. }
  119. }
  120. this.type = new Type(innerType.name.equals("Func") ? "Pointer" : innerType.name, innerType.pointerLevel + 1, startToken);
  121. type.getTypeParams().addAll(innerType.getTypeParams());
  122. type.setArray(true);
  123. stack.push(this);
  124. type.resolve(stack, res, fatal);
  125. innerType.resolve(stack, res, fatal);
  126. stack.pop(this);
  127. }
  128. if(type == defaultType && fatal) {
  129. throw new OocCompilationError(this, stack, "Couldn't figure out type of ArrayLiteral with elements "+elements);
  130. }
  131. return (type == defaultType) ? Response.LOOP : super.resolve(stack, res, fatal);
  132. }
  133. @SuppressWarnings("unchecked")
  134. public boolean unwrap(NodeList<Node> stack) throws IOException {
  135. // try to determine the innerType from the outer requirements
  136. if(outerCall == null || outerArgIndex == -1) {
  137. ArrayLiteral lit = this;
  138. int litIndex = stack.find(ArrayLiteral.class);
  139. int callIndex = stack.find(FunctionCall.class);
  140. if(callIndex != -1) {
  141. if(litIndex != -1 && litIndex > callIndex) {
  142. lit = (ArrayLiteral) stack.get(litIndex);
  143. }
  144. outerCall = (FunctionCall) stack.get(callIndex);
  145. outerArgIndex = ((NodeList<Node>) stack.get(callIndex + 1)).indexOf(lit);
  146. }
  147. }
  148. if(stack.peek() instanceof Cast || stack.peek() instanceof Foreach) {
  149. return false;
  150. }
  151. if(stack.peek(2) instanceof ArrayLiteral) {
  152. return false;
  153. }
  154. int varDeclIndex = stack.find(VariableDecl.class);
  155. // if stack.size() - varDeclIndex > 3, we're nested in another varDecl
  156. //, thus we need to unwrap
  157. if(varDeclIndex == -1 || (stack.size() - varDeclIndex) > 3) {
  158. stack.peek().replace(this, new VariableDecl(
  159. null, generateTempName("array", stack), this, startToken, stack.getModule()));
  160. return true;
  161. }
  162. return false;
  163. }
  164. @Override
  165. public String toString() {
  166. StringBuilder sb = new StringBuilder();
  167. sb.append('[');
  168. boolean isFirst = true;
  169. for(Statement element : elements) {
  170. if(isFirst) isFirst = false;
  171. else sb.append(", ");
  172. sb.append(element.toString());
  173. }
  174. sb.append(']');
  175. return sb.toString();
  176. }
  177. @Override
  178. public boolean isConstant() {
  179. boolean isConstant = true;
  180. for(Expression element : elements) {
  181. if(!element.isConstant()) {
  182. isConstant = false;
  183. break;
  184. }
  185. }
  186. return isConstant;
  187. }
  188. }