Package com.redhat.ceylon.compiler.loader

Source Code of com.redhat.ceylon.compiler.loader.MetamodelGenerator

package com.redhat.ceylon.compiler.loader;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import com.redhat.ceylon.common.Versions;
import com.redhat.ceylon.compiler.js.TypeUtils;
import com.redhat.ceylon.compiler.typechecker.model.Annotation;
import com.redhat.ceylon.compiler.typechecker.model.Declaration;
import com.redhat.ceylon.compiler.typechecker.model.DeclarationKind;
import com.redhat.ceylon.compiler.typechecker.model.Interface;
import com.redhat.ceylon.compiler.typechecker.model.IntersectionType;
import com.redhat.ceylon.compiler.typechecker.model.Method;
import com.redhat.ceylon.compiler.typechecker.model.MethodOrValue;
import com.redhat.ceylon.compiler.typechecker.model.Module;
import com.redhat.ceylon.compiler.typechecker.model.ModuleImport;
import com.redhat.ceylon.compiler.typechecker.model.Parameter;
import com.redhat.ceylon.compiler.typechecker.model.ParameterList;
import com.redhat.ceylon.compiler.typechecker.model.ProducedType;
import com.redhat.ceylon.compiler.typechecker.model.SiteVariance;
import com.redhat.ceylon.compiler.typechecker.model.TypeAlias;
import com.redhat.ceylon.compiler.typechecker.model.TypeDeclaration;
import com.redhat.ceylon.compiler.typechecker.model.TypeParameter;
import com.redhat.ceylon.compiler.typechecker.model.UnionType;
import com.redhat.ceylon.compiler.typechecker.model.Util;
import com.redhat.ceylon.compiler.typechecker.model.Value;

/** Generates the metamodel for all objects in a module.
* This is used by the MetamodelVisitor.
*
* @author Enrique Zamudio
*/
public class MetamodelGenerator {

    public static final String KEY_CLASSES      = "$c";
    public static final String KEY_INTERFACES   = "$i";
    public static final String KEY_OBJECTS      = "$o";
    public static final String KEY_METHODS      = "$m";
    public static final String KEY_ATTRIBUTES   = "$at";
    public static final String KEY_ANNOTATIONS  = "an";
    public static final String KEY_PACKED_ANNS  = "pa";
    public static final String KEY_TYPE         = "$t";
    public static final String KEY_TYPES        = "l";
    public static final String KEY_TYPE_PARAMS  = "tp";
    public static final String KEY_METATYPE     = "mt";
    public static final String KEY_MODULE       = "md";
    public static final String KEY_NAME         = "nm";
    public static final String KEY_PACKAGE      = "pk";
    public static final String KEY_PARAMS       = "ps";
    public static final String KEY_SELF_TYPE    = "st";
    public static final String KEY_SATISFIES    = "sts";
    public static final String KEY_DS_VARIANCE  = "dv"; //declaration-site variance
    public static final String KEY_US_VARIANCE  = "uv"; //use-site variance

    public static final String KEY_DEFAULT      = "def";
    public static final String KEY_DYNAMIC      = "dyn";

    public static final String METATYPE_CLASS           = "c";
    public static final String METATYPE_INTERFACE       = "i";
    public static final String METATYPE_ALIAS           = "als";
    public static final String METATYPE_OBJECT          = "o";
    public static final String METATYPE_METHOD          = "m";
    public static final String METATYPE_ATTRIBUTE       = "a";
    public static final String METATYPE_GETTER          = "g";
    public static final String METATYPE_SETTER          = "s";
    public static final String METATYPE_TYPE_PARAMETER  = "tp";
    public static final String METATYPE_PARAMETER       = "prm";
    //DO NOT REARRANGE, only append
    public static final List<String> annotationBits = Arrays.asList("shared", "actual", "formal", "default",
            "sealed", "final", "native", "late", "abstract", "annotation", "variable");

    private final Map<String, Object> model = new HashMap<>();
    private static final Map<String,Object> unknownTypeMap = new HashMap<>();
    private final Module module;

    public MetamodelGenerator(Module module) {
        this.module = module;
        model.put("$mod-name", module.getNameAsString());
        model.put("$mod-version", module.getVersion());
        model.put("$mod-bin", Versions.JS_BINARY_MAJOR_VERSION+"."+Versions.JS_BINARY_MINOR_VERSION);
        if (!module.getImports().isEmpty()) {
            ArrayList<Object> imps = new ArrayList<>(module.getImports().size());
            for (ModuleImport mi : module.getImports()) {
                if (mi.getModule().getVersion() == null) { //#416
                    continue;
                }
                String impath = String.format("%s/%s", mi.getModule().getNameAsString(), mi.getModule().getVersion());
                if (mi.isOptional() || mi.isExport()) {
                    Map<String,Object> optimp = new HashMap<>(3);
                    optimp.put("path",impath);
                    if (mi.isOptional()) {
                        optimp.put("opt",1);
                    }
                    if (mi.isExport()) {
                        optimp.put("exp", 1);
                    }
                    imps.add(optimp);
                } else {
                    imps.add(impath);
                }
            }
            model.put("$mod-deps", imps);
        }
        if (unknownTypeMap.isEmpty()) {
            unknownTypeMap.put(KEY_NAME, "$U");
        }
    }

