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 ConstructorReferenceToClass {
029    
030      /* Build a nested ArrayTypeWithSizeAccess from the normal
031         ArrayTypeAccess. This is to be used when generating
032         the anonymous inner class which must instantiate a new
033         array according to the array reference */
034      syn ArrayTypeAccess ArrayReference.getArrayTypeWithSizeAccess(Expr expr) {
035        ArrayTypeAccess startAccess = (ArrayTypeAccess) getTypeAccess().treeCopyNoTransform();
036        return recursiveArrayTypeWithSizeAccess(startAccess, (Expr) expr.treeCopyNoTransform());
037      }
038    
039      syn ArrayTypeAccess ArrayReference.recursiveArrayTypeWithSizeAccess(ArrayTypeAccess access, Expr expr) {
040        if (!(access.getAccess() instanceof ArrayTypeAccess)) {
041          return new ArrayTypeWithSizeAccess(access.getAccess(), expr);
042        } else {
043          return new ArrayTypeAccess(recursiveArrayTypeWithSizeAccess((ArrayTypeAccess) access.getAccess(), expr));
044        }
045      }
046    
047      // Build an anonymous inner class for bytecode generation
048      syn nta lazy ClassInstanceExpr ConstructorReference.toClass() {
049        List<Access> implementsList = new List<Access>();
050        InterfaceDecl iDecl = targetInterface();
051    
052        // First compute the interface implemented by the anonymous class
053        Access implementsInterface = iDecl.createQualifiedAccess();
054        implementsList.add(implementsInterface);
055    
056        // Next compute the BodyDecls for the anonymous class
057        List<BodyDecl> bodyDecls = new List<BodyDecl>();
058    
059        // Which means we must build the method overriding the abstract methods
060    
061        Modifiers methodModifiers = new Modifiers(new List<Modifier>().add(new Modifier("public")));
062        Access returnType = new SyntheticTypeAccess(iDecl.functionDescriptor().method.type());
063        List<ParameterDeclaration> methodParams = toParameterList();
064        List<Access> methodThrows = new List<Access>();
065        for (TypeDecl throwsType : iDecl.functionDescriptor().throwsList) {
066          methodThrows.add(new SyntheticTypeAccess(throwsType));
067        }
068        Opt<Block> methodBlock = new Opt<Block>(toBlock());
069        MethodDecl method = new MethodDecl(methodModifiers, returnType, iDecl.functionDescriptor().method.name(),
070                          methodParams, methodThrows, methodBlock);
071    
072        bodyDecls.add(method);
073    
074        /* Now the anonymous class can be built. Must use the type LambdaAnonymousDecl instead
075        of a normal AnonymousDecl in order for this and super keywords to get the type of the outer
076        scope. */
077        LambdaAnonymousDecl anonymousDecl = new LambdaAnonymousDecl(new Modifiers(), "ConstructorReference", bodyDecls);
078        for (Access impl: implementsList) {
079          anonymousDecl.addImplements(impl);
080        }
081    
082        return new ClassInstanceExpr((Access) implementsInterface.treeCopyNoTransform(), new List<Expr>(), new Opt<TypeDecl>(anonymousDecl));
083      }
084    
085      syn lazy Block ConstructorReference.toBlock();
086    
087      syn lazy List<ParameterDeclaration> ConstructorReference.toParameterList() {
088        List<ParameterDeclaration> list = new List<ParameterDeclaration>();
089        for (int i = 0; i < targetInterface().functionDescriptor().method.getNumParameter(); i++) {
090          TypeDecl paramType = targetInterface().functionDescriptor().method.getParameter(i).type();
091          String paramName = targetInterface().functionDescriptor().method.getParameter(i).name();
092          list.add(new ParameterDeclaration(new SyntheticTypeAccess(paramType), paramName));
093        }
094        return list;
095      }
096    
097      eq ArrayReference.toBlock() {
098        // First, build an ArrayCreationExpr used in the block
099        String paramName = targetInterface().functionDescriptor().method.getParameter(0).name();
100        VarAccess paramAccess = new VarAccess(paramName);
101        ArrayCreationExpr arrayExpr = new ArrayCreationExpr(getArrayTypeWithSizeAccess(paramAccess), new Opt());
102    
103        // Next build actual block
104        Stmt blockStmt = null;
105        if (targetInterface().functionDescriptor().method.type().isVoid()) {
106          blockStmt = new ExprStmt(arrayExpr);
107        } else {
108          blockStmt = new ReturnStmt(arrayExpr);
109        }
110        List<Stmt> stmtList = new List<Stmt>();
111        stmtList.add(blockStmt);
112        return new Block(stmtList);
113      }
114    
115      eq ClassReference.toBlock() {
116        List<Expr> arguments = new List<Expr>();
117        for (int i = 0; i < targetInterface().functionDescriptor().method.getNumParameter(); i++) {
118          String paramName = targetInterface().functionDescriptor().method.getParameter(i).name();
119          arguments.add(new VarAccess(paramName));
120        }
121    
122        ClassInstanceExpr instanceExpr = null;
123        if (hasTypeArgument()) {
124          instanceExpr = new ParClassInstanceExpr((Access) getTypeAccess().treeCopyNoTransform(), arguments,
125                              new Opt(), (List<Access>)getTypeArgumentList().treeCopyNoTransform());
126        } else {
127          if (getTypeAccess().type().isRawType()) {
128            DiamondAccess diamond = new DiamondAccess((Access) getTypeAccess().treeCopyNoTransform());
129            instanceExpr = new ClassInstanceExpr(diamond, arguments);
130          } else {
131            instanceExpr = new ClassInstanceExpr((Access) getTypeAccess().treeCopyNoTransform(), arguments);
132          }
133        }
134        Stmt blockStmt = null;
135        if (targetInterface().functionDescriptor().method.type().isVoid()) {
136          blockStmt = new ExprStmt(instanceExpr);
137        } else {
138          blockStmt = new ReturnStmt(instanceExpr);
139        }
140        List<Stmt> stmtList = new List<Stmt>();
141        stmtList.add(blockStmt);
142        return new Block(stmtList);
143    
144      }
145    }