/* * This file is part of Skript. * * Skript is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Skript 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 for more details. * * You should have received a copy of the GNU General Public License * along with Skript. If not, see <http://www.gnu.org/licenses/>. * * * Copyright 2011-2014 Peter Güttinger * */ package ch.njol.skript.lang; import java.util.Iterator; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.ScriptLoader; import ch.njol.skript.Skript; import ch.njol.skript.classes.Changer; import ch.njol.skript.classes.Changer.ChangeMode; import ch.njol.skript.classes.Changer.ChangerUtils; import ch.njol.skript.classes.Converter; import ch.njol.skript.conditions.CondIsSet; import ch.njol.skript.lang.util.ConvertedExpression; import ch.njol.skript.lang.util.SimpleExpression; import ch.njol.skript.log.ErrorQuality; import ch.njol.util.Checker; /** * Represents an expression. Expressions are used within conditions, effects and other expressions. * * @author Peter Güttinger * @see Skript#registerExpression(Class, Class, ExpressionType, String...) * @see SimpleExpression * @see SyntaxElement */ public interface Expression<T> extends SyntaxElement, Debuggable { /** * Get the single value of this expression. * <p> * This method may only return null if it always returns null for the given event, i.e. it is equivalent to getting a random element out of {@link #getAll(Event)} or null iff * that array is empty. * <p> * Do not use this in conditions, use {@link #check(Event, Checker, boolean)} instead. * * @param e The event * @return The value or null if this expression doesn't have any value for the event * @throws UnsupportedOperationException (optional) if this was called on a non-single expression */ @Nullable public T getSingle(final Event e); /** * Get all the values of this expression. The returned array is empty if this expression doesn't have any values for the given event. * <p> * The returned array must not contain any null values. * <p> * Do not use this in conditions, use {@link #check(Event, Checker, boolean)} instead. * * @param e The event * @return An array of values of this expression which must neither be null nor contain nulls, and which must not be an internal array. */ public T[] getArray(final Event e); /** * Gets all possible return values of this expression, i.e. it returns the same as {@link #getArray(Event)} if {@link #getAnd()} is true, otherwise all possible values for * {@link #getSingle(Event)}. * * @param e The event * @return An array of all possible values of this expression for the given event which must neither be null nor contain nulls, and which must not be an internal array. */ public T[] getAll(final Event e); /** * @return true if this expression will ever only return one value at most, false if it can return multiple values. */ public abstract boolean isSingle(); /** * Checks this expression against the given checker. This is the normal version of this method and the one which must be used for simple checks, * or as the innermost check of nested checks. * <p> * Usual implementation (may differ, e.g. may return false for nonexistent values independent of <tt>negated</tt>): * * <pre> * return negated ^ {@link #check(Event, Checker)}; * </pre> * * @param e The event * @param c A checker * @param negated The cheking condition's negated state. This is used to invert the output of the checker if set to true (i.e. <tt>negated ^ checker.check(...)</tt>) * @return Whether this expression matches or doesn't match the given checker depending on the condition's negated state. * @see SimpleExpression#check(Object[], Checker, boolean, boolean) */ public boolean check(final Event e, final Checker<? super T> c, final boolean negated); /** * Checks this expression against the given checker. This method must only be used around other checks, use {@link #check(Event, Checker, boolean)} for a simple ckeck or the * innermost check of a nested check. * * @param e The event * @param c A checker * @return Whether this expression matches the given checker * @see SimpleExpression#check(Object[], Checker, boolean, boolean) */ public boolean check(final Event e, final Checker<? super T> c); /** * Tries to convert this expression to the given type. This method can print an error prior to returning null to specify the cause. * <p> * Please note that expressions whose {@link #getReturnType() returnType} is not Object will not be parsed at all for a certain class if there's no converter from the * expression's returnType to the desired class. Thus this method should only be overridden if this expression's returnType is Object. * <p> * The returned expression should delegate this method to the original expression's method to prevent excessive converted expression chains (see also * {@link ConvertedExpression}). * * @param to The desired return type of the returned expression * @return Expression with the desired return type or null if the expression can't be converted to the given type. Returns the expression itself if it already returns the * desired type. * @see Converter * @see ConvertedExpression */ @Nullable public <R> Expression<? extends R> getConvertedExpression(final Class<R>... to); /** * Gets the return type of this expression. * * @return A supertype of any objects returned by {@link #getSingle(Event)} and the component type of any arrays returned by {@link #getArray(Event)} */ public abstract Class<? extends T> getReturnType(); /** * Returns true if this expression returns all possible values, false if it only returns some of them. * <p> * This method significantly influences {@link #check(Event, Checker)}, {@link #check(Event, Checker, boolean)} and {@link CondIsSet} and thus breaks conditions that use this * expression if it returns a wrong value. * <p> * This method must return true if this is a {@link #isSingle() single} expression. // TODO make this method irrelevant for single expressions * * @return Whether this expression returns all values at once or only part of them. */ public boolean getAnd(); /** * Sets the time of this expression, i.e. whether the returned value represents this expression before or after the event. * <p> * This method will <b>not</b> be called if this expression is <i>guaranteed</i> to be used after a delay (an error will be printed immediately), but <b>will</b> be called if * it only <i>can be</i> after a delay (e.g. if the preceding delay is in an if or a loop) as well as if there's no delay involved. * <p> * If this method returns false the expression will be discarded and an error message is printed. Custom error messages must be of {@link ErrorQuality#SEMANTIC_ERROR} to be * printed (NB: {@link Skript#error(String)} always creates semantic errors). * * @param time -1 for past or 1 for future. 0 is never passed to this method as it represents the default state. * @return Whether this expression has distinct time states, e.g. a player never changes but a block can. This should be sensitive for the event (using * {@link ScriptLoader#isCurrentEvent(Class)}). * @see SimpleExpression#setTime(int, Class, Expression...) * @see SimpleExpression#setTime(int, Expression, Class...) * @see ScriptLoader#isCurrentEvent(Class...) */ public boolean setTime(int time); /** * @return The value passed to {@link #setTime(int)} or 0 if it was never changed. * @see #setTime(int) */ public int getTime(); /** * Returns whether this value represents the default value of its type for the event, i.e. it can be replaced with a call to event.getXyz() if one knows the event & value type. * <p> * This method might be removed in the future as it's better to check whether value == event.getXyz() for every value an expression returns. * * @return Whether is is the return types' default expression */ public boolean isDefault(); /** * Returns the same as {@link #getArray(Event)} but as an iterator. This method should be overriden by expressions intended to be looped to increase performance. * * @param e The event * @return An iterator to iterate over all values of this expression which may be empty and/or null, but must not return null elements. */ @Nullable public Iterator<? extends T> iterator(Event e); /** * Checks whether the given 'loop-...' expression should match this loop, e.g. loop-block matches any loops that loop through blocks and loop-argument matches an * argument loop. * <p> * You should usually just return false as e.g. loop-block will automatically match the expression if its returnType is Block or a subtype of it. * * @param s The entered string * @return Whether this loop matches the given string */ public boolean isLoopOf(String s); /** * Returns the original expression that was parsed, i.e. without any conversions done. * <p> * This method is undefined for simplified expressions. * * @return The unconverted source expression of this expression or this expression itself if it was never converted. */ public Expression<?> getSource(); /** * Simplifies the expression, e.g. if it only contains literals the expression may be simplified to a literal, and wrapped expressions are unwrapped. * <p> * After this method was used the toString methods are likely not useful anymore. * <p> * This method is not yet used but will be used to improve efficiency in the future. * * @return A reference to a simpler version of this expression. Can change this expression directly and return itself if applicable, i.e. no references to the expression before * this method call should be kept! */ public Expression<? extends T> simplify(); /** * Tests whether this expression supports the given mode, and if yes what type it expects the <code>delta</code> to be. * <p> * <b>Use {@link ChangerUtils#acceptsChange(Expression, ChangeMode, Class...)} to test whether an expression supports changing</b>, don't directly use this method! * <p> * Please note that if a changer is registered for this expression's {@link #getReturnType() returnType} this method does not have to be overridden. If you override it though * make sure to return <tt>super.acceptChange(mode)</tt>, and to handle the appropriate ChangeMode(s) in {@link #change(Event, Object[], ChangeMode)} with * <tt>super.change(...)</tt>. * <p> * Unlike {@link Changer#acceptChange(ChangeMode)} this method may print errors. * * @param mode * @return An array of types that {@link #change(Event, Object[], ChangeMode)} accepts as its <code>delta</code> parameter (which can be arrays to denote that multiple of * that type are accepted), or null if the given mode is not supported. For {@link ChangeMode#DELETE} and {@link ChangeMode#RESET} this can return any non-null array to * mark them as supported. */ @Nullable public Class<?>[] acceptChange(ChangeMode mode); /** * Changes the expression's value by the given amount. This will only be called on supported modes and with the desired <code>delta</code> type as returned by * {@link #acceptChange(ChangeMode)} * * @param e * @param delta An array with one or more instances of one or more of the the classes returned by {@link #acceptChange(ChangeMode)} for the given change mode (null for * {@link ChangeMode#DELETE} and {@link ChangeMode#RESET}). <b>This can be a Object[], thus casting is not allowed.</b> * @param mode * @throws UnsupportedOperationException (optional) - If this method was called on an unsupported ChangeMode. */ public void change(Event e, final @Nullable Object[] delta, final ChangeMode mode); }