blob: da42397af95b348857e565408853bc4ba48598c2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 INRIA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* INRIA - initial API and implementation
*
* $Id: ASM.java,v 1.2.4.4 2008/07/07 13:22:03 fjouault Exp $
*******************************************************************************/
package org.eclipse.m2m.atl.engine.emfvm;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import org.eclipse.m2m.atl.engine.emfvm.AtlSuperimposeModule.AtlSuperimposeModuleException;
import org.eclipse.m2m.atl.engine.emfvm.emf.EMFModelAdapter;
import org.eclipse.m2m.atl.engine.emfvm.lib.ASMModule;
import org.eclipse.m2m.atl.engine.emfvm.lib.ExecEnv;
import org.eclipse.m2m.atl.engine.emfvm.lib.Extension;
import org.eclipse.m2m.atl.engine.emfvm.lib.ModelAdapter;
import org.eclipse.m2m.atl.engine.emfvm.lib.ReferenceModel;
import org.eclipse.m2m.atl.engine.emfvm.lib.VMException;
/**
*
* @author Frederic Jouault
* @author Mikael Barbero
* @author Dennis Wagelaar <dennis.wagelaar@vub.ac.be>
*/
public class ASM {
private String name;
private List operations = new ArrayList();
private List fields = new ArrayList();
private ASMOperation mainOperation = null;
public ASM() {
}
public void setName(String name) {
this.name = name;
}
public void addField(String name, String type) {
fields.add(name);
}
public void addOperation(ASMOperation operation) {
operations.add(operation);
if(operation.getName().equals("main") && operation.getContext().equals("A")) {
mainOperation = operation;
}
}
/**
* @return All registered operations.
* @see #addOperation(ASMOperation)
* @author Dennis Wagelaar <dennis.wagelaar@vub.ac.be>
*/
public Iterator getOperations() {
return operations.iterator();
}
/**
* @return "main" operation, if any.
* @author Dennis Wagelaar <dennis.wagelaar@vub.ac.be>
*/
public ASMOperation getMainOperation() {
return mainOperation;
}
// TODO:
// - implements other options
// - define options somewhere (currently, best definition is in regular VM)
public Object run(Map models, Map libraries, List superimpose, Map options) {
Object ret = null;
boolean printExecutionTime = "true".equals(options.get("printExecutionTime"));
long startTime = System.currentTimeMillis();
ExecEnv execEnv = new ExecEnv(models);
ModelAdapter modelAdapter = new EMFModelAdapter(execEnv);
// by default (if options.get("checkSameModel") == null) interModelReferences are not allowed
modelAdapter.setAllowInterModelReferences("false".equals(options.get("checkSameModel")));
execEnv.init(modelAdapter);
if("true".equals(options.get("step")))
execEnv.step = true;
String ext = (String)options.get("extensions");
if(ext != null) {
ClassLoader cl = getClass().getClassLoader();
String extraClasspath = (String)options.get("extraClasspath");
if(extraClasspath != null) {
String paths[] = extraClasspath.split(",");
URL urls[] = new URL[paths.length];
String userDir = (String)options.get("user.dir");
if(userDir == null)
userDir = System.getProperty("user.dir");
for(int i = 0 ; i < paths.length ; i++) {
try {
urls[i] = new File(userDir, paths[i]).toURI().toURL();
} catch (MalformedURLException e) {
throw new RuntimeException("error while loading extra classpath entry: \"" + paths[i] +"\"", e);
}
}
cl = new URLClassLoader(urls, cl);
}
String extensions[] = ext.split(",");
for(int i = 0 ; i < extensions.length ; i++) {
try {
Extension extension = (Extension)cl.loadClass(extensions[i]).newInstance();
extension.apply(execEnv, options);
} catch (ClassNotFoundException e) {
throw new RuntimeException("error while loading extension class: \"" + extensions[i] +"\"", e);
} catch (InstantiationException e) {
throw new RuntimeException("error while instantiating extension class: \"" + extensions[i] +"\"", e);
} catch (IllegalAccessException e) {
throw new RuntimeException("error while instantiating extension class: \"" + extensions[i] +"\"", e);
}
}
}
List extensionObjects = (List)options.get("extensionObjects");
if(extensionObjects != null) {
for(Iterator i = extensionObjects.iterator() ; i.hasNext() ; ) {
((Extension)i.next()).apply(execEnv, options);
}
}
ASMModule asmModule = new ASMModule();
StackFrame frame = new StackFrame(execEnv, asmModule, mainOperation);
for(Iterator i = libraries.values().iterator() ; i.hasNext() ; ) {
ASM library = (ASM)i.next();
registerOperations(execEnv, library.operations);
if(library.mainOperation != null)
library.mainOperation.exec(new StackFrame(execEnv, asmModule, library.mainOperation));
}
// register module operations after libraries to avoid overriding
// "main" in execEnv (avoid superimposition problems)
registerOperations(execEnv, operations);
for(Iterator i = superimpose.iterator() ; i.hasNext() ; ) {
ASM module = (ASM)i.next();
AtlSuperimposeModule ami = new AtlSuperimposeModule(execEnv, module);
try {
ami.adaptModuleOperations();
} catch (AtlSuperimposeModuleException e) {
throw new VMException(frame, e);
}
registerOperations(execEnv, module.operations);
}
ret = mainOperation.exec(frame);
long endTime = System.currentTimeMillis();
if(printExecutionTime)
execEnv.logger.info("Executed " + name + " in " + ((endTime - startTime) / 1000.) + "s.");
if("true".equals(options.get("showSummary")))
execEnv.logger.info("Number of instructions executed: " + execEnv.nbExecutedBytecodes);
return ret;
}
public void registerOperations(ExecEnv execEnv, List operations) {
for(Iterator i = operations.iterator() ; i.hasNext() ; ) {
ASMOperation op = (ASMOperation)i.next();
String signature = op.getContext();
if(signature.matches("^(Q|G|C|E|O|N).*$")) {
// Sequence, Bag, Collection, Set, OrderedSet, Native type
execEnv.logger.warning("Unsupported registration: " + signature);
// } else if(signature.startsWith("T")) {
// logger.warning("Unsupported registration: " + signature);
} else {
try {
Object type = parseType(execEnv, new StringCharacterIterator(signature));
//logger.info("registering " + op + " on " + type);
execEnv.registerOperation(type, op, op.getName());
//op.setContextType(type);
} catch(SignatureParsingException spe) {
execEnv.logger.log(Level.SEVERE, spe.getLocalizedMessage(), spe);
// spe.printStackTrace(System.out);
}
}
}
}
// read until c, including c
// returns everything read before c
private String readUntil(CharacterIterator ci, char c) throws SignatureParsingException {
StringBuffer ret = new StringBuffer();
while(ci.current() != c) {
ret.append(ci.current());
ci.next();
}
read(ci, c);
return ret.toString();
}
private void read(CharacterIterator ci, char c) throws SignatureParsingException {
if(ci.current() != c)
throw new SignatureParsingException("Expected \'" + c + "\', found \'" + ci.current() + "\' at position " + ci.getIndex() + ".");
ci.next();
}
// Type may be java.lang.Class, EClass, OclType
private Object parseType(ExecEnv execEnv, CharacterIterator ci) throws SignatureParsingException {
Object ret = parseTypeInternal(execEnv, ci);
if(ci.next() != CharacterIterator.DONE) {
throw new SignatureParsingException("End of type signature expected at position " + ci.getIndex() + ".");
}
return ret;
}
private Object parseTypeInternal(ExecEnv execEnv, CharacterIterator ci) throws SignatureParsingException {
Object ret = null;
switch(ci.current()) {
// case 'Q': case 'G': case 'C': // Sequence, Bag, Collection,
// case 'E': case 'O': case 'N': // Set, OrderedSet, Native type
// ci.next();
// //ASMOclType elementType = parseTypeInternal(ci);
// read(ci, ';');
// break;
// case 'T': // Tuple
// ci.next();
// Map attrs = new HashMap();
// while(ci.current() != ';') {
// ASMOclType attrType = parseTypeInternal(ci);
// String attrName = readUntil(ci, ';');
// //attrs.put(attrName, attrType); // TODO: correct type
// attrs.put(attrName, ASMOclAny.myType);
// }
// ret = new ASMTupleType(attrs);
// break;
case 'M': // Metamodel Class
ci.next();
String mname = readUntil(ci, '!');
String name = readUntil(ci, ';');
ReferenceModel model = (ReferenceModel)execEnv.getModel(mname);
if(model != null) {
Object ec = model.getMetaElementByName(name);
if(ec == null)
throw new SignatureParsingException("ERROR: could not find model element " + name + " from " + mname);
ret = ec;
} else {
execEnv.logger.warning("Could not find model " + mname + ".");
}
break;
// Primitive types, VM Types
case 'A': // Module
ret = ASMModule.class;
ci.next();
break;
case 'J': // Object => OclAny ?
ret = Object.class;
ci.next();
break;
// case 'V': // Void
// ret = ASMOclUndefined.myType;
// ci.next();
// break;
case 'I': // Integer
ret = Integer.class;
ci.next();
break;
case 'B': // Boolean
ret = Boolean.class;
ci.next();
break;
case 'S': // String
ret = String.class;
ci.next();
break;
// case 'Z': // String
// ret = ASMEnumLiteral.myType;
// ci.next();
// break;
case 'D': // Real
ret = Double.class;
ci.next();
break;
// case 'L': // Model
// ret = ASMModel.myType;
// ci.next();
// break;
case CharacterIterator.DONE:
throw new SignatureParsingException("End of type signature unexpected at position " + ci.getIndex() + ".");
default:
throw new SignatureParsingException("Unknown type code : " + ci.current() + ".");
}
return ret;
}
private class SignatureParsingException extends Exception {
/**
*
*/
private static final long serialVersionUID = 7488097967558841786L;
public SignatureParsingException(String msg) {
super(msg);
}
}
}