package org.simantics.scl.compiler.compilation; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.Map; import org.simantics.scl.compiler.environment.EnvironmentFactory; import org.simantics.scl.compiler.errors.ErrorLog; import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator; import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory; import org.simantics.scl.compiler.internal.header.ModuleHeader; import org.simantics.scl.compiler.internal.parsing.declarations.DeclarationAst; import org.simantics.scl.compiler.internal.parsing.exceptions.SCLSyntaxErrorException; import org.simantics.scl.compiler.internal.parsing.parser.SCLParserImpl; import org.simantics.scl.compiler.internal.parsing.parser.SCLParserOptions; import org.simantics.scl.compiler.module.ConcreteModule; import org.simantics.scl.compiler.module.options.ModuleCompilationOptions; import org.simantics.scl.compiler.top.ModuleInitializer; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.top.StandardModuleInitializer; public class SCLCompiler { CompilationContext compilationContext = new CompilationContext(); DeclarationClassification declarations = new DeclarationClassification(compilationContext); // publishable results Map classes; ConcreteModule module; ModuleInitializer moduleInitializer; private CompilationTimer timer; private ModuleCompilationOptions options; JavaReferenceValidatorFactory jrvFactory; public SCLCompiler(ModuleCompilationOptions options, JavaReferenceValidatorFactory jrvFactory) { this.options = options == null ? ModuleCompilationOptions.STANDARD_OPTIONS : options; this.jrvFactory = jrvFactory; } @SuppressWarnings("unchecked") public void addSource(Reader sourceReader) { if(SCLCompilerConfiguration.ENABLE_TIMING) initializeTiming(); try { SCLParserImpl parser = new SCLParserImpl(sourceReader); parser.setParserOptions(SCLParserOptions.MODULE_DEFAULT); if(!parser.isEmpty()) for(DeclarationAst declaration : (ArrayList)parser.parseModule()) declarations.handle(declaration); } catch(SCLSyntaxErrorException e) { compilationContext.errorLog.log(e.location, e.getMessage()); } catch(Exception e) { compilationContext.errorLog.log(e); } finally { try { sourceReader.close(); } catch (IOException e) { e.printStackTrace(); } } if(SCLCompilerConfiguration.ENABLE_TIMING) phaseFinished("Parsing"); } private boolean hasErrors() { return !compilationContext.errorLog.hasNoErrors(); } public void compile( EnvironmentFactory localEnvironmentFactory, String moduleName) { try { if(hasErrors()) return; Elaboration elaboration = new Elaboration(compilationContext, timer, localEnvironmentFactory, moduleName, ModuleHeader.process(compilationContext.errorLog, declarations.moduleHeader), declarations.importsAst, jrvFactory, declarations.valueDefinitionsAst, declarations.relationDefinitionsAst); if(options.computeCoverage) elaboration.addCoverageBranchPoints(); // Elaboration if(hasErrors()) return; elaboration.addTypesToEnvironment( declarations.dataTypesAst, declarations.typeAliasesAst, declarations.effectsAst); if(hasErrors()) return; elaboration.processTypeAliases(declarations.typeAliasesAst); if(hasErrors()) return; elaboration.processDataTypes(declarations.dataTypesAst); if(hasErrors()) return; elaboration.processTypeClasses(declarations.typeClassesAst); if(hasErrors()) return; elaboration.processDerivingInstances(declarations.derivingInstancesAst, declarations.instancesAst); if(hasErrors()) return; elaboration.processInstances(declarations.instancesAst); if(hasErrors()) return; elaboration.processJavaMethods(declarations.javaMethodDeclarations); if(hasErrors()) return; elaboration.addDataTypesToEnvironment(); elaboration.addTypeClassesToEnvironment(); elaboration.preprocessValueDefinitions(declarations.typeAnnotationsAst); elaboration.processMappingRelations(declarations.mappingRelationsAst); elaboration.addFixityToEnvironment(declarations.fixityAst); elaboration.addValueDefinitionsToEnvironment(declarations.typeAnnotationsAst); elaboration.processRules(declarations.rulesAst); elaboration.addSupplementedTypeAnnotationsToEnvironment(); if(SCLCompilerConfiguration.ENABLE_TIMING) phaseFinished("Elaboration"); // Type checking if(hasErrors()) return; //new TypeChecking(errorLog, elaboration.environment, elaboration.module).typeCheck(); new TypeChecking(compilationContext, elaboration.module).typeCheck(); if(SCLCompilerConfiguration.ENABLE_TIMING) phaseFinished("Type checking"); // FIXME HACK for testing /*if(!elaboration.module.getRules().isEmpty()) { TransformationBuilder tb = new TransformationBuilder(elaboration.module.getRules()); tb.compileRules(elaboration.environment); System.out.println(tb.getCompiledExpression(elaboration.environment)); }*/ // Documentation generation new DocumentationGeneration( declarations.valueDocumentation, declarations.typeDocumentation, declarations.classDocumentation, elaboration.module ) .generateDocumentation(); this.declarations = null; // Code generation if(hasErrors()) return; CodeGeneration codeGeneration = new CodeGeneration( compilationContext, elaboration.javaReferenceValidator, elaboration.module); codeGeneration.simplifyValues(); if(hasErrors()) return; codeGeneration.convertToSSA(); if(hasErrors()) return; codeGeneration.optimizeSSA(); if(SCLCompilerConfiguration.ENABLE_TIMING) phaseFinished("SSA conversion and optimization"); if(hasErrors()) return; codeGeneration.generateCode(); if(hasErrors()) return; codeGeneration.generateDataTypes(elaboration.dataTypes); if(hasErrors()) return; codeGeneration.generateTypeClasses(); if(hasErrors()) return; codeGeneration.generateTypeClassInstances(); if(hasErrors()) return; classes = codeGeneration.classes; module = codeGeneration.module; moduleInitializer = StandardModuleInitializer.create( compilationContext.namingPolicy.getModuleClassName(), codeGeneration.externalConstants); module.setClasses(classes); module.setParentClassLoader(elaboration.javaReferenceValidator.getClassLoader()); module.setModuleInitializer(moduleInitializer); module.setBranchPoints(elaboration.branchPoints); if(compilationContext.errorLog.hasErrorsOrWarnings()) module.setWarnings(compilationContext.errorLog.getErrors()); if(SCLCompilerConfiguration.ENABLE_TIMING) { phaseFinished("Code generation"); reportTiming(moduleName); } } catch(Exception e) { compilationContext.errorLog.log(e); } } public ErrorLog getErrorLog() { return compilationContext.errorLog; } public Map getClasses() { return classes; } public ConcreteModule getModule() { return module; } public ModuleInitializer getModuleInitializer() { return moduleInitializer; } private void initializeTiming() { timer = new CompilationTimer(); } private void phaseFinished(String phaseName) { timer.phaseFinished(phaseName); } private void reportTiming(String moduleName) { timer.report(moduleName); } }