001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 aspect EnumsCodegen { 032 // add flags to enums 033 public static final int Modifiers.ACC_ENUM = 0x4000; 034 eq EnumDecl.flags() = super.flags() | Modifiers.ACC_ENUM; 035 eq EnumConstant.flags() = super.flags() | Modifiers.ACC_ENUM; 036 037 // transform enum switch statements into integer indexed switch statements 038 public void SwitchStmt.transformation() { 039 if (getExpr().type().isEnumDecl()) { 040 TypeDecl type = getExpr().type(); 041 hostType().createEnumArray(type); 042 hostType().createEnumMethod(type); 043 setExpr( 044 hostType().createEnumMethod(type).createBoundAccess(new List()).qualifiesAccess( 045 new ArrayAccess( 046 ((Expr) getExpr().treeCopyNoTransform()).qualifiesAccess(new MethodAccess("ordinal", new List())) 047 )) 048 ); 049 } 050 super.transformation(); 051 } 052 053 public void ConstCase.transformation() { 054 if (getValue() instanceof VarAccess && getValue().varDecl() instanceof EnumConstant) { 055 int i = hostType().createEnumIndex((EnumConstant) getValue().varDecl()); 056 setValue(Literal.buildIntegerLiteral(i)); 057 } 058 super.transformation(); 059 } 060 061 062 // static method with lazy initalization 063 syn lazy MethodDecl TypeDecl.createEnumMethod(TypeDecl enumDecl) { 064 MethodDecl m = new MethodDecl( 065 new Modifiers(new List().add(new Modifier("static")).add(new Modifier("final")).add(new Modifier("private"))), 066 typeInt().arrayType().createQualifiedAccess(), 067 "$SwitchMap$" + enumDecl.fullName().replace('.', '$'), 068 new List(), 069 new List(), 070 new Opt( 071 new Block( 072 new List().add( 073 new IfStmt( 074 new EQExpr( 075 createEnumArray(enumDecl).createBoundFieldAccess(), 076 new NullLiteral("null") 077 ), 078 AssignExpr.asStmt( 079 createEnumArray(enumDecl).createBoundFieldAccess(), 080 new ArrayCreationExpr( 081 new ArrayTypeWithSizeAccess( 082 typeInt().createQualifiedAccess(), 083 enumDecl.createQualifiedAccess().qualifiesAccess( 084 new MethodAccess("values", new List())).qualifiesAccess( 085 new VarAccess("length")) 086 ), 087 new Opt() 088 ) 089 ), 090 new Opt() 091 ) 092 ).add( 093 new ReturnStmt( 094 createEnumArray(enumDecl).createBoundFieldAccess() 095 ) 096 ) 097 ) 098 ) 099 ); 100 // add method declaration as a body declaration 101 getBodyDeclList().insertChild(m, 1); 102 // trigger possible rewrites 103 return (MethodDecl) getBodyDeclList().getChild(1); 104 } 105 // compute index of enum constants 106 private HashMap TypeDecl.createEnumIndexMap = null; 107 syn lazy int TypeDecl.createEnumIndex(EnumConstant e) { 108 if (createEnumIndexMap == null) { 109 createEnumIndexMap = new HashMap(); 110 } 111 if (!createEnumIndexMap.containsKey(e.hostType())) { 112 createEnumIndexMap.put(e.hostType(), new Integer(0)); 113 } 114 Integer i = (Integer) createEnumIndexMap.get(e.hostType()); 115 i = new Integer(i.intValue() + 1); 116 createEnumIndexMap.put(e.hostType(), i); 117 118 MethodDecl m = createEnumMethod(e.hostType()); 119 List list = m.getBlock().getStmtList(); 120 list.insertChild( 121 new TryStmt( 122 new Block( 123 new List().add( 124 AssignExpr.asStmt( 125 createEnumArray(e.hostType()).createBoundFieldAccess().qualifiesAccess( 126 new ArrayAccess( 127 e.createBoundFieldAccess().qualifiesAccess(new MethodAccess("ordinal", new List())) 128 ) 129 ), 130 Literal.buildIntegerLiteral(i.intValue()) 131 ) 132 ) 133 ), 134 new List().add( 135 new BasicCatch( 136 new ParameterDeclaration( 137 lookupType("java.lang", "NoSuchFieldError").createQualifiedAccess(), 138 "e" 139 ), 140 new Block( 141 new List() 142 ) 143 ) 144 ), 145 new Opt() 146 ), 147 list.getNumChild()-1 148 ); 149 return i.intValue(); 150 } 151 // static field with array contents 152 syn lazy FieldDeclaration TypeDecl.createEnumArray(TypeDecl enumDecl) { 153 FieldDeclaration f = new FieldDeclaration( 154 new Modifiers(new List().add(new Modifier("static")).add(new Modifier("final")).add(new Modifier("private"))), 155 typeInt().arrayType().createQualifiedAccess(), 156 "$SwitchMap$" + enumDecl.fullName().replace('.', '$'), 157 new Opt() 158 ); 159 // add field declaration as a body declaration 160 getBodyDeclList().insertChild(f, 0); 161 // trigger possible rewrites 162 return (FieldDeclaration) getBodyDeclList().getChild(0); 163 } 164 }