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