142 ]. |
154 ]. |
143 ^ variableName, ':= context remember.' |
155 ^ variableName, ':= context remember.' |
144 ! |
156 ! |
145 |
157 |
146 smartRestore: parser |
158 smartRestore: parser |
|
159 self flag: 'deprecated'. |
147 ^ self smartRestore: parser from: #memento |
160 ^ self smartRestore: parser from: #memento |
148 ! |
161 ! |
149 |
162 |
150 smartRestore: parser from: mementoName |
163 smartRestore: parser from: mementoName |
151 parser isContextFree ifTrue: [ |
164 parser isContextFree ifTrue: [ |
152 ^ 'context lwRestore: ', mementoName, '.'. |
165 ^ 'context lwRestore: ', mementoName, '.'. |
153 ]. |
166 ]. |
154 ^ 'context restore: ', mementoName, '.'. |
167 ^ 'context restore: ', mementoName, '.'. |
155 ! ! |
168 ! ! |
156 |
169 |
|
170 !PPCCompiler methodsFor:'code generation - coding'! |
|
171 |
|
172 codeAssign: code to: variable |
|
173 self assert: variable isNil not. |
|
174 |
|
175 "TODO JK: Hack alert, whatever is magic constant!!" |
|
176 (variable == #whatever) ifFalse: [ |
|
177 "Do not assign, if somebody does not care!!" |
|
178 self add: variable ,' := ', code. |
|
179 ] ifTrue: [ |
|
180 "In case code hava a side effect" |
|
181 self add: code |
|
182 ] |
|
183 ! |
|
184 |
|
185 codeClearError |
|
186 self add: 'self clearError.'. |
|
187 ! |
|
188 |
|
189 codeError: errorMessage |
|
190 self add: 'self error: ''', errorMessage, '''.' |
|
191 ! |
|
192 |
|
193 codeHalt |
|
194 self add: 'self halt. ' |
|
195 ! |
|
196 |
|
197 codeReturn |
|
198 currentMethod isInline ifTrue: [ |
|
199 "If inlined, the return variable already holds the value" |
|
200 ] ifFalse: [ |
|
201 self add: '^ ', currentMethod returnVariable |
|
202 ]. |
|
203 |
|
204 "Created: / 23-04-2015 / 18:01:05 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
205 "Modified: / 23-04-2015 / 20:51:41 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
206 ! |
|
207 |
|
208 codeReturn: code |
|
209 " - returns whatever is in code OR |
|
210 - assigns whatever is in code into the returnVariable" |
|
211 currentMethod isInline ifTrue:[ |
|
212 self codeAssign: code to: currentMethod returnVariable. |
|
213 ] ifFalse: [ |
|
214 self add: '^ ', code |
|
215 ] |
|
216 |
|
217 "Created: / 23-04-2015 / 18:01:05 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
218 "Modified: / 23-04-2015 / 20:51:41 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
219 ! |
|
220 |
|
221 codeStoreValueOf: aBlock intoVariable: aString |
|
222 | tmpVarirable method | |
|
223 self assert: aBlock isBlock. |
|
224 self assert: aString isNil not. |
|
225 |
|
226 tmpVarirable := returnVariable. |
|
227 returnVariable := aString. |
|
228 method := [ |
|
229 aBlock value |
|
230 ] ensure: [ |
|
231 returnVariable := tmpVarirable |
|
232 ]. |
|
233 |
|
234 method isInline ifTrue: [ |
|
235 self callOnLine: method |
|
236 ] ifFalse: [ |
|
237 self codeAssign: (method call) to: aString. |
|
238 ] |
|
239 |
|
240 "Created: / 23-04-2015 / 18:21:51 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
241 ! ! |
|
242 |
157 !PPCCompiler methodsFor:'code generation - ids'! |
243 !PPCCompiler methodsFor:'code generation - ids'! |
|
244 |
|
245 idFor: object |
|
246 self assert: (object isKindOf: PPCNode). |
|
247 ^ self idFor: object prefixed: object prefix suffixed: object suffix effect: #none |
|
248 ! |
158 |
249 |
159 idFor: object prefixed: prefix |
250 idFor: object prefixed: prefix |
160 ^ self idFor: object prefixed: prefix effect: #none |
251 ^ self idFor: object prefixed: prefix effect: #none |
161 ! |
252 ! |
162 |
253 |
163 idFor: object prefixed: prefix effect: effect |
254 idFor: object prefixed: prefix effect: effect |
164 ^ self idFor: object prefixed: prefix suffixed: '' effect: effect. |
255 ^ self idFor: object prefixed: prefix suffixed: '' effect: effect. |
165 ! |
256 ! |
166 |
257 |
167 idFor: object prefixed: prefix suffixed: suffix effect: effect |
258 idFor: object prefixed: prefix suffixed: suffix effect: effect |
168 | body id | |
259 | name id | |
169 |
|
170 "Halt if: [ (object isKindOf: PPCNode) and: [object name = #smalltalk_ws ] ]." |
|
171 |
|
172 " ((object isKindOf: PPCNode) and: [object name = #smalltalk_ws ]) ifTrue: [ Transcript crShow: 'st_ws' ]. |
|
173 " |
|
174 ^ ids at: object ifAbsentPut: [ |
260 ^ ids at: object ifAbsentPut: [ |
175 ((object isKindOf: PPCNode) and: [object name isNotNil]) ifTrue: [ |
261 ((object isKindOf: PPCNode) and: [object name isNotNil]) ifTrue: [ |
176 "Halt if: [ object name = #smalltalk_ws ]." |
262 "Do not use prefix, if there is a name" |
177 " (object name = #smalltalk_ws) ifTrue: [Transcript crShow: 'NEW st_ws']. |
263 name := object name asLegalSelector. |
178 " |
264 id := (name, suffix) asSymbol. |
179 id := (object name, suffix) asSymbol. |
265 |
180 "Make sure, that the generated ID is uniqe!!" |
266 "Make sure, that the generated ID is uniqe!!" |
181 ((ids values select: [ :e | e = id ]) isEmpty) ifTrue: [ id ] |
267 (ids includes: id) ifTrue: [ |
182 ifFalse: [ |
268 (id, '_', ids size asString) asSymbol |
183 body := ids size asString. |
269 ] ifFalse: [ |
184 (id, '_', body) asSymbol |
270 id |
185 ] |
271 ] |
186 ] ifFalse: [ |
272 ] ifFalse: [ |
187 body := ids size asString. |
273 (prefix, '_', (ids size asString), suffix) asSymbol |
188 (prefix asString, '_', body, suffix) asSymbol |
|
189 ] |
274 ] |
190 ] |
275 ] |
191 ! ! |
276 ! ! |
192 |
277 |
193 !PPCCompiler methodsFor:'code generation - support'! |
278 !PPCCompiler methodsFor:'code generation - support'! |
224 |
311 |
225 "Modified: / 21-11-2014 / 12:27:18 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
312 "Modified: / 21-11-2014 / 12:27:18 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
226 ! |
313 ! |
227 |
314 |
228 startInline: id |
315 startInline: id |
229 | sender | |
316 (cache includesKey: id) ifTrue: [ self error: 'OOOUPS!!' ]. |
230 |
317 |
231 currentMethod := PPCInlinedMethod new. |
318 currentMethod := PPCInlinedMethod new. |
232 currentMethod id: id. |
319 currentMethod id: id. |
233 currentMethod profile: self profile. |
320 currentMethod profile: arguments profile. |
|
321 currentMethod returnVariable: returnVariable. |
234 self push. |
322 self push. |
235 |
323 |
236 |
324 "Modified: / 23-04-2015 / 18:28:26 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
237 sender := thisContext sender receiver. |
|
238 self addComment: 'START inlining by ', sender asString. |
|
239 ! |
325 ! |
240 |
326 |
241 startMethod: id |
327 startMethod: id |
242 | sender | |
|
243 (cache includesKey: id) ifTrue: [ self error: 'OOOUPS!!' ]. |
328 (cache includesKey: id) ifTrue: [ self error: 'OOOUPS!!' ]. |
244 |
329 |
245 currentMethod := PPCMethod new. |
330 currentMethod := PPCMethod new. |
246 currentMethod id: id. |
331 currentMethod id: id. |
247 currentMethod profile: self profile. |
332 currentMethod profile: arguments profile. |
248 self push. |
333 self push. |
249 |
334 |
250 self cache: id as: currentMethod. |
335 self cache: id as: currentMethod. |
251 |
336 |
252 sender := thisContext sender receiver. |
337 "Modified: / 23-04-2015 / 18:36:23 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
253 self addComment: 'START of method generated by ', sender asString. |
|
254 ! |
338 ! |
255 |
339 |
256 stopInline |
340 stopInline |
257 | sender | |
341 |
258 sender := thisContext sender receiver. |
|
259 self addComment: 'STOP inlining by ', sender asString. |
|
260 ^ self pop. |
342 ^ self pop. |
|
343 |
|
344 "Modified: / 23-04-2015 / 18:28:33 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
261 ! |
345 ! |
262 |
346 |
263 stopMethod |
347 stopMethod |
264 | sender | |
|
265 sender := thisContext sender receiver. |
|
266 self addComment: 'END of method generated by ', sender asString. |
|
267 |
|
268 self cache: currentMethod methodName as: currentMethod. |
348 self cache: currentMethod methodName as: currentMethod. |
|
349 |
|
350 arguments profile ifTrue: [ Transcript crShow: currentMethod code ]. |
269 ^ self pop. |
351 ^ self pop. |
|
352 |
|
353 "Modified: / 23-04-2015 / 18:36:55 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
270 ! |
354 ! |
271 |
355 |
272 top |
356 top |
273 ^ compilerStack top |
357 ^ compilerStack top |
274 ! ! |
358 ! ! |
275 |
359 |
|
360 !PPCCompiler methodsFor:'code generation - variables'! |
|
361 |
|
362 allocateReturnVariable |
|
363 "Return a new variable to store parsed value" |
|
364 |
|
365 ^ currentMethod allocateReturnVariable |
|
366 |
|
367 "Created: / 23-04-2015 / 17:58:00 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
368 "Modified (comment): / 23-04-2015 / 21:12:57 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
369 ! |
|
370 |
|
371 allocateTemporaryVariableNamed: preferredName |
|
372 "Allocate a new variable with (preferably) given name. |
|
373 Returns a real variable name that should be used." |
|
374 |
|
375 ^ self currentNonInlineMethod allocateTemporaryVariableNamed: preferredName |
|
376 |
|
377 "Created: / 23-04-2015 / 17:33:31 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
378 ! ! |
|
379 |
276 !PPCCompiler methodsFor:'compiling'! |
380 !PPCCompiler methodsFor:'compiling'! |
277 |
381 |
278 compile: aPPParser as: name |
382 compileParser |
279 ^ self compile: aPPParser as: name params: #() |
383 self installVariables. |
280 ! |
384 self installMethods. |
281 |
385 self installClassConstants. |
282 compile: aPPParser as: name params: params |
386 |
283 | parser | |
387 ^ compiledParser |
284 parser := self copy: aPPParser. |
388 ! |
285 parser := self toCompilerTree: parser. |
389 |
286 parser := self optimize: parser params: params. |
390 copy: parser |
287 parser := self compileTree: parser as: name parser: aPPParser params: params. |
391 ^ parser transform: [ :p | p copy ]. |
288 ^ parser |
392 ! |
289 |
393 |
290 ! |
394 installClassConstants |
291 |
395 constants keysAndValuesDo: [ :key :value | |
292 compileTree: compilerTree as: name parser: parser params: params |
396 compiledParser constants at: key put: value |
293 | | |
397 ] |
294 params do: [ :p | |
398 ! |
295 (p key = #guards) ifTrue: [ self guards: p value ]. |
399 |
296 ]. |
400 installMethods |
297 |
401 cache keysAndValuesDo: [ :key :method | |
298 |
402 compiledParser compileSilently: method code classified: 'generated'. |
|
403 ] |
|
404 ! |
|
405 |
|
406 installVariables |
|
407 | varString | |
|
408 varString := constants keys inject: '' into: [:r :e | r, ' ', e ]. |
|
409 |
|
410 PPCompiledParser |
|
411 subclass: compiledParserName |
|
412 instanceVariableNames: varString |
|
413 classVariableNames: '' |
|
414 poolDictionaries: '' |
|
415 category: 'PetitCompiler-Generated'. |
|
416 |
|
417 compiledParser := Smalltalk at: compiledParserName. |
|
418 ! |
|
419 |
|
420 precomputeFirstSets: root |
|
421 | firstSets | |
|
422 firstSets := root firstSets. |
|
423 |
|
424 root allNodesDo: [ :node | |
|
425 node firstSet: (firstSets at: node). |
|
426 ] |
|
427 |
|
428 ! |
|
429 |
|
430 precomputeFollowSets: root |
|
431 | followSets | |
|
432 followSets := root followSets. |
|
433 |
|
434 root allNodesDo: [ :node | |
|
435 node followSet: (followSets at: node). |
|
436 ] |
|
437 |
|
438 ! |
|
439 |
|
440 precomputeFollowSetsWithTokens: root |
|
441 | followSets | |
|
442 followSets := root followSetsSuchThat: [:e | e isTerminal or: [ e isKindOf: PPCTrimmingTokenNode ]]. |
|
443 |
|
444 root allNodesDo: [ :node | |
|
445 node followSetWithTokens: (followSets at: node). |
|
446 ] |
|
447 |
|
448 ! |
|
449 |
|
450 toCompilerTree: parser |
|
451 ^ parser asCompilerTree |
|
452 ! ! |
|
453 |
|
454 !PPCCompiler methodsFor:'initialization'! |
|
455 |
|
456 initializeForCompiledClassName: aString |
|
457 |
|
458 self initialize. |
|
459 compilerStack := Stack new. |
|
460 cache := IdentityDictionary new. |
|
461 constants := IdentityDictionary new. |
|
462 ids := IdentityDictionary new. |
|
463 |
|
464 |
|
465 compiledParserName := aString asSymbol. |
|
466 |
299 ((Smalltalk respondsTo:#isSmalltalkX) and:[ Smalltalk isSmalltalkX ]) ifTrue:[ |
467 ((Smalltalk respondsTo:#isSmalltalkX) and:[ Smalltalk isSmalltalkX ]) ifTrue:[ |
300 | rPackageOrganizer | |
468 | rPackageOrganizer | |
301 rPackageOrganizer := Smalltalk at: #RPackageOrganizer. |
469 rPackageOrganizer := Smalltalk at: #RPackageOrganizer. |
302 rPackageOrganizer notNil ifTrue:[ |
470 rPackageOrganizer notNil ifTrue:[ |
303 rPackageOrganizer default registerPackageNamed: 'PetitCompiler-Generated'. |
471 rPackageOrganizer default registerPackageNamed: 'PetitCompiler-Generated'. |
304 ]. |
472 ]. |
305 |
|
306 compiledParser := (Smalltalk at: name ifAbsent: [ nil ]). |
|
307 compiledParser ifNil: [ |
|
308 PPCompiledParser subclass: name |
|
309 instanceVariableNames:'' |
|
310 classVariableNames:'' |
|
311 poolDictionaries:'' |
|
312 category:'PetitCompiler-Generated'. |
|
313 compiledParser := Smalltalk at: name. |
|
314 ] ifNotNil: [ |
|
315 self clean: compiledParser |
|
316 ]. |
|
317 ] ifFalse: [ |
473 ] ifFalse: [ |
318 RPackageOrganizer default registerPackageNamed: 'PetitCompiler-Generated'. |
474 RPackageOrganizer default registerPackageNamed: 'PetitCompiler-Generated'. |
319 compiledParser := (Smalltalk at: name ifAbsent: [ nil ]). |
|
320 compiledParser ifNil: [ |
|
321 PPCompiledParser subclass: name. |
|
322 compiledParser := Smalltalk at: name. |
|
323 compiledParser category: 'PetitCompiler-Generated' |
|
324 ] ifNotNil: [ |
|
325 self clean: compiledParser |
|
326 ]. |
|
327 ]. |
475 ]. |
328 compiledParser constants removeAll. |
476 |
329 |
477 Smalltalk at: compiledParserName ifPresent: [ :class | |
330 rootNode := compilerTree. |
478 compiledParser := class. |
331 self precomputeFirstSets: rootNode. |
479 self clean: compiledParser. |
332 self precomputeFollowSets: rootNode. |
480 ]. |
333 self precomputeFollowSetsWithTokens: rootNode. |
|
334 |
|
335 self startMethod: #start. |
|
336 self add: '^ '. |
|
337 self callOnLine: (compilerTree compileWith: self). |
|
338 self stopMethod. |
|
339 |
|
340 self installVariablesAndMethods. |
|
341 |
|
342 compiledParser referringParser: parser. |
|
343 ^ compiledParser |
|
344 ! |
|
345 |
|
346 copy: parser |
|
347 ^ parser transform: [ :p | p copy ]. |
|
348 ! |
|
349 |
|
350 installMethods: class |
|
351 cache keysAndValuesDo: [ :key :method | |
|
352 class compileSilently: method code classified: 'generated'. |
|
353 ] |
|
354 ! |
|
355 |
|
356 installMethodsAndVariables: class |
|
357 self installVariables: class. |
|
358 self installMethods: class. |
|
359 |
|
360 ! |
|
361 |
|
362 installVariables: class |
|
363 | string | |
|
364 string := class constants keys inject: '' into: [:r :e | r, ' ', e ]. |
|
365 PPCompiledParser subclass: class name instanceVariableNames: string classVariableNames: '' poolDictionaries: '' category: 'PetitCompiler-Generated'. |
|
366 ! |
|
367 |
|
368 installVariablesAndMethods |
|
369 "Updates the class and compile generated code" |
|
370 |
|
371 | compiledParserClassName | |
|
372 |
|
373 compiledParserClassName := compiledParser name. |
|
374 self installVariables: compiledParser. |
|
375 "Now we have to refetch the class again. The reason is, that |
|
376 in (at least) Smalltalk/X modyfing a layout of a class results |
|
377 in creating a new class rather than updating an old one and migrating |
|
378 instances. Therefore, to install methods in in correct class, we have |
|
379 to refetch new version from system dictionary. On Pharo it should not harm." |
|
380 compiledParser := Smalltalk at: compiledParserClassName. |
|
381 |
|
382 self installMethods: compiledParser. |
|
383 ! |
|
384 |
|
385 optimize: parser params: params |
|
386 | retval | |
|
387 retval := parser optimizeTree: params. |
|
388 retval checkTree. |
|
389 ^ retval |
|
390 ! |
|
391 |
|
392 precomputeFirstSets: root |
|
393 | firstSets | |
|
394 firstSets := root firstSets. |
|
395 |
|
396 root allNodesDo: [ :node | |
|
397 node firstSet: (firstSets at: node). |
|
398 ] |
|
399 |
|
400 ! |
|
401 |
|
402 precomputeFollowSets: root |
|
403 | followSets | |
|
404 followSets := root followSets. |
|
405 |
|
406 root allNodesDo: [ :node | |
|
407 node followSet: (followSets at: node). |
|
408 ] |
|
409 |
|
410 ! |
|
411 |
|
412 precomputeFollowSetsWithTokens: root |
|
413 | followSets | |
|
414 followSets := root followSetsSuchThat: [:e | e isTerminal or: [ e isKindOf: PPCTrimmingTokenNode ]]. |
|
415 |
|
416 root allNodesDo: [ :node | |
|
417 node followSetWithTokens: (followSets at: node). |
|
418 ] |
|
419 |
|
420 ! |
|
421 |
|
422 toCompilerTree: parser |
|
423 ^ parser asCompilerTree |
|
424 ! ! |
|
425 |
|
426 !PPCCompiler methodsFor:'guard'! |
|
427 |
|
428 guards |
|
429 ^ guards |
|
430 ! |
|
431 |
|
432 guards: aBoolean |
|
433 guards := aBoolean |
|
434 ! ! |
|
435 |
|
436 !PPCCompiler methodsFor:'initialization'! |
|
437 |
|
438 initialize |
|
439 super initialize. |
|
440 compilerStack := Stack new. |
|
441 cache := IdentityDictionary new. |
|
442 ids := Dictionary new. |
|
443 |
|
444 tokenMode := false. |
|
445 inlining := true. |
|
446 profile := false. |
|
447 guards := true. |
|
448 ! ! |
481 ! ! |
449 |
482 |
450 !PPCCompiler class methodsFor:'documentation'! |
483 !PPCCompiler class methodsFor:'documentation'! |
451 |
484 |
452 version_HG |
485 version_HG |