|
Cs is apparently a barrier that blocks outside access to all its
captures. They are only accessible to patterns inside of Cs, not those
outside. Minimal testcase:
local lpeg = require 'lpeg'
setmetatable(_ENV, {__index = lpeg})
local patt1 = Cg(Cc('test!'), 'not inside Cs') * Cb 'not inside Cs'
local patt2 = Cs(Cg(Cc('test!'), 'inside Cs')) * Cb 'inside Cs'
print(patt1:match '') -- no error
print(patt2:match '') -- error!
So you can't do a substitution over the whole "char" pattern and
access the capture named "redirect". But if Cs is put at a lower level
of the pattern, you can:
lpeg = require "lpeg"
char = lpeg.Cs(lpeg.P"%s" * lpeg.Carg(1) / "%1") *
lpeg.Cg(lpeg.Cc(false),'redirect')
+ lpeg.Cs(lpeg.P"%t" * lpeg.Carg(2) / "%1")
+ lpeg.C(lpeg.R" ~")
cmd = lpeg.Cg(lpeg.Cc(true),'redirect')
* lpeg.Cf(char^1, function (a, b) return a .. (b or "") end)
* lpeg.Cb'redirect'
print(cmd:match("foo -t %t %s",1,"/tmp/bar.foo","application/x-foo"))
print(cmd:match("bar -t %t", 1,"/tmp/foo.bar","application/x-bar"))
It's a messy solution because it requires concatenating all the
captures from "char^1" (inefficient because it creates a bunch of
intermediate string objects!), I don't know if this is better or worse
than the solutions already posted.
— Gabriel
On Fri, Dec 7, 2018 at 11:55 PM Sean Conner <sean@conman.org> wrote:
>
>
> I'm working on a personal project [1] and for some media types, I'm using
> mailcap files to specify external programs to view media types not directly
> supported by the program I'm writing. So I have a mailcap file:
>
> application/x-foo; foo -t %t %s
> application/x-bar; bar -t %t
>
> This, I can parse [2]. The first field is the MIME type, followed by the
> command to run, but there are substitutions that need to happen before the
> command is run. The '%t' is replaced by the MIME type, and the '%s' is
> replaced by the file; if '%s' is *NOT* specified, then the data is piped in
> via stdin. This is where I'm having an issue. I would like to have LPeg do
> the substitutions but the part I'm having trouble with is indicating if '%s'
> was indeed, part of the command. While I could check to see if '%s' exists
> in the string before I do the substition, I'd prefer if I didn't have to.
>
> My current attempt:
>
> lpeg = require "lpeg"
>
> char = lpeg.P"%s" * lpeg.Carg(1) / "%1" * lpeg.Cg(lpeg.Cc(false),'redirect')
> + lpeg.P"%t" * lpeg.Carg(2) / "%1"
> + lpeg.R" ~"
> cmd = lpeg.Cg(lpeg.Cc(true),'redirect')
> * lpeg.Cs(char^1)
> * lpeg.Cb'redirect'
>
> print(cmd:match("foo -t %t %s",1,"/tmp/bar.foo","application/x-foo"))
> print(cmd:match("bar -t %t", 1,"/tmp/foo.bar","application/x-bar"))
>
> This outputs:
>
> foo -t application/x-foo /tmp/bar.foo true
> bar -t application/x-bar true
>
> I'd like the output to be:
>
> foo -t application/x-foo /tmp/bar.foo false
> bar -t application/x-bar true
>
> Now, lpeg.Cg() states:
>
> An anonymous group serves to join values from several captures into
> a single capture. A named group has a different behavior. In most
> situations, a named group returns no values at all. Its values are
> only relevant for a following back capture or when used inside a
> table capture.
>
> and lpeg.Cs():
>
> Creates a substitution capture, which captures the substring of the
> subject that matches patt, with substitutions. For any capture
> inside patt with a value, the substring that matched the capture is
> replaced by the capture value (which should be a string). The final
> captured value is the string resulting from all replacements.
>
> I'm using a named group to track if I need redirection or not, and since a
> named group does not return a value, it shouldn't affect the substitution
> capture (and it doesn't). But the group capture in the char _expression_
> seems to be ignored.
>
> What's going on here? Am I misunderstanding the documentation?
>
> -spc
>
> [1] A gopher client for those curious.
>
> [2] There's more to the format but I don't want to bog down the issue
> more than I have to, and as I said, parsing the mailcap file isn't
> the issue.
>