package org.simantics.scl.compiler.source; import java.io.IOException; import java.io.Reader; import java.util.Arrays; import org.simantics.scl.compiler.compilation.SCLCompiler; import org.simantics.scl.compiler.environment.EnvironmentFactoryImpl; import org.simantics.scl.compiler.errors.CompilationErrorFormatter; import org.simantics.scl.compiler.errors.Failable; import org.simantics.scl.compiler.errors.Failure; import org.simantics.scl.compiler.errors.Success; import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator; import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory; import org.simantics.scl.compiler.internal.codegen.types.RuntimeJavaReferenceValidator; import org.simantics.scl.compiler.module.ImportDeclaration; import org.simantics.scl.compiler.module.Module; import org.simantics.scl.compiler.module.options.ModuleCompilationOptions; import org.simantics.scl.compiler.module.repository.ModuleRepository; import org.simantics.scl.compiler.module.repository.UpdateListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class TextualModuleSource implements ModuleSource { private static final Logger LOGGER = LoggerFactory.getLogger(TextualModuleSource.class); public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] { new ImportDeclaration("Builtin", ""), new ImportDeclaration("Prelude", "") }; private final String moduleName; private final double priority; public TextualModuleSource(String moduleName, double priority) { this.moduleName = moduleName; this.priority = priority; } public TextualModuleSource(String moduleName) { this(moduleName, 0.0); } @Override public ClassLoader getClassLoader() { return getClass().getClassLoader(); } protected abstract Reader getSourceReader(UpdateListener listener) throws IOException; protected JavaReferenceValidator getJavaReferenceValidator() { return new RuntimeJavaReferenceValidator(getClassLoader()); } public String getSourceText(UpdateListener listener) throws IOException { Reader reader = getSourceReader(listener); char[] buffer = new char[65536]; int pos = 0; try { while(true) { int count = reader.read(buffer, pos, buffer.length-pos); if(count == -1) return new String(buffer, 0, pos); pos += count; if(pos == buffer.length) buffer = Arrays.copyOf(buffer, 2*buffer.length); } } finally { reader.close(); } } protected ImportDeclaration[] getBuiltinImports(UpdateListener listener) { return DEFAULT_IMPORTS; } @Override public String getModuleName() { return moduleName; } @SuppressWarnings("unchecked") @Override public Failable compileModule(final ModuleRepository environment, final UpdateListener listener, ModuleCompilationOptions options) { SCLCompiler compiler = new SCLCompiler(options, getJavaReferenceValidatorFactory()); try { compiler.addSource(getSourceReader(listener)); compiler.compile( new EnvironmentFactoryImpl( environment, getBuiltinImports(listener), listener), moduleName); if(compiler.getErrorLog().hasNoErrors()) return new Success(compiler.getModule()); else { LOGGER.error("While compiling " + getModuleName() + ":"); LOGGER.error(CompilationErrorFormatter.toString(getSourceReader(null), compiler.getErrorLog().getErrors())); return new Failure(compiler.getErrorLog().getErrors()); } } catch (IOException e) { return new Failure(e); } } public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() { return new JavaReferenceValidatorFactory() { @Override public JavaReferenceValidator getJavaReferenceValidator(String context) { return (JavaReferenceValidator)TextualModuleSource.this.getJavaReferenceValidator(); } @Override public JavaReferenceValidator getDefaultJavaReferenceValidator() { return (JavaReferenceValidator)TextualModuleSource.this.getJavaReferenceValidator(); } }; } @Override public double getPriority() { return priority; } @Override public String toString() { return getClass().getSimpleName() + "(" + moduleName + ")"; } public boolean isUpdateable() { return false; } public void update(String newSourceText) { throw new UnsupportedOperationException(); } }