package com.github.sommeri.less4j.core.compiler.expressions;
import java.util.LinkedList;
import java.util.List;
import com.github.sommeri.less4j.LessCompiler.Configuration;
import com.github.sommeri.less4j.core.ast.ReusableStructure;
import com.github.sommeri.less4j.core.compiler.scopes.IScope;
import com.github.sommeri.less4j.core.problems.ProblemsHandler;
public class MixinsGuardsValidator {
private final DefaultPoweredExpressionEvaluator ifDefaultExpressionEvaluator;
private final DefaultPoweredExpressionEvaluator ifNotDefaultExpressionEvaluator;
public MixinsGuardsValidator(IScope scope, ProblemsHandler problemsHandler, Configuration configuration) {
ifDefaultExpressionEvaluator = new DefaultPoweredExpressionEvaluator(scope, problemsHandler, configuration, true);
ifNotDefaultExpressionEvaluator = new DefaultPoweredExpressionEvaluator(scope, problemsHandler, configuration, false);
}
public boolean guardsSatisfied(ReusableStructure mixin, boolean assumeDefault) {
if (assumeDefault)
return ifDefaultExpressionEvaluator.guardsSatisfied(mixin);
return ifNotDefaultExpressionEvaluator.guardsSatisfied(mixin);
}
private class DefaultPoweredExpressionEvaluator extends ExpressionEvaluator {
public DefaultPoweredExpressionEvaluator(IScope scope, ProblemsHandler problemsHandler, Configuration configuration, boolean assumeDefault) {
super(scope, problemsHandler, configuration);
addFunctionsPack(new GuardOnlyFunctions(problemsHandler, assumeDefault));
}
}
public GuardValue evaluateGuards(ReusableStructure mixin) {
boolean ifDefaultGuardValue = guardsSatisfied(mixin, true);
boolean ifNotDefaultGuardValue = guardsSatisfied(mixin, false);
return toDefaultFunctionUse(ifDefaultGuardValue, ifNotDefaultGuardValue);
}
/**
* CAREFULL: side-effect - the <code>namespacesGuards</code> list is modified
* @param namespacesGuards
* @param mixin
* @return
*/
public GuardValue evaluateGuards(LinkedList<GuardValue> namespacesGuards, ReusableStructure mixin) {
namespacesGuards.add(evaluateGuards(mixin));
return andGuards(namespacesGuards);
}
/**
* Re-implementing less.js heuristic. If guards value does not depend on default value, then less.js
* assumes the default was not used. It does not check whether the default function was really used, so
* this: not(default()), (default()) can be used multiple times.
*/
private GuardValue toDefaultFunctionUse(boolean ifDefaultGuardValue, boolean ifNotDefaultGuardValue) {
if (ifDefaultGuardValue && ifNotDefaultGuardValue) {//default was NOT used
return GuardValue.USE;
} else if (!ifDefaultGuardValue && !ifNotDefaultGuardValue) {//default was NOT used
return GuardValue.DO_NOT_USE;
} else if (ifDefaultGuardValue) {//default is required
return GuardValue.USE_IF_DEFAULT;
} else {//if (must not be default)
return GuardValue.USE_IF_NOT_DEFAULT;
}//
}
public GuardValue andGuards(List<GuardValue> guards) {
boolean ifDefaultGuardValue = ifDefaultGuardValue(guards);
boolean ifNotDefaultGuardValue = ifNotDefaultGuardValue(guards);
return toDefaultFunctionUse(ifDefaultGuardValue, ifNotDefaultGuardValue);
}
private boolean ifNotDefaultGuardValue(List<GuardValue> guards) {
for (GuardValue guardValue : guards) {
switch (guardValue) {
case USE:
case USE_IF_NOT_DEFAULT:
break;
case DO_NOT_USE:
case USE_IF_DEFAULT:
return false;
}
}
return true;
}
private boolean ifDefaultGuardValue(List<GuardValue> guards) {
for (GuardValue guardValue : guards) {
switch (guardValue) {
case USE:
case USE_IF_DEFAULT:
break ;
case DO_NOT_USE:
case USE_IF_NOT_DEFAULT:
return false;
}
}
return true;
}
}