# HG changeset patch # User Christian Humer # Date 1408380076 -7200 # Node ID 2db61eddcb97f0d2396fb4718d99708e688b13ff # Parent d6c002f4d2a980eb1274ffb24133e763e7634815 Truffle-DSL: argument syntax support for guards diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java Mon Aug 18 18:41:16 2014 +0200 @@ -46,25 +46,25 @@ @ImportGuards(Imports0.class) static class ImportGuards1 extends ValueNode { - @ExpectError("No compatible guard with method name 'nonStaticGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'nonStaticGuard' found.") @Specialization(guards = "nonStaticGuard") int f1(int a) { return a; } - @ExpectError("No compatible guard with method name 'protectedGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'protectedGuard' found.") @Specialization(guards = "protectedGuard") int f2(int a) { return a; } - @ExpectError("No compatible guard with method name 'packageGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'packageGuard' found.") @Specialization(guards = "packageGuard") int f3(int a) { return a; } - @ExpectError("No compatible guard with method name 'privateGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No compatible guard with method name 'privateGuard' found.") @Specialization(guards = "privateGuard") int f4(int a) { return a; diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java Mon Aug 18 18:41:16 2014 +0200 @@ -142,7 +142,7 @@ } @Specialization(guards = "baseGuard") - @ExpectError("No compatible guard with method name 'baseGuard' found. Please note that all signature types of the method guard must be declared in the type system.") + @ExpectError("No guard with name 'baseGuard' matched the required signature.%") int doSpecialized(String value0) { return 42; } diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java Mon Aug 18 18:41:16 2014 +0200 @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2012, 2013, 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.truffle.api.dsl.test; + +import static com.oracle.truffle.api.dsl.test.TestHelper.*; + +import org.junit.*; + +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArguments0Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArguments1Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble0Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble1Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble2Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsDouble3Factory; +import com.oracle.truffle.api.dsl.test.MethodGuardsWithArgumentsTestFactory.MArgumentsSingle2Factory; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode; +import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode; + +public class MethodGuardsWithArgumentsTest { + + @Test + public void testMArguments0() { + TestRootNode root = createRoot(MArguments0Factory.getInstance()); + Assert.assertEquals(42, executeWith(root)); + } + + abstract static class MArguments0 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard()") + int do1() { + return 42; + } + } + + @Test + public void testMArguments1() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root)); + } + + abstract static class MArguments1 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard ()") + int do1() { + return 42; + } + } + + @Test + public void testMArgumentsSingle0() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle0 extends ValueNode { + + static boolean guard() { + return true; + } + + @Specialization(guards = "guard()") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsSingle1() { + TestRootNode root = createRoot(MArguments1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle1 extends ValueNode { + + static boolean guard(int a) { + return a == 42; + } + + @Specialization(guards = "guard(a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsSingle2() { + TestRootNode root = createRoot(MArgumentsSingle2Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42)); + } + + @NodeChild("a") + abstract static class MArgumentsSingle2 extends ValueNode { + + static boolean guard(int a1, int a2) { + return a1 == 42 && a2 == 42; + } + + @Specialization(guards = "guard(a,a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsDouble0() { + TestRootNode root = createRoot(MArgumentsDouble0Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 0)); + } + + @NodeChild("a") + abstract static class MArgumentsDouble0 extends ValueNode { + + static boolean guard(int a1, Object a2) { + return a1 == 42 && a2.equals(new Integer(42)); + } + + @Specialization(guards = "guard(a,a)") + int do1(int a) { + return a; + } + } + + @Test + public void testMArgumentsDouble1() { + TestRootNode root = createRoot(MArgumentsDouble1Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble1 extends ValueNode { + + static boolean guard(int a1, double a2) { + return a1 == 42 && a2 == 41; + } + + @Specialization(guards = "guard(a,b)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + @Test + public void testMArgumentsDouble2() { + TestRootNode root = createRoot(MArgumentsDouble2Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41.0)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble2 extends ValueNode { + + static boolean guard(double a1, int a2) { + return a1 == 41 && a2 == 42; + } + + @Specialization(guards = "guard(b,a)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + @Test + public void testMArgumentsDouble3() { + TestRootNode root = createRoot(MArgumentsDouble3Factory.getInstance()); + Assert.assertEquals(42, executeWith(root, 42, 41.0)); + } + + @NodeChildren({@NodeChild("a"), @NodeChild("b")}) + abstract static class MArgumentsDouble3 extends ValueNode { + + static boolean guard(Object a1, double a2) { + return new Double(41.0).equals(a1) && a2 == 41; + } + + @Specialization(guards = "guard(b,b)") + int do1(int a, @SuppressWarnings("unused") double b) { + return a; + } + } + + abstract static class MArgumentsError0 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("No compatible guard with method name 'guard(' found.%") + @Specialization(guards = "guard(") + int do1() { + return 42; + } + } + + abstract static class MArgumentsError1 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("No compatible guard with method name 'guard)' found.%") + @Specialization(guards = "guard)") + int do1() { + return 42; + } + + } + + abstract static class MArgumentsError2 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.") + @Specialization(guards = "guard(a)") + int do1() { + return 42; + } + } + + @NodeChild("b") + abstract static class MArgumentsError3 extends ValueNode { + + static boolean guard() { + return true; + } + + @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.") + @Specialization(guards = "guard(a)") + int do1(int b) { + return b; + } + } + +} diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java Mon Aug 18 18:41:16 2014 +0200 @@ -322,12 +322,12 @@ /** *
      * variant1 $condition != null
