001 /* Copyright (c) 2014, Erik Hogeman <Erik.Hogemn@gmail.com> 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 * * Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * * Redistributions in binary form must reproduce the above copyright 010 * notice, this list of conditions and the following disclaimer in the 011 * documentation and/or other materials provided with the distribution. 012 * * Neither the name of the Lund University nor the names of its 013 * contributors may be used to endorse or promote products derived from 014 * this software without specific prior written permission. 015 * 016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026 * POSSIBILITY OF SUCH DAMAGE. 027 */ 028 aspect LambdaToClass { 029 030 // Build an anonymous class which will be converted to byte code 031 // Since a lambda can't target generic methods, eventual type variables don't have to be taken into accound 032 syn nta lazy ClassInstanceExpr LambdaExpr.toClass() { 033 List<Access> implementsList = new List<Access>(); 034 InterfaceDecl iDecl = targetInterface(); 035 036 // First compute the interface implemented by the anonymous class 037 Access implementsInterface = iDecl.createQualifiedAccess(); 038 implementsList.add(implementsInterface); 039 040 // Next compute the BodyDecls for the anonymous class 041 List<BodyDecl> bodyDecls = new List<BodyDecl>(); 042 043 // To do that we must build the method which is the only BodyDecl 044 Modifiers methodModifiers = new Modifiers(new List<Modifier>().add(new Modifier("public"))); 045 Access returnType = (Access)iDecl.functionDescriptor().method.getTypeAccess().treeCopyNoTransform(); 046 List<ParameterDeclaration> methodParams = getLambdaParameters().toParameterList(); 047 List<Access> methodThrows = new List<Access>(); 048 for (TypeDecl throwsType : iDecl.functionDescriptor().throwsList) { 049 methodThrows.add(throwsType.createQualifiedAccess()); 050 } 051 Opt<Block> methodBlock = new Opt<Block>(getLambdaBody().toBlock()); 052 MethodDecl method = new MethodDecl(methodModifiers, returnType, iDecl.functionDescriptor().method.name(), 053 methodParams, methodThrows, methodBlock); 054 055 bodyDecls.add(method); 056 057 /* Now the anonymous class can be built. Must use the type LambdaAnonymousDecl instead 058 of a normal AnonymousDecl in order for this and super keywords to get the type of the outer 059 scope. */ 060 LambdaAnonymousDecl anonymousDecl = new LambdaAnonymousDecl(new Modifiers(), "Lambda", bodyDecls); 061 for (Access impl: implementsList) { 062 anonymousDecl.addImplements(impl); 063 } 064 065 return new ClassInstanceExpr(implementsInterface, new List<Expr>(), new Opt<TypeDecl>(anonymousDecl)); 066 } 067 068 syn lazy Block LambdaBody.toBlock(); 069 070 eq BlockLambdaBody.toBlock() { 071 Block b = getBlock(); 072 setChild(new Block(), 0); 073 b.flushCaches(); 074 return b; 075 } 076 eq ExprLambdaBody.toBlock() { 077 List<Stmt> stmtList = new List<Stmt>(); 078 // If expected return type is void, insert ExprStmt in list 079 Expr expr = getExpr(); 080 setChild(new VarAccess("tmp"), 0); 081 expr.flushCaches(); 082 if (enclosingLambda().targetInterface().functionDescriptor().method.type().isVoid()) { 083 stmtList.add(new ExprStmt(expr)); 084 } 085 // Otherwise, insert return stmt 086 else { 087 stmtList.add(new ReturnStmt(expr)); 088 } 089 return new Block(stmtList); 090 } 091 092 /*eq BlockLambdaBody.toBlock() = getBlock().treeCopyNoTransform(); 093 eq ExprLambdaBody.toBlock() { 094 List<Stmt> stmtList = new List<Stmt>(); 095 // If expected return type is void, insert ExprStmt in list 096 if (enclosingLambda().targetInterface().functionDescriptor().method.type().isVoid()) { 097 stmtList.add(new ExprStmt((Expr)getExpr().treeCopyNoTransform())); 098 } 099 // Otherwise, insert return stmt 100 else { 101 stmtList.add(new ReturnStmt((Expr)getExpr().treeCopyNoTransform())); 102 } 103 return new Block(stmtList); 104 }*/ 105 106 syn lazy List<ParameterDeclaration> LambdaParameters.toParameterList(); 107 eq DeclaredLambdaParameters.toParameterList() = getParameterList().treeCopyNoTransform(); 108 eq InferredLambdaParameters.toParameterList() { 109 List<ParameterDeclaration> paramList = new List<ParameterDeclaration>(); 110 int i = 0; 111 for (InferredParameterDeclaration infDecl : getParameterList()) { 112 ParameterDeclaration funcDecl = enclosingLambda().targetInterface().functionDescriptor().method.getParameter(i); 113 paramList.add(new ParameterDeclaration(funcDecl.getTypeAccess(), infDecl.name())); 114 i++; 115 } 116 return paramList; 117 } 118 }