Skip to content

Commit 6ffcadf

Browse files
committed
Groovy REPL does not load classes from groovy sources, fixes #664
1 parent eb1199e commit 6ffcadf

1 file changed

Lines changed: 101 additions & 22 deletions

File tree

groovy/src/main/java/org/jline/script/GroovyEngine.java

Lines changed: 101 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,12 @@
88
*/
99
package org.jline.script;
1010

11-
import java.io.File;
12-
import java.io.FileOutputStream;
13-
import java.io.OutputStream;
14-
import java.io.PrintStream;
11+
import java.io.*;
1512
import java.lang.reflect.Constructor;
1613
import java.lang.reflect.Field;
1714
import java.lang.reflect.Method;
1815
import java.lang.reflect.Modifier;
19-
import java.nio.file.Path;
16+
import java.nio.file.*;
2017
import java.util.*;
2118
import java.util.regex.Matcher;
2219
import java.util.regex.Pattern;
@@ -25,6 +22,7 @@
2522
import groovy.lang.*;
2623
import org.apache.groovy.ast.tools.ImmutablePropertyUtils;
2724
import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
25+
import org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack;
2826
import org.codehaus.groovy.syntax.SyntaxException;
2927
import org.jline.builtins.Nano.SyntaxHighlighter;
3028
import org.jline.builtins.Styles;
@@ -79,6 +77,7 @@ public enum Format {JSON, GROOVY, NONE}
7977
private static final Pattern PATTERN_CLASS_DEF = Pattern.compile("^class\\s+(" + REGEX_VAR + ") .*?\\{.*?}(|\n)$"
8078
, Pattern.DOTALL);
8179
private static final Pattern PATTERN_CLASS_NAME = Pattern.compile("(.*?)\\.([A-Z].*)");
80+
private static final Pattern PATTERN_LOAD_CLASS = Pattern.compile("(new\\s+)*\\s*(([a-z]+\\.)*)([A-Z]+[a-zA-Z]*)+(\\..*|\\(.*|)");
8281
private static final List<String> DEFAULT_IMPORTS = Arrays.asList("java.lang.*", "java.util.*", "java.io.*"
8382
, "java.net.*", "groovy.lang.*", "groovy.util.*"
8483
, "java.math.BigInteger", "java.math.BigDecimal");
@@ -267,17 +266,48 @@ public Object execute(String statement) throws Exception {
267266
out = "def " + name + methods.get(name);
268267
}
269268
} else {
270-
StringBuilder e = new StringBuilder();
269+
out = executeStatement(shell, imports, statement);
270+
}
271+
return out;
272+
}
273+
274+
private static Object executeStatement(GroovyShell shell, Map<String, String> imports, String statement) throws IOException {
275+
boolean classLoaded = false;
276+
int idx = statement.indexOf("=") + 1;
277+
Matcher matcher = PATTERN_LOAD_CLASS.matcher(statement.substring(idx));
278+
if (matcher.matches()) {
279+
String fileName = convertNull(matcher.group(2)) + matcher.group(4);
280+
fileName = fileName.replace(".", "/");
281+
for (String type : Arrays.asList(".groovy", ".java")) {
282+
File file = new File(fileName + type);
283+
if (file.exists()) {
284+
try {
285+
shell.evaluate(file);
286+
} catch (MissingMethodExceptionNoStack ignore) {
287+
288+
}
289+
classLoaded = true;
290+
statement = statement.substring(0, idx) + convertNull(matcher.group(1)) + matcher.group(4)
291+
+ convertNull(matcher.group(5));
292+
break;
293+
}
294+
}
295+
}
296+
StringBuilder e = new StringBuilder();
297+
if (!classLoaded) {
271298
for (Map.Entry<String, String> entry : imports.entrySet()) {
272299
e.append(entry.getValue()).append("\n");
273300
}
274-
e.append(statement);
275-
if (classDef(statement)) {
276-
e.append("; null");
277-
}
278-
out = shell.evaluate(e.toString());
279301
}
280-
return out;
302+
e.append(statement);
303+
if (classDef(statement)) {
304+
e.append("; null");
305+
}
306+
return shell.evaluate(e.toString());
307+
}
308+
309+
private static String convertNull(String string) {
310+
return string == null ? "" : string;
281311
}
282312

283313
@Override
@@ -323,7 +353,7 @@ private boolean functionDef(String statement) throws Exception{
323353
return out;
324354
}
325355

