develooper Front page | perl.perl6.compiler | Postings from June 2010

Re: Str.trans implementation

Thread Previous | Thread Next
From:
Moritz Lenz
Date:
June 3, 2010 02:13
Subject:
Re: Str.trans implementation
Message ID:
4C077228.7040404@faui2k3.org

David Green wrote:
> On 2010-05-31, at 5:32 pm, Chris Fields wrote:
>> I think, in order to get regexes to work we will need a way of getting the name of the matching regex from the Match object somehow.  Any idea how to do that?

afaict there's no direct way, only workarounds (as David showed).

> I had started working on this too, and ended up going on quite an adventure... 
> my starting idea was something like s/ @from / %to{$/} / to look up the replacement
> based on what was matched, but $/ isn't available in a subst, 

It is, but currently only as the first positional argument of the closure.

Example:

10:54 <@moritz_> rakudo: say 'a b c'.subst(/<alpha>/, -> $m { uc $m }, :g)
10:54 <+p6eval> rakudo a1140c: OUTPUT«A B C␤»


> and anyway, as you indicate, $/ would only get the matched text, not the regex's name or other identifier.
> 
> So I thought of what seemed like a good trick: have each pattern set its own replacement through the magic of embedded closures:
> 	/ @from[$n] { $replacement = $to[$n] } /
> 
> As long as $replacement had the right scope, it would get the correct value as a side-effect of matching, 
> and then could be substituted for the right thing.  Except it turns out .subst does all the matching first,
> and then the replacement, so everything got replaced with whatever the final match happened to be.

... unless you push all the replacement markers onto an array, and
traverse the array during the substitution phase.

Maybe an explanation is in order why .subst matches eagerly, and only
then replaces:

The :x modifier takes a number or range of match numbers, for example

'a b c d e'.subst(/<alpha>/, 'Z', :x(3))

is supposed to return

'Z Z Z d e'.

If less than $x matches are present, no substitution is carried out at all.


> However, I was stubborn enough to look at the code for .subst, and 
> saw that instead of passing off :g to self.match, I could loop through
> the individual matches manually, and replace each one as it came up, /SK
> thus using the correct value of $replacement.  So I did. 
> 
> Of course, I was using :c to continue matching each successive occurrence
> from where the previous one left off, so I had to handle any :c option 
> manually too.  And :p.  And :x and :n... well, it started to feel a bit 
> silly, especially since .subst is going to change to make $/ work anyway. 

I don't like the code duplication in .subst and .match, I'd rather see
.trans working with the workarounds I mentioned above than re-writing
.subst to re-implement much of .match.

> But... by then, I had it almost working.  So I've also included my mangled version of .subst. (It passes the same spectests from subst.t that it did before, except for a couple that I'm not sure are right.)

I'll look through the tests and weed out the old, wrong tests.

> And once .subst was able to re-evaluate the RHS for each match, my .trans worked.  Almost.  Interpolating a literal string doesn't seem to work yet, so I had to escape all the chars and interpolate it as a rule.  And then there was a weird bug where creating regexes in a loop returned a list of copies of the same regex.  But it worked spelling them all out without using a loop, so I made a long string with all the regexes I needed and then eval()ed, and that *did* work.  
> 
> But at least the error messages were better, and just since last week!  (Hooray for line numbers!)  

Aye, kudos to Jonathan Worthington for these lovely backtraces!

> As you can see, I didn't pay attention to optimisation, but it does pass the spectests that use .trans (rather than tr//); and I didn't do any adverbs.  (I reckon the P5 modifiers were dropped because they aren't as useful now: :c and :s can be handled with regexes as the search key, and :d is now done simply by using an empty string as the replacement value.)

Fine by me. The spec doesn't mention them, just the tests.

Cheers,
Moritz

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About