Skip to content

Commit e976585

Browse files
committed
Fix to fine-tune URI link for Python QSTRING,LQSTRING
1 parent f152ade commit e976585

File tree

6 files changed

+156
-12
lines changed

6 files changed

+156
-12
lines changed

src/org/opensolaris/opengrok/analysis/python/PythonSymbolTokenizer.lex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@
2727
*/
2828

2929
package org.opensolaris.opengrok.analysis.python;
30-
import java.io.IOException;
31-
import java.io.Reader;
32-
import org.opensolaris.opengrok.analysis.JFlexTokenizer;
3330

31+
import org.opensolaris.opengrok.analysis.JFlexTokenizer;
3432
%%
3533
%public
3634
%class PythonSymbolTokenizer
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2017, Chris Fraire <[email protected]>.
22+
*/
23+
24+
package org.opensolaris.opengrok.analysis.python;
25+
26+
import java.util.regex.Pattern;
27+
import org.opensolaris.opengrok.util.RegexUtils;
28+
29+
/**
30+
* Represents a container for Python-related utility methods
31+
*/
32+
public class PythonUtils {
33+
34+
/**
35+
* Matches an apostrophe followed by two more apostrophes as a Python
36+
* long-string delimiter and not following a backslash escape or following
37+
* an even number¹ of backslash escapes:
38+
* <pre>
39+
* {@code
40+
* \'(?=\'\') #...
41+
* }
42+
* </pre>
43+
* (Edit above and paste below [in NetBeans] for easy String escaping.)
44+
* <p>
45+
* ¹See {@link RegexUtils#getNotFollowingEscapePattern()} for a caveat
46+
* about the backslash assertion.
47+
*/
48+
public static final Pattern LONGSTRING_APOS =
49+
Pattern.compile("\\'(?=\\'\\')" +
50+
RegexUtils.getNotFollowingEscapePattern());
51+
52+
/** Private to enforce singleton. */
53+
private PythonUtils() {
54+
}
55+
}

src/org/opensolaris/opengrok/analysis/python/PythonXref.lex

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@
2727
*/
2828

2929
package org.opensolaris.opengrok.analysis.python;
30+
3031
import org.opensolaris.opengrok.analysis.JFlexXrefSimple;
31-
import java.io.IOException;
32-
import java.io.Writer;
33-
import java.io.Reader;
32+
import org.opensolaris.opengrok.util.StringUtils;
3433
import org.opensolaris.opengrok.web.HtmlConsts;
3534
import org.opensolaris.opengrok.web.Util;
36-
3735
%%
3836
%public
3937
%class PythonXref
@@ -182,12 +180,26 @@ File = [a-zA-Z]{FNameChar}* "." ([Pp][Yy] | [Pp][Mm] | [Cc][Oo][Nn][Ff] |
182180
out.write(path);
183181
out.write("</a>");}
184182

