/** * Copyright 2011-2017 Asakusa Framework Team. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.asakusafw.operator.model; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.type.TypeMirror; import com.asakusafw.operator.description.ValueDescription; /** * Represents an operator's semantics for Asakusa DSL. */ public class OperatorDescription implements AttributeContainer { private final Document document; private final List<Node> parameters; private final List<Node> outputs; private final List<ValueDescription> attributes; private ExecutableElement support; /** * Creates a new instance. * @param document the document about the operator * @param parameters parameters (input datasets/arguments) * @param outputs output datasets * @throws IllegalArgumentException if some parameters were {@code null} */ public OperatorDescription( Document document, List<? extends Node> parameters, List<? extends Node> outputs) { this(document, parameters, outputs, Collections.emptyList()); } /** * Creates a new instance. * @param document the document about the operator * @param parameters parameters (input datasets/arguments) * @param outputs output datasets * @param attributes operator attributes * @throws IllegalArgumentException if some parameters were {@code null} */ public OperatorDescription( Document document, List<? extends Node> parameters, List<? extends Node> outputs, List<? extends ValueDescription> attributes) { Objects.requireNonNull(document, "document must not be null"); //$NON-NLS-1$ Objects.requireNonNull(parameters, "parameters must not be null"); //$NON-NLS-1$ Objects.requireNonNull(outputs, "outputs must not be null"); //$NON-NLS-1$ Objects.requireNonNull(attributes, "attributes must not be null"); //$NON-NLS-1$ this.document = document; this.parameters = new ArrayList<>(parameters); this.outputs = new ArrayList<>(outputs); this.attributes = new ArrayList<>(attributes); } /** * Returns the documents about the operator. * @return the document */ public Document getDocument() { return document; } /** * Returns the parameters, which include input datasets and arguments. * @return the parameters */ public List<Node> getParameters() { return parameters; } /** * Returns the input datasets. * @return the inputs */ public List<Node> getInputs() { List<Node> results = new ArrayList<>(); for (Node node : parameters) { if (node.getKind() == Node.Kind.INPUT) { results.add(node); } } return results; } /** * Returns the input arguments. * @return the arguments */ public List<Node> getArguments() { List<Node> results = new ArrayList<>(); for (Node node : parameters) { if (node.getKind() == Node.Kind.DATA) { results.add(node); } } return results; } /** * Returns the output datasets. * @return the outputs */ public List<Node> getOutputs() { return outputs; } /** * Returns input/output/arguments. * @return all node elements */ public List<Node> getAllNodes() { List<Node> results = new ArrayList<>(); results.addAll(parameters); results.addAll(outputs); return results; } @Override public List<ValueDescription> getAttributes() { return attributes; } /** * Returns the support method for this operator. * @return the support method for this operator, or {@code null} if this operator does not have support methods */ public ExecutableElement getSupport() { return support; } /** * Sets the support method for this operator. * @param newValue the support method * @return this */ public OperatorDescription withSupport(ExecutableElement newValue) { this.support = newValue; return this; } /** * Represents reference to original declaration. */ public abstract static class Reference { /** * Creates a new instance. * @return the created instance. */ public static Reference method() { return new MethodReference(); } /** * Creates a new instance. * @return the created instance. */ public static Reference returns() { return new ReturnReference(); } /** * Creates a new instance. * @param location the parameter index (0-origin) * @return the created instance. */ public static ParameterReference parameter(int location) { return new ParameterReference(location); } /** * Creates a new instance. * @param info operator specific information * @return the created instance. * @throws IllegalArgumentException if some parameters were {@code null} */ public static SpecialReference special(String info) { return new SpecialReference(info); } /** * Returns the kind of this reference. * @return the kind */ public abstract Kind getKind(); @Override public int hashCode() { return getKind().hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Reference other = (Reference) obj; if (getKind() != other.getKind()) { return false; } return true; } /** * Represents kind of references. */ public enum Kind { /** * Represents method declaration, or synopsis block in documentation comment. */ METHOD, /** * Represents a method parameter, or parameter block in documentation comment. */ PARAMETER, /** * Represents a method return type, or return block in documentation comment. */ RETURN, /** * Represents an operator specific reference. */ SPECIAL, } } /** * Represents a reference to body of declaration. */ public static final class MethodReference extends Reference { @Override public Kind getKind() { return Kind.METHOD; } } /** * Represents a reference to a parameter declaration. */ public static final class ParameterReference extends Reference { private final int location; /** * Creates a new instance. * @param location the parameter location (0-origin) */ public ParameterReference(int location) { this.location = location; } @Override public Kind getKind() { return Kind.PARAMETER; } /** * Returns the location of parameter (0-origin). * @return the location */ public int getLocation() { return location; } @Override public int hashCode() { final int prime = 31; int result = getKind().hashCode(); result = prime * result + location; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ParameterReference other = (ParameterReference) obj; if (location != other.location) { return false; } return true; } } /** * Represents a reference to return type/value of declaration. */ public static final class ReturnReference extends Reference { @Override public Kind getKind() { return Kind.RETURN; } } /** * Represents an operator specific reference. */ public static final class SpecialReference extends Reference { private final String info; /** * Creates a new instance. * @param info reference info * @throws IllegalArgumentException if some parameters were {@code null} */ public SpecialReference(String info) { this.info = Objects.requireNonNull(info, "info must not be null"); //$NON-NLS-1$ } @Override public Kind getKind() { return Kind.SPECIAL; } /** * Return the operator specific information. * @return the operator specific information */ public String getInfo() { return info; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + info.hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } SpecialReference other = (SpecialReference) obj; if (!info.equals(other.info)) { return false; } return true; } } /** * Represents document. */ public abstract static class Document { /** * Creates a new instance. * @param text text of this document * @return the created instance * @throws IllegalArgumentException if some parameters were {@code null} */ public static TextDocument text(String text) { return new TextDocument(text); } /** * Creates a new instance. * @param reference reference description * @return the created instance * @throws IllegalArgumentException if some parameters were {@code null} */ public static ReferenceDocument reference(Reference reference) { return new ReferenceDocument(reference); } /** * Creates a new instance. * @param element the target element * @return the created instance * @throws IllegalArgumentException if some parameters were {@code null} */ public static ExternalDocument external(Element element) { return new ExternalDocument(element); } /** * Returns the kind of this document. * @return the kind */ public abstract Kind getKind(); /** * Represents document kind. */ public enum Kind { /** * Just text. */ TEXT, /** * Reference to other document. */ REFERENCE, /** * The external element. */ EXTERNAL, } } /** * Represents a document with text. */ public static class TextDocument extends Document { private final String text; /** * Creates a new instance. * @param text text of this document */ public TextDocument(String text) { this.text = text; } /** * Return the text of this document. * @return the text, or {@code null} if not declared */ public String getText() { return text; } @Override public Kind getKind() { return Kind.TEXT; } } /** * Represents a document with reference. */ public static class ReferenceDocument extends Document { private final Reference reference; /** * Creates a new instance. * @param reference reference description * @throws IllegalArgumentException if some parameters were {@code null} */ public ReferenceDocument(Reference reference) { this.reference = Objects.requireNonNull(reference, "reference must not be null"); //$NON-NLS-1$ } @Override public Kind getKind() { return Kind.REFERENCE; } /** * Returns the reference which represents the document location in original method declaration. * @return the reference */ public Reference getReference() { return reference; } } /** * Represents a document provided by an external element. */ public static class ExternalDocument extends Document { private final Element element; /** * Creates a new instance. * @param element the external element */ public ExternalDocument(Element element) { this.element = Objects.requireNonNull(element); } @Override public Kind getKind() { return Kind.EXTERNAL; } /** * Returns the element. * @return the element */ public Element getElement() { return element; } } /** * Represents input/output/argument. * @since 0.9.0 * @version 0.9.1 */ public static final class Node implements AttributeContainer { private final Kind kind; private final String name; private final Document document; private final TypeMirror type; private final Reference reference; private volatile KeyMirror key; private volatile ExternMirror extern; private final List<ValueDescription> attributes = new ArrayList<>(); /** * Creates a new instance. * @param kind the kind of this node * @param name the name of this node * @param document the document for this node * @param type the type of this node * @param reference the reference to original declaration * @throws IllegalArgumentException if some parameters were {@code null} */ public Node(Kind kind, String name, Document document, TypeMirror type, Reference reference) { this.kind = Objects.requireNonNull(kind, "kind must not be null"); //$NON-NLS-1$ this.name = Objects.requireNonNull(name, "name must not be null"); //$NON-NLS-1$ this.document = Objects.requireNonNull(document, "document must not be null"); //$NON-NLS-1$ this.type = Objects.requireNonNull(type, "type must not be null"); //$NON-NLS-1$ this.reference = Objects.requireNonNull(reference, "reference must not be null"); //$NON-NLS-1$ } /** * Returns the kind of this node. * @return the kind */ public Kind getKind() { return kind; } /** * Returns the name of this node. * @return the name */ public String getName() { return name; } /** * Returns the document for this node. * @return the document */ public Document getDocument() { return document; } /** * Returns the type of this node. * @return the type */ public TypeMirror getType() { return type; } /** * Returns the reference to original component. * @return the reference to original component */ public Reference getReference() { return reference; } /** * Sets the key mirror. * @param newValue the key mirror * @return this */ public Node withKey(KeyMirror newValue) { this.key = newValue; return this; } /** * Returns the key mirror of this node. * @return the key mirror, or {@code null} if this does not have any keys */ public KeyMirror getKey() { return key; } /** * Sets the extern mirror. * @param newValue the extern mirror * @return this */ public Node withExtern(ExternMirror newValue) { this.extern = newValue; return this; } /** * Returns the extern mirror of this node. * @return the extern mirror, or {@code null} if this does not have any externs */ public ExternMirror getExtern() { return extern; } /** * Adds an attribute. * @param attribute the attribute * @return this */ public Node withAttribute(ValueDescription attribute) { this.attributes.add(attribute); return this; } @Override public List<ValueDescription> getAttributes() { return Collections.unmodifiableList(attributes); } @Override public String toString() { return String.format("%s(%s)", getKind(), getName()); //$NON-NLS-1$ } /** * Represents parameter kind. */ public enum Kind { /** * dataset input. */ INPUT, /** * dataset output. */ OUTPUT, /** * Constant expression. */ DATA, } } }