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