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