lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

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.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/","application/x-foo"))
print(cmd:match("bar -t %t",   1,"/tmp/","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 <> 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/","application/x-foo"))
> print(cmd:match("bar -t %t",   1,"/tmp/","application/x-bar"))
>   This outputs:
> foo -t application/x-foo /tmp/   true
> bar -t application/x-bar        true
> I'd like the output to be:
> foo -t application/x-foo /tmp/   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.