Class { #name : 'PPCCodeGen', #superclass : 'Object', #instVars : [ 'clazz', 'options', 'memoizationStrategy' ], #category : 'PetitCompiler-Compiler-Codegen' } { #category : 'instance creation' } PPCCodeGen class >> new [ "return an initialized instance" ^ self on: PPCCompilationOptions new "Modified: / 07-09-2015 / 10:22:49 / Jan Vrany " ] { #category : 'instance creation' } PPCCodeGen class >> on: aPPCArguments [ "return an initialized instance" ^ self basicNew initialize; options: aPPCArguments ] { #category : 'code primitives' } PPCCodeGen >> add: string [ self error: 'deprecated?'. clazz currentMethod add: string. ] { #category : 'code primitives' } PPCCodeGen >> addConstant: value as: name [ clazz addConstant: value as: name ] { #category : 'code primitives' } PPCCodeGen >> addOnLine: string [ self error: 'deprecated'. clazz currentMethod addOnLine: string. ] { #category : 'code primitives' } PPCCodeGen >> addVariable: name [ ^ clazz currentNonInlineMethod addVariable: name "Modified: / 23-04-2015 / 17:34:02 / Jan Vrany " ] { #category : 'variables' } PPCCodeGen >> allocateReturnVariable [ ^ clazz allocateReturnVariableNamed: '__retval' "Created: / 23-04-2015 / 18:03:40 / Jan Vrany " "Modified: / 15-06-2015 / 17:52:56 / Jan Vrany " ] { #category : 'variables' } PPCCodeGen >> allocateReturnVariableNamed: name [ ^ clazz allocateReturnVariableNamed: name ] { #category : 'variables' } PPCCodeGen >> allocateTemporaryVariableNamed: preferredName [ "Allocate a new variable with (preferably) given name. Returns a real variable name that should be used." ^ clazz allocateTemporaryVariableNamed: preferredName "Created: / 23-04-2015 / 17:33:31 / Jan Vrany " ] { #category : 'caching' } PPCCodeGen >> cacheMethod: method as: id [ ^ clazz store: method as: id ] { #category : 'caching' } PPCCodeGen >> cachedMethod: id [ ^ clazz cachedMethod: id ] { #category : 'caching' } PPCCodeGen >> cachedMethod: id ifPresent: aBlock [ ^ clazz cachedMethod: id ifPresent: aBlock ] { #category : 'code primitives' } PPCCodeGen >> call: anotherMethod [ self error: 'deprecated?'. clazz currentMethod add: anotherMethod call. ] { #category : 'code primitives' } PPCCodeGen >> callOnLine: anotherMethod [ self error: 'deprecated?'. clazz currentMethod addOnLine: anotherMethod call. ] { #category : 'accessing' } PPCCodeGen >> clazz [ ^ clazz ] { #category : 'accessing' } PPCCodeGen >> clazz: aPPCClass [ clazz := aPPCClass ] { #category : 'code' } PPCCodeGen >> code: aStringOrBlockOrRBParseNode [ clazz currentMethod code: aStringOrBlockOrRBParseNode "Created: / 01-06-2015 / 23:49:11 / Jan Vrany " ] { #category : 'code' } PPCCodeGen >> codeAssert: aCode [ self code: 'self assert: (', aCode, ').'. ] { #category : 'code assignment' } PPCCodeGen >> codeAssign: stringOrBlock to: variable [ self assert: variable isNil not. stringOrBlock isString ifTrue: [ ^ self codeAssignString: stringOrBlock to: variable ]. (stringOrBlock isKindOf: BlockClosure) ifTrue: [ ^ self codeAssignParsedValueOf: stringOrBlock to: variable ]. self error: 'unknown argument'. ] { #category : 'code assignment' } PPCCodeGen >> codeAssignParsedValueOf:aBlock to: variable [ | method | method := clazz parsedValueOf: aBlock to: variable. method isInline ifTrue:[ self codeCallOnLine:method ] ifFalse:[ self codeAssignString: (method call) to: variable. ] "Created: / 23-04-2015 / 18:21:51 / Jan Vrany " ] { #category : 'code assignment' } PPCCodeGen >> codeAssignString: string to: variable [ self assert: variable isNil not. "TODO JK: Hack alert, whatever is magic constant!" (variable == #whatever) ifFalse: [ "Do not assign, if somebody does not care!" self code: variable ,' := ', string. ] ] { #category : 'code' } PPCCodeGen >> codeBlock: contents [ clazz currentMethod codeBlock: contents "Created: / 01-06-2015 / 22:35:32 / Jan Vrany " ] { #category : 'code' } PPCCodeGen >> codeCall: aMethod [ self assert: (aMethod isKindOf: PPCMethod). self code: aMethod call. ] { #category : 'code' } PPCCodeGen >> codeCallOnLine: aMethod [ self assert: (aMethod isKindOf: PPCMethod). self codeOnLine: aMethod call. ] { #category : 'code error handling' } PPCCodeGen >> codeClearError [ self code: 'error := false.'. ] { #category : 'code debugging' } PPCCodeGen >> codeComment: string [ self code: '"', (string copyReplaceAll: '"' with: '""'), '"'. ] { #category : 'code' } PPCCodeGen >> codeDot [ self codeOnLine: '.'. "Created: / 16-06-2015 / 06:09:07 / Jan Vrany " ] { #category : 'code error handling' } PPCCodeGen >> codeError [ self code: 'self parseError: ''message notspecified''.'. ] { #category : 'code error handling' } PPCCodeGen >> codeError: errorMessage [ | escaped | escaped := (errorMessage copyReplaceAll: '''' with: ''''''). self code: 'self parseError: ''', escaped, '''.' ] { #category : 'code error handling' } PPCCodeGen >> codeError: errorMessage at: position [ | escaped | escaped := (errorMessage copyReplaceAll: '''' with: ''''''). self code: 'self parseError: ''', escaped, ''' at: ', position asString, '.' ] { #category : 'code assignment' } PPCCodeGen >> codeEvaluate: stringOrBlock [ ^ self codeEvaluateAndAssign: stringOrBlock to: #whatever ] { #category : 'code assignment' } PPCCodeGen >> codeEvaluate: selector argument: argument on: variable [ self assert: variable isNil not. "TODO JK: Hack alert, whatever is magic constant!" (variable == #whatever) ifFalse: [ "Do not assign, if somebody does not care!" self code: variable, ' ', selector,' ', argument. ] ifTrue: [ "In case argument has a side effect" self code: argument ] ] { #category : 'code assignment' } PPCCodeGen >> codeEvaluateAndAssign: stringOrBlock to: variable [ "Contrary to codeAssign:to: I always put code onto the stream" stringOrBlock isString ifTrue: [ self codeEvaluateAndAssignString: stringOrBlock to: variable ] ifFalse: [ self assert: (stringOrBlock isKindOf: BlockClosure). self codeEvaluateAndAssignParsedValueOf: stringOrBlock to: variable ] ] { #category : 'code assignment' } PPCCodeGen >> codeEvaluateAndAssignParsedValueOf: aBlock to: variable [ | method | method := clazz parsedValueOf: aBlock to: variable . method isInline ifFalse: [ self codeEvaluateAndAssignString: method call to: variable. ] ifTrue: [ "if inlined, the variable is already filled in, just call it" self code: method call ] ] { #category : 'code assignment' } PPCCodeGen >> codeEvaluateAndAssignString: string to: variable [ "Contrary to codeAssign:to: I always put code onto the stream" self assert: string isString. self assert: variable isNil not. "TODO JK: Hack alert, whatever is magic constant!" (variable == #whatever) ifFalse: [ self codeAssignString: string to: variable ] ifTrue: [ "In case code has a side effect" self code: string. ] ] { #category : 'code debugging' } PPCCodeGen >> codeHalt [ self code: 'self halt. ' ] { #category : 'code debugging' } PPCCodeGen >> codeHaltIfShiftPressed [ options debug ifTrue: [ ((Smalltalk respondsTo: #isSmalltalkX) and:[Smalltalk isSmalltalkX]) ifFalse:[ self code: 'self haltIf:[Sensor shiftPressed].' ] ] "Modified: / 10-05-2015 / 07:39:47 / Jan Vrany " ] { #category : 'code structures' } PPCCodeGen >> codeIf: condition then: then [ self codeIf: condition then: then else: nil "Created: / 16-06-2015 / 06:07:06 / Jan Vrany " ] { #category : 'code structures' } PPCCodeGen >> codeIf: condition then: then else: else [ self code: '('; codeOnLine: condition; codeOnLine: ')'. then notNil ifTrue:[ self codeOnLine:' ifTrue: '; codeBlock: then. ]. else notNil ifTrue:[ self codeOnLine:' ifFalse: '; codeBlock: else. ]. self codeDot. "Created: / 01-06-2015 / 22:43:15 / Jan Vrany " "Modified: / 16-06-2015 / 06:09:33 / Jan Vrany " ] { #category : 'code error handling' } PPCCodeGen >> codeIfErrorThen: then [ ^ self codeIf: 'error' then: then else: nil "Created: / 16-06-2015 / 06:06:44 / Jan Vrany " ] { #category : 'code error handling' } PPCCodeGen >> codeIfErrorThen: then else: else [ ^ self codeIf: 'error' then: then else: else "Created: / 16-06-2015 / 06:05:56 / Jan Vrany " ] { #category : 'code indentation' } PPCCodeGen >> codeIndentPop [ self code: 'context indentStack pop'; codeDot ] { #category : 'code' } PPCCodeGen >> codeNil [ self codeOnLine: 'nil'. ] { #category : 'code' } PPCCodeGen >> codeNl [ self code: ''. ] { #category : 'code' } PPCCodeGen >> codeOnLine:aStringOrBlockOrRBParseNode [ clazz currentMethod codeOnLine: aStringOrBlockOrRBParseNode "Created: / 01-06-2015 / 23:49:11 / Jan Vrany " ] { #category : 'code debugging' } PPCCodeGen >> codeProfileStart [ self code: 'context methodInvoked: #', clazz currentMethod methodName, '.' "Created: / 01-06-2015 / 21:17:19 / Jan Vrany " ] { #category : 'code debugging' } PPCCodeGen >> codeProfileStop [ self code: 'context methodFinished: #', clazz currentMethod methodName, '.' "Created: / 01-06-2015 / 21:19:11 / Jan Vrany " ] { #category : 'code' } PPCCodeGen >> codeReturn [ clazz currentMethod isInline ifTrue: [ "If inlined, the return variable already holds the value" ] ifFalse: [ options profile ifTrue:[ self codeProfileStop. ]. self code: '^ ', clazz currentMethod returnVariable ]. "Created: / 23-04-2015 / 18:01:05 / Jan Vrany " "Modified: / 01-06-2015 / 21:49:04 / Jan Vrany " ] { #category : 'code' } PPCCodeGen >> codeReturn: code [ " - returns whatever is in code OR - assigns whatever is in code into the returnVariable" clazz currentMethod isInline ifTrue:[ self codeEvaluateAndAssign: code to: clazz currentMethod returnVariable. ] ifFalse: [ options profile ifTrue:[ self codeProfileStop. ]. self code: '^ '. self codeOnLine: code ] "Created: / 23-04-2015 / 18:01:05 / Jan Vrany " "Modified: / 01-06-2015 / 21:48:51 / Jan Vrany " ] { #category : 'code' } PPCCodeGen >> codeReturnParsedValueOf: aBlock [ | method | method := clazz parsedValueOf: aBlock to: clazz currentReturnVariable. method isInline ifTrue:[ self codeCallOnLine: method. self codeReturn: clazz currentReturnVariable. ] ifFalse:[ self codeReturn: method call. ] "Created: / 23-04-2015 / 18:21:51 / Jan Vrany " ] { #category : 'code debugging' } PPCCodeGen >> codeTranscriptShow: text [ (options debug) ifTrue: [ self code: 'Transcript show: ', text storeString, '; cr.'. ] ] { #category : 'accessing' } PPCCodeGen >> currentMethod [ ^ clazz currentMethod ] { #category : 'variables' } PPCCodeGen >> currentReturnVariable [ ^ clazz currentReturnVariable ] { #category : 'accessing - options' } PPCCodeGen >> debug [ ^ options debug ] { #category : 'code primitives' } PPCCodeGen >> dedent [ clazz currentMethod dedent ] { #category : 'gt' } PPCCodeGen >> gtCurrentMethod: composite [ composite text title: 'Current Method'; display: [ :codeGen | codeGen clazz currentMethod source ] ] { #category : 'ids' } PPCCodeGen >> idFor: anObject [ ^ clazz idFor: anObject ] { #category : 'ids' } PPCCodeGen >> idFor: anObject defaultName: defaultName [ ^ clazz idFor: anObject defaultName: defaultName ] { #category : 'accessing' } PPCCodeGen >> idGen [ ^ clazz idGen ] { #category : 'accessing' } PPCCodeGen >> idGen: idGenerator [ ^ clazz idGen: idGenerator ] { #category : 'accessing' } PPCCodeGen >> ids [ ^ clazz idGen ids ] { #category : 'code primitives' } PPCCodeGen >> indent [ clazz currentMethod indent ] { #category : 'initialization' } PPCCodeGen >> initialize [ super initialize. clazz := PPCClass new. ] { #category : 'memoization' } PPCCodeGen >> memoizationStrategy [ memoizationStrategy isNil ifTrue: [ memoizationStrategy := (options memoizationStrategy asClass new) codeGen: self; yourself ]. ^ memoizationStrategy ] { #category : 'accessing' } PPCCodeGen >> methodCategory [ ^ 'generated' ] { #category : 'ids' } PPCCodeGen >> numberIdFor: object [ ^ clazz numberIdFor: object ] { #category : 'accessing' } PPCCodeGen >> options: args [ options := args ] { #category : 'code debugging' } PPCCodeGen >> profileTokenRead: tokenName [ options profile ifTrue: [ self code: 'context tokenRead: ', tokenName storeString, '.' ] ] { #category : 'support' } PPCCodeGen >> startInline [ ^ clazz startInline "Modified: / 01-06-2015 / 21:48:35 / Jan Vrany " ] { #category : 'support' } PPCCodeGen >> startInline: id [ ^ clazz startInline: id "Modified: / 01-06-2015 / 21:48:35 / Jan Vrany " ] { #category : 'support' } PPCCodeGen >> startMethod: id [ clazz startMethod: id category: self methodCategory. options profile ifTrue:[ self codeProfileStart. ]. ] { #category : 'support' } PPCCodeGen >> stopInline [ ^ clazz stopInline "Modified: / 01-06-2015 / 21:37:59 / Jan Vrany " ] { #category : 'support' } PPCCodeGen >> stopMethod [ ^ clazz stopInline "Modified: / 01-06-2015 / 21:38:05 / Jan Vrany " ]