326-
private boolean classDef(String statement) {
356+
private static boolean classDef(String statement) {
327357
return PATTERN_CLASS_DEF.matcher(statement).matches();
328358
}
329359

@@ -552,6 +582,41 @@ private static Map<String,String> getFields(Class<?> clazz, boolean all, boolean
552582
return out;
553583
}
554584

585+
private static Set<String> fileDomain() {
586+
return nextFileDomain(null, 0);
587+
}
588+
589+
private static Set<String> nextFileDomain(String domain, int position) {
590+
String separator = FileSystems.getDefault().getSeparator();
591+
if (separator.equals("\\")) {
592+
separator += separator;
593+
}
594+
String dom;
595+
if (domain != null) {
596+
dom = domain.isEmpty() ? ".*" + separator : separator + domain.replace(".", separator);
597+
} else {
598+
dom = separator;
599+
}
600+
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("regex:\\." + dom
601+
+ "[A-Z]+[a-zA-Z]*\\.(groovy|java)");
602+
Set<String> out = new HashSet<>();
603+
try {
604+
List<Path> paths = Files.walk(Paths.get(".")).filter(matcher::matches).collect(Collectors.toList());
605+
for (Path p : paths) {
606+
if(!p.getFileName().toString().matches("[A-Z]+[a-zA-Z]*\\.(groovy|java)")){
607+
continue;
608+
}
609+
String[] s = p.toString().split(separator);
610+
if (s.length > position + 1) {
611+
out.add(s[position + 1].split(".(groovy|java)")[0]);
612+
}
613+
}
614+
} catch(Exception ignore) {
615+
616+
}
617+
return out;
618+
}
619+
555620
public static Set<String> nextDomain(String domain, CandidateType type) {
556621
return nextDomain(domain, new AccessRules(), type);
557622
}
@@ -562,8 +627,14 @@ public static Set<String> nextDomain(String domain, AccessRules access, Candidat
562627
for (String p : loadedPackages()) {
563628
out.add(p.split("\\.")[0]);
564629
}
630+
if (type != CandidateType.PACKAGE) {
631+
out.addAll(nextFileDomain("", 0));
632+
}
565633
} else if ((domain.split("\\.")).length < 2) {
566634
out = names(domain);
635+
if (type != CandidateType.PACKAGE) {
636+
out.addAll(nextFileDomain(domain, 1));
637+
}
567638
} else {
568639
try {
569640
for (Class<?> c : classesForPackage(domain)) {
@@ -592,6 +663,9 @@ && noStaticFields(c, access.allFields))) {
592663
}
593664
}
594665
}
666+
if (out.isEmpty() && type != CandidateType.PACKAGE) {
667+
out.addAll(nextFileDomain(domain, domain.split("\\.").length));
668+
}
595669
} catch (ClassNotFoundException e) {
596670
if (Log.isDebugEnabled()) {
597671
e.printStackTrace();
@@ -853,6 +927,9 @@ public void complete(LineReader reader, ParsedLine commandLine, List<Candidate>
853927
try {
854928
param = wordbuffer.substring(eqsep + 1, varsep);
855929
Class<?> clazz = classResolver(param);
930+
if (clazz == null) {
931+
clazz = (Class<?>)inspector.execute(param + ".class");
932+
}
856933
if (clazz != null) {
857934
doStaticMethodCandidates(candidates, clazz, curBuf);
858935
}
@@ -991,6 +1068,7 @@ private Set<String> retrieveConstructors(boolean all) {
9911068
it.remove();
9921069
}
9931070
}
1071+
out.addAll(Helpers.fileDomain());
9941072
return out;
9951073
}
9961074

@@ -1008,6 +1086,7 @@ private Set<String> retrieveClassesWithStaticMethods() {
10081086
it.remove();
10091087
}
10101088
}
1089+
out.addAll(Helpers.fileDomain());
10111090
return out;
10121091
}
10131092
}
@@ -1091,7 +1170,11 @@ public Class<?> evaluateClass(String objectStatement) {
10911170
if (!objectStatement.contains(".") ) {
10921171
out = (Class<?>)execute(objectStatement + ".class");
10931172
} else {
1094-
out = Class.forName(objectStatement);
1173+
try {
1174+
out = Class.forName(objectStatement);
1175+
} catch (ClassNotFoundException e) {
1176+
out = (Class<?>)execute(objectStatement + ".class");
1177+
}
10951178
}
10961179
}
10971180
} catch (Exception e) {
@@ -1107,14 +1190,10 @@ public Object execute(String statement) {
11071190
System.setOut(nullstream);
11081191
System.setErr(nullstream);
11091192
}
1110-
Object out;
1193+
Object out = null;
11111194
try {
1112-
StringBuilder e = new StringBuilder();
1113-
for (Map.Entry<String, String> entry : imports.entrySet()) {
1114-
e.append(entry.getValue()).append("\n");
1115-
}
1116-
e.append(statement);
1117-
out = shell.evaluate(e.toString());
1195+
out = executeStatement(shell, imports, statement);
1196+
} catch (IOException ignore) {
11181197
} finally {
11191198
System.setOut(origOut);
11201199
System.setErr(origErr);
@@ -1481,7 +1560,7 @@ private CmdDesc checkSyntax(CmdLine line) {
14811560
} else {
14821561
try {
14831562
execute(objEquation);
1484-
} catch (groovy.lang.MissingPropertyException e) {
1563+
} catch (MissingPropertyException e) {
14851564
mainDesc.addAll(doExceptionMessage(e));
14861565
out.setErrorPattern(Pattern.compile("\\b" + e.getProperty() + "\\b"));
14871566
} catch (java.util.regex.PatternSyntaxException e) {

0 commit comments

Comments
 (0)