Skip to content

Commit 283fd66

Browse files
committed
Implement sre parse_template as a Truffle Node.
1 parent 937fcd9 commit 283fd66

File tree

6 files changed

+610
-140
lines changed

6 files changed

+610
-140
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/MathModuleBuiltins.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,10 +1043,12 @@ public Gcd2Node(boolean isRecursive) {
10431043
abstract Object execute(VirtualFrame frame, Object a, Object b);
10441044

10451045
private static long count(long a, long b) {
1046-
if (b == 0) {
1047-
return a;
1046+
while (b != 0) {
1047+
long tmp = b;
1048+
b = a % b;
1049+
a = tmp;
10481050
}
1049-
return count(b, a % b);
1051+
return a;
10501052
}
10511053

10521054
@Specialization

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/SREModuleBuiltins.java

Lines changed: 197 additions & 38 deletions
Large diffs are not rendered by default.
Lines changed: 364 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,364 @@
1+
/*
2+
* Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins.modules;
42+
43+
import com.oracle.graal.python.builtins.objects.str.StringBuiltinsFactory;
44+
import com.oracle.truffle.api.CompilerAsserts;
45+
import com.oracle.truffle.api.CompilerDirectives;
46+
import com.oracle.truffle.api.dsl.Cached;
47+
import com.oracle.truffle.api.dsl.GenerateCached;
48+
import com.oracle.truffle.api.dsl.GenerateInline;
49+
import com.oracle.truffle.api.dsl.GenerateUncached;
50+
import com.oracle.truffle.api.dsl.ImportStatic;
51+
import com.oracle.truffle.api.dsl.NeverDefault;
52+
import com.oracle.truffle.api.dsl.Specialization;
53+
import com.oracle.truffle.api.interop.ArityException;
54+
import com.oracle.truffle.api.interop.InteropLibrary;
55+
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
56+
import com.oracle.truffle.api.interop.UnknownIdentifierException;
57+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
58+
import com.oracle.truffle.api.interop.UnsupportedTypeException;
59+
import com.oracle.truffle.api.library.CachedLibrary;
60+
import com.oracle.truffle.api.nodes.Node;
61+
import com.oracle.truffle.api.strings.TruffleString;
62+
63+
public final class TRegexUtil {
64+
65+
private TRegexUtil() {
66+
// should not be constructed
67+
}
68+
69+
public static final class Props {
70+
private Props() {
71+
// should not be constructed
72+
}
73+
74+
public static final class CompiledRegex {
75+
private CompiledRegex() {
76+
// should not be constructed
77+
}
78+
79+
public static final String PATTERN = "pattern";
80+
public static final String FLAGS = "flags";
81+
public static final String EXEC = "exec";
82+
public static final String GROUP_COUNT = "groupCount";
83+
public static final String GROUPS = "groups";
84+
}
85+
86+
public static final class Flags {
87+
private Flags() {
88+
// should not be constructed
89+
}
90+
91+
public static final String SOURCE = "source";
92+
public static final String GLOBAL = "global";
93+
public static final String MULTILINE = "multiline";
94+
public static final String IGNORE_CASE = "ignoreCase";
95+
public static final String STICKY = "sticky";
96+
public static final String UNICODE = "unicode";
97+
public static final String DOT_ALL = "dotAll";
98+
public static final String HAS_INDICES = "hasIndices";
99+
public static final String UNICODE_SETS = "unicodeSets";
100+
}
101+
102+
public static final class RegexResult {
103+
private RegexResult() {
104+
// should not be constructed
105+
}
106+
107+
public static final String IS_MATCH = "isMatch";
108+
public static final String GET_START = "getStart";
109+
public static final String GET_END = "getEnd";
110+
}
111+
}
112+
113+
private static final String NUMBER_OF_REGEX_RESULT_TYPES = "1";
114+
115+
public static final class Constants {
116+
private Constants() {
117+
// should not be constructed
118+
}
119+
120+
public static final int CAPTURE_GROUP_NO_MATCH = -1;
121+
}
122+
123+
@GenerateCached
124+
@GenerateInline(inlineByDefault = true)
125+
@GenerateUncached
126+
public abstract static class InteropReadMemberNode extends Node {
127+
128+
public abstract Object execute(Node node, Object obj, String key);
129+
130+
@Specialization(limit = NUMBER_OF_REGEX_RESULT_TYPES)
131+
static Object read(Object obj, String key,
132+
@CachedLibrary("obj") InteropLibrary objs) {
133+
try {
134+
return objs.readMember(obj, key);
135+
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
136+
throw CompilerDirectives.shouldNotReachHere(e);
137+
}
138+
}
139+
140+
@NeverDefault
141+
public static InteropReadMemberNode create() {
142+
return /*InteropReadMemberNodeGen.create()*/null;
143+
}
144+
145+
public static InteropReadMemberNode getUncached() {
146+
return /*InteropReadMemberNodeGen.getUncached()*/null;
147+
}
148+
}
149+
150+
@GenerateCached(false)
151+
@GenerateInline(inlineByDefault = true)
152+
@GenerateUncached
153+
public abstract static class InteropReadIntArrayMemberNode extends Node {
154+
155+
public abstract int[] execute(Node node, Object obj, String key);
156+
157+
@Specialization(limit = NUMBER_OF_REGEX_RESULT_TYPES)
158+
static int[] read(Node node, Object obj, String key,
159+
@CachedLibrary("obj") InteropLibrary objs,
160+
@CachedLibrary(limit = "1") InteropLibrary arrays) {
161+
try {
162+
Object interopArray = objs.readMember(obj, key);
163+
int length = (int) arrays.getArraySize(interopArray);
164+
int[] array = new int[length];
165+
for (int i = 0; i < length; i++) {
166+
array[i] = (int) arrays.readArrayElement(interopArray, i);
167+
}
168+
return array;
169+
} catch (UnsupportedMessageException | UnknownIdentifierException | InvalidArrayIndexException e) {
170+
throw CompilerDirectives.shouldNotReachHere(e);
171+
}
172+
}
173+
174+
public static InteropReadIntArrayMemberNode getUncached() {
175+
return /*InteropReadIntArrayMemberNodeGen.getUncached()*/null;
176+
}
177+
}
178+
179+
@GenerateCached(false)
180+
@GenerateInline
181+
@GenerateUncached
182+
public abstract static class InvokeExecMethodNode extends Node {
183+
184+
public abstract Object execute(Node inliningTarget, Object compiledRegex, TruffleString input, int fromIndex);
185+
186+
@Specialization(limit = "3")
187+
static Object exec(Object compiledRegex, TruffleString input, int fromIndex,
188+
@CachedLibrary("compiledRegex") InteropLibrary objs) {
189+
try {
190+
return objs.invokeMember(compiledRegex, Props.CompiledRegex.EXEC, input, fromIndex);
191+
} catch (UnsupportedMessageException | UnsupportedTypeException | ArityException | UnknownIdentifierException e) {
192+
throw CompilerDirectives.shouldNotReachHere(e);
193+
}
194+
}
195+
}
196+
197+
@GenerateCached(false)
198+
@GenerateInline
199+
@GenerateUncached
200+
public abstract static class ReadIsMatchNode extends Node {
201+
static final String IS_MATCH = "isMatch";
202+
203+
public abstract boolean execute(Node inliningTarget, Object regexResult);
204+
205+
@Specialization(limit = "3")
206+
static boolean read(Object regexResult, @CachedLibrary("regexResult") InteropLibrary objs) {
207+
try {
208+
return (boolean) objs.readMember(regexResult, IS_MATCH);
209+
} catch (UnsupportedMessageException | UnknownIdentifierException e) {
210+
throw CompilerDirectives.shouldNotReachHere(e);
211+
}
212+
}
213+
}
214+
215+
@GenerateCached(false)
216+
@GenerateInline
217+
@GenerateUncached
218+
public abstract static class InvokeGetGroupBoundariesMethodNode extends Node {
219+
220+
public abstract int execute(Node inliningTarget, Object regexResult, Object method, int groupNumber);
221+
222+
@Specialization(limit = "3")
223+
static int exec(Object regexResult, String method, int groupNumber,
224+
@CachedLibrary("regexResult") InteropLibrary objs) {
225+
try {
226+
return (int) objs.invokeMember(regexResult, method, groupNumber);
227+
} catch (UnsupportedMessageException | UnsupportedTypeException | ArityException | UnknownIdentifierException e) {
228+
throw CompilerDirectives.shouldNotReachHere(e);
229+
}
230+
}
231+
}
232+
233+
public static final class TRegexCompiledRegexAccessor {
234+
235+
private TRegexCompiledRegexAccessor() {
236+
}
237+
238+
public static String pattern(Object compiledRegexObject, Node node, InteropReadMemberNode readPattern) {
239+
return (String) readPattern.execute(node, compiledRegexObject, Props.CompiledRegex.PATTERN);
240+
}
241+
242+
public static Object flags(Object compiledRegexObject, Node node, InteropReadMemberNode readFlags) {
243+
return readFlags.execute(node, compiledRegexObject, Props.CompiledRegex.FLAGS);
244+
}
245+
246+
public static int groupCount(Object compiledRegexObject, Node node, InteropReadMemberNode readGroupCount) {
247+
return (int) readGroupCount.execute(node, compiledRegexObject, Props.CompiledRegex.GROUP_COUNT);
248+
}
249+
250+
public static Object namedCaptureGroups(Object compiledRegexObject, Node node, InteropReadMemberNode readGroups) {
251+
return readGroups.execute(node, compiledRegexObject, Props.CompiledRegex.GROUPS);
252+
}
253+
}
254+
255+
public static final class TRegexNamedCaptureGroupsAccessor {
256+
257+
private TRegexNamedCaptureGroupsAccessor() {
258+
}
259+
260+
public static boolean hasGroup(Object namedCaptureGroupsMap, TruffleString name, InteropLibrary interop) {
261+
return interop.isMemberReadable(namedCaptureGroupsMap, name.toJavaStringUncached());
262+
}
263+
264+
public static int[] getGroupNumbers(Object namedCaptureGroupsMap, TruffleString name, InteropLibrary libMap, InteropLibrary libArray) {
265+
try {
266+
Object interopArray = libMap.readMember(namedCaptureGroupsMap, name.toJavaStringUncached());
267+
int length = (int) libArray.getArraySize(interopArray);
268+
int[] array = new int[length];
269+
for (int i = 0; i < length; i++) {
270+
array[i] = (int) libArray.readArrayElement(interopArray, i);
271+
}
272+
return array;
273+
} catch (UnsupportedMessageException | UnknownIdentifierException | InvalidArrayIndexException e) {
274+
throw CompilerDirectives.shouldNotReachHere(e);
275+
}
276+
}
277+
}
278+
279+
public static final class TRegexFlagsAccessor {
280+
281+
private TRegexFlagsAccessor() {
282+
}
283+
284+
public static String source(Object regexFlagsObject, Node node, InteropReadMemberNode readSourceNode) {
285+
return (String) readSourceNode.execute(node, regexFlagsObject, Props.Flags.SOURCE);
286+
}
287+
288+
public static boolean global(Object regexFlagsObject, Node node, InteropReadMemberNode readGlobalNode) {
289+
return (boolean) readGlobalNode.execute(node, regexFlagsObject, Props.Flags.GLOBAL);
290+
}
291+
292+
public static boolean multiline(Object regexFlagsObject, Node node, InteropReadMemberNode readMultilineNode) {
293+
return (boolean) readMultilineNode.execute(node, regexFlagsObject, Props.Flags.MULTILINE);
294+
}
295+
296+
public static boolean ignoreCase(Object regexFlagsObject, Node node, InteropReadMemberNode readIgnoreCaseNode) {
297+
return (boolean) readIgnoreCaseNode.execute(node, regexFlagsObject, Props.Flags.IGNORE_CASE);
298+
}
299+
300+
public static boolean sticky(Object regexFlagsObject, Node node, InteropReadMemberNode readStickyNode) {
301+
return (boolean) readStickyNode.execute(node, regexFlagsObject, Props.Flags.STICKY);
302+
}
303+
304+
public static boolean unicode(Object regexFlagsObject, Node node, InteropReadMemberNode readUnicodeNode) {
305+
return (boolean) readUnicodeNode.execute(node, regexFlagsObject, Props.Flags.UNICODE);
306+
}
307+
308+
public static boolean dotAll(Object regexFlagsObject, Node node, InteropReadMemberNode readDotAllNode) {
309+
return (boolean) readDotAllNode.execute(node, regexFlagsObject, Props.Flags.DOT_ALL);
310+
}
311+
312+
public static boolean hasIndices(Object regexFlagsObject, Node node, InteropReadMemberNode readHasIndicesNode) {
313+
return (boolean) readHasIndicesNode.execute(node, regexFlagsObject, Props.Flags.HAS_INDICES);
314+
}
315+
316+
public static boolean unicodeSets(Object regexFlagsObject, Node node, InteropReadMemberNode readUnicodeSetsNode) {
317+
return (boolean) readUnicodeSetsNode.execute(node, regexFlagsObject, Props.Flags.UNICODE_SETS);
318+
}
319+
}
320+
321+
@GenerateInline
322+
@GenerateCached(false)
323+
public abstract static class TRegexCompiledRegexSingleFlagAccessorNode extends Node {
324+
325+
public abstract boolean execute(Node node, Object compiledRegex, String flag);
326+
327+
@Specialization
328+
static boolean get(Node node, Object compiledRegex, String flag,
329+
@Cached InteropReadMemberNode readFlagsObjectNode,
330+
@Cached InteropReadMemberNode readFlagNode) {
331+
CompilerAsserts.partialEvaluationConstant(flag);
332+
return (boolean) readFlagNode.execute(node, readFlagsObjectNode.execute(node, compiledRegex, Props.CompiledRegex.FLAGS), flag);
333+
}
334+
}
335+
336+
public static final class TRegexResultAccessor {
337+
338+
private TRegexResultAccessor() {
339+
}
340+
341+
public static boolean isMatch(Object result, Node node, InteropReadMemberNode readIsMatch) {
342+
return (boolean) readIsMatch.execute(node, result, Props.RegexResult.IS_MATCH);
343+
}
344+
345+
public static int groupCount(Object compiledRegex, Node node, InteropReadMemberNode readGroupCount) {
346+
return (int) readGroupCount.execute(node, compiledRegex, Props.CompiledRegex.GROUP_COUNT);
347+
}
348+
349+
public static int captureGroupStart(Object result, int groupNumber, Node node, InvokeGetGroupBoundariesMethodNode getStart) {
350+
return getStart.execute(node, result, Props.RegexResult.GET_START, groupNumber);
351+
}
352+
353+
public static int captureGroupEnd(Object result, int groupNumber, Node node, InvokeGetGroupBoundariesMethodNode getEnd) {
354+
return getEnd.execute(node, result, Props.RegexResult.GET_END, groupNumber);
355+
}
356+
357+
public static int captureGroupLength(Object regexResultObject, int groupNumber, Node node,
358+
InvokeGetGroupBoundariesMethodNode getStart,
359+
InvokeGetGroupBoundariesMethodNode getEnd) {
360+
return captureGroupEnd(regexResultObject, groupNumber, node, getStart) - captureGroupStart(regexResultObject, groupNumber, node, getEnd);
361+
}
362+
363+
}
364+
}

0 commit comments

Comments
 (0)