]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 package org.simantics.scl.compiler.internal.parsing.types;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5
6 import org.simantics.scl.compiler.elaboration.contexts.TypeTranslationContext;
7 import org.simantics.scl.compiler.elaboration.modules.TypeClass;
8 import org.simantics.scl.compiler.environment.AmbiguousNameException;
9 import org.simantics.scl.compiler.environment.Environments;
10 import org.simantics.scl.compiler.internal.parsing.Symbol;
11 import org.simantics.scl.compiler.internal.types.TypeElaborationContext;
12 import org.simantics.scl.compiler.types.TCon;
13 import org.simantics.scl.compiler.types.TPred;
14 import org.simantics.scl.compiler.types.Type;
15 import org.simantics.scl.compiler.types.Types;
16 import org.simantics.scl.compiler.types.exceptions.KindUnificationException;
17 import org.simantics.scl.compiler.types.kinds.Kind;
18 import org.simantics.scl.compiler.types.kinds.Kinds;
19
20 import gnu.trove.map.hash.TObjectIntHashMap;
21 import gnu.trove.set.hash.TIntHashSet;
22
23
24 /**
25  * This class is a common base class for type-related nodes in an SCL abstract syntax tree.
26  * sub-nodes of type nodes in the AST are restricted to the subclasses of this abstract base class.
27  */
28 public abstract class TypeAst extends Symbol { 
29     public static final TypeAst[] EMPTY_ARRAY = new TypeAst[0];
30     
31     @Override
32     public String toString() {
33         StringBuilder b = new StringBuilder();
34         toString(b);
35         return b.toString();
36     }
37
38     /**
39      * Write a text representation of this node to a string builder.
40      * All sub-classes must override this abstract method instead of
41      * directly overriding the {@link #toString()} method. 
42      */
43     public abstract void toString(StringBuilder b);
44     
45     /**
46      * Write a text representation of this node, with parenthesis if demanded by the precedence.
47      * Literals that never need to be parenthesized can override this method directly.
48      */
49     public void toString(StringBuilder b, int outerPrecedence) {
50         if(getPrecedence() >= outerPrecedence) {
51             b.append('(');
52             toString(b);
53             b.append(')');
54         }
55         else
56             toString(b);
57     }
58     
59     /**
60      * Translate this node into a Type instance usinga TypeTranslationContext, with expected Kind.
61      */
62     public abstract Type toType(TypeTranslationContext context, Kind expectedKind);
63     
64     /**
65      * Elaborate this node into a Type using a TypeElaborationContext.
66      */
67     public abstract Type toType(TypeElaborationContext context);
68
69     /**
70      * Elaborate an array of type nodes into an array of Type instances.
71      */
72     public static Type[] toTypes(TypeElaborationContext context, TypeAst[] typeAsts) {
73         Type[] result = new Type[typeAsts.length];
74         for(int i=0;i<typeAsts.length;++i)
75             result[i] = typeAsts[i].toType(context);
76         return result;
77     }
78
79     /**
80      * Translate an array of type nodes into an array of Type instances, using Kinds.STAR is the expected kind.
81      */
82     public static Type[] toTypes(TypeTranslationContext context, TypeAst[] typeAsts) {
83         Type[] result = new Type[typeAsts.length];
84         for(int i=0;i<typeAsts.length;++i)
85             result[i] = typeAsts[i].toType(context, Kinds.STAR);
86         return result;
87     }
88
89     /**
90      * Get a TPred instance from this node as a type function application (a type class restriction).
91      */
92     public TPred toTFuncApply(TypeTranslationContext context) {
93         ArrayList<Type> parameters = new ArrayList<Type>();
94         ArrayList<Kind> parameterKinds = new ArrayList<Kind>();
95         TypeAst cur = this;
96         loop: while(true) {
97             if(cur instanceof TApplyAst) {
98                 TApplyAst apply = (TApplyAst)cur;
99                 for(int i=apply.parameters.length-1;i>=0;--i) {
100                     TypeAst parameter = apply.parameters[i];
101                     Kind kind = Kinds.metaVar();
102                     parameters.add(parameter.toType(context, kind));
103                     parameterKinds.add(kind);
104                 }
105                 cur = apply.function;
106             }
107             else if(cur instanceof TVarAst) {
108                 TVarAst con = (TVarAst)cur;
109                 Collections.reverse(parameters);
110                 Collections.reverse(parameterKinds);
111                 TCon typeClass;
112                 try {
113                     typeClass = Environments.getTypeClassName(context.getEnvironment(), con.name);
114                 } catch (AmbiguousNameException e1) {
115                     context.getErrorLog().log(con.location, e1.getMessage());
116                     break;
117                 }
118                 if(typeClass == null) {
119                     context.getErrorLog().log(con.location, "Unresolved type class " + con.name + ".");
120                     break;
121                 }
122                 TypeClass classDesc = context.getEnvironment().getTypeClass(typeClass);
123                 if(classDesc.parameters.length != parameters.size()) {
124                     context.getErrorLog().log(location, "Wrong number of parameters. " + classDesc.parameters.length + " parameters were expected.");
125                     break;
126                 }
127                 for(int i=0;i<parameterKinds.size();++i)
128                     try {
129                         Kinds.unify(parameterKinds.get(i), classDesc.parameters[i].getKind());
130                     } catch(KindUnificationException e) {
131                         context.getErrorLog().log(location, "Parameter kinds do not match. The kind of the parameter " + 
132                                 (i+1) + " should be " + classDesc.parameters[i].getKind() + ".");
133                         break loop;
134                     }
135                 return Types.pred(
136                         typeClass,
137                         parameters.toArray(new Type[parameters.size()]));
138             }
139             else {
140                 context.getErrorLog().log(location, "Invalid constraint.");
141                 break;
142             }
143         }
144         // Returns something dummy
145         return Types.pred(Types.ORD, Types.metaVar(Kinds.STAR));
146     }
147
148     /**
149      * Elaborate this node to a type function application. Not supported for all type definition nodes.
150      * @throw UnsupportedOperationException  The node does not support elaboration.
151      */
152     public TPred toTFuncApply(TypeElaborationContext context) {
153         throw new UnsupportedOperationException();
154     }
155     
156     /**
157      * Get node precedence. TVarAst, TEffectAst, TListAst and TTupleAst nodes have precedence 0, TApplyAst has 1,
158      * and TPredAst, TForAllAst and TFunctionAst 2.
159      * 
160      * The precedence value is used for generating parentheses in deparsed expressions.
161      */
162     public abstract int getPrecedence();
163
164     /**
165      * Translate this node to an effect Type. Not all type definition constructs are allowed for effects.
166      * @throw UnsupportedOperationException  An illegal type definition constuct for effects has been used. 
167      */
168     public Type toEffect(TypeTranslationContext context) {
169         throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support toEffect.");
170     }
171     
172     /**
173      * Elaborate this node to an effect Type. Not all type definition constructs are allowed for effects.
174      * @throw UnsupportedOperationException  An illegal type definition constuct for effects has been used. 
175      */
176     public Type toEffect(TypeElaborationContext context) {
177         throw new UnsupportedOperationException(getClass().getSimpleName() + " does not support toEffect.");
178     }
179
180     public abstract void collectReferences(TObjectIntHashMap<String> typeNameMap, TIntHashSet set);
181 }