1 package org.simantics.scl.compiler.internal.elaboration.matching2;
3 import java.util.ArrayList;
4 import java.util.Arrays;
7 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
8 import org.simantics.scl.compiler.compilation.CompilationContext;
9 import org.simantics.scl.compiler.constants.Constant;
10 import org.simantics.scl.compiler.elaboration.expressions.EApply;
11 import org.simantics.scl.compiler.elaboration.expressions.EApplyType;
12 import org.simantics.scl.compiler.elaboration.expressions.EAsPattern;
13 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
14 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
15 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
16 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
17 import org.simantics.scl.compiler.elaboration.expressions.EViewPattern;
18 import org.simantics.scl.compiler.elaboration.expressions.Expression;
19 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
20 import org.simantics.scl.compiler.elaboration.modules.TypeConstructor;
21 import org.simantics.scl.compiler.internal.codegen.continuations.Branch;
22 import org.simantics.scl.compiler.internal.codegen.continuations.ICont;
23 import org.simantics.scl.compiler.internal.codegen.references.IVal;
24 import org.simantics.scl.compiler.internal.codegen.writer.CodeWriter;
25 import org.simantics.scl.compiler.types.TCon;
26 import org.simantics.scl.compiler.types.Types;
27 import org.simantics.scl.compiler.types.exceptions.MatchException;
29 import gnu.trove.map.hash.THashMap;
31 public class PatternMatchingCompiler2 {
33 private static class ExpressionMatrix {
35 final IVal[] scrutinee;
36 final List<Row2> rows = new ArrayList<Row2>();
38 public ExpressionMatrix(CodeWriter w, IVal[] scrutinee) {
40 this.scrutinee = scrutinee;
44 public static IVal[] replace(IVal[] vals, int columnToReplace, IVal ... substitution) {
45 IVal[] newVals = new IVal[vals.length-1+substitution.length];
47 for(int i=0;i<columnToReplace;++i)
48 newVals[j++] = vals[i];
49 for(int i=0;i<substitution.length;++i)
50 newVals[j++] = substitution[i];
51 for(int i=columnToReplace+1;i<vals.length;++i)
52 newVals[j++] = vals[i];
56 private static void splitByConstructors(CodeWriter w, final CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int columnId) {
57 THashMap<Object, ExpressionMatrix> matrixMap = new THashMap<Object, ExpressionMatrix>();
58 ArrayList<Branch> branches = new ArrayList<Branch>();
59 ArrayList<ExpressionMatrix> matrices = new ArrayList<ExpressionMatrix>();
61 /*System.out.println("---");
63 for(Expression e : row.patterns)
64 System.out.print(e + " ");
69 for(i=0;i<rows.size();++i) {
70 Row2 row = rows.get(i);
71 Expression pattern = row.patterns[columnId];
73 if(pattern instanceof EApplyType)
74 pattern = ((EApplyType)pattern).getExpression();
75 else if(pattern instanceof EAsPattern) {
76 EAsPattern asPattern = (EAsPattern)pattern;
77 pattern = asPattern.getPattern();
78 asPattern.getVariable().setVal(scrutinee[columnId]);
82 row.patterns[columnId] = pattern;
84 if(pattern instanceof EVariable)
86 else if(pattern instanceof EApply) {
87 EApply applyConstructor = (EApply)pattern;
88 Expression constructor_ = applyConstructor.getFunction();
89 while(constructor_ instanceof EApplyType)
90 constructor_ = ((EApplyType)constructor_).getExpression();
91 Expression[] parameters = applyConstructor.getParameters();
92 // TODO How type parameters are handled???
93 if(constructor_ instanceof EConstant) {
94 SCLValue constructor = ((EConstant)constructor_).getValue();
96 ExpressionMatrix matrix = matrixMap.get(constructor.getName());
98 CodeWriter newW = w.createBlock(Types.getTypes(parameters));
99 branches.add(new Branch((Constant)constructor.getValue(), newW.getContinuation()));
100 matrix = new ExpressionMatrix(newW, replace(scrutinee, columnId, newW.getParameters()));
101 matrices.add(matrix);
102 matrixMap.put(constructor.getName(), matrix);
104 matrix.rows.add(row.replace(columnId, parameters));
106 else if(constructor_ instanceof ELiteral) {
107 Constant constructor = ((ELiteral)constructor_).getValue();
109 ExpressionMatrix matrix = matrixMap.get(constructor);
111 CodeWriter newW = w.createBlock(Types.getTypes(parameters));
112 branches.add(new Branch(constructor, newW.getContinuation()));
113 matrix = new ExpressionMatrix(newW, replace(scrutinee, columnId, newW.getParameters()));
114 matrices.add(matrix);
115 matrixMap.put(constructor, matrix);
117 matrix.rows.add(row.replace(columnId, parameters));
120 else if(pattern instanceof EConstant) {
121 EConstant applyConstructor = (EConstant)pattern;
122 SCLValue constructor = applyConstructor.getValue();
124 ExpressionMatrix matrix = matrixMap.get(constructor.getName());
126 CodeWriter newW = w.createBlock();
127 branches.add(new Branch((Constant)constructor.getValue(), newW.getContinuation()));
128 matrix = new ExpressionMatrix(newW, replace(scrutinee, columnId, newW.getParameters()));
129 matrices.add(matrix);
130 matrixMap.put(constructor.getName(), matrix);
132 matrix.rows.add(row.replace(columnId, Expression.EMPTY_ARRAY));
134 else if(pattern instanceof ELiteral) {
135 ELiteral literal = (ELiteral)pattern;
136 Constant constructor = literal.getValue();
138 ExpressionMatrix matrix = matrixMap.get(constructor);
140 CodeWriter newW = w.createBlock();
141 branches.add(new Branch(constructor, newW.getContinuation()));
142 matrix = new ExpressionMatrix(newW, replace(scrutinee, columnId, newW.getParameters()));
143 matrices.add(matrix);
144 matrixMap.put(constructor, matrix);
146 matrix.rows.add(row.replace(columnId, Expression.EMPTY_ARRAY));
148 else if(pattern instanceof EExternalConstant) {
149 EExternalConstant constant = (EExternalConstant)pattern;
150 Constant constructor = w.getModuleWriter().getExternalConstant(constant.getValue(), constant.getType());
152 ExpressionMatrix matrix = matrixMap.get(constructor);
154 CodeWriter newW = w.createBlock();
155 branches.add(new Branch(constructor, newW.getContinuation()));
156 matrix = new ExpressionMatrix(newW, replace(scrutinee, columnId, newW.getParameters()));
157 matrices.add(matrix);
158 matrixMap.put(constructor, matrix);
160 matrix.rows.add(row.replace(columnId, Expression.EMPTY_ARRAY));
163 throw new InternalCompilerError("Cannot handle an instance of " + pattern.getClass().getSimpleName() + " in a pattern.");
165 if(i < rows.size()) {
166 CodeWriter newW = w.createBlock();
167 ICont cont = newW.getContinuation();
168 branches.add(new Branch(null, cont));
169 split(newW, context, scrutinee, failure, rows.subList(i, rows.size()));
175 con = Types.getConstructor(scrutinee[columnId].getType());
176 } catch (MatchException e) {
177 throw new InternalCompilerError(e);
179 TypeConstructor cons = (TypeConstructor)context.environment.getTypeDescriptor(con);
180 int maxBranchCount = cons.isOpen ? Integer.MAX_VALUE
181 : cons.constructors.length;
182 if(branches.size() < maxBranchCount)
183 branches.add(new Branch(null, failure));
186 for(ExpressionMatrix mx : matrices)
187 split(mx.w, context, mx.scrutinee, failure, mx.rows);
188 w.switch_(scrutinee[columnId], branches.toArray(new Branch[branches.size()]));
191 private static void splitByViewPattern(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows, int viewPatternColumn) {
192 Row2 firstRow = rows.get(0);
193 EViewPattern firstViewPattern = (EViewPattern)firstRow.patterns[viewPatternColumn];
194 firstRow.patterns[viewPatternColumn] = firstViewPattern.pattern;
196 for(i=1;i<rows.size();++i) {
197 Row2 row = rows.get(i);
198 Expression pattern = row.patterns[viewPatternColumn];
200 if(pattern instanceof EApplyType)
201 pattern = ((EApplyType)pattern).getExpression();
202 else if(pattern instanceof EAsPattern) {
203 EAsPattern asPattern = (EAsPattern)pattern;
204 pattern = asPattern.getPattern();
205 asPattern.getVariable().setVal(scrutinee[viewPatternColumn]);
209 row.patterns[viewPatternColumn] = pattern;
211 if(!(pattern instanceof EViewPattern))
213 EViewPattern otherViewPattern = (EViewPattern)pattern;
214 if(!otherViewPattern.expression.equalsExpression(firstViewPattern.expression))
216 row.patterns[viewPatternColumn] = otherViewPattern.pattern;
219 IVal[] newScrutinee = Arrays.copyOf(scrutinee, scrutinee.length);
220 newScrutinee[viewPatternColumn] =
221 w.apply(firstViewPattern.location,
222 firstViewPattern.expression.toVal(context, w),
223 scrutinee[viewPatternColumn]);
224 if(i == rows.size()) {
225 split(w, context, newScrutinee, failure, rows);
228 CodeWriter cont = w.createBlock();
229 split(w, context, newScrutinee, cont.getContinuation(), rows.subList(0, i));
230 split(cont, context, scrutinee, failure, rows.subList(i, rows.size()));
234 public static void split(CodeWriter w, CompilationContext context, IVal[] scrutinee, ICont failure, List<Row2> rows) {
235 Row2 firstRow = rows.get(0);
236 Expression[] patterns = firstRow.patterns;
237 if(scrutinee.length != patterns.length)
238 throw new InternalCompilerError("Scrutinee and patterns have a different length");
240 // Find a non-variable pattern and split by it
241 int viewPatternColumn = -1;
242 for(int i=0;i<patterns.length;++i) {
243 Expression pattern = patterns[i];
244 if(pattern instanceof EViewPattern) {
245 if(viewPatternColumn == -1)
246 viewPatternColumn = i;
248 else if(!(pattern instanceof EVariable)) {
249 splitByConstructors(w, context, scrutinee, failure, rows, i);
254 if(viewPatternColumn >= 0) {
255 splitByViewPattern(w, context, scrutinee, failure, rows, viewPatternColumn);
259 // The first row has only variable patterns: no matching needed
260 for(int i=0;i<patterns.length;++i)
261 ((EVariable)patterns[i]).getVariable().setVal(scrutinee[i]);
262 w.jump(firstRow.continuation);