@@ -0,0 +1,176 @@
1+! Copyright (C) 2025 John Benediktsson
2+! See https://factorcode.org/license.txt for BSD license
3+4+USING: arrays combinators hash-sets hashtables kernel make math
5+math.parser peg peg.parsers sequences splitting strings
6+strings.parser unicode vectors ;
7+8+IN: edn
9+10+TUPLE: keyword name ;
11+12+TUPLE: symbol name ;
13+14+TUPLE: tagged name value ;
15+16+<PRIVATE
17+18+: spaces ( -- parser )
19+ [ blank? ] satisfy repeat1 ;
20+21+: newline ( -- parser )
22+"\n" token "\r\n" token 2choice ;
23+24+: comments ( -- parser )
25+";" token [ CHAR: \n = not ] satisfy repeat0 newline optional 3seq ;
26+27+: spaces-or-comments ( -- parser )
28+ spaces comments 2choice repeat1 ;
29+30+: nil-parser ( -- parser )
31+"nil" token [ drop null ] action ;
32+33+: boolean-parser ( -- parser )
34+"true" token [ drop t ] action
35+"false" token [ drop f ] action
36+ 2choice ;
37+38+: escaped ( -- parser )
39+"\\" token hide [ "\"\\befnrt" member-eq? ] satisfy 2seq
40+ [ first escape ] action ;
41+42+: string-parser ( -- parser )
43+ escaped [ CHAR: \" = not ] satisfy 2choice repeat0
44+"\"" dup surrounded-by [ >string ] action ;
45+46+: char-parser ( -- parser )
47+"\\" token hide [ blank? not ] satisfy repeat1 [
48+>string {
49+ { "newline" [ CHAR: \n ] }
50+ { "return" [ CHAR: \r ] }
51+ { "space" [ CHAR: \s ] }
52+ { "tab" [ CHAR: \t ] }
53+ [ "u" ?head [ hex> ] [ first ] if ]
54+ } case
55+ ] action 2seq [ first ] action ;
56+57+: keyword-parser ( -- parser )
58+":" token hide
59+ [ blank? not ] satisfy repeat1 [ >string ] action
60+ 2seq [ first keyword boa ] action ;
61+62+: symbol-parser ( -- parser )
63+ [ [ digit? not ] [ [ alpha? ] [ ".*+!-_?$%&=<>" member? ] bi or ] bi and ] satisfy
64+ [ [ alpha? ] [ ".*+!-_?$%&=<>" member? ] bi or ] satisfy repeat0 2seq
65+ [ first2 swap prefix >string ] action
66+"/" token list-of [ "/" join symbol boa ] action ;
67+68+: sign ( -- parser )
69+"+" token "-" token 2choice ;
70+71+: decdigit ( -- parser )
72+CHAR: 0 CHAR: 9 range ;
73+74+: int-parser ( -- parser )
75+ sign optional decdigit repeat1 "N" token hide optional 3seq
76+ [ "" concat-as string>number ] action ;
77+78+: exponent ( -- parser )
79+"e" token "E" token 2choice sign optional
80+ decdigit repeat1 3seq [ "" concat-as ] action ;
81+82+: float-parser ( -- parser )
83+ [ sign optional , decdigit repeat1 , exponent , ] seq*
84+ [ sign optional , decdigit repeat1 , "." token , decdigit repeat1 , exponent optional , ] seq*
85+ 2choice [ "" concat-as string>number ] action ;
86+87+DEFER: value-parser
88+89+: discard-parser ( -- parser )
90+"#_" token spaces-or-comments optional value-parser 3seq ;
91+92+: ?value-parser ( -- parser )
93+ discard-parser hide comments hide value-parser 3choice ;
94+95+: values-parser ( -- parser )
96+ [
97+ spaces-or-comments optional hide ,
98+ ?value-parser ,
99+ spaces-or-comments hide ?value-parser 2seq repeat0
100+ [ concat ] action ,
101+ spaces-or-comments optional hide ,
102+ ] seq* [ dup length 1 > [ first2 swap prefix ] [ ?first ] if ] action ;
103+104+: list-parser ( -- parser )
105+ [
106+"(" token hide , spaces-or-comments optional hide ,
107+ values-parser optional ,
108+ spaces-or-comments optional hide , ")" token hide ,
109+ ] seq* [ ?first >array ] action ;
110+111+: vector-parser ( -- parser )
112+ [
113+"[" token hide , spaces-or-comments optional hide ,
114+ values-parser optional ,
115+ spaces-or-comments optional hide , "]" token hide ,
116+ ] seq* [ ?first >vector ] action ;
117+118+: pair-parser ( -- parser )
119+ value-parser spaces-or-comments hide value-parser 3seq ;
120+121+: pairs-parser ( -- parser )
122+ pair-parser
123+ [ [ CHAR: , = ] [ blank? ] bi or ] satisfy repeat1 hide
124+ pair-parser 2seq
125+ [ first ] action repeat0 2seq
126+ [ first2 swap prefix ] action ;
127+128+: map-parser ( -- parser )
129+ [
130+"{" token hide , spaces-or-comments optional hide ,
131+ pairs-parser optional ,
132+ spaces-or-comments optional hide , "}" token hide ,
133+ ] seq* [ ?first >hashtable ] action ;
134+135+: set-parser ( -- parser )
136+ [
137+"#{" token hide , spaces-or-comments optional hide ,
138+ values-parser optional ,
139+ spaces-or-comments optional hide , "}" token hide ,
140+ ] seq* [ ?first >hash-set ] action ;
141+142+: tagged-parser ( -- parser )
143+ [
144+"#" token hide ,
145+ [ blank? not ] satisfy repeat1 [ >string ] action ,
146+ spaces-or-comments hide ,
147+ value-parser ,
148+ ] seq* [ first2 tagged boa ] action ;
149+150+: value-parser ( -- parser )
151+ [
152+ [
153+ nil-parser ,
154+ boolean-parser ,
155+ string-parser ,
156+ keyword-parser ,
157+ symbol-parser ,
158+ string-parser ,
159+ char-parser ,
160+ float-parser ,
161+ int-parser ,
162+ list-parser ,
163+ vector-parser ,
164+ map-parser ,
165+ set-parser ,
166+ tagged-parser ,
167+ ] choice*
168+ ] delay ;
169+170+! XXX: #inst "rfc-3339-format"
171+! XXX: #uuid "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
172+173+PRIVATE>
174+175+: edn> ( string -- object )
176+ values-parser parse-fully ;