All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.epsilon.hutn.HutnModule Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2008 The University of York.
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 * 
 * Contributors:
 *     Louis Rose - initial API and implementation
 ******************************************************************************/
package org.eclipse.epsilon.hutn;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.antlr.runtime.ANTLRInputStream;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Lexer;
import org.antlr.runtime.TokenStream;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.epsilon.antlr.postprocessor.model.antlrAst.Ast;
import org.eclipse.epsilon.common.module.IModule;
import org.eclipse.epsilon.common.module.ModuleElement;
import org.eclipse.epsilon.common.parse.AST;
import org.eclipse.epsilon.common.parse.EpsilonParser;
import org.eclipse.epsilon.common.parse.problem.ParseProblem;
import org.eclipse.epsilon.emc.emf.AbstractEmfModel;
import org.eclipse.epsilon.emc.emf.EmfModel;
import org.eclipse.epsilon.emc.emf.EmfUtil;
import org.eclipse.epsilon.emc.emf.InMemoryEmfModel;
import org.eclipse.epsilon.eol.EolModule;
import org.eclipse.epsilon.hutn.exceptions.HutnConfigFileNotFoundException;
import org.eclipse.epsilon.hutn.exceptions.HutnException;
import org.eclipse.epsilon.hutn.exceptions.HutnGenerationException;
import org.eclipse.epsilon.hutn.exceptions.HutnUnrecognisedNsUriException;
import org.eclipse.epsilon.hutn.generate.metamodel.MetaModelGenerator;
import org.eclipse.epsilon.hutn.generate.model.ModelGenerator;
import org.eclipse.epsilon.hutn.model.hutn.HutnPackage;
import org.eclipse.epsilon.hutn.model.hutn.NsUri;
import org.eclipse.epsilon.hutn.model.hutn.Spec;
import org.eclipse.epsilon.hutn.parse.HutnLexer;
import org.eclipse.epsilon.hutn.parse.HutnParser;
import org.eclipse.epsilon.hutn.parse.postprocessor.HutnPostProcessor;
import org.eclipse.epsilon.hutn.translate.HutnTranslator;
import org.eclipse.epsilon.hutn.validation.model.HutnValidator;

public class HutnModule extends EolModule implements IHutnModule {

	protected HutnDocument document;
	protected Spec spec;
	protected boolean metaModelIsValid = true;
	protected File configFileDirectory;
	protected boolean hutnIsValid = false;
	
	public HutnModule() {
		this(null);
	}
	
	/**
	 * Instantiates the module with the specified execution context.
	 * 
	 * @param context The execution context
	 * @since 1.6
	 */
	public HutnModule(IHutnContext context) {
		super(context != null ? context : new HutnContext());
		getContext().setModule(this);
	}
	
	@Override
	protected Lexer createLexer(ANTLRInputStream inputStream) {
		return new HutnLexer(inputStream);
	}
	
	@Override
	public EpsilonParser createParser(TokenStream tokenStream) {
		return new HutnParser(tokenStream);
	}
	
	@Override
	public ModuleElement adapt(AST cst, ModuleElement parentAst) {
		
		if (parentAst == null) return this;
		
		if (cst.getParent() == null) {
			return new HutnDocument();
		}
		return null;
	}
	
	@Override
	public String getMainRule() {
		return "document";
	}
	
