All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jruby.truffle.parser.ast.ParseNode Maven / Gradle / Ivy

The newest version!
/*
 ***** BEGIN LICENSE BLOCK *****
 * Version: EPL 1.0/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Eclipse Public
 * License Version 1.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.eclipse.org/legal/epl-v10.html
 *
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 *
 * Copyright (C) 2001-2002 Jan Arne Petersen 
 * Copyright (C) 2001-2002 Benoit Cerrina 
 * Copyright (C) 2002-2004 Anders Bengtsson 
 * Copyright (C) 2004 Thomas E Enebo 
 * Copyright (C) 2004 Stefan Matthias Aust 
 * Copyright (C) 2006 Thomas Corbat 
 * 
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the EPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the EPL, the GPL or the LGPL.
 ***** END LICENSE BLOCK *****/
package org.jruby.truffle.parser.ast;

import org.jruby.truffle.language.SourceIndexLength;
import org.jruby.truffle.parser.ast.types.INameNode;
import org.jruby.truffle.parser.ast.visitor.NodeVisitor;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Base class for all Nodes in the AST
 */
public abstract class ParseNode {
    // We define an actual list to get around bug in java integration (1387115)
    static final List EMPTY_LIST = new ArrayList<>();

    private int sourceCharIndex;
    private int sourceLength;

    // Does this node contain a node which is an assignment.  We can use this knowledge when emitting IR
    // instructions to do more or less depending on whether we have to cope with scenarios like:
    //    a = 1; [a, a = 2];
    // in IR, we can see that ArrayParseNode contains an assignment and emit its individual elements differently
    // so that the two values of a end up being different.
    protected boolean containsVariableAssignment;
    protected boolean newline;

    public ParseNode(SourceIndexLength position, boolean containsAssignment) {
        if (position == null) {
            sourceCharIndex = -1;
            sourceLength = -1;
        } else {
            sourceCharIndex = position.getCharIndex();
            sourceLength = position.getLength();
        }
        this.containsVariableAssignment = containsAssignment;
    }

    public void setNewline() {
        this.newline = true;
    }

    public boolean isNewline() {
        return newline;
    }

    /**
     * Location of this node within the source
     */
    public SourceIndexLength getPosition() {
        return new SourceIndexLength(sourceCharIndex, sourceLength);
    }

    public void setPosition(SourceIndexLength position) {
        sourceCharIndex = position.getCharIndex();
        sourceLength = position.getLength();
    }
    
    public abstract  T accept(NodeVisitor visitor);
    public abstract List childNodes();

    protected static List createList(ParseNode node) {
        return Collections.singletonList(node);
    }

    protected static List createList(ParseNode node1, ParseNode node2) {
        ArrayList list = new ArrayList<>(2);

        list.add(node1);
        list.add(node2);

        return list;
    }

    protected static List createList(ParseNode node1, ParseNode node2, ParseNode node3) {
        ArrayList list = new ArrayList<>(3);

        list.add(node1);
        list.add(node2);
        list.add(node3);

        return list;
    }

    protected static List createList(ParseNode... nodes) {
        ArrayList list = new ArrayList<>(nodes.length);
        
        for (ParseNode node: nodes) {
            if (node != null) list.add(node);
        }
        
        return list;
    }

    @Override
    public String toString() {
        return toString(false, 0);
    }

    public String toString(boolean indent, int indentation) {
        if (this instanceof InvisibleNode) return "";

        StringBuilder builder = new StringBuilder(60);

        if (indent) indent(indentation, builder);

        builder.append("(").append(getNodeName());

        String moreState = toStringInternal();

        if (moreState != null) builder.append("[").append(moreState).append("]");

        if (this instanceof INameNode) builder.append(":").append(((INameNode) this).getName());

        if (!childNodes().isEmpty() && indent) builder.append("\n");

        for (ParseNode child : childNodes()) {
            if (!indent) builder.append(", ");

            if (child == null) {
                if (indent) indent(indentation + 1, builder);

                builder.append("null");
            } else {
                if (indent && child instanceof NilImplicitParseNode) {
                    indent(indentation + 1, builder);

                    builder.append(child.getClass().getSimpleName());
                } else {
                    builder.append(child.toString(indent, indentation + 1));
                }
            }

            if (indent) builder.append("\n");
        }

        if (!childNodes().isEmpty() && indent) indent(indentation, builder);

        builder.append(")");

        return builder.toString();
    }

    /**
     * Overridden by nodes that have additional internal state to be displated in toString.
     *
     * For nodes that have it, name is handled separately, by implementing INameNode.
     *
     * Child nodes are handled via iterating #childNodes.
     *
     * @return A string representing internal node state, or null if none.
     */
    protected String toStringInternal() {
        return null;
    }

    private static void indent(int indentation, StringBuilder builder) {
        for (int n = 0; n < indentation; n++) {
            builder.append("  ");
        }
    }

    protected String getNodeName() {
        String name = getClass().getName();
        return name.substring(name.lastIndexOf('.') + 1);
    }

    /**
     * @return the nodeId
     */
    public abstract NodeType getNodeType();

    /**
     * Whether the node evaluates to nil and has no side effects.
     *
     * @return true if nil, false otherwise
     */
    public boolean isNil() {
        return false;
    }

    /**
     * Check whether the given node is considered always "defined" or whether it
     * has some form of definition check.
     *
     * @return Whether the type of node represents a possibly undefined construct
     */
    public boolean needsDefinitionCheck() {
        return true;
    }

    /**
     * Does this node or one of its children contain an assignment?
     */
    public boolean containsVariableAssignment() {
        return containsVariableAssignment;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy