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.

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…

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

Reply via email to