/* * 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.parser; import juzu.impl.router.regex.SyntaxException; import juzu.impl.common.Location; /** * An hand crafted parser for the compact route syntax. * * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ public class RouteParser { /** . */ public static final int CODE_UNCLOSED_EXPR = 0; /** . */ public static final int CODE_MISSING_EXPR_IDENT = 1; /** . */ private static final int READ_PATH = 0; /** . */ private static final int READ_SEGMENT = 1; /** . */ private static final int READ_DONE = 7; /** . */ private static final int EXPR_BEGIN = 0; /** . */ private static final int EXPR_IDENT = 1; public static void parse(CharSequence s, RouteParserHandler handler) throws SyntaxException { parse(s, 0, s.length(), handler); } private static void parse(CharSequence s, int from, final int to, RouteParserHandler handler) throws SyntaxException { int status = READ_PATH; int pos = 0; while (true) { // switch (status) { case READ_PATH: { if (from < to) { char c = s.charAt(from); if (c == '/') { from++; } else { handler.segmentOpen(); status = READ_SEGMENT; pos = from; } } else { boolean slash = from > pos && s.charAt(from - 1) == '/'; handler.pathClose(slash); status = READ_DONE; } break; } case READ_SEGMENT: { if (from < to) { char c = s.charAt(from); if (c == '{') { if (from - pos > 0) { handler.segmentChunk(s, pos, from); } handler.exprOpen(); from = pos = parseExpr(s, from + 1, to, handler); handler.exprClose(); } else if (c == '/') { status = READ_PATH; if (from - pos > 0) { handler.segmentChunk(s, pos, from); } handler.segmentClose(); } else { ++from; } } else { if (from - pos > 0) { handler.segmentChunk(s, pos, from); } handler.segmentClose(); status = READ_PATH; } break; } case READ_DONE: return; default: throw new UnsupportedOperationException("Need to implement status " + status); } } } private static int parseExpr(CharSequence s, int from, int to, RouteParserHandler handler) throws SyntaxException { int status = EXPR_BEGIN; int pos = from; while (true) { switch (status) { case EXPR_BEGIN: { if (from < to) { char c = s.charAt(from); if (c == '}') { throw new SyntaxException(CODE_MISSING_EXPR_IDENT, "Missing expression identifier at " + from, Location.at(1 + from)); } else { status = EXPR_IDENT; break; } } else { throw new SyntaxException(CODE_UNCLOSED_EXPR, "Unclosed expression at " + from, Location.at(1 + from)); } } case EXPR_IDENT: { if (from < to) { char c = s.charAt(from); if (c == '}') { handler.exprIdent(s, pos, from); return ++from; } else { ++from; break; } } else { throw new SyntaxException(CODE_UNCLOSED_EXPR, "Unclosed expression at " + from, Location.at(1 + from)); } } default: throw new UnsupportedOperationException("todo"); } } } }