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

org.modelcc.language.syntax.ObjectWrapper Maven / Gradle / Ivy

Go to download

ModelCC is a model-based parser generator (a.k.a. compiler compiler) that decouples language specification from language processing, avoiding some of the problems caused by grammar-driven parser generators. ModelCC receives a conceptual model as input, along with constraints that annotate it. It is then able to create a parser for the desired textual language and the generated parser fully automates the instantiation of the language conceptual model. ModelCC also includes a built-in reference resolution mechanism that results in abstract syntax graphs, rather than mere abstract syntax trees.

The newest version!
/*
 * ModelCC, distributed under ModelCC Shared Software License, www.modelcc.org
 */

package org.modelcc.language.syntax;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.modelcc.io.java.Reflection;
import org.modelcc.language.metamodel.MemberCollection;
import org.modelcc.language.metamodel.CompositeLanguageElement;
import org.modelcc.language.metamodel.LanguageModel;
import org.modelcc.language.metamodel.LanguageElement;
import org.modelcc.language.metamodel.LanguageMember;

/**
 * Object Wrapper.
 * 
 * @author Luis Quesada ([email protected]) & Fernando Berzal ([email protected])
 */
public class ObjectWrapper implements Serializable 
{    
    /**
     * Wrapped object.
     */
    private Object o;
    
    /**
     * Track used for basic elements.
     */
    private Object track;
    
    /**
     * The model.
     */
    private LanguageModel m;
    
    /**
     * Key
     */
    private boolean key;
    
    /**
     * Hash code
     */
    private int hash;
    
    /**
     * The map.
     */
    private Map mymap;


    /**
     * Constructor
     * @param o the object
     * @param m the model.
     * @param track used for basic elements. 
     */
    public ObjectWrapper(Object o, LanguageModel m, Object track) 
    {
        this.o = o;
        this.m = m;
        this.track = track;
        this.hash = track.hashCode();
        this.mymap = new HashMap();
        this.mymap.put(o, (this));
    }
    
    /**
     * Constructor
     * @param o the object
     * @param m the model.
     * @param hash the hash code.
     * @param mymap my mappings. 
     */
    protected ObjectWrapper (Object o, LanguageModel m, int hash, Map mymap, boolean key) 
    {
        this.o = o;
        this.m = m;
        this.hash = hash;
        this.key = key;
        this.mymap = mymap;
    }


    /**
     * Element members
     * @param cme Composite element
     * @param key is key?
     * @return key members when key is true, all members when key is false
     */
    private static List getMembers (CompositeLanguageElement cme, boolean key)
    {
    	if (key)
    		return cme.getKeyMembers();
		else
			return cme.getMembers();
    }
    
    /**
     * Gets a ObjectWrapper
     * @param o the object to wrap
     * @param m the model
     * @param map the object wrappers map.
     * @return the object wrapper.
     */
    public static ObjectWrapper createObjectWrapper(Object o,LanguageModel m,Map map) 
    {
        return createObjectWrapper(o,m,map,null,false);
    }

    /**
	 * Gets a KeyWrapper
	 * @param o the object to wrap
	 * @param m the model
	 * @param map the object wrappers map.
	 * @return the key wrapper.
	 */
	public static ObjectWrapper createKeyWrapper (Object o,LanguageModel m,Map map) 
	{
		return createObjectWrapper(o,m,map,null,true);
	} 
    
    /**
     * Gets a ObjectWrapper
     * @param o the object to wrap
     * @param m the model
     * @param map the object wrappers map.
     * @param added last added mappings.
     * @return the object wrapper.
     */
    private static ObjectWrapper createObjectWrapper (
    		Object o,
    		LanguageModel m,
    		Map map,
    		Map added, 
    		boolean key ) 
    {
        int hash = 0;
        
        ObjectWrapper kw = map.get(o);
        if (kw != null) {
            if (added != null) {
                added.putAll(kw.mymap);
            }
            return kw;
        }
        
        LanguageElement e = m.getClassToElement().get(o.getClass());
    	Map myadded = new HashMap();
        
        if (e instanceof CompositeLanguageElement) {
        	hash = hashComposite(o, m, map, key, myadded, (CompositeLanguageElement) e);
        } else {
        	hash = o.hashCode();        	
        }
        //System.err.println("LE "+e +"OBJ "+o+" "+o.getClass()+" hash="+hash);
    	        
        ObjectWrapper th = new ObjectWrapper(o, m, hash, myadded, key);

        map.put(o,th);
        if (added != null)
            added.putAll(myadded);
        
        return th;
    }

