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    }