61
61
_VECTOR = symbol .symbol ('vector' , ns = 'basilisp.core' )
62
62
63
63
64
+ class Comment :
65
+ pass
66
+
67
+
68
+ COMMENT = Comment ()
69
+
70
+ LispReaderForm = Union [LispForm , Comment ]
71
+
72
+
64
73
class SyntaxError (Exception ): # pylint:disable=redefined-builtin
65
74
pass
66
75
@@ -298,8 +307,10 @@ def _read_namespaced(ctx: ReaderContext, allowed_suffix: Optional[str] = None) -
298
307
return ns_str , name_str
299
308
300
309
301
- def _read_coll (ctx : ReaderContext , f : Callable [[Collection [Any ]], Union [
302
- llist .List , lset .Set , vector .Vector ]], end_token : str , coll_name : str ):
310
+ def _read_coll (ctx : ReaderContext ,
311
+ f : Callable [[Collection [Any ]], Union [llist .List , lset .Set , vector .Vector ]],
312
+ end_token : str ,
313
+ coll_name : str ):
303
314
"""Read a collection from the input stream and create the
304
315
collection using f."""
305
316
coll : List = []
@@ -315,6 +326,8 @@ def _read_coll(ctx: ReaderContext, f: Callable[[Collection[Any]], Union[
315
326
reader .next_token ()
316
327
return f (coll )
317
328
elem = _read_next (ctx )
329
+ if elem is COMMENT :
330
+ continue
318
331
coll .append (elem )
319
332
320
333
@@ -350,8 +363,8 @@ def _read_interop(ctx: ReaderContext, end_token: str) -> llist.List:
350
363
351
364
token = reader .peek ()
352
365
if whitespace_chars .match (token ):
353
- instance = _read_next (ctx )
354
- member = _read_next (ctx )
366
+ instance = _read_next_consuming_comment (ctx )
367
+ member = _read_next_consuming_comment (ctx )
355
368
if not isinstance (member , symbol .Symbol ):
356
369
raise SyntaxError (f"Expected Symbol; found { type (member )} " )
357
370
is_property = member .name .startswith ('-' )
@@ -367,17 +380,17 @@ def _read_interop(ctx: ReaderContext, end_token: str) -> llist.List:
367
380
seq .append (_INTEROP_PROP )
368
381
if whitespace_chars .match (reader .peek ()):
369
382
raise SyntaxError (f"Expected Symbol; found whitespace" )
370
- member = _read_next (ctx )
383
+ member = _read_next_consuming_comment (ctx )
371
384
if not isinstance (member , symbol .Symbol ):
372
385
raise SyntaxError (f"Expected Symbol; found { type (member )} " )
373
- instance = _read_next (ctx )
386
+ instance = _read_next_consuming_comment (ctx )
374
387
seq .append (instance )
375
388
seq .append (member )
376
389
else :
377
390
assert not whitespace_chars .match (token )
378
391
seq .append (_INTEROP_CALL )
379
- member = _read_next (ctx )
380
- instance = _read_next (ctx )
392
+ member = _read_next_consuming_comment (ctx )
393
+ instance = _read_next_consuming_comment (ctx )
381
394
if not isinstance (member , symbol .Symbol ):
382
395
raise SyntaxError (f"Expected Symbol; found { type (member )} " )
383
396
seq .append (instance )
@@ -391,6 +404,8 @@ def _read_interop(ctx: ReaderContext, end_token: str) -> llist.List:
391
404
reader .next_token ()
392
405
return llist .list (seq )
393
406
elem = _read_next (ctx )
407
+ if elem is COMMENT or isinstance (elem , Comment ):
408
+ continue
394
409
seq .append (elem )
395
410
396
411
@@ -438,11 +453,17 @@ def _read_map(ctx: ReaderContext) -> lmap.Map:
438
453
reader .next_token ()
439
454
break
440
455
k = _read_next (ctx )
441
- if reader .peek () == '}' :
442
- raise SyntaxError ("Unexpected token '}'; expected map value" )
443
- v = _read_next (ctx )
444
- if k in d :
445
- raise SyntaxError ("Duplicate key '{}' in map literal" .format (k ))
456
+ if k is COMMENT :
457
+ continue
458
+ while True :
459
+ if reader .peek () == '}' :
460
+ raise SyntaxError ("Unexpected token '}'; expected map value" )
461
+ v = _read_next (ctx )
462
+ if v is COMMENT :
463
+ continue
464
+ if k in d :
465
+ raise SyntaxError (f"Duplicate key '{ k } ' in map literal" )
466
+ break
446
467
d [k ] = v
447
468
448
469
return lmap .map (d )
@@ -613,7 +634,7 @@ def _read_meta(ctx: ReaderContext) -> lmeta.Meta:
613
634
input stream."""
614
635
start = ctx .reader .advance ()
615
636
assert start == '^'
616
- meta = _read_next (ctx )
637
+ meta = _read_next_consuming_comment (ctx )
617
638
618
639
meta_map = None
619
640
if isinstance (meta , symbol .Symbol ):
@@ -626,7 +647,7 @@ def _read_meta(ctx: ReaderContext) -> lmeta.Meta:
626
647
raise SyntaxError (
627
648
f"Expected symbol, keyword, or map for metadata, not { type (meta )} " )
628
649
629
- obj_with_meta = _read_next (ctx )
650
+ obj_with_meta = _read_next_consuming_comment (ctx )
630
651
try :
631
652
return obj_with_meta .with_meta (meta_map ) # type: ignore
632
653
except AttributeError :
@@ -684,7 +705,7 @@ def _read_quoted(ctx: ReaderContext) -> llist.List:
684
705
"""Read a quoted form from the input stream."""
685
706
start = ctx .reader .advance ()
686
707
assert start == "'"
687
- next_form = _read_next (ctx )
708
+ next_form = _read_next_consuming_comment (ctx )
688
709
return llist .l (_QUOTE , next_form )
689
710
690
711
@@ -788,7 +809,7 @@ def _read_syntax_quoted(ctx: ReaderContext) -> LispForm:
788
809
assert start == "`"
789
810
790
811
with ctx .syntax_quoted ():
791
- return _process_syntax_quoted_form (ctx , _read_next (ctx ))
812
+ return _process_syntax_quoted_form (ctx , _read_next_consuming_comment (ctx ))
792
813
793
814
794
815
def _read_unquote (ctx : ReaderContext ) -> LispForm :
@@ -811,18 +832,18 @@ def _read_unquote(ctx: ReaderContext) -> LispForm:
811
832
next_char = ctx .reader .peek ()
812
833
if next_char == '@' :
813
834
ctx .reader .advance ()
814
- next_form = _read_next (ctx )
835
+ next_form = _read_next_consuming_comment (ctx )
815
836
return llist .l (_UNQUOTE_SPLICING , next_form )
816
837
else :
817
- next_form = _read_next (ctx )
838
+ next_form = _read_next_consuming_comment (ctx )
818
839
return llist .l (_UNQUOTE , next_form )
819
840
820
841
821
842
def _read_deref (ctx : ReaderContext ) -> LispForm :
822
843
"""Read a derefed form from the input stream."""
823
844
start = ctx .reader .advance ()
824
845
assert start == "@"
825
- next_form = _read_next (ctx )
846
+ next_form = _read_next_consuming_comment (ctx )
826
847
return llist .l (_DEREF , next_form )
827
848
828
849
@@ -888,7 +909,7 @@ def _read_regex(ctx: ReaderContext) -> Pattern:
888
909
raise SyntaxError (f"Unrecognized regex pattern syntax: { s } " )
889
910
890
911
891
- def _read_reader_macro (ctx : ReaderContext ) -> LispForm :
912
+ def _read_reader_macro (ctx : ReaderContext ) -> LispReaderForm :
892
913
"""Return a data structure evaluated as a reader
893
914
macro from the input stream."""
894
915
start = ctx .reader .advance ()
@@ -907,11 +928,11 @@ def _read_reader_macro(ctx: ReaderContext) -> LispForm:
907
928
elif token == "_" :
908
929
ctx .reader .advance ()
909
930
_read_next (ctx ) # Ignore the entire next form
910
- return _read_next ( ctx )
931
+ return COMMENT
911
932
elif ns_name_chars .match (token ):
912
933
s = _read_sym (ctx )
913
934
assert isinstance (s , symbol .Symbol )
914
- v = _read_next (ctx )
935
+ v = _read_next_consuming_comment (ctx )
915
936
if s in ctx .data_readers :
916
937
f = ctx .data_readers [s ]
917
938
return f (v )
@@ -921,7 +942,7 @@ def _read_reader_macro(ctx: ReaderContext) -> LispForm:
921
942
raise SyntaxError (f"Unexpected token '{ token } ' in reader macro" )
922
943
923
944
924
- def _read_comment (ctx : ReaderContext ) -> LispForm :
945
+ def _read_comment (ctx : ReaderContext ) -> LispReaderForm :
925
946
"""Read (and ignore) a single-line comment from the input stream.
926
947
Return the next form after the next line break."""
927
948
reader = ctx .reader
@@ -937,8 +958,20 @@ def _read_comment(ctx: ReaderContext) -> LispForm:
937
958
reader .advance ()
938
959
939
960
940
- def _read_next (ctx : ReaderContext ) -> LispForm : # noqa: C901
941
- """Read the next full token from the input stream."""
961
+ def _read_next_consuming_comment (ctx : ReaderContext ) -> LispForm :
962
+ """Read the next full form from the input stream, consuming any
963
+ reader comments completely."""
964
+ while True :
965
+ v = _read_next (ctx )
966
+ if v is __EOF :
967
+ return __EOF
968
+ if v is COMMENT or isinstance (v , Comment ):
969
+ continue
970
+ return v
971
+
972
+
973
+ def _read_next (ctx : ReaderContext ) -> LispReaderForm : # noqa: C901
974
+ """Read the next full form from the input stream."""
942
975
reader = ctx .reader
943
976
token = reader .peek ()
944
977
if token == '(' :
@@ -1000,6 +1033,8 @@ def read(stream, resolver: Resolver = None, data_readers: DataReaders = None) ->
1000
1033
expr = _read_next (ctx )
1001
1034
if expr is __EOF :
1002
1035
return
1036
+ if expr is COMMENT or isinstance (expr , Comment ):
1037
+ continue
1003
1038
yield expr
1004
1039
1005
1040
0 commit comments