Fortran · 27490 bytes Raw Blame History
1 module json_module
2 ! Minimal JSON parser/builder for LSP communication
3 use iso_fortran_env, only: int32, int64, real64
4 implicit none
5 private
6
7 public :: json_value_t, json_object_t, json_array_t
8 public :: json_parse, json_stringify
9 public :: json_create_object, json_create_array, json_create_string
10 public :: json_add_string, json_add_number, json_add_bool, json_add_null
11 public :: json_add_object, json_add_array
12 public :: json_get_string, json_get_number, json_get_bool
13 public :: json_get_object, json_get_array, json_get_value
14 public :: json_has_key
15 public :: json_array_size, json_get_array_element, json_array_add_element
16 public :: JSON_NULL, JSON_BOOL, JSON_NUMBER, JSON_STRING, JSON_ARRAY, JSON_OBJECT
17
18 ! JSON value types
19 integer, parameter :: JSON_NULL = 0
20 integer, parameter :: JSON_BOOL = 1
21 integer, parameter :: JSON_NUMBER = 2
22 integer, parameter :: JSON_STRING = 3
23 integer, parameter :: JSON_ARRAY = 4
24 integer, parameter :: JSON_OBJECT = 5
25
26 ! Forward declarations for recursive types
27 type :: json_value_t
28 integer :: value_type = JSON_NULL
29 logical :: bool_value = .false.
30 real(real64) :: number_value = 0.0
31 character(len=:), allocatable :: string_value
32 type(json_array_t), pointer :: array_value => null()
33 type(json_object_t), pointer :: object_value => null()
34 end type json_value_t
35
36 type :: json_pair_t
37 character(len=:), allocatable :: key
38 type(json_value_t) :: value
39 end type json_pair_t
40
41 type :: json_object_t
42 type(json_pair_t), allocatable :: pairs(:)
43 integer :: count = 0
44 end type json_object_t
45
46 type :: json_array_t
47 type(json_value_t), allocatable :: elements(:)
48 integer :: count = 0
49 end type json_array_t
50
51 contains
52
53 function json_create_object() result(obj)
54 type(json_value_t) :: obj
55
56 obj%value_type = JSON_OBJECT
57 allocate(obj%object_value)
58 allocate(obj%object_value%pairs(0))
59 obj%object_value%count = 0
60 end function json_create_object
61
62 function json_create_array() result(arr)
63 type(json_value_t) :: arr
64
65 arr%value_type = JSON_ARRAY
66 allocate(arr%array_value)
67 allocate(arr%array_value%elements(0))
68 arr%array_value%count = 0
69 end function json_create_array
70
71 function json_create_string(value) result(str)
72 character(len=*), intent(in) :: value
73 type(json_value_t) :: str
74
75 str%value_type = JSON_STRING
76 str%string_value = value
77 end function json_create_string
78
79 subroutine json_add_string(obj, key, value)
80 type(json_value_t), intent(inout) :: obj
81 character(len=*), intent(in) :: key, value
82 type(json_pair_t), allocatable :: new_pairs(:)
83 integer :: n
84
85 if (obj%value_type /= JSON_OBJECT) return
86
87 n = obj%object_value%count
88 allocate(new_pairs(n + 1))
89
90 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
91
92 new_pairs(n + 1)%key = key
93 new_pairs(n + 1)%value%value_type = JSON_STRING
94 new_pairs(n + 1)%value%string_value = value
95
96 deallocate(obj%object_value%pairs)
97 obj%object_value%pairs = new_pairs
98 obj%object_value%count = n + 1
99 end subroutine json_add_string
100
101 subroutine json_add_number(obj, key, value)
102 type(json_value_t), intent(inout) :: obj
103 character(len=*), intent(in) :: key
104 real(real64), intent(in) :: value
105 type(json_pair_t), allocatable :: new_pairs(:)
106 integer :: n
107
108 if (obj%value_type /= JSON_OBJECT) return
109
110 n = obj%object_value%count
111 allocate(new_pairs(n + 1))
112
113 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
114
115 new_pairs(n + 1)%key = key
116 new_pairs(n + 1)%value%value_type = JSON_NUMBER
117 new_pairs(n + 1)%value%number_value = value
118
119 deallocate(obj%object_value%pairs)
120 obj%object_value%pairs = new_pairs
121 obj%object_value%count = n + 1
122 end subroutine json_add_number
123
124 subroutine json_add_bool(obj, key, value)
125 type(json_value_t), intent(inout) :: obj
126 character(len=*), intent(in) :: key
127 logical, intent(in) :: value
128 type(json_pair_t), allocatable :: new_pairs(:)
129 integer :: n
130
131 if (obj%value_type /= JSON_OBJECT) return
132
133 n = obj%object_value%count
134 allocate(new_pairs(n + 1))
135
136 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
137
138 new_pairs(n + 1)%key = key
139 new_pairs(n + 1)%value%value_type = JSON_BOOL
140 new_pairs(n + 1)%value%bool_value = value
141
142 deallocate(obj%object_value%pairs)
143 obj%object_value%pairs = new_pairs
144 obj%object_value%count = n + 1
145 end subroutine json_add_bool
146
147 subroutine json_add_null(obj, key)
148 type(json_value_t), intent(inout) :: obj
149 character(len=*), intent(in) :: key
150 type(json_pair_t), allocatable :: new_pairs(:)
151 integer :: n
152
153 if (obj%value_type /= JSON_OBJECT) return
154
155 n = obj%object_value%count
156 allocate(new_pairs(n + 1))
157
158 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
159
160 new_pairs(n + 1)%key = key
161 new_pairs(n + 1)%value%value_type = JSON_NULL
162
163 deallocate(obj%object_value%pairs)
164 obj%object_value%pairs = new_pairs
165 obj%object_value%count = n + 1
166 end subroutine json_add_null
167
168 subroutine json_add_object(obj, key, child)
169 type(json_value_t), intent(inout) :: obj
170 character(len=*), intent(in) :: key
171 type(json_value_t), intent(in) :: child
172 type(json_pair_t), allocatable :: new_pairs(:)
173 integer :: n
174
175 if (obj%value_type /= JSON_OBJECT) return
176 if (child%value_type /= JSON_OBJECT) return
177
178 n = obj%object_value%count
179 allocate(new_pairs(n + 1))
180
181 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
182
183 new_pairs(n + 1)%key = key
184 new_pairs(n + 1)%value = child
185
186 deallocate(obj%object_value%pairs)
187 obj%object_value%pairs = new_pairs
188 obj%object_value%count = n + 1
189 end subroutine json_add_object
190
191 subroutine json_add_array(obj, key, arr)
192 type(json_value_t), intent(inout) :: obj
193 character(len=*), intent(in) :: key
194 type(json_value_t), intent(in) :: arr
195 type(json_pair_t), allocatable :: new_pairs(:)
196 integer :: n
197
198 if (obj%value_type /= JSON_OBJECT) return
199 if (arr%value_type /= JSON_ARRAY) return
200
201 n = obj%object_value%count
202 allocate(new_pairs(n + 1))
203
204 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
205
206 new_pairs(n + 1)%key = key
207 new_pairs(n + 1)%value = arr
208
209 deallocate(obj%object_value%pairs)
210 obj%object_value%pairs = new_pairs
211 obj%object_value%count = n + 1
212 end subroutine json_add_array
213
214 subroutine json_add_value(obj, key, value)
215 type(json_value_t), intent(inout) :: obj
216 character(len=*), intent(in) :: key
217 type(json_value_t), intent(in) :: value
218 type(json_pair_t), dimension(:), allocatable :: new_pairs
219 integer :: n
220
221 if (obj%value_type /= JSON_OBJECT) return
222 if (.not. associated(obj%object_value)) return
223
224 n = obj%object_value%count
225 allocate(new_pairs(n + 1))
226
227 if (n > 0) new_pairs(1:n) = obj%object_value%pairs
228
229 new_pairs(n + 1)%key = key
230 new_pairs(n + 1)%value = value
231
232 deallocate(obj%object_value%pairs)
233 obj%object_value%pairs = new_pairs
234 obj%object_value%count = n + 1
235 end subroutine json_add_value
236
237 subroutine json_array_add_element(arr, element)
238 type(json_value_t), intent(inout) :: arr
239 type(json_value_t), intent(in) :: element
240 type(json_value_t), dimension(:), allocatable :: new_elements
241 integer :: n
242
243 if (arr%value_type /= JSON_ARRAY) return
244 if (.not. associated(arr%array_value)) return
245
246 n = arr%array_value%count
247 allocate(new_elements(n + 1))
248
249 if (n > 0) new_elements(1:n) = arr%array_value%elements
250
251 new_elements(n + 1) = element
252
253 deallocate(arr%array_value%elements)
254 arr%array_value%elements = new_elements
255 arr%array_value%count = n + 1
256 end subroutine json_array_add_element
257
258 recursive function json_stringify(value) result(str)
259 type(json_value_t), intent(in) :: value
260 character(len=:), allocatable :: str
261
262 select case(value%value_type)
263 case(JSON_NULL)
264 str = "null"
265 case(JSON_BOOL)
266 if (value%bool_value) then
267 str = "true"
268 else
269 str = "false"
270 end if
271 case(JSON_NUMBER)
272 str = number_to_string(value%number_value)
273 case(JSON_STRING)
274 str = '"' // escape_string(value%string_value) // '"'
275 case(JSON_OBJECT)
276 str = object_to_string(value%object_value)
277 case(JSON_ARRAY)
278 str = array_to_string(value%array_value)
279 end select
280 end function json_stringify
281
282 recursive function object_to_string(obj) result(str)
283 type(json_object_t), pointer, intent(in) :: obj
284 character(len=:), allocatable :: str
285 integer :: i
286
287 if (.not. associated(obj)) then
288 str = "null"
289 return
290 end if
291
292 str = "{"
293 do i = 1, obj%count
294 if (i > 1) str = str // ","
295 str = str // '"' // obj%pairs(i)%key // '":' // &
296 json_stringify(obj%pairs(i)%value)
297 end do
298 str = str // "}"
299 end function object_to_string
300
301 recursive function array_to_string(arr) result(str)
302 type(json_array_t), pointer, intent(in) :: arr
303 character(len=:), allocatable :: str
304 integer :: i
305
306 if (.not. associated(arr)) then
307 str = "null"
308 return
309 end if
310
311 str = "["
312 do i = 1, arr%count
313 if (i > 1) str = str // ","
314 str = str // json_stringify(arr%elements(i))
315 end do
316 str = str // "]"
317 end function array_to_string
318
319 function escape_string(str) result(escaped)
320 character(len=*), intent(in) :: str
321 character(len=:), allocatable :: escaped
322 integer :: i
323 character :: ch
324
325 escaped = ""
326 do i = 1, len(str)
327 ch = str(i:i)
328 select case(ch)
329 case('"')
330 escaped = escaped // '\"'
331 case('\')
332 escaped = escaped // '\\'
333 case(char(8)) ! backspace
334 escaped = escaped // '\b'
335 case(char(12)) ! form feed
336 escaped = escaped // '\f'
337 case(char(10)) ! newline
338 escaped = escaped // '\n'
339 case(char(13)) ! carriage return
340 escaped = escaped // '\r'
341 case(char(9)) ! tab
342 escaped = escaped // '\t'
343 case default
344 escaped = escaped // ch
345 end select
346 end do
347 end function escape_string
348
349 ! Unescape JSON string escape sequences (inverse of escape_string)
350 function unescape_string(str) result(unescaped)
351 character(len=*), intent(in) :: str
352 character(len=:), allocatable :: unescaped
353 integer :: i, n
354
355 unescaped = ""
356 n = len(str)
357 i = 1
358 do while (i <= n)
359 if (str(i:i) == '\' .and. i < n) then
360 select case(str(i+1:i+1))
361 case('"')
362 unescaped = unescaped // '"'
363 case('\')
364 unescaped = unescaped // '\'
365 case('b')
366 unescaped = unescaped // char(8) ! backspace
367 case('f')
368 unescaped = unescaped // char(12) ! form feed
369 case('n')
370 unescaped = unescaped // char(10) ! newline
371 case('r')
372 unescaped = unescaped // char(13) ! carriage return
373 case('t')
374 unescaped = unescaped // char(9) ! tab
375 case default
376 ! Unknown escape, keep as-is
377 unescaped = unescaped // str(i:i+1)
378 end select
379 i = i + 2
380 else
381 unescaped = unescaped // str(i:i)
382 i = i + 1
383 end if
384 end do
385 end function unescape_string
386
387 function number_to_string(num) result(str)
388 real(real64), intent(in) :: num
389 character(len=:), allocatable :: str
390 character(len=32) :: buffer
391
392 if (num == int(num)) then
393 write(buffer, '(i0)') int(num)
394 else
395 write(buffer, '(f0.6)') num
396 end if
397 str = trim(buffer)
398 end function number_to_string
399
400 function json_has_key(obj, key) result(has)
401 type(json_value_t), intent(in) :: obj
402 character(len=*), intent(in) :: key
403 logical :: has
404 integer :: i
405
406 has = .false.
407 if (obj%value_type /= JSON_OBJECT) return
408 if (.not. associated(obj%object_value)) return
409
410 do i = 1, obj%object_value%count
411 if (obj%object_value%pairs(i)%key == key) then
412 has = .true.
413 return
414 end if
415 end do
416 end function json_has_key
417
418 function json_get_string(obj, key, default) result(value)
419 type(json_value_t), intent(in) :: obj
420 character(len=*), intent(in) :: key
421 character(len=*), intent(in), optional :: default
422 character(len=:), allocatable :: value
423 integer :: i
424
425 if (present(default)) then
426 value = default
427 else
428 value = ""
429 end if
430
431 if (obj%value_type /= JSON_OBJECT) return
432 if (.not. associated(obj%object_value)) return
433
434 do i = 1, obj%object_value%count
435 if (obj%object_value%pairs(i)%key == key) then
436 if (obj%object_value%pairs(i)%value%value_type == JSON_STRING) then
437 value = obj%object_value%pairs(i)%value%string_value
438 end if
439 return
440 end if
441 end do
442 end function json_get_string
443
444 function json_get_number(obj, key, default) result(value)
445 type(json_value_t), intent(in) :: obj
446 character(len=*), intent(in) :: key
447 real(real64), intent(in), optional :: default
448 real(real64) :: value
449 integer :: i
450
451 if (present(default)) then
452 value = default
453 else
454 value = 0.0
455 end if
456
457 if (obj%value_type /= JSON_OBJECT) return
458 if (.not. associated(obj%object_value)) return
459
460 do i = 1, obj%object_value%count
461 if (obj%object_value%pairs(i)%key == key) then
462 if (obj%object_value%pairs(i)%value%value_type == JSON_NUMBER) then
463 value = obj%object_value%pairs(i)%value%number_value
464 end if
465 return
466 end if
467 end do
468 end function json_get_number
469
470 function json_get_bool(obj, key, default) result(value)
471 type(json_value_t), intent(in) :: obj
472 character(len=*), intent(in) :: key
473 logical, intent(in), optional :: default
474 logical :: value
475 integer :: i
476
477 if (present(default)) then
478 value = default
479 else
480 value = .false.
481 end if
482
483 if (obj%value_type /= JSON_OBJECT) return
484 if (.not. associated(obj%object_value)) return
485
486 do i = 1, obj%object_value%count
487 if (obj%object_value%pairs(i)%key == key) then
488 if (obj%object_value%pairs(i)%value%value_type == JSON_BOOL) then
489 value = obj%object_value%pairs(i)%value%bool_value
490 end if
491 return
492 end if
493 end do
494 end function json_get_bool
495
496 function json_get_object(obj, key) result(value)
497 type(json_value_t), intent(in) :: obj
498 character(len=*), intent(in) :: key
499 type(json_value_t) :: value
500 integer :: i
501
502 value%value_type = JSON_NULL
503
504 if (obj%value_type /= JSON_OBJECT) return
505 if (.not. associated(obj%object_value)) return
506
507 do i = 1, obj%object_value%count
508 if (obj%object_value%pairs(i)%key == key) then
509 if (obj%object_value%pairs(i)%value%value_type == JSON_OBJECT) then
510 value = obj%object_value%pairs(i)%value
511 end if
512 return
513 end if
514 end do
515 end function json_get_object
516
517 function json_get_array(obj, key) result(value)
518 type(json_value_t), intent(in) :: obj
519 character(len=*), intent(in) :: key
520 type(json_value_t) :: value
521 integer :: i
522
523 value%value_type = JSON_NULL
524
525 if (obj%value_type /= JSON_OBJECT) return
526 if (.not. associated(obj%object_value)) return
527
528 do i = 1, obj%object_value%count
529 if (obj%object_value%pairs(i)%key == key) then
530 if (obj%object_value%pairs(i)%value%value_type == JSON_ARRAY) then
531 value = obj%object_value%pairs(i)%value
532 end if
533 return
534 end if
535 end do
536 end function json_get_array
537
538 ! Get any JSON value by key (regardless of type) - for LSP data field
539 function json_get_value(obj, key) result(value)
540 type(json_value_t), intent(in) :: obj
541 character(len=*), intent(in) :: key
542 type(json_value_t) :: value
543 integer :: i
544
545 value%value_type = JSON_NULL
546
547 if (obj%value_type /= JSON_OBJECT) return
548 if (.not. associated(obj%object_value)) return
549
550 do i = 1, obj%object_value%count
551 if (obj%object_value%pairs(i)%key == key) then
552 value = obj%object_value%pairs(i)%value
553 return
554 end if
555 end do
556 end function json_get_value
557
558 ! Simple JSON parser (basic implementation)
559 function json_parse(str) result(value)
560 character(len=*), intent(in) :: str
561 type(json_value_t) :: value
562 integer :: pos
563
564 pos = 1
565 call skip_whitespace(str, pos)
566 value = parse_value(str, pos)
567 end function json_parse
568
569 recursive function parse_value(str, pos) result(value)
570 character(len=*), intent(in) :: str
571 integer, intent(inout) :: pos
572 type(json_value_t) :: value
573
574 call skip_whitespace(str, pos)
575
576 if (pos > len(str)) then
577 value%value_type = JSON_NULL
578 return
579 end if
580
581 select case(str(pos:pos))
582 case('{')
583 value = parse_object(str, pos)
584 case('[')
585 value = parse_array(str, pos)
586 case('"')
587 value = parse_string(str, pos)
588 case('t', 'f') ! true or false
589 value = parse_bool(str, pos)
590 case('n') ! null
591 value = parse_null(str, pos)
592 case default
593 ! Try to parse as number
594 value = parse_number(str, pos)
595 end select
596 end function parse_value
597
598 recursive function parse_object(str, pos) result(obj)
599 character(len=*), intent(in) :: str
600 integer, intent(inout) :: pos
601 type(json_value_t) :: obj
602 character(len=:), allocatable :: key
603 type(json_value_t) :: value
604 logical :: first_pair
605
606 obj = json_create_object()
607 pos = pos + 1 ! skip '{'
608 first_pair = .true.
609
610 call skip_whitespace(str, pos)
611
612 ! Handle empty object
613 if (pos <= len(str) .and. str(pos:pos) == '}') then
614 pos = pos + 1
615 return
616 end if
617
618 ! Parse key-value pairs
619 do while (pos <= len(str))
620 ! Skip comma if not first pair
621 if (.not. first_pair) then
622 if (str(pos:pos) /= ',') exit
623 pos = pos + 1
624 call skip_whitespace(str, pos)
625 end if
626 first_pair = .false.
627
628 ! Check for end of object
629 if (pos > len(str)) exit
630 if (str(pos:pos) == '}') then
631 pos = pos + 1
632 exit
633 end if
634
635 ! Parse key (must be a string)
636 if (str(pos:pos) /= '"') exit
637 key = parse_object_key(str, pos)
638
639 call skip_whitespace(str, pos)
640
641 ! Expect colon
642 if (pos > len(str) .or. str(pos:pos) /= ':') exit
643 pos = pos + 1
644
645 call skip_whitespace(str, pos)
646
647 ! Parse value
648 value = parse_value(str, pos)
649
650 ! Add key-value pair to object
651 call json_add_value(obj, key, value)
652
653 call skip_whitespace(str, pos)
654
655 ! Check for end of object
656 if (pos <= len(str) .and. str(pos:pos) == '}') then
657 pos = pos + 1
658 exit
659 end if
660 end do
661 end function parse_object
662
663 function parse_object_key(str, pos) result(key)
664 character(len=*), intent(in) :: str
665 integer, intent(inout) :: pos
666 character(len=:), allocatable :: key
667 integer :: start_pos
668
669 pos = pos + 1 ! skip opening '"'
670 start_pos = pos
671
672 ! Find closing '"' (ignoring escaped quotes)
673 do while (pos <= len(str))
674 if (str(pos:pos) == '\' .and. pos < len(str)) then
675 pos = pos + 2 ! skip escaped character
676 else if (str(pos:pos) == '"') then
677 if (pos > start_pos) then
678 key = str(start_pos:pos-1)
679 else
680 key = ""
681 end if
682 pos = pos + 1 ! skip closing '"'
683 return
684 else
685 pos = pos + 1
686 end if
687 end do
688
689 ! If we get here, string was not terminated
690 key = ""
691 end function parse_object_key
692
693 recursive function parse_array(str, pos) result(arr)
694 character(len=*), intent(in) :: str
695 integer, intent(inout) :: pos
696 type(json_value_t) :: arr
697 type(json_value_t) :: element
698 logical :: first_element
699
700 arr = json_create_array()
701 pos = pos + 1 ! skip '['
702 first_element = .true.
703
704 call skip_whitespace(str, pos)
705
706 ! Handle empty array
707 if (pos <= len(str) .and. str(pos:pos) == ']') then
708 pos = pos + 1
709 return
710 end if
711
712 ! Parse elements
713 do while (pos <= len(str))
714 ! Skip comma if not first element
715 if (.not. first_element) then
716 if (str(pos:pos) /= ',') exit
717 pos = pos + 1
718 call skip_whitespace(str, pos)
719 end if
720 first_element = .false.
721
722 ! Check for end of array
723 if (pos > len(str)) exit
724 if (str(pos:pos) == ']') then
725 pos = pos + 1
726 exit
727 end if
728
729 ! Parse element
730 element = parse_value(str, pos)
731
732 ! Add element to array
733 call json_array_add_element(arr, element)
734
735 call skip_whitespace(str, pos)
736
737 ! Check for end of array
738 if (pos <= len(str) .and. str(pos:pos) == ']') then
739 pos = pos + 1
740 exit
741 end if
742 end do
743 end function parse_array
744
745 function parse_string(str, pos) result(value)
746 character(len=*), intent(in) :: str
747 integer, intent(inout) :: pos
748 type(json_value_t) :: value
749 integer :: start_pos
750
751 value%value_type = JSON_STRING
752 pos = pos + 1 ! skip opening '"'
753 start_pos = pos
754
755 ! Find closing '"' (ignoring escaped quotes)
756 do while (pos <= len(str))
757 if (str(pos:pos) == '\' .and. pos < len(str)) then
758 pos = pos + 2 ! skip escaped character
759 else if (str(pos:pos) == '"') then
760 ! Unescape the string (convert \n to newline, etc.)
761 value%string_value = unescape_string(str(start_pos:pos-1))
762 pos = pos + 1 ! skip closing '"'
763 return
764 else
765 pos = pos + 1
766 end if
767 end do
768
769 value%string_value = unescape_string(str(start_pos:))
770 end function parse_string
771
772 function parse_number(str, pos) result(value)
773 character(len=*), intent(in) :: str
774 integer, intent(inout) :: pos
775 type(json_value_t) :: value
776 integer :: start_pos
777 character :: ch
778
779 value%value_type = JSON_NUMBER
780 start_pos = pos
781
782 ! Parse sign
783 if (pos <= len(str)) then
784 ch = str(pos:pos)
785 if (ch == '-' .or. ch == '+') pos = pos + 1
786 end if
787
788 ! Parse digits
789 do while (pos <= len(str))
790 ch = str(pos:pos)
791 if ((ch >= '0' .and. ch <= '9') .or. ch == '.' .or. &
792 ch == 'e' .or. ch == 'E' .or. ch == '+' .or. ch == '-') then
793 pos = pos + 1
794 else
795 exit
796 end if
797 end do
798
799 read(str(start_pos:pos-1), *) value%number_value
800 end function parse_number
801
802 function parse_bool(str, pos) result(value)
803 character(len=*), intent(in) :: str
804 integer, intent(inout) :: pos
805 type(json_value_t) :: value
806
807 value%value_type = JSON_BOOL
808
809 if (str(pos:min(pos+3, len(str))) == 'true') then
810 value%bool_value = .true.
811 pos = pos + 4
812 else if (str(pos:min(pos+4, len(str))) == 'false') then
813 value%bool_value = .false.
814 pos = pos + 5
815 end if
816 end function parse_bool
817
818 function parse_null(str, pos) result(value)
819 character(len=*), intent(in) :: str
820 integer, intent(inout) :: pos
821 type(json_value_t) :: value
822
823 value%value_type = JSON_NULL
824 if (str(pos:min(pos+3, len(str))) == 'null') then
825 pos = pos + 4
826 end if
827 end function parse_null
828
829 subroutine skip_whitespace(str, pos)
830 character(len=*), intent(in) :: str
831 integer, intent(inout) :: pos
832
833 do while (pos <= len(str))
834 select case(str(pos:pos))
835 case(' ', char(9), char(10), char(13))
836 pos = pos + 1
837 case default
838 return
839 end select
840 end do
841 end subroutine skip_whitespace
842
843 ! Get the size of a JSON array
844 function json_array_size(arr) result(size)
845 type(json_value_t), intent(in) :: arr
846 integer :: size
847
848 size = 0
849 if (arr%value_type == JSON_ARRAY .and. associated(arr%array_value)) then
850 size = arr%array_value%count
851 end if
852 end function json_array_size
853
854 ! Get an element from a JSON array by index (0-based)
855 function json_get_array_element(arr, index) result(element)
856 type(json_value_t), intent(in) :: arr
857 integer, intent(in) :: index
858 type(json_value_t) :: element
859
860 element%value_type = JSON_NULL
861
862 if (arr%value_type == JSON_ARRAY .and. associated(arr%array_value)) then
863 if (index >= 0 .and. index < arr%array_value%count) then
864 element = arr%array_value%elements(index + 1) ! Convert to 1-based
865 end if
866 end if
867 end function json_get_array_element
868
869 end module json_module