[[PageOutline(1-2)]] = Macro Support for Squeak = Macros is a framework which provides compile-time macros for Squeak. It is primarily focused on macros that need to generate additional methods or check constraints. Basic integration with !OmniBrowser and the Squeak Debugger is provided. Already exemplarily implemented use-cases are: * optional parameters * protocol delegation * automatically created setters and getters * immutable classes * sealed classes * ... = How to Install = {{{ #!div class="wiki_infotable" style="float:right;" ||'''Environment'''|| || || [[Image(media/icons/custom:squeak_16.png, title="Recommended Squeak Version", nolink, right)]] || 4.1, 4.2 || || [[Image(media/icons/silk:application_home.png, title="Recommended Squeak VM Version", nolink, right)]] || Any || || [[Image(media/icons/silk:cog.png, title="Recommended Cog VM Version", nolink, right)]] || Any || ||'''Sources'''|| || || [[Image(media/icons/silk:script_gear.png, title="Metacello Configuration", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/MetacelloRepository/ ConfigurationOfMacros] || || [[Image(media/icons/silk:database.png, title="Repository", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/macros/ Macros] || || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `CTM` || || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `CTMOB` ^optional^ || || [[Image(media/icons/silk:bullet_go.png, title="Dependents", nolink, right)]] || [http://www.squeaksource.com/OmniBrowser.html OmniBrowser] ^optional^ || ||'''Misc'''|| || || [[Image(media/icons/silk:world.png, title="Website", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/macros.html Macros@SqueakSource] || }}} Use the Metacello configuration or just load the `CTM` package (''CTM'' stands for ''compile-time metaprogramming''). If you also want !OmniBrowser support, load the `CTMOB` package, too. You can find the following categories in the packages: `CTM-Core`:: core implemenation including the event listener `CTM-Operations`:: supported operations, currently those for methods `CTM-Tests`:: some basic tests, all should pass `CTM-Examples`:: basic macros, see the class documentation of each for details `CTMOB`:: !OmniBrowser support {{{ #!div style="clear:both;" }}} = How to Use = == Applying Macros == To apply macros, just add pragmas to methods and classes. Method pragmas are added in the usual way, between the signature line and the code; class pragmas are added by placing them above the `subclass:` call in the class definition window. Examples: {{{ withAll: aNumberArray ^ self new addAll: aNumberArray }}} {{{ Object subclass: #Klasse1 instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Playground' }}} == Creating New Macros == To create a macro you have to subclass the {{{CTMMacro}}} class. The first thing to do is to decide on which pragmas the macro should listen. You need to implement at least one of those two methods: `matchMethodPragma:` ''aPragma'':: This should return true if the macro wants to process a method annotated with ''aPragma'' or false otherwise. Additionally the method can be used to store additional information that are found in the pragma, e.g. pragma parameters. `matchClassPragma:` ''aPragma'':: Same as `matchMethodPragma:` but for classes and their pragmas. Depending on the use-case and the decision you made above, implement one or more of the following methods which are called when an event in a relevant entity occurs: `methodAdded:` ''aMethod'' `in:` ''aClass'':: `methodCompiled:` ''aCompiledMethod'' `in:` ''aClass'' `from:` ''anOldCompiledMethodOrNil'':: `methodModified:` ''aMethod'' `in:` ''aClass'' `from:` ''anOldMethod'':: `methodRemoved:` ''aMethod'' `in:` ''aClass'':: Those are called if a method event occurred. `classAdded:` ''aClass'':: `classCompiled:` ''aClass'' `from:` ''anOldClassOrNil'':: `classModified:` ''aClass'' `from:` ''anOldClass'':: `classRemoved:` ''aClass'':: Those are called if a class event occurred. To perform actions on the classes and methods related to the entity in the event, the methods should return a collection of `CTMOperation` elements. At this time, only method operations are implemented. You can add methods to classes or remove them using the following operation constructors: `CTMMethodOperation class>>add:` ''aSelector'' `in:` ''aClass'' `for:` ''aClassOrMethod'' `with:` ''aSourceString'':: returns an operation to add a method to a class, the parameters should be self-explanatory `CTMMethodOperation class>>remove:` ''aSelector'' `in:` ''aClass'':: removes a method from a class in the same way See the `CTM-Examples` category for some macro implementations. = Some Hints = * Our macros implementation and its ''operations'' system ensure that (a) your hand-written code will never be overridden, (b) you cannot change generated methods and (c) you cannot apply macros that would break (a). * The debugger normally steps through generated methods. They will still appear on the stack though. If you want to step into a generated method, hold Shift while clicking on ''Step Into''. * Monticello cannot see generated methods. This is a design decision to simplify cooperative work on a code base and to prevent merge decisions resulting in inconsistent states. * When you use class pragmas, those classes might not be loadable in a Squeak system without the macro system. However, it will not affect classes not using class pragmas. = How to Extend = For starters, be aware that some of the components are deeply integrated with the Squeak system. There is a significant number of override and extension methods. The basic control flow is as follows: [[BR]] The `CTMEventListener` singleton is registered as a listener for all system events. Its `event:` method dispatches the events to `methodEvent:` and `classEvent:`. Those two methods find a all relevant macros, run them and finally execute the generated operations when no conflicts occurred. One common way to extend the system is to support more kinds of tracked operations. To implement those, you have to subclass `CTMOperation`. Its four methods should be self-explanatory. = Acknowledgments = [[Image(media/icons/silk:user.png, nolink)]] To date, the following people contributed to this project: * Michael Grünewald * Stefan Richter