S-expressions: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
|||
Line 4,080: | Line 4,080: | ||
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</pre> |
((data "quoted data" 123 4.5) (data (!@# (4.5) "(more" "data)")))</pre> |
||
=={{header|jq}}== |
|||
{{works with|jq}} |
|||
'''Also works with gojq, the Go implementation of jq''' |
|||
This entry is based on a Parsing Expression Grammar (PEG) for S-expressions. |
|||
The idea is to pass a JSON object `{remainder:_, result:_ }` through a |
|||
jq pipeline corresponding to a PEG for S-expressions, consuming the |
|||
text in `.remainder` and building up `.result`. |
|||
For further details about this approach, see e.g. |
|||
[https://github.com/stedolan/jq/wiki/Parsing-Expression-Grammars jq as a PEG Engine]. |
|||
<syntaxhighlight lang=jq> |
|||
# PEG infrastructure |
|||
def star(E): ((E | star(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 parseNumber($re): |
|||
consume($re) |
|||
| .result = .result + [.match|tonumber] ; |
|||
def eos: select(.remainder == ""); |
|||
# whitespace |
|||
def ws: consume("[ \t\r\n]*"); |
|||
def box(E): |
|||
((.result = null) | E) as $e |
|||
| .remainder = $e.remainder |
|||
| .result += [$e.result] # the magic sauce |
|||
; |
|||
# S-expressions |
|||
# Input: a string |
|||
# Output: an array representation of the input if it is an S-expression |
|||
def SExpression: |
|||
def string: consume("\"") | parse("[^\"]") | consume("\""); |
|||
def identifier: parse("[^ \t\n\r()]+"); |
|||
def decimal: parseNumber("[0-9]+([.][0-9]*)?"); |
|||
def hex: parse("0x[0-9A-Fa-f]+") ; |
|||
def number: hex // decimal; |
|||
def atom: ws | (string // number // identifier); |
|||
def SExpr: ws | consume("[(]") | ws | box(star(atom // SExpr)) | consume("[)]"); |
|||
{remainder: .} | SExpr | ws | eos | .result; |
|||
SExpression |
|||
</syntaxhighlight> |
|||
'''Invocation:''' |
|||
<pre> |
|||
cat << EOF | |
|||
((data "quoted data" 123 4.5) |
|||
(data (!@# (4.5) "(more" "data)"))) |
|||
EOF |
|||
jq -Rsc -f s-expression.jq |
|||
</pre> |
|||
{{output}} |
|||
<pre> |
|||
[[["data","\"quoted","data\"",123,4.5],["data",["!@#",[4.5],"\"",["more\"","\"data"],"\""]]]] |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |