Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 41.8% 104 / 0 / 249
Functions: -% 0 / 1 / 1
Branches: 27.7% 38 / 0 / 137

OMCompiler/Compiler/Parsers/JSON.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated uniontype JSON
37
38 import LexerJSON;
39 import LexerJSON.{Token,TokenId,tokenContent,printToken,tokenSourceInfo};
40 import Vector;
41 import UnorderedMap;
42
43 protected
44
45 import Error;
46 import MetaModelica.Dangerous.listReverseInPlace;
47 import Util;
48 import Print;
49 import Testsuite;
50
51 public
52
53 record OBJECT
54 UnorderedMap<String, JSON> values;
55 end OBJECT;
56 record LIST_OBJECT
57 list<tuple<String, JSON>> values;
58 end LIST_OBJECT;
59 record ARRAY
60 Vector<JSON> values;
61 end ARRAY;
62 record LIST
63 list<JSON> values;
64 end LIST;
65 record STRING
66 String str;
67 end STRING;
68 record INTEGER
69 Integer i;
70 end INTEGER;
71 record NUMBER
72 Real r;
73 end NUMBER;
74 record TRUE
75 end TRUE;
76 record FALSE
77 end FALSE;
78 record NULL
79 end NULL;
80
81 function emptyObject
82 output JSON obj;
83 algorithm
84 2251 obj := OBJECT(UnorderedMap.new<JSON>(stringHashDjb2, stringEq));
85 end emptyObject;
86
87 function emptyListObject
88 output JSON obj = LIST_OBJECT({});
89 end emptyListObject;
90
91 function fromPair
92 input String key;
93 input JSON value;
94 output JSON obj;
95 algorithm
96 ✗ obj := emptyObject();
97 ✗ obj := addPair(key, value, obj);
98 end fromPair;
99
100 function listObjectFromPair
101 input String key;
102 input JSON value;
103 output JSON obj = LIST_OBJECT({(key, value)});
104 end listObjectFromPair;
105
106 function emptyArray
107 input Integer capacity = 0;
108 output JSON obj = ARRAY(Vector.new<JSON>(capacity));
109 end emptyArray;
110
111 function makeArray
112 input list<JSON> elements;
113 output JSON obj = ARRAY(Vector.fromList(elements));
114 end makeArray;
115
116 function makeList
117 input list<JSON> elements;
118 output JSON obj = LIST(elements);
119 end makeList;
120
121 function makeString
122 input String str;
123 output JSON obj = STRING(str);
124 end makeString;
125
126 function makeInteger
127 input Integer i;
128 output JSON obj = INTEGER(i);
129 end makeInteger;
130
131 function makeNumber
132 input Real r;
133 output JSON obj = NUMBER(r);
134 end makeNumber;
135
136 function makeBoolean
137 input Boolean b;
138 output JSON obj = if b then TRUE() else FALSE();
139 end makeBoolean;
140
141 function makeNull
142 output JSON obj = NULL();
143 end makeNull;
144
145 function isNull
146 input JSON obj;
147 output Boolean res;
148 algorithm
149 res := match obj
150 case NULL() then true;
151 else false;
152 end match;
153 end isNull;
154
155 function addElement
156 "Adds a value at the end of a JSON array, or returns a new array with the
157 given value if the JSON is null."
158 input JSON value;
159 input JSON obj;
160 output JSON outObj;
161 algorithm
162 outObj := match obj
163 case ARRAY()
164 algorithm
165 443 Vector.push(obj.values, value);
166 then
167 obj;
168
169 case NULL()
170 104 then addElement(value, emptyArray());
171 end match;
172 end addElement;
173
174 function addElementNotNull
175 input JSON value;
176 input JSON obj;
177 output JSON outObj;
178 algorithm
179
2/2
✓ Branch 1 taken 137 times.
✓ Branch 2 taken 2 times.
139 outObj := if isNull(value) then obj else addElement(value, obj);
180 end addElementNotNull;
181
182 function addPair
183 "Adds a key-value pair to a JSON object, or returns a new object with the
184 key-value pair if the JSON is null."
185 input String key;
186 input JSON value;
187 input JSON obj;
188 output JSON outObj;
189 algorithm
190 outObj := match obj
191 case OBJECT()
192 algorithm
193 ✗ UnorderedMap.add(key, value, obj.values);
194 then
195 obj;
196
197 case LIST_OBJECT()
198 4276 then LIST_OBJECT((key, value) :: obj.values);
199
200 case NULL()
201 790 then addPair(key, value, emptyListObject());
202 end match;
203 end addPair;
204
205 function addPairNotNull
206 "Adds a key-value pair to a JSON object if the value is not null."
207 input String key;
208 input JSON value;
209 input JSON obj;
210 output JSON outObj;
211 algorithm
212
2/2
✓ Branch 1 taken 233 times.
✓ Branch 2 taken 1075 times.
1308 outObj := if isNull(value) then obj else addPair(key, value, obj);
213 end addPairNotNull;
214
215 function toListForm
216 "Returns a JSON value where all OBJECT (hash-map backed) and ARRAY (vector
217 backed) nodes have been converted, recursively, into the list-based
218 LIST_OBJECT and LIST nodes. The result consists only of plain MetaModelica
219 lists, tuples and scalars, which can be traversed from C/C++ (e.g. from
220 OMEdit, see issue #15219) without knowing the internal layout of UnorderedMap
221 and Vector."
222 input JSON value;
223 output JSON outValue;
224 algorithm
225 outValue := match value
226 local
227 list<tuple<String, JSON>> pairs;
228 list<JSON> elems;
229 String key;
230 JSON v;
231
232 case OBJECT()
233 algorithm
234 pairs := {};
235 ✗ for i in 1:UnorderedMap.size(value.values) loop
236 ✗ pairs := (UnorderedMap.keyAt(value.values, i),
237 toListForm(UnorderedMap.valueAt(value.values, i))) :: pairs;
238 end for;
239 ✗ then
240 LIST_OBJECT(listReverse(pairs));
241
242 case LIST_OBJECT()
243 algorithm
244 pairs := {};
245
2/2
✓ Branch 0 taken 724 times.
✓ Branch 1 taken 312 times.
1036 for p in value.values loop
246 724 (key, v) := p;
247 724 pairs := (key, toListForm(v)) :: pairs;
248 end for;
249 312 then
250 LIST_OBJECT(listReverse(pairs));
251
252 case ARRAY()
253 algorithm
254 elems := {};
255
1/2
✓ Branch 1 taken 120 times.
✗ Branch 2 not taken.
356 for i in Vector.size(value.values):-1:1 loop
256 236 elems := toListForm(Vector.getNoBounds(value.values, i)) :: elems;
257 end for;
258 120 then
259 LIST(elems);
260
261 case LIST()
262 algorithm
263 elems := {};
264
2/2
✓ Branch 1 taken 800 times.
✓ Branch 2 taken 241 times.
1041 for e in listReverse(value.values) loop
265 800 elems := toListForm(e) :: elems;
266 end for;
267 241 then
268 LIST(elems);
269
270 else value;
271 end match;
272 end toListForm;
273
274 function toString
275 input JSON value;
276 input Boolean prettyPrint = false;
277 output String str;
278 protected
279 Integer handle;
280 algorithm
281 86 handle := Print.saveAndClearBuf();
282
283
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 18 times.
86 if prettyPrint then
284 68 toStringPP_work(value);
285 else
286 18 toString_work(value);
287 end if;
288
289 86 str := Print.getString();
290 86 Print.restoreBuf(handle);
291 end toString;
292
293 function toString_work
294 input JSON value;
295 algorithm
296 () := match value
297 case STRING()
298 algorithm
299 279 Print.printBuf("\"");
300 279 Print.printBuf(System.escapedString(value.str, true));
301 279 Print.printBuf("\"");
302 then
303 ();
304
305 case TRUE()
306 algorithm
307 24 Print.printBuf("true");
308 then
309 ();
310
311 case FALSE()
312 algorithm
313 7 Print.printBuf("false");
314 then
315 ();
316
317 case NULL()
318 algorithm
319 5 Print.printBuf("null");
320 then
321 ();
322
323 case INTEGER()
324 algorithm
325 330 Print.printBuf(String(value.i));
326 then
327 ();
328
329 case NUMBER()
330 algorithm
331 ✗ Print.printBuf(String(value.r));
332 then
333 ();
334
335 case ARRAY()
336 algorithm
337 45 toString_array(value.values);
338 then
339 ();
340
341 case LIST()
342 algorithm
343 19 toString_list(value.values);
344 then
345 ();
346
347 case OBJECT()
348 algorithm
349 ✗ toString_object(value.values);
350 then
351 ();
352
353 case LIST_OBJECT()
354 algorithm
355 83 toString_listObject(value.values);
356 then
357 ();
358
359 else ();
360 end match;
361 end toString_work;
362
363 function toString_array
364 input Vector<JSON> values;
365 algorithm
366 45 Print.printBuf("[");
367
368
2/2
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 23 times.
86 for i in 1:Vector.size(values) loop
369
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 22 times.
41 if i <> 1 then
370 19 Print.printBuf(", ");
371 end if;
372
373 41 toString_work(Vector.getNoBounds(values, i));
374 end for;
375
376 45 Print.printBuf("]");
377 end toString_array;
378
379 function toString_list
380 input list<JSON> values;
381 protected
382 Boolean first = true;
383 algorithm
384 19 Print.printBuf("[");
385
386
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 19 times.
41 for v in values loop
387
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 16 times.
22 if first then
388 first := false;
389 else
390 6 Print.printBuf(", ");
391 end if;
392
393 22 toString_work(v);
394 end for;
395
396 19 Print.printBuf("]");
397 end toString_list;
398
399 function toString_object
400 input UnorderedMap<String, JSON> map;
401 algorithm
402 ✗ Print.printBuf("{");
403
404 ✗ for i in 1:UnorderedMap.size(map) loop
405 ✗ if i <> 1 then
406 ✗ Print.printBuf(", ");
407 end if;
408
409 ✗ Print.printBuf("\"");
410 ✗ Print.printBuf(UnorderedMap.keyAt(map, i));
411 ✗ Print.printBuf("\":");
412 ✗ toString_work(UnorderedMap.valueAt(map, i));
413 end for;
414
415 ✗ Print.printBuf("}");
416 end toString_object;
417
418 function toString_listObject
419 input list<tuple<String, JSON>> object;
420 protected
421 Boolean first = true;
422 String key;
423 JSON value;
424 algorithm
425 83 Print.printBuf("{");
426
427
2/2
✓ Branch 1 taken 711 times.
✓ Branch 2 taken 83 times.
794 for entry in listReverse(object) loop
428 711 (key, value) := entry;
429
430
2/2
✓ Branch 0 taken 628 times.
✓ Branch 1 taken 83 times.
711 if first then
431 first := false;
432 else
433 628 Print.printBuf(", ");
434 end if;
435
436 711 Print.printBuf("\"");
437 711 Print.printBuf(key);
438 711 Print.printBuf("\":");
439 711 toString_work(value);
440 end for;
441
442 83 Print.printBuf("}");
443 end toString_listObject;
444
445 function toStringPP_work
446 input JSON value;
447 input String indent = "";
448 algorithm
449 () := match value
450 case STRING()
451 algorithm
452 1323 Print.printBuf("\"");
453 1323 Print.printBuf(System.escapedString(value.str, true));
454 1323 Print.printBuf("\"");
455 then
456 ();
457
458 case TRUE()
459 algorithm
460 91 Print.printBuf("true");
461 then
462 ();
463
464 case FALSE()
465 algorithm
466 8 Print.printBuf("false");
467 then
468 ();
469
470 case NULL()
471 algorithm
472 ✗ Print.printBuf("null");
473 then
474 ();
475
476 case INTEGER()
477 algorithm
478 931 Print.printBuf(String(value.i));
479 then
480 ();
481
482 case NUMBER()
483 algorithm
484 123 Print.printBuf(String(value.r));
485 then
486 ();
487
488 case ARRAY()
489 algorithm
490 203 toStringPP_array(value.values, indent);
491 then
492 ();
493
494 case LIST()
495 algorithm
496 133 toStringPP_list(value.values, indent);
497 then
498 ();
499
500 case OBJECT()
501 algorithm
502 ✗ toStringPP_object(value.values, indent);
503 then
504 ();
505
506 case LIST_OBJECT()
507 algorithm
508 807 toStringPP_listObject(value.values, indent);
509 then
510 ();
511
512 else ();
513 end match;
514 end toStringPP_work;
515
516 function toStringPP_array
517 input Vector<JSON> values;
518 input String indent;
519 protected
520 String next_indent = indent + " ";
521 algorithm
522 203 Print.printBuf("[\n");
523
524
2/2
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 22 times.
491 for i in 1:Vector.size(values) loop
525
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 181 times.
288 if i <> 1 then
526 107 Print.printBuf(",\n");
527 end if;
528
529 288 Print.printBuf(next_indent);
530 288 toStringPP_work(Vector.getNoBounds(values, i), next_indent);
531 end for;
532
533 203 Print.printBuf("\n");
534 203 Print.printBuf(indent);
535 203 Print.printBuf("]");
536 end toStringPP_array;
537
538 function toStringPP_list
539 input list<JSON> values;
540 input String indent;
541 protected
542 String next_indent = indent + " ";
543 Boolean first = true;
544 algorithm
545 133 Print.printBuf("[\n");
546
547
2/2
✓ Branch 0 taken 378 times.
✓ Branch 1 taken 133 times.
511 for v in values loop
548
2/2
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 125 times.
378 if first then
549 first := false;
550 else
551 253 Print.printBuf(",\n");
552 end if;
553
554 378 Print.printBuf(next_indent);
555 378 toStringPP_work(v, next_indent);
556 end for;
557
558 133 Print.printBuf("\n");
559 133 Print.printBuf(indent);
560 133 Print.printBuf("]");
561 end toStringPP_list;
562
563 function toStringPP_object
564 input UnorderedMap<String, JSON> map;
565 input String indent;
566 protected
567 String next_indent = indent + " ";
568 algorithm
569 ✗ Print.printBuf("{");
570
571 ✗ for i in 1:UnorderedMap.size(map) loop
572 ✗ Print.printBuf(if i == 1 then "\n" else ",\n");
573 ✗ Print.printBuf(next_indent);
574 ✗ Print.printBuf("\"");
575 ✗ Print.printBuf(UnorderedMap.keyAt(map, i));
576 ✗ Print.printBuf("\": ");
577 ✗ toStringPP_work(UnorderedMap.valueAt(map, i), next_indent);
578 end for;
579
580 ✗ Print.printBuf("\n");
581 ✗ Print.printBuf(indent);
582 ✗ Print.printBuf("}");
583 end toStringPP_object;
584
585 function toStringPP_listObject
586 input list<tuple<String, JSON>> object;
587 input String indent;
588 protected
589 Boolean first = true;
590 String key;
591 JSON value;
592 String next_indent = indent + " ";
593 algorithm
594 807 Print.printBuf("{\n");
595
596
2/2
✓ Branch 1 taken 2885 times.
✓ Branch 2 taken 807 times.
3692 for entry in listReverse(object) loop
597 2885 (key, value) := entry;
598
599
2/2
✓ Branch 0 taken 2079 times.
✓ Branch 1 taken 806 times.
2885 if first then
600 first := false;
601 else
602 2079 Print.printBuf(",\n");
603 end if;
604
605 2885 Print.printBuf(next_indent);
606 2885 Print.printBuf("\"");
607 2885 Print.printBuf(key);
608 2885 Print.printBuf("\": ");
609 2885 toStringPP_work(value, next_indent);
610 end for;
611
612 807 Print.printBuf("\n");
613 807 Print.printBuf(indent);
614 807 Print.printBuf("}");
615 end toStringPP_listObject;
616
617 partial function partialParser
618 input list<Token> inTokens;
619 output JSON value;
620 output list<Token> tokens = inTokens;
621 protected
622 Token tok;
623 end partialParser;
624
625 function parseFile
626 input String fileName;
627 output JSON value;
628 protected
629 list<Token> tokens,errTokens;
630 algorithm
631 ✗ (tokens,errTokens) := LexerJSON.scan(fileName);
632 ✗ reportErrors(errTokens);
633 ✗ value := parse_value_check_empty(tokens);
634 end parseFile;
635
636 function hasKey
637 input JSON obj;
638 input String str;
639 output Boolean b;
640 algorithm
641 b := match obj
642 ✗ case OBJECT() then UnorderedMap.contains(str, obj.values);
643 case LIST_OBJECT()
644 algorithm
645 b := false;
646 ✗ for entry in obj.values loop
647 ✗ if Util.tuple21(entry) == str then
648 b := true;
649 end if;
650 end for;
651 then
652 b;
653 end match;
654 end hasKey;
655
656 function get
657 input JSON obj;
658 input String str;
659 output JSON out;
660 algorithm
661 out := match obj
662 2251 case OBJECT() then UnorderedMap.getOrFail(str, obj.values);
663 case LIST_OBJECT()
664 algorithm
665 ✗ for entry in obj.values loop
666 ✗ if Util.tuple21(entry) == str then
667 ✗ out := Util.tuple22(entry);
668 ✗ return;
669 end if;
670 end for;
671 ✗ then
672 fail();
673 end match;
674 end get;
675
676 function getOrDefault
677 input JSON obj;
678 input String str;
679 input JSON default;
680 output JSON out;
681 algorithm
682 out := match obj
683 ✗ case OBJECT() then UnorderedMap.getOrDefault(str, obj.values, default);
684 case LIST_OBJECT()
685 algorithm
686 ✗ for entry in obj.values loop
687 ✗ if Util.tuple21(entry) == str then
688 ✗ out := Util.tuple22(entry);
689 ✗ return;
690 end if;
691 end for;
692 then
693 default;
694 else default;
695 end match;
696 end getOrDefault;
697
698 function at
699 input JSON obj;
700 input Integer index;
701 output JSON out;
702 algorithm
703 out := match obj
704 ✗ case ARRAY() then Vector.get(obj.values, index);
705 end match;
706 end at;
707
708 function getString
709 input JSON obj;
710 output String str;
711 algorithm
712 ✗ JSON.STRING(str) := obj;
713 end getString;
714
715 function getStringList
716 input JSON obj;
717 output list<String> strl;
718 algorithm
719 strl := match obj
720 ✗ case OBJECT() then list(getString(v) for v in UnorderedMap.valueList(obj.values));
721 ✗ case LIST_OBJECT() then listReverse(getString(Util.tuple22(v)) for v in obj.values);
722 ✗ case ARRAY() then Vector.mapToList(obj.values, getString);
723 ✗ case LIST() then list(getString(v) for v in obj.values);
724 end match;
725 end getStringList;
726
727 function getKeys
728 input JSON obj;
729 output list<String> keys;
730 algorithm
731 keys := match obj
732 ✗ case OBJECT() then UnorderedMap.keyList(obj.values);
733 ✗ case LIST_OBJECT() then listReverse(Util.tuple21(e) for e in obj.values);
734 end match;
735 end getKeys;
736
737 function getBoolean
738 input JSON obj;
739 output Boolean b;
740 algorithm
741 b := match obj
742 case JSON.TRUE() then true;
743 case JSON.FALSE() then false;
744 end match;
745 end getBoolean;
746
747 function size
748 input JSON obj;
749 output Integer sz;
750 algorithm
751 sz := match obj
752 ✗ case OBJECT() then UnorderedMap.size(obj.values);
753 ✗ case LIST_OBJECT() then listLength(obj.values);
754 ✗ case ARRAY() then Vector.size(obj.values);
755 ✗ case LIST() then listLength(obj.values);
756 else 1;
757 end match;
758 end size;
759
760 function parse
761 input String content;
762 input String fileName="<String>";
763 output JSON value;
764 protected
765 list<Token> tokens,errTokens;
766 algorithm
767 ✗ (tokens,errTokens) := LexerJSON.scanString(content,fileName=fileName);
768 ✗ reportErrors(errTokens);
769 ✗ value := parse_value_check_empty(tokens);
770 end parse;
771
772 function parse_value_check_empty
773 input list<Token> inTokens;
774 output JSON value;
775 protected
776 list<Token> tokens;
777 algorithm
778 ✗ (value,tokens) := parse_value(inTokens);
779 ✗ check_empty(tokens);
780 end parse_value_check_empty;
781
782 function parse_value
783 extends partialParser;
784 algorithm
785 ✗ not_eof(tokens);
786 ✗ tok::tokens := tokens;
787 (value,tokens) := match tok.id
788 ✗ case TokenId.STRING algorithm (value,tokens) := parse_string(inTokens); then (value,tokens);
789 ✗ case TokenId.INTEGER algorithm (value,tokens) := parse_integer(inTokens); then (value,tokens);
790 ✗ case TokenId.NUMBER algorithm (value,tokens) := parse_number(inTokens); then (value,tokens);
791 ✗ case TokenId.OBJECTBEGIN algorithm (value,tokens) := parse_object(inTokens); then (value,tokens);
792 ✗ case TokenId.ARRAYBEGIN algorithm (value,tokens) := parse_array(inTokens); then (value,tokens);
793 ✗ case TokenId.TRUE then (TRUE(),tokens);
794 ✗ case TokenId.FALSE then (FALSE(),tokens);
795 ✗ case TokenId.NULL then (NULL(),tokens);
796 else
797 algorithm
798 ✗ errorExpected("a value", tok);
799 then fail();
800 end match;
801 end parse_value;
802
803 function parse_string
804 extends partialParser;
805 protected
806 String content;
807 algorithm
808 ✗ not_eof(tokens);
809 ✗ tok::tokens := tokens;
810 ✗ if tok.id <> TokenId.STRING then
811 ✗ errorExpected("a String", tok);
812 end if;
813 ✗ content := tokenContent(tok);
814 ✗ if stringLength(content)==2 then
815 content := "";
816 else
817 ✗ content := System.unescapedString(substring(content,2,stringLength(content)-1));
818 end if;
819 ✗ value := STRING(content);
820 end parse_string;
821
822 function parse_integer
823 extends partialParser;
824 protected
825 String content;
826 algorithm
827 ✗ not_eof(tokens);
828 ✗ tok::tokens := tokens;
829 ✗ if tok.id <> TokenId.INTEGER then
830 ✗ errorExpected("an integer", tok);
831 end if;
832 ✗ content := tokenContent(tok);
833 ✗ value := INTEGER(stringInt(content));
834 end parse_integer;
835
836 function parse_number
837 extends partialParser;
838 protected
839 String content;
840 algorithm
841 ✗ not_eof(tokens);
842 ✗ tok::tokens := tokens;
843 ✗ if tok.id <> TokenId.NUMBER then
844 ✗ errorExpected("a (real) number", tok);
845 end if;
846 ✗ content := tokenContent(tok);
847 ✗ value := NUMBER(stringReal(content));
848 end parse_number;
849
850
851 function parse_array
852 extends partialParser;
853 protected
854 Vector<JSON> values = Vector.new<JSON>();
855 Boolean cont;
856 algorithm
857 ✗ value := emptyObject();
858 ✗ tokens := parse_expected_token(tokens, TokenId.ARRAYBEGIN);
859 ✗ cont := peek_id(tokens) <> TokenId.ARRAYEND;
860 ✗ while cont loop
861 ✗ (value,tokens) := parse_value(tokens);
862 ✗ Vector.push(values, value);
863 ✗ (tokens,cont) := eat_if_next_token_matches(tokens, TokenId.COMMA);
864 end while;
865 ✗ tokens := parse_expected_token(tokens, TokenId.ARRAYEND);
866 ✗ value := ARRAY(values);
867 end parse_array;
868
869 function parse_object
870 extends partialParser;
871 protected
872 UnorderedMap<String, JSON> values;
873 String key;
874 Boolean cont;
875 algorithm
876 ✗ values := UnorderedMap.new<JSON>(stringHashDjb2, stringEq);
877 ✗ tokens := parse_expected_token(tokens, TokenId.OBJECTBEGIN);
878 ✗ cont := peek_id(tokens) <> TokenId.ARRAYEND;
879 ✗ while cont loop
880 ✗ (STRING(str=key), tokens) := parse_string(tokens);
881 ✗ tokens := parse_expected_token(tokens,TokenId.COLON);
882 ✗ (value,tokens) := parse_value(tokens);
883 ✗ UnorderedMap.add(key, value, values);
884 ✗ (tokens,cont) := eat_if_next_token_matches(tokens, TokenId.COMMA);
885 end while;
886 ✗ tokens := parse_expected_token(tokens, TokenId.OBJECTEND);
887 ✗ value := OBJECT(values);
888 end parse_object;
889
890 protected
891
892 function reportErrors
893 input list<Token> tokens;
894 protected
895 Integer i=0;
896 algorithm
897 ✗ for t in tokens loop
898 ✗ i := i+1;
899 ✗ if i>10 then
900 ✗ Error.addMessage(Error.SCANNER_ERROR_LIMIT, {});
901 end if;
902 ✗ Error.addSourceMessage(Error.SCANNER_ERROR, {tokenContent(t)}, tokenSourceInfo(t));
903 end for;
904 ✗ if not listEmpty(tokens) then
905 ✗ fail();
906 end if;
907 end reportErrors;
908
909 function not_eof
910 input output list<Token> tokens;
911 algorithm
912 ✗ if listEmpty(tokens) then
913 ✗ Error.addCompilerError("JSON expected value, got <EOF>...");
914 ✗ fail();
915 end if;
916 end not_eof;
917
918 function peek_id
919 input list<Token> tokens;
920 output TokenId nextToken;
921 protected
922 Token tok;
923 algorithm
924 if listEmpty(tokens) then
925 nextToken := TokenId._NO_TOKEN;
926 end if;
927 ✗ tok := listHead(tokens);
928 ✗ nextToken := tok.id;
929 end peek_id;
930
931 function eat_if_next_token_matches
932 input output list<Token> tokens;
933 input TokenId expectedToken;
934 output Boolean matched=false;
935 protected
936 Token tok;
937 algorithm
938 ✗ if listEmpty(tokens) then
939 ✗ return;
940 end if;
941 ✗ tok := listHead(tokens);
942 ✗ if tok.id <> expectedToken then
943 ✗ return;
944 end if;
945 matched := true;
946 ✗ _::tokens := tokens;
947 end eat_if_next_token_matches;
948
949 function parse_expected_token
950 input output list<Token> tokens;
951 input TokenId expectedToken;
952 protected
953 Token tok;
954 algorithm
955 ✗ not_eof(tokens);
956 ✗ tok::tokens := tokens;
957 ✗ if tok.id <> expectedToken then
958 ✗ Error.addSourceMessage(Error.COMPILER_ERROR, {"Expected a "+String(expectedToken)+", got token: " + tokenContent(tok)}, tokenSourceInfo(tok));
959 ✗ fail();
960 end if;
961 end parse_expected_token;
962
963 function check_empty
964 input list<Token> tokens;
965 protected
966 Token tok;
967 algorithm
968 ✗ if listEmpty(tokens) then
969 ✗ return;
970 end if;
971 ✗ tok := listHead(tokens);
972 ✗ Error.addSourceMessage(Error.COMPILER_ERROR, {"Expected <EOF>, got more tokens, starting with: " + tokenContent(tok)}, tokenSourceInfo(tok));
973 ✗ fail();
974 end check_empty;
975
976 function errorExpected
977 input String expected;
978 input Token tok;
979 algorithm
980 ✗ Error.addSourceMessage(Error.COMPILER_ERROR, {"JSON expected "+expected+", got token "+String(tok.id)+": " + tokenContent(tok)}, tokenSourceInfo(tok));
981 ✗ fail();
982 end errorExpected;
983
984 public function dumpJSONSourceInfo
985 input SourceInfo info;
986 input Boolean dumpFilename = true;
987 output JSON json = JSON.makeNull();
988 algorithm
989
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 5 times.
119 if dumpFilename then
990 114 json := JSON.addPair("filename", JSON.makeString(Testsuite.friendly(info.fileName)), json);
991 end if;
992
993 119 json := JSON.addPair("lineStart", JSON.makeInteger(info.lineNumberStart), json);
994 119 json := JSON.addPair("columnStart", JSON.makeInteger(info.columnNumberStart), json);
995 119 json := JSON.addPair("lineEnd", JSON.makeInteger(info.lineNumberEnd), json);
996 119 json := JSON.addPair("columnEnd", JSON.makeInteger(info.columnNumberEnd), json);
997
998
1/2
✓ Branch 0 taken 119 times.
✗ Branch 1 not taken.
119 if info.isReadOnly then
999 ✗ json := JSON.addPair("readonly", JSON.makeBoolean(true), json);
1000 end if;
1001 end dumpJSONSourceInfo;
1002
1003 annotation(__OpenModelica_Interface="util");
1004 end JSON;
1005