Package org.jnode.shell.syntax

Source Code of org.jnode.shell.syntax.RepeatSyntax

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.shell.syntax;

import org.jnode.nanoxml.XMLElement;


/**
* A RepeatedSyntax instance specifies that a given 'child' syntax may be repeated
* a number of times as determined by the constructor arguments.  These allow you
* to specify a minimum and/or maximum bound on the number of repetitions, and to
* specify whether the syntax is 'eager' (i.e. matching as many instances as possible) or
* 'lazy' (i.e. matching as few instances as possible).
*
* @author crawley@jnode.org
*/
public class RepeatSyntax extends GroupSyntax {
   
    private final Syntax child;
    private final int minCount;
    private final int maxCount;
    private final boolean eager;

    /**
     * Construct syntax with caller-specified repetition count range and a label.
     *
     * @param label this Syntax's label
     * @param child the child Syntax that may be repeated.
     * @param minCount the minimum number of occurrences required.
     * @param maxCount the maximum number of occurrences allowed.
     * @param eager if {@code true}, the syntax matches as many child instances
     *     as possible, subject to the 'maxCount' constraint.
     * @param description the description for this syntax
     */
    public RepeatSyntax(String label, Syntax child, int minCount, int maxCount,
            boolean eager, String description) {
        super(label, description, child);
        if (minCount < 0 || maxCount < minCount) {
            throw new IllegalArgumentException("bad min/max counts");
        }
        this.child = child;
        this.minCount = minCount;
        this.maxCount = maxCount;
        this.eager = eager;
    }
   
    /**
     * Construct syntax with caller-specified repetition count range and a label.
     *
     * @param label this Syntax's label
     * @param child the child Syntax that may be repeated.
     * @param minCount the minimum number of occurrences required.
     * @param maxCount the maximum number of occurrences allowed.
     */
    public RepeatSyntax(String label, Syntax child, int minCount, int maxCount) {
        this(label, child, minCount, maxCount, false, null);
    }

    /**
     * Construct syntax with caller-specified repetition count range.
     *
     * @param child the child Syntax that may be repeated.
     * @param minCount the minimum number of occurrences required.
     * @param maxCount the maximum number of occurrences allowed.
     */
    public RepeatSyntax(Syntax child, int minCount, int maxCount) {
        this(null, child, minCount, maxCount, false, null);
    }
   
    /**
     * Construct syntax which can repeated from zero to many times.
     *
     * @param child the child Syntax that may be repeated.
     */
    public RepeatSyntax(Syntax child) {
        this(null, child, 0, Integer.MAX_VALUE, false, null);
    }
   
    @Override
    public String toString() {
        return "RepeatedSyntax{" + super.toString() +
            "minCount=" + minCount + ", maxCount=" + maxCount + "}";
    }

    @Override
    public MuSyntax prepare(ArgumentBundle bundle) {
        // The result of 'prepare' is rather ugly for the unusual cases.  One
        // alternative would be to add new MuSyntax constructs, and that would
        // make the Mu parsing code more complicated.  Another might be to
        // create a special Argument class that would operate as a counter.
        String label = MuSyntax.genLabel();
        MuSyntax childSyntax = child.prepare(bundle);
        MuSyntax res, tail;
        if (maxCount == Integer.MAX_VALUE) {
            if (eager) {
                tail = new MuAlternation(label,
                        new MuSequence(childSyntax, new MuBackReference(label)),
                        null);
            } else {
                tail = new MuAlternation(label,
                        null,
                        new MuSequence(childSyntax, new MuBackReference(label)));
            }
        } else {
            int tailCount = maxCount - minCount;
            tail = null;
            while (tailCount-- > 0) {
                if (eager) {
                    tail = new MuAlternation(
                            (tail == null) ? childSyntax : new MuSequence(childSyntax, tail),
                            null);
                } else {
                    tail = new MuAlternation(
                            (MuSyntax) null,
                            (tail == null) ? childSyntax : new MuSequence(childSyntax, tail));
                }
            }
        }
        if (minCount == 0) {
            res = tail;
        } else if (minCount == 1) {
            res = (tail == null) ? childSyntax : new MuSequence(childSyntax, tail);
        } else {
            MuSyntax[] sequence = new MuSyntax[minCount];
            for (int i = 0; i < minCount; i++) {
                sequence[i] = childSyntax;
            }
            res = (tail == null) ? new MuSequence(sequence) :
                new MuSequence(new MuSequence(sequence), tail);
        }
        if (maxCount == Integer.MAX_VALUE) {
            res.resolveBackReferences();
        }
        return res;
    }

    @Override
    public String format(ArgumentBundle bundle) {
        if (minCount == 0) {
            if (maxCount == Integer.MAX_VALUE) {
                return "[ " + child.format(bundle) + " ... ]";
            } else if (maxCount == 1) {
                return "[ " + child.format(bundle) + "]";
            } else {
                return "[ " + child.format(bundle) + " ..." + maxCount + " ]";
            }
        } else if (minCount == 1) {
            if (maxCount == Integer.MAX_VALUE) {
                return child.format(bundle) + " ...";
            } else if (maxCount == 1) {
                return child.format(bundle);
            } else {
                return child.format(bundle) + " ..." + maxCount;
            }
        } else {
            if (maxCount == Integer.MAX_VALUE) {
                return child.format(bundle) + " " + minCount + "...";
            } else {
                return child.format(bundle) + " " + minCount + "..." + maxCount;
            }
        }
    }
   


    @Override
    public XMLElement toXML() {
        XMLElement element = basicElement("repeat");
        if (minCount > 0) {
            element.setAttribute("minCount", minCount);
        }
        if (maxCount != Integer.MAX_VALUE) {
            element.setAttribute("maxCount", maxCount);
        }
        if (eager) {
            element.setAttribute("eager", "true");
        }
        return element;
    }

}
TOP

Related Classes of org.jnode.shell.syntax.RepeatSyntax

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.