On Wed, Aug 30, 2017 at 9:50 PM, Tim Mackinnon <tim@testit.works> wrote:
Iâm looking for some feedback on the usage of RBParser>>#parseMethod:onError:.
I am looking at ways of improving the way we edit code - and making things work (as least for me - but maybe for everyone) a bit more like IntelliJ where they have some great code operations and very good keyboard support. We are certainly close, but at times feel a bit clumsy - which is a shame as we have far better infrastructure to support equivalent features. So I thought I would have a go.
Excellent!!!
Anyway - step one (which I think Iâve come close on), was to teach senders/implementors to look at the AST so you donât have to highlight exactly what you want to search on - instead it can infer from your cursor⦠however my next step was to improve how we can select code to ease refactoring, bracketing etcâ¦
Yes but we have to handle broken code then. Did you check how smart suggestions did it for code that compiled?
So this is where Iâve hit a few issues which strike me as confusing (and I will freely admit that Iâm not a mega compiler, parser guy - but Iâd love to beâ¦).
The following code blows up strangely - and I think its very confusing⦠as it turns out that #parseMethod:onError: doesnât work like I would expect (and this is where Iâm after feedback). It seems that the onError block doesât actually exit parsing - it takes the result and then keeps running with something in an intermediate state - thus below, when I try to parse with a subset of the code (and maybe this is a naive approach to handle the case when you start typing code in the middle of a complete method, but want to parse it before youâve entered a final â.â or â;â) - you actually end up with an AST that is using all of the source code because the result of the error block is then applied inside the executing method.
I find this very confusing? There are no comments in this code, and for me the convention of onError: is to execute in isolation unless there is a parameter that the error block can interact with. Iâm wondering if those with more knowledge agree - or if it is my naiveté?
This was my original code (and yes it needs refactoring a bit) - but anyway:
bestNodeInTextAreaOnError: aBlock "Find the best node in the editor text area at the current pointer location"
| ast start stop node source |
start := self textArea startIndex. stop := self textArea stopIndex.
source := self textArea string trimRight.
ast := RBParser parseMethod: source onError: [ RBParser parseExpression: source onError: [ source := (source truncateTo: stop) trimRight.
RBParser parseMethod: source onError: [ RBParser parseExpression: source onError: aBlock ]]].
stop > source size ifTrue: [ start := stop := source size].
node := ast bestNodeFor: (start to: stop).
node ifNil: aBlock.
^node
But this doesnât work, as âastâ is incorrect when it parses truncated source. To work around what Iâm seeing I have to instead extract the ast assignment to another method that looks as follows - but to me it seems very unexpected to have the explicit ^ statements?
agressivelyParse: source at: loc "Find the best node in the editor text area at the current pointer location"
^RBParser parseMethod: source onError: [ ^RBParser parseExpression: source onError: [ | reducedSrc | reducedSrc := (source truncateTo: loc) trimRight.
^RBParser parseMethod: reducedSrc onError: [ ^RBParser parseExpression: reducedSrc onError: [^nil]]]].
This forces the ast to be exactly what I would expect - but Iâm wondering if I am missing something obvious?
Tim