/*******************************************************************************
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
*
*
*
*******************************************************************************/
package hudson.model.labels;
import hudson.model.Label;
import hudson.util.VariableResolver;
/**
* Boolean expression of labels.
*
* @author Kohsuke Kawaguchi
* @since 1.372
*/
public abstract class LabelExpression extends Label {
protected LabelExpression(String name) {
super(name);
}
@Override
public String getExpression() {
return getDisplayName();
}
public static class Not extends LabelExpression {
private final Label base;
public Not(Label base) {
super('!' + paren(LabelOperatorPrecedence.NOT, base));
this.base = base;
}
@Override
public boolean matches(VariableResolver<Boolean> resolver) {
return !base.matches(resolver);
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.NOT;
}
}
/**
* No-op but useful for preserving the parenthesis in the user input.
*/
public static class Paren extends LabelExpression {
private final Label base;
public Paren(Label base) {
super('(' + base.getExpression() + ')');
this.base = base;
}
@Override
public boolean matches(VariableResolver<Boolean> resolver) {
return base.matches(resolver);
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.ATOM;
}
}
/**
* Puts the label name into a parenthesis if the given operator will have a
* higher precedence.
*/
static String paren(LabelOperatorPrecedence op, Label l) {
if (op.compareTo(l.precedence()) < 0) {
return '(' + l.getExpression() + ')';
}
return l.getExpression();
}
public static abstract class Binary extends LabelExpression {
private final Label lhs, rhs;
public Binary(Label lhs, Label rhs, LabelOperatorPrecedence op) {
super(combine(lhs, rhs, op));
this.lhs = lhs;
this.rhs = rhs;
}
private static String combine(Label lhs, Label rhs, LabelOperatorPrecedence op) {
return paren(op, lhs) + op.str + paren(op, rhs);
}
/**
* Note that we evaluate both branches of the expression all the time.
* That is, it behaves like "a|b" not "a||b"
*/
@Override
public boolean matches(VariableResolver<Boolean> resolver) {
return op(lhs.matches(resolver), rhs.matches(resolver));
}
protected abstract boolean op(boolean a, boolean b);
}
public static final class And extends Binary {
public And(Label lhs, Label rhs) {
super(lhs, rhs, LabelOperatorPrecedence.AND);
}
@Override
protected boolean op(boolean a, boolean b) {
return a && b;
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.AND;
}
}
public static final class Or extends Binary {
public Or(Label lhs, Label rhs) {
super(lhs, rhs, LabelOperatorPrecedence.OR);
}
@Override
protected boolean op(boolean a, boolean b) {
return a || b;
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.OR;
}
}
public static final class Iff extends Binary {
public Iff(Label lhs, Label rhs) {
super(lhs, rhs, LabelOperatorPrecedence.IFF);
}
@Override
protected boolean op(boolean a, boolean b) {
return !(a ^ b);
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.IFF;
}
}
public static final class Implies extends Binary {
public Implies(Label lhs, Label rhs) {
super(lhs, rhs, LabelOperatorPrecedence.IMPLIES);
}
@Override
protected boolean op(boolean a, boolean b) {
return !a || b;
}
@Override
public LabelOperatorPrecedence precedence() {
return LabelOperatorPrecedence.IMPLIES;
}
}
}