juzu.impl.router.ValueResolverFactory Maven / Gradle / Ivy
/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.router;
import juzu.impl.router.regex.GroupType;
import juzu.impl.router.regex.RENode;
import juzu.impl.router.regex.RERenderer;
import juzu.impl.router.regex.REVisitor;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
/** @author Julien Viet */
class ValueResolverFactory extends REVisitor {
static class Alternative {
/** . */
private StringBuilder resolvingExpression = new StringBuilder();
/** . */
private String prefix;
/** . */
private String suffix;
/** . */
private StringBuilder buffer = new StringBuilder();
/** . */
private StringBuilder valueMatcher = new StringBuilder();
StringBuilder getResolvingExpression() {
return resolvingExpression;
}
String getPrefix() {
return prefix;
}
String getSuffix() {
return suffix;
}
StringBuilder getValueMatcher() {
return valueMatcher;
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + resolvingExpression + "]";
}
}
/** . */
private List alternatives = new ArrayList();
/** . */
private Alternative current = null;
List foo(RENode root) {
alternatives.clear();
root.accept(this);
return alternatives;
}
@Override
protected void visit(RENode.Disjunction disjunction) throws RuntimeException {
if (current != null) {
RENode.Alternative alternative = disjunction.getAlternative();
if (alternative != null) {
alternative.accept(this);
}
}
else {
RENode.Alternative alternative = disjunction.getAlternative();
if (alternative != null) {
current = new Alternative();
alternative.accept(this);
current.suffix = current.buffer.toString();
current.buffer.setLength(0);
alternatives.add(current);
current = null;
}
//
RENode.Disjunction next = disjunction.getNext();
if (next != null) {
next.accept(this);
}
}
}
@Override
protected void visit(RENode.Group expr) throws RuntimeException {
if (expr.getType() == GroupType.CAPTURING_GROUP) {
try {
RERenderer renderer = new RERenderer(current.resolvingExpression);
expr.accept(renderer);
}
catch (IOException e) {
// Should not happen
throw new AssertionError(e);
}
try {
RERenderer renderer = new RERenderer(current.valueMatcher);
expr.accept(renderer);
}
catch (IOException e) {
// Should not happen
throw new AssertionError(e);
}
current.prefix = current.buffer.toString();
current.buffer.setLength(0);
}
else {
super.visit(expr);
}
}
@Override
protected void visit(RENode.Alternative alternative) throws RuntimeException {
alternative.getExpr().accept(this);
RENode.Alternative next = alternative.getNext();
if (next != null) {
next.accept(this);
}
}
@Override
protected void visit(RENode.Char expr) throws RuntimeException {
for (int i = expr.getMin();i > 0;i--) {
current.resolvingExpression.append(expr.getValue());
current.buffer.append(expr.getValue());
}
}
@Override
protected void visit(RENode.Any expr) throws RuntimeException {
for (int i = expr.getMin();i > 0;i--) {
// Any can be 'a'
current.resolvingExpression.append('a');
current.buffer.append('a');
}
}
/** . */
private Solver solver;
@Override
protected void visit(RENode.CharacterClass expr) throws RuntimeException {
expr.getExpr().accept(this);
for (int i = expr.getMin();i > 0;i--) {
if (solver.hasNext()) {
char c = solver.next();
current.resolvingExpression.append(c);
current.buffer.append(c);
solver.reset();
}
else {
throw new UnsupportedOperationException("wtf?");
}
}
}
@Override
protected void visit(RENode.CharacterClassExpr.Or expr) throws RuntimeException {
expr.getLeft().accept(this);
Solver left = solver;
expr.getRight().accept(this);
Solver right = solver;
solver = new Solver.Or(left, right);
}
@Override
protected void visit(RENode.CharacterClassExpr.Range expr) throws RuntimeException {
RENode.CharacterClassExpr.Char from = expr.getFrom();
RENode.CharacterClassExpr.Char to = expr.getTo();
solver = new Solver.Range(from.getValue(), to.getValue());
}
@Override
protected void visit(RENode.CharacterClassExpr.Char expr) throws RuntimeException {
solver = new Solver.Char(expr.getValue());
}
@Override
protected void visit(RENode.CharacterClassExpr.And expr) throws RuntimeException {
expr.getLeft().accept(this);
Solver left = solver;
expr.getRight().accept(this);
Solver right = solver;
solver = new Solver.And(left, right);
}
@Override
protected void visit(RENode.CharacterClassExpr.Not expr) throws RuntimeException {
RENode.CharacterClassExpr negated = expr.getNegated();
if (negated == null) {
// Do nothing ?
}
else {
negate(negated);
}
}
private void negate(RENode.CharacterClassExpr negated) throws RuntimeException {
if (negated instanceof RENode.CharacterClassExpr.Not) {
RENode.CharacterClassExpr nested = ((RENode.CharacterClassExpr.Not)negated).getNegated();
if (nested != null) {
nested.accept(this);
}
}
else if (negated instanceof RENode.CharacterClassExpr.Or) {
RENode.CharacterClassExpr.Or or = (RENode.CharacterClassExpr.Or)negated;
negate(or.getLeft());
Solver left = solver;
negate(or.getRight());
Solver right = solver;
solver = new Solver.And(left, right);
}
else if (negated instanceof RENode.CharacterClassExpr.And) {
RENode.CharacterClassExpr.And or = (RENode.CharacterClassExpr.And)negated;
negate(or.getLeft());
Solver left = solver;
negate(or.getRight());
Solver right = solver;
solver = new Solver.Or(left, right);
}
else {
char from;
char to;
if (negated instanceof RENode.CharacterClassExpr.Char) {
from = to = ((RENode.CharacterClassExpr.Char)negated).getValue();
}
else if (negated instanceof RENode.CharacterClassExpr.Range) {
RENode.CharacterClassExpr.Range range = (RENode.CharacterClassExpr.Range)negated;
from = range.getFrom().getValue();
to = range.getTo().getValue();
}
else {
throw new UnsupportedOperationException();
}
Solver.Range left = null;
Character c = prevValid(--from);
if (c != null) {
left = new Solver.Range(' ', c);
}
Solver.Range right = null;
c = nextValid(++to);
if (c != null) {
right = new Solver.Range(c, Character.MAX_VALUE);
}
if (left == null) {
if (right != null) {
solver = right;
}
}
else {
if (right == null) {
solver = left;
}
else {
solver = new Solver.Or(left, right);
}
}
}
}
private static abstract class Solver implements Iterator {
public void remove() {
throw new UnsupportedOperationException();
}
protected abstract void reset();
private static class And extends Solver {
/** . */
private final Solver left;
/** . */
private final Solver right;
/** . */
private Character leftChar;
/** . */
private Character next;
private And(Solver left, Solver right) {
this.left = left;
this.right = right;
this.next = null;
this.leftChar = null;
}
public boolean hasNext() {
while (next == null) {
if (leftChar == null) {
if (left.hasNext()) {
leftChar = left.next();
}
else {
break;
}
}
if (right.hasNext()) {
Character c = right.next();
if (c == leftChar) {
next = c;
}
}
else {
right.reset();
leftChar = null;
}
}
return next != null;
}
public Character next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
Character tmp = next;
next = null;
return tmp;
}
@Override
protected void reset() {
left.reset();
right.reset();
}
}
private static class Or extends Solver {
/** . */
private final Solver left;
/** . */
private final Solver right;
private Or(Solver left, Solver right) {
this.left = left;
this.right = right;
}
public boolean hasNext() {
return left.hasNext() || right.hasNext();
}
public Character next() {
if (left.hasNext()) {
return left.next();
}
else if (right.hasNext()) {
return right.next();
}
throw new NoSuchElementException();
}
@Override
protected void reset() {
left.reset();
right.reset();
}
}
private static class Range extends Solver {
/** . */
private char from;
/** . */
private char current;
/** . */
private char to;
private Range(char from, char to) {
this.from = from;
this.current = from;
this.to = to;
}
public boolean hasNext() {
return current < to;
}
public Character next() {
if (current >= to) {
throw new NoSuchElementException();
}
return current++;
}
@Override
protected void reset() {
current = from;
}
}
private static class Char extends Solver {
/** . */
private final char value;
/** . */
private boolean done;
private Char(char value) {
this.value = value;
this.done = false;
}
public boolean hasNext() {
return !done;
}
public Character next() {
if (done) {
throw new NoSuchElementException();
}
done = true;
return value;
}
@Override
protected void reset() {
done = false;
}
}
}
private static Character nextValid(char from) {
while (true) {
if (!Character.isISOControl(from)) {
return from;
}
else {
if (from == Character.MAX_VALUE) {
return null;
}
else {
from++;
}
}
}
}
private static Character prevValid(char from) {
while (true) {
if (!Character.isISOControl(from)) {
return from;
}
else {
if (from == Character.MIN_VALUE) {
return null;
}
else {
from--;
}
}
}
}
}