package org.matheclipse.core.visit;
import org.matheclipse.core.expression.F;
import org.matheclipse.core.interfaces.IAST;
import org.matheclipse.core.interfaces.IComplex;
import org.matheclipse.core.interfaces.IComplexNum;
import org.matheclipse.core.interfaces.IExpr;
import org.matheclipse.core.interfaces.IFraction;
import org.matheclipse.core.interfaces.IInteger;
import org.matheclipse.core.interfaces.INum;
import org.matheclipse.core.interfaces.IPattern;
import org.matheclipse.core.interfaces.IPatternSequence;
import org.matheclipse.core.interfaces.IStringX;
import org.matheclipse.core.interfaces.ISymbol;
import org.matheclipse.parser.client.math.MathException;
import com.google.common.base.Function;
/**
* A level specification visitor for levels in abstract syntax trees (AST).
*
* Example: the nested list [x,[y]] has depth 3
*
*/
public class VisitorLevelSpecification extends AbstractVisitor {
private final Function fFunction;
private int fFromLevel;
private int fToLevel;
private int fFromDepth;
private int fToDepth;
private final boolean fIncludeHeads;
private int fCurrentLevel;
private int fCurrentDepth;
/**
* Create a LevelSpecification from an IInteger or IAST list-object.
*
*
* An expr is interpreted as a level specification for
* the allowed levels in an AST.
* If expr is a non-negative IInteger iValue set Level
* {1,iValue};
* If expr is a negative IInteger iValue set Level {iValue, 0};
* If expr is a List {i0Value, i1Value} set Level {i0Value,
* i1Value};
*
* @param function
* the function which should be applied for an element
* @param expr
* the given level specification
* @param includeHeads
* set to true, if the header of an AST expression
* should be included
* @throws MathException
* if the expr is not a level specification
* @see
*/
public VisitorLevelSpecification(final Function function, final IExpr expr, boolean includeHeads) {
fFromLevel = fToLevel = -1;
fFromDepth = fToDepth = 0;
this.fIncludeHeads = includeHeads;
this.fFunction = function;
if (expr instanceof IInteger) {
final IInteger value = (IInteger) expr;
if (value.isNegative()) {
fFromDepth = Integer.MIN_VALUE;
fToDepth = value.getBigNumerator().intValue();
fFromLevel = 1;
fToLevel = Integer.MAX_VALUE;
} else {
fToLevel = value.getBigNumerator().intValue();
fFromLevel = 1;
fFromDepth = Integer.MIN_VALUE;
fToDepth = -1;
}
return;
}
if (expr.isList()) {
final IAST lst = (IAST) expr;
if (lst.size() == 2) {
if (lst.get(1) instanceof IInteger) {
final IInteger i = (IInteger) lst.get(1);
if (i.isNegative()) {
fFromDepth = i.getBigNumerator().intValue();
fToDepth = i.getBigNumerator().intValue();
fFromLevel = 0;
fToLevel = Integer.MAX_VALUE;
if (fToDepth < fFromDepth) {
throw new MathException("Invalid Level specification: " + expr.toString());
}
} else {
fToLevel = i.getBigNumerator().intValue();
fFromLevel = i.getBigNumerator().intValue();
fFromDepth = Integer.MIN_VALUE;
fToDepth = -1;
if (fToLevel < fFromLevel) {
throw new MathException("Invalid Level specification: " + expr.toString());
}
}
return;
}
} else {
if ((lst.size() == 3)) {
if ((lst.get(1) instanceof IInteger) && (lst.get(2) instanceof IInteger)) {
final IInteger i0 = (IInteger) lst.get(1);
final IInteger i1 = (IInteger) lst.get(2);
if (i0.isNegative() && i1.isNegative()) {
fFromDepth = i0.getBigNumerator().intValue();
fToDepth = i1.getBigNumerator().intValue();
fFromLevel = 0;
fToLevel = Integer.MAX_VALUE;
} else if (i0.isNegative()) {
throw new MathException("Invalid Level specification: " + expr.toString());
} else if (i1.isNegative()) {
fFromDepth = Integer.MIN_VALUE;
fToDepth = i1.getBigNumerator().intValue();
fFromLevel = i0.getBigNumerator().intValue();
fToLevel = Integer.MAX_VALUE;
} else {
fFromDepth = Integer.MIN_VALUE;
fToDepth = -1;
fFromLevel = i0.getBigNumerator().intValue();
fToLevel = i1.getBigNumerator().intValue();
}
return;
} else if ((lst.get(1) instanceof IInteger) && (lst.get(2).isInfinity())) {
final IInteger i0 = (IInteger) lst.get(1);
if (i0.isNegative()) {
throw new MathException("Invalid Level specification: " + expr.toString());
} else {
fFromDepth = Integer.MIN_VALUE;
fToDepth = -1;
fFromLevel = i0.getBigNumerator().intValue();
fToLevel = Integer.MAX_VALUE;
}
return;
}
}
}
}
if (expr.equals(F.CInfinity)) {
fToLevel = Integer.MAX_VALUE;
fFromLevel = 1;
fFromDepth = Integer.MIN_VALUE;
fToDepth = -1;
return;
}
throw new MathException("Invalid Level specification: " + expr.toString());
}
// public AbstractVisitorLevel(final Function function,
// LevelSpec spec) {
// super();
// this.fFunction = function;
// this.fFromLevel = spec.getFromLevel();
// this.fToLevel = spec.getToLevel();
// this.fFromDepth = spec.getFromDepth();
// this.fToDepth = spec.getToDepth();
// this.fIncludeHeads = spec.isIncludeHeads();
// this.fCurrentLevel = 0;
// // System.out.println(this.fromLevel);
// // System.out.println(this.toLevel);
// // System.out.println(this.fromDepth);
// // System.out.println(this.toDepth);
// }
/**
* Define a level specification for all elements on level level
* .
*
* @param level
*/
public VisitorLevelSpecification(final Function function, final int level) {
this(function, level, true);
}
public VisitorLevelSpecification(final Function function, final int level, final boolean includeHeads) {
this(function, level, level, includeHeads);
}
public VisitorLevelSpecification(final Function function, final int fromLevel, final int toLevel) {
this(function, fromLevel, toLevel, true);
}
public VisitorLevelSpecification(final Function function, final int fromLevel, final int toLevel,
final boolean includeHeads) {
this(function, fromLevel, toLevel, Integer.MIN_VALUE, -1, includeHeads);
}
/**
*
* Example value set for including all levels:
* fromLevel = 0;
* toLevel = Integer.MAX_VALUE;
* fromDepth = Integer.MIN_VALUE;
* toDepth = -1;
*
* @param function
* the function which should be applied for an element
* @param fromLevel
* @param toLevel
* @param fromDepth
* @param toDepth
* @param includeHeads
*/
public VisitorLevelSpecification(final Function function, final int fromLevel, final int toLevel,
final int fromDepth, final int toDepth, final boolean includeHeads) {
fFunction = function;
fFromLevel = fromLevel;
fToLevel = toLevel;
fCurrentLevel = 0;
fIncludeHeads = includeHeads;
fFromDepth = fromDepth;
fCurrentDepth = -1;
fToDepth = toDepth;
}
public void incCurrentLevel() {
fCurrentLevel++;
}
public void decCurrentLevel() {
fCurrentLevel--;
}
public boolean isInRange(int level, int depth) {
return (level >= fFromLevel) && (level <= fToLevel) && (depth >= fFromDepth) && (depth <= fToDepth);
}
/**
*
*/
public IExpr visit(IInteger element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IFraction element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IComplex element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(INum element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IComplexNum element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(ISymbol element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IPattern element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IPatternSequence element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
/**
*
*/
public IExpr visit(IStringX element) {
fCurrentDepth = -1;
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
public IExpr visitExpr(IExpr element) {
if (isInRange(fCurrentLevel, -1)) {
return fFunction.apply(element);
}
return null;
}
public IExpr visit(IAST ast) {
int minDepth = -1;
IExpr temp;
IAST result = null;
try {
fCurrentLevel++;
if (fIncludeHeads) {
temp = ast.get(0).accept(this);
if (temp != null) {
if (result == null) {
result = ast.clone();
}
result.set(0, temp);
}
if (fCurrentDepth < minDepth) {
minDepth = fCurrentDepth;
}
}
for (int i = 1; i < ast.size(); i++) {
temp = ast.get(i).accept(this);
if (temp != null) {
if (result == null) {
result = ast.clone();
}
result.set(i, temp);
}
if (fCurrentDepth < minDepth) {
minDepth = fCurrentDepth;
}
}
} finally {
fCurrentLevel--;
}
fCurrentDepth = --minDepth;
if (isInRange(fCurrentLevel, minDepth)) {
if (result == null) {
return fFunction.apply(ast);
} else {
temp = fFunction.apply(result);
if (temp != null) {
return temp;
}
}
}
return result;
}
}
Ads help maintain this website.