1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime.regexp;
27
28import static java.util.regex.Pattern.CASE_INSENSITIVE;
29import static java.util.regex.Pattern.MULTILINE;
30import static java.util.regex.Pattern.UNICODE_CASE;
31
32import java.util.regex.Matcher;
33import java.util.regex.Pattern;
34import java.util.regex.PatternSyntaxException;
35import jdk.nashorn.internal.runtime.ParserException;
36
37/**
38 * Default regular expression implementation based on java.util.regex package.
39 *
40 * Note that this class is not thread-safe as it stores the current match result
41 * and the string being matched in instance fields.
42 */
43public class JdkRegExp extends RegExp {
44
45    /** Java regexp pattern to use for match. We compile to one of these */
46    private Pattern pattern;
47
48    /**
49     * Construct a Regular expression from the given {@code source} and {@code flags} strings.
50     *
51     * @param source RegExp source string
52     * @param flags RegExp flag string
53     * @throws ParserException if flags is invalid or source string has syntax error.
54     */
55    public JdkRegExp(final String source, final String flags) throws ParserException {
56        super(source, flags);
57
58        int intFlags = 0;
59
60        if (isIgnoreCase()) {
61            intFlags |= CASE_INSENSITIVE | UNICODE_CASE;
62        }
63        if (isMultiline()) {
64            intFlags |= MULTILINE;
65        }
66
67        try {
68            RegExpScanner parsed;
69
70            try {
71                parsed = RegExpScanner.scan(source);
72            } catch (final PatternSyntaxException e) {
73                // refine the exception with a better syntax error, if this
74                // passes, just rethrow what we have
75                Pattern.compile(source, intFlags);
76                throw e;
77            }
78
79            if (parsed != null) {
80                this.pattern = Pattern.compile(parsed.getJavaPattern(), intFlags);
81                this.groupsInNegativeLookahead = parsed.getGroupsInNegativeLookahead();
82            }
83        } catch (final PatternSyntaxException e2) {
84            throwParserException("syntax", e2.getMessage());
85        }
86    }
87
88    @Override
89    public RegExpMatcher match(final String str) {
90        if (pattern == null) {
91            return null; // never matches or similar, e.g. a[]
92        }
93
94        return new DefaultMatcher(str);
95    }
96
97    class DefaultMatcher implements RegExpMatcher {
98        final String input;
99        final Matcher defaultMatcher;
100
101        DefaultMatcher(final String input) {
102            this.input = input;
103            this.defaultMatcher = pattern.matcher(input);
104        }
105
106        @Override
107        public boolean search(final int start) {
108            return defaultMatcher.find(start);
109        }
110
111        @Override
112        public String getInput() {
113            return input;
114        }
115
116        @Override
117        public int start() {
118            return defaultMatcher.start();
119        }
120
121        @Override
122        public int start(final int group) {
123            return defaultMatcher.start(group);
124        }
125
126        @Override
127        public int end() {
128            return defaultMatcher.end();
129        }
130
131        @Override
132        public int end(final int group) {
133            return defaultMatcher.end(group);
134        }
135
136        @Override
137        public String group() {
138            return defaultMatcher.group();
139        }
140
141        @Override
142        public String group(final int group) {
143            return defaultMatcher.group(group);
144        }
145
146        @Override
147        public int groupCount() {
148            return defaultMatcher.groupCount();
149        }
150    }
151
152}
153