Skip to content

Commit 53d2faa

Browse files
authored
Merge pull request #2749 from usethesource/fix/issue-2747
fixed #2747 and a number of other error scenarios like wrong module names
2 parents 1a68d99 + af23414 commit 53d2faa

6 files changed

Lines changed: 172 additions & 8 deletions

File tree

src/org/rascalmpl/interpreter/env/GlobalEnvironment.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Set;
2525
import java.util.stream.Collectors;
26+
import java.util.stream.Stream;
2627

2728
import org.rascalmpl.ast.AbstractAST;
2829
import org.rascalmpl.ast.QualifiedName;
@@ -34,6 +35,7 @@
3435
import org.rascalmpl.values.IRascalValueFactory;
3536

3637
import io.usethesource.capsule.SetMultimap;
38+
import io.usethesource.vallang.IConstructor;
3739
import io.usethesource.vallang.IList;
3840
import io.usethesource.vallang.IString;
3941

@@ -329,4 +331,11 @@ public void clearLookupChaches() {
329331
public void clearModuleLoadMessage() {
330332
moduleEnvironment.values().forEach(ModuleEnvironment::clearLoadMessages);
331333
}
334+
335+
public Stream<IConstructor> streamModuleLoadMessages() {
336+
return moduleEnvironment
337+
.values()
338+
.stream()
339+
.flatMap(me -> me.streamLoadMessages());
340+
}
332341
}

src/org/rascalmpl/interpreter/env/ModuleEnvironment.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Optional;
3333
import java.util.Set;
3434
import java.util.function.Predicate;
35+
import java.util.stream.Stream;
3536

