GlobalModule.java
package org.sterling.runtime;
import static java.util.regex.Pattern.quote;
import static org.sterling.runtime.expression.ExpressionConversions.convertSymbol;
import static org.sterling.runtime.expression.ExpressionFactory.declaration;
import static org.sterling.runtime.expression.ExpressionFactory.module;
import static org.sterling.runtime.expression.ExpressionFactory.symbol;
import static org.sterling.util.StringUtil.stringify;
import java.io.IOException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import org.sterling.SterlingException;
import org.sterling.runtime.exception.LoadModuleException;
import org.sterling.runtime.exception.UndefinedMemberException;
import org.sterling.runtime.expression.DeclaredExpression;
import org.sterling.runtime.expression.Expression;
import org.sterling.runtime.expression.ModuleExpression;
import org.sterling.runtime.expression.Symbol;
import org.sterling.source.scanner.InputReader;
public class GlobalModule extends Expression {
private final Compiler compiler;
private final Map<Symbol, DeclaredExpression> members;
private final Set<Symbol> loadedMembers;
private final ClassLoader classLoader;
public GlobalModule(ClassLoader classLoader, Compiler compiler) {
this.compiler = compiler;
this.classLoader = classLoader;
this.members = new ConcurrentHashMap<>();
this.loadedMembers = new CopyOnWriteArraySet<>();
}
@Override
public Expression access(Expression member) throws SterlingException {
Symbol symbol = convertSymbol(member);
if (!isDefined(symbol)) {
try {
return super.access(member);
} catch (UndefinedMemberException exception) {
load(symbol);
}
}
return members.get(symbol).getExpression();
}
public Expression load(String name) throws SterlingException {
Expression expression = this;
for (String part : name.split(quote("/"))) {
expression = expression.access(symbol(part));
}
return expression;
}
public ModuleExpression loadModule(Symbol module) throws SterlingException {
URL url = getModuleUrl(module);
if (url == null) {
return module(module, this);
} else {
try (InputReader reader = readSource(url)) {
return module(module, this, compiler.compile(reader, this));
} catch (IOException exception) {
throw new LoadModuleException(exception);
}
}
}
@Override
public String toString() {
return stringify(this);
}
private boolean isDefined(Symbol symbol) {
return members.containsKey(symbol);
}
private void load(Symbol subModule) throws SterlingException {
if (!loadedMembers.contains(subModule)) {
loadedMembers.add(subModule);
members.put(subModule, declaration(subModule, loadModule(subModule)));
}
}
private URL getModuleUrl(Symbol module) {
String moduleName = module.getValue();
URL url = classLoader.getResource(moduleName + ".ag");
if (url == null) {
url = classLoader.getResource(moduleName + "/_base.ag");
}
return url;
}
private InputReader readSource(URL url) throws SterlingException, IOException {
return new InputReader(url.toString(), url.openStream());
}
}