@@ -287,6 +287,9 @@ module json_value_module
287
287
! ! * If true [default], an exception will be raised if an integer
288
288
! ! value cannot be read when parsing JSON.
289
289
290
+ logical (LK) :: allow_trailing_comma = .true.
291
+ ! ! Allow a single trailing comma in arrays and objects.
292
+
290
293
integer :: ichunk = 0 ! ! index in `chunk` for [[pop_char]]
291
294
! ! when `use_unformatted_stream=True`
292
295
integer :: filesize = 0 ! ! the file size when when `use_unformatted_stream=True`
@@ -1140,6 +1143,10 @@ subroutine json_initialize(me,&
1140
1143
me% strict_integer_type_checking = strict_integer_type_checking
1141
1144
end if
1142
1145
1146
+ if (present (allow_trailing_comma)) then
1147
+ me% allow_trailing_comma = allow_trailing_comma
1148
+ end if
1149
+
1143
1150
! Set the format for real numbers:
1144
1151
! [if not changing it, then it remains the same]
1145
1152
@@ -10154,7 +10161,7 @@ recursive subroutine parse_value(json, unit, str, value)
10154
10161
10155
10162
! start object
10156
10163
call json% to_object(value) ! allocate class
10157
- call json% parse_object(unit, str, value)
10164
+ call json% parse_object(unit, str, value, expecting_next_element = .false. )
10158
10165
10159
10166
case (start_array)
10160
10167
@@ -10879,14 +10886,17 @@ end subroutine to_array
10879
10886
! >
10880
10887
! Core parsing routine.
10881
10888
10882
- recursive subroutine parse_object (json , unit , str , parent )
10889
+ recursive subroutine parse_object (json , unit , str , parent , expecting_next_element )
10883
10890
10884
10891
implicit none
10885
10892
10886
10893
class(json_core),intent (inout ) :: json
10887
10894
integer (IK),intent (in ) :: unit ! ! file unit number (if parsing from a file)
10888
10895
character (kind= CK,len=* ),intent (in ) :: str ! ! JSON string (if parsing from a string)
10889
10896
type (json_value),pointer :: parent ! ! the parsed object will be added as a child of this
10897
+ logical (LK),intent (in ) :: expecting_next_element ! ! if true, this object is preceeded by a comma, so
10898
+ ! ! we expect a valid object to exist. used to check
10899
+ ! ! for trailing delimiters.
10890
10900
10891
10901
type (json_value),pointer :: pair ! ! temp variable
10892
10902
logical (LK) :: eof ! ! end of file flag
@@ -10907,13 +10917,18 @@ recursive subroutine parse_object(json, unit, str, parent)
10907
10917
10908
10918
! pair name
10909
10919
call json% pop_char(unit, str= str, eof= eof, skip_ws= .true. , &
10910
- skip_comments= json% allow_comments, popped= c)
10920
+ skip_comments= json% allow_comments, popped= c)
10911
10921
if (eof) then
10912
10922
call json% throw_exception(' Error in parse_object:' // &
10913
10923
' Unexpected end of file while parsing start of object.' )
10914
10924
return
10915
10925
else if (end_object == c) then
10916
10926
! end of an empty object
10927
+ if (expecting_next_element .and. .not. json% allow_trailing_comma) then
10928
+ ! this is a dangling comma.
10929
+ call json% throw_exception(' Error in parse_object: ' // &
10930
+ ' Dangling comma when parsing an object.' )
10931
+ end if
10917
10932
return
10918
10933
else if (quotation_mark == c) then
10919
10934
call json_value_create(pair)
@@ -10935,7 +10950,7 @@ recursive subroutine parse_object(json, unit, str, parent)
10935
10950
10936
10951
! pair value
10937
10952
call json% pop_char(unit, str= str, eof= eof, skip_ws= .true. , &
10938
- skip_comments= json% allow_comments, popped= c)
10953
+ skip_comments= json% allow_comments, popped= c)
10939
10954
if (eof) then
10940
10955
call json% destroy(pair)
10941
10956
call json% throw_exception(' Error in parse_object:' // &
@@ -10959,14 +10974,15 @@ recursive subroutine parse_object(json, unit, str, parent)
10959
10974
10960
10975
! another possible pair
10961
10976
call json% pop_char(unit, str= str, eof= eof, skip_ws= .true. , &
10962
- skip_comments= json% allow_comments, popped= c)
10977
+ skip_comments= json% allow_comments, popped= c)
10963
10978
if (eof) then
10964
10979
call json% throw_exception(' Error in parse_object: ' // &
10965
10980
' End of file encountered when parsing an object' )
10966
10981
return
10967
10982
else if (delimiter == c) then
10968
10983
! read the next member
10969
- call json% parse_object(unit = unit, str= str, parent = parent)
10984
+ call json% parse_object(unit = unit, str= str, parent = parent, &
10985
+ expecting_next_element= .true. )
10970
10986
else if (end_object == c) then
10971
10987
! end of object
10972
10988
return
@@ -10996,6 +11012,9 @@ recursive subroutine parse_array(json, unit, str, array)
10996
11012
type (json_value),pointer :: element ! ! temp variable for array element
10997
11013
logical (LK) :: eof ! ! end of file flag
10998
11014
character (kind= CK,len= 1 ) :: c ! ! character returned by [[pop_char]]
11015
+ logical (LK) :: expecting_next_element ! ! to check for trailing delimiters
11016
+
11017
+ expecting_next_element = .false.
10999
11018
11000
11019
do
11001
11020
@@ -11011,7 +11030,10 @@ recursive subroutine parse_array(json, unit, str, array)
11011
11030
end if
11012
11031
11013
11032
! parse value will deallocate an empty array value
11014
- if (associated (element)) call json% add(array, element)
11033
+ if (associated (element)) then
11034
+ expecting_next_element = .false.
11035
+ call json% add(array, element)
11036
+ end if
11015
11037
11016
11038
! popped the next character
11017
11039
call json% pop_char(unit, str= str, eof= eof, skip_ws= .true. , &
@@ -11024,9 +11046,15 @@ recursive subroutine parse_array(json, unit, str, array)
11024
11046
exit
11025
11047
else if (delimiter == c) then
11026
11048
! parse the next element
11049
+ expecting_next_element = .true.
11027
11050
cycle
11028
11051
else if (end_array == c) then
11029
11052
! end of array
11053
+ if (expecting_next_element .and. .not. json% allow_trailing_comma) then
11054
+ ! this is a dangling comma.
11055
+ call json% throw_exception(' Error in parse_array: ' // &
11056
+ ' Dangling comma when parsing an array.' )
11057
+ end if
11030
11058
exit
11031
11059
else
11032
11060
call json% throw_exception(' Error in parse_array: ' // &
0 commit comments