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."
15 w@(IndentedPrintStream traits) indentedDo: block surroundedBy: str1 and: str2
19 w indentedDo: [block do].
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
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."
43 x@(nodes Node traits) printOn: o
44 "Specialize printOn: for syntax nodes"
46 (SourcePrintStream newOn: o) print: x.
50 w@(SourcePrintStream traits) print: _@(nodes ImplicitArgument traits)
51 "The target of implicit message sends to the context. Prints nothing."
54 w@(SourcePrintStream traits) print: node@(nodes Comment traits)
55 "(Optionally) print out the comment on the following line."
59 ifTrue: [w ; '"' ; node comment ; '"'].
64 "w@(SourcePrintStream traits) print: node inParenthesesOn: s
73 w@(SourcePrintStream traits) print: node@(nodes Literal traits)
74 [w ; node value printString. ].
76 w@(SourcePrintStream traits) printSelectorPrefixOf: _
79 w@(SourcePrintStream traits) printSelectorPrefixOf: _@(nodes Macro traits)
82 w@(SourcePrintStream traits) printSelectorPrefixOf: _@(nodes Deferred traits)
85 w@(SourcePrintStream traits) withSurroundingArity: arity do: block
87 previousArity := w surroundingArity.
88 w surroundingArity := arity.
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 |
98 previousArity := w surroundingArity.
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.
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.
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
121 [Syntax isKeywordSelector: selector]
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:
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: $\)].
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)
156 ifTrue: [w ; '(' ; node selector printString ; ' applyWith: '
157 ; node arguments printString ; ')']
158 ifFalse: [w print: node sending: node selector to: node arguments].
162 w@(SourcePrintStream traits) print: node@(nodes MessageWrapper traits)
164 w print: node message
167 w@(SourcePrintStream traits) print: node@(nodes OptionalKeywords traits)
170 w surroundingArity >= 0 ifTrue: [w ; '('. closeParen := True].
171 w withSurroundingArity: -1 do:
173 w withSurroundingArity: 2 do:
174 [node keywords with: node arguments do:
175 [| :selector :argument |
180 w printAsArgument: argument]]].
181 closeParen ifTrue: [w ; ')'].
185 w@(SourcePrintStream traits) print: node@(nodes RestArguments traits)
188 w surroundingArity >= 0 ifTrue: [w ; '('. closeParen := True].
189 w withSurroundingArity: -1 do:
191 w withSurroundingArity: 2 do:
197 w printAsArgument: argument]]].
198 closeParen ifTrue: [w ; ')'].
202 w@(SourcePrintStream traits) print: node@(nodes Placeholder traits)
207 w@(SourcePrintStream traits) print: node@(nodes Pattern traits)
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."
219 w@(SourcePrintStream traits) isDefaultLastStatement: node@(nodes Literal traits)
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]].
235 w@(SourcePrintStream traits) printAsRole: node
237 w withSurroundingArity: 0 do: [w print: node].
240 w@(SourcePrintStream traits) print: node@(nodes CompoundStatement traits)
244 w printStatements: node statements].
249 w@(SourcePrintStream traits) print: node@(nodes Array traits)
257 w@(SourcePrintStream traits) print: node@(nodes Parenthesis traits)
260 w printStatements: node statements.
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)]
274 [node inputVariables do:
277 w ; ':' ; (inputVar name as: String)]].
278 node localVariables do:
280 (node inputVariables includes: localVar) \/ [node optionalVariables includes: localVar]
283 w ; (localVar name as: String)]].
287 w@(SourcePrintStream traits) print: node@(nodes Block traits)
290 w printVariablesOf: node.
295 w@(SourcePrintStream traits) printAsStatement: node
300 w@(SourcePrintStream traits) printArg: arg withRole: role
302 w ; (arg name as: String).
303 (role is: nodes Literal) /\ [role value == NoRole] ifFalse:
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."
312 selector := node selector.
313 args := node inputVariables.
316 [(Syntax isUnarySelector: selector) /\ [args size = 1]]
317 -> [w printArg: args first withRole: node roles first.
320 [(Syntax isBinarySelector: selector) /\ [args size = 2]]
321 -> [w printArg: args first withRole: node roles first.
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
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:
338 w ; ((keywords at: index - 1) as: String) ; ':'.
340 w printArg: (args at: index) withRole: (node roles at: index)]]).
341 node optionalKeywords with: node optionalVariables do:
342 [| :selector :variable |
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)
360 w printVariablesOf: node &skipInputs: True.
363 w printStatements: node statements].
368 w@(SourcePrintStream traits) print: node@(nodes MethodDefinition traits)
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)
387 w@(SourcePrintStream traits) treatAsSimpleNode: node
390 node walk: [| :each | (nodeCount += 1) > 7 ifTrue: [^ False]].
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"
408 w@(SourcePrintStream traits) printAsArgument: def@(nodes MethodDefinition traits)
410 w surroundingArity isNegative
413 w surroundingArity isNegative
418 w@(SourcePrintStream traits) printAsArgument: _@(nodes ImplicitArgument traits)
421 w@(SourcePrintStream traits) printAsArgument: node@(nodes CompoundStatement traits)
429 w@(SourcePrintStream traits) printAsArgument: node@(nodes Parenthesis traits)
433 [w printStatements: node statements &separatedBy: [w newColumn]].
438 w@(SourcePrintStream traits) printAsArgument: node@(nodes Block traits)
440 (w treatAsSimpleNode: node)
443 w printVariablesOf: node.
445 [w printStatements: node statements &separatedBy: [w newColumn]].
451 w@(SourcePrintStream traits) printAsArgument: node@(nodes Array traits)
453 (w treatAsSimpleNode: node)
457 [w printStatements: node statements &separatedBy: [w newColumn]].