    /** Returns the in-memory model as a collection of maps.
     * The top-level map represents the module. */
    public Map<String, Object> getModel() {
        return Collections.unmodifiableMap(model);
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> findParent(Declaration d) {
        Map<String,Object> pkgmap = getPackageMap(d.getUnit().getPackage());
        if (d.isToplevel()) {
            return pkgmap;
        }
        List<String> names = TypeUtils.generateModelPath(Util.getContainingDeclaration(d));
        names.remove(0); //we don't need the package key
        Map<String, Object> last = pkgmap;
        for (String name : names) {
            if (name.startsWith("anonymous#"))continue;
            if (last == null) {
                break;
            }
            Map<String,Object> sub = (Map<String,Object>)last.get(name);
            if (sub == null && name.charAt(0)=='$') {
                sub = new HashMap<>();
                last.put(name, sub);
            }
            last = sub;
        }
        return last;
    }

    /** Create a map for the specified ProducedType.
     * Includes name, package, module and type parameters, unless it's a union or intersection
     * type, in which case it contains a "comp" key with an "i" or "u" and a key "types" with
     * the list of types that compose it. */
    private Map<String, Object> typeMap(ProducedType pt, Declaration from) {
        if (pt==null || pt.isUnknown()) {
            return unknownTypeMap;
        }
        TypeDeclaration d = pt.getDeclaration();
        Map<String, Object> m = new HashMap<>();
        if (d instanceof UnionType || d instanceof IntersectionType) {
            List<ProducedType> subtipos = d instanceof UnionType ? d.getCaseTypes() : d.getSatisfiedTypes();
            List<Map<String,Object>> subs = new ArrayList<>(subtipos.size());
            for (ProducedType sub : subtipos) {
                subs.add(typeMap(sub, from));
            }
            m.put("comp", d instanceof UnionType ? "u" : "i");
            m.put(KEY_TYPES, subs);
            return m;
        }
        if (d.isToplevel() || d instanceof TypeParameter) {
            m.put(KEY_NAME, d.getName());
        } else {
            String qn = d.getQualifiedNameString();
            int p0 = qn.indexOf("::");
            if (p0>=0) {
                qn = qn.substring(p0+2);
            }
            p0 = qn.indexOf('.');
            if (p0 >= 0) {
                StringBuilder nestedName = new StringBuilder(TypeUtils.modelName(d));
                Declaration pd = Util.getContainingDeclaration(d);
                while (pd != null) {
                    nestedName.insert(0, '.');
                    nestedName.insert(0, TypeUtils.modelName(pd));
                    pd = Util.getContainingDeclaration(pd);
                }
                qn = nestedName.toString();
            }
            m.put(KEY_NAME, qn);
        }
        if (d.getDeclarationKind()==DeclarationKind.TYPE_PARAMETER) {
            //For types that reference type parameters, we're done
            return m;
        }
        com.redhat.ceylon.compiler.typechecker.model.Package pkg = d.getUnit().getPackage();
        if (pkg == null || pkg.equals(from.getUnit().getPackage())) {
            addPackage(m, ".");
        } else {
            addPackage(m, pkg.getNameAsString());
        }
        if (pkg != null && !pkg.getModule().equals(module)) {
            final String modname = pkg.getModule().getNameAsString();
            m.put(KEY_MODULE, Module.LANGUAGE_MODULE_NAME.equals(modname)?"$":modname);
        }
        putTypeParameters(m, pt, from);
        return m;
    }

    /** Returns a map with the same info as {@link #typeParameterMap(ProducedType)} but with
     * an additional key {@value #KEY_DS_VARIANCE} if it's covariant ("out") or contravariant ("in"). */
    private Map<String, Object> typeParameterMap(TypeParameter tp, Declaration from) {
        Map<String, Object> map = new HashMap<>();
        map.put(MetamodelGenerator.KEY_NAME, tp.getName());
        if (tp.isCovariant()) {
            map.put(KEY_DS_VARIANCE, "out");
        } else if (tp.isContravariant()) {
            map.put(KEY_DS_VARIANCE, "in");
        }
        if (tp.getSelfType() != null) {
            map.put(KEY_SELF_TYPE, typeMap(tp.getSelfType(), from));
        }
        if (tp.getSatisfiedTypes() != null && !tp.getSatisfiedTypes().isEmpty()) {
            encodeTypes(tp.getSatisfiedTypes(), map, KEY_SATISFIES, from);
        } else if (tp.getCaseTypes() != null && !tp.getCaseTypes().isEmpty()) {
            encodeTypes(tp.getCaseTypes(), map, "of", from);
        }
        if (tp.getDefaultTypeArgument() != null) {
            map.put(KEY_DEFAULT, typeMap(tp.getDefaultTypeArgument(), from));
        }
        return map;
    }

    /** Create a map for the ProducedType, as a type parameter.
     * Includes name, package, module and type parameters, unless it's a union or intersection
     * type, in which case it will contain a "comp" key with an "i" or "u", and a list of the types
     * that compose it. */
    private Map<String, Object> typeParameterMap(ProducedType pt, Declaration from) {
        if (pt == null)return null;
        final Map<String, Object> m = new HashMap<>();
        final TypeDeclaration d = pt.getDeclaration();
        m.put(KEY_METATYPE, METATYPE_TYPE_PARAMETER);
        if (d instanceof UnionType || d instanceof IntersectionType) {
            List<ProducedType> subtipos = d instanceof UnionType ? d.getCaseTypes() : d.getSatisfiedTypes();
            List<Map<String,Object>> subs = new ArrayList<>(subtipos.size());
            for (ProducedType sub : subtipos) {
                subs.add(typeMap(sub, from));
            }
            m.put("comp", d instanceof UnionType ? "u" : "i");
            m.put(KEY_TYPES, subs);
            return m;
        }
        m.put(KEY_NAME, d.getName());
        if (d.getDeclarationKind()==DeclarationKind.TYPE_PARAMETER) {
            //Don't add package, etc
            return m;
        }
        com.redhat.ceylon.compiler.typechecker.model.Package pkg = d.getUnit().getPackage();
        if (pkg.equals(from.getUnit().getPackage())) {
            addPackage(m, ".");
        } else {
            addPackage(m, pkg.getNameAsString());
        }
        if (!pkg.getModule().equals(module)) {
            final String modname = d.getUnit().getPackage().getModule().getNameAsString();
            m.put(KEY_MODULE, Module.LANGUAGE_MODULE_NAME.equals(modname)?"$":modname);
        }
        putTypeParameters(m, pt, from);
        return m;
    }

    private void putTypeParameters(Map<String, Object> container, ProducedType pt, Declaration from) {
        if (pt.getTypeArgumentList() != null && !pt.getTypeArgumentList().isEmpty()) {
            final List<Map<String, Object>> list = new ArrayList<>(pt.getTypeArgumentList().size());
            final Map<TypeParameter, SiteVariance> usv = pt.getVarianceOverrides();
            final Iterator<TypeParameter> typeParameters = usv == null || usv.isEmpty() ?
                    null : pt.getDeclaration().getTypeParameters().iterator();
            for (ProducedType targ : pt.getTypeArgumentList()) {
                final Map<String, Object> tpmap = typeParameterMap(targ, from);
                final TypeParameter typeParam = typeParameters == null ? null : typeParameters.next();
                final SiteVariance variance = typeParam == null ? null : usv.get(typeParam);
                if (variance != null) {
                    tpmap.put(MetamodelGenerator.KEY_US_VARIANCE, variance.ordinal());
                }
                list.add(tpmap);
            }
            container.put(KEY_TYPE_PARAMS, list);
        }
    }

    /** Create a list of maps from the list of type parameters.
     * @see #typeParameterMap(TypeParameter) */
    private List<Map<String, Object>> typeParameters(List<TypeParameter> tpl, Declaration from) {
        if (tpl != null && !tpl.isEmpty()) {
            List<Map<String, Object>> l = new ArrayList<>(tpl.size());
            for (TypeParameter tp : tpl) {
                l.add(typeParameterMap(tp, from));
            }
            return l;
        }
        return null;
    }

    /** Create a list of maps for the parameter list. Each map will be a parameter, including
     * name, type, default value (if any), and whether it's sequenced. */
    private List<Map<String,Object>> parameterListMap(ParameterList plist, Declaration from) {
        List<Parameter> parms = plist.getParameters();
        if (parms.size() > 0) {
            List<Map<String,Object>> p = new ArrayList<>(parms.size());
            for (Parameter parm : parms) {
                Map<String, Object> pm = new HashMap<>();
                pm.put(KEY_NAME, parm.getName());
                pm.put(KEY_METATYPE, METATYPE_PARAMETER);
                if (parm.isSequenced()) {
                    pm.put("seq", 1);
                }
                if (parm.isDefaulted()) {
                    pm.put(KEY_DEFAULT, 1);
                }
                if (parm.isAtLeastOne()) {
                    pm.put("$min1", 1);
                }
                final MethodOrValue parmtype = parm.getModel();
                if (parmtype != null && parmtype.getDeclarationKind()==DeclarationKind.TYPE_PARAMETER) {
                    pm.put(KEY_TYPE, parmtype.getName());
                } else {
                    pm.put(KEY_TYPE, typeMap(parm.getType(), from));
                }
                if (parm.isHidden()) {
                    pm.put("$hdn", 1);
                }
                if (parmtype instanceof Method) {
                    pm.put("$pt", "f");
                    List<List<Map<String, Object>>> _paramLists = new ArrayList<>(
                            ((Method)parmtype).getParameterLists().size());
                    for (ParameterList subplist : ((Method)parmtype).getParameterLists()) {
                        List<Map<String,Object>> params = parameterListMap(subplist, from);
                        if (params == null) {
                            params = Collections.emptyList();
                        }
                        _paramLists.add(params);
                    }
                    if (_paramLists.size() > 1 || !_paramLists.get(0).isEmpty()) {
                        pm.put(KEY_PARAMS, _paramLists);
                    }
                }
                //TODO do these guys need anything else?
                /*if (parm.getDefaultArgument() != null) {
                    //This could be compiled to JS...
                    pm.put(ANN_DEFAULT, parm.getDefaultArgument().getSpecifierExpression().getExpression().getTerm().getText());
                }*/
                encodeAnnotations(parm.getModel(), pm);
                p.add(pm);
            }
            return p;
        }
        return null;
    }

    @SuppressWarnings("unchecked")
    public Map<String,Object> encodeMethod(Method d) {
        final Map<String, Object> m = new HashMap<>();
        m.put(KEY_METATYPE, METATYPE_METHOD);
        m.put(KEY_NAME, d.getName());
        List<Map<String, Object>> tpl = typeParameters(d.getTypeParameters(), d);
        if (tpl != null) {
            m.put(KEY_TYPE_PARAMS, tpl);
        }
        m.put(KEY_TYPE, typeMap(d.getType(), d));
        List<List<Map<String, Object>>> paramLists = new ArrayList<>(d.getParameterLists().size());
        for (ParameterList plist : d.getParameterLists()) {
            List<Map<String,Object>> params = parameterListMap(plist, d);
            if (params == null) {
                params = Collections.emptyList();
            }
            paramLists.add(params);
        }
        if (paramLists.size() > 1 || !paramLists.get(0).isEmpty()) {
            m.put(KEY_PARAMS, paramLists);
        }

        //Annotations
        encodeAnnotations(d, m);
        Map<String, Object> parent= findParent(d);
        if (parent != null) {
            if (!d.isToplevel()) {
                if (!parent.containsKey(KEY_METHODS)) {
                    parent.put(KEY_METHODS, new HashMap<>());
                }
                parent = (Map<String, Object>)parent.get(KEY_METHODS);
            }
            if (parent != null) {
                parent.put(TypeUtils.modelName(d), m);
            }
        }
        return m;
    }

    @SuppressWarnings("unchecked")
    public Map<String,Object> encodeClass(com.redhat.ceylon.compiler.typechecker.model.Class d) {
        final Map<String, Object> m = new HashMap<>();
        m.put(KEY_METATYPE, METATYPE_CLASS);
        m.put(KEY_NAME, TypeUtils.modelName(d));

        //Type parameters
        List<Map<String, Object>> tpl = typeParameters(d.getTypeParameters(), d);
        if (tpl != null) {
            m.put(KEY_TYPE_PARAMS, tpl);
        }
        //self type
        if (d.getSelfType() != null) {
            m.put(KEY_SELF_TYPE, typeMap(d.getSelfType(), d));
        }

        //Extends
        if (d.getExtendedType() != null) {
            m.put("super", typeMap(d.getExtendedType(), d));
        }
        //Satisfies
        encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);

        //Initializer parameters
        final List<Map<String,Object>> inits = parameterListMap(d.getParameterList(), d);
        if (inits != null && !inits.isEmpty()) {
            m.put(KEY_PARAMS, inits);
        }
        //Case types
        encodeTypes(d.getCaseTypes(), m, "of", d);

        //Annotations
        encodeAnnotations(d, m);
        if (d.isAnonymous()) {
            m.put("$anon", 1);
        }
        if (d.isAlias()) {
            m.put("$alias", 1);
        }
        Map<String, Object> parent = findParent(d);
        if (parent != null) {
            if (!d.isToplevel() || d.isMember()) {
                if (!parent.containsKey(KEY_CLASSES)) {
                    parent.put(KEY_CLASSES, new HashMap<>());
                }
                parent = (Map<String,Object>)parent.get(KEY_CLASSES);
            }
            parent.put(TypeUtils.modelName(d), m);
        }
        return m;
    }

