Pharo-dev
By thread
pharo-dev@lists.pharo.org
By month
Messages by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
November 2020
- 31 messages
Re: This week (47/2020) on the Issue Tracker
by Noury Bouraqadi
Indeed, posting these emails is useful. It helps keeping us posted about the ongoing progress of Pharo.
I like they are grouped by topic, so it makes easier to get what it's about. Sean's suggestion would indeed understand more. Though I expect it will require more time/effort to write. Moreover, these emails are already long. I'm affraid they'll become way too long.
A solution that mixes both might be posting more often updates. But, again I expect it to be time consuming.
Thanks again Marcus and all Pharo core team,
Noury
On Nov 20 2020, at 5:25 pm, Sean P. DeNigris <sean(a)clipperadams.com> wrote:
> Marcus Denker-4 wrote
> > Question: are these mails interesting? Do they have enough information
> > added to
> > have value?
>
> Yes! Please continue. I like that they are brief because too much detail can
> be overwhelming and we can always ask questions about items that seem
> interesting. IHMO the only extra info worth adding (if there's ever the
> time) is the "why" - motivation and summaries of internal discussions that
> we wouldn't understand just by looking at the commits...
>
>
>
> -----
> Cheers,
> Sean
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
>
Nov. 21, 2020
Re: This week (47/2020) on the Issue Tracker
by Sean P. DeNigris
Marcus Denker-4 wrote
> Question: are these mails interesting? Do they have enough information
> added to
> have value?
Yes! Please continue. I like that they are brief because too much detail can
be overwhelming and we can always ask questions about items that seem
interesting. IHMO the only extra info worth adding (if there's ever the
time) is the "why" - motivation and summaries of internal discussions that
we wouldn't understand just by looking at the commits...
-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
Nov. 20, 2020
Re: This week (47/2020) on the Issue Tracker
by Marcus Denker
Question: are these mails interesting? Do they have enough information added to
have value?
> On 20 Nov 2020, at 11:23, Marcus Denker <marcus.denker(a)inria.fr> wrote:
>
>
> Pharo8
> ======
> HOT-FIX: Support GitHub Personal Access Tokens. This was already merged in
> Pharo9 before.
>
> - Merge Iceberg v1.6.10 in Pharo 8 #7732
> https://github.com/pharo-project/pharo/pull/7732
>
>
> First class Variables
> ================
>
> Work continues: some small improvements (e.g. primitve error variables) and cleanups
>
> - MetaLinks-Cleanup-Variables2 #7742
> https://github.com/pharo-project/pharo/pull/7742
>
> - Variables defined with #primitive:error: are shown as undefined, fixes 7748 #7749
> https://github.com/pharo-project/pharo/pull/7749
>
> - Cleanup-SystemDictionary-varlookup #7746
> https://github.com/pharo-project/pharo/pull/7746
>
> - 7731-OCUndeclaredVariableWarning-isUninitialized-with-NonInteractiveUIManager #7745
> https://github.com/pharo-project/pharo/pull/7745
>
> - DoItVariable instead of ForeignVariable and tests #7710
> https://github.com/pharo-project/pharo/pull/7710
>
>
> ReadOnly Literals
> ==============
>
> Some cleanups... all literals added as literals
> are read only, no special code needed anymore.
>
> - Compiler-compile-all-Literals-readOnly #7631
> https://github.com/pharo-project/pharo/pull/7631
>
> - #isReadOnlyLiteral is not needed anymore #7767
> https://github.com/pharo-project/pharo/pull/7767
>
> - 7740-CI-32bit-testIsImmediateObject #7744
> https://github.com/pharo-project/pharo/pull/7744
>
>
> Graphics
> ========
>
> - Add support for creating OpenGL ES contexts #7750
> https://github.com/pharo-project/pharo/pull/7750
>
> - Disable the dpi based computation screen scale factor computation in OS X #7747
> https://github.com/pharo-project/pharo/pull/7747
>
>
> Small Improvements
> ==================
>
> - 7755 re excessive arguments rule should exclude ffi callouts
> https://github.com/pharo-project/pharo/pull/7757
>
> - ReLiteralArrayContainsCommaRule should ignore all UFFI selectors #7754
> https://github.com/pharo-project/pharo/pull/7754
>
>
> Fixes
> =====
> - Allow catalog json to be served from GitHub and other #7738
> https://github.com/pharo-project/pharo/pull/7738
>
> - Duplicate API from Behavior to RGBehavior. #7743
> https://github.com/pharo-project/pharo/pull/7743
>
>
> Cleanups
> =========
> And lots of small cleanups. As always, these are not important
> in itself as single items. But over time, taking them all together, they do matter.
>
> - Move ReAsClassRule to GeneralRules #7759
> https://github.com/pharo-project/pharo/pull/7759
>
> - 5457-environmentKeyNotFound-looks-deadcode #7773
> https://github.com/pharo-project/pharo/pull/7773
>
> - ObjectsAsMethodsTest-move-to-Kernel-Tests #7762
> https://github.com/pharo-project/pharo/pull/7762
>
> - Typo #7766
> https://github.com/pharo-project/pharo/pull/7766
>
> - DeadCode-Cleanup-Finder #7734
> https://github.com/pharo-project/pharo/pull/7734
>
> - FFICompilerPlugin-Simpler #7726
> https://github.com/pharo-project/pharo/pull/7726
>
> - Small cleanup on ReMissingSuperSendsRule #7761
> https://github.com/pharo-project/pharo/pull/7761
>
> - Typo in RGBehaviorDefinition>>#soleInstance #7752
> https://github.com/pharo-project/pharo/pull/7752
>
> - Another cleanup pass on DoubleLinkedList package #7736
> https://github.com/pharo-project/pharo/pull/7736
>
> - Cleanup System-Support-Tests #7729
> https://github.com/pharo-project/pharo/pull/7729
>
> - BaseStreamTest had just one subclass. Move the tests there and remove⦠#7739
> https://github.com/pharo-project/pharo/pull/7739
>
> - NautilusRefactoring-DeadcodeClean #7723
> https://github.com/pharo-project/pharo/pull/7723
>
> - Introduce package Collections-Sequenceable-Tests #7719
> https://github.com/pharo-project/pharo/pull/7719
>
> - Move-isHaltNode-to-AST #7765
> https://github.com/pharo-project/pharo/pull/7765
Nov. 20, 2020
This week (47/2020) on the Issue Tracker
by Marcus Denker
Pharo8
======
HOT-FIX: Support GitHub Personal Access Tokens. This was already merged in
Pharo9 before.
- Merge Iceberg v1.6.10 in Pharo 8 #7732
https://github.com/pharo-project/pharo/pull/7732
First class Variables
================
Work continues: some small improvements (e.g. primitve error variables) and cleanups
- MetaLinks-Cleanup-Variables2 #7742
https://github.com/pharo-project/pharo/pull/7742
- Variables defined with #primitive:error: are shown as undefined, fixes 7748 #7749
https://github.com/pharo-project/pharo/pull/7749
- Cleanup-SystemDictionary-varlookup #7746
https://github.com/pharo-project/pharo/pull/7746
- 7731-OCUndeclaredVariableWarning-isUninitialized-with-NonInteractiveUIManager #7745
https://github.com/pharo-project/pharo/pull/7745
- DoItVariable instead of ForeignVariable and tests #7710
https://github.com/pharo-project/pharo/pull/7710
ReadOnly Literals
==============
Some cleanups... all literals added as literals
are read only, no special code needed anymore.
- Compiler-compile-all-Literals-readOnly #7631
https://github.com/pharo-project/pharo/pull/7631
- #isReadOnlyLiteral is not needed anymore #7767
https://github.com/pharo-project/pharo/pull/7767
- 7740-CI-32bit-testIsImmediateObject #7744
https://github.com/pharo-project/pharo/pull/7744
Graphics
========
- Add support for creating OpenGL ES contexts #7750
https://github.com/pharo-project/pharo/pull/7750
- Disable the dpi based computation screen scale factor computation in OS X #7747
https://github.com/pharo-project/pharo/pull/7747
Small Improvements
==================
- 7755 re excessive arguments rule should exclude ffi callouts
https://github.com/pharo-project/pharo/pull/7757
- ReLiteralArrayContainsCommaRule should ignore all UFFI selectors #7754
https://github.com/pharo-project/pharo/pull/7754
Fixes
=====
- Allow catalog json to be served from GitHub and other #7738
https://github.com/pharo-project/pharo/pull/7738
- Duplicate API from Behavior to RGBehavior. #7743
https://github.com/pharo-project/pharo/pull/7743
Cleanups
=========
And lots of small cleanups. As always, these are not important
in itself as single items. But over time, taking them all together, they do matter.
- Move ReAsClassRule to GeneralRules #7759
https://github.com/pharo-project/pharo/pull/7759
- 5457-environmentKeyNotFound-looks-deadcode #7773
https://github.com/pharo-project/pharo/pull/7773
- ObjectsAsMethodsTest-move-to-Kernel-Tests #7762
https://github.com/pharo-project/pharo/pull/7762
- Typo #7766
https://github.com/pharo-project/pharo/pull/7766
- DeadCode-Cleanup-Finder #7734
https://github.com/pharo-project/pharo/pull/7734
- FFICompilerPlugin-Simpler #7726
https://github.com/pharo-project/pharo/pull/7726
- Small cleanup on ReMissingSuperSendsRule #7761
https://github.com/pharo-project/pharo/pull/7761
- Typo in RGBehaviorDefinition>>#soleInstance #7752
https://github.com/pharo-project/pharo/pull/7752
- Another cleanup pass on DoubleLinkedList package #7736
https://github.com/pharo-project/pharo/pull/7736
- Cleanup System-Support-Tests #7729
https://github.com/pharo-project/pharo/pull/7729
- BaseStreamTest had just one subclass. Move the tests there and remove⦠#7739
https://github.com/pharo-project/pharo/pull/7739
- NautilusRefactoring-DeadcodeClean #7723
https://github.com/pharo-project/pharo/pull/7723
- Introduce package Collections-Sequenceable-Tests #7719
https://github.com/pharo-project/pharo/pull/7719
- Move-isHaltNode-to-AST #7765
https://github.com/pharo-project/pharo/pull/7765
Nov. 20, 2020
[Pharo 8.0] Build #1142: Merge Iceberg v1.6.10 in Pharo 8
by ci-pharo-ci-jenkins2@inria.fr
There is a new Pharo build available!
The status of the build #1142 was: FAILURE.
The Pull Request #7732 was integrated: "Merge Iceberg v1.6.10 in Pharo 8"
Pull request url: https://github.com/pharo-project/pharo/pull/7732
Issue Url: https://github.com/pharo-project/pharo/issues/merge_iceberg_1_6_10
Build Url: https://ci.inria.fr/pharo-ci-jenkins2/job/Test%20pending%20pull%20request%2…
Nov. 19, 2020
Re: AST Transformation Techniques
by hogoww
Indeed !
I'm going to show you a simplified example here, hopefully it'll be
understandable.
Bit of context, I'm generating code for visitors, from a Famix metamodel.
body := [ :anInstance | ] asPlainCodeBC.
collections do:[:propertyName|
body add: [:anInstance|
  anInstance propertyName
            ifNotNil:[:aCollection| aCollection
               do:[:aMember| aMember acceptVisitor: self ]]]
withArguments: {#aCollection -> propertyName . #aMember -> propertyName
asAnInstance } asDictionary ].
   singleElements do:[:propertyName|
body add: [:anInstance| anInstance propertyName
               ifNotNil:[:aPropertyName| aPropertyName
acceptVisitor: self ] ]
         withArguments: {#aPropertyName -> propertyName asAnInstance
} asDictionary ].
We first declare a block that we can concatenate stuff too, then we add
others blocks to it.
In this loop, we have to visit every objects in collections for an
instance variable of a class.
So we have to add a block per collection to go through.
The actual block that will be added to the resulting block.
Replacements for *this* block.
(Note about this one, I do not remember well, buit I think that you can
use one scope per block added, it is copied when the block is added, so
you can modify the variables)
The second part is exactly the same as the first one, but for instance
variables that do not have to be iterate over.
If you understood the first one, you'll understand the second one !
Otherwise the second one might be able to help you with the first one !
And an example of generated code:
visitStructureDefinition: aStructureDefinition
aStructureDefinition members
      ifNotNil:
         [ :members | members do: [ :aMembers | aMembers
acceptVisitor: self ] ].
aStructureDefinition declaration
      ifNotNil: [ :aDeclaration | aDeclaration acceptVisitor: self ]
