001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect EnumsCodegen { 011 // add flags to enums 012 public static final int Modifiers.ACC_ENUM = 0x4000; 013 eq EnumDecl.flags() = super.flags() | Modifiers.ACC_ENUM; 014 eq EnumConstant.flags() = super.flags() | Modifiers.ACC_ENUM; 015 016 // transform enum switch statements into integer indexed switch statements 017 public void SwitchStmt.transformation() { 018 if(getExpr().type().isEnumDecl()) { 019 TypeDecl type = getExpr().type(); 020 hostType().createEnumArray(type); 021 hostType().createEnumMethod(type); 022 setExpr( 023 hostType().createEnumMethod(type).createBoundAccess(new List()).qualifiesAccess( 024 new ArrayAccess( 025 ((Expr)getExpr().fullCopy()).qualifiesAccess(new MethodAccess("ordinal", new List())) 026 )) 027 ); 028 } 029 super.transformation(); 030 } 031 032 public void ConstCase.transformation() { 033 if(getValue() instanceof VarAccess && getValue().varDecl() instanceof EnumConstant) { 034 int i = hostType().createEnumIndex((EnumConstant)getValue().varDecl()); 035 setValue(Literal.buildIntegerLiteral(i)); 036 } 037 super.transformation(); 038 } 039 040 041 // static method with lazy initalization 042 syn lazy MethodDecl TypeDecl.createEnumMethod(TypeDecl enumDecl) { 043 MethodDecl m = new MethodDecl( 044 new Modifiers(new List().add(new Modifier("static")).add(new Modifier("final")).add(new Modifier("private"))), 045 typeInt().arrayType().createQualifiedAccess(), 046 "$SwitchMap$" + enumDecl.fullName().replace('.', '$'), 047 new List(), 048 new List(), 049 new Opt( 050 new Block( 051 new List().add( 052 new IfStmt( 053 new EQExpr( 054 createEnumArray(enumDecl).createBoundFieldAccess(), 055 new NullLiteral("null") 056 ), 057 AssignExpr.asStmt( 058 createEnumArray(enumDecl).createBoundFieldAccess(), 059 new ArrayCreationExpr( 060 new ArrayTypeWithSizeAccess( 061 typeInt().createQualifiedAccess(), 062 enumDecl.createQualifiedAccess().qualifiesAccess( 063 new MethodAccess("values", new List())).qualifiesAccess( 064 new VarAccess("length")) 065 ), 066 new Opt() 067 ) 068 ), 069 new Opt() 070 ) 071 ).add( 072 new ReturnStmt( 073 createEnumArray(enumDecl).createBoundFieldAccess() 074 ) 075 ) 076 ) 077 ) 078 ); 079 // add method declaration as a body declaration 080 getBodyDeclList().insertChild(m, 1); 081 // trigger possible rewrites 082 return (MethodDecl)getBodyDeclList().getChild(1); 083 } 084 // compute index of enum constants 085 private HashMap TypeDecl.createEnumIndexMap = null; 086 syn lazy int TypeDecl.createEnumIndex(EnumConstant e) { 087 if(createEnumIndexMap == null) 088 createEnumIndexMap = new HashMap(); 089 if(!createEnumIndexMap.containsKey(e.hostType())) 090 createEnumIndexMap.put(e.hostType(), new Integer(0)); 091 Integer i = (Integer)createEnumIndexMap.get(e.hostType()); 092 i = new Integer(i.intValue() + 1); 093 createEnumIndexMap.put(e.hostType(), i); 094 095 MethodDecl m = createEnumMethod(e.hostType()); 096 List list = m.getBlock().getStmtList(); 097 list.insertChild( 098 new TryStmt( 099 new Block( 100 new List().add( 101 AssignExpr.asStmt( 102 createEnumArray(e.hostType()).createBoundFieldAccess().qualifiesAccess( 103 new ArrayAccess( 104 e.createBoundFieldAccess().qualifiesAccess(new MethodAccess("ordinal", new List())) 105 ) 106 ), 107 Literal.buildIntegerLiteral(i.intValue()) 108 ) 109 ) 110 ), 111 new List().add( 112 new BasicCatch( 113 new ParameterDeclaration( 114 lookupType("java.lang", "NoSuchFieldError").createQualifiedAccess(), 115 "e" 116 ), 117 new Block( 118 new List() 119 ) 120 ) 121 ), 122 new Opt() 123 ), 124 list.getNumChild()-1 125 ); 126 return i.intValue(); 127 } 128 // static field with array contents 129 syn lazy FieldDeclaration TypeDecl.createEnumArray(TypeDecl enumDecl) { 130 FieldDeclaration f = new FieldDeclaration( 131 new Modifiers(new List().add(new Modifier("static")).add(new Modifier("final")).add(new Modifier("private"))), 132 typeInt().arrayType().createQualifiedAccess(), 133 "$SwitchMap$" + enumDecl.fullName().replace('.', '$'), 134 new Opt() 135 ); 136 // add field declaration as a body declaration 137 getBodyDeclList().insertChild(f, 0); 138 // trigger possible rewrites 139 return (FieldDeclaration)getBodyDeclList().getChild(0); 140 } 141 }