3637
import org.rascalmpl.ast.AbstractAST;
3738
import org.rascalmpl.ast.KeywordFormal;
@@ -143,6 +144,10 @@ public void clearLookupCaches() {
143144
public void clearLoadMessages() {
144145
this.loadMessages.clear();
145146
}
147+
148+
public Stream<IConstructor> streamLoadMessages() {
149+
return loadMessages.stream();
150+
}
146151

147152
public void extend(ModuleEnvironment other) {
148153
extendNameFlags(other);
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
module lang::rascal::tests::loading::LoadingErrorModules
2+
3+
import IO;
4+
import util::Eval;
5+
import util::PathConfig;
6+
import Message;
7+
8+
PathConfig init() = pathConfig(srcs=[|memory://LoadingErrorModules/|]);
9+
10+
loc moduleFile(str name) = |memory://LoadingErrorModules/| + "<name>.rsc";
11+
12+
test bool moduleWithParseError() {
13+
exec = createRascalRuntime(pcfg=init());
14+
15+
writeFile(moduleFile("A"), "modle A");
16+
17+
try {
18+
exec.eval(#void, "import A;");
19+
return false;
20+
}
21+
catch ModuleLoadMessages([error(_,_)]): {
22+
// that's ok
23+
;
24+
}
25+
26+
writeFile(moduleFile("A"), "module A");
27+
28+
return exec.eval(#void, "import A;") == ok();
29+
}
30+
31+
test bool moduleWithTransientParseError() {
32+
exec = createRascalRuntime(pcfg=init());
33+
34+
writeFile(moduleFile("A"), "module A");
35+
assert exec.eval(#void, "import A;") == ok();
36+
writeFile(moduleFile("A"), "modle A");
37+
38+
try {
39+
exec.eval(#void, "import A;");
40+
return false;
41+
}
42+
catch ModuleLoadMessages([error(_,_)]): {
43+
// that's ok
44+
;
45+
}
46+
47+
writeFile(moduleFile("A"), "module A");
48+
49+
return exec.eval(#void, "import A;") == ok();
50+
}
51+
52+
test bool moduleWithTransitiveParseError() {
53+
exec = createRascalRuntime(pcfg=init());
54+
55+
writeFile(moduleFile("A"), "modle A");
56+
writeFile(moduleFile("B"), "module B import A;");
57+
58+
try {
59+
exec.eval(#void, "import B;");
60+
return false;
61+
}
62+
catch ModuleLoadMessages([error(_,_)]): {
63+
// that's ok
64+
;
65+
}
66+
67+
writeFile(moduleFile("A"), "module A");
68+
69+
return exec.eval(#void, "import A;") == ok()
70+
&& exec.eval(#void, "import B;") == ok();
71+
}
72+
73+
test bool moduleWithStaticError() {
74+
exec = createRascalRuntime(pcfg=init());
75+
76+
writeFile(moduleFile("A"), "module A str aap = 42;");
77+
78+
try {
79+
exec.eval(#void, "import A;");
80+
return false;
81+
}
82+
catch ModuleLoadMessages([error(_,_)]): {
83+
// that's ok
84+
;
85+
}
86+
87+
writeFile(moduleFile("A"), "module A str aap = \"42\";");
88+
89+
return exec.eval(#void, "import A;") == ok();
90+
}
91+
92+
test bool importNonExistingModule() {
93+
exec = createRascalRuntime(pcfg=init());
94+
95+
try {
96+
exec.eval(#void, "import Z;");
97+
return false;
98+
}
99+
catch ModuleLoadMessages([error(_,_)]): {
100+
// that's ok
101+
;
102+
}
103+
104+
writeFile(moduleFile("Z"), "module Z public str aap = \"aap\";");
105+
106+
return exec.eval(#void, "import Z;") == ok()
107+
&& result("aap") == exec.eval(#str, "aap");
108+
}
109+
110+
111+
test bool importBrokenModuleName() {
112+
exec = createRascalRuntime(pcfg=init());
113+
114+
writeFile(moduleFile("AAA"), "module AA public str aap = \"aap\";");
115+
116+
try {
117+
exec.eval(#void, "import AAA;");
118+
return false;
119+
}
120+
catch ModuleLoadMessages([error(_,_)]): {
121+
// that's ok
122+
;
123+
}
124+
125+
writeFile(moduleFile("AAA"), "module AAA public str aap = \"aap\";");
126+
127+
return exec.eval(#void, "import AAA;") == ok()
128+
&& result("aap") == exec.eval(#str, "aap");
129+
}
130+

src/org/rascalmpl/library/util/Eval.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.net.URISyntaxException;
2121
import java.util.HashMap;
2222
import java.util.Map;
23-
2423
import org.rascalmpl.debug.IRascalMonitor;
2524
import org.rascalmpl.exceptions.RuntimeExceptionFactory;
2625
import org.rascalmpl.exceptions.Throw;
@@ -31,6 +30,7 @@
3130
import org.rascalmpl.interpreter.result.Result;
3231
import org.rascalmpl.interpreter.staticErrors.StaticError;
3332
import org.rascalmpl.interpreter.staticErrors.UnexpectedType;
33+
import org.rascalmpl.library.Messages;
3434
import org.rascalmpl.shell.ShellEvaluatorFactory;
3535
import org.rascalmpl.types.RascalTypeFactory;
3636
import org.rascalmpl.types.TypeReifier;
@@ -40,6 +40,7 @@
4040

4141
import io.usethesource.vallang.IConstructor;
4242
import io.usethesource.vallang.IInteger;
43+
import io.usethesource.vallang.IList;
4344
import io.usethesource.vallang.IString;
4445
import io.usethesource.vallang.IValue;
4546
import io.usethesource.vallang.type.Type;
@@ -58,7 +59,8 @@ public class Eval {
5859
public final Type Result_void = tf.constructor(store, Result, "ok");
5960
public final Type Result_value = tf.constructor(store, Result, "result", param, "val");
6061
public final Type Exception = tf.abstractDataType(store, "Exception");
61-
public final Type Exception_StaticError = tf.constructor(store, Exception, "StaticError", tf.stringType(), "messages", tf.sourceLocationType(), "location");
62+
public final Type Exception_StaticError = tf.constructor(store, Exception, "StaticError", tf.stringType(), "message", tf.sourceLocationType(), "location");
63+
public final Type Exception_LoadMessages = tf.constructor(store, Exception, "ModuleLoadMessages", tf.listType(Messages.Message), "messages");
6264
private final Type resetType = tf.functionType(tf.voidType(), tf.tupleEmpty(), tf.tupleEmpty());
6365
private final Type setTimeoutType = tf.functionType(tf.voidType(), tf.tupleType(tf.integerType()), tf.tupleEmpty());
6466
private final Type evalType = tf.functionType(Result_value, tf.tupleType(TypeTyp, tf.stringType()), tf.tupleEmpty());
@@ -175,6 +177,11 @@ private IFunction buildEvalFunction(RascalRuntime exec) {
175177
throw new UnexpectedType(typ, result.getStaticType(), URIUtil.rootLocation("eval"));
176178
}
177179

180+
IList loadMessages = exec.moduleLoadMessages();
181+
if (loadMessages.stream().anyMatch(c -> ((IConstructor) c).getName().equals("error"))) {
182+
throw new Throw(values.constructor(Exception_LoadMessages, loadMessages), null, null);
183+
}
184+
178185
if (result.getStaticType().isBottom()) {
179186
return values.constructor(Result_void);
180187
}
@@ -231,6 +238,10 @@ public void reset() {
231238
eval.getHeap().clear();
232239
}
233240

241+
public IList moduleLoadMessages() {
242+
return eval.__getHeap().streamModuleLoadMessages().collect(eval.getValueFactory().listWriter());
243+
}
244+
234245
public Result<IValue> eval(IRascalMonitor monitor, String line) throws InterruptedException, IOException {
235246
return eval.eval(monitor, line, IRascalValueFactory.getInstance().sourceLocation(URIUtil.assumeCorrect("eval", "", "", "command=" + line)));
236247
}

src/org/rascalmpl/library/util/Eval.rsc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ module util::Eval
1313

1414
extend Exception;
1515
extend util::Reflective;
16+
1617
import IO;
18+
import Message;
1719

1820
@synopsis{Results encode the output of a call to `eval`}
1921
@description{
@@ -31,6 +33,7 @@ data Result[&T]
3133
}
3234
data RuntimeException
3335
= StaticError(str message, loc location)
36+
| ModuleLoadMessages(list[Message] messages)
3437
;
3538

3639
@synopsis{A reusable instance of the Rascal runtime system configured by a specific PathConfig.}
@@ -96,7 +99,7 @@ This creates a ((RascalRuntime)), uses it to evaluate one command, and then disc
9699
}
97100
@deprecated{Use ((createRascalRuntime)) for better efficiency/configurability.}
98101
Result[&T] eval(type[&T] typ, str command, int duration=-1, PathConfig pcfg=pathConfig())
99-
throws Timeout, StaticError, ParseError
102+
throws Timeout, StaticError, ParseError, ModuleLoadMessages
100103
= eval(typ, [command], pcfg=pcfg, duration=duration);
101104

102105
@synopsis{Evaluate a list of command and return the value of the last command.}

src/org/rascalmpl/semantics/dynamic/Import.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,11 +344,17 @@ public static ModuleEnvironment loadModule(ISourceLocation x, String name, IEval
344344

345345
ISourceLocation uri = eval.getRascalResolver().resolveModule(name);
346346

347+
if (uri == null) {
348+
heap.setModuleURI(jobName, URIUtil.correctLocation("not-found", name, "").getURI());
349+
throw new ModuleImport(name, "can not find in search path", x);
350+
}
351+
else {
352+
heap.setModuleURI(name, uri.getURI());
353+
}
354+
347355
try {
348356
eval.jobTodo(jobName, 1);
349-
if (uri == null) {
350-
throw new ModuleImport(name, "can not find in search path", x);
351-
}
357+
352358
Module module = buildModule(uri, env, eval, jobName);
353359

354360
if (isDeprecated(module)) {
@@ -360,7 +366,7 @@ public static ModuleEnvironment loadModule(ISourceLocation x, String name, IEval
360366
if (!internalName.equals(name)) {
361367
throw new ModuleNameMismatch(internalName, name, x);
362368
}
363-
heap.setModuleURI(name, module.getLocation().getURI());
369+
364370

365371
module.interpret(eval);
366372
}
@@ -434,7 +440,7 @@ private static ASTBuilder getBuilder() {
434440
}
435441

436442
private static void addImportToCurrentModule(ISourceLocation src, String name, IEvaluator<Result<IValue>> eval) {
437-
ModuleEnvironment module = eval.getHeap().getModule(name);
443+
ModuleEnvironment module = eval.getHeap().getModule(name);
438444
if (module == null) {
439445
throw new UndeclaredModule(name, src);
440446
}

0 commit comments

Comments
 (0)