/*
* Copyright (C) 2009 JavaRosa
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.openrosa.client.jr.xpath.parser.ast;
import java.util.Vector;
import org.openrosa.client.jr.xpath.expr.XPathExpression;
import org.openrosa.client.jr.xpath.expr.XPathNumericLiteral;
import org.openrosa.client.jr.xpath.expr.XPathQName;
import org.openrosa.client.jr.xpath.expr.XPathStringLiteral;
import org.openrosa.client.jr.xpath.expr.XPathVariableReference;
import org.openrosa.client.jr.xpath.parser.Parser;
import org.openrosa.client.jr.xpath.parser.Token;
import org.openrosa.client.jr.xpath.parser.XPathSyntaxException;
public class ASTNodeAbstractExpr extends ASTNode {
public static final int CHILD = 1;
public static final int TOKEN = 2;
public Vector content; //mixture of tokens and ASTNodes
public ASTNodeAbstractExpr () {
content = new Vector();
}
public Vector getChildren () {
Vector children = new Vector();
for (int i = 0; i < content.size(); i++) {
if (getType(i) == CHILD) {
children.addElement(content.elementAt(i));
}
}
return children;
}
public XPathExpression build() throws XPathSyntaxException {
if (content.size() == 1) {
if (getType(0) == CHILD) {
return ((ASTNode)content.elementAt(0)).build();
} else {
switch (getTokenType(0)) {
case Token.NUM: return new XPathNumericLiteral((Double)getToken(0).val);
case Token.STR: return new XPathStringLiteral((String)getToken(0).val);
case Token.VAR: return new XPathVariableReference((XPathQName)getToken(0).val);
default: throw new XPathSyntaxException();
}
}
} else {
throw new XPathSyntaxException();
}
}
public boolean isTerminal () {
if (content.size() == 1) {
int type = getTokenType(0);
return (type == Token.NUM || type == Token.STR || type == Token.VAR);
} else {
return false;
}
}
public boolean isNormalized () {
if (content.size() == 1 && getType(0) == CHILD) {
ASTNode child = (ASTNode)content.elementAt(0);
if (child instanceof ASTNodePathStep || child instanceof ASTNodePredicate)
throw new RuntimeException("shouldn't happen");
return true;
} else {
return isTerminal();
}
}
public int getType (int i) {
Object o = content.elementAt(i);
if (o instanceof Token)
return TOKEN;
else if (o instanceof ASTNode)
return CHILD;
else
return -1;
}
public Token getToken (int i) {
return (getType(i) == TOKEN ? (Token)content.elementAt(i) : null);
}
public int getTokenType (int i) {
Token t = getToken(i);
return (t == null ? -1 : t.type);
}
//create new node containing children from [start,end)
public ASTNodeAbstractExpr extract (int start, int end) {
ASTNodeAbstractExpr node = new ASTNodeAbstractExpr();
for (int i = start; i < end; i++) {
node.content.addElement(content.elementAt(i));
}
return node;
}
//remove children from [start,end) and replace with node n
public void condense (ASTNode node, int start, int end) {
for (int i = end - 1; i >= start; i--) {
content.removeElementAt(i);
}
content.insertElementAt(node, start);
}
//find the next incidence of 'target' at the current stack level
//start points to the opening of the current stack level
public int indexOfBalanced (int start, int target, int leftPush, int rightPop) {
int depth = 0;
int i = start + 1;
boolean found = false;
while (depth >= 0 && i < content.size()) {
int type = getTokenType(i);
if (depth == 0 && type == target) {
found = true;
break;
}
if (type == leftPush)
depth++;
else if (type == rightPop)
depth--;
i++;
}
return (found ? i : -1);
}
public class Partition {
public Partition () {
pieces = new Vector();
separators = new Vector();
}
public Vector pieces;
public Vector separators;
}
//paritition the range [start,end), separating by any occurrence of separator
public Partition partition (int[] separators, int start, int end) {
Partition part = new Partition();
Vector sepIdxs = new Vector();
for (int i = start; i < end; i++) {
for (int j = 0; j < separators.length; j++) {
if (getTokenType(i) == separators[j]) {
part.separators.addElement(new Integer(separators[j]));
sepIdxs.addElement(new Integer(i));
break;
}
}
}
for (int i = 0; i <= sepIdxs.size(); i++) {
int pieceStart = (i == 0 ? start : Parser.vectInt(sepIdxs, i - 1) + 1);
int pieceEnd = (i == sepIdxs.size() ? end : Parser.vectInt(sepIdxs, i));
part.pieces.addElement(extract(pieceStart, pieceEnd));
}
return part;
}
//partition by sep, to the end of the current stack level
//start is the opening token of the current stack level
public Partition partitionBalanced (int sep, int start, int leftPush, int rightPop) {
Partition part = new Partition();
Vector sepIdxs = new Vector();
int end = indexOfBalanced(start, rightPop, leftPush, rightPop);
if (end == -1)
return null;
int k = start;
do {
k = indexOfBalanced(k, sep, leftPush, rightPop);
if (k != -1) {
sepIdxs.addElement(new Integer(k));
part.separators.addElement(new Integer(sep));
}
} while (k != -1);
for (int i = 0; i <= sepIdxs.size(); i++) {
int pieceStart = (i == 0 ? start + 1 : Parser.vectInt(sepIdxs, i - 1) + 1);
int pieceEnd = (i == sepIdxs.size() ? end : Parser.vectInt(sepIdxs, i));
part.pieces.addElement(extract(pieceStart, pieceEnd));
}
return part;
}
}