PetitCommonMark/software/petitcompiler/PPCCodeGen.class.st

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>"
]