develooper Front page | perl.perl5.porters | Postings from August 2013

Re: [perl #119455] [EXPERIMENT] pluggable keyword API

Thread Previous | Thread Next
From:
Lukas Mai
Date:
August 28, 2013 19:53
Subject:
Re: [perl #119455] [EXPERIMENT] pluggable keyword API
Message ID:
521E5512.2030402@gmail.com
On 25.08.2013 15:09, Zefram wrote:
> Lukas Mai wrote:
>> Devel::CallParser solves a different problem. I can only use it to
>> implement custom argument syntax for subroutines, but what I actually
>> want is custom keywords.
> 
> The breakthrough that led to Devel::CallParser is the understanding that
> there's no need for such a distinction, and in fact that we're better
> off without one.  Keyword-led syntax and subroutine calls both begin
> the same way, with a bareword that identifies the type of construction
> that is to follow.  Keywords and subroutine names are semantically
> active in the same situations.  So it doesn't make sense to treat
> them as two separate namespaces.  Better to have one namespace, with
> the metaobject to which the name refers determining all the behaviour.
> Of the two namespaces we already have, the one that is more manipulable
> is the subroutine namespace.
> 
>> For example: if I want to reimplement 'sub', I need to accept a bareword
>> (subroutine name) followed by a block (subroutine body). None of the
>> parse_args_* functions can be used for this.
> 
> That's orthogonal to how the namespace is managed.  You need those
> parsing routines regardless of how your plugged-in parser got invoked.
> parse_args_*() don't cover your needs, but the core's parse_block()
> does the sub body.  parse_block() can be perfectly well called from a
> D:CP-managed sub arg parser.  The possibility of calling parsing code
> other than the standard argument parsers is the point of D:CP.
> 
>>                                 I still have to return an argument
>> list. This isn't needed because all the effects I want happen at
>> runtime, but the API insists on constructing a sub call.
> 
> When using D:CP for this sort of thing, you'll also want to use
> Devel::CallChecker to turn the sub calling ops into something
> other than a sub call.  See Memoize::Lift, for example, which turns
> lift(some_arbitrary_expr()) into a compile-time constant, requiring
> modification of both stages.
> 
> It's sane to argue that the eventual API should make it easier than
> this to generate a completely custom op sequence from a custom parser.
> I think there is some use in keeping the two-phase structure, because
> this potentially allows use of the op customisation from code that builds
> ops directly rather than using the parser.  This is always possible for
> things that use only Devel::CallChecker: one can build the entersub op
> tree manually, and the check phase replaces it with the custom ops just
> as if the sub call had been parsed normally.  But where such a split is
> really not convenient (as in Memoize::Lift, which actually does all the
> constant lifting in the parse phase), a call checker that just throws
> away the entersub wrapper and yields the parameter's op tree (M:L's
> myck_entersub_lift minus the const op type check) could be supplied by
> the core for convenience.
> 
>> Finally, the whole thing won't be a statement by itself, so the user
>> will need to add a ';'.
> 
> That's what the CALLPARSER_STATEMENT flag in the D:CP API is for.
> For example, see Scope::Escape::Sugar, which implements "block foo
> {...}" being a complete statement, without semicolon.  The code that
> implements that form is a bit tricky to follow, I'm afraid, partly due
> to also allowing "block(foo {...})" as an expression (not statement)
> and partly due to some hackery to support parsing on Perls that don't
> supply the parser callback interfaces.
> 
>> In short: If I haven't misunderstood how D:CP works,
> 
> You have misunderstood much of D:CP.

Fair enough.

I've been thinking about creating a branch to convert
Function::Parameters to D:CP. I've hit two problems so far:

1) There's no documentation that tells you how you actually integrate it
in a distribution. There's only this in the synopsis:

# to generate header prior to XS compilation

perl -MDevel::CallParser=callparser0_h \
        -e 'print callparser0_h' > callparser0.h
perl -MDevel::CallParser=callparser1_h \
        -e 'print callparser1_h' > callparser1.h


What exactly is "prior"? Do I do this once and check the file in? Or is
this supposed to run as part of the build process (in which case, how do
I extend the Makefile to make it do that)? Or is this supposed to run at
configure time (in which case this code needs to go into Makefile.PL,
but then why is it presented in shell script form)?


2) Function::Parameters is a lexical pragma. Does D:CP provide lexical
exports? I don't see how to get the effect of lexically scoped keywords
with plain subs.

-- 
Lukas Mai <plokinom@gmail.com>

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