Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/org/rascalmpl/interpreter/env/GlobalEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.rascalmpl.ast.AbstractAST;
import org.rascalmpl.ast.QualifiedName;
Expand All @@ -34,6 +35,7 @@
import org.rascalmpl.values.IRascalValueFactory;

import io.usethesource.capsule.SetMultimap;
import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IList;
import io.usethesource.vallang.IString;

Expand Down Expand Up @@ -329,4 +331,11 @@ public void clearLookupChaches() {
public void clearModuleLoadMessage() {
moduleEnvironment.values().forEach(ModuleEnvironment::clearLoadMessages);
}

public Stream<IConstructor> streamModuleLoadMessages() {
return moduleEnvironment
.values()
.stream()
.flatMap(me -> me.streamLoadMessages());
}
}
5 changes: 5 additions & 0 deletions src/org/rascalmpl/interpreter/env/ModuleEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.rascalmpl.ast.AbstractAST;
import org.rascalmpl.ast.KeywordFormal;
Expand Down Expand Up @@ -143,6 +144,10 @@ public void clearLookupCaches() {
public void clearLoadMessages() {
this.loadMessages.clear();
}

public Stream<IConstructor> streamLoadMessages() {
return loadMessages.stream();
}

public void extend(ModuleEnvironment other) {
extendNameFlags(other);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
module lang::rascal::tests::loading::LoadingErrorModules

import IO;
import util::Eval;
import util::PathConfig;
import Message;

PathConfig init() = pathConfig(srcs=[|memory://LoadingErrorModules/|]);

loc moduleFile(str name) = |memory://LoadingErrorModules/| + "<name>.rsc";

test bool moduleWithParseError() {
exec = createRascalRuntime(pcfg=init());

writeFile(moduleFile("A"), "modle A");

try {
exec.eval(#void, "import A;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("A"), "module A");

return exec.eval(#void, "import A;") == ok();
}

test bool moduleWithTransientParseError() {
exec = createRascalRuntime(pcfg=init());

writeFile(moduleFile("A"), "module A");
assert exec.eval(#void, "import A;") == ok();
writeFile(moduleFile("A"), "modle A");

try {
exec.eval(#void, "import A;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("A"), "module A");

return exec.eval(#void, "import A;") == ok();
}

test bool moduleWithTransitiveParseError() {
exec = createRascalRuntime(pcfg=init());

writeFile(moduleFile("A"), "modle A");
writeFile(moduleFile("B"), "module B import A;");

try {
exec.eval(#void, "import B;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("A"), "module A");

return exec.eval(#void, "import A;") == ok()
&& exec.eval(#void, "import B;") == ok();
}

test bool moduleWithStaticError() {
exec = createRascalRuntime(pcfg=init());

writeFile(moduleFile("A"), "module A str aap = 42;");

try {
exec.eval(#void, "import A;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("A"), "module A str aap = \"42\";");

return exec.eval(#void, "import A;") == ok();
}

test bool importNonExistingModule() {
exec = createRascalRuntime(pcfg=init());

try {
exec.eval(#void, "import Z;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("Z"), "module Z public str aap = \"aap\";");

return exec.eval(#void, "import Z;") == ok()
&& result("aap") == exec.eval(#str, "aap");
}


test bool importBrokenModuleName() {
exec = createRascalRuntime(pcfg=init());

writeFile(moduleFile("AAA"), "module AA public str aap = \"aap\";");

try {
exec.eval(#void, "import AAA;");
return false;
}
catch ModuleLoadMessages([error(_,_)]): {
// that's ok
;
}

writeFile(moduleFile("AAA"), "module AAA public str aap = \"aap\";");

return exec.eval(#void, "import AAA;") == ok()
&& result("aap") == exec.eval(#str, "aap");
}

15 changes: 13 additions & 2 deletions src/org/rascalmpl/library/util/Eval.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.rascalmpl.debug.IRascalMonitor;
import org.rascalmpl.exceptions.RuntimeExceptionFactory;
import org.rascalmpl.exceptions.Throw;
Expand All @@ -31,6 +30,7 @@
import org.rascalmpl.interpreter.result.Result;
import org.rascalmpl.interpreter.staticErrors.StaticError;
import org.rascalmpl.interpreter.staticErrors.UnexpectedType;
import org.rascalmpl.library.Messages;
import org.rascalmpl.shell.ShellEvaluatorFactory;
import org.rascalmpl.types.RascalTypeFactory;
import org.rascalmpl.types.TypeReifier;
Expand All @@ -40,6 +40,7 @@

import io.usethesource.vallang.IConstructor;
import io.usethesource.vallang.IInteger;
import io.usethesource.vallang.IList;
import io.usethesource.vallang.IString;
import io.usethesource.vallang.IValue;
import io.usethesource.vallang.type.Type;
Expand All @@ -58,7 +59,8 @@ public class Eval {
public final Type Result_void = tf.constructor(store, Result, "ok");
public final Type Result_value = tf.constructor(store, Result, "result", param, "val");
public final Type Exception = tf.abstractDataType(store, "Exception");
public final Type Exception_StaticError = tf.constructor(store, Exception, "StaticError", tf.stringType(), "messages", tf.sourceLocationType(), "location");
public final Type Exception_StaticError = tf.constructor(store, Exception, "StaticError", tf.stringType(), "message", tf.sourceLocationType(), "location");
public final Type Exception_LoadMessages = tf.constructor(store, Exception, "ModuleLoadMessages", tf.listType(Messages.Message), "messages");
private final Type resetType = tf.functionType(tf.voidType(), tf.tupleEmpty(), tf.tupleEmpty());
private final Type setTimeoutType = tf.functionType(tf.voidType(), tf.tupleType(tf.integerType()), tf.tupleEmpty());
private final Type evalType = tf.functionType(Result_value, tf.tupleType(TypeTyp, tf.stringType()), tf.tupleEmpty());
Expand Down Expand Up @@ -175,6 +177,11 @@ private IFunction buildEvalFunction(RascalRuntime exec) {
throw new UnexpectedType(typ, result.getStaticType(), URIUtil.rootLocation("eval"));
}

IList loadMessages = exec.moduleLoadMessages();
if (loadMessages.stream().anyMatch(c -> ((IConstructor) c).getName().equals("error"))) {
throw new Throw(values.constructor(Exception_LoadMessages, loadMessages), null, null);
}

if (result.getStaticType().isBottom()) {
return values.constructor(Result_void);
}
Expand Down Expand Up @@ -231,6 +238,10 @@ public void reset() {
eval.getHeap().clear();
}

public IList moduleLoadMessages() {
return eval.__getHeap().streamModuleLoadMessages().collect(eval.getValueFactory().listWriter());
}

public Result<IValue> eval(IRascalMonitor monitor, String line) throws InterruptedException, IOException {
return eval.eval(monitor, line, IRascalValueFactory.getInstance().sourceLocation(URIUtil.assumeCorrect("eval", "", "", "command=" + line)));
}
Expand Down
5 changes: 4 additions & 1 deletion src/org/rascalmpl/library/util/Eval.rsc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ module util::Eval

extend Exception;
extend util::Reflective;

import IO;
import Message;

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

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

@synopsis{Evaluate a list of command and return the value of the last command.}
Expand Down
16 changes: 11 additions & 5 deletions src/org/rascalmpl/semantics/dynamic/Import.java
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,17 @@ public static ModuleEnvironment loadModule(ISourceLocation x, String name, IEval

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

if (uri == null) {
heap.setModuleURI(jobName, URIUtil.correctLocation("not-found", name, "").getURI());
throw new ModuleImport(name, "can not find in search path", x);
}
else {
heap.setModuleURI(name, uri.getURI());
}

try {
eval.jobTodo(jobName, 1);
if (uri == null) {
throw new ModuleImport(name, "can not find in search path", x);
}

Module module = buildModule(uri, env, eval, jobName);

if (isDeprecated(module)) {
Expand All @@ -360,7 +366,7 @@ public static ModuleEnvironment loadModule(ISourceLocation x, String name, IEval
if (!internalName.equals(name)) {
throw new ModuleNameMismatch(internalName, name, x);
}
heap.setModuleURI(name, module.getLocation().getURI());


module.interpret(eval);
}
Expand Down Expand Up @@ -434,7 +440,7 @@ private static ASTBuilder getBuilder() {
}

private static void addImportToCurrentModule(ISourceLocation src, String name, IEvaluator<Result<IValue>> eval) {
ModuleEnvironment module = eval.getHeap().getModule(name);
ModuleEnvironment module = eval.getHeap().getModule(name);
if (module == null) {
throw new UndeclaredModule(name, src);
}
Expand Down
Loading