This is an indexable object, a collection.
So we want to visit each objects contained in it.
This is a non indexable object, so we send the visitMessage.
The visit method for this type will take care of visiting its slots
properly.
Note that I initially went with #+, but #, makes as much or more sense ! :)
Pierre
On 18/11/2020 08:42, Hernán Morales Durand wrote:
>
> I took a simple ish example, but we can do more advanced stuff,
> like concatenating blocks.
>
>
> This is something which I've been expecting and trying to find some
> time to do myself.
> Just to be clear, you mean something like:
>
> [ :arg1 | arg1 + 0 ] , [ :arg2 | arg2 + 7 ]
>
> which would give:
> [ :arg1 :arg2 |
> Â Â Â arg1 + 0.
> Â Â Â arg2 + 7 ]
>
> Did I understand well?
>
> Â Thanks for this report!
>
> Cheers,
>
> Hernán
>
> You can find more example in the following project in which I use
> PlainPharoCode exclusively to generate my code:
> https://github.com/hogoww/C-AST <https://github.com/hogoww/C-AST>.
> (In the ASTCGenerator class)
> (You will need a moose image).
>
> I hope you find this interesting !
>
> Have a nice day !
>
> Pierre.
>
Nov. 18, 2020
Re: AST Transformation Techniques
by Hernán Morales Durand
Hi Pierre,
El mar., 17 nov. 2020 a las 5:04, hogoww (<pierre.misse-chanabier(a)inria.fr>)
escribió:
> Hi Sean,
>
> I'm aware of Julien Delplanque which has done something a bit like this,
> or my own project.
> Julien's has a good documentation.
> Repo: https://github.com/juliendelplanque/PharoCodeGenerator
>
> You also have my own project, which takes a different approach that might
> be more what you want.
> (I didn't document it as well though...):
> https://github.com/hogoww/PlainPharoCode
>
> Quickly, my way of doing things is to use blocks instead of strings.
> This ensures that the generated code is at least well formed.
> This also enables code highlighting [...].
> It then replaces variables using the lexical scope (except for block args
> if i recall correctly, since shadowing is not a feature of pharo)
>
> ```smalltalk
>
> generateValidatorVisitOf: aClass
> "add an empty behavior visit method"
> | method body anInstance visitClass
> errors | "IV of the visitor"
> anInstance := aClass name asAnInstance.
>
> visitClass := aClass name asVisitClassSelector.
> body := [ :aClass |
> [ super visitClass: {aClass} ]
> on: AssertionFailure
> do: [ errors := errors + 1 ]
> ].
>
> method := visitClass
> asMethodWithBody: body
> withArguments: {(#aClass -> anInstance )} asDictionary.
>
>
> structureValidatorVisitorClass compile: method asString classified:
> 'visiting'
>
> ```
>
> This is a temp variable, used as a selector, which will be replace when evaluating
> the #asMethodWithBody:withArguments: message send.
> The temp var visitClass is a string that will describe the name of the
> method when sending the #asMethodWithBody:withArguments: message.
> This is the block that we want to generate.
> The temp var errors has no value, which means it already has the right
> name. this will not be replaced.
> The message send asMethodWithBody will do the required replacements.
> As said earlier , block arguments cannot be replaced using the same
> method, as Pharo disabled shadowing.
> We currently have to compile the string version of the method. Although
> slow, this has not yet been an issue
>
> (I hope that color way of describing a method is readable :D)
> This will for example give the folowing output:
>
> ```smalltalk
>
> visitExpression: anExpression
> [ super visitExpression: anExpression ]
> on: AssertionFailure
> do: [ errors := errors + 1 ]
>
> ```
>
> I took a simple ish example, but we can do more advanced stuff, like
> concatenating blocks.
>
>
This is something which I've been expecting and trying to find some time to
do myself.
Just to be clear, you mean something like:
[ :arg1 | arg1 + 0 ] , [ :arg2 | arg2 + 7 ]
which would give:
[ :arg1 :arg2 |
arg1 + 0.
arg2 + 7 ]
Did I understand well?
Thanks for this report!
Cheers,
Hernán
> You can find more example in the following project in which I use
> PlainPharoCode exclusively to generate my code:
> https://github.com/hogoww/C-AST.
> (In the ASTCGenerator class)
> (You will need a moose image).
>
> I hope you find this interesting !
>
> Have a nice day !
>
> Pierre.
> On 16/11/2020 23:55, sean(a)clipperadams.com wrote:
>
> To generate code, I used to use templates like the following (contrived
> example):
>
> ```smalltalk
>
> template := 'method1
>
> ^ {returnValue}'.
>
> template format: { #returnValue -> 2 } asDictionary
>
> ```
>
> This is *okay* for simple cases, but can get unwieldy, and doesn't benefit
> from e.g. (early) compiler warnings. It is also lacking when one wants to
> offer the behavior as a method and also as a script with no dependencies
> (maybe for CI).
>
> To overcome some of these limitations, I started saving the code template
> as an actual method and transforming the AST, e.g.:
>
> ```smalltalk
>
> "Convert baseline##: method"
>
> methodTree := (self methodNamed: selector) parseTree.
>
> methodTree selector: #baseline:.
>
> methodTree pragmas at: 1 put: (RBPragmaNode selector: #baseline arguments:
> #()).
>
> commonBlockBody := methodTree statements first arguments last body.
>
> commonBlockBody statements
>
> detect: [ :e | e selector = #repository: ]
>
> ifFound: [ :repoSetter | commonBlockBody removeNode: repoSetter ].
>
> "Compile baseline method"
>
> baseline compile: methodTree newSource classified: 'baseline'
>
> ```
>
> When I started doing this, I noticed two things:
>
> 1. There were idioms that were repeated over and over.
>
> 2. It still isn't super easy to turn a method into a script with no
> dependencies (e.g. self sends)
>
> So, I did a spike to wrap a few common idioms for this use case. It works
> like this. Say you have a method like this:
>
> ```
>
> SmallRemoteGitRepository>>#addRemote: urlString as: nameString
>
> "Assumes repo is loaded"
>
> | repo remote |
>
> repo := IceRepository registry detect: [ :e | e name = self projectName ].
>
> remote := IceGitRemote name: nameString url: urlString.
>
> repo addRemote: remote.
>
> remote fetch
>
> ```
>
> And you want to also provide it as source code for a script with no
> dependencies. You can do:
>
> ```
>
> SmallRemoteGitRepository >>#scriptToAddRemote: urlString as: nameString
>
> | method transformer |
>
> method := SmallRemoteGitRepository methodNamed: #addRemote:as:.
>
> transformer := method peAST_Transformer
>
> beScript;
>
> addStatementFirst: #projectName , ' := ' , self projectName printString;
>
> addStatementFirst: #nameString , ' := ' , nameString printString;
>
> addStatementFirst: #urlString , ' := ' , urlString printString;
>
> replaceNodeDetect: [ :e | e isMessage and: [ e selector = #projectName ] ]
>
> withNode: (RBVariableNode named: #projectName).
>
> ^ transformer newSource
>
> ```
>
> which would generate (for example, for a particular instance):
>
> ```
>
> | repo remote projectName |
>
> urlString := 'git@github.com:magritte-metamodel/magritte.git'.
>
> nameString := 'upstream'.
>
> projectName := 'Magritte'.
>
> repo := IceRepository registry detect: [ :e | e name = projectName ].
>
> remote := IceGitRemote name: nameString url: urlString.
>
> repo addRemote: remote.
>
> remote fetch
>
> ```
>
> So my questions are:
>
> - Does something like this already exist?
>
> - Are there better ways to solve this problem?
>
> - Does this solution look promising/generally-helpful?
>
>
Nov. 18, 2020
Re: AST Transformation Techniques
by Sean P. DeNigris
hogoww wrote
> I'm aware of Julien Delplanque which has done something a bit like this,
> or my own project.
Thanks! Both interesting and good to know about. Your project took me a
while to understand by reading and rereading the examples in the readme, but
I really like the block idea. I think Julien's could work for my use case
because there is a feature to generate his AST model from an existing
method. One day, I'd love to sit down and properly compare all three
approaches. I'll add it to the never-ending TODOs!
-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html
Nov. 17, 2020
Re: AST Transformation Techniques
by hogoww
Hi Sean,
I'm aware of Julien Delplanque which has done something a bit like this,
or my own project.
Julien's has a good documentation.
Repo: https://github.com/juliendelplanque/PharoCodeGenerator
You also have my own project, which takes a different approach that
might be more what you want.
(I didn't document it as well though...):
https://github.com/hogoww/PlainPharoCode
Quickly, my way of doing things is to use blocks instead of strings.
This ensures that the generated code is at least well formed.
This also enables code highlighting [...].
It then replaces variables using the lexical scope (except for block
args if i recall correctly, since shadowing is not a feature of pharo)
```smalltalk
generateValidatorVisitOf: aClass
   "add an empty behavior visit method"
   | method body anInstance visitClass
errors | "IV of the visitor"
  anInstance := aClass name asAnInstance.
 visitClass := aClass name asVisitClassSelector.
   body := [:aClass |
      [ super visitClass: {aClass} ]
      on: AssertionFailure
      do: [errors := errors + 1 ]
].
method := visitClass
asMethodWithBody: body
      withArguments: {(#aClass -> anInstance )} asDictionary.
   structureValidatorVisitorClass compile: method asString classified:
'visiting'
```
This is a temp variable, used as a selector, which will be replace when
evaluating the #asMethodWithBody:withArguments: message send.
The temp var visitClass is a string that will describe the name of the
method when sending the #asMethodWithBody:withArguments: message.
This is the block that we want to generate.
The temp var errors has no value, which means it already has the right
name. this will not be replaced.
The message send asMethodWithBody will do the required replacements.
As said earlier , block arguments cannot be replaced using the same
method, as Pharo disabled shadowing.
We currently have to compile the string version of the method. Although
slow, this has not yet been an issue
(I hope that color way of describing a method is readable :D)
This will for example give the folowing output:
```smalltalk
visitExpression: anExpression
   [ super visitExpression: anExpression ]
      on: AssertionFailure
      do: [ errors := errors + 1 ]
```
I took a simple ish example, but we can do more advanced stuff, like
concatenating blocks.
You can find more example in the following project in which I use
PlainPharoCode exclusively to generate my code:
https://github.com/hogoww/C-AST.
(In the ASTCGenerator class)
(You will need a moose image).
I hope you find this interesting !
Have a nice day !
Pierre.
On 16/11/2020 23:55, sean(a)clipperadams.com wrote:
>
> To generate code, I used to use templates like the following
> (contrived example):
>
> ```smalltalk
>
> |template := 'method1|
>
> |^ {returnValue}'.|
>
> |template format: { #returnValue -> 2 } asDictionary|
>
> ```
>
> This is *okay* for simple cases, but can get unwieldy, and doesn't
> benefit from e.g. (early) compiler warnings. It is also lacking when
> one wants to offer the behavior as a method and also as a script with
> no dependencies (maybe for CI).
>
> To overcome some of these limitations, I started saving the code
> template as an actual method and transforming the AST, e.g.:
>
> ```smalltalk
>
> |"Convert baseline##: method"|
>
> |methodTree := (self methodNamed: selector) parseTree.|
>
> |methodTree selector: #baseline:.|
>
> |methodTree pragmas at: 1 put: (RBPragmaNode selector: #baseline
> arguments: #()).|
>
> |commonBlockBody := methodTree statements first arguments last body.|
>
> |commonBlockBody statements|
>
> |detect: [ :e | e selector = #repository: ]|
>
> |ifFound: [ :repoSetter | commonBlockBody removeNode: repoSetter ].|
>
> ||
>
> |"Compile baseline method"|
>
> |baseline compile: methodTree newSource classified: 'baseline'|
>
> ```
>
> When I started doing this, I noticed two things:
>
> 1. There were idioms that were repeated over and over.
>
> 2. It still isn't super easy to turn a method into a script with no
> dependencies (e.g. self sends)
>
> So, I did a spike to wrap a few common idioms for this use case. It
> works like this. Say you have a method like this:
>
> ```
>
> |SmallRemoteGitRepository>>#addRemote: urlString as: nameString|
>
> |"Assumes repo is loaded"|
>
> ||
>
> || repo remote ||
>
> |repo := IceRepository registry detect: [ :e | e name = self
> projectName ].|
>
> |remote := IceGitRemote name: nameString url: urlString.|
>
> |repo addRemote: remote.|
>
> |remote fetch|
>
> ```
>
> And you want to also provide it as source code for a script with no
> dependencies. You can do:
>
> ```
>
> |SmallRemoteGitRepository >>#scriptToAddRemote: urlString as: nameString|
>
> || method transformer ||
>
> |method := SmallRemoteGitRepository methodNamed: #addRemote:as:.|
>
> |transformer := method peAST_Transformer|
>
> |beScript;|
>
> |addStatementFirst: #projectName , ' := ' , self projectName printString;|
>
> |addStatementFirst: #nameString , ' := ' , nameString printString;|
>
> |addStatementFirst: #urlString , ' := ' , urlString printString;|
>
> |replaceNodeDetect: [ :e | e isMessage and: [ e selector =
> #projectName ] ]|
>
> |withNode: (RBVariableNode named: #projectName).|
>
> |^ transformer newSource|
>
> ```
>
> which would generate (for example, for a particular instance):
>
> ```
>
> || repo remote projectName ||
>
> |urlString := 'git@github.com:magritte-metamodel/magritte.git'.|
>
> |nameString := 'upstream'.|
>
> |projectName := 'Magritte'.|
>
> |repo := IceRepository registry detect: [ :e | e name = projectName ].|
>
> |remote := IceGitRemote name: nameString url: urlString.|
>
> |repo addRemote: remote.|
>
> |remote fetch|
>
> ```
>
> So my questions are:
>
> - Does something like this already exist?
>
> - Are there better ways to solve this problem?
>
> - Does this solution look promising/generally-helpful?
>
Nov. 17, 2020
AST Transformation Techniques
by sean@clipperadams.com
To generate code, I used to use templates like the following (contrived example):
\`\`\`smalltalk
`template := 'method1`
` ^ {returnValue}'.`
`template format: { #returnValue -> 2 } asDictionary`
\`\`\`
This is \*okay\* for simple cases, but can get unwieldy, and doesn't benefit from e.g. (early) compiler warnings. It is also lacking when one wants to offer the behavior as a method and also as a script with no dependencies (maybe for CI).
To overcome some of these limitations, I started saving the code template as an actual method and transforming the AST, e.g.:
\`\`\`smalltalk
`"Convert baseline##: method"`
` methodTree := (self methodNamed: selector) parseTree.`
` methodTree selector: #baseline:.`
` methodTree pragmas at: 1 put: (RBPragmaNode selector: #baseline arguments: #()).`
` commonBlockBody := methodTree statements first arguments last body.`
` commonBlockBody statements`
` detect: [ :e | e selector = #repository: ]`
` ifFound: [ :repoSetter | commonBlockBody removeNode: repoSetter ].`
` `
` "Compile baseline method"`
` baseline compile: methodTree newSource classified: 'baseline'`
\`\`\`
When I started doing this, I noticed two things:
1\. There were idioms that were repeated over and over.
2\. It still isn't super easy to turn a method into a script with no dependencies (e.g. self sends)
So, I did a spike to wrap a few common idioms for this use case. It works like this. Say you have a method like this:
\`\`\`
`SmallRemoteGitRepository>>#addRemote: urlString as: nameString`
` "Assumes repo is loaded"`
` `
` | repo remote |`
` repo := IceRepository registry detect: [ :e | e name = self projectName ].`
` remote := IceGitRemote name: nameString url: urlString.`
` repo addRemote: remote.`
` remote fetch`
\`\`\`
And you want to also provide it as source code for a script with no dependencies. You can do:
\`\`\`
`SmallRemoteGitRepository >>#scriptToAddRemote: urlString as: nameString`
` | method transformer |`
` method := SmallRemoteGitRepository methodNamed: #addRemote:as:.`
` transformer := method peAST_Transformer`
` beScript;`
` addStatementFirst: #projectName , ' := ' , self projectName printString;`
` addStatementFirst: #nameString , ' := ' , nameString printString;`
` addStatementFirst: #urlString , ' := ' , urlString printString;`
` replaceNodeDetect: [ :e | e isMessage and: [ e selector = #projectName ] ]`
` withNode: (RBVariableNode named: #projectName).`
` ^ transformer newSource`
\`\`\`
which would generate (for example, for a particular instance):
\`\`\`
`| repo remote projectName |`
`urlString := 'git@github.com:magritte-metamodel/magritte.git'.`
`nameString := 'upstream'.`
`projectName := 'Magritte'.`
`repo := IceRepository registry detect: [ :e | e name = projectName ].`
`remote := IceGitRemote name: nameString url: urlString.`
`repo addRemote: remote.`
`remote fetch`
\`\`\`
So my questions are:
\- Does something like this already exist?
\- Are there better ways to solve this problem?
\- Does this solution look promising/generally-helpful?
Nov. 16, 2020