Renamed "Writer" types to "PrintStream" and appropriate variations.
[cslatevm.git] / src / syntax / writer.slate
blob14da570044545b63edb368a774f3504a444c54f9
1 "This file only defines methods on Syntax Nodes for the purpose of generating
2 static source output which can be used as valid input. These methods make a
3 general attempt at comprehensible output. All of them assume that the
4 previously-called method responsibly adds a line-ending when possible."
6 define: #IndentedPrintStream &parents: {StructuredPrinterMixin. Stream WrapperStream}.
7 "A basis for formatted code-printing."
9 IndentedPrintStream traits define: #indentString -> '  '.
11 w@(IndentedPrintStream traits) print: node
12 "The basic printing method to specialize on the target syntax object."
13 [overrideThis].
15 w@(IndentedPrintStream traits) indentedDo: block surroundedBy: str1 and: str2
17   w newLine.
18   w ; str1.
19   w indentedDo: [block do].
20   w newLine.
21   w ; str2.
24 define: #SourcePrintStream &parents: {IndentedPrintStream} &slots: {
25   #printComments -> False.
26   "Whether comments are added to the source. The default is not to."
27   #useApplyWith -> False.
28   "Whether method calls should be printed with applyWith:"
29   #surroundingArity -> -1.
30   "The arity of a message-send context. This is significant if >= 0, and should
31    be set to -1 otherwise. Comparisons are made with a current arity, and if the
32    current is greater, the message is surrounded with precedence-preserving
33    parentheses."
35 "This visitor is a dispatch point for these methods and may be overridden."
37 w@(SourcePrintStream traits) print: node@(nodes Node traits)
38 "All printable nodes need to override this method."
40   overrideThis
43 x@(nodes Node traits) printOn: o
44 "Specialize printOn: for syntax nodes"
46   (SourcePrintStream newOn: o) print: x.
47   o
50 w@(SourcePrintStream traits) print: _@(nodes ImplicitArgument traits)
51 "The target of implicit message sends to the context. Prints nothing."
52 [].
54 w@(SourcePrintStream traits) print: node@(nodes Comment traits)
55 "(Optionally) print out the comment on the following line."
57   w print: node value.
58   w printComments
59     ifTrue: [w ; '"' ; node comment ; '"'].
60   w newLine.
61   w
64 "w@(SourcePrintStream traits) print: node inParenthesesOn: s
66   s ; '('.
67   w print: node on: s.
68   s ; ')'.
69   w
73 w@(SourcePrintStream traits) print: node@(nodes Literal traits)
74 [w ; node value printString. ].
76 w@(SourcePrintStream traits) printSelectorPrefixOf: _
77 [].
79 w@(SourcePrintStream traits) printSelectorPrefixOf: _@(nodes Macro traits)
80 [w ; '`'. ].
82 w@(SourcePrintStream traits) printSelectorPrefixOf: _@(nodes Deferred traits)
83 [w ; '%'. ].
85 w@(SourcePrintStream traits) withSurroundingArity: arity do: block
86 [| previousArity |
87   previousArity := w surroundingArity.
88   w surroundingArity := arity.
89   block do.
90   w surroundingArity := previousArity.
93 w@(SourcePrintStream traits) print: node sending: selector to: args
94 "Accepts a method name and array of arguments, and print the appropriate
95 source on the stream."
96 [| previousArity closeParen |
97   closeParen := False.
98   previousArity := w surroundingArity.
99   `conditions: (
100     [Syntax isUnarySelector: selector]
101       -> [w withSurroundingArity: 1 do:
102             [previousArity isZero
103                /\ [(args first isSameAs: nodes ImplicitArgument) not]
104                ifTrue: [w nextPut: $\(. closeParen := True].
105              (w printAsArgument: args first) ifTrue: [w newColumn].
106              w printSelectorPrefixOf: node.
107              w ; selector name]].
108     [Syntax isBinarySelector: selector]
109       -> [w withSurroundingArity: 2 do:
110             [(previousArity between: 0 and: 1)
111                ifTrue: [w nextPut: $\(. closeParen := True].
112              (w printAsArgument: args first) ifTrue: [w newColumn].
113              w printSelectorPrefixOf: node.
114              w ; selector name.
115              w newColumn.
116              w printAsArgument: args second]].
117     "For keyword sends, print the first argument, partition the selector by
118       the colons, (at an offset of 1 to synchronize indices for looping),
119       and then loop from one to the end, printing the keywords and arguments
120       alternately."
121     [Syntax isKeywordSelector: selector]
122       -> [| keywords |
123           keywords := selector keywords.
124           w withSurroundingArity: 3 do:
125             [previousArity >= 0 ifTrue:
126                [w nextPut: $\(. closeParen := True].
127                 (w printAsArgument: args first) ifTrue: [w newColumn].
128                 1 below: args size do:
129                   [| :index arg |
130                    index = 1
131                      ifTrue: [w printSelectorPrefixOf: node]
132                      ifFalse: [w newColumn].
133                    w ; ((keywords at: index - 1) as: String) ; ': '.
134                    w printAsArgument: (args at: index)]]]).
135   closeParen ifTrue: [w nextPut: $\)].
136   w
139 w@(SourcePrintStream traits) print: node@(nodes StoreVariable traits)
141   w print: node sending: (node variable name name ; ':') intern
142                 to: {nodes ImplicitArgument. node value}
145 w@(SourcePrintStream traits) print: node@(nodes LoadVariable traits)
147   w print: node sending: node variable name to: {nodes ImplicitArgument}
150 w@(SourcePrintStream traits) print: node@(nodes Variable traits)
151 [shouldNotImplement].
153 w@(SourcePrintStream traits) print: node@(nodes Message traits)
155   w useApplyWith
156     ifTrue: [w ; '(' ; node selector printString ; ' applyWith: '
157                      ; node arguments printString ; ')']
158     ifFalse: [w print: node sending: node selector to: node arguments].
159   w
162 w@(SourcePrintStream traits) print: node@(nodes MessageWrapper traits)
164   w print: node message
167 w@(SourcePrintStream traits) print: node@(nodes OptionalKeywords traits)
168 [| closeParen |
169   closeParen := False.
170   w surroundingArity >= 0 ifTrue: [w ; '('. closeParen := True].
171   w withSurroundingArity: -1 do:
172     [resend].
173   w withSurroundingArity: 2 do:
174     [node keywords with: node arguments do:
175       [| :selector :argument |
176        w indentedDo:
177          [w newColumn.
178           w ; selector name.
179           w newColumn.
180           w printAsArgument: argument]]].
181   closeParen ifTrue: [w ; ')'].
182   w
185 w@(SourcePrintStream traits) print: node@(nodes RestArguments traits)
186 [| closeParen |
187   closeParen := False.
188   w surroundingArity >= 0 ifTrue: [w ; '('. closeParen := True].
189   w withSurroundingArity: -1 do:
190     [resend].
191   w withSurroundingArity: 2 do:
192     [node arguments do:
193       [| :argument |
194        w indentedDo:
195          [w ; ','.
196           w newColumn.
197           w printAsArgument: argument]]].
198   closeParen ifTrue: [w ; ')'].
199   w
202 w@(SourcePrintStream traits) print: node@(nodes Placeholder traits)
204   w ; '_'
207 w@(SourcePrintStream traits) print: node@(nodes Pattern traits)
209   w ; '#('.
210   resend.
211   w ; ')'
214 w@(SourcePrintStream traits) isDefaultLastStatement: node
215 "Whether the expression would be a default value for the last statement in a
216 sequence - only True for Literal Nil."
217 [False].
219 w@(SourcePrintStream traits) isDefaultLastStatement: node@(nodes Literal traits)
220 [node value isNil].
222 w@(SourcePrintStream traits) printStatements: statements &separatedBy: separator
224   separator `defaultsTo: [w newLine].
225   w withSurroundingArity: -1 do:
226     [statements indexLast `cache.
227      statements doWithIndex:
228        [| :statement :index |
229         index = statements indexLast /\ [w isDefaultLastStatement: statement]
230           ifFalse: [w print: statement]]
231                 separatedBy: [w ; '.'. separator do]].
232   w
235 w@(SourcePrintStream traits) printAsRole: node
237   w withSurroundingArity: 0 do: [w print: node].
240 w@(SourcePrintStream traits) print: node@(nodes CompoundStatement traits)
242   w indentedDo:
243     [w newLine.
244      w printStatements: node statements].
245   w newLine.
246   w
249 w@(SourcePrintStream traits) print: node@(nodes Array traits)
251   w ; '{'.
252   resend.
253   w ; '}'.
254   w
257 w@(SourcePrintStream traits) print: node@(nodes Parenthesis traits)
259   w ; '('.
260   w printStatements: node statements.
261   w ; ')'.
262   w
265 w@(SourcePrintStream traits) printVariablesOf: node@(nodes Block traits) &skipInputs: skipInputs
267   skipInputs `defaultsTo: False.
268   (skipInputs not /\ [node inputVariables size > 0]) \/
269     [node localVariables size > (node inputVariables size + node optionalVariables size)]
270       ifTrue:
271         [w nextPut: $|.
272          skipInputs
273            ifFalse:
274              [node inputVariables do:
275                [| :inputVar |
276                 w newColumn.
277                 w ; ':' ; (inputVar name as: String)]].
278          node localVariables do:
279            [| :localVar |
280             (node inputVariables includes: localVar) \/ [node optionalVariables includes: localVar]
281               ifFalse:
282                 [w newColumn.
283                  w ; (localVar name as: String)]].
284          w ; ' | '].
287 w@(SourcePrintStream traits) print: node@(nodes Block traits)
289   w ; '['.
290   w printVariablesOf: node.
291   resend.
292   w ; ']'.
295 w@(SourcePrintStream traits) printAsStatement: node
297   w print: node
300 w@(SourcePrintStream traits) printArg: arg withRole: role
302   w ; (arg name as: String).
303   (role is: nodes Literal) /\ [role value == NoRole] ifFalse:
304     [w ; '@'.
305      w printAsRole: role]
308 w@(SourcePrintStream traits) print: node@(nodes Signature traits)
309 "Accepts a method name and array of arguments, and print the appropriate
310 source on the stream."
311 [| args selector |
312   selector := node selector.
313   args := node inputVariables.
314   w indentedDo:
315     [`conditions: (
316        [(Syntax isUnarySelector: selector) /\ [args size = 1]]
317          -> [w printArg: args first withRole: node roles first.
318              w newColumn.
319              w ; selector name].
320        [(Syntax isBinarySelector: selector) /\ [args size = 2]]
321          -> [w printArg: args first withRole: node roles first.
322              w newColumn.
323              w ; selector name.
324              w newColumn.
325              w printArg: args second withRole: node roles second].
326        "For keyword sends, print the first argument, partition the selector by
327          the colons, (at an offset of 1 to synchronize indices for looping),
328          and then loop from one to the end, printing the keywords and arguments
329          alternately."
330        [Syntax isKeywordSelector: selector]
331          -> [| name keywords |
332              name := selector name.
333              keywords := selector keywords.
334              w printArg: args first withRole: node roles first.
335              1 below: args size do:
336                [| :index |
337                 w newColumn.
338                 w ; ((keywords at: index - 1) as: String) ; ':'.
339                 w newColumn.
340                 w printArg: (args at: index) withRole: (node roles at: index)]]).
341      node optionalKeywords with: node optionalVariables do:
342        [| :selector :variable |
343         w newColumn.
344         w ; selector name.
345         w newColumn.
346         w ; variable name]].
349 w@(SourcePrintStream traits) printSignatureOf: node@(nodes MethodDefinition traits)
350 "Accepts a method name and array of arguments, and print the appropriate
351 source on the stream."
353   w print: (node as: nodes Signature)
356 w@(SourcePrintStream traits) printAsMethodBody: node@(nodes Block traits)
358   w newLine.
359   w ; '['.
360   w printVariablesOf: node &skipInputs: True.
361   w indentedDo:
362     [w newLine.
363      w printStatements: node statements].
364   w newLine.
365   w ; ']'.
368 w@(SourcePrintStream traits) print: node@(nodes MethodDefinition traits)
370   w newLine.
371   w printSignatureOf: node.
372   w printAsMethodBody: node.
375 w@(SourcePrintStream traits) print: node@(nodes Return traits)
377   w ; node selector ; ' '.
378   w withSurroundingArity: 2 do:
379     [w print: node value].
382 w@(SourcePrintStream traits) print: _@(nodes Resend traits)
384   w ; 'resend'.
387 w@(SourcePrintStream traits) treatAsSimpleNode: node
388 [| nodeCount |
389   nodeCount := 0.
390   node walk: [| :each | (nodeCount += 1) > 7 ifTrue: [^ False]].
391   True
395 w@(SourcePrintStream traits) treatAsSimpleNode: node@(nodes CompoundStatement traits)
397   node statements size <= 1
401 w@(SourcePrintStream traits) printAsArgument: node
402 "Print the node as an argument and return wether something was printed at all"
404   w print: node.
405   True
408 w@(SourcePrintStream traits) printAsArgument: def@(nodes MethodDefinition traits)
410   w surroundingArity isNegative
411     ifFalse: [w ; '('].
412   w print: node.
413   w surroundingArity isNegative
414     ifFalse: [w ; ')'].
415   True
418 w@(SourcePrintStream traits) printAsArgument: _@(nodes ImplicitArgument traits)
419 [False].
421 w@(SourcePrintStream traits) printAsArgument: node@(nodes CompoundStatement traits)
423   w indentedDo:
424     [w newLine.
425      w print: node].
426   True
429 w@(SourcePrintStream traits) printAsArgument: node@(nodes Parenthesis traits)
431   w ; '('.
432   w indentedDo:
433     [w printStatements: node statements &separatedBy: [w newColumn]].
434   w ; ')'.
435   True
438 w@(SourcePrintStream traits) printAsArgument: node@(nodes Block traits)
440   (w treatAsSimpleNode: node)
441     ifTrue:
442       [w ; '['.
443        w printVariablesOf: node.
444        w indentedDo:
445          [w printStatements: node statements &separatedBy: [w newColumn]].
446        w ; ']']
447     ifFalse: [resend].
448   True
451 w@(SourcePrintStream traits) printAsArgument: node@(nodes Array traits)
453   (w treatAsSimpleNode: node)
454     ifTrue:
455       [w ; '{'.
456        w indentedDo:
457          [w printStatements: node statements &separatedBy: [w newColumn]].
458        w ; '}']
459     ifFalse: [resend].
460   True