    @SuppressWarnings("unchecked")
    public Map<String,Object> encodeInterface(Interface d) {
        final Map<String, Object> m = new HashMap<>();
        m.put(KEY_METATYPE, METATYPE_INTERFACE);
        m.put(KEY_NAME, d.getName());

        //Type parameters
        List<Map<String, Object>> tpl = typeParameters(d.getTypeParameters(), d);
        if (tpl != null) {
            m.put(KEY_TYPE_PARAMS, tpl);
        }
        //self type
        if (d.getSelfType() != null) {
            m.put(KEY_SELF_TYPE, d.getSelfType().getDeclaration().getName());
        }
        if (d.isDynamic()) {
            m.put(KEY_DYNAMIC, 1);
        }
        //satisfies
        encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);
        //Case types
        encodeTypes(d.getCaseTypes(), m, "of", d);
        //Annotations
        encodeAnnotations(d, m);
        if (d.isAlias()) {
            m.put("$alias", typeMap(d.getExtendedType(), d));
        }
        Map<String, Object> parent = findParent(d);
        if (parent != null) {
            if (!d.isToplevel() || d.isMember()) {
                if (!parent.containsKey(KEY_INTERFACES)) {
                    parent.put(KEY_INTERFACES, new HashMap<>());
                }
                parent = (Map<String,Object>)parent.get(KEY_INTERFACES);
            }
            parent.put(TypeUtils.modelName(d), m);
        }
        return m;
    }

    @SuppressWarnings("unchecked")
    public void encodeObject(Value d) {
        Map<String, Object> parent = findParent(d);
        if (!d.isToplevel()) {
            if (!parent.containsKey(KEY_OBJECTS)) {
                parent.put(KEY_OBJECTS, new HashMap<>());
            }
            parent = (Map<String,Object>)parent.get(KEY_OBJECTS);
        }
        Map<String, Object> m = new HashMap<>();
        m.put(KEY_METATYPE, METATYPE_OBJECT);
        m.put(KEY_NAME, d.getName());
        //Extends
        m.put("super", typeMap(d.getTypeDeclaration().getExtendedType(), d));
        //Satisfies
        encodeTypes(d.getTypeDeclaration().getSatisfiedTypes(), m, KEY_SATISFIES, d);

        //Certain annotations
        encodeAnnotations(d, m);
        parent.put(TypeUtils.modelName(d.getTypeDeclaration()), m);
    }

    @SuppressWarnings("unchecked")
    public Map<String, Object> encodeAttributeOrGetter(MethodOrValue d) {
        Map<String, Object> m = new HashMap<>();
        Map<String, Object> parent;
        final String mname = TypeUtils.modelName(d);
        if (d.isToplevel() || d.isMember() || containsTypes(d)) {
            parent = findParent(d);
            if (parent == null) {
                return null;
            }
            if (!d.isToplevel()) {
                final String _k = KEY_ATTRIBUTES;
                if (!parent.containsKey(_k)) {
                    parent.put(_k, new HashMap<>());
                }
                parent = (Map<String,Object>)parent.get(_k);
            }
            if (parent.containsKey(mname)) {
                //merge existing
                m = (Map<String, Object>)parent.get(mname);
            }
        } else {
            //Ignore attributes inside control blocks, methods, etc.
            return null;
        }
        m.put(KEY_NAME, d.getName());
        m.put(KEY_METATYPE, (d instanceof Value && ((Value)d).isTransient()) ? METATYPE_GETTER : METATYPE_ATTRIBUTE);
        m.put(KEY_TYPE, typeMap(d.getType(), d));
        parent.put(mname, m);
        encodeAnnotations(d, m);
        if (d instanceof Value && ((Value) d).getSetter() != null) {
            Map<String,Object> smap = (Map<String,Object>)m.get("$set");
            if (smap==null) {
                smap = new HashMap<>();
                m.put("$set", smap);
                smap.put(KEY_METATYPE, METATYPE_SETTER);
                encodeAnnotations(((Value)d).getSetter(), smap);
            }
        }
        return m;
    }

    @SuppressWarnings("unchecked")
    public Map<String, Object> encodeTypeAlias(TypeAlias d) {
        Map<String, Object> parent;
        if (d.isToplevel() || d.isMember()) {
            parent = findParent(d);
            if (parent == null) {
                return null;
            }
            if (!d.isToplevel()) {
                if (!parent.containsKey(KEY_ATTRIBUTES)) {
                    parent.put(KEY_ATTRIBUTES, new HashMap<>());
                }
                parent = (Map<String,Object>)parent.get(KEY_ATTRIBUTES);
            }
        } else {
            //Ignore attributes inside control blocks, methods, etc.
            return null;
        }
        Map<String, Object> m = new HashMap<>();
        m.put(KEY_METATYPE, METATYPE_ALIAS);
        m.put(KEY_NAME, d.getName());
        List<Map<String, Object>> tpl = typeParameters(d.getTypeParameters(), d);
        if (tpl != null) {
            m.put(KEY_TYPE_PARAMS, tpl);
        }
        if (d.getSelfType() != null) {
            m.put(KEY_SELF_TYPE, typeMap(d.getSelfType(), d));
        }
        m.put("$alias", typeMap(d.getExtendedType(), d));
        encodeTypes(d.getCaseTypes(), m, "of", d);
        encodeTypes(d.getSatisfiedTypes(), m, KEY_SATISFIES, d);
        encodeAnnotations(d, m);
        parent.put(TypeUtils.modelName(d), m);
        return m;
    }

    /** Encodes the list of types and puts them under the specified key in the map. */
    private void encodeTypes(List<ProducedType> types, Map<String,Object> m, String key, Declaration from) {
        if (types == null || types.isEmpty()) return;
        List<Map<String, Object>> sats = new ArrayList<>(types.size());
        for (ProducedType st : types) {
            sats.add(typeMap(st, from));
        }
        m.put(key, sats);
    }

    /** Encodes all annotations as a map which is then stored under the
     * {@link #KEY_ANNOTATIONS} key in the specified map.
     * If the map is null, only the bitset annotations are calculated and returned.
     * @return The bitmask for the bitset annotations. */
    public static int encodeAnnotations(Declaration d, Map<String, Object> m) {
        HashMap<String, Object> anns = m == null ? null : new HashMap<String, Object>();
        int bits = 0;
        for (Annotation a : d.getAnnotations()) {
            String name = a.getName();
            int idx = annotationBits.indexOf(name);
            if (idx >= 0) {
                bits |= (1 << idx);
            } else if (anns != null) {
                List<String> args = a.getPositionalArguments();
                if (args == null) {
                    args = Collections.emptyList();
                }
                anns.put(name, args);
            }
        }
        if (d instanceof Value && ((Value)d).isVariable()) {
            //Sometimes the value is not annotated, it only has a defined Setter
            bits |= (1 << annotationBits.indexOf("variable"));
        }
        if (bits > 0 && m != null) {
            m.put(KEY_PACKED_ANNS, bits);
        }
        if (anns != null && m != null && !anns.isEmpty()) {
            m.put(KEY_ANNOTATIONS, anns);
        }
        return bits;
    }

    private void addPackage(final Map<String,Object> map, final String pkgName) {
        if (pkgName.equals(Module.LANGUAGE_MODULE_NAME)) {
            map.put(KEY_PACKAGE, "$");
        } else {
            map.put(KEY_PACKAGE, pkgName);
        }
    }

    public boolean containsTypes(Declaration d) {
        for (Declaration m : d.getMembers()) {
            if (m instanceof Value && ((Value)m).getTypeDeclaration().isAnonymous())return true;
            if (m instanceof TypeDeclaration || containsTypes(m)) {
                return true;
            }
        }
        return false;
    }

    public Map<String,Object> getPackageMap(com.redhat.ceylon.compiler.typechecker.model.Package p) {
        @SuppressWarnings("unchecked")
        Map<String,Object> pkgmap = (Map<String,Object>)model.get(p.getNameAsString());
        if (pkgmap == null) {
            pkgmap = new HashMap<>();
            if (p.isShared()) {
                pkgmap.put("$pkg-shared", 1);
            }
            model.put(p.getNameAsString(), pkgmap);
        }
        return pkgmap;
    }

}
TOP

Related Classes of com.redhat.ceylon.compiler.loader.MetamodelGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.