Thu, 16 May 2013 19:52:39 +0200
8012359: Increase code coverage in Joni
Reviewed-by: jlaskey, lagergren
hannesw@115 | 1 | /* |
hannesw@115 | 2 | * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. |
hannesw@115 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
hannesw@115 | 4 | * |
hannesw@115 | 5 | * This code is free software; you can redistribute it and/or modify it |
hannesw@115 | 6 | * under the terms of the GNU General Public License version 2 only, as |
hannesw@115 | 7 | * published by the Free Software Foundation. Oracle designates this |
hannesw@115 | 8 | * particular file as subject to the "Classpath" exception as provided |
hannesw@115 | 9 | * by Oracle in the LICENSE file that accompanied this code. |
hannesw@115 | 10 | * |
hannesw@115 | 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
hannesw@115 | 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
hannesw@115 | 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
hannesw@115 | 14 | * version 2 for more details (a copy is included in the LICENSE file that |
hannesw@115 | 15 | * accompanied this code). |
hannesw@115 | 16 | * |
hannesw@115 | 17 | * You should have received a copy of the GNU General Public License version |
hannesw@115 | 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
hannesw@115 | 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
hannesw@115 | 20 | * |
hannesw@115 | 21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
hannesw@115 | 22 | * or visit www.oracle.com if you need additional information or have any |
hannesw@115 | 23 | * questions. |
hannesw@115 | 24 | */ |
hannesw@115 | 25 | |
hannesw@115 | 26 | package jdk.nashorn.internal.runtime.regexp; |
hannesw@115 | 27 | |
hannesw@115 | 28 | import jdk.nashorn.internal.runtime.ParserException; |
hannesw@115 | 29 | import jdk.nashorn.internal.runtime.regexp.joni.Matcher; |
hannesw@115 | 30 | import jdk.nashorn.internal.runtime.regexp.joni.Option; |
hannesw@115 | 31 | import jdk.nashorn.internal.runtime.regexp.joni.Regex; |
hannesw@115 | 32 | import jdk.nashorn.internal.runtime.regexp.joni.Region; |
hannesw@115 | 33 | import jdk.nashorn.internal.runtime.regexp.joni.Syntax; |
hannesw@115 | 34 | import jdk.nashorn.internal.runtime.regexp.joni.exception.JOniException; |
hannesw@115 | 35 | |
hannesw@115 | 36 | import java.util.regex.Pattern; |
hannesw@115 | 37 | import java.util.regex.PatternSyntaxException; |
hannesw@115 | 38 | |
hannesw@115 | 39 | /** |
hannesw@115 | 40 | * Regular expression implementation based on the Joni engine from the JRuby project. |
hannesw@115 | 41 | */ |
hannesw@115 | 42 | public class JoniRegExp extends RegExp { |
hannesw@115 | 43 | |
hannesw@115 | 44 | /** Compiled Joni Regex */ |
hannesw@115 | 45 | private Regex regex; |
hannesw@115 | 46 | |
hannesw@115 | 47 | /** Matcher */ |
hannesw@115 | 48 | private RegExpMatcher matcher; |
hannesw@115 | 49 | |
hannesw@115 | 50 | /** |
hannesw@115 | 51 | * Construct a Regular expression from the given {@code pattern} and {@code flags} strings. |
hannesw@115 | 52 | * |
hannesw@115 | 53 | * @param pattern RegExp pattern string |
hannesw@115 | 54 | * @param flags RegExp flag string |
hannesw@115 | 55 | * @throws ParserException if flags is invalid or pattern string has syntax error. |
hannesw@115 | 56 | */ |
hannesw@115 | 57 | public JoniRegExp(final String pattern, final String flags) throws ParserException { |
hannesw@115 | 58 | super(pattern, flags); |
hannesw@115 | 59 | |
hannesw@115 | 60 | int option = Option.SINGLELINE; |
hannesw@115 | 61 | |
hannesw@115 | 62 | if (this.isIgnoreCase()) { |
hannesw@115 | 63 | option |= Option.IGNORECASE; |
hannesw@115 | 64 | } |
hannesw@115 | 65 | if (this.isMultiline()) { |
hannesw@115 | 66 | option &= ~Option.SINGLELINE; |
hannesw@115 | 67 | option |= Option.NEGATE_SINGLELINE; |
hannesw@115 | 68 | } |
hannesw@115 | 69 | |
hannesw@115 | 70 | try { |
hannesw@115 | 71 | RegExpScanner parsed; |
hannesw@115 | 72 | |
hannesw@115 | 73 | try { |
hannesw@115 | 74 | parsed = RegExpScanner.scan(pattern); |
hannesw@115 | 75 | } catch (final PatternSyntaxException e) { |
hannesw@115 | 76 | // refine the exception with a better syntax error, if this |
hannesw@115 | 77 | // passes, just rethrow what we have |
hannesw@115 | 78 | Pattern.compile(pattern, 0); |
hannesw@115 | 79 | throw e; |
hannesw@115 | 80 | } |
hannesw@115 | 81 | |
hannesw@115 | 82 | if (parsed != null) { |
hannesw@115 | 83 | char[] javaPattern = parsed.getJavaPattern().toCharArray(); |
hannesw@115 | 84 | this.regex = new Regex(javaPattern, 0, javaPattern.length, option, Syntax.JAVASCRIPT); |
hannesw@115 | 85 | this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead(); |
hannesw@115 | 86 | } |
hannesw@115 | 87 | } catch (final PatternSyntaxException e2) { |
hannesw@115 | 88 | throwParserException("syntax", e2.getMessage()); |
hannesw@115 | 89 | } catch (JOniException e2) { |
hannesw@115 | 90 | throwParserException("syntax", e2.getMessage()); |
hannesw@115 | 91 | } |
hannesw@115 | 92 | } |
hannesw@115 | 93 | |
hannesw@115 | 94 | @Override |
hannesw@115 | 95 | public RegExpMatcher match(final String input) { |
hannesw@115 | 96 | if (regex == null) { |
hannesw@115 | 97 | return null; |
hannesw@115 | 98 | } |
hannesw@115 | 99 | |
lagergren@139 | 100 | RegExpMatcher currentMatcher = this.matcher; |
hannesw@115 | 101 | |
lagergren@139 | 102 | if (currentMatcher == null || input != currentMatcher.getInput()) { |
lagergren@139 | 103 | currentMatcher = new JoniMatcher(input); |
lagergren@139 | 104 | this.matcher = currentMatcher; |
hannesw@115 | 105 | } |
hannesw@115 | 106 | |
lagergren@139 | 107 | return currentMatcher; |
hannesw@115 | 108 | } |
hannesw@115 | 109 | |
hannesw@115 | 110 | /** |
hannesw@115 | 111 | * RegExp Factory class for Joni regexp engine. |
hannesw@115 | 112 | */ |
hannesw@115 | 113 | public static class Factory extends RegExpFactory { |
hannesw@115 | 114 | |
hannesw@115 | 115 | @Override |
hannesw@273 | 116 | public RegExp compile(final String pattern, final String flags) throws ParserException { |
hannesw@115 | 117 | return new JoniRegExp(pattern, flags); |
hannesw@115 | 118 | } |
hannesw@115 | 119 | |
hannesw@115 | 120 | } |
hannesw@115 | 121 | |
hannesw@115 | 122 | class JoniMatcher implements RegExpMatcher { |
hannesw@115 | 123 | final String input; |
lagergren@247 | 124 | final Matcher joniMatcher; |
hannesw@115 | 125 | |
hannesw@115 | 126 | JoniMatcher(final String input) { |
hannesw@115 | 127 | this.input = input; |
lagergren@247 | 128 | this.joniMatcher = regex.matcher(input.toCharArray()); |
hannesw@115 | 129 | } |
hannesw@115 | 130 | |
hannesw@115 | 131 | @Override |
hannesw@115 | 132 | public boolean search(final int start) { |
lagergren@247 | 133 | return joniMatcher.search(start, input.length(), Option.NONE) > -1; |
hannesw@115 | 134 | } |
hannesw@115 | 135 | |
hannesw@115 | 136 | @Override |
hannesw@115 | 137 | public String getInput() { |
hannesw@115 | 138 | return input; |
hannesw@115 | 139 | } |
hannesw@115 | 140 | |
hannesw@115 | 141 | @Override |
hannesw@115 | 142 | public int start() { |
lagergren@247 | 143 | return joniMatcher.getBegin(); |
hannesw@115 | 144 | } |
hannesw@115 | 145 | |
hannesw@115 | 146 | @Override |
hannesw@115 | 147 | public int start(final int group) { |
lagergren@247 | 148 | return group == 0 ? start() : joniMatcher.getRegion().beg[group]; |
hannesw@115 | 149 | } |
hannesw@115 | 150 | |
hannesw@115 | 151 | @Override |
hannesw@115 | 152 | public int end() { |
lagergren@247 | 153 | return joniMatcher.getEnd(); |
hannesw@115 | 154 | } |
hannesw@115 | 155 | |
hannesw@115 | 156 | @Override |
hannesw@115 | 157 | public int end(final int group) { |
lagergren@247 | 158 | return group == 0 ? end() : joniMatcher.getRegion().end[group]; |
hannesw@115 | 159 | } |
hannesw@115 | 160 | |
hannesw@115 | 161 | @Override |
hannesw@115 | 162 | public String group() { |
lagergren@247 | 163 | return input.substring(joniMatcher.getBegin(), joniMatcher.getEnd()); |
hannesw@115 | 164 | } |
hannesw@115 | 165 | |
hannesw@115 | 166 | @Override |
hannesw@115 | 167 | public String group(final int group) { |
hannesw@115 | 168 | if (group == 0) { |
hannesw@115 | 169 | return group(); |
hannesw@115 | 170 | } |
lagergren@247 | 171 | final Region region = joniMatcher.getRegion(); |
hannesw@115 | 172 | return input.substring(region.beg[group], region.end[group]); |
hannesw@115 | 173 | } |
hannesw@115 | 174 | |
hannesw@115 | 175 | @Override |
hannesw@115 | 176 | public int groupCount() { |
lagergren@247 | 177 | final Region region = joniMatcher.getRegion(); |
hannesw@115 | 178 | return region == null ? 0 : region.numRegs - 1; |
hannesw@115 | 179 | } |
hannesw@115 | 180 | } |
hannesw@115 | 181 | } |