]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/types/TypeAst.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / parsing / types / TypeAst.java
diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/types/TypeAst.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/parsing/types/TypeAst.java
new file mode 100644 (file)
index 0000000..aceb7fb
--- /dev/null
@@ -0,0 +1,181 @@
+package org.simantics.scl.compiler.internal.parsing.types;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
+import org.simantics.scl.compiler.elaboration.modules.TypeClass;
+import org.simantics.scl.compiler.environment.AmbiguousNameException;
+import org.simantics.scl.compiler.environment.Environments;
+import org.simantics.scl.compiler.internal.parsing.Symbol;
+import org.simantics.scl.compiler.internal.types.TypeElaborationContext;
+import org.simantics.scl.compiler.types.TCon;
+import org.simantics.scl.compiler.types.TPred;
+import org.simantics.scl.compiler.types.Type;
+import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
+import org.simantics.scl.compiler.types.kinds.Kind;
+import org.simantics.scl.compiler.types.kinds.Kinds;
+
+import gnu.trove.map.hash.TObjectIntHashMap;
+import gnu.trove.set.hash.TIntHashSet;
+
+
+/**
+ * This class is a common base class for type-related nodes in an SCL abstract syntax tree.
+ * sub-nodes of type nodes in the AST are restricted to the subclasses of this abstract base class.
+ */
+public abstract class TypeAst extends Symbol { 
+    public static final TypeAst[] EMPTY_ARRAY = new TypeAst[0];
+    
+    @Override
+    public String toString() {
+        StringBuilder b = new StringBuilder();
+        toString(b);
+        return b.toString();
+    }
+
+    /**
+     * Write a text representation of this node to a string builder.
+     * All sub-classes must override this abstract method instead of
+     * directly overriding the {@link #toString()} method. 
+     */
+    public abstract void toString(StringBuilder b);
+    
+    /**
+     * Write a text representation of this node, with parenthesis if demanded by the precedence.
+     * Literals that never need to be parenthesized can override this method directly.
+     */
+    public void toString(StringBuilder b, int outerPrecedence) {
+        if(getPrecedence() >= outerPrecedence) {
+            b.append('(');
+            toString(b);
+            b.append(')');
+        }
+        else
+            toString(b);
+    }
+    
+    /**
+     * Translate this node into a Type instance usinga TypeTranslationContext, with expected Kind.
+     */
+    public abstract Type toType(TypeTranslationContext context, Kind expectedKind);
+    
+    /**
+     * Elaborate this node into a Type using a TypeElaborationContext.
+     */
+    public abstract Type toType(TypeElaborationContext context);
+
+    /**
+     * Elaborate an array of type nodes into an array of Type instances.
+     */
+    public static Type[] toTypes(TypeElaborationContext context, TypeAst[] typeAsts) {
+        Type[] result = new Type[typeAsts.length];
+        for(int i=0;i<typeAsts.length;++i)
+            result[i] = typeAsts[i].toType(context);
+        return result;
+    }
+
+    /**
+     * Translate an array of type nodes into an array of Type instances, using Kinds.STAR is the expected kind.
+     */
+    public static Type[] toTypes(TypeTranslationContext context, TypeAst[] typeAsts) {
+        Type[] result = new Type[typeAsts.length];
+        for(int i=0;i<typeAsts.length;++i)
+            result[i] = typeAsts[i].toType(context, Kinds.STAR);
+        return result;
+    }
+
+    /**
+     * Get a TPred instance from this node as a type function application (a type class restriction).
+     */
+    public TPred toTFuncApply(TypeTranslationContext context) {
+        ArrayList<Type> parameters = new ArrayList<Type>();
+        ArrayList<Kind> parameterKinds = new ArrayList<Kind>();
+        TypeAst cur = this;
+        loop: while(true) {
+            if(cur instanceof TApplyAst) {
+                TApplyAst apply = (TApplyAst)cur;
+                for(int i=apply.parameters.length-1;i>=0;--i) {
+                    TypeAst parameter = apply.parameters[i];
+                    Kind kind = Kinds.metaVar();
+                    parameters.add(parameter.toType(context, kind));
+                    parameterKinds.add(kind);
+                }
+                cur = apply.function;
+            }
+            else if(cur instanceof TVarAst) {
+                TVarAst con = (TVarAst)cur;
+                Collections.reverse(parameters);
+                Collections.reverse(parameterKinds);
+                TCon typeClass;
+                try {
+                    typeClass = Environments.getTypeClassName(context.getEnvironment(), con.name);
+                } catch (AmbiguousNameException e1) {
+                    context.getErrorLog().log(con.location, e1.getMessage());
+                    break;
+                }
+                if(typeClass == null) {
+                    context.getErrorLog().log(con.location, "Unresolved type class " + con.name + ".");
+                    break;
+                }
+                TypeClass classDesc = context.getEnvironment().getTypeClass(typeClass);
+                if(classDesc.parameters.length != parameters.size()) {
+                    context.getErrorLog().log(location, "Wrong number of parameters. " + classDesc.parameters.length + " parameters were expected.");
+                    break;
+                }
+                for(int i=0;i<parameterKinds.size();++i)
+                    try {
+                        Kinds.unify(parameterKinds.get(i), classDesc.parameters[i].getKind());
+                    } catch(KindUnificationException e) {
+                        context.getErrorLog().log(location, "Parameter kinds do not match. The kind of the parameter " + 
+                                (i+1) + " should be " + classDesc.parameters[i].getKind() + ".");
+                        break loop;
+                    }
+                return Types.pred(
+                        typeClass,
+                        parameters.toArray(new Type[parameters.size()]));
+            }
+            else {
+                context.getErrorLog().log(location, "Invalid constraint.");
+                break;
+            }
+        }
+        // Returns something dummy
+        return Types.pred(Types.ORD, Types.metaVar(Kinds.STAR));
+    }
+
+    /**
+     * Elaborate this node to a type function application. Not supported for all type definition nodes.
+     * @throw UnsupportedOperationException  The node does not support elaboration.
+     */
+    public TPred toTFuncApply(TypeElaborationContext context) {
+        throw new UnsupportedOperationException();
+    }
+    
+    /**
+     * Get node precedence. TVarAst, TEffectAst, TListAst and TTupleAst nodes have precedence 0, TApplyAst has 1,
+     * and TPredAst, TForAllAst and TFunctionAst 2.
+     * 
+     * The precedence value is used for generating parentheses in deparsed expressions.
+     */
+    public abstract int getPrecedence();
+
+    /**
+     * Translate this node to an effect Type. Not all type definition constructs are allowed for effects.
+     * @throw UnsupportedOperationException  An illegal type definition constuct for effects has been used. 
+     */
+    public Type toEffect(TypeTranslationContext context) {
+        throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support toEffect.");
+    }
+    
+    /**
+     * Elaborate this node to an effect Type. Not all type definition constructs are allowed for effects.
+     * @throw UnsupportedOperationException  An illegal type definition constuct for effects has been used. 
+     */
+    public Type toEffect(TypeElaborationContext context) {
+        throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support toEffect.");
+    }
+
+    public abstract void collectReferences(TObjectIntHashMap<String> typeNameMap, TIntHashSet set);
+}