185-
{BrowseableURI} {
186-
appendLink(yytext(), true);
187-
}
188-
189183
{FNameChar}+ "@" {FNameChar}+ "." {FNameChar}+
190184
{
191185
writeEMailAddress(yytext());
192186
}
193187
}
188+
189+
<SCOMMENT, STRING, LSTRING> {
190+
{BrowseableURI} {
191+
appendLink(yytext(), true);
192+
}
193+
}
194+
195+
<QSTRING> {
196+
{BrowseableURI} {
197+
appendLink(yytext(), true, StringUtils.APOS_NO_BSESC);
198+
}
199+
}
200+
201+
<LQSTRING> {
202+
{BrowseableURI} {
203+
appendLink(yytext(), true, PythonUtils.LONGSTRING_APOS);
204+
}
205+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* See LICENSE.txt included in this distribution for the specific
9+
* language governing permissions and limitations under the License.
10+
*
11+
* When distributing Covered Code, include this CDDL HEADER in each
12+
* file and include the License file at LICENSE.txt.
13+
* If applicable, add the following below this CDDL HEADER, with the
14+
* fields enclosed by brackets "[]" replaced with your own identifying
15+
* information: Portions Copyright [yyyy] [name of copyright owner]
16+
*
17+
* CDDL HEADER END
18+
*/
19+
20+
/*
21+
* Copyright (c) 2017, Chris Fraire <[email protected]>.
22+
*/
23+
24+
package org.opensolaris.opengrok.analysis.python;
25+
26+
import static org.junit.Assert.assertEquals;
27+
import org.junit.Test;
28+
import org.opensolaris.opengrok.util.StringUtils;
29+
30+
/**
31+
* Represents a test class for {@link PythonUtils}.
32+
*/
33+
public class PythonUtilsTest {
34+
35+
@Test
36+
public void shouldMatchLongstringApostrophe() {
37+
final String value = "1-2-3'''";
38+
int i = StringUtils.patindexOf(value, PythonUtils.LONGSTRING_APOS);
39+
assertEquals("long-string apostrophe", 5, i);
40+
}
41+
42+
@Test
43+
public void shouldMatchInitialLongstringApostrophe() {
44+
final String value = "'''";
45+
int i = StringUtils.patindexOf(value, PythonUtils.LONGSTRING_APOS);
46+
assertEquals("initial long-string apostrophe", 0, i);
47+
}
48+
49+
@Test
50+
public void shouldMatchLongstringApostropheAfterEscapedApostrophe() {
51+
// Copy-and-paste the following so Netbeans does the escaping:
52+
// value: \'1-2-3\''''
53+
final String value = "\\'1-2-3\\''''";
54+
int i = StringUtils.patindexOf(value, PythonUtils.LONGSTRING_APOS);
55+
assertEquals("long-string apostrophe after quoted apostrophe", 9, i);
56+
}
57+
58+
@Test
59+
public void shouldMatchLongstringApostropheAfterEvenEscapes() {
60+
// Copy-and-paste the following so Netbeans does the escaping:
61+
// value: \\'''
62+
final String value = "\\\\'''";
63+
int i = StringUtils.patindexOf(value, PythonUtils.LONGSTRING_APOS);
64+
assertEquals("long-string apostrophe after backslashes", 2, i);
65+
}
66+
67+
@Test
68+
public void shouldNotMatchLongstringApostropheAfterOddEscapes() {
69+
// Copy-and-paste the following so Netbeans does the escaping:
70+
// value: \\\'''
71+
final String value = "\\\\\\'''";
72+
int i = StringUtils.patindexOf(value, PythonUtils.LONGSTRING_APOS);
73+
assertEquals("three apostrophes after backslashes", -1, i);
74+
}
75+
}

test/org/opensolaris/opengrok/analysis/python/sample.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,5 @@ def pickleload(path):
148148
f=open(save_path[:-4] + '.txt', 'w')
149149
f.writelines(text)
150150
f.close()
151+
print('http://example.com?a=')
152+
print('''http://example.com?a='b'&''')

test/org/opensolaris/opengrok/analysis/python/sample_xref.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,5 +156,7 @@
156156
<a class="l" name="148" href="#148">148</a> f=<a href="/source/s?defs=open" class="intelliWindow-symbol" data-definition-place="undefined-in-file">open</a>(<a class="d intelliWindow-symbol" href="#save_path" data-definition-place="defined-in-file">save_path</a>[:-<span class="n">4</span>] + <span class="s">&apos;.txt&apos;</span>, <span class="s">&apos;w&apos;</span>)
157157
<a class="l" name="149" href="#149">149</a> f.<a href="/source/s?defs=writelines" class="intelliWindow-symbol" data-definition-place="undefined-in-file">writelines</a>(<a class="d intelliWindow-symbol" href="#text" data-definition-place="defined-in-file">text</a>)
158158
<a class="hl" name="150" href="#150">150</a> f.<a href="/source/s?defs=close" class="intelliWindow-symbol" data-definition-place="undefined-in-file">close</a>()
159-
<a class="l" name="151" href="#151">151</a></body>
159+
<a class="l" name="151" href="#151">151</a><b>print</b>(<span class="s">&apos;<a href="http://example.com?a=">http://example.com?a=</a>&apos;</span>)
160+
<a class="l" name="152" href="#152">152</a><b>print</b>(<span class="s">&apos;&apos;&apos;<a href="http://example.com?a='b'&amp;">http://example.com?a='b'&amp;</a>&apos;&apos;&apos;</span>)
161+
<a class="l" name="153" href="#153">153</a></body>
160162
</html>

0 commit comments

Comments
 (0)