]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/elaboration/expressions/printing/ExpressionToStringVisitor.java
ac347385ae68b5d860ad927cb52a4f67ff9a0282
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / elaboration / expressions / printing / ExpressionToStringVisitor.java
1 package org.simantics.scl.compiler.elaboration.expressions.printing;
2
3 import java.util.Map.Entry;
4
5 import org.simantics.scl.compiler.elaboration.chr.CHRLiteral;
6 import org.simantics.scl.compiler.elaboration.chr.CHRQuery;
7 import org.simantics.scl.compiler.elaboration.chr.CHRRule;
8 import org.simantics.scl.compiler.elaboration.chr.relations.CHRConstraint;
9 import org.simantics.scl.compiler.elaboration.expressions.Assignment;
10 import org.simantics.scl.compiler.elaboration.expressions.Case;
11 import org.simantics.scl.compiler.elaboration.expressions.EApply;
12 import org.simantics.scl.compiler.elaboration.expressions.EApplyType;
13 import org.simantics.scl.compiler.elaboration.expressions.EAsPattern;
14 import org.simantics.scl.compiler.elaboration.expressions.EBind;
15 import org.simantics.scl.compiler.elaboration.expressions.ECHRRuleset;
16 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
17 import org.simantics.scl.compiler.elaboration.expressions.ECoveringBranchPoint;
18 import org.simantics.scl.compiler.elaboration.expressions.EEnforce;
19 import org.simantics.scl.compiler.elaboration.expressions.EEquations;
20 import org.simantics.scl.compiler.elaboration.expressions.EError;
21 import org.simantics.scl.compiler.elaboration.expressions.EExternalConstant;
22 import org.simantics.scl.compiler.elaboration.expressions.EFieldAccess;
23 import org.simantics.scl.compiler.elaboration.expressions.EGetConstraint;
24 import org.simantics.scl.compiler.elaboration.expressions.EIf;
25 import org.simantics.scl.compiler.elaboration.expressions.EIntegerLiteral;
26 import org.simantics.scl.compiler.elaboration.expressions.ELambda;
27 import org.simantics.scl.compiler.elaboration.expressions.ELambdaType;
28 import org.simantics.scl.compiler.elaboration.expressions.ELet;
29 import org.simantics.scl.compiler.elaboration.expressions.EListComprehension;
30 import org.simantics.scl.compiler.elaboration.expressions.EListLiteral;
31 import org.simantics.scl.compiler.elaboration.expressions.ELiteral;
32 import org.simantics.scl.compiler.elaboration.expressions.EMatch;
33 import org.simantics.scl.compiler.elaboration.expressions.EPlaceholder;
34 import org.simantics.scl.compiler.elaboration.expressions.ERealLiteral;
35 import org.simantics.scl.compiler.elaboration.expressions.ERuleset;
36 import org.simantics.scl.compiler.elaboration.expressions.ESelect;
37 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLambda;
38 import org.simantics.scl.compiler.elaboration.expressions.ESimpleLet;
39 import org.simantics.scl.compiler.elaboration.expressions.ETransformation;
40 import org.simantics.scl.compiler.elaboration.expressions.ETypeAnnotation;
41 import org.simantics.scl.compiler.elaboration.expressions.EVariable;
42 import org.simantics.scl.compiler.elaboration.expressions.EViewPattern;
43 import org.simantics.scl.compiler.elaboration.expressions.EWhen;
44 import org.simantics.scl.compiler.elaboration.expressions.Expression;
45 import org.simantics.scl.compiler.elaboration.expressions.ExpressionVisitor;
46 import org.simantics.scl.compiler.elaboration.expressions.GuardedExpression;
47 import org.simantics.scl.compiler.elaboration.expressions.GuardedExpressionGroup;
48 import org.simantics.scl.compiler.elaboration.expressions.Variable;
49 import org.simantics.scl.compiler.elaboration.java.EqRelation;
50 import org.simantics.scl.compiler.elaboration.java.MemberRelation;
51 import org.simantics.scl.compiler.elaboration.query.QAlternative;
52 import org.simantics.scl.compiler.elaboration.query.QAtom;
53 import org.simantics.scl.compiler.elaboration.query.QConjunction;
54 import org.simantics.scl.compiler.elaboration.query.QDisjunction;
55 import org.simantics.scl.compiler.elaboration.query.QExists;
56 import org.simantics.scl.compiler.elaboration.query.QIf;
57 import org.simantics.scl.compiler.elaboration.query.QMapping;
58 import org.simantics.scl.compiler.elaboration.query.QNegation;
59 import org.simantics.scl.compiler.elaboration.query.Query;
60 import org.simantics.scl.compiler.elaboration.query.QueryVisitor;
61 import org.simantics.scl.compiler.elaboration.rules.SectionName;
62 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
63
64 public class ExpressionToStringVisitor implements ExpressionVisitor, QueryVisitor {
65
66     StringBuilder b = new StringBuilder();
67     int indentation;
68     
69     public ExpressionToStringVisitor(StringBuilder b) {
70         this.b = b;
71     }
72
73     public void show(Variable variable) {
74         if(variable == null)
75             b.append("NULL_VARIABLE");
76         else
77             b.append(variable.getName());
78     }
79     
80     private void newLine() {
81         b.append('\n');
82         for(int i=0;i<indentation;++i)
83             b.append("  ");
84     }
85     
86     public void showPar(Expression expression) {
87         boolean needsPar = false;
88         while(true) {
89             if(expression instanceof EPlaceholder)
90                 expression = ((EPlaceholder)expression).expression;
91             else if(expression instanceof ETypeAnnotation)
92                 expression = ((ETypeAnnotation)expression).getValue();
93             else if(expression instanceof EApplyType)
94                 expression = ((EApplyType)expression).getExpression();
95             else if(expression instanceof ELambdaType)
96                 expression = ((ELambdaType)expression).value;
97             else if(expression instanceof ECoveringBranchPoint)
98                 expression = ((ECoveringBranchPoint)expression).expression;
99             else
100                 break;
101         }
102         if(expression instanceof EApply ||
103                 expression instanceof EIf ||
104                 expression instanceof ESimpleLambda ||
105                 expression instanceof ESimpleLet)
106             needsPar = true;
107         if(needsPar)
108             b.append('(');
109         expression.accept(this);
110         if(needsPar)
111             b.append(')');
112     }
113     
114     @Override
115     public void visit(EApply expression) {
116         showPar(expression.getFunction());
117         for(Expression parameter : expression.getParameters()) {
118             b.append(' ');
119             showPar(parameter);
120         }
121     }
122
123     @Override
124     public void visit(EApplyType expression) {
125         expression.getExpression().accept(this);
126     }
127
128     @Override
129     public void visit(EAsPattern expression) {
130         show(expression.getVariable());
131         b.append('@');
132         showPar(expression.getPattern());
133     }
134
135     @Override
136     public void visit(EBind expression) {
137         b.append("EBind");
138     }
139
140     @Override
141     public void visit(EConstant expression) {
142         String name = expression.getValue().getName().name;
143         if(Character.isJavaIdentifierStart(name.charAt(0)))
144             b.append(name);
145         else
146             b.append('(').append(name).append(')');
147     }
148
149     @Override
150     public void visit(EEnforce expression) {
151         b.append("enforce ");
152         expression.getQuery().accept(this);
153     }
154
155     @Override
156     public void visit(EError expression) {
157         b.append("EError");
158     }
159
160     @Override
161     public void visit(EExternalConstant expression) {
162         b.append(expression.getValue());
163     }
164
165     @Override
166     public void visit(EFieldAccess expression) {
167         b.append("EFieldAccess");
168     }
169
170     @Override
171     public void visit(EGetConstraint expression) {
172         b.append("EGetConstraint");
173     }
174
175     @Override
176     public void visit(EIf expression) {
177         b.append("if ");
178         expression.condition.accept(this);
179         ++indentation;
180         newLine();
181         b.append("then ");
182         expression.then_.accept(this);
183         if(expression.else_ != null) {
184             newLine();
185             b.append("else ");
186             expression.else_.accept(this);
187         }
188         --indentation;
189     }
190     
191     @Override
192     public void visit(QIf query) {
193         b.append("if ");
194         query.condition.accept(this);
195         ++indentation;
196         newLine();
197         b.append("then ");
198         query.thenQuery.accept(this);
199         newLine();
200         b.append("else ");
201         query.elseQuery.accept(this);
202         --indentation;
203     }
204
205     @Override
206     public void visit(EIntegerLiteral expression) {
207         b.append(expression.getValue());
208     }
209
210     @Override
211     public void visit(ELambda expression) {
212         b.append('\\');
213         ++indentation;
214         for(Case case_ : expression.getCases()) {
215             newLine();
216             for(Expression pat : case_.patterns) {
217                 showPar(pat);
218                 b.append(' ');
219             }
220             b.append("-> ");
221             ++indentation;
222             case_.value.accept(this);
223             --indentation;
224         }
225         --indentation;
226     }
227     
228     @Override
229     public void visit(EViewPattern expression) {
230         b.append('(');
231         expression.expression.accept(this);
232         b.append(" -> ");
233         expression.pattern.accept(this);
234         b.append(')');
235     }
236
237     @Override
238     public void visit(ELambdaType expression) {
239         expression.value.accept(this);
240     }
241
242     @Override
243     public void visit(ELet expression) {
244         b.append("do");
245         ++indentation;
246         printAsDo(expression);
247         --indentation;
248     }
249
250     @Override
251     public void visit(EListComprehension expression) {
252         b.append("EListComprehension");
253     }
254
255     @Override
256     public void visit(EListLiteral expression) {
257         b.append('[');
258         boolean first = true;
259         for(Expression component : expression.getComponents()) {
260             if(first)
261                 first = false;
262             else
263                 b.append(',');
264             component.accept(this);
265         }
266         b.append(']');
267     }
268
269     @Override
270     public void visit(ELiteral expression) {
271         b.append(expression.getValue().toString());
272     }
273
274     @Override
275     public void visit(EMatch expression) {
276         b.append("match");
277         for(Expression s : expression.getScrutinee()) {
278             b.append(' ');
279             showPar(s);
280         }
281         b.append(" with");
282         ++indentation;
283         for(Case case_ : expression.getCases()) {
284             newLine();
285             for(Expression pat : case_.patterns) {
286                 showPar(pat);
287                 b.append(' ');
288             }
289             b.append("-> ");
290             ++indentation;
291             case_.value.accept(this);
292             --indentation;
293         }
294         --indentation;
295     }
296
297     @Override
298     public void visit(EPlaceholder expression) {
299         expression.expression.accept(this);
300     }
301
302     @Override
303     public void visit(ERealLiteral expression) {
304         b.append(expression.getValue());
305     }
306
307     @Override
308     public void visit(ERuleset expression) {
309         b.append("let\n");
310         ++indentation;
311         for(ERuleset.DatalogRule rule : expression.getRules()) {
312             newLine();
313             visit(rule);
314         }
315         --indentation;
316         b.append("\nin ");
317         expression.getIn().accept(this);
318     }
319
320     @Override
321     public void visit(ESelect expression) {
322         b.append("ESelect");
323     }
324
325     @Override
326     public void visit(ESimpleLambda expression) {
327         b.append('\\');
328         show(expression.getParameter());
329         while(expression.getValue() instanceof ESimpleLambda) {
330             expression = (ESimpleLambda)expression.getValue();
331             b.append(' ');
332             show(expression.getParameter());
333         }
334         b.append(" -> ");
335         expression.getValue().accept(this);
336     }
337
338     @Override
339     public void visit(ESimpleLet expression) {
340         b.append("do");
341         ++indentation;
342         printAsDo(expression);
343         --indentation;
344     }
345     
346     private void printAsDo(Expression expression) {
347         if(expression instanceof ESimpleLet) {
348             ESimpleLet let = (ESimpleLet)expression;
349             Variable variable = let.getVariable();
350             Expression value = let.getValue();
351             if(variable == null || "_".equals(variable.getName()))
352                 printAsDo(value);
353             else {
354                 newLine();
355                 show(variable);
356                 b.append(" = ");
357                 value.accept(this);
358             }
359             printAsDo(let.getIn());
360         }
361         else if(expression instanceof ELet) {
362             ELet let = (ELet)expression;
363             for(Assignment assignment : let.assignments) {
364                 newLine();
365                 assignment.pattern.accept(this);
366                 b.append(" = ");
367                 assignment.value.accept(this);
368             }
369             printAsDo(let.in);
370         }
371         else {
372             newLine();
373             expression.accept(this);
374         }
375     }
376
377     @Override
378     public void visit(ETransformation expression) {
379         b.append("<transformation>");
380     }
381
382     @Override
383     public void visit(ETypeAnnotation expression) {
384         expression.getValue().accept(this);
385     }
386
387     @Override
388     public void visit(EVariable expression) {
389         show(expression.getVariable());
390     }
391
392     @Override
393     public void visit(EWhen expression) {
394         b.append("when ");
395         expression.getQuery().accept(this);
396         b.append("\n");
397         expression.getAction().accept(this);
398     }
399
400     @Override
401     public void visit(GuardedExpressionGroup expression) {
402         boolean first = true;
403         for(GuardedExpression gexp : expression.expressions) {
404             if(first)
405                 first = false;
406             else
407                 newLine();
408             b.append("| ");
409             for(int i=0;i<gexp.guards.length;++i) {
410                 if(i > 0)
411                     b.append(", ");
412                 gexp.guards[i].accept(this);
413             }
414             b.append(" = ");
415             gexp.value.accept(this);
416         }
417     }
418
419     @Override
420     public void visit(QAlternative query) {
421         b.append("QAlternative");
422     }
423
424     @Override
425     public void visit(QAtom query) {
426         if(query.relation == EqRelation.INSTANCE) {
427             query.parameters[0].accept(this);
428             b.append(" = ");
429             query.parameters[1].accept(this);
430         }
431         else if(query.relation == MemberRelation.INSTANCE) {
432             query.parameters[0].accept(this);
433             b.append(" <- ");
434             query.parameters[1].accept(this);
435         }
436         else {
437             b.append(query.relation);
438             for(Expression parameter : query.parameters) {
439                 b.append(' ');
440                 showPar(parameter);
441             }
442         }
443     }
444
445     @Override
446     public void visit(QConjunction query) {
447         boolean first = true;
448         for(Query q : query.queries) {
449             if(first)
450                 first = false;
451             else
452                 newLine();
453             q.accept(this);
454         }
455     }
456
457     @Override
458     public void visit(QDisjunction query) {
459         b.append("QDisjunction");
460     }
461
462     @Override
463     public void visit(QExists query) {
464         b.append("QExists");
465     }
466
467     @Override
468     public void visit(QNegation query) {
469         b.append("QNegation");
470     }
471
472     @Override
473     public void visit(QMapping query) {
474         b.append(query.mappingRelation.name.name);
475         for(Expression parameter : query.parameters) {
476             b.append(' ');
477             parameter.accept(this);
478         }
479     }
480
481     public void visit(ERuleset.DatalogRule rule) {
482         b.append(rule.headRelation.getName());
483         for(Expression parameter : rule.headParameters) {
484             b.append(' ');
485             showPar(parameter);
486         }
487         b.append(" :-\n");
488         ++indentation;
489         rule.body.accept(this);
490         --indentation;
491     }
492
493     public void visit(TransformationRule rule) {
494         b.append("rule ").append(rule.name.name).append(" where");
495         for(Entry<SectionName, Query[]> section : rule.sections.entrySet()) {
496             b.append("\n@").append(section.getKey().name());
497             for(Query query : section.getValue()) {
498                 b.append('\n');
499                 query.accept(this);
500             }
501         }
502     }
503
504
505     @Override
506     public void visit(ECoveringBranchPoint expression) {
507         expression.expression.accept(this);
508     }
509
510     @Override
511     public void visit(EEquations eEquations) {
512         b.append("eq");
513     }
514
515     @Override
516     public void visit(ECHRRuleset echrRuleset) {
517         b.append("CHRRuleset");
518     }
519
520     public void visit(CHRRule rule) {
521         visit(rule.head);
522         b.append(" => ");
523         visit(rule.body);
524     }
525
526     public void visit(CHRQuery query) {
527         boolean first = true;
528         for(CHRLiteral literal : query.literals) {
529             if(first)
530                 first = false;
531             else
532                 b.append(", ");
533             visit(literal);
534         }
535     }
536
537     public void visit(CHRLiteral literal) {
538         if(literal.passive && literal.relation instanceof CHRConstraint)
539             b.append("@passive ");
540         if(literal.killAfterMatch)
541             b.append('-');
542         b.append(literal.relation);
543         for(Expression parameter : literal.parameters) {
544             b.append(' ');
545             showPar(parameter);
546         }
547     }
548 }