-     * 
+     *
      * $type $name = defaultValue($type);
      * if ($condition) {
      *     $name = $value;
      * }
-     * 
+     *
      * variant2 $condition != null
      * $type $name = $value;
      * 
@@ -1590,12 +1590,16 @@ } private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) { - int signatureIndex = 0; for (Parameter parameter : guard.getResolvedGuard().getParameters()) { if (!parameter.getSpecification().isSignature()) { continue; } + int signatureIndex = source.getNode().getChildExecutions().indexOf(parameter.getSpecification().getExecution()); + if (signatureIndex == -1) { + continue; + } + TypeGuard typeGuard = group.findTypeGuard(signatureIndex); if (typeGuard != null) { TypeData requiredType = typeGuard.getType(); @@ -1609,8 +1613,6 @@ return true; } } - - signatureIndex++; } return false; } diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java Mon Aug 18 18:41:16 2014 +0200 @@ -530,7 +530,7 @@ public static boolean isEnclosedIn(Element enclosedIn, Element element) { if (element == null) { return false; - } else if (enclosedIn.equals(element)) { + } else if (typeEquals(enclosedIn.asType(), element.asType())) { return true; } else { return isEnclosedIn(enclosedIn, element.getEnclosingElement()); diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java Mon Aug 18 18:41:16 2014 +0200 @@ -27,18 +27,43 @@ public final class GuardExpression { private GuardData resolvedGuard; + private NodeExecutionData[] resolvedChildren; private final String guardName; private final boolean negated; + private final String[] childNames; - public GuardExpression(String expression) { - if (expression.startsWith("!")) { - guardName = expression.substring(1, expression.length()); + public GuardExpression(String expression, boolean allowArguments) { + String exp = expression; + if (exp.startsWith("!")) { + exp = exp.substring(1, exp.length()); negated = true; } else { - guardName = expression; negated = false; } + + int argumentStart = exp.indexOf('('); + int endIndex = exp.lastIndexOf(')'); + if (allowArguments && argumentStart != -1 && endIndex != -1) { + guardName = exp.substring(0, argumentStart).trim(); + String arguments = exp.substring(argumentStart + 1, endIndex); + String[] children = arguments.split(","); + for (int i = 0; i < children.length; i++) { + children[i] = children[i].trim(); + } + if (children.length == 1 && children[0].isEmpty()) { + childNames = new String[0]; + } else { + childNames = children; + } + } else { + guardName = exp; + childNames = null; + } + } + + public String[] getChildNames() { + return childNames; } public boolean isResolved() { @@ -49,18 +74,32 @@ return guardName; } - public void setGuard(GuardData guard) { + public NodeExecutionData[] getResolvedChildren() { + return resolvedChildren; + } + + public void setResolvedChildren(NodeExecutionData[] resolvedChildren) { + this.resolvedChildren = resolvedChildren; + } + + public void setResolvedGuard(GuardData guard) { this.resolvedGuard = guard; } @Override public boolean equals(Object obj) { - if (obj instanceof GuardExpression) { + if (this == obj) { + return true; + } else if (obj instanceof GuardExpression) { GuardExpression other = (GuardExpression) obj; if (isResolved() && other.isResolved()) { - return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated; + return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated && Arrays.equals(resolvedChildren, other.resolvedChildren); } else { - return guardName.equals(other.guardName) && negated == other.negated; + boolean equal = guardName.equals(other.guardName) && negated == other.negated; + if (childNames != null && other.childNames != null) { + equal &= Arrays.equals(childNames, other.childNames); + } + return equal; } } return false; @@ -68,18 +107,13 @@ @Override public int hashCode() { - return Objects.hash(guardName, negated, resolvedGuard); + return Objects.hash(guardName, negated, resolvedGuard, resolvedChildren); } public final boolean implies(GuardExpression other) { - if (other == this) { + if (equals(other)) { return true; } - if (getGuardName().equals(other.getGuardName())) { - if (isNegated() == other.isNegated()) { - return true; - } - } if (isResolved() && other.isResolved()) { for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) { diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java Mon Aug 18 18:41:16 2014 +0200 @@ -30,7 +30,6 @@ import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; -import com.oracle.truffle.dsl.processor.parser.*; public class NodeData extends Template implements Comparable { @@ -208,6 +207,30 @@ return true; } + public NodeExecutionData findExecutionByExpression(String childNameExpression) { + String childName = childNameExpression; + int index = -1; + + int start = childName.indexOf('['); + int end = childName.lastIndexOf(']'); + if (start != -1 && end != -1 && start < end) { + try { + index = Integer.parseInt(childName.substring(start + 1, end)); + childName = childName.substring(0, start); + childName = NodeExecutionData.createName(childName, index); + } catch (NumberFormatException e) { + // ignore + } + } + + for (NodeExecutionData execution : childExecutions) { + if (execution.getName().equals(childName) && (execution.getIndex() == -1 || execution.getIndex() == index)) { + return execution; + } + } + return null; + } + public List getNodeDeclaringChildren() { List nodeChildren = new ArrayList<>(); for (NodeData child : getEnclosingNodes()) { diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java Mon Aug 18 18:41:16 2014 +0200 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012, 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.truffle.dsl.processor.model; + +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; + +public class NodeExecutionData { + + private final NodeChildData child; + private final String name; + private final int index; + private final boolean shortCircuit; + + public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { + this.child = child; + this.index = index; + this.shortCircuit = shortCircuit; + this.name = createName(); + } + + private String createName() { + return createName(child.getName(), index); + } + + public TypeMirror getNodeType() { + TypeMirror type; + if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { + type = ((ArrayType) child.getNodeType()).getComponentType(); + } else { + type = child.getNodeType(); + } + return type; + } + + public String getName() { + return name; + } + + public NodeChildData getChild() { + return child; + } + + public int getIndex() { + return index; + } + + public boolean isIndexed() { + return index > -1; + } + + public boolean isShortCircuit() { + return shortCircuit; + } + + public String getShortCircuitId() { + return createShortCircuitId(child, index); + } + + public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { + String shortCircuitName = child.getName(); + if (child.getCardinality().isMany()) { + shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; + } + return shortCircuitName; + } + + public static String createName(String childName, int index) { + if (index > -1) { + return childName + index; + } + return childName; + } + +} diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java Mon Aug 18 18:41:16 2014 +0200 @@ -28,7 +28,6 @@ import com.oracle.truffle.dsl.processor.java.*; import com.oracle.truffle.dsl.processor.model.MethodSpec.TypeDef; -import com.oracle.truffle.dsl.processor.parser.*; public class ParameterSpec { diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java Mon Aug 18 18:41:16 2014 +0200 @@ -163,6 +163,17 @@ return foundParameters; } + public List findByExecutionData(NodeExecutionData execution) { + List foundParameters = new ArrayList<>(); + for (Parameter parameter : getParameters()) { + ParameterSpec spec = parameter.getSpecification(); + if (spec != null && spec.getExecution() != null && spec.getExecution().equals(execution) && parameter.getSpecification().isSignature()) { + foundParameters.add(parameter); + } + } + return foundParameters; + } + public Parameter findParameter(String valueName) { for (Parameter param : getReturnTypeAndParameters()) { if (param.getLocalName().equals(valueName)) { diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethodParser.java Mon Aug 18 17:44:42 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.dsl.processor.model; - -import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; - -import java.lang.annotation.*; -import java.util.*; - -import javax.lang.model.element.*; -import javax.lang.model.type.*; -import javax.lang.model.util.*; - -import com.oracle.truffle.dsl.processor.*; -import com.oracle.truffle.dsl.processor.java.*; - -public abstract class TemplateMethodParser { - - private final ProcessorContext context; - - protected final T template; - - private boolean emitErrors = true; - private boolean parseNullOnError = false; - private boolean useVarArgs = false; - - public TemplateMethodParser(ProcessorContext context, T template) { - this.template = template; - this.context = context; - } - - protected void setUseVarArgs(boolean useVarArgs) { - this.useVarArgs = useVarArgs; - } - - public boolean isUseVarArgs() { - return useVarArgs; - } - - public boolean isEmitErrors() { - return emitErrors; - } - - public void setParseNullOnError(boolean nullOnError) { - this.parseNullOnError = nullOnError; - } - - public boolean isParseNullOnError() { - return parseNullOnError; - } - - public void setEmitErrors(boolean emitErrors) { - this.emitErrors = emitErrors; - } - - public ProcessorContext getContext() { - return context; - } - - public TypeSystemData getTypeSystem() { - return template.getTypeSystem(); - } - - public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); - - public abstract E create(TemplateMethod method, boolean invalid); - - public abstract boolean isParsable(ExecutableElement method); - - public Class getAnnotationType() { - return null; - } - - public final List parse(List elements) { - List methods = new ArrayList<>(); - methods.addAll(ElementFilter.methodsIn(elements)); - - List parsedMethods = new ArrayList<>(); - boolean valid = true; - int naturalOrder = 0; - for (ExecutableElement method : methods) { - if (!isParsable(method)) { - continue; - } - - Class annotationType = getAnnotationType(); - AnnotationMirror mirror = null; - if (annotationType != null) { - mirror = ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); - } - - E parsedMethod = parse(naturalOrder, method, mirror); - - if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) { - parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); - parsedMethods.add(parsedMethod); - valid = false; - continue; - } - - if (parsedMethod != null) { - parsedMethods.add(parsedMethod); - } else { - valid = false; - } - naturalOrder++; - } - Collections.sort(parsedMethods); - - if (!valid && parseNullOnError) { - return null; - } - return parsedMethods; - } - - private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { - MethodSpec methodSpecification = createSpecification(method, annotation); - if (methodSpecification == null) { - return null; - } - - methodSpecification.applyTypeDefinitions("types"); - - String id = method.getSimpleName().toString(); - TypeMirror returnType = method.getReturnType(); - List parameterTypes = new ArrayList<>(); - for (VariableElement var : method.getParameters()) { - parameterTypes.add(var.asType()); - } - - return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); - } - - private E parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, List parameterTypes) { - ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); - Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); - if (returnTypeMirror == null) { - if (emitErrors) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String expectedReturnType = returnTypeSpec.toSignatureString(true); - String actualReturnType = ElementUtils.getSimpleName(returnType); - - String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); - if (parameters == null) { - if (isEmitErrors() && method != null) { - E invalidMethod = create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()), true); - String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), - methodSpecification.toSignatureString(method.getSimpleName().toString())); - invalidMethod.addError(message); - return invalidMethod; - } else { - return null; - } - } - - return create(new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters), false); - } - - private static String createActualSignature(ExecutableElement method) { - StringBuilder b = new StringBuilder("("); - String sep = ""; - if (method != null) { - for (VariableElement var : method.getParameters()) { - b.append(sep); - b.append(ElementUtils.getSimpleName(var.asType())); - sep = ", "; - } - } - b.append(")"); - return b.toString(); - } - - /* - * Parameter parsing tries to parse required arguments starting from offset 0 with increasing - * offset until it finds a signature end that matches the required specification. If there is no - * end matching the required arguments, parsing fails. Parameters prior to the parsed required - * ones are cut and used to parse the optional parameters. - */ - private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { - List parsedRequired = null; - int offset = 0; - for (; offset <= parameterTypes.size(); offset++) { - List parameters = new ArrayList<>(); - parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); - parsedRequired = parseParametersRequired(spec, parameters, varArgs); - if (parsedRequired != null) { - break; - } - } - - if (parsedRequired == null) { - return null; - } - - if (parsedRequired.isEmpty() && offset == 0) { - offset = parameterTypes.size(); - } - List potentialOptionals = parameterTypes.subList(0, offset); - List parsedOptionals = parseParametersOptional(spec, potentialOptionals); - if (parsedOptionals == null) { - return null; - } - - List finalParameters = new ArrayList<>(); - finalParameters.addAll(parsedOptionals); - finalParameters.addAll(parsedRequired); - return finalParameters; - } - - private List parseParametersOptional(MethodSpec spec, List types) { - List parsedParams = new ArrayList<>(); - - int typeStartIndex = 0; - List specifications = spec.getOptional(); - outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { - ParameterSpec specification = specifications.get(specIndex); - for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { - TypeMirror actualType = types.get(typeIndex); - Parameter optionalParam = matchParameter(specification, actualType, -1, -1); - if (optionalParam != null) { - parsedParams.add(optionalParam); - typeStartIndex = typeIndex + 1; - continue outer; - } - } - } - - if (typeStartIndex < types.size()) { - // not enough types found - return null; - } - return parsedParams; - } - - private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { - List parsedParams = new ArrayList<>(); - List specifications = spec.getRequired(); - boolean specVarArgs = spec.isVariableRequiredParameters(); - int typeIndex = 0; - int specificationIndex = 0; - - ParameterSpec specification; - while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { - TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); - if (actualType == null) { - if (spec.isIgnoreAdditionalSpecifications()) { - break; - } - return null; - } - - int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; - int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; - - if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { - // both specifications and types have a variable number of arguments - // we would get into an endless loop if we would continue - break; - } - - Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); - if (resolvedParameter == null) { - return null; - } - parsedParams.add(resolvedParameter); - typeIndex++; - specificationIndex++; - } - - if (typeIndex < types.size()) { - // additional types available - if (spec.isIgnoreAdditionalParameters()) { - return parsedParams; - } else { - return null; - } - } - - return parsedParams; - } - - private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { - if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { - return specifications.get(specifications.size() - 1); - } else if (specIndex < specifications.size()) { - return specifications.get(specIndex); - } else { - return null; - } - } - - private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { - if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { - // unpack varargs array argument - TypeMirror actualType = types.get(types.size() - 1); - if (actualType.getKind() == TypeKind.ARRAY) { - actualType = ((ArrayType) actualType).getComponentType(); - } - return actualType; - } else if (typeIndex < types.size()) { - return types.get(typeIndex); - } else { - return null; - } - } - - private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { - TypeMirror resolvedType = mirror; - if (hasError(resolvedType)) { - return null; - } - - if (!specification.matches(resolvedType)) { - return null; - } - - TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); - if (resolvedTypeData != null) { - return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); - } else { - return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); - } - } - - public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { - return parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); - } -} diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -35,9 +35,9 @@ public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) { super(context, node); - setEmitErrors(false); setParseNullOnError(false); - setUseVarArgs(true); + getParser().setEmitErrors(false); + getParser().setUseVarArgs(true); } @Override diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -35,14 +35,14 @@ public class GuardParser extends NodeMethodParser { - private final Set guardNames; - private final TemplateMethod compatibleSource; + private final GuardExpression expression; + private final TemplateMethod guardedMethod; - public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, Set guardNames) { + public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, GuardExpression expression) { super(context, node); - this.guardNames = guardNames; - this.compatibleSource = compatibleSource; - setEmitErrors(false); + this.expression = expression; + this.guardedMethod = compatibleSource; + getParser().setEmitErrors(false); setParseNullOnError(false); } @@ -55,21 +55,35 @@ public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null); spec.setIgnoreAdditionalSpecifications(true); - if (compatibleSource != null) { - spec.getRequired().clear(); - for (Parameter parameter : compatibleSource.getRequiredParameters()) { - List typeMirrors = ElementUtils.getAssignableTypes(getContext(), parameter.getType()); - Set typeIds = new HashSet<>(); - for (TypeMirror typeMirror : typeMirrors) { - typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror)); + spec.getRequired().clear(); + + if (expression.getResolvedChildren() != null) { + for (NodeExecutionData execution : expression.getResolvedChildren()) { + List foundInGuardedMethod = guardedMethod.findByExecutionData(execution); + for (Parameter guardedParameter : foundInGuardedMethod) { + spec.addRequired(createParameterSpec(guardedParameter)); } - - spec.addRequired(new ParameterSpec(parameter.getSpecification(), typeMirrors, typeIds)); + } + } else { + for (Parameter parameter : guardedMethod.getRequiredParameters()) { + spec.addRequired(createParameterSpec(parameter)); } } + return spec; } + private ParameterSpec createParameterSpec(Parameter parameter) { + List typeMirrors = ElementUtils.getAssignableTypes(getContext(), parameter.getType()); + Set typeIds = new HashSet<>(); + for (TypeMirror typeMirror : typeMirrors) { + typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror)); + } + typeIds.retainAll(getTypeSystem().getTypeIdentifiers()); + + return new ParameterSpec(parameter.getSpecification(), typeMirrors, typeIds); + } + @Override protected List nodeTypeMirrors(NodeData nodeData) { Set typeMirrors = new LinkedHashSet<>(); @@ -90,7 +104,7 @@ @Override public boolean isParsable(ExecutableElement method) { - return guardNames == null || guardNames.contains(method.getSimpleName().toString()); + return true; } @Override @@ -102,7 +116,7 @@ } List guardExpressions = new ArrayList<>(); for (String string : impliesExpressions) { - guardExpressions.add(new GuardExpression(string)); + guardExpressions.add(new GuardExpression(string, false)); } return new GuardData(method, guardExpressions); } diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2012, 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.truffle.dsl.processor.parser; + +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public final class MethodSpecParser { + + private boolean emitErrors = true; + private boolean useVarArgs = false; + + private final Template template; + + public MethodSpecParser(Template template) { + this.template = template; + } + + public Template getTemplate() { + return template; + } + + public TypeSystemData getTypeSystem() { + return template.getTypeSystem(); + } + + public boolean isEmitErrors() { + return emitErrors; + } + + public boolean isUseVarArgs() { + return useVarArgs; + } + + public void setEmitErrors(boolean emitErrors) { + this.emitErrors = emitErrors; + } + + public void setUseVarArgs(boolean useVarArgs) { + this.useVarArgs = useVarArgs; + } + + public TemplateMethod parse(MethodSpec methodSpecification, ExecutableElement method, AnnotationMirror annotation, int naturalOrder) { + if (methodSpecification == null) { + return null; + } + + methodSpecification.applyTypeDefinitions("types"); + + String id = method.getSimpleName().toString(); + TypeMirror returnType = method.getReturnType(); + List parameterTypes = new ArrayList<>(); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes); + } + + public TemplateMethod parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType, + List parameterTypes) { + ParameterSpec returnTypeSpec = methodSpecification.getReturnType(); + Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1); + if (returnTypeMirror == null) { + if (emitErrors) { + TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); + String expectedReturnType = returnTypeSpec.toSignatureString(true); + String actualReturnType = ElementUtils.getSimpleName(returnType); + + String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType, + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + List parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method != null ? method.isVarArgs() : false); + if (parameters == null) { + if (isEmitErrors() && method != null) { + TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections. emptyList()); + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(method), + methodSpecification.toSignatureString(method.getSimpleName().toString())); + invalidMethod.addError(message); + return invalidMethod; + } else { + return null; + } + } + + return new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, parameters); + } + + private static String createActualSignature(ExecutableElement method) { + StringBuilder b = new StringBuilder("("); + String sep = ""; + if (method != null) { + for (VariableElement var : method.getParameters()) { + b.append(sep); + b.append(ElementUtils.getSimpleName(var.asType())); + sep = ", "; + } + } + b.append(")"); + return b.toString(); + } + + /* + * Parameter parsing tries to parse required arguments starting from offset 0 with increasing + * offset until it finds a signature end that matches the required specification. If there is no + * end matching the required arguments, parsing fails. Parameters prior to the parsed required + * ones are cut and used to parse the optional parameters. + */ + private List parseParameters(MethodSpec spec, List parameterTypes, boolean varArgs) { + List parsedRequired = null; + int offset = 0; + for (; offset <= parameterTypes.size(); offset++) { + List parameters = new ArrayList<>(); + parameters.addAll(parameterTypes.subList(offset, parameterTypes.size())); + parsedRequired = parseParametersRequired(spec, parameters, varArgs); + if (parsedRequired != null) { + break; + } + } + + if (parsedRequired == null) { + return null; + } + + if (parsedRequired.isEmpty() && offset == 0) { + offset = parameterTypes.size(); + } + List potentialOptionals = parameterTypes.subList(0, offset); + List parsedOptionals = parseParametersOptional(spec, potentialOptionals); + if (parsedOptionals == null) { + return null; + } + + List finalParameters = new ArrayList<>(); + finalParameters.addAll(parsedOptionals); + finalParameters.addAll(parsedRequired); + return finalParameters; + } + + private List parseParametersOptional(MethodSpec spec, List types) { + List parsedParams = new ArrayList<>(); + + int typeStartIndex = 0; + List specifications = spec.getOptional(); + outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) { + ParameterSpec specification = specifications.get(specIndex); + for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) { + TypeMirror actualType = types.get(typeIndex); + Parameter optionalParam = matchParameter(specification, actualType, -1, -1); + if (optionalParam != null) { + parsedParams.add(optionalParam); + typeStartIndex = typeIndex + 1; + continue outer; + } + } + } + + if (typeStartIndex < types.size()) { + // not enough types found + return null; + } + return parsedParams; + } + + private List parseParametersRequired(MethodSpec spec, List types, boolean typeVarArgs) { + List parsedParams = new ArrayList<>(); + List specifications = spec.getRequired(); + boolean specVarArgs = spec.isVariableRequiredParameters(); + int typeIndex = 0; + int specificationIndex = 0; + + ParameterSpec specification; + while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) { + TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs); + if (actualType == null) { + if (spec.isIgnoreAdditionalSpecifications()) { + break; + } + return null; + } + + int typeVarArgsIndex = typeVarArgs ? typeIndex - types.size() + 1 : -1; + int specVarArgsIndex = specVarArgs ? specificationIndex - specifications.size() + 1 : -1; + + if (typeVarArgsIndex >= 0 && specVarArgsIndex >= 0) { + // both specifications and types have a variable number of arguments + // we would get into an endless loop if we would continue + break; + } + + Parameter resolvedParameter = matchParameter(specification, actualType, specVarArgsIndex, typeVarArgsIndex); + if (resolvedParameter == null) { + return null; + } + parsedParams.add(resolvedParameter); + typeIndex++; + specificationIndex++; + } + + if (typeIndex < types.size()) { + // additional types available + if (spec.isIgnoreAdditionalParameters()) { + return parsedParams; + } else { + return null; + } + } + + return parsedParams; + } + + private static ParameterSpec nextSpecification(List specifications, int specIndex, boolean varArgs) { + if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) { + return specifications.get(specifications.size() - 1); + } else if (specIndex < specifications.size()) { + return specifications.get(specIndex); + } else { + return null; + } + } + + private static TypeMirror nextActualType(List types, int typeIndex, boolean varArgs) { + if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) { + // unpack varargs array argument + TypeMirror actualType = types.get(types.size() - 1); + if (actualType.getKind() == TypeKind.ARRAY) { + actualType = ((ArrayType) actualType).getComponentType(); + } + return actualType; + } else if (typeIndex < types.size()) { + return types.get(typeIndex); + } else { + return null; + } + } + + private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) { + TypeMirror resolvedType = mirror; + if (hasError(resolvedType)) { + return null; + } + + if (!specification.matches(resolvedType)) { + return null; + } + + TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType); + if (resolvedTypeData != null) { + return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex); + } else { + return new Parameter(specification, resolvedType, specificationIndex, varArgsIndex); + } + } + +} diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeExecutionData.java Mon Aug 18 17:44:42 2014 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2012, 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.truffle.dsl.processor.parser; - -import javax.lang.model.type.*; - -import com.oracle.truffle.dsl.processor.model.*; -import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; - -public class NodeExecutionData { - - private final NodeChildData child; - private final String name; - private final int index; - private final boolean shortCircuit; - - public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) { - this.child = child; - this.index = index; - this.shortCircuit = shortCircuit; - this.name = createName(); - } - - private String createName() { - if (isIndexed()) { - return child.getName() + index; - } - return child.getName(); - } - - public TypeMirror getNodeType() { - TypeMirror type; - if (child.getCardinality() == Cardinality.MANY && child.getNodeType().getKind() == TypeKind.ARRAY) { - type = ((ArrayType) child.getNodeType()).getComponentType(); - } else { - type = child.getNodeType(); - } - return type; - } - - public String getName() { - return name; - } - - public NodeChildData getChild() { - return child; - } - - public int getIndex() { - return index; - } - - public boolean isIndexed() { - return index > -1; - } - - public boolean isShortCircuit() { - return shortCircuit; - } - - public String getShortCircuitId() { - return createShortCircuitId(child, index); - } - - public static String createShortCircuitId(NodeChildData child, int varArgsIndex) { - String shortCircuitName = child.getName(); - if (child.getCardinality().isMany()) { - shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]"; - } - return shortCircuitName; - } - -} diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -190,12 +190,18 @@ continue; } TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass); - if (!typeElement.getModifiers().contains(Modifier.PUBLIC)) { + + // hack to reload type is necessary for incremental compiling in eclipse. + // otherwise methods inside of import guard types are just not found. + typeElement = ElementUtils.fromTypeMirror(context.reloadType(typeElement.asType())); + + if (typeElement.getEnclosingElement().getKind().isClass() && !typeElement.getModifiers().contains(Modifier.PUBLIC)) { node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass)); continue; } List importMethods = ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(typeElement)); + for (ExecutableElement importMethod : importMethods) { if (!importMethod.getModifiers().contains(Modifier.PUBLIC) || !importMethod.getModifiers().contains(Modifier.STATIC)) { continue; @@ -883,53 +889,70 @@ } private void initializeGuards(List elements, NodeData node) { - Map> guards = new HashMap<>(); + Map> potentialGuards = new HashMap<>(); for (SpecializationData specialization : node.getSpecializations()) { for (GuardExpression exp : specialization.getGuards()) { - guards.put(exp.getGuardName(), null); + potentialGuards.put(exp.getGuardName(), null); } } - GuardParser parser = new GuardParser(context, node, null, guards.keySet()); - List resolvedGuards = parser.parse(elements); - for (GuardData guard : resolvedGuards) { - List groupedGuards = guards.get(guard.getMethodName()); - if (groupedGuards == null) { - groupedGuards = new ArrayList<>(); - guards.put(guard.getMethodName(), groupedGuards); + TypeMirror booleanType = context.getType(boolean.class); + for (ExecutableElement potentialGuard : ElementFilter.methodsIn(elements)) { + if (potentialGuard.getModifiers().contains(Modifier.PRIVATE)) { + continue; + } + String methodName = potentialGuard.getSimpleName().toString(); + if (!potentialGuards.containsKey(methodName)) { + continue; } - groupedGuards.add(guard); + + if (!ElementUtils.typeEquals(potentialGuard.getReturnType(), booleanType)) { + continue; + } + + List potentialMethods = potentialGuards.get(methodName); + if (potentialMethods == null) { + potentialMethods = new ArrayList<>(); + potentialGuards.put(methodName, potentialMethods); + } + potentialMethods.add(potentialGuard); } for (SpecializationData specialization : node.getSpecializations()) { for (GuardExpression exp : specialization.getGuards()) { - resolveGuardExpression(node, specialization, guards, exp); + resolveGuardExpression(node, specialization, potentialGuards, exp); } } } - private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { - List availableGuards = guards.get(expression.getGuardName()); + private void resolveGuardExpression(NodeData node, TemplateMethod source, Map> guards, GuardExpression expression) { + List availableGuards = guards.get(expression.getGuardName()); if (availableGuards == null) { - source.addError("No compatible guard with method name '%s' found. Please note that all signature types of the method guard must be declared in the type system.", expression.getGuardName()); + source.addError("No compatible guard with method name '%s' found.", expression.getGuardName()); return; } - List guardMethods = new ArrayList<>(); - for (GuardData guard : availableGuards) { - guardMethods.add(guard.getMethod()); + + String[] childNames = expression.getChildNames(); + if (childNames != null) { + NodeExecutionData[] resolvedExecutions = new NodeExecutionData[childNames.length]; + for (int i = 0; i < childNames.length; i++) { + String childName = childNames[i]; + NodeExecutionData execution = node.findExecutionByExpression(childName); + if (execution == null) { + source.addError("Guard parameter '%s' for guard '%s' could not be mapped to a declared child node.", childName, expression.getGuardName()); + return; + } + resolvedExecutions[i] = execution; + } + expression.setResolvedChildren(resolvedExecutions); } - GuardParser parser = new GuardParser(context, node, source, null); - List matchingGuards = parser.parse(guardMethods); + + GuardParser parser = new GuardParser(context, node, source, expression); + List matchingGuards = parser.parse(availableGuards); if (!matchingGuards.isEmpty()) { GuardData guard = matchingGuards.get(0); // use the shared instance of the guard data - for (GuardData guardData : availableGuards) { - if (guardData.getMethod() == guard.getMethod()) { - expression.setGuard(guardData); - return; - } - } - throw new AssertionError("Should not reach here."); + expression.setResolvedGuard(guard); } else { MethodSpec spec = parser.createSpecification(source.getMethod(), source.getMarkerAnnotation()); spec.applyTypeDefinitions("types"); diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java Mon Aug 18 18:41:16 2014 +0200 @@ -424,16 +424,15 @@ } public boolean isTypeGuardUsedInAnyGuardBelow(ProcessorContext context, SpecializationData source, TypeGuard typeGuard) { + NodeExecutionData execution = source.getNode().getChildExecutions().get(typeGuard.getSignatureIndex()); for (GuardExpression guard : guards) { - Parameter guardParameter = guard.getResolvedGuard().getSignatureParameter(typeGuard.getSignatureIndex()); - if (guardParameter == null) { - // guardParameters are optional - continue; - } + List guardParameters = guard.getResolvedGuard().findByExecutionData(execution); Parameter sourceParameter = source.getSignatureParameter(typeGuard.getSignatureIndex()); - if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { - return true; + for (Parameter guardParameter : guardParameters) { + if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) { + return true; + } } } diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Mon Aug 18 17:44:42 2014 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -84,7 +84,7 @@ List guardDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards"); List guardExpressions = new ArrayList<>(); for (String guardDef : guardDefs) { - guardExpressions.add(new GuardExpression(guardDef)); + guardExpressions.add(new GuardExpression(guardDef, true)); } specialization.setGuards(guardExpressions); diff -r d6c002f4d2a9 -r 2db61eddcb97 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java Mon Aug 18 18:41:16 2014 +0200 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2012, 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.truffle.dsl.processor.parser; + +import java.lang.annotation.*; +import java.util.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +import com.oracle.truffle.dsl.processor.*; +import com.oracle.truffle.dsl.processor.java.*; +import com.oracle.truffle.dsl.processor.model.*; + +public abstract class TemplateMethodParser { + + protected final T template; + private final ProcessorContext context; + private final MethodSpecParser parser; + + private boolean parseNullOnError; + + public TemplateMethodParser(ProcessorContext context, T template) { + this.template = template; + this.context = context; + this.parser = new MethodSpecParser(template); + } + + public void setParseNullOnError(boolean parseNullOnError) { + this.parseNullOnError = parseNullOnError; + } + + public boolean isParseNullOnError() { + return parseNullOnError; + } + + public MethodSpecParser getParser() { + return parser; + } + + public ProcessorContext getContext() { + return context; + } + + public TypeSystemData getTypeSystem() { + return template.getTypeSystem(); + } + + public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror); + + public abstract E create(TemplateMethod method, boolean invalid); + + public abstract boolean isParsable(ExecutableElement method); + + public Class getAnnotationType() { + return null; + } + + public final List parse(List elements) { + List methods = new ArrayList<>(); + methods.addAll(ElementFilter.methodsIn(elements)); + + List parsedMethods = new ArrayList<>(); + boolean valid = true; + int naturalOrder = 0; + for (ExecutableElement method : methods) { + if (!isParsable(method)) { + continue; + } + + Class annotationType = getAnnotationType(); + AnnotationMirror mirror = null; + if (annotationType != null) { + mirror = ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType); + } + + E parsedMethod = parse(naturalOrder, method, mirror); + + if (method.getModifiers().contains(Modifier.PRIVATE) && parser.isEmitErrors()) { + parsedMethod.addError("Method annotated with @%s must not be private.", getAnnotationType().getSimpleName()); + parsedMethods.add(parsedMethod); + valid = false; + continue; + } + + if (parsedMethod != null) { + parsedMethods.add(parsedMethod); + } else { + valid = false; + } + naturalOrder++; + } + Collections.sort(parsedMethods); + + if (!valid && isParseNullOnError()) { + return null; + } + return parsedMethods; + } + + private E parse(int naturalOrder, ExecutableElement method, AnnotationMirror annotation) { + MethodSpec methodSpecification = createSpecification(method, annotation); + if (methodSpecification == null) { + return null; + } + + TemplateMethod templateMethod = parser.parse(methodSpecification, method, annotation, naturalOrder); + if (templateMethod != null) { + return create(templateMethod, templateMethod.hasErrors()); + } + return null; + } + + public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List parameterTypes) { + TemplateMethod method = parser.parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes); + if (method != null) { + return create(method, method.hasErrors()); + } + return null; + } +}