Bug 580300 - thisModule.refSetValue() not supported in EMFTVM

Change-Id: I5a97b321922d4a9a85b19fc30e62a916124603df
Signed-off-by: Dennis Wagelaar <dwagelaar@gmail.com>
diff --git a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/OCLOperations.java b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/OCLOperations.java
index 2fdb480..27f6a56 100644
--- a/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/OCLOperations.java
+++ b/plugins/org.eclipse.m2m.atl.emftvm/src/org/eclipse/m2m/atl/emftvm/util/OCLOperations.java
@@ -37,6 +37,7 @@
 import org.eclipse.m2m.atl.emftvm.CodeBlock;
 import org.eclipse.m2m.atl.emftvm.EmftvmFactory;
 import org.eclipse.m2m.atl.emftvm.ExecEnv;
+import org.eclipse.m2m.atl.emftvm.Field;
 import org.eclipse.m2m.atl.emftvm.Model;
 import org.eclipse.m2m.atl.emftvm.Module;
 import org.eclipse.m2m.atl.emftvm.Operation;
@@ -864,6 +865,115 @@
 							rule, name, EMFTVMUtil.toPrettyString(object, frame.getEnv())));
 				}
 			});
+		createOperation(true, "refGetValue", Types.EXEC_ENV_TYPE, Types.OCL_ANY_TYPE,
+				new String[][][]{{{"propname"}, Types.STRING_TYPE}},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = frame.getEnv();
+						final String propname = (String) frame.getLocal(0, 0);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							return field.getStaticValue(frame);
+						}
+						throw new VMException(frame,
+								String.format("Cannot find property %s::%s",
+										EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(false, "refGetValue", Types.EXEC_ENV_TYPE, Types.OCL_ANY_TYPE,
+				new String[][][]{{{"propname"}, Types.STRING_TYPE}},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = (ExecEnv) frame.getLocal(0, 0);
+						final String propname = (String) frame.getLocal(0, 1);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							return field.getStaticValue(frame);
+						}
+						throw new VMException(frame,
+								String.format("Cannot find property %s::%s",
+										EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(true, "refSetValue", Types.EXEC_ENV_TYPE, Types.EXEC_ENV_TYPE,
+				new String[][][]{{{"propname"}, Types.STRING_TYPE}, {{"value"}, Types.OCL_ANY_TYPE}},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = frame.getEnv();
+						final String propname = (String) frame.getLocal(0, 0);
+						final Object value = frame.getLocal(0, 1);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							field.setStaticValue(value);
+							return env;
+						}
+						throw new VMException(frame,
+								String.format("Cannot find property %s::%s",
+										EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(false, "refSetValue", Types.EXEC_ENV_TYPE, Types.EXEC_ENV_TYPE,
+				new String[][][] { { { "propname" }, Types.STRING_TYPE }, { { "value" }, Types.OCL_ANY_TYPE } },
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = (ExecEnv) frame.getLocal(0, 0);
+						final String propname = (String) frame.getLocal(0, 1);
+						final Object value = frame.getLocal(0, 2);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							field.setStaticValue(value);
+							return env;
+						}
+						throw new VMException(frame, String.format("Cannot find property %s::%s",
+								EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(true, "refUnsetValue", Types.EXEC_ENV_TYPE, Types.EXEC_ENV_TYPE,
+				new String[][][]{{{"propname"}, Types.STRING_TYPE}},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = frame.getEnv();
+						final String propname = (String) frame.getLocal(0, 0);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							field.clear();
+							return env;
+						}
+						throw new VMException(frame,
+								String.format("Cannot find property %s::%s",
+										EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(false, "refUnsetValue", Types.EXEC_ENV_TYPE, Types.EXEC_ENV_TYPE,
+				new String[][][]{{{"propname"}, Types.STRING_TYPE}},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						final ExecEnv env = (ExecEnv) frame.getLocal(0, 0);
+						final String propname = (String) frame.getLocal(0, 1);
+						final Field field = env.findStaticField(EXEC_ENV, propname);
+						if (field != null) {
+							field.clear();
+							return env;
+						}
+						throw new VMException(frame,
+								String.format("Cannot find property %s::%s",
+										EMFTVMUtil.toPrettyString(EXEC_ENV, env), propname));
+					}
+				});
+		createOperation(true, "getEnv", Types.EXEC_ENV_TYPE, Types.EXEC_ENV_TYPE,
+				new String[][][] {},
+				new NativeCodeBlock() {
+					@Override
+					public Object execute(final StackFrame frame) {
+						return frame.getEnv();
+					}
+				});
 		/////////////////////////////////////////////////////////////////////
 		// Class
 		/////////////////////////////////////////////////////////////////////
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug580300.launch b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug580300.launch
new file mode 100644
index 0000000..df8c008
--- /dev/null
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/launch/Bug580300.launch
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.m2m.atl.emftvm.launcher.EMFTVMTransformation">
+    <stringAttribute key="ATL File Name" value="//org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.atl"/>
+    <booleanAttribute key="Disable JIT compiler" value="false"/>
+    <booleanAttribute key="Display Profiling Data" value="false"/>
+    <booleanAttribute key="Display Timing Data" value="true"/>
+    <mapAttribute key="Inout Model Options"/>
+    <mapAttribute key="Inout Models"/>
+    <mapAttribute key="Inout Models Output Locations"/>
+    <mapAttribute key="Input Model Options"/>
+    <mapAttribute key="Input Models">
+        <mapEntry key="IN" value="http://www.eclipse.org/emf/2002/Ecore"/>
+    </mapAttribute>
+    <mapAttribute key="Metamodel Options">
+        <mapEntry key="ECORE" value="isMetametamodel"/>
+    </mapAttribute>
+    <mapAttribute key="Metamodels">
+        <mapEntry key="ECORE" value=""/>
+    </mapAttribute>
+    <stringAttribute key="Module Name" value="Regression::Bug580300"/>
+    <stringAttribute key="Module Path" value="/org.eclipse.m2m.atl.emftvm.tests/test-data/"/>
+    <mapAttribute key="Output Model Options">
+        <mapEntry key="OUT" value="derivedFile"/>
+    </mapAttribute>
+    <mapAttribute key="Output Models">
+        <mapEntry key="OUT" value="platform:/resource/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300-out.ecore"/>
+    </mapAttribute>
+    <listAttribute key="Superimpose"/>
+</launchConfiguration>
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java
index 056bb0c..bd63365 100644
--- a/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/src/org/eclipse/m2m/atl/emftvm/tests/integration/IntegrationTest.java
@@ -425,6 +425,28 @@
 	}
 
 	/**
+	 * Tests regression of <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=580300">Bug # 580300</a>.
+	 */
+	public void testBug580300() {
+		final ResourceSet rs = new ResourceSetImpl();
+		final ExecEnv env = EmftvmFactory.eINSTANCE.createExecEnv();
+		final TimingData td = new TimingData();
+		final Metamodel metamodel = EmftvmFactory.eINSTANCE.createMetamodel(EcorePackage.eINSTANCE.eResource());
+		final Model out = createTestModel(rs, "/test-data/Regression/Bug441027-out.xmi");
+		env.registerMetaModel("ECORE", metamodel);
+		env.registerInputModel("IN", metamodel);
+		env.registerOutputModel("OUT", out);
+		env.loadModule(createTestModuleResolver(), "Regression::Bug580300");
+		td.finishLoading();
+		env.run(td);
+		td.finish();
+
+		final ResourceSet refRs = new ResourceSetImpl();
+		final Model refOut = loadTestModel(refRs, "/test-data/Regression/Bug580300-out.ecore");
+		assertEquals(refOut.getResource(), out.getResource());
+	}
+
+	/**
 	 * Tests the ATL metamodel API.
 	 */
 	public void testATLAPI() throws Exception {
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300-out.ecore b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300-out.ecore
new file mode 100644
index 0000000..8f279f6
--- /dev/null
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300-out.ecore
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="ecoreCounter">
+  <eClassifiers xsi:type="ecore:EClass" name="1"/>
+  <eClassifiers xsi:type="ecore:EClass" name="2"/>
+  <eClassifiers xsi:type="ecore:EClass" name="3"/>
+  <eClassifiers xsi:type="ecore:EClass" name="4"/>
+  <eClassifiers xsi:type="ecore:EClass" name="5"/>
+  <eClassifiers xsi:type="ecore:EClass" name="6"/>
+  <eClassifiers xsi:type="ecore:EClass" name="7"/>
+  <eClassifiers xsi:type="ecore:EClass" name="8"/>
+  <eClassifiers xsi:type="ecore:EClass" name="9"/>
+  <eClassifiers xsi:type="ecore:EClass" name="10"/>
+  <eClassifiers xsi:type="ecore:EClass" name="11"/>
+  <eClassifiers xsi:type="ecore:EClass" name="12"/>
+  <eClassifiers xsi:type="ecore:EClass" name="13"/>
+  <eClassifiers xsi:type="ecore:EClass" name="14"/>
+  <eClassifiers xsi:type="ecore:EClass" name="15"/>
+  <eClassifiers xsi:type="ecore:EClass" name="16"/>
+  <eClassifiers xsi:type="ecore:EClass" name="17"/>
+  <eClassifiers xsi:type="ecore:EClass" name="18"/>
+  <eClassifiers xsi:type="ecore:EClass" name="19"/>
+  <eClassifiers xsi:type="ecore:EClass" name="20"/>
+</ecore:EPackage>
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.atl b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.atl
new file mode 100644
index 0000000..d27568a
--- /dev/null
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.atl
@@ -0,0 +1,42 @@
+-- @atlcompiler emftvm
+-- @nsURI ECORE=http://www.eclipse.org/emf/2002/Ecore
+module "Regression::Bug580300";
+
+create OUT : ECORE from IN : ECORE;
+
+helper def: diff2 : Integer = 0;
+
+-- This helper increments diff2 value
+-- CONTEXT: thisModule
+-- RETURN:  Integer
+helper def: incDiff2() : Integer =
+	thisModule.refSetValue('diff2', thisModule.diff2+1).refGetValue('diff2');
+
+rule EPackage {
+	from
+		s : ECORE!EPackage
+	to
+		t : ECORE!EPackage (
+			name <- s.name + 'Counter',
+			eClassifiers <- s.eClassifiers->select(c | c.oclIsKindOf(ECORE!EClass)),
+			eSubpackages <- s.eSubpackages
+		)
+}
+
+rule EClass {
+	from
+		s : ECORE!EClass
+	to
+		t : ECORE!EClass (
+			name <- thisModule.incDiff2().toString()
+		)
+}
+
+endpoint rule After() {
+	do {
+		thisModule.refUnsetValue('diff2');
+		thisModule.getEnv().debug('getEnv')
+			.findStaticField(EMFTVM!ExecEnv, 'diff2').debug('findField')
+			.getStaticValue().debug('getStaticValue');
+	}
+}
diff --git a/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.emftvm b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.emftvm
new file mode 100644
index 0000000..c85ed92
--- /dev/null
+++ b/tests/org.eclipse.m2m.atl.emftvm.tests/test-data/Regression/Bug580300.emftvm
Binary files differ