Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Compiler plugin implementation #8114

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/OpalCompiler-Core/OCASTCompilerPlugin.class.st
@@ -0,0 +1,50 @@
"
I am an abtract superclass for compiler plugins.

The compiler consists of multiple passes:

source
- [ Scanner/Parser ] ->
AST
- [ SemCheck ] ->
AST <<HERE>>
- [ ASTTranslator ] ->
IR
- [ IRBuilder ] ->
CompiledMethod


These plugins are called <<HERE>>, that is, after semantic analysis before generating the IR.
They are sorted by #priority and handed the AST without making a copy (as plugins might just analyse the AST).

IMPORTANT: If you modify the AST, you have to make a copy before!
"
Class {
#name : #OCASTCompilerPlugin,
#superclass : #Object,
#category : #'OpalCompiler-Core-Plugins'
}

{ #category : #'accessing - defaults' }
OCASTCompilerPlugin class >> defaultPriority [
"Use a high priority by default (a priority of 0 would be used by Reflectivity to be the last)"

^ 100
]

{ #category : #testing }
OCASTCompilerPlugin class >> isAbstract [

^ self = OCASTCompilerPlugin
]

{ #category : #accessing }
OCASTCompilerPlugin >> priority [
^self class defaultPriority
]

{ #category : #transforming }
OCASTCompilerPlugin >> transform: ast [

self subclassResponsibility
]
62 changes: 0 additions & 62 deletions src/OpalCompiler-Core/OCCompilerASTPlugin.class.st

This file was deleted.

52 changes: 0 additions & 52 deletions src/OpalCompiler-Core/OCCompilerDynamicASTPlugin.class.st

This file was deleted.

75 changes: 75 additions & 0 deletions src/OpalCompiler-Core/OCDynamicASTCompilerPlugin.class.st
@@ -0,0 +1,75 @@
"
Look at the `OCASTCompilerPlugin` class comment for information about compiler plugins.

I allow the dynamic creation of compiler plugins.

Instantiate me using either
- `newFromTransformBlock: aBlock andPriority: aPriority` - _to get a compiler plugin with custom transformation block and priority_ or
- `newFromTransformBlock: aBlock` - _to get a compiler plugin with custom transformation block and default high priority_

You can then add the new plugin to an OpalCompiler instance with OpalCompiler>>addPlugin:

- aBlock must be a block of the form [ :ast | do something to ast ] that returns the modified ast.
- aPriority is the priority the created plugin should have

Check out my test class (`OCASTDynamicCompilerPluginTest`) for a usage example.
"
Class {
#name : #OCDynamicASTCompilerPlugin,
#superclass : #OCASTCompilerPlugin,
#instVars : [
'priority',
'transformBlock'
],
#category : #'OpalCompiler-Core-Plugins'
}

{ #category : #'instance creation' }
OCDynamicASTCompilerPlugin class >> newFromTransformBlock: aBlock [
"Return a new instance of the receiver using the given AST transformation block and default priority."

^ self new
transformBlock: aBlock;
yourself
]

{ #category : #'instance creation' }
OCDynamicASTCompilerPlugin class >> newFromTransformBlock: aBlock andPriority: aPriority [
"Return a new instance of the receiver using the given AST transformation block and the given priority."

^ (self newFromTransformBlock: aBlock)
priority: aPriority;
yourself
]

{ #category : #initialization }
OCDynamicASTCompilerPlugin >> initialize [

super initialize.
self priority: self class defaultPriority
]

{ #category : #accessing }
OCDynamicASTCompilerPlugin >> priority [
^ priority
]

{ #category : #accessing }
OCDynamicASTCompilerPlugin >> priority: anObject [
priority := anObject
]

{ #category : #transforming }
OCDynamicASTCompilerPlugin >> transform: ast [
^ transformBlock value: ast copy
]

{ #category : #accessing }
OCDynamicASTCompilerPlugin >> transformBlock [
^ transformBlock
]

{ #category : #accessing }
OCDynamicASTCompilerPlugin >> transformBlock: anObject [
transformBlock := anObject
]
53 changes: 53 additions & 0 deletions src/OpalCompiler-Core/OCStaticASTCompilerPlugin.class.st
@@ -0,0 +1,53 @@
"
I am an abtract superclass for AST based compiler plugins providing a static transformation of an AST


"
Class {
#name : #OCStaticASTCompilerPlugin,
#superclass : #OCASTCompilerPlugin,
#instVars : [
'ast'
],
#category : #'OpalCompiler-Core-Plugins'
}

{ #category : #testing }
OCStaticASTCompilerPlugin class >> isAbstract [

^ self = OCStaticASTCompilerPlugin
]

{ #category : #'instance creation' }
OCStaticASTCompilerPlugin class >> transform: anAST [
"Return a new instance of the receiver transforming the given AST"

^self new transform: anAST
]

{ #category : #accessing }
OCStaticASTCompilerPlugin >> ast: anAST [
ast := anAST
]

{ #category : #utilities }
OCStaticASTCompilerPlugin >> copyAST [
"Utility method to make a copy of the AST before manipulating it"

ast := ast copy
]

{ #category : #'private - transforming' }
OCStaticASTCompilerPlugin >> transform [
"Subclasses override this method to actually provide the AST transformation.
IMPORTANT: If you modify the AST, make sure to copy it before using #copyAST!"

self subclassResponsibility
]

{ #category : #transforming }
OCStaticASTCompilerPlugin >> transform: anAST [
ast := anAST.
self transform.
^ast
]
6 changes: 3 additions & 3 deletions src/OpalCompiler-Tests/ASTPluginMeaningOfLife.class.st
Expand Up @@ -5,7 +5,7 @@ I replace 42 with a 'meaning of life'.
"
Class {
#name : #ASTPluginMeaningOfLife,
#superclass : #OCCompilerASTPlugin,
#superclass : #OCStaticASTCompilerPlugin,
#category : #'OpalCompiler-Tests-Plugins'
}

Expand All @@ -18,8 +18,8 @@ ASTPluginMeaningOfLife class >> priority [
ASTPluginMeaningOfLife >> transform [
| rule |
"copy the AST as we modify it"
ast := ast copy.
"we use the RBParseTreeRewriter to do the change, anothe option is to do it directly using
self copyAST.
"we use the RBParseTreeRewriter to do the change, another option is to do it directly using
e.g #replaceWith:"
rule := RBParseTreeRewriter replaceLiteral: 42 with: 'meaning of life'.
rule executeTree: ast.
Expand Down
19 changes: 0 additions & 19 deletions src/OpalCompiler-Tests/ASTTransformationPluginTest.class.st

This file was deleted.

19 changes: 0 additions & 19 deletions src/OpalCompiler-Tests/OCCompilerDynamicASTPluginTest.class.st

This file was deleted.

28 changes: 28 additions & 0 deletions src/OpalCompiler-Tests/OCDynamicASTCompilerPluginTest.class.st
@@ -0,0 +1,28 @@
Class {
#name : #OCDynamicASTCompilerPluginTest,
#superclass : #TestCase,
#category : #'OpalCompiler-Tests-Plugins'
}

{ #category : #tests }
OCDynamicASTCompilerPluginTest >> testCreateAndUseDynamicCompilerPlugin [
| result plugin |
plugin := OCDynamicASTCompilerPlugin
newFromTransformBlock: [ :ast | (RBParseTreeRewriter replaceLiteral: 42 with: 'meaning of life') executeTree: ast. ast ]
andPriority: 0.

"Use plugin with compiler"
result := Object compiler
addPlugin: plugin;
evaluate: '42'.

self assert: result equals: 'meaning of life'
]

{ #category : #tests }
OCDynamicASTCompilerPluginTest >> testCreateDynamicCompilerPluginWithDefaultPriority [

| plugin |
plugin := OCDynamicASTCompilerPlugin newFromTransformBlock: [ :ast | ast ].
self assert: plugin priority equals: OCDynamicASTCompilerPlugin defaultPriority
]