forked from google/re2j
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInst.java
More file actions
138 lines (126 loc) · 3.86 KB
/
Copy pathInst.java
File metadata and controls
138 lines (126 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
* Copyright (c) 2020 The Go Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
*/
// Original Go source here:
// http://code.google.com/p/go/source/browse/src/pkg/regexp/syntax/prog.go
package com.google.re2j;
/**
* A single instruction in the regular expression virtual machine.
*
* @see http://swtch.com/~rsc/regexp/regexp2.html
*/
final class Inst {
public static final int ALT = 1;
public static final int ALT_MATCH = 2;
public static final int CAPTURE = 3;
public static final int EMPTY_WIDTH = 4;
public static final int FAIL = 5;
public static final int MATCH = 6;
public static final int NOP = 7;
public static final int RUNE = 8;
public static final int RUNE1 = 9;
public static final int RUNE_ANY = 10;
public static final int RUNE_ANY_NOT_NL = 11;
int op;
int out; // all but MATCH, FAIL
int arg; // ALT, ALT_MATCH, CAPTURE, EMPTY_WIDTH
int[] runes; // length==1 => exact match
// otherwise a list of [lo,hi] pairs. hi is *inclusive*.
// REVIEWERS: why not half-open intervals?
Inst(int op) {
this.op = op;
}
static boolean isRuneOp(int op) {
return RUNE <= op && op <= RUNE_ANY_NOT_NL;
}
// MatchRune returns true if the instruction matches (and consumes) r.
// It should only be called when op == InstRune.
boolean matchRune(int r) {
// Special case: single-rune slice is from literal string, not char
// class.
if (runes.length == 1) {
int r0 = runes[0];
// If this pattern is case-insensitive, apply Unicode case folding to compare the two runes.
// Note that this may result in a case-folding loop when executed on a JVM newer than the version used
// to generate Unicode data for re2j, so attempt to reduce the chance of that occurring
// by performing case folding on |r0| from the pattern rather than |r| from the input.
if ((arg & RE2.FOLD_CASE) != 0) {
return Unicode.equalsIgnoreCase(r0, r);
}
return r == r0;
}
// Peek at the first few pairs.
// Should handle ASCII well.
for (int j = 0; j < runes.length && j <= 8; j += 2) {
if (r < runes[j]) {
return false;
}
if (r <= runes[j + 1]) {
return true;
}
}
// Otherwise binary search.
for (int lo = 0, hi = runes.length / 2; lo < hi; ) {
int m = lo + (hi - lo) / 2;
int c = runes[2 * m];
if (c <= r) {
if (r <= runes[2 * m + 1]) {
return true;
}
lo = m + 1;
} else {
hi = m;
}
}
return false;
}
@Override
public String toString() {
switch (op) {
case ALT:
return "alt -> " + out + ", " + arg;
case ALT_MATCH:
return "altmatch -> " + out + ", " + arg;
case CAPTURE:
return "cap " + arg + " -> " + out;
case EMPTY_WIDTH:
return "empty " + arg + " -> " + out;
case MATCH:
return "match";
case FAIL:
return "fail";
case NOP:
return "nop -> " + out;
case RUNE:
if (runes == null) {
return "rune <null>"; // can't happen
}
return "rune "
+ escapeRunes(runes)
+ (((arg & RE2.FOLD_CASE) != 0) ? "/i" : "")
+ " -> "
+ out;
case RUNE1:
return "rune1 " + escapeRunes(runes) + " -> " + out;
case RUNE_ANY:
return "any -> " + out;
case RUNE_ANY_NOT_NL:
return "anynotnl -> " + out;
default:
throw new IllegalStateException("unhandled case in Inst.toString");
}
}
// Returns an RE2 expression matching exactly |runes|.
private static String escapeRunes(int[] runes) {
StringBuilder out = new StringBuilder();
out.append('"');
for (int rune : runes) {
Utils.escapeRune(out, rune);
}
out.append('"');
return out.toString();
}
}