Package ch.njol.skript.conditions

Source Code of ch.njol.skript.conditions.CondCompare

/*
*   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.conditions;

import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.Skript;
import ch.njol.skript.classes.Comparator;
import ch.njol.skript.classes.Comparator.Relation;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.ExpressionList;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.log.ErrorQuality;
import ch.njol.skript.log.RetainingLogHandler;
import ch.njol.skript.log.SkriptLogger;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.registrations.Comparators;
import ch.njol.skript.util.Patterns;
import ch.njol.skript.util.Utils;
import ch.njol.util.Checker;
import ch.njol.util.Kleenean;

/**
* @author Peter Güttinger
*/
@Name("Comparison")
@Description({"A very general condition, it simply compares two values. Usually you can only compare for equality (e.g. block is/isn't of &lt;type&gt;), " +
    "but some values can also be compared using greater than/less than. In that case you can also test for whether an object is between two others.",
    "Note: This is the only element where not all patterns are shown. It has actually another two sets of similar patters, " +
        "but with <code>(was|were)</code> or <code>will be</code> instead of <code>(is|are)</code> respectively, " +
        "which check different <a href='../expressions/#ExprTimeState'>time states</a> of the first expression."})
@Examples({"the clicked block is a stone slab or a double stone slab",
    "time in the player's world is greater than 8:00",
    "the creature is not an enderman or an ender dragon"})
@Since("1.0")
public class CondCompare extends Condition {
 
  private final static Patterns<Relation> patterns = new Patterns<Relation>(new Object[][] {
      {"(1¦neither|) %objects% ((is|are)(|2¦(n't| not|4¦ neither)) ((greater|more|higher|bigger|larger) than|above)|\\>) %objects%", Relation.GREATER},
      {"(1¦neither|) %objects% ((is|are)(|2¦(n't| not|4¦ neither)) (greater|more|higher|bigger|larger|above) [than] or (equal to|the same as)|\\>=) %objects%", Relation.GREATER_OR_EQUAL},
      {"(1¦neither|) %objects% ((is|are)(|2¦(n't| not|4¦ neither)) ((less|smaller) than|below)|\\<) %objects%", Relation.SMALLER},
      {"(1¦neither|) %objects% ((is|are)(|2¦(n't| not|4¦ neither)) (less|smaller|below) [than] or (equal to|the same as)|\\<=) %objects%", Relation.SMALLER_OR_EQUAL},
      {"(1¦neither|) %objects% (2¦)((is|are) (not|4¦neither)|isn't|aren't|!=) [equal to] %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects% (is|are|=) [(equal to|the same as)] %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects% (is|are) between %objects% and %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects% (2¦)(is not|are not|isn't|aren't) between %objects% and %objects%", Relation.EQUAL},
     
      {"(1¦neither|) %objects@-1% (was|were)(|2¦(n't| not|4¦ neither)) ((greater|more|higher|bigger|larger) than|above) %objects%", Relation.GREATER},
      {"(1¦neither|) %objects@-1% (was|were)(|2¦(n't| not|4¦ neither)) (greater|more|higher|bigger|larger|above) [than] or (equal to|the same as) %objects%", Relation.GREATER_OR_EQUAL},
      {"(1¦neither|) %objects@-1% (was|were)(|2¦(n't| not|4¦ neither)) ((less|smaller) than|below) %objects%", Relation.SMALLER},
      {"(1¦neither|) %objects@-1% (was|were)(|2¦(n't| not|4¦ neither)) (less|smaller|below) [than] or (equal to|the same as) %objects%", Relation.SMALLER_OR_EQUAL},
      {"(1¦neither|) %objects@-1% (2¦)((was|were) (not|4¦neither)|wasn't|weren't) [equal to] %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@-1% (was|were) [(equal to|the same as)] %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@-1% (was|were) between %objects% and %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@-1% (2¦)(was not|were not|wasn't|weren't) between %objects% and %objects%", Relation.EQUAL},
     
      {"(1¦neither|) %objects@1% (will be|2¦(will (not|4¦neither) be|won't be)) ((greater|more|higher|bigger|larger) than|above) %objects%", Relation.GREATER},
      {"(1¦neither|) %objects@1% (will be|2¦(will (not|4¦neither) be|won't be)) (greater|more|higher|bigger|larger|above) [than] or (equal to|the same as) %objects%", Relation.GREATER_OR_EQUAL},
      {"(1¦neither|) %objects@1% (will be|2¦(will (not|4¦neither) be|won't be)) ((less|smaller) than|below) %objects%", Relation.SMALLER},
      {"(1¦neither|) %objects@1% (will be|2¦(will (not|4¦neither) be|won't be)) (less|smaller|below) [than] or (equal to|the same as) %objects%", Relation.SMALLER_OR_EQUAL},
      {"(1¦neither|) %objects@1% (2¦)((will (not|4¦neither) be|won't be)|(isn't|aren't|is not|are not) (turning|changing) [in]to) [equal to] %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@1% (will be [(equal to|the same as)]|(is|are) (turning|changing) [in]to) %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@1% will be between %objects% and %objects%", Relation.EQUAL},
      {"(1¦neither|) %objects@1% (2¦)(will not be|won't be) between %objects% and %objects%", Relation.EQUAL}
  });
 
