package gve.calc.formula;
public class OperatorSpace extends InfixBinaryOp {
public String getName() { return " "; }
/* The priority of the space operator is, as far as we seem to see, irrelevant.
* We kiezen 10000 om "x^f(y)" te associeren als "x^(f(y))". */
public int getPri() { return 10000; }
public int getLeftPri() { return 10010; }
public int getRightPri() { return 9990; }
public OperatorSpace(Part l,Part r) {
super(l,r);
}
public Part evaluate(Evaluator ev) {
if (right == null) return null;
if (left == null) return null;
if (left instanceof Identifier) {
String fname = ((Identifier)left).getString();
// Note: we don't ev.call(fname,right.evaluate(ev)) since some functions work
// on expressions, e.g. freevar(x=y) may not be evaluated as
// freevar(false) but must be evaluated as freevar(x=y) ...
Part result = ev.call(fname,right);
if (result == null)
return new OperatorSpace(new Identifier(fname),right.evaluate(ev));
return result;
}
Part arg = right.evaluate(ev); // argument
return new OperatorSpace(left.evaluate(ev),arg);
}
public boolean recognizeOp(Formula f) {
return recognizeOp(f,null);
}
public boolean recognizeOp(FormulaView view) {
return recognizeOp(view.getFormula(),view);
}
Call this method on a freshly inserted space operator.
This method checks if with this fresh space, we can recognize an operator.
If so, this method returns true; in that case, the space (and some
Identifier---the recognized operator) is no longer part of the formula.
If the view argument is non-null, take special care that the cursor is in a
"nice" position after rotating if necessary. |
public boolean recognizeOp(Formula f,FormulaView view) {
rotate(f,view); // rotate myself into the right position, between possible other spaces
if (recognizeOpWithParent(f,view)) return true;
if (left instanceof OperatorSpace) {
if (((OperatorSpace)left).recognizeOpWithParent(f,view)) return true;
// return false;
}
if (right instanceof OperatorSpace) {
if (((OperatorSpace)right).recognizeOpWithParent(f,view)) return true;
// return false;
}
if (left instanceof Identifier) {
Identifier ident = (Identifier)left;
if (PrefixUnaryOp.isOperatorName(ident.getString())) {
// Recognize prefix unary op
// using this approach, right.parent ends up bad
// UnaryOp op = PrefixUnaryOp.getInstance(ident.getString(),right);
// f.replace(this,op);
Identifier dummy = new Identifier("");
UnaryOp op = PrefixUnaryOp.getInstance(ident.getString(),dummy);
f.replace(this,op);
f.replace(dummy,right);
if (view != null) {
Part cp = view.getCursorPart();
if (cp == this)
view.setCursorPart(op,HasCursorPos.Somewhere_MYRIGHT);
else if (cp==left) {
int pos = ((HasCursorPos)view.getView(cp)).getCursorPos();
view.setCursorPart(op,pos);
}
}
op.rotate(f,view);
return true;
}
} else if (right instanceof Identifier) {
Identifier ident = (Identifier)right;
if (PostfixUnaryOp.isOperatorName(ident.getString())) {
// Recognize postfix unary op
UnaryOp op = PostfixUnaryOp.getInstance(ident.getString(),left);
f.replace(this,op);
op.rotate(f,view);
return true;
}
}
return false;
}
If the parent is also a space operator, try to recognize a new operator. |
private boolean recognizeOpWithParent(Formula f,FormulaView view) {
if (!(parent instanceof OperatorSpace)) return false;
OperatorSpace par = (OperatorSpace)parent;
if (par.right==this && left instanceof Identifier) {
Identifier leftid = (Identifier)left;
if (InfixBinaryOp.isOperatorName(leftid.getString())) {
InfixBinaryOp rot = InfixBinaryOp.getInstance(leftid.getString(),par.left,right);
f.replace(par,rot);
if (view != null) {
Part cp = view.getCursorPart();
if (cp == this)
view.setCursorPart(rot,HasCursorPos.Somewhere_MYRIGHT);
else if (cp==left) {
int pos = ((HasCursorPos)view.getView(cp)).getCursorPos();
view.setCursorPart(rot,pos);
}
}
rot.rotate(f,view);
return true;
} else if (leftid.getString().equals("")) {
// An empty identifier between two other Part trees => gobble up
if (par.left instanceof Identifier && right instanceof Identifier) {
// Special case: join two Identifiers
// NOTE (& PENDING:) that this is very ad hoc: it works only if the two
// Identifiers are directly next to each other
// e.g. if you type "a*b+[]c*d" ([] == cursor) and press backspace,
// the trick doesn't quite work ...
Identifier a = (Identifier)par.left;
Identifier b = (Identifier)right;
Identifier newident = new Identifier(a.getString() + b.getString());
f.replace(par,newident);
if (view != null)
view.setCursorPart(newident,a.getString().length());
}
f.replace(this,right);
if (view != null) {
Part cp = view.getCursorPart();
if (cp==this || cp==left) // cursor is on parts that vanished
view.setCursorPart(right);
}
}
} else if (par.left==this && right instanceof Identifier) {
Identifier rightid = (Identifier)right;
if (InfixBinaryOp.isOperatorName(rightid.getString())) {
InfixBinaryOp rot = InfixBinaryOp.getInstance(rightid.getString(),left,par.right);
f.replace(par,rot);
// PENDING: reposition cursor! [6-dec-2000]
// (see above case)
rot.rotate(f,view);
return true;
}
}
return false;
}
public static Part read(java.io.BufferedReader r) throws java.io.IOException,
ClassNotFoundException,NoSuchMethodException,
java.lang.reflect.InvocationTargetException,IllegalAccessException{
Part left = Part.read(r);
Part right = Part.read(r);
return new OperatorSpace(left,right);
}
public boolean same(Object o) {
if (o instanceof OperatorSpace) {
OperatorSpace spat = (OperatorSpace)o;
return spat.left.same(left) && spat.right.same(right);
}
return false;
}
public void saveOperatorLatex(java.io.BufferedWriter w) throws java.io.IOException {
if (right instanceof Brackets) ;
else w.write("\\ ");
}
}