use of org.apache.camel.language.simple.ast.SimpleNode in project camel by apache.
the class BaseSimpleParser method prepareBlocks.
/**
* Prepares blocks, such as functions, single or double quoted texts.
* <p/>
* This process prepares the {@link Block}s in the AST. This is done
* by linking child {@link SimpleNode nodes} which are within the start and end of the blocks,
* as child to the given block. This is done to have the AST graph updated and prepared properly.
* <p/>
* So when the AST node is later used to create the {@link org.apache.camel.Predicate}s
* or {@link org.apache.camel.Expression}s to be used by Camel then the AST graph
* has a linked and prepared graph of nodes which represent the input expression.
*/
protected void prepareBlocks() {
List<SimpleNode> answer = new ArrayList<SimpleNode>();
Stack<Block> stack = new Stack<Block>();
for (SimpleNode token : nodes) {
if (token instanceof BlockStart) {
// a new block is started, so push on the stack
stack.push((Block) token);
} else if (token instanceof BlockEnd) {
// end block is just an abstract mode, so we should not add it
if (stack.isEmpty()) {
throw new SimpleParserException(token.getToken().getType().getType() + " has no matching start token", token.getToken().getIndex());
}
Block top = stack.pop();
// if there is a block on the stack then it should accept the child token
Block block = stack.isEmpty() ? null : stack.peek();
if (block != null) {
if (!block.acceptAndAddNode(top)) {
throw new SimpleParserException(block.getToken().getType() + " cannot accept " + token.getToken().getType(), token.getToken().getIndex());
}
} else {
// no block, so add to answer
answer.add(top);
}
} else {
// if there is a block on the stack then it should accept the child token
Block block = stack.isEmpty() ? null : stack.peek();
if (block != null) {
if (!block.acceptAndAddNode(token)) {
throw new SimpleParserException(block.getToken().getType() + " cannot accept " + token.getToken().getType(), token.getToken().getIndex());
}
} else {
// no block, so add to answer
answer.add(token);
}
}
}
// replace nodes from the stack
nodes.clear();
nodes.addAll(answer);
}
use of org.apache.camel.language.simple.ast.SimpleNode in project camel by apache.
the class SimpleExpressionParser method parseAndCreateAstModel.
protected void parseAndCreateAstModel() {
// we loop the tokens and create a sequence of ast nodes
// counter to keep track of number of functions in the tokens
AtomicInteger functions = new AtomicInteger();
LiteralNode imageToken = null;
for (SimpleToken token : tokens) {
// break if eol
if (token.getType().isEol()) {
break;
}
// create a node from the token
SimpleNode node = createNode(token, functions);
if (node != null) {
// a new token was created so the current image token need to be added first
if (imageToken != null) {
nodes.add(imageToken);
imageToken = null;
}
// and then add the created node
nodes.add(node);
// continue to next
continue;
}
// which we need to add together in the same image
if (imageToken == null) {
imageToken = new LiteralExpression(token);
}
imageToken.addText(token.getText());
}
// append any leftover image tokens (when we reached eol)
if (imageToken != null) {
nodes.add(imageToken);
}
}
use of org.apache.camel.language.simple.ast.SimpleNode in project camel by apache.
the class SimplePredicateParser method prepareLogicalExpressions.
/**
* Prepares logical expressions.
* <p/>
* This process prepares the logical expressions in the AST. This is done
* by linking the logical operator with both the right and left hand side
* nodes, to have the AST graph updated and prepared properly.
* <p/>
* So when the AST node is later used to create the {@link Predicate}s
* to be used by Camel then the AST graph has a linked and prepared
* graph of nodes which represent the input expression.
*/
private void prepareLogicalExpressions() {
Stack<SimpleNode> stack = new Stack<SimpleNode>();
SimpleNode left = null;
for (int i = 0; i < nodes.size(); i++) {
if (left == null) {
left = i > 0 ? nodes.get(i - 1) : null;
}
SimpleNode token = nodes.get(i);
SimpleNode right = i < nodes.size() - 1 ? nodes.get(i + 1) : null;
if (token instanceof LogicalExpression) {
LogicalExpression logical = (LogicalExpression) token;
// remember the logical operator
String operator = logical.getOperator().toString();
if (left == null) {
throw new SimpleParserException("Logical operator " + operator + " has no left hand side token", token.getToken().getIndex());
}
if (!logical.acceptLeftNode(left)) {
throw new SimpleParserException("Logical operator " + operator + " does not support left hand side token " + left.getToken(), token.getToken().getIndex());
}
if (right == null) {
throw new SimpleParserException("Logical operator " + operator + " has no right hand side token", token.getToken().getIndex());
}
if (!logical.acceptRightNode(right)) {
throw new SimpleParserException("Logical operator " + operator + " does not support right hand side token " + left.getToken(), token.getToken().getIndex());
}
// pop previous as we need to replace it with this binary operator
stack.pop();
stack.push(token);
// advantage after the right hand side
i++;
// this token is now the left for the next loop
left = token;
} else {
// clear left
left = null;
stack.push(token);
}
}
nodes.clear();
nodes.addAll(stack);
}
use of org.apache.camel.language.simple.ast.SimpleNode in project camel by apache.
the class SimplePredicateParser method parseTokensAndCreateNodes.
/**
* Parses the tokens and crates the AST nodes.
* <p/>
* After the initial parsing of the input (input -> tokens) then we
* parse again (tokens -> ast).
* <p/>
* In this parsing the balance of the blocks is checked, so that each block has a matching
* start and end token. For example a single quote block, or a function block etc.
*/
protected void parseTokensAndCreateNodes() {
// we loop the tokens and create a sequence of ast nodes
// we need to keep a bit of state for keeping track of single and double quotes
// which need to be balanced and have matching start/end pairs
SimpleNode lastSingle = null;
SimpleNode lastDouble = null;
SimpleNode lastFunction = null;
AtomicBoolean startSingle = new AtomicBoolean(false);
AtomicBoolean startDouble = new AtomicBoolean(false);
AtomicBoolean startFunction = new AtomicBoolean(false);
LiteralNode imageToken = null;
for (SimpleToken token : tokens) {
// break if eol
if (token.getType().isEol()) {
break;
}
// create a node from the token
SimpleNode node = createNode(token, startSingle, startDouble, startFunction);
if (node != null) {
// keep state of last single/double
if (node instanceof SingleQuoteStart) {
lastSingle = node;
} else if (node instanceof DoubleQuoteStart) {
lastDouble = node;
} else if (node instanceof SimpleFunctionStart) {
lastFunction = node;
}
// a new token was created so the current image token need to be added first
if (imageToken != null) {
nodes.add(imageToken);
imageToken = null;
}
// and then add the created node
nodes.add(node);
// continue to next
continue;
}
// which we need to add together in the same image
if (imageToken == null) {
imageToken = new LiteralExpression(token);
}
imageToken.addText(token.getText());
}
// append any leftover image tokens (when we reached eol)
if (imageToken != null) {
nodes.add(imageToken);
}
// validate the single, double quote pairs and functions is in balance
if (startSingle.get()) {
int index = lastSingle != null ? lastSingle.getToken().getIndex() : 0;
throw new SimpleParserException("single quote has no ending quote", index);
}
if (startDouble.get()) {
int index = lastDouble != null ? lastDouble.getToken().getIndex() : 0;
throw new SimpleParserException("double quote has no ending quote", index);
}
if (startFunction.get()) {
// we have a start function, but no ending function
int index = lastFunction != null ? lastFunction.getToken().getIndex() : 0;
throw new SimpleParserException("function has no ending token", index);
}
}
use of org.apache.camel.language.simple.ast.SimpleNode in project camel by apache.
the class SimplePredicateParser method prepareBinaryExpressions.
/**
* Prepares binary expressions.
* <p/>
* This process prepares the binary expressions in the AST. This is done
* by linking the binary operator with both the right and left hand side
* nodes, to have the AST graph updated and prepared properly.
* <p/>
* So when the AST node is later used to create the {@link Predicate}s
* to be used by Camel then the AST graph has a linked and prepared
* graph of nodes which represent the input expression.
*/
private void prepareBinaryExpressions() {
Stack<SimpleNode> stack = new Stack<SimpleNode>();
SimpleNode left = null;
for (int i = 0; i < nodes.size(); i++) {
if (left == null) {
left = i > 0 ? nodes.get(i - 1) : null;
}
SimpleNode token = nodes.get(i);
SimpleNode right = i < nodes.size() - 1 ? nodes.get(i + 1) : null;
if (token instanceof BinaryExpression) {
BinaryExpression binary = (BinaryExpression) token;
// remember the binary operator
String operator = binary.getOperator().toString();
if (left == null) {
throw new SimpleParserException("Binary operator " + operator + " has no left hand side token", token.getToken().getIndex());
}
if (!binary.acceptLeftNode(left)) {
throw new SimpleParserException("Binary operator " + operator + " does not support left hand side token " + left.getToken(), token.getToken().getIndex());
}
if (right == null) {
throw new SimpleParserException("Binary operator " + operator + " has no right hand side token", token.getToken().getIndex());
}
if (!binary.acceptRightNode(right)) {
throw new SimpleParserException("Binary operator " + operator + " does not support right hand side token " + right.getToken(), token.getToken().getIndex());
}
// pop previous as we need to replace it with this binary operator
stack.pop();
stack.push(token);
// advantage after the right hand side
i++;
// this token is now the left for the next loop
left = token;
} else {
// clear left
left = null;
stack.push(token);
}
}
nodes.clear();
nodes.addAll(stack);
}
Aggregations