  static {
    Skript.registerCondition(CondCompare.class, patterns.getPatterns());
  }
 
  @SuppressWarnings("null")
  private Expression<?> first;
  @SuppressWarnings("null")
  Expression<?> second;
  @Nullable
  Expression<?> third;
  @SuppressWarnings("null")
  Relation relation;
  @SuppressWarnings("rawtypes")
  @Nullable
  Comparator comp;
 
  @SuppressWarnings("null")
  @Override
  public boolean init(final Expression<?>[] vars, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
    first = vars[0];
    second = vars[1];
    if (vars.length == 3)
      third = vars[2];
    relation = patterns.getInfo(matchedPattern);
    if ((parser.mark & 0x2) != 0) // "not" somewhere in the condition
      setNegated(true);
    if ((parser.mark & 0x1) != 0) // "neither" on the left side
      setNegated(!isNegated());
    if ((parser.mark & 0x4) != 0) {// "neither" on the right side
      if (second instanceof ExpressionList)
        ((ExpressionList<?>) second).invertAnd();
      if (third instanceof ExpressionList)
        ((ExpressionList<?>) third).invertAnd();
    }
    final boolean b = init();
    final Expression<?> third = this.third;
    if (!b) {
      if (third == null && first.getReturnType() == Object.class && second.getReturnType() == Object.class) {
        return false;
      } else {
        Skript.error("Can't compare " + f(first) + " with " + f(second) + (third == null ? "" : " and " + f(third)), ErrorQuality.NOT_AN_EXPRESSION);
        return false;
      }
    }
    @SuppressWarnings("rawtypes")
    final Comparator comp = this.comp;
    if (comp != null) {
      if (third == null) {
        if (!relation.isEqualOrInverse() && !comp.supportsOrdering()) {
          Skript.error("Can't test " + f(first) + " for being '" + relation + "' " + f(second), ErrorQuality.NOT_AN_EXPRESSION);
          return false;
        }
      } else {
        if (!comp.supportsOrdering()) {
          Skript.error("Can't test " + f(first) + " for being 'between' " + f(second) + " and " + f(third), ErrorQuality.NOT_AN_EXPRESSION);
          return false;
        }
      }
    }
    return true;
  }
 
  public final static String f(final Expression<?> e) {
    if (e.getReturnType() == Object.class)
      return e.toString(null, false);
    return Classes.getSuperClassInfo(e.getReturnType()).getName().withIndefiniteArticle();
  }
 
  @SuppressWarnings("unchecked")
  private boolean init() {
    final RetainingLogHandler log = SkriptLogger.startRetainingLog();
    Expression<?> third = this.third;
    try {
      if (first.getReturnType() == Object.class) {
        final Expression<?> e = first.getConvertedExpression(Object.class);
        if (e == null) {
          log.printErrors();
          return false;
        }
        first = e;
      }
      if (second.getReturnType() == Object.class) {
        final Expression<?> e = second.getConvertedExpression(Object.class);
        if (e == null) {
          log.printErrors();
          return false;
        }
        second = e;
      }
      if (third != null && third.getReturnType() == Object.class) {
        final Expression<?> e = third.getConvertedExpression(Object.class);
        if (e == null) {
          log.printErrors();
          return false;
        }
        this.third = third = e;
      }
      log.printLog();
    } finally {
      log.stop();
    }
   
    final Class<?> f = first.getReturnType(), s = third == null ? second.getReturnType() : Utils.getSuperType(second.getReturnType(), third.getReturnType());
    if (f == Object.class || s == Object.class)
      return true;
    comp = Comparators.getComparator(f, s);
   
    return comp != null;
  }
 
