--- /dev/null
+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);
+}