Extending the Pier Parser
Early versions of Pier included the syntax to embed Smalltalk code into a page. This was a nice feature for power users, but caused certain confusion among others. Moreover it also caused potential security issues, when the permissions weren't setup properly. Never the less, as there were some people complaining about the missing feature, I am going to show how to extend Pier and its pluggable parser to support this functionality.
1. Creating a new Node Type
First let's create a new node type, a subclass of PRText:
PRText subclass: #PRCode
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Pier-Executable'
2. Register with the Parser
Let's specify an initializer method on the class side to register it with the parser. We choose a single pipe character as the new markup:
Next we need to implement the hook method #parse: aString markup: aMarkupString with: aParser to parse the string. In our case this is simple as we just want to return a new instance of PRCode with the contents:
3. Plugging into the Visitors
Next we have to make sure that the new node type plays well with the visitor framework:
Now we add the different #visitCode: implementations in specific visitors. First this is the visitor to serialize a parsed node back to Wiki syntax:
PRWikiWriter>>visitCode: anObject
self nextPutAll: anObject class markup.
self nextPutAll: anObject text.
self nextPutAll: anObject class markup
And second, this is the XHTML visitor that should evaluate the code and display it on the resulting output stream:
PRViewRenderer>>visitCode: anObject
html render: (Compiler
evaluate: anObject text
for: self component
logged: false)
That's all for a very basic implementation. Now we can write in any document |TimeStamp current| to embed the current time. Since self refers to the current component, we can embed the current page title into the document by writing: |self context structure title|. Or, you can write Seaside rendering code to create a link that calls the counter example: | [ :html | html anchor callback: [ self call: WACounter new ]; with: 'Start Counter' ] |. The possibilites are endless.
To use the presented code in a productive environment, some error handling has to be added. Propre sandboxing would also be a requirement.