  /*
   * # := condition (e.g. is, is less than, contains, is enchanted with, has permission, etc.)
   * !# := not #
   *
   * a and b # x === a # x && b # x
   * a or b # x === a # x || b # x
   * a # x and y === a # x && a # y
   * a # x or y === a # x || a # y
   * a and b # x and y === a # x and y && b # x and y === a # x && a # y && b # x && b # y
   * a and b # x or y === a # x or y && b # x or y
   * a or b # x and y === a # x and y || b # x and y
   * a or b # x or y === a # x or y || b # x or y
   *
   *
   * a and b !# x === a !# x && b !# x
   * neither a nor b # x === a !# x && b !# x    // nor = and
   * a or b !# x === a !# x || b !# x
   *
   * a !# x and y === a !# x || a !# y              // e.g. "player doesn't have 2 emeralds and 5 gold ingots" == "NOT(player has 2 emeralds and 5 gold ingots)" == "player doesn't have 2 emeralds OR player doesn't have 5 gold ingots"
   * a # neither x nor y === a !# x && a !# y    // nor = or   // e.g. "player has neither 2 emeralds nor 5 gold ingots" == "player doesn't have 2 emeralds AND player doesn't have 5 gold ingots"
   * a # neither x nor y === a !# x && a !# y    // nor = or   // e.g. "player is neither the attacker nor the victim" == "player is not the attacker AND player is not the victim"
   * a !# x or y === a !# x && a !# y                // e.g. "player doesn't have 2 emeralds or 5 gold ingots" == "NOT(player has 2 emeralds or 5 gold ingots)" == "player doesn't have 2 emeralds AND player doesn't have 5 gold ingots"
   *
   * a and b !# x and y === a !# x and y && b !# x and y === (a !# x || a !# y) && (b !# x || b !# y)
   * a and b !# x or y === a !# x or y && b !# x or y
   * a and b # neither x nor y === a # neither x nor y && b # neither x nor y
   *
   * a or b !# x and y === a !# x and y || b !# x and y
   * a or b !# x or y === a !# x or y || b !# x or y
   * a or b # neither x nor y === a # neither x nor y || b # neither x nor y
   *
   * neither a nor b # x and y === a !# x and y && b !# x and y    // nor = and
   * neither a nor b # x or y === a !# x or y && b !# x or y      // nor = and
   */
  @Override
  public boolean check(final Event e) {
    final Expression<?> third = this.third;
    return first.check(e, new Checker<Object>() {
      @Override
      public boolean check(final Object o1) {
        return second.check(e, new Checker<Object>() {
          @Override
          public boolean check(final Object o2) {
            if (third == null)
              return relation.is(comp != null ? comp.compare(o1, o2) : Comparators.compare(o1, o2));
            return third.check(e, new Checker<Object>() {
              @Override
              public boolean check(final Object o3) {
                return relation == Relation.NOT_EQUAL ^
                    (Relation.GREATER_OR_EQUAL.is(comp != null ? comp.compare(o1, o2) : Comparators.compare(o1, o2))
                    && Relation.SMALLER_OR_EQUAL.is(comp != null ? comp.compare(o1, o3) : Comparators.compare(o1, o3)));
              }
            });
          }
        }, isNegated());
      }
    });
  }
 
  @Override
  public String toString(final @Nullable Event e, final boolean debug) {
    String s;
    final Expression<?> third = this.third;
    if (third == null)
      s = first.toString(e, debug) + " is " + (isNegated() ? "not " : "") + relation + " " + second.toString(e, debug);
    else
      s = first.toString(e, debug) + " is " + (isNegated() ? "not " : "") + "between " + second.toString(e, debug) + " and " + third.toString(e, debug);
    if (debug)
      s += " (comparator: " + comp + ")";
    return s;
  }
 
}
TOP

Related Classes of ch.njol.skript.conditions.CondCompare

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.