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