	private static int hashComposite(
			Object o, LanguageModel m,
			Map map, boolean key,
			Map myadded, CompositeLanguageElement me) 
	{
		int hash = 0;
		
		try {
			for (LanguageMember em: getMembers(me,key) ) {
				Field fld = Reflection.findField(me.getElementClass(),em.getID());
				fld.setAccessible(true);
				Object val = fld.get(o);
				if (val == null) {
					hash *= 53;
				} else {
					if (MemberCollection.class.isAssignableFrom(em.getClass())) {
						hash = hashCollection(m, map, myadded, (MemberCollection) em, val, hash);
					} else {
						ObjectWrapper ow = createObjectWrapper(val,m,map,myadded,key);
						map.put(val,ow);
						hash += val.toString().hashCode(); // vs. ow.hashCode();
						hash *= 53;
					}
				}
			}
		} catch (Exception ex) {
			Logger.getLogger(ObjectWrapper.class.getName()).log(Level.SEVERE, null, ex);
		}
		return hash;
	}

	private static int hashCollection(
			LanguageModel m, Map map, Map myadded,
			MemberCollection mem, Object val, int hash) 
	{
		switch (mem.getCollection()) {
		
		case ARRAY:
			Object[] array = (Object[])val;
			for (int j = 0;j < array.length;j++) {
				ObjectWrapper ow = createObjectWrapper(array[j],m,map,myadded,false);
				map.put(array[j],ow);
				hash += ow.hashCode();
				hash *= 53;
			}
			break;
		case LIST:
			List list = (List)val;
			for (int j = 0;j < list.size();j++) {
				ObjectWrapper ow = createObjectWrapper(list.get(j),m,map,myadded,false);
				map.put(list.get(j),ow);
				hash += ow.hashCode();
				hash *= 53;
			}
			break;
		case SET:
			Set dictionary = new HashSet();
			Set set = (Set)val;
			for (Object on: set) {
				ObjectWrapper ow = createObjectWrapper(on,m,map,myadded,false);
				map.put(on,ow);
				dictionary.add(ow);
			}
			for (ObjectWrapper w: dictionary) {
				hash += w.hashCode();
			}
			hash *= 53;
			break;
		}
		return hash;
	}
    
    
    // equals

    @Override
    public boolean equals(Object obj) 
    {
        if (obj == null) 
            return false;

        if (getClass() != obj.getClass()) 
            return false;

        ObjectWrapper other = (ObjectWrapper) obj;

        if (key != other.key)
        	return false;
        
        if (hashCode()!=other.hashCode()) 
            return false;
        
        LanguageElement me = m.getClassToElement().get(o.getClass());

        if (CompositeLanguageElement.class.isAssignableFrom(me.getClass())) {
            return equalsComposite(other);         
        } else {
            return track.equals(other.track);
        }
    }

    
	private boolean equalsComposite(ObjectWrapper other) 
	{
		CompositeLanguageElement cme = (CompositeLanguageElement) m.getClassToElement().get(o.getClass());
	
		try {
			
			for (LanguageMember em: getMembers(cme,key) ) {
				
		        Field fld = Reflection.findField(cme.getElementClass(),em.getID());
		        fld.setAccessible(true);
		        
		        Object val = fld.get(o);
		        Object val2 = fld.get(other.o);
		        
		        if (val == null && val2 == null) {
		        } else if (val != null && val2 == null) {
		            return false;
		        } else if (val == null && val2 != null) {
		            return false;
		        } else if (MemberCollection.class.isAssignableFrom(em.getClass())) {
		        	return equalsCollection(other, (MemberCollection) em, val, val2);
		        } else {
		        	return val.toString().equals(val2.toString());
		        }
		    }
		} catch (Exception ex) {
		    Logger.getLogger(ObjectWrapper.class.getName()).log(Level.SEVERE, null, ex);
		}
		
		return true;
	}
	
	
	private boolean equalsCollection (ObjectWrapper other, MemberCollection mem, Object val, Object val2)
	{
        Map mymap2 = other.mymap;
        
    	switch (mem.getCollection()) {
    	
    	case ARRAY:
    		Object[] array = (Object[])val;
    		Object[] array2 = (Object[])val2;
    		if (array.length!=array2.length)
    			return false;
    		for (int j=0; j set = (Set)val;
    		Set set2 = (Set)val2;
    		Set wrappers = new HashSet();
    		Set wrappers2 = new HashSet();
    		for (Object obj: set)
    			wrappers.add(createObjectWrapper(obj, m, mymap));
    		for (Object obj: set2)
    			wrappers2.add(createObjectWrapper(obj, m, mymap2));
    		if (wrappers.size()!=wrappers2.size())
    			return false;
    		for (Object obj: wrappers) {
    			if (!wrappers2.contains(obj))
    				return false;
    		}
    		break;
    	}	
    	
    	return true;
	}
	

    @Override
    public final int hashCode() 
    {
        return hash;
    }
    
    
    @Override
    public String toString ()
    {
    	return "Wrapper for "+(key?"KEY ":"")+o.getClass()+": "+o+" ("+track+") hash="+hash;
    }

}