@@ -32,6 +32,8 @@ public class EdnReader{
32
32
static Pattern floatPat = Pattern .compile ("([-+]?[0-9]+(\\ .[0-9]*)?([eE][-+]?[0-9]+)?)(M)?" );
33
33
static final Symbol SLASH = Symbol .intern ("/" );
34
34
35
+ static IFn taggedReader = new TaggedReader ();
36
+
35
37
static
36
38
{
37
39
macros ['"' ] = new StringReader ();
@@ -54,10 +56,14 @@ public class EdnReader{
54
56
dispatchMacros ['_' ] = new DiscardReader ();
55
57
}
56
58
57
- static public Object readString (String s ){
59
+ static boolean nonConstituent (int ch ){
60
+ return ch == '@' || ch == '`' || ch == '~' ;
61
+ }
62
+
63
+ static public Object readString (String s , IPersistentMap opts ){
58
64
PushbackReader r = new PushbackReader (new java .io .StringReader (s ));
59
65
try {
60
- return EdnReader . read (r , true , null , false );
66
+ return read (r , opts );
61
67
}
62
68
catch (Exception e ) {
63
69
throw Util .sneakyThrow (e );
@@ -102,7 +108,14 @@ static public int read1(Reader r){
102
108
}
103
109
}
104
110
105
- static public Object read (PushbackReader r , boolean eofIsError , Object eofValue , boolean isRecursive )
111
+ static final Keyword EOF = Keyword .intern (null ,"eof" );
112
+
113
+ static public Object read (PushbackReader r , IPersistentMap opts ){
114
+ return read (r ,!opts .containsKey (EOF ),opts .valAt (EOF ),false ,opts );
115
+ }
116
+
117
+ static public Object read (PushbackReader r , boolean eofIsError , Object eofValue , boolean isRecursive ,
118
+ Object opts )
106
119
{
107
120
108
121
try
@@ -132,7 +145,7 @@ static public Object read(PushbackReader r, boolean eofIsError, Object eofValue,
132
145
IFn macroFn = getMacro (ch );
133
146
if (macroFn != null )
134
147
{
135
- Object ret = macroFn .invoke (r , (char ) ch );
148
+ Object ret = macroFn .invoke (r , (char ) ch , opts );
136
149
if (RT .suppressRead ())
137
150
return null ;
138
151
//no op macros return the reader
@@ -173,16 +186,22 @@ static public Object read(PushbackReader r, boolean eofIsError, Object eofValue,
173
186
174
187
static private String readToken (PushbackReader r , char initch ) {
175
188
StringBuilder sb = new StringBuilder ();
189
+ if (nonConstituent (initch ))
190
+ throw Util .runtimeException ("Invalid leading character: " + (char )initch );
191
+
176
192
sb .append (initch );
177
193
178
194
for (; ;)
179
195
{
180
196
int ch = read1 (r );
197
+
181
198
if (ch == -1 || isWhitespace (ch ) || isTerminatingMacro (ch ))
182
199
{
183
200
unread (r , ch );
184
201
return sb .toString ();
185
202
}
203
+ else if (nonConstituent (ch ))
204
+ throw Util .runtimeException ("Invalid constituent character: " + (char )ch );
186
205
sb .append ((char ) ch );
187
206
}
188
207
}
@@ -391,7 +410,7 @@ public Object invoke(Object reader, Object doublequote) {
391
410
*/
392
411
393
412
public static class StringReader extends AFn {
394
- public Object invoke (Object reader , Object doublequote ) {
413
+ public Object invoke (Object reader , Object doublequote , Object opts ) {
395
414
StringBuilder sb = new StringBuilder ();
396
415
Reader r = (Reader ) reader ;
397
416
@@ -453,7 +472,7 @@ public Object invoke(Object reader, Object doublequote) {
453
472
}
454
473
455
474
public static class CommentReader extends AFn {
456
- public Object invoke (Object reader , Object semicolon ) {
475
+ public Object invoke (Object reader , Object semicolon , Object opts ) {
457
476
Reader r = (Reader ) reader ;
458
477
int ch ;
459
478
do
@@ -466,29 +485,36 @@ public Object invoke(Object reader, Object semicolon) {
466
485
}
467
486
468
487
public static class DiscardReader extends AFn {
469
- public Object invoke (Object reader , Object underscore ) {
488
+ public Object invoke (Object reader , Object underscore , Object opts ) {
470
489
PushbackReader r = (PushbackReader ) reader ;
471
- read (r , true , null , true );
490
+ read (r , true , null , true , opts );
472
491
return r ;
473
492
}
474
493
}
475
494
476
495
public static class DispatchReader extends AFn {
477
- public Object invoke (Object reader , Object hash ) {
496
+ public Object invoke (Object reader , Object hash , Object opts ) {
478
497
int ch = read1 ((Reader ) reader );
479
498
if (ch == -1 )
480
499
throw Util .runtimeException ("EOF while reading character" );
481
500
IFn fn = dispatchMacros [ch ];
482
501
483
502
if (fn == null ) {
503
+ //try tagged reader
504
+ if (Character .isLetter (ch ))
505
+ {
506
+ unread ((PushbackReader ) reader , ch );
507
+ return taggedReader .invoke (reader , ch , opts );
508
+ }
509
+
484
510
throw Util .runtimeException (String .format ("No dispatch macro for: %c" , (char ) ch ));
485
511
}
486
- return fn .invoke (reader , ch );
512
+ return fn .invoke (reader , ch , opts );
487
513
}
488
514
}
489
515
490
516
public static class MetaReader extends AFn {
491
- public Object invoke (Object reader , Object caret ) {
517
+ public Object invoke (Object reader , Object caret , Object opts ) {
492
518
PushbackReader r = (PushbackReader ) reader ;
493
519
int line = -1 ;
494
520
int column = -1 ;
@@ -497,15 +523,15 @@ public Object invoke(Object reader, Object caret) {
497
523
line = ((LineNumberingPushbackReader ) r ).getLineNumber ();
498
524
column = ((LineNumberingPushbackReader ) r ).getColumnNumber ()-1 ;
499
525
}
500
- Object meta = read (r , true , null , true );
526
+ Object meta = read (r , true , null , true , opts );
501
527
if (meta instanceof Symbol || meta instanceof String )
502
528
meta = RT .map (RT .TAG_KEY , meta );
503
529
else if (meta instanceof Keyword )
504
530
meta = RT .map (meta , RT .T );
505
531
else if (!(meta instanceof IPersistentMap ))
506
532
throw new IllegalArgumentException ("Metadata must be Symbol,Keyword,String or Map" );
507
533
508
- Object o = read (r , true , null , true );
534
+ Object o = read (r , true , null , true , opts );
509
535
if (o instanceof IMeta )
510
536
{
511
537
if (line != -1 && o instanceof ISeq )
@@ -531,7 +557,7 @@ else if(!(meta instanceof IPersistentMap))
531
557
}
532
558
533
559
public static class CharacterReader extends AFn {
534
- public Object invoke (Object reader , Object backslash ) {
560
+ public Object invoke (Object reader , Object backslash , Object opts ) {
535
561
PushbackReader r = (PushbackReader ) reader ;
536
562
int ch = read1 (r );
537
563
if (ch == -1 )
@@ -574,7 +600,7 @@ else if(token.startsWith("o"))
574
600
}
575
601
576
602
public static class ListReader extends AFn {
577
- public Object invoke (Object reader , Object leftparen ) {
603
+ public Object invoke (Object reader , Object leftparen , Object opts ) {
578
604
PushbackReader r = (PushbackReader ) reader ;
579
605
int line = -1 ;
580
606
int column = -1 ;
@@ -583,7 +609,7 @@ public Object invoke(Object reader, Object leftparen) {
583
609
line = ((LineNumberingPushbackReader ) r ).getLineNumber ();
584
610
column = ((LineNumberingPushbackReader ) r ).getColumnNumber ()-1 ;
585
611
}
586
- List list = readDelimitedList (')' , r , true );
612
+ List list = readDelimitedList (')' , r , true , opts );
587
613
if (list .isEmpty ())
588
614
return PersistentList .EMPTY ;
589
615
IObj s = (IObj ) PersistentList .create (list );
@@ -599,17 +625,17 @@ public Object invoke(Object reader, Object leftparen) {
599
625
}
600
626
601
627
public static class VectorReader extends AFn {
602
- public Object invoke (Object reader , Object leftparen ) {
628
+ public Object invoke (Object reader , Object leftparen , Object opts ) {
603
629
PushbackReader r = (PushbackReader ) reader ;
604
- return LazilyPersistentVector .create (readDelimitedList (']' , r , true ));
630
+ return LazilyPersistentVector .create (readDelimitedList (']' , r , true , opts ));
605
631
}
606
632
607
633
}
608
634
609
635
public static class MapReader extends AFn {
610
- public Object invoke (Object reader , Object leftparen ) {
636
+ public Object invoke (Object reader , Object leftparen , Object opts ) {
611
637
PushbackReader r = (PushbackReader ) reader ;
612
- Object [] a = readDelimitedList ('}' , r , true ).toArray ();
638
+ Object [] a = readDelimitedList ('}' , r , true , opts ).toArray ();
613
639
if ((a .length & 1 ) == 1 )
614
640
throw Util .runtimeException ("Map literal must contain an even number of forms" );
615
641
return RT .map (a );
@@ -618,27 +644,27 @@ public Object invoke(Object reader, Object leftparen) {
618
644
}
619
645
620
646
public static class SetReader extends AFn {
621
- public Object invoke (Object reader , Object leftbracket ) {
647
+ public Object invoke (Object reader , Object leftbracket , Object opts ) {
622
648
PushbackReader r = (PushbackReader ) reader ;
623
- return PersistentHashSet .createWithCheck (readDelimitedList ('}' , r , true ));
649
+ return PersistentHashSet .createWithCheck (readDelimitedList ('}' , r , true , opts ));
624
650
}
625
651
626
652
}
627
653
628
654
public static class UnmatchedDelimiterReader extends AFn {
629
- public Object invoke (Object reader , Object rightdelim ) {
655
+ public Object invoke (Object reader , Object rightdelim , Object opts ) {
630
656
throw Util .runtimeException ("Unmatched delimiter: " + rightdelim );
631
657
}
632
658
633
659
}
634
660
635
661
public static class UnreadableReader extends AFn {
636
- public Object invoke (Object reader , Object leftangle ) {
662
+ public Object invoke (Object reader , Object leftangle , Object opts ) {
637
663
throw Util .runtimeException ("Unreadable form" );
638
664
}
639
665
}
640
666
641
- public static List readDelimitedList (char delim , PushbackReader r , boolean isRecursive ) {
667
+ public static List readDelimitedList (char delim , PushbackReader r , boolean isRecursive , Object opts ) {
642
668
final int firstline =
643
669
(r instanceof LineNumberingPushbackReader ) ?
644
670
((LineNumberingPushbackReader ) r ).getLineNumber () : -1 ;
@@ -666,7 +692,7 @@ public static List readDelimitedList(char delim, PushbackReader r, boolean isRec
666
692
IFn macroFn = getMacro (ch );
667
693
if (macroFn != null )
668
694
{
669
- Object mret = macroFn .invoke (r , (char ) ch );
695
+ Object mret = macroFn .invoke (r , (char ) ch , opts );
670
696
//no op macros return the reader
671
697
if (mret != r )
672
698
a .add (mret );
@@ -675,7 +701,7 @@ public static List readDelimitedList(char delim, PushbackReader r, boolean isRec
675
701
{
676
702
unread (r , ch );
677
703
678
- Object o = read (r , true , null , isRecursive );
704
+ Object o = read (r , true , null , isRecursive , opts );
679
705
if (o != r )
680
706
a .add (o );
681
707
}
@@ -685,5 +711,37 @@ public static List readDelimitedList(char delim, PushbackReader r, boolean isRec
685
711
return a ;
686
712
}
687
713
714
+ public static class TaggedReader extends AFn {
715
+ public Object invoke (Object reader , Object firstChar , Object opts ){
716
+ PushbackReader r = (PushbackReader ) reader ;
717
+ Object name = read (r , true , null , false , opts );
718
+ if (!(name instanceof Symbol ))
719
+ throw new RuntimeException ("Reader tag must be a symbol" );
720
+ Symbol sym = (Symbol )name ;
721
+ return readTagged (r , sym , (IPersistentMap ) opts );
722
+ }
723
+
724
+ static Keyword READERS = Keyword .intern (null ,"readers" );
725
+ static Keyword DEFAULT = Keyword .intern (null ,"default" );
726
+
727
+ private Object readTagged (PushbackReader reader , Symbol tag , IPersistentMap opts ){
728
+ Object o = read (reader , true , null , true , opts );
729
+
730
+ ILookup readers = (ILookup )RT .get (opts , READERS );
731
+ IFn dataReader = (IFn )RT .get (readers , tag );
732
+ if (dataReader == null )
733
+ dataReader = (IFn )RT .get (RT .DEFAULT_DATA_READERS .deref (),tag );
734
+ if (dataReader == null ){
735
+ IFn defaultReader = (IFn )RT .get (opts , DEFAULT );
736
+ if (defaultReader != null )
737
+ return defaultReader .invoke (tag , o );
738
+ else
739
+ throw new RuntimeException ("No reader function for tag " + tag .toString ());
740
+ }
741
+ else
742
+ return dataReader .invoke (o );
743
+ }
744
+
745
+ }
688
746
}
689
747
0 commit comments