Compiler/Verifying syntax: Difference between revisions

→‎{{header|jq}}: include "peg" {search: "."};
(→‎Generic PEG Library: def q: def box:)
(→‎{{header|jq}}: include "peg" {search: "."};)
Line 668:
</syntaxhighlight>
====Generic PEG Library====
The jq module at [[:Category:Jq/peg.jq]] can be included by copying it to a file,
and adding an `include` statement to top of the main program, e.g. as follows:
<syntaxhighlight lang=jq>
include "peg" {search: "."};
# Sequence: e1 e2 e1 | e2
# Ordered choice: e1 / e2 e1 // e2
# Zero-or-more: e* star(E)
# One-or-more: e+ plus(E)
# Optional: e? optional(E)
# And-predicate: &e amp(E) # no input is consumed
# Not-predicate: !e neg(E) # no input is consumed
 
# The idea is to pass a JSON object {remainder:_, result:_ } through a
# pipeline, consuming the text in .remainder and building up .result.
 
def star(E): ((E | star(E)) // .) ;
def plus(E): E | (plus(E) // . );
def optional(E): (E // .);
def amp(E): . as $in | E | $in;
def neg(E): select( [E] == [] );
 
### Helper functions:
 
# Consume a regular expression rooted at the start of .remainder, or emit empty;
# on success, update .remainder and set .match but do NOT update .result
def consume($re):
# on failure, match yields empty
(.remainder | match("^" + $re)) as $match
| .remainder |= .[$match.length :]
| .match = $match.string;
 
def parse($re):
consume($re)
| .result = .result + [.match] ;
 
def q($s):
select(.remainder | startswith($s))
| .remainder |= .[$s | length :] ;
 
def literal($s):
q($s)
| .result += [$s];
 
def eos: select(.remainder | length == 0);
 
# required white space
def _: consume("[ \n\r\t]+");
 
# optional white space
def ws: consume("[ \n\r\t]*");
 
# Tagging
def box(E):
((.result = null) | E) as $e
| .remainder = $e.remainder
| .result += [$e.result] # the magic sauce
;
 
</syntaxhighlight>
 
2,458

edits