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("\\ "); } }