/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.regexp; import java.util.BitSet; import java.util.regex.Pattern; import org.joni.Matcher; import org.joni.Option; import org.joni.Regex; /** * {@link RegExpMatcher} implementation for Joni {@link Regex} regular expressions */ final class JoniRegExpMatcher implements RegExpMatcher { // Java pattern for the input RegExp private final String regex; // Java flags for the input RegExp private final int flags; private final BitSet negativeLAGroups; private Regex pattern; // FIXME: Memory issue? private CharSequence lastInput = null; private byte[] lastInputBytes = null; public JoniRegExpMatcher(String regex, int flags, BitSet negativeLAGroups) { this.regex = regex; this.flags = flags; this.negativeLAGroups = negativeLAGroups; } private UEncoding getEncoding() { if ((this.flags & Pattern.UNICODE_CASE) != 0) { return UTF32Encoding.INSTANCE; } return UCS2Encoding.INSTANCE; } private Regex getPattern() { if (pattern == null) { int flags = 0; if ((this.flags & Pattern.MULTILINE) != 0) { flags |= Option.NEGATE_SINGLELINE; } else { flags |= Option.SINGLELINE; } if ((this.flags & Pattern.CASE_INSENSITIVE) != 0) { flags |= Option.IGNORECASE; } UEncoding enc = getEncoding(); byte[] bytes = enc.toBytes(regex); int length = bytes.length - enc.minLength(); pattern = new Regex(bytes, 0, length, flags, enc, JoniSyntax.ECMAScript); } return pattern; } @Override public JoniMatchState matcher(String s) { UEncoding enc = getEncoding(); if (s != lastInput) { lastInput = s; lastInputBytes = enc.toBytes(s); } int length = lastInputBytes.length - enc.minLength(); Matcher matcher = getPattern().matcher(lastInputBytes, 0, length); return new JoniMatchState(enc, matcher, s, negativeLAGroups); } @Override public JoniMatchState matcher(CharSequence s) { UEncoding enc = getEncoding(); if (s != lastInput) { lastInput = s; lastInputBytes = enc.toBytes(s); } int length = lastInputBytes.length - enc.minLength(); Matcher matcher = getPattern().matcher(lastInputBytes, 0, length); return new JoniMatchState(enc, matcher, s, negativeLAGroups); } @Override public JoniRegExpMatcher clone() { JoniRegExpMatcher clone = new JoniRegExpMatcher(regex, flags, negativeLAGroups); clone.pattern = pattern; return clone; } @Override public String toString() { StringBuilder sb = new StringBuilder(3); if ((flags & Pattern.CASE_INSENSITIVE) != 0) { sb.append('i'); } if ((flags & Pattern.MULTILINE) != 0) { sb.append('m'); } if ((flags & Pattern.UNICODE_CASE) != 0) { sb.append('u'); } return String.format("regex=%s, flags=%s", regex, sb); } }