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."
15 w@(Writer traits) indentedDo: block surroundedBy: str1 and: str2
19 w indentedDo: [block do].
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
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."
43 x@(Syntax Node traits) printOn: o
44 "Specialize printOn: for syntax nodes"
46 (Syntax SourceWriter newOn: o) print: x.
50 w@(Syntax SourceWriter traits) print: _@(Syntax ImplicitArgument traits)
51 "The target of implicit message sends to the context. Prints nothing."
54 w@(Syntax SourceWriter traits) print: node@(Syntax nodes Comment traits)
55 "(Optionally) print out the comment on the following line."
59 ifTrue: [w ; '"' ; node comment ; '"'].
64 "w@(Syntax SourceWriter traits) print: node inParenthesesOn: s
73 w@(Syntax SourceWriter traits) print: node@(Syntax Literal traits)
74 [w ; node value printString. ].
76 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _
79 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _@(Syntax Macro traits)
82 w@(Syntax SourceWriter traits) printSelectorPrefixOf: _@(Syntax Deferred traits)
85 w@(Syntax SourceWriter traits) withSurroundingArity: arity do: block
87 previousArity: w surroundingArity.
88 w surroundingArity: arity.
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 |
98 previousArity: w surroundingArity.
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.
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.
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 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:
130 ifTrue: [w printSelectorPrefixOf: node]
131 ifFalse: [w newColumn].
132 w ; ((names at: index - 1) as: String).
134 w printAsArgument: (args at: index)]]].
135 closeParen ifTrue: [w nextPut: $)].
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)
157 ifTrue: [w ; '(' ; node selector printString ; ' applyWith: '
158 ; node arguments printString ; ')']
159 ifFalse: [w print: node sending: node selector to: node arguments].
163 w@(Syntax SourceWriter traits) print: node@(Syntax OptionalKeywords traits)
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 |
176 w printAsArgument: argument]]].
177 closeParen ifTrue: [w ; ')'].
181 w@(Syntax SourceWriter traits) print: node@(Syntax RestArguments traits)
184 w surroundingArity >= 0 ifTrue: [w ; '('. closeParen: True].
185 w withSurroundingArity: -1 do:
186 [w print: node message].
187 w withSurroundingArity: 2 do:
193 w printAsArgument: argument]]].
194 closeParen ifTrue: [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."
203 w@(Syntax SourceWriter traits) isDefaultLastStatement: node@(Syntax Literal traits)
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]].
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)
228 w printStatements: node statements].
233 w@(Syntax SourceWriter traits) print: node@(Syntax Array traits)
241 w@(Syntax SourceWriter traits) print: node@(Syntax Parenthesis traits)
244 w printStatements: node statements.
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)]
258 [node inputVariables do:
261 w ; ':' ; (inputVar name as: String)]].
262 node localVariables do:
264 (node inputVariables includes: localVar) \/ [node optionalVariables includes: localVar]
267 w ; (localVar name as: String)]].
271 w@(Syntax SourceWriter traits) print: node@(Syntax Block traits)
274 w printVariablesOf: node.
279 w@(Syntax SourceWriter traits) printAsStatement: 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:
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."
296 selector: node selector.
297 args: node inputVariables.
299 (Syntax isUnarySelector: selector) /\ [args size = 1]
301 role: (node roles first).
302 w printArg: args first withRole: role.
304 w ; (selector as: String)
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.
312 w ; (selector as: String).
314 w printArg: args second withRole: role1
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
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.
328 w ; ((names at: index - 1) as: String).
331 w printArg: (args at: index) withRole: (node roles at: index)]].
332 node optionalKeywords with: node optionalVariables do: [| :selector :variable |
340 w@(Syntax SourceWriter traits) printAsMethodBody: node@(Syntax Block traits)
344 w printVariablesOf: node &skipInputs: True.
347 w printStatements: node statements].
352 w@(Syntax SourceWriter traits) print: node@(Syntax MethodDefinition traits)
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)
371 w@(Syntax SourceWriter traits) treatAsSimpleNode: node
374 node walk: [| :each | nodeCount: nodeCount + 1. nodeCount > 7 ifTrue: [ ^ False]].
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"
392 w@(Syntax SourceWriter traits) printAsArgument: def@(Syntax MethodDefinition traits)
394 w surroundingArity < 0
395 ifFalse: [w nextPut: $(].
397 w surroundingArity < 0
398 ifFalse: [w nextPut: $)].
402 w@(Syntax SourceWriter traits) printAsArgument: _@(Syntax ImplicitArgument traits)
405 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax CompoundStatement traits)
413 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Parenthesis traits)
417 [w printStatements: node statements &separatedBy: [w newColumn]].
422 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Block traits)
424 (w treatAsSimpleNode: node)
427 w printVariablesOf: node.
429 [w printStatements: node statements &separatedBy: [w newColumn]].
435 w@(Syntax SourceWriter traits) printAsArgument: node@(Syntax Array traits)
437 (w treatAsSimpleNode: node)
441 [w printStatements: node statements &separatedBy: [w newColumn]].