/** * @return <code>false</code> if sub-expression represented the specified ParseNode definitely * cannot appear on either side of the range (':') operator */ private static boolean isValidRangeOperand(ParseNode a) { Ptg tkn = a.getToken(); // Note - order is important for these instance-of checks if (tkn instanceof OperandPtg) { // notably cell refs and area refs return true; } // next 2 are special cases of OperationPtg if (tkn instanceof AbstractFunctionPtg) { AbstractFunctionPtg afp = (AbstractFunctionPtg) tkn; byte returnClass = afp.getDefaultOperandClass(); return Ptg.CLASS_REF == returnClass; } if (tkn instanceof ValueOperatorPtg) { return false; } if (tkn instanceof OperationPtg) { return true; } // one special case of ControlPtg if (tkn instanceof ParenthesisPtg) { // parenthesis Ptg should have only one child return isValidRangeOperand(a.getChildren()[0]); } // one special case of ScalarConstantPtg if (tkn == ErrPtg.REF_INVALID) { return true; } // All other ControlPtgs and ScalarConstantPtgs cannot be used with ':' return false; }
/** * @param callerForceArrayFlag <code>true</code> if one of the current node's parents is a * function Ptg which has been changed from default 'V' to 'A' type (due to requirements on * the function return value). */ private void transformNode( ParseNode node, byte desiredOperandClass, boolean callerForceArrayFlag) { Ptg token = node.getToken(); ParseNode[] children = node.getChildren(); boolean isSimpleValueFunc = isSimpleValueFunction(token); if (isSimpleValueFunc) { boolean localForceArray = desiredOperandClass == Ptg.CLASS_ARRAY; for (int i = 0; i < children.length; i++) { transformNode(children[i], desiredOperandClass, localForceArray); } setSimpleValueFuncClass( (AbstractFunctionPtg) token, desiredOperandClass, callerForceArrayFlag); return; } if (isSingleArgSum(token)) { // Need to process the argument of SUM with transformFunctionNode below // so make a dummy FuncVarPtg for that call. token = FuncVarPtg.SUM; // Note - the tAttrSum token (node.getToken()) is a base // token so does not need to have its operand class set } if (token instanceof ValueOperatorPtg || token instanceof ControlPtg || token instanceof MemFuncPtg || token instanceof MemAreaPtg || token instanceof UnionPtg) { // Value Operator Ptgs and Control are base tokens, so token will be unchanged // but any child nodes are processed according to desiredOperandClass and callerForceArrayFlag // As per OOO documentation Sec 3.2.4 "Token Class Transformation", "Step 1" // All direct operands of value operators that are initially 'R' type will // be converted to 'V' type. byte localDesiredOperandClass = desiredOperandClass == Ptg.CLASS_REF ? Ptg.CLASS_VALUE : desiredOperandClass; for (int i = 0; i < children.length; i++) { transformNode(children[i], localDesiredOperandClass, callerForceArrayFlag); } return; } if (token instanceof AbstractFunctionPtg) { transformFunctionNode( (AbstractFunctionPtg) token, children, desiredOperandClass, callerForceArrayFlag); return; } if (children.length > 0) { if (token == RangePtg.instance) { // TODO is any token transformation required under the various ref operators? return; } throw new IllegalStateException("Node should not have any children"); } if (token.isBaseToken()) { // nothing to do return; } token.setClass(transformClass(token.getPtgClass(), desiredOperandClass, callerForceArrayFlag)); }
/** * From OOO doc: "Whenever one operand of the reference subexpression is a function, a defined * name, a 3D reference, or an external reference (and no error occurs), a tMemFunc token is used" */ private static boolean needsMemFunc(ParseNode root) { Ptg token = root.getToken(); if (token instanceof AbstractFunctionPtg) { return true; } if (token instanceof ExternSheetReferenceToken) { // 3D refs return true; } if (token instanceof NamePtg || token instanceof NameXPtg) { // 3D refs return true; } if (token instanceof OperationPtg || token instanceof ParenthesisPtg) { // expect RangePtg, but perhaps also UnionPtg, IntersectionPtg etc for (ParseNode child : root.getChildren()) { if (needsMemFunc(child)) { return true; } } return false; } if (token instanceof OperandPtg) { return false; } if (token instanceof OperationPtg) { return true; } return false; }
public ParseNode not(ParseNode child) { if (child instanceof ExistsParseNode) { return exists(child.getChildren().get(0), !((ExistsParseNode) child).isNegate()); } return new NotParseNode(child); }