576 lines
14 KiB
Smalltalk
576 lines
14 KiB
Smalltalk
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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'variables' }
|
|
PPCCodeGen >> allocateReturnVariable [
|
|
^ clazz allocateReturnVariableNamed: '__retval'
|
|
|
|
"Created: / 23-04-2015 / 18:03:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
"Modified: / 15-06-2015 / 17:52:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'code structures' }
|
|
PPCCodeGen >> codeIf: condition then: then [
|
|
self codeIf: condition then: then else: nil
|
|
|
|
"Created: / 16-06-2015 / 06:07:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
"Modified: / 16-06-2015 / 06:09:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'code error handling' }
|
|
PPCCodeGen >> codeIfErrorThen: then [
|
|
^ self codeIf: 'error' then: then else: nil
|
|
|
|
"Created: / 16-06-2015 / 06:06:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'code debugging' }
|
|
PPCCodeGen >> codeProfileStart [
|
|
self code: 'context methodInvoked: #', clazz currentMethod methodName, '.'
|
|
|
|
"Created: / 01-06-2015 / 21:17:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'code debugging' }
|
|
PPCCodeGen >> codeProfileStop [
|
|
self code: 'context methodFinished: #', clazz currentMethod methodName, '.'
|
|
|
|
"Created: / 01-06-2015 / 21:19:11 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
"Modified: / 01-06-2015 / 21:49:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
"Modified: / 01-06-2015 / 21:48:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 [
|
|
<gtInspectorPresentationOrder: 40>
|
|
|
|
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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'support' }
|
|
PPCCodeGen >> startInline: id [
|
|
^ clazz startInline: id
|
|
|
|
"Modified: / 01-06-2015 / 21:48:35 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #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 <jan.vrany@fit.cvut.cz>"
|
|
]
|
|
|
|
{ #category : 'support' }
|
|
PPCCodeGen >> stopMethod [
|
|
^ clazz stopInline
|
|
|
|
"Modified: / 01-06-2015 / 21:38:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
|
|
]
|