 peg.search quotations sequences splitting stack-checker strings
 summary unicode.categories words ;
 FROM: compiler.units => with-compilation-unit ;
+FROM: strings.parser => unescape-string ;
 FROM: vocabs.parser => search ;
 FROM: peg.search => replace ;
 IN: peg.ebnf

    #! begin and end.
    [ syntax ] 2dip syntax pack ;

#! Don't want to use 'replace' in an action since replace doesn't infer.
#! Do the compilation of the peg at parse time and call (replace).
PEG: escaper ( string -- ast )
    [
        "\\t" token [ drop "\t" ] action ,
        "\\n" token [ drop "\n" ] action ,
        "\\r" token [ drop "\r" ] action ,
        "\\\\" token [ drop "\\" ] action ,
    ] choice* any-char-parser 2array choice repeat0 ;

: replace-escapes ( string -- string )
    escaper sift [ [ tree-write ] each ] with-string-writer ;

: insert-escapes ( string -- string )
    [
        "\t" token [ drop "\\t" ] action ,

        [ "[" syntax , "[" token ensure-not , ] seq* hide ,
        [ CHAR: ] = not ] satisfy repeat1 ,
        "]" syntax ,
    ] seq* [ first >string unescape-string <ebnf-range> ] action ;

: ('element') ( -- parser )
    #! An element of a rule. It can be a terminal or a