	@Override
	public IHutnContext getContext(){
		return (IHutnContext) super.getContext();
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.eclipse.epsilon.eol.AbstractModule#invokeMainRule()
	 * 
	 * Overridden to ensure that errors found during building
	 * the HUTN model cause parse() to return false.
	 */
	@Override
	protected boolean invokeMainRule(List comments) throws Exception {
		boolean buildModelWasCalled = super.invokeMainRule(comments);
		
		if (buildModelWasCalled) {
			return parsingWasSuccessful();
		}
		
		return false; // parsing must have failed before build model was called
	}
	
	protected boolean parsingWasSuccessful() {
		for (ParseProblem p : getParseProblems()) {
			if (p.getSeverity() == ParseProblem.ERROR)
				return false;
		}
		
		return true;
	}

	@Override
	public void build(AST cst, IModule module) {
		document = (HutnDocument) module.createAst(cst, this);
		try {
			translateAst(cst);
		} catch (HutnException e) {
			throw new RuntimeException(e);
		}
	}

	protected void translateAst(AST ast) throws HutnException {
		try {
			final Ast astModel = new HutnPostProcessor(getParseProblems()).process(ast);
			
			final HutnTranslator translator = new HutnTranslator(configFileDirectory);
			getParseProblems().addAll(translator.validateConfigModel(astModel));
			
			hutnIsValid = parsingWasSuccessful();
			if (hutnIsValid) {
				spec = translator.createIntermediateModel(astModel, sourceFile);
				if (spec == null)
					throw new IllegalArgumentException("Could not generate Intermediate model for specified text.");
				
				getParseProblems().addAll(new HutnValidator().getProblemsForIntermediateModel(spec));
			}
		
		} catch (HutnConfigFileNotFoundException e) {
			getParseProblems().add(new ParseProblem(e.getLine(), e.getColumn(), "Configuration file not found: " + e.getPath()));
		
		} catch (HutnUnrecognisedNsUriException e) {
			getParseProblems().add(new ParseProblem(e.getLine(), e.getColumn(), "Unrecognised namespace URI: " + e.getUri()));
			metaModelIsValid = false;
		}
	}

	@Override
	public boolean hasValidHutn() {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		
		return hutnIsValid;
	}
	
	@Override
	public void setConfigFileDirectory(File configFileDirectory) {
		this.configFileDirectory = configFileDirectory;
	}
	
	@Override
	public boolean hasValidMetaModel() {
		return metaModelIsValid;
	}
	
	@Override
	public List getNsUris() {
		final List nsUris = new LinkedList<>();
		
		if (spec != null) {
			for (NsUri uri : spec.getNsUris()) {
				nsUris.add(uri.getValue());
			}
		}
		
		return Collections.unmodifiableList(nsUris);
	}
	
	@Override
	public String getModelFile() {
		if (spec != null) {
			return spec.getModelFile();
		}
		
		return null;
	}
	
	@Override
	public AbstractEmfModel generateEmfModel() throws HutnGenerationException {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		if (hasInferredMetaModel()) {
			throw new IllegalStateException("Cannot generate an in-memory model when the metamodel needs to be inferred.");
		} else {
			return new ModelGenerator(spec).generate(spec.getModelFile());
		}
	}
	
	@Override
	public List storeEmfModel(File baseDirectory, String defaultModelPath, String inferredMetamodelPath) throws HutnGenerationException {
		final List generated = new LinkedList<>();
		
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		
		// Construct new generator based on whether a metamodel needs to be inferred
		final ModelGenerator generator;
		
		if (hasInferredMetaModel()) {
			final File metamodel = new File(baseDirectory, inferredMetamodelPath);
			generateEmfMetaModel(metamodel);
			generator = new ModelGenerator(spec, metamodel);
			
			generated.add(metamodel);
			
		} else {
			generator = new ModelGenerator(spec);
		}
			
		// Generate and store model based on whether a model file has been specified in the @Spec
		final File model;
		
		if (spec.getModelFile() == null) {
			model = new File(baseDirectory, defaultModelPath);
		} else {
			model = new File(baseDirectory, spec.getModelFile());
		}
		
		generator.store(model);
		generated.add(model);
		
		return generated;
	}
	
	private boolean hasInferredMetaModel() {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		return spec.getNsUris().isEmpty();
	}
	
	private void generateEmfMetaModel(File destination) throws HutnGenerationException {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		new MetaModelGenerator(spec).store(destination);
	}
	
	
	@Override
	public Spec getIntermediateModel() {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		
		return spec;
	}
	
	@Override
	public void storeIntermediateModel(File destination) {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		
		final URI fileUri = URI.createFileURI(destination.getAbsolutePath());
		final Resource resource = EmfUtil.createResource(fileUri);
		resource.getContents().add(spec);
		
		try (EmfModel model = new InMemoryEmfModel("Intermediate", resource, HutnPackage.eINSTANCE)) {
			model.store(fileUri);
		}
	}
	
	@Override
	public void storeIntermediateModelTransformation(File destination) throws HutnGenerationException {
		storeIntermediateModelTransformation(destination, false);
	}
	
	@Override
	public void storeIntermediateModelTransformationForAllInputModels(File destination) throws HutnGenerationException {
		storeIntermediateModelTransformation(destination, true);
	}

	private void storeIntermediateModelTransformation(File destination, boolean generateCompleteTransformation) throws HutnGenerationException {
		if (spec == null) throw new IllegalStateException("No HUTN has been parsed.");
		
		try {
			final ModelGenerator modelGenerator = new ModelGenerator(spec);
			if (generateCompleteTransformation) {
				modelGenerator.forceGenerationOfTransformationForWholeMetamodel();
			}
			
			try (FileWriter writer = new FileWriter(destination)) {
				writer.write(modelGenerator.generateTransformation());
			}
		}
		catch (IOException e) {
			throw new HutnGenerationException(e);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy