Slight code cleanups to printing code.
[cslatevm.git] / src / syntax / writer.slate
blob84de39dfe37e75ca6e80ad5cd8e44cc5f6a6c7e5
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 prototypes define: #Writer &parents: {StructuredPrinterMixin. Stream WrapperStream}.
7 "A basis for formatted code-printing."
9 Writer traits define: #indentString -> '  '.
11 w@(Writer traits) print: node
12 "The basic printing method to specialize on the target syntax object."
13 [overrideThis].
15 w@(Writer 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 Syntax define: #SourceWriter &parents: {Writer} &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@(Syntax SourceWriter traits) print: node@(Syntax Node traits)
38 "All printable nodes need to override this method."
40   overrideThis
43 x@(Syntax Node traits) printOn: o
44 "Specialize printOn: for syntax nodes"
46   (Syntax SourceWriter newOn: o) print: x.
47   o
50 w@(Syntax SourceWriter traits) print: _@(Syntax ImplicitArgument traits)
51 "The target of implicit message sends to the context. Prints nothing."
52 [].
54 w@(Syntax SourceWriter traits) print: node@(Syntax 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@(Syntax SourceWriter traits) print: node inParenthesesOn: s
66   s ; '('.
67   w print: node on: s.
68   s ; ')'.
69   w
73 w@(Syntax SourceWriter traits) print: node@(Syntax Literal traits)
74 [w ; node value printString. ].
76 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _
77 [].
79 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _@(Syntax Macro traits)
80 [w ; '`'. ].
82 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _@(Syntax Deferred traits)
83 [w ; '%'. ].
85 w@(Syntax SourceWriter traits) withSurroundingArity: arity do: block
86 [| previousArity |
87   previousArity: w surroundingArity.
88   w surroundingArity: arity.
89   block do.
90   w surroundingArity: previousArity.
93 w@(Syntax SourceWriter 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 "  w indentedDo: ["
100     (Syntax isUnarySelector: selector)
101       ifTrue: [w withSurroundingArity: 1 do:
102                 [previousArity isZero /\
103                    [(args first isSameAs: Syntax 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       ifTrue: [w withSurroundingArity: 2 do:
110                 [(previousArity between: 0 and: 1) ifTrue:
111                     [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       ifTrue: [| names |
123                 names: (selector name splitWith: $:).
124                 w withSurroundingArity: 3 do:
125                   [previousArity >= 0 ifTrue: [w nextPut: $(. closeParen: True].
126                     (w printAsArgument: args first) ifTrue: [w newColumn].
127                     1 below: args size do:
128                       [| :index arg |
129                         index = 1
130                           ifTrue: [w printSelectorPrefixOf: node]
131                           ifFalse: [w newColumn].
132                         w ; ((names at: index - 1) as: String).
133                         w ; ': '.
134                         w printAsArgument: (args at: index)]]].
135     closeParen ifTrue: [w nextPut: $)].
136 "  ]."
137   w
140 w@(Syntax SourceWriter traits) print: node@(Syntax StoreVariable traits)
142   w print: node sending: (node variable name name ; ':') intern
143                 to: {Syntax ImplicitArgument. node value}
146 w@(Syntax SourceWriter traits) print: node@(Syntax LoadVariable traits)
148   w print: node sending: node variable name to: {Syntax ImplicitArgument}
151 w@(Syntax SourceWriter traits) print: node@(Syntax Variable traits)
152 [shouldNotImplement].
154 w@(Syntax SourceWriter traits) print: node@(Syntax Message traits)
156   w useApplyWith
157     ifTrue: [w ; '(' ; node selector printString ; ' applyWith: '
158                      ; node arguments printString ; ')']
159     ifFalse: [w print: node sending: node selector to: node arguments].
160   w
163 w@(Syntax SourceWriter traits) print: node@(Syntax OptionalKeywords traits)
164 [| closeParen |
165   closeParen: False.
166   w surroundingArity >= 0 ifTrue: [w ; '('. closeParen: True].
167   w withSurroundingArity: -1 do:
168     [w print: node message].
169   w withSurroundingArity: 2 do:
170     [node keywords with: node arguments do:
171       [| :selector :argument |
172        w indentedDo:
173          [w newColumn.
174           w ; selector name.
175           w newColumn.
176           w printAsArgument: argument]]].
177   closeParen ifTrue: [w ; ')'].
178   w
181 w@(Syntax SourceWriter traits) print: node@(Syntax RestArguments traits)
182 [| closeParen |
183   closeParen: False.
184   w surroundingArity >= 0 ifTrue: [w ; '('. closeParen: True].
185   w withSurroundingArity: -1 do:
186     [w print: node message].
187   w withSurroundingArity: 2 do:
188     [node arguments do:
189       [| :argument |
190        w indentedDo:
191          [w ; ','.
192           w newColumn.
193           w printAsArgument: argument]]].
194   closeParen ifTrue: [w ; ')'].
195   w
198 w@(Syntax SourceWriter traits) isDefaultLastStatement: node
199 "Whether the expression would be a default value for the last statement in a
200 sequence - only True for Literal Nil."
201 [False].
203 w@(Syntax SourceWriter traits) isDefaultLastStatement: node@(Syntax Literal traits)
204 [node value isNil].
206 w@(Syntax SourceWriter traits) printStatements: statements &separatedBy: separator
208   separator `defaultsTo: [w newLine].
209   w withSurroundingArity: -1 do:
210     [statements indexLast `cache.
211      statements doWithIndex:
212        [| :statement :index |
213         index = statements indexLast /\ [w isDefaultLastStatement: statement]
214           ifFalse: [w print: statement]]
215                 separatedBy: [w ; '.'. separator do]].
216   w
219 w@(Syntax SourceWriter traits) printAsRole: node
221   w withSurroundingArity: 0 do: [w print: node].
224 w@(Syntax SourceWriter traits) print: node@(Syntax CompoundStatement traits)
226   w indentedDo:
227     [w newLine.
228      w printStatements: node statements].
229   w newLine.
230   w
233 w@(Syntax SourceWriter traits) print: node@(Syntax Array traits)
235   w ; '{'.
236   resend.
237   w ; '}'.
238   w
241 w@(Syntax SourceWriter traits) print: node@(Syntax Parenthesis traits)
243   w ; '('.
244   w printStatements: node statements.
245   w ; ')'.
246   w
249 w@(Syntax SourceWriter traits) printVariablesOf: node@(Syntax Block traits) &skipInputs: skipInputs
251   skipInputs `defaultsTo: False.
252   (skipInputs not /\ [node inputVariables size > 0]) \/
253     [node localVariables size > (node inputVariables size + node optionalVariables size)]
254       ifTrue:
255         [w nextPut: $|.
256          skipInputs
257            ifFalse:
258              [node inputVariables do:
259                [| :inputVar |
260                 w newColumn.
261                 w ; ':' ; (inputVar name as: String)]].
262          node localVariables do:
263            [| :localVar |
264             (node inputVariables includes: localVar) \/ [node optionalVariables includes: localVar]
265               ifFalse:
266                 [w newColumn.
267                  w ; (localVar name as: String)]].
268          w ; ' | '].
271 w@(Syntax SourceWriter traits) print: node@(Syntax Block traits)
273   w ; '['.
274   w printVariablesOf: node.
275   resend.
276   w ; ']'.
279 w@(Syntax SourceWriter traits) printAsStatement: node
281   w print: node
284 w@(Syntax SourceWriter traits) printArg: arg withRole: role
286   w ; (arg name as: String).
287   (role is: Syntax Literal) /\ [role value == NoRole] ifFalse:
288     [w ; '@'.
289      w printAsRole: role]
292 w@(Syntax SourceWriter traits) printMethodHeader: node@(Syntax MethodDefinition traits)
293 "Accepts a method name and array of arguments, and print the appropriate
294 source on the stream."
295 [| args selector |
296   selector: node selector.
297   args: node inputVariables.
298   w indentedDo: [
299     (Syntax isUnarySelector: selector) /\ [args size = 1]
300       ifTrue: [ | role |
301                role: (node roles first).
302                w printArg: args first withRole: role.
303                w newColumn.
304                w ; (selector as: String)
305               ].
306     (Syntax isBinarySelector: selector) /\ [args size = 2]
307       ifTrue: [ | role0 role1 |
308                role0: (node roles first).
309                role1: (node roles second).
310                w printArg: args first withRole: role0.
311                w newColumn.
312                w ; (selector as: String).
313                w newColumn.
314                w printArg: args second withRole: role1
315               ].
316     "For keyword sends, print the first argument, partition the selector by
317      the colons, (at an offset of 1 to synchronize indices for looping),
318      and then loop from one to the end, printing the keywords and arguments
319      alternately."
320     (Syntax isKeywordSelector: selector)
321       ifTrue: [| name names |
322                 name: (selector as: String).
323                 names: (name splitWith: $:).
324                 w printArg: args first withRole: node roles first.
325                 1 below: args size
326                   do: [| :index |
327                         w newColumn.
328                         w ; ((names at: index - 1) as: String).
329                         w nextPut: $:.
330                         w newColumn.
331                         w printArg: (args at: index) withRole: (node roles at: index)]].
332     node optionalKeywords with: node optionalVariables do: [| :selector :variable |
333       w newColumn.
334       w ; selector name.
335       w newColumn.
336       w ; variable name].
337   ].
340 w@(Syntax SourceWriter traits) printAsMethodBody: node@(Syntax Block traits)
342   w newLine.
343   w ; '['.
344   w printVariablesOf: node &skipInputs: True.
345   w indentedDo:
346     [w newLine.
347      w printStatements: node statements].
348   w newLine.
349   w ; ']'.
352 w@(Syntax SourceWriter traits) print: node@(Syntax MethodDefinition traits)
354   w newLine.
355   w printMethodHeader: node.
356   w printAsMethodBody: node.
359 w@(Syntax SourceWriter traits) print: node@(Syntax Return traits)
361   w ; node selector ; ' '.
362   w withSurroundingArity: 2 do:
363    [w print: node value].
366 w@(Syntax SourceWriter traits) print: _@(Syntax Resend traits)
368   w ; 'resend'.
371 w@(Syntax SourceWriter traits) treatAsSimpleNode: node
372 [| nodeCount |
373   nodeCount: 0.
374   node walk: [| :each | nodeCount: nodeCount + 1. nodeCount > 7 ifTrue: [ ^ False]].
375   True
379 w@(Syntax SourceWriter traits) treatAsSimpleNode: node@(Syntax CompoundStatement traits)
381   node statements size <= 1
385 w@(Syntax SourceWriter traits) printAsArgument: node
386 "Print the node as an argument and return wether something was printed at all"
388   w print: node.
389   True
392 w@(Syntax SourceWriter traits) printAsArgument: def@(Syntax MethodDefinition traits)
394   w surroundingArity < 0
395     ifFalse: [w nextPut: $(].
396   w print: node.
397   w surroundingArity < 0
398     ifFalse: [w nextPut: $)].
399   True
402 w@(Syntax SourceWriter traits) printAsArgument: _@(Syntax ImplicitArgument traits)
403 [False].
405 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax CompoundStatement traits)
407   w indentedDo:
408     [w newLine.
409      w print: node].
410   True
413 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Parenthesis traits)
415   w ; '('.
416   w indentedDo:
417     [w printStatements: node statements &separatedBy: [w newColumn]].
418   w ; ')'.
419   True
422 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Block traits)
424   (w treatAsSimpleNode: node)
425     ifTrue:
426       [w ; '['.
427        w printVariablesOf: node.
428        w indentedDo:
429          [w printStatements: node statements &separatedBy: [w newColumn]].
430        w ; ']']
431     ifFalse: [resend].
432   True
435 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Array traits)
437   (w treatAsSimpleNode: node)
438     ifTrue:
439       [w ; '{'.
440        w indentedDo:
441          [w printStatements: node statements &separatedBy: [w newColumn]].
442        w ; '}']
443     ifFalse: [resend].
444   True