-/*******************************************************************************\r
- * Copyright (c) 2007, 2011 Association for Decentralized Information Management in\r
- * Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.graph.utils;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Stack;\r
-\r
-import org.simantics.databoard.Accessors;\r
-import org.simantics.databoard.Bindings;\r
-import org.simantics.databoard.accessor.Accessor;\r
-import org.simantics.databoard.accessor.ArrayAccessor;\r
-import org.simantics.databoard.accessor.LongAccessor;\r
-import org.simantics.databoard.accessor.MapAccessor;\r
-import org.simantics.databoard.accessor.OptionalAccessor;\r
-import org.simantics.databoard.accessor.RecordAccessor;\r
-import org.simantics.databoard.accessor.UnionAccessor;\r
-import org.simantics.databoard.accessor.VariantAccessor;\r
-import org.simantics.databoard.accessor.error.AccessorConstructionException;\r
-import org.simantics.databoard.accessor.error.AccessorException;\r
-import org.simantics.databoard.accessor.reference.ChildReference;\r
-import org.simantics.databoard.accessor.reference.ComponentReference;\r
-import org.simantics.databoard.accessor.reference.IndexReference;\r
-import org.simantics.databoard.binding.Binding;\r
-import org.simantics.databoard.type.ArrayType;\r
-import org.simantics.databoard.type.Datatype;\r
-import org.simantics.databoard.type.LongType;\r
-import org.simantics.databoard.type.MapType;\r
-import org.simantics.databoard.type.OptionalType;\r
-import org.simantics.databoard.type.RecordType;\r
-import org.simantics.databoard.type.UnionType;\r
-import org.simantics.databoard.type.VariantType;\r
-import org.simantics.databoard.util.DatatypeVisitorAdapter;\r
-\r
-/**\r
- * Util for converting all the Long values in a TG, that have metadata "resource=true".\r
- * \r
- * @author toni.kalajainen\r
- */\r
-public class TGResourceUtil {\r
- \r
- public static final Datatype RESOURCE_TYPE;\r
- \r
- Map<Datatype, Item> items = new HashMap<Datatype, Item>();\r
- int index = 0;\r
-\r
- /**\r
- * Add type to the cache and get some info.\r
- * \r
- * @param type\r
- * @return\r
- */\r
- public Item createItem( Datatype type )\r
- {\r
- Item item = new Item();\r
- item.index = index++;\r
- item.type = type;\r
- HasResVisitor v = new HasResVisitor();\r
- type.accept( v, item );\r
- if ( v.hasRes || v.hasVariant ) {\r
- GetRefsVisitor vv = new GetRefsVisitor();\r
- type.accept( vv, item );\r
- }\r
- return item;\r
- }\r
- \r
- \r
- /**\r
- * Find all resources in the value. The resources are added to the result-collection.\r
- * It may be good to idea to use a Set to avoid duplicate values. \r
- * \r
- * @param type\r
- * @param value\r
- * @param result\r
- * @throws AccessorException \r
- * @throws AccessorConstructionException \r
- */\r
- public void findResources( Datatype type, byte[] value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
- {\r
- LongAdapter la = new LongAdapter() {\r
- @Override\r
- public long adapt(long in) {\r
- result.add(in);\r
- // Return same value\r
- return in;\r
- } \r
- };\r
- \r
- adaptValue( type, value, la );\r
- }\r
-\r
- public void findResources( Binding binding, Object value, final Collection<Long> result) throws AccessorConstructionException, AccessorException\r
- {\r
- LongAdapter la = new LongAdapter() {\r
- @Override\r
- public long adapt(long in) {\r
- result.add(in);\r
- // Return same value\r
- return in;\r
- } \r
- };\r
- \r
- adaptValue( binding, value, la );\r
- }\r
- \r
- /**\r
- * Add type to the util.\r
- * @param type\r
- * @return\r
- */\r
- public Item addType( Datatype type )\r
- {\r
- Item i = items.get( type );\r
- if ( i==null ) {\r
- i = createItem(type);\r
- items.put(type, i);\r
- }\r
- return i;\r
- }\r
- \r
- public void adaptValue( Datatype type, byte[] value, LongAdapter adapter ) throws AccessorException\r
- {\r
- Item i = addType( type );\r
- if (!i.mayHaveResource()) return;\r
- try {\r
- Accessor a = Accessors.getAccessor(value, type);\r
- adaptValue(i, a, adapter);\r
- } catch (AccessorConstructionException e) {\r
- throw new AccessorException(e);\r
- }\r
- }\r
- \r
- public boolean mayHaveResource( Datatype type ) {\r
- Item i = addType( type );\r
- return i.mayHaveResource();\r
- }\r
- \r
- public void adaptValue( Binding binding, Object value, LongAdapter adapter ) throws AccessorException\r
- {\r
- Item i = addType( binding.type() );\r
- if (!i.mayHaveResource()) return;\r
- try {\r
- Accessor a = Accessors.getAccessor(binding, value);\r
- adaptValue(i, a, adapter);\r
- } catch (AccessorConstructionException e) {\r
- throw new AccessorException(e);\r
- }\r
- }\r
- \r
- void adaptValue( Item i, Accessor a, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
- {\r
- if ( i.resources != null ) {\r
- for (ChildReference r : i.resources)\r
- {\r
- adaptValue(a, r, adapter);\r
- }\r
- }\r
- if ( i.variants != null ) {\r
- for (ChildReference r : i.variants)\r
- {\r
- adaptValue(a, r, adapter);\r
- }\r
- }\r
- }\r
- \r
- void adaptValue( Accessor a, ChildReference r, LongAdapter adapter ) throws AccessorException, AccessorConstructionException\r
- {\r
- if ( a instanceof LongAccessor ) {\r
- LongAccessor x = (LongAccessor) a;\r
- long value = x.getValue();\r
- long newValue = adapter.adapt( value );\r
- if ( newValue != value ) x.setValue( newValue );\r
- }\r
-\r
- if ( a instanceof VariantAccessor ) {\r
- VariantAccessor x = (VariantAccessor) a;\r
- Item i = createItem( x.getContentType() );\r
- adaptValue(i, x.getContentAccessor(), adapter);\r
- }\r
- \r
- if ( a instanceof MapAccessor ) {\r
- MapAccessor x = (MapAccessor) a;\r
- if (r instanceof IndexReference) {\r
- IndexReference ir = (IndexReference) r;\r
- // Resource is in the Key\r
- if (ir.index==0) {\r
- // Read the key as whole\r
- Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
- Binding valueBinding = Bindings.getBinding( x.type().valueType );\r
- Object[] keys = x.getKeys(keyBinding);\r
- for ( Object key : keys ) {\r
- Object value = x.get(keyBinding, key, valueBinding);\r
- // Fix the key\r
- Accessor ka = Accessors.getAccessor(keyBinding, key);\r
- adaptValue(ka, r.childReference, adapter);\r
- \r
- // Write \r
- x.remove(keyBinding, key);\r
- x.put(keyBinding, key, valueBinding, value);\r
- }\r
- }\r
- \r
- // Resource is in the value\r
- if (ir.index==1) {\r
- Binding keyBinding = Bindings.getBinding( x.type().keyType );\r
- Object[] keys = x.getKeys(keyBinding);\r
- for ( Object key : keys ) {\r
- Accessor va = x.getValueAccessor(keyBinding, key);\r
- adaptValue(va, r.childReference, adapter);\r
- }\r
- }\r
- } \r
- }\r
- \r
- if ( a instanceof ArrayAccessor ) {\r
- ArrayAccessor x = (ArrayAccessor) a;\r
- int len = x.size();\r
- for (int i=0; i<len; i++) {\r
- Accessor sa = x.getAccessor(i); \r
- adaptValue(sa, r.childReference, adapter);\r
- }\r
- }\r
- \r
- if ( a instanceof UnionAccessor ) {\r
- UnionAccessor x = (UnionAccessor) a;\r
- IndexReference ir = (IndexReference) r;\r
- if ( x.getTag() == ir.index ) {\r
- Accessor sa = x.getComponentAccessor();\r
- adaptValue(sa, ir.childReference, adapter);\r
- }\r
- }\r
- \r
- if ( a instanceof RecordAccessor ) {\r
- RecordAccessor x = (RecordAccessor) a;\r
- IndexReference ir = (IndexReference) r;\r
- Accessor sa = x.getFieldAccessor(ir.index);\r
- adaptValue(sa, ir.childReference, adapter);\r
- }\r
- \r
- if ( a instanceof OptionalAccessor ) {\r
- OptionalAccessor x = (OptionalAccessor) a;\r
- if (x.hasValue()) {\r
- Accessor sa = x.getComponentAccessor();\r
- adaptValue(sa, r.childReference, adapter);\r
- }\r
- }\r
- \r
- }\r
- \r
- public interface LongAdapter {\r
- long adapt(long in);\r
- }\r
- \r
- public static class Item {\r
- // The datatype\r
- public Datatype type;\r
- // Index of the type\r
- public int index;\r
- // Locations of variants in Datatype \r
- List<ChildReference> variants; \r
- // Locations of resources in Datatype \r
- List<ChildReference> resources;\r
- \r
- public boolean mayHaveResource() {\r
- return (variants!=null&&!variants.isEmpty()) || \r
- (resources!=null&&!resources.isEmpty());\r
- }\r
- \r
- void addVariant(ChildReference ref) {\r
- if ( variants == null ) variants = new ArrayList<ChildReference>();\r
- variants.add(ref);\r
- }\r
- \r
- void addResource(ChildReference ref) {\r
- if ( resources == null ) resources = new ArrayList<ChildReference>();\r
- resources.add( ref );\r
- }\r
- }\r
- \r
- static {\r
- RESOURCE_TYPE = new LongType();\r
- RESOURCE_TYPE.metadata.put("resource", "true");\r
- }\r
- \r
- /**\r
- * This visitor makes a quick peek to see if there is resource or variants.\r
- */\r
- static class HasResVisitor extends DatatypeVisitorAdapter {\r
-\r
- boolean hasRes = false, hasVariant = false;\r
- \r
- @Override\r
- public void visit(VariantType b, Object obj) {\r
- hasVariant = true;\r
- }\r
- \r
- @Override\r
- public void visit(LongType b, Object obj) {\r
- String s = b.metadata.get("unit");\r
- hasRes |= s!=null && s.equals("resource");\r
- }\r
- \r
- }\r
- \r
- static class GetRefsVisitor extends DatatypeVisitorAdapter {\r
- \r
- Stack<ChildReference> stack = new Stack<ChildReference>(); \r
- \r
- @Override\r
- public void visit(ArrayType b, Object obj) { \r
- if ( !visited.add(b) ) return; \r
- \r
- ComponentReference r = new ComponentReference();\r
- stack.push(r);\r
- b.componentType.accept(this, obj);\r
- stack.pop();\r
- }\r
- \r
- @Override\r
- public void visit(LongType b, Object obj) {\r
- String s = b.metadata.get("unit");\r
- boolean isRes = s!=null && s.equals("resource");\r
- if ( isRes ) {\r
- Item item = (Item) obj;\r
- item.addResource( toRef() );\r
- }\r
- }\r
- @Override\r
- public void visit(MapType b, Object obj) {\r
- if ( !visited.add(b) ) return; \r
- \r
- IndexReference r = new IndexReference(0);\r
- stack.push(r);\r
- b.keyType.accept(this, obj);\r
- stack.pop();\r
- r.index = 1;\r
- stack.push(r);\r
- b.valueType.accept(this, obj);\r
- stack.pop();\r
- }\r
- @Override\r
- public void visit(OptionalType b, Object obj) {\r
- if ( !visited.add(b) ) return; \r
- \r
- ComponentReference r = new ComponentReference();\r
- stack.push(r);\r
- b.componentType.accept(this, obj);\r
- stack.pop();\r
- }\r
- @Override\r
- public void visit(RecordType b, Object obj) {\r
- if ( !visited.add(b) ) return; \r
- \r
- IndexReference r = new IndexReference(0);\r
- stack.push(r);\r
- for (int i=0; i<b.getComponentCount(); i++) {\r
- r.index = i;\r
- b.getComponent(i).type.accept(this, obj);\r
- }\r
- stack.pop();\r
- }\r
- @Override\r
- public void visit(UnionType b, Object obj) {\r
- if ( !visited.add(b) ) return; \r
- \r
- IndexReference r = new IndexReference(0);\r
- stack.push(r);\r
- for (int i=0; i<b.getComponentCount(); i++) {\r
- r.index = i;\r
- b.getComponent(i).type.accept(this, obj);\r
- }\r
- stack.pop();\r
- }\r
- @Override\r
- public void visit(VariantType b, Object obj) {\r
- Item item = (Item) obj;\r
- item.addVariant( toRef() );\r
- }\r
- ChildReference toRef() {\r
- return ChildReference.compile(stack);\r
- }\r
- \r
- }\r
- \r
-\r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2011 Association for Decentralized Information Management in
+ * Industry THTH ry.
+ * 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:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.graph.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import org.simantics.databoard.Accessors;
+import org.simantics.databoard.Bindings;
+import org.simantics.databoard.accessor.Accessor;
+import org.simantics.databoard.accessor.ArrayAccessor;
+import org.simantics.databoard.accessor.LongAccessor;
+import org.simantics.databoard.accessor.MapAccessor;
+import org.simantics.databoard.accessor.OptionalAccessor;
+import org.simantics.databoard.accessor.RecordAccessor;
+import org.simantics.databoard.accessor.UnionAccessor;
+import org.simantics.databoard.accessor.VariantAccessor;
+import org.simantics.databoard.accessor.error.AccessorConstructionException;
+import org.simantics.databoard.accessor.error.AccessorException;
+import org.simantics.databoard.accessor.reference.ChildReference;
+import org.simantics.databoard.accessor.reference.ComponentReference;
+import org.simantics.databoard.accessor.reference.IndexReference;
+import org.simantics.databoard.binding.Binding;
+import org.simantics.databoard.type.ArrayType;
+import org.simantics.databoard.type.Datatype;
+import org.simantics.databoard.type.LongType;
+import org.simantics.databoard.type.MapType;
+import org.simantics.databoard.type.OptionalType;
+import org.simantics.databoard.type.RecordType;
+import org.simantics.databoard.type.UnionType;
+import org.simantics.databoard.type.VariantType;
+import org.simantics.databoard.util.DatatypeVisitorAdapter;
+
+/**
+ * Util for converting all the Long values in a TG, that have metadata "resource=true".
+ *
+ * @author toni.kalajainen
+ */
+public class TGResourceUtil {
+
+ public static final Datatype RESOURCE_TYPE;
+
+ Map<Datatype, Item> items = new HashMap<Datatype, Item>();
+ int index = 0;
+
+ /**
+ * Add type to the cache and get some info.
+ *
+ * @param type
+ * @return
+ */
+ public Item createItem( Datatype type )
+ {
+ Item item = new Item();
+ item.index = index++;
+ item.type = type;
+ HasResVisitor v = new HasResVisitor();
+ type.accept( v, item );
+ if ( v.hasRes || v.hasVariant ) {
+ GetRefsVisitor vv = new GetRefsVisitor();
+ type.accept( vv, item );
+ }
+ return item;
+ }
+
+
+ /**
+ * Find all resources in the value. The resources are added to the result-collection.
+ * It may be good to idea to use a Set to avoid duplicate values.
+ *
+ * @param type
+ * @param value
+ * @param result
+ * @throws AccessorException
+ * @throws AccessorConstructionException
+ */
+ public void findResources( Datatype type, byte[] value, final Collection<Long> result) throws AccessorConstructionException, AccessorException
+ {
+ LongAdapter la = new LongAdapter() {
+ @Override
+ public long adapt(long in) {
+ result.add(in);
+ // Return same value
+ return in;
+ }
+ };
+
+ adaptValue( type, value, la );
+ }
+
+ public void findResources( Binding binding, Object value, final Collection<Long> result) throws AccessorConstructionException, AccessorException
+ {
+ LongAdapter la = new LongAdapter() {
+ @Override
+ public long adapt(long in) {
+ result.add(in);
+ // Return same value
+ return in;
+ }
+ };
+
+ adaptValue( binding, value, la );
+ }
+
+ /**
+ * Add type to the util.
+ * @param type
+ * @return
+ */
+ public Item addType( Datatype type )
+ {
+ Item i = items.get( type );
+ if ( i==null ) {
+ i = createItem(type);
+ items.put(type, i);
+ }
+ return i;
+ }
+
+ public void adaptValue( Datatype type, byte[] value, LongAdapter adapter ) throws AccessorException
+ {
+ Item i = addType( type );
+ if (!i.mayHaveResource()) return;
+ try {
+ Accessor a = Accessors.getAccessor(value, type);
+ adaptValue(i, a, adapter);
+ } catch (AccessorConstructionException e) {
+ throw new AccessorException(e);
+ }
+ }
+
+ public boolean mayHaveResource( Datatype type ) {
+ Item i = addType( type );
+ return i.mayHaveResource();
+ }
+
+ public void adaptValue( Binding binding, Object value, LongAdapter adapter ) throws AccessorException
+ {
+ Item i = addType( binding.type() );
+ if (!i.mayHaveResource()) return;
+ try {
+ Accessor a = Accessors.getAccessor(binding, value);
+ adaptValue(i, a, adapter);
+ } catch (AccessorConstructionException e) {
+ throw new AccessorException(e);
+ }
+ }
+
+ void adaptValue( Item i, Accessor a, LongAdapter adapter ) throws AccessorException, AccessorConstructionException
+ {
+ if ( i.resources != null ) {
+ for (ChildReference r : i.resources)
+ {
+ adaptValue(a, r, adapter);
+ }
+ }
+ if ( i.variants != null ) {
+ for (ChildReference r : i.variants)
+ {
+ adaptValue(a, r, adapter);
+ }
+ }
+ }
+
+ void adaptValue( Accessor a, ChildReference r, LongAdapter adapter ) throws AccessorException, AccessorConstructionException
+ {
+ if ( a instanceof LongAccessor ) {
+ LongAccessor x = (LongAccessor) a;
+ long value = x.getValue();
+ long newValue = adapter.adapt( value );
+ if ( newValue != value ) x.setValue( newValue );
+ }
+
+ if ( a instanceof VariantAccessor ) {
+ VariantAccessor x = (VariantAccessor) a;
+ Item i = createItem( x.getContentType() );
+ adaptValue(i, x.getContentAccessor(), adapter);
+ }
+
+ if ( a instanceof MapAccessor ) {
+ MapAccessor x = (MapAccessor) a;
+ if (r instanceof IndexReference) {
+ IndexReference ir = (IndexReference) r;
+ // Resource is in the Key
+ if (ir.index==0) {
+ // Read the key as whole
+ Binding keyBinding = Bindings.getBinding( x.type().keyType );
+ Binding valueBinding = Bindings.getBinding( x.type().valueType );
+ Object[] keys = x.getKeys(keyBinding);
+ for ( Object key : keys ) {
+ Object value = x.get(keyBinding, key, valueBinding);
+ // Fix the key
+ Accessor ka = Accessors.getAccessor(keyBinding, key);
+ adaptValue(ka, r.childReference, adapter);
+
+ // Write
+ x.remove(keyBinding, key);
+ x.put(keyBinding, key, valueBinding, value);
+ }
+ }
+
+ // Resource is in the value
+ if (ir.index==1) {
+ Binding keyBinding = Bindings.getBinding( x.type().keyType );
+ Object[] keys = x.getKeys(keyBinding);
+ for ( Object key : keys ) {
+ Accessor va = x.getValueAccessor(keyBinding, key);
+ adaptValue(va, r.childReference, adapter);
+ }
+ }
+ }
+ }
+
+ if ( a instanceof ArrayAccessor ) {
+ ArrayAccessor x = (ArrayAccessor) a;
+ int len = x.size();
+ for (int i=0; i<len; i++) {
+ Accessor sa = x.getAccessor(i);
+ adaptValue(sa, r.childReference, adapter);
+ }
+ }
+
+ if ( a instanceof UnionAccessor ) {
+ UnionAccessor x = (UnionAccessor) a;
+ IndexReference ir = (IndexReference) r;
+ if ( x.getTag() == ir.index ) {
+ Accessor sa = x.getComponentAccessor();
+ adaptValue(sa, ir.childReference, adapter);
+ }
+ }
+
+ if ( a instanceof RecordAccessor ) {
+ RecordAccessor x = (RecordAccessor) a;
+ IndexReference ir = (IndexReference) r;
+ Accessor sa = x.getFieldAccessor(ir.index);
+ adaptValue(sa, ir.childReference, adapter);
+ }
+
+ if ( a instanceof OptionalAccessor ) {
+ OptionalAccessor x = (OptionalAccessor) a;
+ if (x.hasValue()) {
+ Accessor sa = x.getComponentAccessor();
+ adaptValue(sa, r.childReference, adapter);
+ }
+ }
+
+ }
+
+ public interface LongAdapter {
+ long adapt(long in);
+ }
+
+ public static class Item {
+ // The datatype
+ public Datatype type;
+ // Index of the type
+ public int index;
+ // Locations of variants in Datatype
+ List<ChildReference> variants;
+ // Locations of resources in Datatype
+ List<ChildReference> resources;
+
+ public boolean mayHaveResource() {
+ return (variants!=null&&!variants.isEmpty()) ||
+ (resources!=null&&!resources.isEmpty());
+ }
+
+ void addVariant(ChildReference ref) {
+ if ( variants == null ) variants = new ArrayList<ChildReference>();
+ variants.add(ref);
+ }
+
+ void addResource(ChildReference ref) {
+ if ( resources == null ) resources = new ArrayList<ChildReference>();
+ resources.add( ref );
+ }
+ }
+
+ static {
+ RESOURCE_TYPE = new LongType();
+ RESOURCE_TYPE.metadata.put("resource", "true");
+ }
+
+ /**
+ * This visitor makes a quick peek to see if there is resource or variants.
+ */
+ static class HasResVisitor extends DatatypeVisitorAdapter {
+
+ boolean hasRes = false, hasVariant = false;
+
+ @Override
+ public void visit(VariantType b, Object obj) {
+ hasVariant = true;
+ }
+
+ @Override
+ public void visit(LongType b, Object obj) {
+ String s = b.metadata.get("unit");
+ hasRes |= s!=null && s.equals("resource");
+ }
+
+ }
+
+ static class GetRefsVisitor extends DatatypeVisitorAdapter {
+
+ Stack<ChildReference> stack = new Stack<ChildReference>();
+
+ @Override
+ public void visit(ArrayType b, Object obj) {
+ if ( !visited.add(b) ) return;
+
+ ComponentReference r = new ComponentReference();
+ stack.push(r);
+ b.componentType.accept(this, obj);
+ stack.pop();
+ }
+
+ @Override
+ public void visit(LongType b, Object obj) {
+ String s = b.metadata.get("unit");
+ boolean isRes = s!=null && s.equals("resource");
+ if ( isRes ) {
+ Item item = (Item) obj;
+ item.addResource( toRef() );
+ }
+ }
+ @Override
+ public void visit(MapType b, Object obj) {
+ if ( !visited.add(b) ) return;
+
+ IndexReference r = new IndexReference(0);
+ stack.push(r);
+ b.keyType.accept(this, obj);
+ stack.pop();
+ r.index = 1;
+ stack.push(r);
+ b.valueType.accept(this, obj);
+ stack.pop();
+ }
+ @Override
+ public void visit(OptionalType b, Object obj) {
+ if ( !visited.add(b) ) return;
+
+ ComponentReference r = new ComponentReference();
+ stack.push(r);
+ b.componentType.accept(this, obj);
+ stack.pop();
+ }
+ @Override
+ public void visit(RecordType b, Object obj) {
+ if ( !visited.add(b) ) return;
+
+ IndexReference r = new IndexReference(0);
+ stack.push(r);
+ for (int i=0; i<b.getComponentCount(); i++) {
+ r.index = i;
+ b.getComponent(i).type.accept(this, obj);
+ }
+ stack.pop();
+ }
+ @Override
+ public void visit(UnionType b, Object obj) {
+ if ( !visited.add(b) ) return;
+
+ IndexReference r = new IndexReference(0);
+ stack.push(r);
+ for (int i=0; i<b.getComponentCount(); i++) {
+ r.index = i;
+ b.getComponent(i).type.accept(this, obj);
+ }
+ stack.pop();
+ }
+ @Override
+ public void visit(VariantType b, Object obj) {
+ Item item = (Item) obj;
+ item.addVariant( toRef() );
+ }
+ ChildReference toRef() {
+ return ChildReference.compile(stack);
+ }
+
+ }
+
+
+}