/* * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.joni; import org.jcodings.Encoding; import org.joni.ast.AnchorNode; import org.joni.ast.BackRefNode; import org.joni.ast.CClassNode; import org.joni.ast.CTypeNode; import org.joni.ast.CallNode; import org.joni.ast.ConsAltNode; import org.joni.ast.EncloseNode; import org.joni.ast.Node; import org.joni.ast.QuantifierNode; import org.joni.ast.StringNode; import org.joni.constants.NodeType; import org.joni.exception.ErrorMessages; import org.joni.exception.InternalException; import org.joni.exception.SyntaxException; abstract class Compiler implements ErrorMessages { protected final Analyser analyser; protected final Encoding enc; protected final Regex regex; protected Compiler(Analyser analyser) { this.analyser = analyser; this.regex = analyser.regex; this.enc = regex.enc; } final void compile() { prepare(); compileTree(analyser.root); finish(); } protected abstract void prepare(); protected abstract void finish(); protected abstract void compileAltNode(ConsAltNode node); private void compileStringRawNode(StringNode sn) { if (sn.length() <= 0) return; addCompileString(sn.bytes, sn.p, 1 /*sb*/, sn.length(), false); } private void compileStringNode(StringNode node) { StringNode sn = node; if (sn.length() <= 0) return; boolean ambig = sn.isAmbig(); int p, prev; p = prev = sn.p; int end = sn.end; byte[]bytes = sn.bytes; int prevLen = enc.length(bytes, p, end); p += prevLen; int slen = 1; while (p < end) { int len = enc.length(bytes, p, end); if (len == prevLen) { slen++; } else { addCompileString(bytes, prev, prevLen, slen, ambig); prev = p; slen = 1; prevLen = len; } p += len; } addCompileString(bytes, prev, prevLen, slen, ambig); } protected abstract void addCompileString(byte[]bytes, int p, int mbLength, int strLength, boolean ignoreCase); protected abstract void compileCClassNode(CClassNode node); protected abstract void compileCTypeNode(CTypeNode node); protected abstract void compileAnyCharNode(); protected abstract void compileCallNode(CallNode node); protected abstract void compileBackrefNode(BackRefNode node); protected abstract void compileCECQuantifierNode(QuantifierNode node); protected abstract void compileNonCECQuantifierNode(QuantifierNode node); protected abstract void compileOptionNode(EncloseNode node); protected abstract void compileEncloseNode(EncloseNode node); protected abstract void compileAnchorNode(AnchorNode node); protected final void compileTree(Node node) { switch (node.getType()) { case NodeType.LIST: ConsAltNode lin = (ConsAltNode)node; do { compileTree(lin.car); } while ((lin = lin.cdr) != null); break; case NodeType.ALT: compileAltNode((ConsAltNode)node); break; case NodeType.STR: StringNode sn = (StringNode)node; if (sn.isRaw()) { compileStringRawNode(sn); } else { compileStringNode(sn); } break; case NodeType.CCLASS: compileCClassNode((CClassNode)node); break; case NodeType.CTYPE: compileCTypeNode((CTypeNode)node); break; case NodeType.CANY: compileAnyCharNode(); break; case NodeType.BREF: compileBackrefNode((BackRefNode)node); break; case NodeType.CALL: if (Config.USE_SUBEXP_CALL) { compileCallNode((CallNode)node); break; } // USE_SUBEXP_CALL break; case NodeType.QTFR: if (Config.USE_COMBINATION_EXPLOSION_CHECK) { compileCECQuantifierNode((QuantifierNode)node); } else { compileNonCECQuantifierNode((QuantifierNode)node); } break; case NodeType.ENCLOSE: EncloseNode enode = (EncloseNode)node; if (enode.isOption()) { compileOptionNode(enode); } else { compileEncloseNode(enode); } break; case NodeType.ANCHOR: compileAnchorNode((AnchorNode)node); break; default: // undefined node type newInternalException(ERR_PARSER_BUG); } // switch } protected final void compileTreeNTimes(Node node, int n) { for (int i=0; i