view graal/com.oracle.graal.nodeinfo/src/com/oracle/graal/nodeinfo/processor/GraphNodeGenerator.java @ 16841:cbd42807a31f

moved NodeInfo and friends into separate com.oracle.graal.nodeinfo project so that annotation processor can be applied to the base Node class
author Doug Simon <doug.simon@oracle.com>
date Fri, 15 Aug 2014 11:34:38 +0200
parents graal/com.oracle.graal.graph.processor/src/com/oracle/graal/graph/processor/GraphNodeGenerator.java@b3a60e14ec37
children
line wrap: on
line source

/*
 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.graal.nodeinfo.processor;

import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;

import javax.annotation.processing.*;
import javax.lang.model.element.*;
import javax.lang.model.type.*;
import javax.lang.model.util.*;

import com.oracle.graal.nodeinfo.*;
import com.oracle.truffle.dsl.processor.java.*;
import com.oracle.truffle.dsl.processor.java.model.*;

/**
 * Generates the source code for a Node class.
 */
public class GraphNodeGenerator {

    private final GraphNodeProcessor processor;

    public GraphNodeGenerator(GraphNodeProcessor processor) {
        this.processor = processor;
    }

    public ProcessingEnvironment getProcessingEnv() {
        return processor.getProcessingEnv();
    }

    private String getGeneratedClassName(TypeElement node) {

        TypeElement typeElement = node;

        String newClassName = typeElement.getSimpleName().toString() + "Gen";
        Element enclosing = typeElement.getEnclosingElement();
        while (enclosing != null) {
            if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
                if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
                    processor.errorMessage(enclosing, "%s %s cannot be private", enclosing.getKind().name().toLowerCase(), enclosing);
                    return null;
                }
                newClassName = enclosing.getSimpleName() + "$" + newClassName;
            } else {
                assert enclosing.getKind() == ElementKind.PACKAGE;
            }
            enclosing = enclosing.getEnclosingElement();
        }
        return newClassName;
    }

    public CodeCompilationUnit process(TypeElement node) {
        CodeCompilationUnit compilationUnit = new CodeCompilationUnit();

        PackageElement packageElement = ElementUtils.findPackageElement(node);

        String newClassName = getGeneratedClassName(node);

        CodeTypeElement nodeGenElement = new CodeTypeElement(modifiers(), ElementKind.CLASS, packageElement, newClassName);

        if (node.getModifiers().contains(Modifier.ABSTRACT)) {
            // we do not support implementation of abstract methods yet.
            nodeGenElement.getModifiers().add(Modifier.ABSTRACT);
        }

        nodeGenElement.setSuperClass(node.asType());

        for (ExecutableElement constructor : ElementFilter.constructorsIn(node.getEnclosedElements())) {
            if (constructor.getModifiers().contains(Modifier.PRIVATE)) {
                // ignore private constructors
                continue;
            }
            nodeGenElement.add(createSuperConstructor(nodeGenElement, constructor));
        }

        DeclaredType generatedNode = (DeclaredType) ElementUtils.getType(getProcessingEnv(), GeneratedNode.class);
        CodeAnnotationMirror generatedByMirror = new CodeAnnotationMirror(generatedNode);
        generatedByMirror.setElementValue(generatedByMirror.findExecutableElement("value"), new CodeAnnotationValue(node.asType()));
        nodeGenElement.getAnnotationMirrors().add(generatedByMirror);

        nodeGenElement.add(createDummyExampleMethod());

        compilationUnit.add(nodeGenElement);
        return compilationUnit;
    }

    private CodeExecutableElement createSuperConstructor(TypeElement type, ExecutableElement element) {
        CodeExecutableElement executable = CodeExecutableElement.clone(getProcessingEnv(), element);

        // to create a constructor we have to set the return type to null.(TODO needs fix)
        executable.setReturnType(null);
        // we have to set the name manually otherwise <init> is inferred (TODO needs fix)
        executable.setSimpleName(CodeNames.of(type.getSimpleName().toString()));

        CodeTreeBuilder b = executable.createBuilder();
        b.startStatement().startSuperCall();
        for (VariableElement v : element.getParameters()) {
            b.string(v.getSimpleName().toString());
        }
        b.end().end();

        return executable;
    }

    public ExecutableElement createDummyExampleMethod() {
        CodeExecutableElement method = new CodeExecutableElement(modifiers(Modifier.PROTECTED), ElementUtils.getType(getProcessingEnv(), int.class), "computeTheMeaningOfLife");

        CodeTreeBuilder builder = method.createBuilder();
        builder.string("// this method got partially evaluated").newLine();
        builder.startReturn().string("42").end();

        return method;
    }

}