xref: /aosp_15_r20/external/emboss/compiler/front_end/module_ir_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
1# Copyright 2019 Google LLC
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Tests for module_ir."""
16
17from __future__ import print_function
18
19import collections
20import pkgutil
21import unittest
22
23from compiler.front_end import module_ir
24from compiler.front_end import parser
25from compiler.front_end import tokenizer
26from compiler.util import ir_data
27from compiler.util import ir_data_fields
28from compiler.util import ir_data_utils
29from compiler.util import test_util
30
31_TESTDATA_PATH = "testdata.golden"
32_MINIMAL_SOURCE = pkgutil.get_data(
33        _TESTDATA_PATH, "span_se_log_file_status.emb").decode(encoding="UTF-8")
34_MINIMAL_SAMPLE = parser.parse_module(
35    tokenizer.tokenize(_MINIMAL_SOURCE, "")[0]).parse_tree
36_MINIMAL_SAMPLE_IR = ir_data_utils.IrDataSerializer.from_json(ir_data.Module,
37    pkgutil.get_data(_TESTDATA_PATH, "span_se_log_file_status.ir.txt").decode(
38        encoding="UTF-8")
39)
40
41# _TEST_CASES contains test cases, separated by '===', that ensure that specific
42# results show up in the IR for .embs.
43#
44# Each test case is of the form:
45#
46#     name
47#     ---
48#     .emb text
49#     ---
50#     (incomplete) IR text format
51#
52# For each test case, the .emb is parsed into a parse tree, which is fed into
53# module_ir.build_ir(), which should successfully return an IR.  The generated
54# IR is then compared against the incomplete IR in the test case to ensure that
55# the generated IR is a strict superset of the test case IR -- that is, it is OK
56# if the generated IR contains fields that are not in the test case, but not if
57# the test case contains fields that are not in the generated IR, and not if the
58# test case contains fields whose values differ from the generated IR.
59#
60# Additionally, for each test case, a pass is executed to ensure that the source
61# code location for each node in the IR is strictly contained within the source
62# location for its parent node.
63_TEST_CASES = r"""
64prelude
65---
66external UInt:
67  [fixed_size: false]
68  [byte_order_dependent: true]
69
70external Byte:
71  [size: 1]
72  [byte_order_dependent: false]
73---
74{
75  "type": [
76    {
77      "external": {},
78      "name": { "name": { "text": "UInt" } },
79      "attribute": [
80        {
81          "name": { "text": "fixed_size" },
82          "value": { "expression": { "boolean_constant": { "value": false } } }
83        },
84        {
85          "name": { "text": "byte_order_dependent" },
86          "value": { "expression": { "boolean_constant": { "value": true } } }
87        }
88      ]
89    },
90    {
91      "external": {},
92      "name": { "name": { "text": "Byte" } },
93      "attribute": [
94        {
95          "name": { "text": "size" },
96          "value": { "expression": { "constant": { "value": "1" } } }
97        },
98        {
99          "name": { "text": "byte_order_dependent" },
100          "value": { "expression": { "boolean_constant": { "value": false } } }
101        }
102      ]
103    }
104  ]
105}
106
107===
108numbers
109---
110bits Foo:
111  0000000000          [+0_000_000_003]   UInt  decimal
112  0b00000100          [+0b0000_0111]     UInt  binary
113  0b00000000_00001000 [+0b0_00001011]    UInt  binary2
114  0b_0_00001100       [+0b_00001111]     UInt  binary3
115  0x00000010          [+0x0000_0013]     UInt  hex
116  0x00000000_00000014 [+0x0_00000017]    UInt  hex2
117  0x_0_00000018       [+0x_0000001b]     UInt  hex3
118---
119{
120  "type": [
121    {
122      "structure": {
123        "field": [
124          {
125            "name": { "name": { "text": "decimal" } },
126            "location": {
127              "start": { "constant": { "value": "0" } },
128              "size": { "constant": { "value": "3" } }
129            }
130          },
131          {
132            "name": { "name": { "text": "binary" } },
133            "location": {
134              "start": { "constant": { "value": "4" } },
135              "size": { "constant": { "value": "7" }
136              }
137            }
138          },
139          {
140            "name": { "name": { "text": "binary2" } },
141            "location": {
142              "start": { "constant": { "value": "8" } },
143              "size": { "constant": { "value": "11" } }
144            }
145          },
146          {
147            "name": { "name": { "text": "binary3" } },
148            "location": {
149              "start": { "constant": { "value": "12" } },
150              "size": { "constant": { "value": "15" } }
151            }
152          },
153          {
154            "name": { "name": { "text": "hex" } },
155            "location": {
156              "start": { "constant": { "value": "16" } },
157              "size": { "constant": { "value": "19" } }
158            }
159          },
160          {
161            "name": { "name": { "text": "hex2" } },
162            "location": {
163              "start": { "constant": { "value": "20" } },
164              "size": { "constant": { "value": "23" } }
165            }
166          },
167          {
168            "name": { "name": { "text": "hex3" } },
169            "location": {
170              "start": { "constant": { "value": "24" } },
171              "size": { "constant": { "value": "27" } }
172            }
173          }
174        ]
175      }
176    }
177  ]
178}
179
180===
181enum
182---
183enum Kind:
184  WIDGET = 0
185  SPROCKET = 1
186  GEEGAW = 2  # Comment.
187  MAX32 = 4294967295
188  MAX64 = 9223372036854775807
189---
190{
191  "type": [
192    {
193      "enumeration": {
194        "value": [
195          {
196            "name": { "name": { "text": "WIDGET" } },
197            "value": { "constant": { "value": "0" } }
198          },
199          {
200            "name": { "name": { "text": "SPROCKET" } },
201            "value": { "constant": { "value": "1" } }
202          },
203          {
204            "name": { "name": { "text": "GEEGAW" } },
205            "value": { "constant": { "value": "2" } }
206          },
207          {
208            "name": { "name": { "text": "MAX32" } },
209            "value": { "constant": { "value": "4294967295" } }
210          },
211          {
212            "name": { "name": { "text": "MAX64" } },
213            "value": { "constant": { "value": "9223372036854775807" } }
214          }
215        ]
216      },
217      "name": { "name": { "text": "Kind" } }
218    }
219  ]
220}
221
222===
223struct attribute
224---
225struct Foo:
226  [size: 10]
227  0 [+0]  UInt  field
228---
229{
230  "type": [
231    {
232      "structure": {
233        "field": [ { "name": { "name": { "text": "field" } } } ]
234      },
235      "name": { "name": { "text": "Foo" } },
236      "attribute": [
237        {
238          "name": { "text": "size" },
239          "value": { "expression": { "constant": { "value": "10" } } },
240          "is_default": false
241        }
242      ]
243    }
244  ]
245}
246
247===
248$default attribute
249---
250[$default byte_order: "LittleEndian"]
251---
252{
253  "attribute": [
254    {
255      "name": { "text": "byte_order" },
256      "value": { "string_constant": { "text": "LittleEndian" } },
257      "is_default": true
258    }
259  ]
260}
261
262===
263abbreviations
264---
265struct Foo:
266  0 [+1]  UInt  size (s)
267---
268{
269  "type": [
270    {
271      "structure": {
272        "field": [
273          {
274            "name": { "name": { "text": "size" } },
275            "abbreviation": { "text": "s" }
276          }
277        ]
278      }
279    }
280  ]
281}
282
283===
284expressions
285---
286struct Foo:
287  0+1 [+2*3]             UInt  plus_times
288  4-5 [+(6)]             UInt  minus_paren
289  nn [+7*(8+9)]          UInt  name_complex
290  10+11+12 [+13*14*15]   UInt  associativity
291  16+17*18 [+19*20-21]   UInt  precedence
292  -(+1) [+0-(-10)]       UInt  unary_plus_minus
293  1 + + 2 [+3 - -4 - 5]  UInt  unary_plus_minus_2
294---
295{
296  "type": [
297    {
298      "structure": {
299        "field": [
300          {
301            "name": { "name": { "text": "plus_times" } },
302            "location": {
303              "start": {
304                "function": {
305                  "function": "ADDITION",
306                  "function_name": { "text": "+" },
307                  "args": [
308                    { "constant": { "value": "0" } },
309                    { "constant": { "value": "1" } }
310                  ]
311                }
312              },
313              "size": {
314                "function": {
315                  "function": "MULTIPLICATION",
316                  "function_name": { "text": "*" },
317                  "args": [
318                    { "constant": { "value": "2" } },
319                    { "constant": { "value": "3" } }
320                  ]
321                }
322              }
323            }
324          },
325          {
326            "name": { "name": { "text": "minus_paren" } },
327            "location": {
328              "start": {
329                "function": {
330                  "function": "SUBTRACTION",
331                  "args": [
332                    { "constant": { "value": "4" } },
333                    { "constant": { "value": "5" } }
334                  ]
335                }
336              },
337              "size": { "constant": { "value": "6" } }
338            }
339          },
340          {
341            "name": { "name": { "text": "name_complex" } },
342            "location": {
343              "start": {
344                "field_reference": {
345                  "path": [ { "source_name": [ { "text": "nn" } ] } ]
346                }
347              },
348              "size": {
349                "function": {
350                  "function": "MULTIPLICATION",
351                  "args": [
352                    { "constant": { "value": "7" } },
353                    {
354                      "function": {
355                        "function": "ADDITION",
356                        "args": [
357                          { "constant": { "value": "8" } },
358                          { "constant": { "value": "9" } }
359                        ]
360                      }
361                    }
362                  ]
363                }
364              }
365            }
366          },
367          {
368            "name": { "name": { "text": "associativity" } },
369            "location": {
370              "start": {
371                "function": {
372                  "function": "ADDITION",
373                  "args": [
374                    {
375                      "function": {
376                        "function": "ADDITION",
377                        "args": [
378                          { "constant": { "value": "10" } },
379                          { "constant": { "value": "11" } }
380                        ]
381                      }
382                    },
383                    { "constant": { "value": "12" } }
384                  ]
385                }
386              },
387              "size": {
388                "function": {
389                  "function": "MULTIPLICATION",
390                  "args": [
391                    {
392                      "function": {
393                        "function": "MULTIPLICATION",
394                        "args": [
395                          { "constant": { "value": "13" } },
396                          { "constant": { "value": "14" } }
397                        ]
398                      }
399                    },
400                    { "constant": { "value": "15" } }
401                  ]
402                }
403              }
404            }
405          },
406          {
407            "name": { "name": { "text": "precedence" } },
408            "location": {
409              "start": {
410                "function": {
411                  "function": "ADDITION",
412                  "args": [
413                    { "constant": { "value": "16" } },
414                    {
415                      "function": {
416                        "function": "MULTIPLICATION",
417                        "args": [
418                          { "constant": { "value": "17" } },
419                          { "constant": { "value": "18" } }
420                        ]
421                      }
422                    }
423                  ]
424                }
425              },
426              "size": {
427                "function": {
428                  "function": "SUBTRACTION",
429                  "args": [
430                    {
431                      "function": {
432                        "function": "MULTIPLICATION",
433                        "args": [
434                          { "constant": { "value": "19" } },
435                          { "constant": { "value": "20" } }
436                        ]
437                      }
438                    },
439                    { "constant": { "value": "21" } }
440                  ]
441                }
442              }
443            }
444          },
445          {
446            "name": { "name": { "text": "unary_plus_minus" } },
447            "location": {
448              "start": {
449                "function": {
450                  "function": "SUBTRACTION",
451                  "function_name": {
452                    "text": "-",
453                    "source_location": {
454                      "start": { "line": 8, "column": 3 },
455                      "end": { "line": 8, "column": 4 }
456                    }
457                  },
458                  "args": [
459                    {
460                      "constant": {
461                        "value": "0",
462                        "source_location": {
463                          "start": { "line": 8, "column": 3 },
464                          "end": { "line": 8, "column": 3 }
465                        }
466                      },
467                      "source_location": {
468                        "start": { "line": 8, "column": 3 },
469                        "end": { "line": 8, "column": 3 }
470                      }
471                    },
472                    {
473                      "function": {
474                        "function": "ADDITION",
475                        "function_name": {
476                          "text": "+",
477                          "source_location": {
478                            "start": { "line": 8, "column": 5 },
479                            "end": { "line": 8, "column": 6 }
480                          }
481                        },
482                        "args": [
483                          {
484                            "constant": { "value": "0" },
485                            "source_location": {
486                              "start": { "line": 8, "column": 5 },
487                              "end": { "line": 8, "column": 5 }
488                            }
489                          },
490                          {
491                            "constant": { "value": "1" },
492                            "source_location": {
493                              "start": { "line": 8, "column": 6 },
494                              "end": { "line": 8, "column": 7 }
495                            }
496                          }
497                        ]
498                      },
499                      "source_location": {
500                        "start": { "line": 8, "column": 4 },
501                        "end": { "line": 8, "column": 8 }
502                      }
503                    }
504                  ]
505                }
506              },
507              "size": {
508                "function": {
509                  "function": "SUBTRACTION",
510                  "function_name": {
511                    "text": "-",
512                    "source_location": {
513                      "start": { "line": 8, "column": 12 },
514                      "end": { "line": 8, "column": 13 }
515                    }
516                  },
517                  "args": [
518                    {
519                      "constant": {
520                        "value": "0",
521                        "source_location": {
522                          "start": { "line": 8, "column": 11 },
523                          "end": { "line": 8, "column": 12 }
524                        }
525                      },
526                      "source_location": {
527                        "start": { "line": 8, "column": 11 },
528                        "end": { "line": 8, "column": 12 }
529                      }
530                    },
531                    {
532                      "function": {
533                        "function": "SUBTRACTION",
534                        "function_name": {
535                          "text": "-",
536                          "source_location": {
537                            "start": { "line": 8, "column": 14 },
538                            "end": { "line": 8, "column": 15 }
539                          }
540                        },
541                        "args": [
542                          {
543                            "constant": { "value": "0" },
544                            "source_location": {
545                              "start": { "line": 8, "column": 14 },
546                              "end": { "line": 8, "column": 14 }
547                            }
548                          },
549                          {
550                            "constant": { "value": "10" },
551                            "source_location": {
552                              "start": { "line": 8, "column": 15 },
553                              "end": { "line": 8, "column": 17 }
554                            }
555                          }
556                        ]
557                      },
558                      "source_location": {
559                        "start": { "line": 8, "column": 13 },
560                        "end": { "line": 8, "column": 18 }
561                      }
562                    }
563                  ]
564                }
565              }
566            }
567          },
568          {
569            "name": { "name": { "text": "unary_plus_minus_2" } },
570            "location": {
571              "start": {
572                "function": {
573                  "function": "ADDITION",
574                  "args": [
575                    { "constant": { "value": "1" } },
576                    {
577                      "function": {
578                        "function": "ADDITION",
579                        "args": [
580                          { "constant": { "value": "0" } },
581                          { "constant": { "value": "2" } }
582                        ]
583                      }
584                    }
585                  ]
586                }
587              },
588              "size": {
589                "function": {
590                  "function": "SUBTRACTION",
591                  "args": [
592                    {
593                      "function": {
594                        "function": "SUBTRACTION",
595                        "args": [
596                          { "constant": { "value": "3" } },
597                          {
598                            "function": {
599                              "function": "SUBTRACTION",
600                              "args": [
601                                { "constant": { "value": "0" } },
602                                { "constant": { "value": "4" } }
603                              ]
604                            }
605                          }
606                        ]
607                      }
608                    },
609                    { "constant": { "value": "5" } }
610                  ]
611                }
612              }
613            }
614          }
615        ]
616      }
617    }
618  ]
619}
620
621===
622auto array size
623---
624struct TenElementArray:
625  0 [+10]  Byte[]  bytes
626---
627{
628  "type": [
629    {
630      "structure": {
631        "field": [
632          {
633            "type": {
634              "array_type": {
635                "base_type": {
636                  "atomic_type": {
637                    "reference": { "source_name": [ { "text": "Byte" } ] }
638                  }
639                },
640                "automatic": {
641                  "source_location": {
642                    "start": { "line": 3, "column": 16 },
643                    "end": { "line": 3, "column": 18 }
644                  }
645                }
646              }
647            },
648            "name": { "name": { "text": "bytes" } }
649          }
650        ]
651      }
652    }
653  ]
654}
655
656===
657start [+size] ranges
658---
659struct Foo:
660  0 [ + 1 ]  UInt     zero_plus_one
661  s [+2]     UInt     s_plus_two
662  s [+t]     Byte[t]  s_plus_t
663---
664{
665  "type": [
666    {
667      "structure": {
668        "field": [
669          {
670            "name": { "name": { "text": "zero_plus_one" } },
671            "location": {
672              "start": {
673                "constant": { "value": "0" },
674                "source_location": {
675                  "start": { "line": 3, "column": 3 },
676                  "end": { "line": 3, "column": 4 }
677                }
678              },
679              "size": {
680                "constant": { "value": "1" },
681                "source_location": {
682                  "start": { "line": 3, "column": 9 },
683                  "end": { "line": 3, "column": 10 }
684                }
685              }
686            }
687          },
688          {
689            "name": { "name": { "text": "s_plus_two" } },
690            "location": {
691              "start": {
692                "field_reference": {
693                  "path": [ { "source_name": [ { "text": "s" } ] } ]
694                }
695              },
696              "size": { "constant": { "value": "2" } }
697            }
698          },
699          {
700            "name": { "name": { "text": "s_plus_t" } },
701            "location": {
702              "start": {
703                "field_reference": {
704                  "path": [ { "source_name": [ { "text": "s" } ] } ]
705                }
706              },
707              "size": {
708                "field_reference": {
709                  "path": [ { "source_name": [ { "text": "t" } ] } ]
710                }
711              }
712            }
713          }
714        ]
715      }
716    }
717  ]
718}
719
720===
721Using Enum.VALUEs in expressions
722---
723struct Foo:
724  0 [+0+Number.FOUR]  UInt               length_four
725  Number.FOUR [+8]    UInt               start_four
726  8 [+3*Number.FOUR]  UInt               end_four
727  12 [+16]            Byte[Number.FOUR]  array_size_four
728
729enum Number:
730  FOUR = 4
731  EIGHT = FOUR + Number.FOUR
732  SIXTEEN = Number.FOUR * FOUR
733  INVALID = Number.NaN.FOUR
734---
735{
736  "type": [
737    {
738      "structure": {
739        "field": [
740          {
741            "name": { "name": { "text": "length_four" } },
742            "location": {
743              "size": {
744                "function": {
745                  "function": "ADDITION",
746                  "args": [
747                    { "constant": { "value": "0" } },
748                    {
749                      "constant_reference": {
750                        "source_name": [
751                          { "text": "Number" },
752                          { "text": "FOUR" }
753                        ]
754                      }
755                    }
756                  ]
757                }
758              }
759            }
760          },
761          {
762            "name": { "name": { "text": "start_four" } },
763            "location": {
764              "start": {
765                "constant_reference": {
766                  "source_name": [
767                    { "text": "Number" },
768                    { "text": "FOUR" }
769                  ]
770                }
771              }
772            }
773          },
774          {
775            "name": { "name": { "text": "end_four" } },
776            "location": {
777              "size": {
778                "function": {
779                  "function": "MULTIPLICATION",
780                  "args": [
781                    { "constant": { "value": "3" } },
782                    {
783                      "constant_reference": {
784                        "source_name": [
785                          { "text": "Number" },
786                          { "text": "FOUR" }
787                        ]
788                      }
789                    }
790                  ]
791                }
792              }
793            }
794          },
795          {
796            "type": {
797              "array_type": {
798                "element_count": {
799                  "constant_reference": {
800                    "source_name": [
801                      { "text": "Number" },
802                      { "text": "FOUR" }
803                    ]
804                  }
805                }
806              }
807            },
808            "name": { "name": { "text": "array_size_four" } }
809          }
810        ]
811      }
812    },
813    {
814      "enumeration": {
815        "value": [
816          {
817            "name": { "name": { "text": "FOUR" } },
818            "value": { "constant": { "value": "4" } }
819          },
820          {
821            "name": { "name": { "text": "EIGHT" } },
822            "value": {
823              "function": {
824                "function": "ADDITION",
825                "args": [
826                  {
827                    "constant_reference": {
828                      "source_name": [ { "text": "FOUR" } ]
829                    }
830                  },
831                  {
832                    "constant_reference": {
833                      "source_name": [
834                        { "text": "Number" },
835                        { "text": "FOUR" }
836                      ]
837                    }
838                  }
839                ]
840              }
841            }
842          },
843          {
844            "name": { "name": { "text": "SIXTEEN" } },
845            "value": {
846              "function": {
847                "function": "MULTIPLICATION",
848                "args": [
849                  {
850                    "constant_reference": {
851                      "source_name": [
852                        { "text": "Number" },
853                        { "text": "FOUR" }
854                      ]
855                    }
856                  },
857                  {
858                    "constant_reference": {
859                      "source_name": [ { "text": "FOUR" } ]
860                    }
861                  }
862                ]
863              }
864            }
865          },
866          {
867            "name": { "name": { "text": "INVALID" } },
868            "value": {
869              "constant_reference": {
870                "source_name": [
871                  { "text": "Number" },
872                  { "text": "NaN" },
873                  { "text": "FOUR" }
874                ]
875              }
876            }
877          }
878        ]
879      }
880    }
881  ]
882}
883
884===
885Using Type.constants in expressions
886---
887struct Foo:
888  0 [+Bar.four]  UInt  length_four
889---
890{
891  "type": [
892    {
893      "structure": {
894        "field": [
895          {
896            "name": { "name": { "text": "length_four" } },
897            "location": {
898              "size": {
899                "constant_reference": {
900                  "source_name": [ { "text": "Bar" }, { "text": "four" } ]
901                }
902              }
903            }
904          }
905        ]
906      }
907    }
908  ]
909}
910
911===
912using Type.Subtype
913---
914struct Foo:
915  0 [+0]  Bar.Baz  bar_baz
916---
917{
918  "type": [
919    {
920      "structure": {
921        "field": [
922          {
923            "type": {
924              "atomic_type": {
925                "reference": {
926                  "source_name": [ { "text": "Bar" }, { "text": "Baz" } ]
927                }
928              }
929            },
930            "name": { "name": { "text": "bar_baz" } }
931          }
932        ]
933      }
934    }
935  ]
936}
937
938===
939module.Type
940---
941struct Foo:
942  0 [+0]  bar.Baz  bar_baz
943---
944{
945  "type": [
946    {
947      "structure": {
948        "field": [
949          {
950            "type": {
951              "atomic_type": {
952                "reference": {
953                  "source_name": [ { "text": "bar" }, { "text": "Baz" } ]
954                }
955              }
956            },
957            "name": { "name": { "text": "bar_baz" } }
958          }
959        ]
960      }
961    }
962  ]
963}
964
965===
966module.Type.ENUM_VALUE
967---
968struct Foo:
969  bar.Baz.QUX [+0]  UInt  i
970---
971{
972  "type": [
973    {
974      "structure": {
975        "field": [
976          {
977            "name": { "name": { "text": "i" } },
978            "location": {
979              "start": {
980                "constant_reference": {
981                  "source_name": [
982                    { "text": "bar" },
983                    { "text": "Baz" },
984                    { "text": "QUX" }
985                  ]
986                }
987              }
988            }
989          }
990        ]
991      }
992    }
993  ]
994}
995
996===
997field attributes
998---
999struct Foo:
1000  0 [+1]  UInt  field  [fixed_size: true]
1001    [size: 1]
1002  1 [+2]  UInt  field2
1003---
1004{
1005  "type": [
1006    {
1007      "structure": {
1008        "field": [
1009          {
1010            "name": {
1011              "name": {
1012                "text": "field"
1013              }
1014            },
1015            "attribute": [
1016              {
1017                "name": {
1018                  "text": "fixed_size"
1019                },
1020                "value": {
1021                  "expression": {
1022                    "boolean_constant": {
1023                      "value": true
1024                    }
1025                  }
1026                }
1027              },
1028              {
1029                "name": {
1030                  "text": "size"
1031                },
1032                "value": {
1033                  "expression": {
1034                    "constant": {
1035                      "value": "1"
1036                    }
1037                  }
1038                }
1039              }
1040            ]
1041          },
1042          {
1043            "name": {
1044              "name": {
1045                "text": "field2"
1046              }
1047            }
1048          }
1049        ]
1050      },
1051      "name": {
1052        "name": {
1053          "text": "Foo"
1054        }
1055      }
1056    }
1057  ]
1058}
1059
1060===
1061enum attribute
1062---
1063enum Foo:
1064  [fixed_size: false]
1065  NAME = 1
1066---
1067{
1068  "type": [
1069    {
1070      "enumeration": {
1071        "value": [ { "name": { "name": { "text": "NAME" } } } ]
1072      },
1073      "name": { "name": { "text": "Foo" } },
1074      "attribute": [
1075        {
1076          "name": { "text": "fixed_size" },
1077          "value": {
1078            "expression": { "boolean_constant": { "value": false } }
1079          }
1080        }
1081      ]
1082    }
1083  ]
1084}
1085
1086===
1087string attribute
1088---
1089[abc: "abc"]
1090[bs: "abc\\"]
1091[bsbs: "abc\\\\"]
1092[nl: "abc\nd"]
1093[q: "abc\"d"]
1094[qq: "abc\"\""]
1095---
1096{
1097  "attribute": [
1098    {
1099      "name": { "text": "abc" },
1100      "value": { "string_constant": { "text": "abc" } }
1101    },
1102    {
1103      "name": { "text": "bs" },
1104      "value": { "string_constant": { "text": "abc\\" } }
1105    },
1106    {
1107      "name": { "text": "bsbs" },
1108      "value": { "string_constant": { "text": "abc\\\\" } }
1109    },
1110    {
1111      "name": { "text": "nl" },
1112      "value": { "string_constant": { "text": "abc\nd" } }
1113    },
1114    {
1115      "name": { "text": "q" },
1116      "value": { "string_constant": { "text": "abc\"d" } }
1117    },
1118    {
1119      "name": { "text": "qq" },
1120      "value": { "string_constant": { "text": "abc\"\"" } }
1121    }
1122  ]
1123}
1124
1125===
1126back-end-specific attribute
1127---
1128[(cpp) namespace: "a::b::c"]
1129---
1130{
1131  "attribute": [
1132    {
1133      "name": { "text": "namespace" },
1134      "value": { "string_constant": { "text": "a::b::c" } },
1135      "back_end": { "text": "cpp" }
1136    }
1137  ]
1138}
1139
1140===
1141documentation
1142---
1143-- module doc
1144--
1145-- module doc 2
1146struct Foo:
1147  -- foo doc
1148  -- foo doc 2
1149  0 [+1]  UInt  bar  -- bar inline doc
1150    -- bar continued doc
1151    -- bar continued doc 2
1152enum Baz:
1153  -- baz doc
1154  -- baz doc 2
1155  QUX = 1  -- qux inline doc
1156    -- qux continued doc
1157    -- qux continued doc 2
1158---
1159{
1160  "type": [
1161    {
1162      "structure": {
1163        "field": [
1164          {
1165            "name": {
1166              "name": {
1167                "text": "bar"
1168              }
1169            },
1170            "documentation": [
1171              {
1172                "text": "bar inline doc"
1173              },
1174              {
1175                "text": "bar continued doc"
1176              },
1177              {
1178                "text": "bar continued doc 2"
1179              }
1180            ]
1181          }
1182        ]
1183      },
1184      "name": {
1185        "name": {
1186          "text": "Foo"
1187        }
1188      },
1189      "documentation": [
1190        {
1191          "text": "foo doc"
1192        },
1193        {
1194          "text": "foo doc 2"
1195        }
1196      ]
1197    },
1198    {
1199      "enumeration": {
1200        "value": [
1201          {
1202            "name": {
1203              "name": {
1204                "text": "QUX"
1205              }
1206            },
1207            "documentation": [
1208              {
1209                "text": "qux inline doc"
1210              },
1211              {
1212                "text": "qux continued doc"
1213              },
1214              {
1215                "text": "qux continued doc 2"
1216              }
1217            ]
1218          }
1219        ]
1220      },
1221      "name": {
1222        "name": {
1223          "text": "Baz"
1224        }
1225      },
1226      "documentation": [
1227        {
1228          "text": "baz doc"
1229        },
1230        {
1231          "text": "baz doc 2"
1232        }
1233      ]
1234    }
1235  ],
1236  "documentation": [
1237    {
1238      "text": "module doc"
1239    },
1240    {
1241      "text": ""
1242    },
1243    {
1244      "text": "module doc 2"
1245    }
1246  ]
1247}
1248
1249===
1250inline enum
1251---
1252struct Foo:
1253  0 [+1]  enum  baz_qux_gibble (bqg):
1254    [q: 5]
1255    BAR = 1
1256    FOO = 2
1257bits Bar:
1258  0 [+1]  enum  baz_qux_gibble (bqg):
1259    [q: 5]
1260    BAR = 1
1261    FOO = 2
1262---
1263{
1264  "type": [
1265    {
1266      "structure": {
1267        "field": [
1268          {
1269            "type": {
1270              "atomic_type": {
1271                "reference": {
1272                  "source_name": [ { "text": "BazQuxGibble" } ],
1273                  "is_local_name": true
1274                }
1275              }
1276            },
1277            "name": { "name": { "text": "baz_qux_gibble" } },
1278            "abbreviation": { "text": "bqg" },
1279            "attribute": [
1280              {
1281                "name": { "text": "q" },
1282                "value": { "expression": { "constant": { "value": "5" } } }
1283              }
1284            ]
1285          }
1286        ]
1287      },
1288      "name": { "name": { "text": "Foo" } },
1289      "subtype": [
1290        {
1291          "enumeration": {
1292            "value": [
1293              {
1294                "name": { "name": { "text": "BAR" } },
1295                "value": { "constant": { "value": "1" } }
1296              },
1297              {
1298                "name": { "name": { "text": "FOO" } },
1299                "value": { "constant": { "value": "2" } }
1300              }
1301            ]
1302          },
1303          "name": { "name": { "text": "BazQuxGibble" } }
1304        }
1305      ]
1306    },
1307    {
1308      "structure": {
1309        "field": [
1310          {
1311            "type": {
1312              "atomic_type": {
1313                "reference": {
1314                  "source_name": [ { "text": "BazQuxGibble" } ],
1315                  "is_local_name": true
1316                }
1317              }
1318            },
1319            "name": { "name": { "text": "baz_qux_gibble" } },
1320            "abbreviation": { "text": "bqg" },
1321            "attribute": [
1322              {
1323                "name": { "text": "q" },
1324                "value": { "expression": { "constant": { "value": "5" } } }
1325              }
1326            ]
1327          }
1328        ]
1329      },
1330      "name": { "name": { "text": "Bar" } },
1331      "subtype": [
1332        {
1333          "enumeration": {
1334            "value": [
1335              {
1336                "name": { "name": { "text": "BAR" } },
1337                "value": { "constant": { "value": "1" } }
1338              },
1339              {
1340                "name": { "name": { "text": "FOO" } },
1341                "value": { "constant": { "value": "2" } }
1342              }
1343            ]
1344          },
1345          "name": { "name": { "text": "BazQuxGibble" } }
1346        }
1347      ]
1348    }
1349  ]
1350}
1351
1352===
1353inline struct
1354---
1355struct Foo:
1356  0 [+1]  struct  baz_qux_gibble (bqg):
1357    [q: 5]
1358    0 [+1]  UInt  bar
1359    1 [+1]  UInt  foo
1360---
1361{
1362  "type": [
1363    {
1364      "structure": {
1365        "field": [
1366          {
1367            "type": {
1368              "atomic_type": {
1369                "reference": {
1370                  "source_name": [ { "text": "BazQuxGibble" } ],
1371                  "is_local_name": true
1372                }
1373              }
1374            },
1375            "name": { "name": { "text": "baz_qux_gibble" } },
1376            "abbreviation": { "text": "bqg" },
1377            "attribute": [
1378              {
1379                "name": { "text": "q" },
1380                "value": { "expression": { "constant": { "value": "5" } } }
1381              }
1382            ]
1383          }
1384        ]
1385      },
1386      "name": { "name": { "text": "Foo" } },
1387      "subtype": [
1388        {
1389          "structure": {
1390            "field": [
1391              {
1392                "type": {
1393                  "atomic_type": {
1394                    "reference": { "source_name": [ { "text": "UInt" } ] }
1395                  }
1396                },
1397                "name": { "name": { "text": "bar" } }
1398              },
1399              {
1400                "type": {
1401                  "atomic_type": {
1402                    "reference": { "source_name": [ { "text": "UInt" } ] }
1403                  }
1404                },
1405                "name": { "name": { "text": "foo" } }
1406              }
1407            ]
1408          },
1409          "name": { "name": { "text": "BazQuxGibble" } }
1410        }
1411      ]
1412    }
1413  ]
1414}
1415
1416===
1417inline bits
1418---
1419struct Foo:
1420  0 [+1]  bits  baz_qux_gibble (bqg):
1421    [q: 5]
1422    0 [+1]  UInt  bar
1423    1 [+1]  UInt  foo
1424bits Bar:
1425  0 [+8]  bits  baz_qux_gibble (bqg):
1426    [q: 5]
1427    0 [+1]  UInt  bar
1428    1 [+1]  UInt  foo
1429---
1430{
1431  "type": [
1432    {
1433      "structure": {
1434        "field": [
1435          {
1436            "type": {
1437              "atomic_type": {
1438                "reference": {
1439                  "source_name": [
1440                    {
1441                      "text": "BazQuxGibble"
1442                    }
1443                  ]
1444                }
1445              }
1446            },
1447            "name": {
1448              "name": {
1449                "text": "baz_qux_gibble"
1450              }
1451            },
1452            "abbreviation": {
1453              "text": "bqg"
1454            },
1455            "attribute": [
1456              {
1457                "name": {
1458                  "text": "q"
1459                },
1460                "value": {
1461                  "expression": {
1462                    "constant": {
1463                      "value": "5"
1464                    }
1465                  }
1466                }
1467              }
1468            ]
1469          }
1470        ]
1471      },
1472      "name": {
1473        "name": {
1474          "text": "Foo"
1475        }
1476      },
1477      "subtype": [
1478        {
1479          "structure": {
1480            "field": [
1481              {
1482                "type": {
1483                  "atomic_type": {
1484                    "reference": {
1485                      "source_name": [
1486                        {
1487                          "text": "UInt"
1488                        }
1489                      ]
1490                    }
1491                  }
1492                },
1493                "name": {
1494                  "name": {
1495                    "text": "bar"
1496                  }
1497                }
1498              },
1499              {
1500                "type": {
1501                  "atomic_type": {
1502                    "reference": {
1503                      "source_name": [
1504                        {
1505                          "text": "UInt"
1506                        }
1507                      ]
1508                    }
1509                  }
1510                },
1511                "name": {
1512                  "name": {
1513                    "text": "foo"
1514                  }
1515                }
1516              }
1517            ]
1518          },
1519          "name": {
1520            "name": {
1521              "text": "BazQuxGibble"
1522            }
1523          }
1524        }
1525      ]
1526    },
1527    {
1528      "structure": {
1529        "field": [
1530          {
1531            "type": {
1532              "atomic_type": {
1533                "reference": {
1534                  "source_name": [
1535                    {
1536                      "text": "BazQuxGibble"
1537                    }
1538                  ]
1539                }
1540              }
1541            },
1542            "name": {
1543              "name": {
1544                "text": "baz_qux_gibble"
1545              }
1546            },
1547            "abbreviation": {
1548              "text": "bqg"
1549            },
1550            "attribute": [
1551              {
1552                "name": {
1553                  "text": "q"
1554                },
1555                "value": {
1556                  "expression": {
1557                    "constant": {
1558                      "value": "5"
1559                    }
1560                  }
1561                }
1562              }
1563            ]
1564          }
1565        ]
1566      },
1567      "name": {
1568        "name": {
1569          "text": "Bar"
1570        }
1571      },
1572      "subtype": [
1573        {
1574          "structure": {
1575            "field": [
1576              {
1577                "type": {
1578                  "atomic_type": {
1579                    "reference": {
1580                      "source_name": [
1581                        {
1582                          "text": "UInt"
1583                        }
1584                      ]
1585                    }
1586                  }
1587                },
1588                "name": {
1589                  "name": {
1590                    "text": "bar"
1591                  }
1592                }
1593              },
1594              {
1595                "type": {
1596                  "atomic_type": {
1597                    "reference": {
1598                      "source_name": [
1599                        {
1600                          "text": "UInt"
1601                        }
1602                      ]
1603                    }
1604                  }
1605                },
1606                "name": {
1607                  "name": {
1608                    "text": "foo"
1609                  }
1610                }
1611              }
1612            ]
1613          },
1614          "name": {
1615            "name": {
1616              "text": "BazQuxGibble"
1617            }
1618          }
1619        }
1620      ]
1621    }
1622  ]
1623}
1624
1625===
1626subfield
1627---
1628struct Foo:
1629  foo.bar [+1]  UInt  x
1630---
1631{
1632  "type": [
1633    {
1634      "structure": {
1635        "field": [
1636          {
1637            "name": {
1638              "name": {
1639                "text": "x"
1640              }
1641            },
1642            "location": {
1643              "start": {
1644                "field_reference": {
1645                  "path": [
1646                    {
1647                      "source_name": [
1648                        {
1649                          "text": "foo"
1650                        }
1651                      ]
1652                    },
1653                    {
1654                      "source_name": [
1655                        {
1656                          "text": "bar"
1657                        }
1658                      ]
1659                    }
1660                  ]
1661                }
1662              }
1663            }
1664          }
1665        ]
1666      },
1667      "name": {
1668        "name": {
1669          "text": "Foo"
1670        }
1671      }
1672    }
1673  ]
1674}
1675
1676===
1677anonymous bits
1678---
1679struct Foo:
1680  0 [+1]  bits:
1681    31 [+1]    enum  high_bit:
1682      OFF = 0
1683      ON  = 1
1684    0 [+1]     Flag  low_bit
1685    if false:
1686      16 [+1]  UInt  mid_high
1687      15 [+1]  UInt  mid_low
1688---
1689{
1690  "type": [
1691    {
1692      "structure": {
1693        "field": [
1694          {
1695            "name": {
1696              "is_anonymous": true
1697            },
1698            "location": {
1699              "start": {
1700                "constant": {
1701                  "value": "0"
1702                }
1703              },
1704              "size": {
1705                "constant": {
1706                  "value": "1"
1707                }
1708              }
1709            }
1710          }
1711        ]
1712      },
1713      "name": {
1714        "name": {
1715          "text": "Foo"
1716        }
1717      },
1718      "subtype": [
1719        {
1720          "structure": {
1721            "field": [
1722              {
1723                "name": {
1724                  "name": {
1725                    "text": "high_bit"
1726                  }
1727                }
1728              },
1729              {
1730                "name": {
1731                  "name": {
1732                    "text": "low_bit"
1733                  }
1734                }
1735              },
1736              {
1737                "name": {
1738                  "name": {
1739                    "text": "mid_high"
1740                  }
1741                },
1742                "existence_condition": {
1743                  "boolean_constant": {
1744                    "value": false
1745                  }
1746                }
1747              },
1748              {
1749                "name": {
1750                  "name": {
1751                    "text": "mid_low"
1752                  }
1753                },
1754                "existence_condition": {
1755                  "boolean_constant": {
1756                    "value": false
1757                  }
1758                }
1759              }
1760            ]
1761          },
1762          "name": { "is_anonymous": true }
1763        },
1764        {
1765          "enumeration": {
1766            "value": [
1767              {
1768                "name": { "name": { "text": "OFF" } },
1769                "value": { "constant": { "value": "0" } }
1770              },
1771              {
1772                "name": { "name": { "text": "ON" } },
1773                "value": { "constant": { "value": "1" } }
1774              }
1775            ]
1776          },
1777          "name": { "name": { "text": "HighBit" } }
1778        }
1779      ]
1780    }
1781  ]
1782}
1783
1784===
1785explicit type size
1786---
1787struct Foo:
1788  0 [+1]  Bar:8  bar
1789---
1790{
1791  "type": [
1792    {
1793      "structure": {
1794        "field": [
1795          { "type": { "size_in_bits": { "constant": { "value": "8" } } } }
1796        ]
1797      },
1798      "name": { "name": { "text": "Foo" } }
1799    }
1800  ]
1801}
1802
1803===
1804import
1805---
1806import "xyz.emb" as yqf
1807---
1808{
1809  "foreign_import": [
1810    { "file_name": { "text": "" }, "local_name": { "text": "" } },
1811    { "file_name": { "text": "xyz.emb" }, "local_name": { "text": "yqf" } }
1812  ]
1813}
1814
1815===
1816empty file
1817---
1818---
1819{
1820  "foreign_import": [
1821    {
1822      "file_name": {
1823        "text": "",
1824        "source_location": {
1825          "start": { "line": 1, "column": 1 },
1826          "end": { "line": 1, "column": 1 }
1827        }
1828      },
1829      "local_name": {
1830        "text": "",
1831        "source_location": {
1832          "start": { "line": 1, "column": 1 },
1833          "end": { "line": 1, "column": 1 }
1834        }
1835      },
1836      "source_location": {
1837        "start": { "line": 1, "column": 1 },
1838        "end": { "line": 1, "column": 1 }
1839      }
1840    }
1841  ],
1842  "source_location": {
1843    "start": { "line": 1, "column": 1 },
1844    "end": { "line": 1, "column": 1 }
1845  }
1846}
1847
1848===
1849existence_condition on unconditional field
1850---
1851struct Foo:
1852  0 [+1]  UInt  bar
1853---
1854{
1855  "type": [
1856    {
1857      "structure": {
1858        "field": [
1859          {
1860            "name": { "name": { "text": "bar" } },
1861            "existence_condition": { "boolean_constant": { "value": true } }
1862          }
1863        ]
1864      }
1865    }
1866  ]
1867}
1868
1869===
1870conditional struct fields
1871---
1872struct Foo:
1873  if true == false:
1874    0 [+1]  UInt  bar
1875    1 [+1]  bits:
1876      0 [+1]  UInt  xx
1877      1 [+1]  UInt  yy
1878    2 [+1]  enum  baz:
1879      XX = 1
1880      YY = 2
1881---
1882{
1883  "type": [
1884    {
1885      "structure": {
1886        "field": [
1887          {
1888            "name": { "name": { "text": "bar" } },
1889            "existence_condition": {
1890              "function": {
1891                "function": "EQUALITY",
1892                "args": [
1893                  { "boolean_constant": { "value": true } },
1894                  { "boolean_constant": { "value": false } }
1895                ]
1896              }
1897            }
1898          },
1899          {
1900            "existence_condition": {
1901              "function": {
1902                "function": "EQUALITY",
1903                "args": [
1904                  { "boolean_constant": { "value": true } },
1905                  { "boolean_constant": { "value": false } }
1906                ]
1907              }
1908            }
1909          },
1910          {
1911            "name": { "name": { "text": "baz" } },
1912            "existence_condition": {
1913              "function": {
1914                "function": "EQUALITY",
1915                "args": [
1916                  { "boolean_constant": { "value": true } },
1917                  { "boolean_constant": { "value": false } }
1918                ]
1919              }
1920            }
1921          }
1922        ]
1923      },
1924      "subtype": [
1925        {
1926          "structure": {
1927            "field": [
1928              {
1929                "name": { "name": { "text": "xx" } },
1930                "existence_condition": { "boolean_constant": { "value": true } }
1931              }
1932            ]
1933          }
1934        }
1935      ]
1936    }
1937  ]
1938}
1939
1940===
1941negative condition
1942---
1943struct Foo:
1944  if true != false:
1945    0 [+1]  UInt  bar
1946---
1947{
1948  "type": [
1949    {
1950      "structure": {
1951        "field": [
1952          {
1953            "name": { "name": { "text": "bar" } },
1954            "existence_condition": {
1955              "function": {
1956                "function": "INEQUALITY",
1957                "args": [
1958                  { "boolean_constant": { "value": true } },
1959                  { "boolean_constant": { "value": false } }
1960                ]
1961              }
1962            }
1963          }
1964        ]
1965      }
1966    }
1967  ]
1968}
1969
1970===
1971conditional bits fields
1972---
1973bits Foo:
1974  if true == false:
1975    0 [+1]  UInt  bar
1976    1 [+1]  enum  baz:
1977      XX = 1
1978      YY = 2
1979---
1980{
1981  "type": [
1982    {
1983      "structure": {
1984        "field": [
1985          {
1986            "name": { "name": { "text": "bar" } },
1987            "existence_condition": {
1988              "function": {
1989                "function": "EQUALITY",
1990                "args": [
1991                  { "boolean_constant": { "value": true } },
1992                  { "boolean_constant": { "value": false } }
1993                ]
1994              }
1995            }
1996          },
1997          {
1998            "name": { "name": { "text": "baz" } },
1999            "existence_condition": {
2000              "function": {
2001                "function": "EQUALITY",
2002                "args": [
2003                  { "boolean_constant": { "value": true } },
2004                  { "boolean_constant": { "value": false } }
2005                ]
2006              }
2007            }
2008          }
2009        ]
2010      }
2011    }
2012  ]
2013}
2014
2015===
2016conditional with logical and
2017---
2018struct Foo:
2019  if true && false:
2020    0 [+1]  UInt  bar
2021---
2022{
2023  "type": [
2024    {
2025      "structure": {
2026        "field": [
2027          {
2028            "name": {
2029              "name": {
2030                "text": "bar"
2031              }
2032            },
2033            "existence_condition": {
2034              "function": {
2035                "function": "AND",
2036                "args": [
2037                  {
2038                    "boolean_constant": {
2039                      "value": true
2040                    }
2041                  },
2042                  {
2043                    "boolean_constant": {
2044                      "value": false
2045                    }
2046                  }
2047                ]
2048              }
2049            }
2050          }
2051        ]
2052      }
2053    }
2054  ]
2055}
2056
2057===
2058conditional with logical or
2059---
2060struct Foo:
2061  if true || false:
2062    0 [+1]  UInt  bar
2063---
2064{
2065  "type": [
2066    {
2067      "structure": {
2068        "field": [
2069          {
2070            "name": {
2071              "name": {
2072                "text": "bar"
2073              }
2074            },
2075            "existence_condition": {
2076              "function": {
2077                "function": "OR",
2078                "args": [
2079                  {
2080                    "boolean_constant": {
2081                      "value": true
2082                    }
2083                  },
2084                  {
2085                    "boolean_constant": {
2086                      "value": false
2087                    }
2088                  }
2089                ]
2090              }
2091            }
2092          }
2093        ]
2094      }
2095    }
2096  ]
2097}
2098
2099===
2100conditional with multiple logical ands
2101---
2102struct Foo:
2103  if true && false && true:
2104    0 [+1]  UInt  bar
2105---
2106{
2107  "type": [
2108    {
2109      "structure": {
2110        "field": [
2111          {
2112            "name": {
2113              "name": {
2114                "text": "bar"
2115              }
2116            },
2117            "existence_condition": {
2118              "function": {
2119                "function": "AND",
2120                "args": [
2121                  {
2122                    "function": {
2123                      "function": "AND",
2124                      "args": [
2125                        {
2126                          "boolean_constant": {
2127                            "value": true
2128                          }
2129                        },
2130                        {
2131                          "boolean_constant": {
2132                            "value": false
2133                          }
2134                        }
2135                      ]
2136                    }
2137                  },
2138                  {
2139                    "boolean_constant": {
2140                      "value": true
2141                    }
2142                  }
2143                ]
2144              }
2145            }
2146          }
2147        ]
2148      }
2149    }
2150  ]
2151}
2152
2153===
2154conditional with multiple logical ors
2155---
2156struct Foo:
2157  if true || false || true:
2158    0 [+1]  UInt  bar
2159---
2160{
2161  "type": [
2162    {
2163      "structure": {
2164        "field": [
2165          {
2166            "name": {
2167              "name": {
2168                "text": "bar"
2169              }
2170            },
2171            "existence_condition": {
2172              "function": {
2173                "function": "OR",
2174                "args": [
2175                  {
2176                    "function": {
2177                      "function": "OR",
2178                      "args": [
2179                        {
2180                          "boolean_constant": {
2181                            "value": true
2182                          }
2183                        },
2184                        {
2185                          "boolean_constant": {
2186                            "value": false
2187                          }
2188                        }
2189                      ]
2190                    }
2191                  },
2192                  {
2193                    "boolean_constant": {
2194                      "value": true
2195                    }
2196                  }
2197                ]
2198              }
2199            }
2200          }
2201        ]
2202      }
2203    }
2204  ]
2205}
2206
2207===
2208conditional with comparisons and logical or
2209---
2210struct Foo:
2211  if 5 == 6 || 6 == 6:
2212    0 [+1]  UInt  bar
2213---
2214{
2215  "type": [
2216    {
2217      "structure": {
2218        "field": [
2219          {
2220            "name": {
2221              "name": {
2222                "text": "bar"
2223              }
2224            },
2225            "existence_condition": {
2226              "function": {
2227                "function": "OR",
2228                "args": [
2229                  {
2230                    "function": {
2231                      "function": "EQUALITY",
2232                      "args": [
2233                        {
2234                          "constant": {
2235                            "value": "5"
2236                          }
2237                        },
2238                        {
2239                          "constant": {
2240                            "value": "6"
2241                          }
2242                        }
2243                      ]
2244                    }
2245                  },
2246                  {
2247                    "function": {
2248                      "function": "EQUALITY",
2249                      "args": [
2250                        {
2251                          "constant": {
2252                            "value": "6"
2253                          }
2254                        },
2255                        {
2256                          "constant": {
2257                            "value": "6"
2258                          }
2259                        }
2260                      ]
2261                    }
2262                  }
2263                ]
2264              }
2265            }
2266          }
2267        ]
2268      }
2269    }
2270  ]
2271}
2272
2273===
2274conditional with or-of-ands
2275---
2276struct Foo:
2277  if true || (false && true):
2278    0 [+1]  UInt  bar
2279---
2280{
2281  "type": [
2282    {
2283      "structure": {
2284        "field": [
2285          {
2286            "name": {
2287              "name": {
2288                "text": "bar"
2289              }
2290            },
2291            "existence_condition": {
2292              "function": {
2293                "function": "OR",
2294                "args": [
2295                  {
2296                    "boolean_constant": {
2297                      "value": true
2298                    }
2299                  },
2300                  {
2301                    "function": {
2302                      "function": "AND",
2303                      "args": [
2304                        {
2305                          "boolean_constant": {
2306                            "value": false
2307                          }
2308                        },
2309                        {
2310                          "boolean_constant": {
2311                            "value": true
2312                          }
2313                        }
2314                      ]
2315                    }
2316                  }
2317                ]
2318              }
2319            }
2320          }
2321        ]
2322      }
2323    }
2324  ]
2325}
2326
2327===
2328less-than comparison
2329---
2330struct Foo:
2331  if 1 < 2:
2332    0 [+1]  UInt  bar
2333---
2334{
2335  "type": [
2336    {
2337      "structure": {
2338        "field": [
2339          {
2340            "name": {
2341              "name": {
2342                "text": "bar"
2343              }
2344            },
2345            "existence_condition": {
2346              "function": {
2347                "function": "LESS",
2348                "args": [
2349                  {
2350                    "constant": {
2351                      "value": "1"
2352                    }
2353                  },
2354                  {
2355                    "constant": {
2356                      "value": "2"
2357                    }
2358                  }
2359                ]
2360              }
2361            }
2362          }
2363        ]
2364      }
2365    }
2366  ]
2367}
2368
2369===
2370less-than-or-equal comparison
2371---
2372struct Foo:
2373  if 1 <= 2:
2374    0 [+1]  UInt  bar
2375---
2376{
2377  "type": [
2378    {
2379      "structure": {
2380        "field": [
2381          {
2382            "name": {
2383              "name": {
2384                "text": "bar"
2385              }
2386            },
2387            "existence_condition": {
2388              "function": {
2389                "function": "LESS_OR_EQUAL",
2390                "args": [
2391                  {
2392                    "constant": {
2393                      "value": "1"
2394                    }
2395                  },
2396                  {
2397                    "constant": {
2398                      "value": "2"
2399                    }
2400                  }
2401                ]
2402              }
2403            }
2404          }
2405        ]
2406      }
2407    }
2408  ]
2409}
2410
2411===
2412greater-than comparison
2413---
2414struct Foo:
2415  if 1 > 2:
2416    0 [+1]  UInt  bar
2417---
2418{
2419  "type": [
2420    {
2421      "structure": {
2422        "field": [
2423          {
2424            "name": {
2425              "name": {
2426                "text": "bar"
2427              }
2428            },
2429            "existence_condition": {
2430              "function": {
2431                "function": "GREATER",
2432                "args": [
2433                  {
2434                    "constant": {
2435                      "value": "1"
2436                    }
2437                  },
2438                  {
2439                    "constant": {
2440                      "value": "2"
2441                    }
2442                  }
2443                ]
2444              }
2445            }
2446          }
2447        ]
2448      }
2449    }
2450  ]
2451}
2452
2453===
2454greater-than-or-equal comparison
2455---
2456struct Foo:
2457  if 1 >= 2:
2458    0 [+1]  UInt  bar
2459---
2460{
2461  "type": [
2462    {
2463      "structure": {
2464        "field": [
2465          {
2466            "name": {
2467              "name": {
2468                "text": "bar"
2469              }
2470            },
2471            "existence_condition": {
2472              "function": {
2473                "function": "GREATER_OR_EQUAL",
2474                "args": [
2475                  {
2476                    "constant": {
2477                      "value": "1"
2478                    }
2479                  },
2480                  {
2481                    "constant": {
2482                      "value": "2"
2483                    }
2484                  }
2485                ]
2486              }
2487            }
2488          }
2489        ]
2490      }
2491    }
2492  ]
2493}
2494
2495===
2496chained less-than comparison
2497---
2498struct Foo:
2499  if 1 < 2 < 3:
2500    0 [+1]  UInt  bar
2501---
2502{
2503  "type": [
2504    {
2505      "structure": {
2506        "field": [
2507          {
2508            "name": {
2509              "name": {
2510                "text": "bar"
2511              }
2512            },
2513            "existence_condition": {
2514              "function": {
2515                "function": "AND",
2516                "args": [
2517                  {
2518                    "function": {
2519                      "function": "LESS",
2520                      "args": [
2521                        {
2522                          "constant": {
2523                            "value": "1"
2524                          }
2525                        },
2526                        {
2527                          "constant": {
2528                            "value": "2"
2529                          }
2530                        }
2531                      ]
2532                    }
2533                  },
2534                  {
2535                    "function": {
2536                      "function": "LESS",
2537                      "args": [
2538                        {
2539                          "constant": {
2540                            "value": "2"
2541                          }
2542                        },
2543                        {
2544                          "constant": {
2545                            "value": "3"
2546                          }
2547                        }
2548                      ]
2549                    }
2550                  }
2551                ]
2552              }
2553            }
2554          }
2555        ]
2556      }
2557    }
2558  ]
2559}
2560
2561===
2562chained greater-than comparison
2563---
2564struct Foo:
2565  if 1 > 2 > 3:
2566    0 [+1]  UInt  bar
2567---
2568{
2569  "type": [
2570    {
2571      "structure": {
2572        "field": [
2573          {
2574            "name": {
2575              "name": {
2576                "text": "bar"
2577              }
2578            },
2579            "existence_condition": {
2580              "function": {
2581                "function": "AND",
2582                "args": [
2583                  {
2584                    "function": {
2585                      "function": "GREATER",
2586                      "args": [
2587                        {
2588                          "constant": {
2589                            "value": "1"
2590                          }
2591                        },
2592                        {
2593                          "constant": {
2594                            "value": "2"
2595                          }
2596                        }
2597                      ]
2598                    }
2599                  },
2600                  {
2601                    "function": {
2602                      "function": "GREATER",
2603                      "args": [
2604                        {
2605                          "constant": {
2606                            "value": "2"
2607                          }
2608                        },
2609                        {
2610                          "constant": {
2611                            "value": "3"
2612                          }
2613                        }
2614                      ]
2615                    }
2616                  }
2617                ]
2618              }
2619            }
2620          }
2621        ]
2622      }
2623    }
2624  ]
2625}
2626
2627===
2628longer chained less-than comparison
2629---
2630struct Foo:
2631  if 1 < 2 < 3 <= 4:
2632    0 [+1]  UInt  bar
2633---
2634{
2635  "type": [
2636    {
2637      "structure": {
2638        "field": [
2639          {
2640            "name": {
2641              "name": {
2642                "text": "bar"
2643              }
2644            },
2645            "existence_condition": {
2646              "function": {
2647                "function": "AND",
2648                "args": [
2649                  {
2650                    "function": {
2651                      "function": "AND",
2652                      "args": [
2653                        {
2654                          "function": {
2655                            "function": "LESS",
2656                            "args": [
2657                              {
2658                                "constant": {
2659                                  "value": "1"
2660                                }
2661                              },
2662                              {
2663                                "constant": {
2664                                  "value": "2"
2665                                }
2666                              }
2667                            ]
2668                          }
2669                        },
2670                        {
2671                          "function": {
2672                            "function": "LESS",
2673                            "args": [
2674                              {
2675                                "constant": {
2676                                  "value": "2"
2677                                }
2678                              },
2679                              {
2680                                "constant": {
2681                                  "value": "3"
2682                                }
2683                              }
2684                            ]
2685                          }
2686                        }
2687                      ]
2688                    }
2689                  },
2690                  {
2691                    "function": {
2692                      "function": "LESS_OR_EQUAL",
2693                      "args": [
2694                        {
2695                          "constant": {
2696                            "value": "3"
2697                          }
2698                        },
2699                        {
2700                          "constant": {
2701                            "value": "4"
2702                          }
2703                        }
2704                      ]
2705                    }
2706                  }
2707                ]
2708              }
2709            }
2710          }
2711        ]
2712      }
2713    }
2714  ]
2715}
2716
2717===
2718longer chained greater-than comparison
2719---
2720struct Foo:
2721  if 1 > 2 > 3 >= 4:
2722    0 [+1]  UInt  bar
2723---
2724{
2725  "type": [
2726    {
2727      "structure": {
2728        "field": [
2729          {
2730            "name": {
2731              "name": {
2732                "text": "bar"
2733              }
2734            },
2735            "existence_condition": {
2736              "function": {
2737                "function": "AND",
2738                "args": [
2739                  {
2740                    "function": {
2741                      "function": "AND",
2742                      "args": [
2743                        {
2744                          "function": {
2745                            "function": "GREATER",
2746                            "args": [
2747                              {
2748                                "constant": {
2749                                  "value": "1"
2750                                }
2751                              },
2752                              {
2753                                "constant": {
2754                                  "value": "2"
2755                                }
2756                              }
2757                            ]
2758                          }
2759                        },
2760                        {
2761                          "function": {
2762                            "function": "GREATER",
2763                            "args": [
2764                              {
2765                                "constant": {
2766                                  "value": "2"
2767                                }
2768                              },
2769                              {
2770                                "constant": {
2771                                  "value": "3"
2772                                }
2773                              }
2774                            ]
2775                          }
2776                        }
2777                      ]
2778                    }
2779                  },
2780                  {
2781                    "function": {
2782                      "function": "GREATER_OR_EQUAL",
2783                      "args": [
2784                        {
2785                          "constant": {
2786                            "value": "3"
2787                          }
2788                        },
2789                        {
2790                          "constant": {
2791                            "value": "4"
2792                          }
2793                        }
2794                      ]
2795                    }
2796                  }
2797                ]
2798              }
2799            }
2800          }
2801        ]
2802      }
2803    }
2804  ]
2805}
2806
2807===
2808chained less-than and equal comparison
2809---
2810struct Foo:
2811  if 1 < 2 == 3:
2812    0 [+1]  UInt  bar
2813---
2814{
2815  "type": [
2816    {
2817      "structure": {
2818        "field": [
2819          {
2820            "name": {
2821              "name": {
2822                "text": "bar"
2823              }
2824            },
2825            "existence_condition": {
2826              "function": {
2827                "function": "AND",
2828                "args": [
2829                  {
2830                    "function": {
2831                      "function": "LESS",
2832                      "args": [
2833                        {
2834                          "constant": {
2835                            "value": "1"
2836                          }
2837                        },
2838                        {
2839                          "constant": {
2840                            "value": "2"
2841                          }
2842                        }
2843                      ]
2844                    }
2845                  },
2846                  {
2847                    "function": {
2848                      "function": "EQUALITY",
2849                      "args": [
2850                        {
2851                          "constant": {
2852                            "value": "2"
2853                          }
2854                        },
2855                        {
2856                          "constant": {
2857                            "value": "3"
2858                          }
2859                        }
2860                      ]
2861                    }
2862                  }
2863                ]
2864              }
2865            }
2866          }
2867        ]
2868      }
2869    }
2870  ]
2871}
2872
2873===
2874chained greater-than and equal comparison
2875---
2876struct Foo:
2877  if 1 > 2 == 3:
2878    0 [+1]  UInt  bar
2879---
2880{
2881  "type": [
2882    {
2883      "structure": {
2884        "field": [
2885          {
2886            "name": {
2887              "name": {
2888                "text": "bar"
2889              }
2890            },
2891            "existence_condition": {
2892              "function": {
2893                "function": "AND",
2894                "args": [
2895                  {
2896                    "function": {
2897                      "function": "GREATER",
2898                      "args": [
2899                        {
2900                          "constant": {
2901                            "value": "1"
2902                          }
2903                        },
2904                        {
2905                          "constant": {
2906                            "value": "2"
2907                          }
2908                        }
2909                      ]
2910                    }
2911                  },
2912                  {
2913                    "function": {
2914                      "function": "EQUALITY",
2915                      "args": [
2916                        {
2917                          "constant": {
2918                            "value": "2"
2919                          }
2920                        },
2921                        {
2922                          "constant": {
2923                            "value": "3"
2924                          }
2925                        }
2926                      ]
2927                    }
2928                  }
2929                ]
2930              }
2931            }
2932          }
2933        ]
2934      }
2935    }
2936  ]
2937}
2938
2939===
2940chained equal and less-than comparison
2941---
2942struct Foo:
2943  if 1 == 2 < 3:
2944    0 [+1]  UInt  bar
2945---
2946{
2947  "type": [
2948    {
2949      "structure": {
2950        "field": [
2951          {
2952            "name": {
2953              "name": {
2954                "text": "bar"
2955              }
2956            },
2957            "existence_condition": {
2958              "function": {
2959                "function": "AND",
2960                "args": [
2961                  {
2962                    "function": {
2963                      "function": "EQUALITY",
2964                      "args": [
2965                        {
2966                          "constant": {
2967                            "value": "1"
2968                          }
2969                        },
2970                        {
2971                          "constant": {
2972                            "value": "2"
2973                          }
2974                        }
2975                      ]
2976                    }
2977                  },
2978                  {
2979                    "function": {
2980                      "function": "LESS",
2981                      "args": [
2982                        {
2983                          "constant": {
2984                            "value": "2"
2985                          }
2986                        },
2987                        {
2988                          "constant": {
2989                            "value": "3"
2990                          }
2991                        }
2992                      ]
2993                    }
2994                  }
2995                ]
2996              }
2997            }
2998          }
2999        ]
3000      }
3001    }
3002  ]
3003}
3004
3005===
3006chained equal and greater-than comparison
3007---
3008struct Foo:
3009  if 1 == 2 > 3:
3010    0 [+1]  UInt  bar
3011---
3012{
3013  "type": [
3014    {
3015      "structure": {
3016        "field": [
3017          {
3018            "name": {
3019              "name": {
3020                "text": "bar"
3021              }
3022            },
3023            "existence_condition": {
3024              "function": {
3025                "function": "AND",
3026                "args": [
3027                  {
3028                    "function": {
3029                      "function": "EQUALITY",
3030                      "args": [
3031                        {
3032                          "constant": {
3033                            "value": "1"
3034                          }
3035                        },
3036                        {
3037                          "constant": {
3038                            "value": "2"
3039                          }
3040                        }
3041                      ]
3042                    }
3043                  },
3044                  {
3045                    "function": {
3046                      "function": "GREATER",
3047                      "args": [
3048                        {
3049                          "constant": {
3050                            "value": "2"
3051                          }
3052                        },
3053                        {
3054                          "constant": {
3055                            "value": "3"
3056                          }
3057                        }
3058                      ]
3059                    }
3060                  }
3061                ]
3062              }
3063            }
3064          }
3065        ]
3066      }
3067    }
3068  ]
3069}
3070
3071===
3072chained equality comparison
3073---
3074struct Foo:
3075  if 1 == 2 == 3:
3076    0 [+1]  UInt  bar
3077---
3078{
3079  "type": [
3080    {
3081      "structure": {
3082        "field": [
3083          {
3084            "name": {
3085              "name": {
3086                "text": "bar"
3087              }
3088            },
3089            "existence_condition": {
3090              "function": {
3091                "function": "AND",
3092                "args": [
3093                  {
3094                    "function": {
3095                      "function": "EQUALITY",
3096                      "args": [
3097                        {
3098                          "constant": {
3099                            "value": "1"
3100                          }
3101                        },
3102                        {
3103                          "constant": {
3104                            "value": "2"
3105                          }
3106                        }
3107                      ]
3108                    }
3109                  },
3110                  {
3111                    "function": {
3112                      "function": "EQUALITY",
3113                      "args": [
3114                        {
3115                          "constant": {
3116                            "value": "2"
3117                          }
3118                        },
3119                        {
3120                          "constant": {
3121                            "value": "3"
3122                          }
3123                        }
3124                      ]
3125                    }
3126                  }
3127                ]
3128              }
3129            }
3130          }
3131        ]
3132      }
3133    }
3134  ]
3135}
3136
3137===
3138choice operator
3139---
3140struct Foo:
3141  true ? 0 : 1 [+1]  UInt  bar
3142---
3143{
3144  "type": [
3145    {
3146      "structure": {
3147        "field": [
3148          {
3149            "name": {
3150              "name": {
3151                "text": "bar"
3152              }
3153            },
3154            "location": {
3155              "start": {
3156                "function": {
3157                  "function": "CHOICE",
3158                  "args": [
3159                    {
3160                      "boolean_constant": {
3161                        "value": true
3162                      }
3163                    },
3164                    {
3165                      "constant": {
3166                        "value": "0"
3167                      }
3168                    },
3169                    {
3170                      "constant": {
3171                        "value": "1"
3172                      }
3173                    }
3174                  ]
3175                }
3176              }
3177            }
3178          }
3179        ]
3180      }
3181    }
3182  ]
3183}
3184
3185===
3186max function
3187---
3188struct Foo:
3189  $max()               [+1]  UInt  no_arg
3190  $max(0)              [+1]  UInt  one_arg
3191  $max(2 * 3)          [+1]  UInt  mul_arg
3192  $max(2, 3)           [+1]  UInt  two_arg
3193  $max(2, 3, 4, 5, 6)  [+1]  UInt  five_arg
3194---
3195{
3196  "type": [
3197    {
3198      "structure": {
3199        "field": [
3200          {
3201            "name": {
3202              "name": {
3203                "text": "no_arg"
3204              }
3205            },
3206            "location": {
3207              "start": {
3208                "function": {
3209                  "function": "MAXIMUM"
3210                }
3211              }
3212            }
3213          },
3214          {
3215            "name": {
3216              "name": {
3217                "text": "one_arg"
3218              }
3219            },
3220            "location": {
3221              "start": {
3222                "function": {
3223                  "function": "MAXIMUM",
3224                  "args": [
3225                    {
3226                      "constant": {
3227                        "value": "0"
3228                      }
3229                    }
3230                  ]
3231                }
3232              }
3233            }
3234          },
3235          {
3236            "name": {
3237              "name": {
3238                "text": "mul_arg"
3239              }
3240            },
3241            "location": {
3242              "start": {
3243                "function": {
3244                  "function": "MAXIMUM",
3245                  "args": [
3246                    {
3247                      "function": {
3248                        "function": "MULTIPLICATION",
3249                        "args": [
3250                          {
3251                            "constant": {
3252                              "value": "2"
3253                            }
3254                          },
3255                          {
3256                            "constant": {
3257                              "value": "3"
3258                            }
3259                          }
3260                        ]
3261                      }
3262                    }
3263                  ]
3264                }
3265              }
3266            }
3267          },
3268          {
3269            "name": {
3270              "name": {
3271                "text": "two_arg"
3272              }
3273            },
3274            "location": {
3275              "start": {
3276                "function": {
3277                  "function": "MAXIMUM",
3278                  "args": [
3279                    {
3280                      "constant": {
3281                        "value": "2"
3282                      }
3283                    },
3284                    {
3285                      "constant": {
3286                        "value": "3"
3287                      }
3288                    }
3289                  ]
3290                }
3291              }
3292            }
3293          },
3294          {
3295            "name": {
3296              "name": {
3297                "text": "five_arg"
3298              }
3299            },
3300            "location": {
3301              "start": {
3302                "function": {
3303                  "function": "MAXIMUM",
3304                  "args": [
3305                    {
3306                      "constant": {
3307                        "value": "2"
3308                      }
3309                    },
3310                    {
3311                      "constant": {
3312                        "value": "3"
3313                      }
3314                    },
3315                    {
3316                      "constant": {
3317                        "value": "4"
3318                      }
3319                    },
3320                    {
3321                      "constant": {
3322                        "value": "5"
3323                      }
3324                    },
3325                    {
3326                      "constant": {
3327                        "value": "6"
3328                      }
3329                    }
3330                  ]
3331                }
3332              }
3333            }
3334          }
3335        ]
3336      }
3337    }
3338  ]
3339}
3340
3341===
3342has function
3343---
3344struct Foo:
3345  if $present(x):
3346    0 [+1]  UInt  field
3347  if $present(x.y.z):
3348    0 [+1]  UInt  field2
3349---
3350{
3351  "type": [
3352    {
3353      "structure": {
3354        "field": [
3355          {
3356            "name": {
3357              "name": {
3358                "text": "field"
3359              }
3360            },
3361            "existence_condition": {
3362              "function": {
3363                "function": "PRESENCE",
3364                "args": [
3365                  {
3366                    "field_reference": {
3367                      "path": [
3368                        {
3369                          "source_name": [
3370                            {
3371                              "text": "x"
3372                            }
3373                          ]
3374                        }
3375                      ]
3376                    }
3377                  }
3378                ]
3379              }
3380            }
3381          },
3382          {
3383            "name": {
3384              "name": {
3385                "text": "field2"
3386              }
3387            },
3388            "existence_condition": {
3389              "function": {
3390                "function": "PRESENCE",
3391                "args": [
3392                  {
3393                    "field_reference": {
3394                      "path": [
3395                        {
3396                          "source_name": [
3397                            {
3398                              "text": "x"
3399                            }
3400                          ]
3401                        },
3402                        {
3403                          "source_name": [
3404                            {
3405                              "text": "y"
3406                            }
3407                          ]
3408                        },
3409                        {
3410                          "source_name": [
3411                            {
3412                              "text": "z"
3413                            }
3414                          ]
3415                        }
3416                      ]
3417                    }
3418                  }
3419                ]
3420              }
3421            }
3422          }
3423        ]
3424      }
3425    }
3426  ]
3427}
3428
3429===
3430upper_bound function
3431---
3432struct Foo:
3433  $upper_bound(0)    [+1]  UInt  one
3434---
3435{
3436  "type": [
3437    {
3438      "structure": {
3439        "field": [
3440          {
3441            "name": {
3442              "name": {
3443                "text": "one"
3444              }
3445            },
3446            "location": {
3447              "start": {
3448                "function": {
3449                  "function": "UPPER_BOUND",
3450                  "args": [
3451                    {
3452                      "constant": {
3453                        "value": "0"
3454                      }
3455                    }
3456                  ]
3457                }
3458              }
3459            }
3460          }
3461        ]
3462      }
3463    }
3464  ]
3465}
3466
3467===
3468lower_bound function
3469---
3470struct Foo:
3471  $lower_bound(0)    [+1]  UInt  one
3472---
3473{
3474  "type": [
3475    {
3476      "structure": {
3477        "field": [
3478          {
3479            "name": {
3480              "name": {
3481                "text": "one"
3482              }
3483            },
3484            "location": {
3485              "start": {
3486                "function": {
3487                  "function": "LOWER_BOUND",
3488                  "args": [
3489                    {
3490                      "constant": {
3491                        "value": "0"
3492                      }
3493                    }
3494                  ]
3495                }
3496              }
3497            }
3498          }
3499        ]
3500      }
3501    }
3502  ]
3503}
3504
3505===
3506struct addressable_unit
3507---
3508struct Foo:
3509  0 [+1]  UInt  size
3510---
3511{ "type": [ { "structure": {}, "addressable_unit": "BYTE" } ] }
3512
3513===
3514bits addressable_unit
3515---
3516bits Foo:
3517  0 [+1]  UInt  size
3518---
3519{ "type": [ { "structure": {}, "addressable_unit": "BIT" } ] }
3520
3521===
3522enum addressable_unit
3523---
3524enum Foo:
3525  BAR = 0
3526---
3527{ "type": [ { "enumeration": {}, "addressable_unit": "BIT" } ] }
3528
3529===
3530type size source_location
3531---
3532struct Foo:
3533  0 [+4]  UInt:32  field
3534---
3535{
3536  "type": [
3537    {
3538      "structure": {
3539        "field": [
3540          {
3541            "type": {
3542              "atomic_type": {
3543                "reference": { "source_name": [ { "text": "UInt" } ] }
3544              },
3545              "size_in_bits": {
3546                "source_location": {
3547                  "start": { "line": 3, "column": 15 },
3548                  "end": { "line": 3, "column": 18 }
3549                }
3550              },
3551              "source_location": {
3552                "start": { "line": 3, "column": 11 },
3553                "end": { "line": 3, "column": 18 }
3554              }
3555            },
3556            "name": { "name": { "text": "field" } }
3557          }
3558        ]
3559      }
3560    }
3561  ]
3562}
3563
3564===
3565builtin references
3566---
3567external Foo:
3568  [requires: $is_statically_sized && $static_size_in_bits == 64]
3569---
3570{
3571  "type": [
3572    {
3573      "external": {},
3574      "attribute": [
3575        {
3576          "name": { "text": "requires" },
3577          "value": {
3578            "expression": {
3579              "function": {
3580                "args": [
3581                  {
3582                    "builtin_reference": {
3583                      "canonical_name": {
3584                        "module_file": "",
3585                        "object_path": [ "$is_statically_sized" ]
3586                      },
3587                      "source_name": [ { "text": "$is_statically_sized" } ]
3588                    }
3589                  },
3590                  {
3591                    "function": {
3592                      "args": [
3593                        {
3594                          "builtin_reference": {
3595                            "canonical_name": {
3596                              "module_file": "",
3597                              "object_path": [ "$static_size_in_bits" ]
3598                            },
3599                            "source_name": [
3600                              { "text": "$static_size_in_bits" }
3601                            ]
3602                          }
3603                        }
3604                      ]
3605                    }
3606                  }
3607                ]
3608              }
3609            }
3610          }
3611        }
3612      ]
3613    }
3614  ]
3615}
3616
3617===
3618$next
3619---
3620struct Foo:
3621  $next [+0]  UInt  x
3622---
3623{
3624  "type": [
3625    {
3626      "structure": {
3627        "field": [
3628          {
3629            "location": {
3630              "start": {
3631                "builtin_reference": { "source_name": [ { "text": "$next" } ] }
3632              }
3633            },
3634            "name": { "name": { "text": "x" } }
3635          }
3636        ]
3637      }
3638    }
3639  ]
3640}
3641
3642===
3643virtual fields
3644---
3645struct Foo:
3646  let x = 10
3647bits Bar:
3648  let y = 100
3649---
3650{
3651  "type": [
3652    {
3653      "structure": {
3654        "field": [
3655          {
3656            "name": { "name": { "text": "x" } },
3657            "read_transform": { "constant": { "value": "10" } }
3658          }
3659        ]
3660      }
3661    },
3662    {
3663      "structure": {
3664        "field": [
3665          {
3666            "name": { "name": { "text": "y" } },
3667            "read_transform": { "constant": { "value": "100" } }
3668          }
3669        ]
3670      }
3671    }
3672  ]
3673}
3674
3675===
3676builtin fields
3677---
3678struct Foo:
3679  let x = $size_in_bytes
3680  let y = $max_size_in_bytes
3681  let z = $min_size_in_bytes
3682bits Bar:
3683  let x = $size_in_bits
3684  let y = $max_size_in_bits
3685  let z = $min_size_in_bits
3686---
3687{
3688  "type": [
3689    {
3690      "structure": {
3691        "field": [
3692          {
3693            "name": { "name": { "text": "x" } },
3694            "read_transform": {
3695              "field_reference": {
3696                "path": [ { "source_name": [ { "text": "$size_in_bytes" } ] } ]
3697              }
3698            }
3699          },
3700          {
3701            "name": { "name": { "text": "y" } },
3702            "read_transform": {
3703              "field_reference": {
3704                "path": [
3705                  { "source_name": [ { "text": "$max_size_in_bytes" } ] }
3706                ]
3707              }
3708            }
3709          },
3710          {
3711            "name": { "name": { "text": "z" } },
3712            "read_transform": {
3713              "field_reference": {
3714                "path": [
3715                  { "source_name": [ { "text": "$min_size_in_bytes" } ] }
3716                ]
3717              }
3718            }
3719          }
3720        ]
3721      }
3722    },
3723    {
3724      "structure": {
3725        "field": [
3726          {
3727            "name": { "name": { "text": "x" } },
3728            "read_transform": {
3729              "field_reference": {
3730                "path": [ { "source_name": [ { "text": "$size_in_bits" } ] } ]
3731              }
3732            }
3733          },
3734          {
3735            "name": { "name": { "text": "y" } },
3736            "read_transform": {
3737              "field_reference": {
3738                "path": [
3739                  { "source_name": [ { "text": "$max_size_in_bits" } ] }
3740                ]
3741              }
3742            }
3743          },
3744          {
3745            "name": { "name": { "text": "z" } },
3746            "read_transform": {
3747              "field_reference": {
3748                "path": [
3749                  { "source_name": [ { "text": "$min_size_in_bits" } ] }
3750                ]
3751              }
3752            }
3753          }
3754        ]
3755      }
3756    }
3757  ]
3758}
3759
3760===
3761parameterized type definitions
3762---
3763struct Foo(a: Flag, b: UInt:32):
3764  let x = 10
3765bits Bar(c: UInt:16):
3766  let y = 100
3767struct Baz():
3768  let x = 10
3769---
3770{
3771  "type": [
3772    {
3773      "runtime_parameter": [
3774        {
3775          "name": { "name": { "text": "a" } },
3776          "physical_type_alias": {
3777            "atomic_type": {
3778              "reference": { "source_name": [ { "text": "Flag" } ] }
3779            }
3780          }
3781        },
3782        {
3783          "name": { "name": { "text": "b" } },
3784          "physical_type_alias": {
3785            "atomic_type": {
3786              "reference": { "source_name": [ { "text": "UInt" } ] }
3787            },
3788            "size_in_bits": { "constant": { "value": "32" } }
3789          }
3790        }
3791      ]
3792    },
3793    {
3794      "runtime_parameter": [
3795        {
3796          "name": { "name": { "text": "c" } },
3797          "physical_type_alias": {
3798            "atomic_type": {
3799              "reference": { "source_name": [ { "text": "UInt" } ] }
3800            },
3801            "size_in_bits": { "constant": { "value": "16" } }
3802          }
3803        }
3804      ]
3805    },
3806    {}
3807  ]
3808}
3809
3810===
3811parameterized type usages
3812---
3813struct Foo:
3814  0 [+1]  Two(1, 2)  two
3815  1 [+1]  One(3)     one
3816  2 [+1]  Zero()     zero
3817---
3818{
3819  "type": [
3820    {
3821      "structure": {
3822        "field": [
3823          {
3824            "type": {
3825              "atomic_type": {
3826                "reference": { "source_name": [ { "text": "Two" } ] },
3827                "runtime_parameter": [
3828                  { "constant": { "value": "1" } },
3829                  { "constant": { "value": "2" } }
3830                ]
3831              }
3832            },
3833            "name": { "name": { "text": "two" } }
3834          },
3835          {
3836            "type": {
3837              "atomic_type": {
3838                "reference": { "source_name": [ { "text": "One" } ] },
3839                "runtime_parameter": [ { "constant": { "value": "3" } } ]
3840              }
3841            },
3842            "name": { "name": { "text": "one" } }
3843          },
3844          {
3845            "type": {
3846              "atomic_type": {
3847                "reference": { "source_name": [ { "text": "Zero" } ] }
3848              }
3849            },
3850            "name": { "name": { "text": "zero" } }
3851          }
3852        ]
3853      }
3854    }
3855  ]
3856}
3857
3858===
3859enum value attribute
3860---
3861enum Foo:
3862  BAR     = 1 [test: 0]
3863  BAZ     = 2
3864    [test: 1]
3865    [different: "test"]
3866  FOO_BAR = 4
3867    -- foo bar doc
3868    [test: 2]
3869  FOO_BAZ = 8 [test: 3] -- foo baz doc
3870  BAR_FOO = 16 [test: 4]
3871    -- bar foo doc
3872  BAZ_FOO = 32 -- baz foo doc
3873    [test: 5]
3874---
3875{
3876  "type": [
3877    {
3878      "enumeration": {
3879        "value": [
3880          {
3881            "name": { "name": { "text": "BAR" } },
3882            "attribute": [
3883              {
3884                "name": { "text": "test" },
3885                "value": { "expression": { "constant": { "value": "0" } } }
3886              }
3887            ]
3888          },
3889          {
3890            "name": { "name": { "text": "BAZ" } },
3891            "attribute": [
3892              {
3893                "name": { "text": "test" },
3894                "value": { "expression": { "constant": { "value": "1" } } }
3895              },
3896              {
3897                "name": { "text": "different" },
3898                "value": { "string_constant": { "text": "test" } }
3899              }
3900            ]
3901          },
3902          {
3903            "name": { "name": { "text": "FOO_BAR" } },
3904            "documentation": [ { "text": "foo bar doc" } ],
3905            "attribute": [
3906              {
3907                "name": { "text": "test" },
3908                "value": { "expression": { "constant": { "value": "2" } } }
3909              }
3910            ]
3911          },
3912          {
3913            "name": { "name": { "text": "FOO_BAZ" } },
3914            "documentation": [ { "text": "foo baz doc" } ],
3915            "attribute": [
3916              {
3917                "name": { "text": "test" },
3918                "value": { "expression": { "constant": { "value": "3" } } }
3919              }
3920            ]
3921          },
3922          {
3923            "name": { "name": { "text": "BAR_FOO" } },
3924            "documentation": [ { "text": "bar foo doc" } ],
3925            "attribute": [
3926              {
3927                "name": { "text": "test" },
3928                "value": { "expression": { "constant": { "value": "4" } } }
3929              }
3930            ]
3931          },
3932          {
3933            "name": { "name": { "text": "BAZ_FOO" } },
3934            "documentation": [ { "text": "baz foo doc" } ],
3935            "attribute": [
3936              {
3937                "name": { "text": "test" },
3938                "value": { "expression": { "constant": { "value": "5" } } }
3939              }
3940            ]
3941          }
3942        ]
3943      },
3944      "name": { "name": { "text": "Foo" } }
3945    }
3946  ]
3947}
3948
3949"""
3950
3951
3952# For each test in _NEGATIVE_TEST_CASES, parsing should fail, and the failure
3953# should indicate the specified token.
3954_NEGATIVE_TEST_CASES = """
3955anonymous bits does not allow documentation
3956---
3957-- doc
3958---
3959struct Foo:
3960  0 [+1]  bits:
3961    -- doc
3962    0 [+2]  UInt  bar
3963===
3964anonymous bits does not allow subtypes
3965---
3966enum
3967---
3968struct Foo:
3969  0 [+1]  bits:
3970    enum Bar:
3971      X = 1
3972    0 [+2]  Bar  bar
3973"""
3974
3975
3976def _get_test_cases():
3977  test_case = collections.namedtuple("test_case", ["name", "parse_tree", "ir"])
3978  result = []
3979  for case in _TEST_CASES.split("==="):
3980    name, emb, ir_text = case.split("---")
3981    name = name.strip()
3982    try:
3983      ir = ir_data_utils.IrDataSerializer.from_json(ir_data.Module, ir_text)
3984    except Exception:
3985      print(name)
3986      raise
3987    parse_result = parser.parse_module(tokenizer.tokenize(emb, "")[0])
3988    assert not parse_result.error, "{}:\n{}".format(name, parse_result.error)
3989    result.append(test_case(name, parse_result.parse_tree, ir))
3990  return result
3991
3992
3993def _get_negative_test_cases():
3994  test_case = collections.namedtuple("test_case",
3995                                     ["name", "text", "error_token"])
3996  result = []
3997  for case in _NEGATIVE_TEST_CASES.split("==="):
3998    name, error_token, text = case.split("---")
3999    name = name.strip()
4000    error_token = error_token.strip()
4001    result.append(test_case(name, text, error_token))
4002  return result
4003
4004
4005def _check_source_location(source_location, path, min_start, max_end):
4006  """Performs sanity checks on a source_location field.
4007
4008  Arguments:
4009    source_location: The source_location to check.
4010    path: The path, to use in error messages.
4011    min_start: A minimum value for source_location.start, or None.
4012    max_end: A maximum value for source_location.end, or None.
4013
4014  Returns:
4015    A list of error messages, or an empty list if no errors.
4016  """
4017  if source_location.is_disjoint_from_parent:
4018    # If source_location.is_disjoint_from_parent, then this source_location is
4019    # allowed to be outside of the parent's source_location.
4020    return []
4021
4022  result = []
4023  start = None
4024  end = None
4025  if not source_location.HasField("start"):
4026    result.append("{}.start missing".format(path))
4027  else:
4028    start = source_location.start
4029  if not source_location.HasField("end"):
4030    result.append("{}.end missing".format(path))
4031  else:
4032    end = source_location.end
4033
4034  if start and end:
4035    if start.HasField("line") and end.HasField("line"):
4036      if start.line > end.line:
4037        result.append("{}.start.line > {}.end.line ({} vs {})".format(
4038            path, path, start.line, end.line))
4039      elif start.line == end.line:
4040        if (start.HasField("column") and end.HasField("column") and
4041            start.column > end.column):
4042          result.append("{}.start.column > {}.end.column ({} vs {})".format(
4043              path, path, start.column, end.column))
4044
4045  for name, field in (("start", start), ("end", end)):
4046    if not field:
4047      continue
4048    if field.HasField("line"):
4049      if field.line <= 0:
4050        result.append("{}.{}.line <= 0 ({})".format(path, name, field.line))
4051    else:
4052      result.append("{}.{}.line missing".format(path, name))
4053    if field.HasField("column"):
4054      if field.column <= 0:
4055        result.append("{}.{}.column <= 0 ({})".format(path, name, field.column))
4056    else:
4057      result.append("{}.{}.column missing".format(path, name))
4058
4059  if min_start and start:
4060    if min_start.line > start.line or (
4061        min_start.line == start.line and min_start.column > start.column):
4062      result.append("{}.start before parent start".format(path))
4063
4064  if max_end and end:
4065    if max_end.line < end.line or (
4066        max_end.line == end.line and max_end.column < end.column):
4067      result.append("{}.end after parent end".format(path))
4068
4069  return result
4070
4071
4072def _check_all_source_locations(proto, path="", min_start=None, max_end=None):
4073  """Performs sanity checks on all source_locations in proto.
4074
4075  Arguments:
4076    proto: The proto to recursively check.
4077    path: The path, to use in error messages.
4078    min_start: A minimum value for source_location.start, or None.
4079    max_end: A maximum value for source_location.end, or None.
4080
4081  Returns:
4082    A list of error messages, or an empty list if no errors.
4083  """
4084  if path:
4085    path += "."
4086
4087  errors = []
4088
4089  child_start = None
4090  child_end = None
4091  # Only check the source_location value if this proto message actually has a
4092  # source_location field.
4093  if proto.HasField("source_location"):
4094    errors.extend(_check_source_location(proto.source_location,
4095                                         path + "source_location",
4096                                         min_start, max_end))
4097    child_start = proto.source_location.start
4098    child_end = proto.source_location.end
4099
4100  for name, spec in ir_data_fields.field_specs(proto).items():
4101    if name == "source_location":
4102      continue
4103    if not proto.HasField(name):
4104      continue
4105    field_path = "{}{}".format(path, name)
4106    if spec.is_dataclass:
4107      if spec.is_sequence:
4108        index = 0
4109        for i in getattr(proto, name):
4110          item_path = "{}[{}]".format(field_path, index)
4111          index += 1
4112          errors.extend(
4113              _check_all_source_locations(i, item_path, child_start, child_end))
4114      else:
4115        errors.extend(_check_all_source_locations(getattr(proto, name),
4116                                                  field_path, child_start,
4117                                                  child_end))
4118
4119  return errors
4120
4121
4122class ModuleIrTest(unittest.TestCase):
4123  """Tests the module_ir.build_ir() function."""
4124
4125  def test_build_ir(self):
4126    ir = module_ir.build_ir(_MINIMAL_SAMPLE)
4127    ir.source_text = _MINIMAL_SOURCE
4128    self.assertEqual(ir, _MINIMAL_SAMPLE_IR)
4129
4130  def test_production_coverage(self):
4131    """Checks that all grammar productions are used somewhere in tests."""
4132    used_productions = set()
4133    module_ir.build_ir(_MINIMAL_SAMPLE, used_productions)
4134    for test in _get_test_cases():
4135      module_ir.build_ir(test.parse_tree, used_productions)
4136    self.assertEqual(set(module_ir.PRODUCTIONS) - used_productions, set([]))
4137
4138  def test_double_negative_non_compilation(self):
4139    """Checks that unparenthesized double unary minus/plus is a parse error."""
4140    for example in ("[x: - -3]", "[x: + -3]", "[x: - +3]", "[x: + +3]"):
4141      parse_result = parser.parse_module(tokenizer.tokenize(example, "")[0])
4142      self.assertTrue(parse_result.error)
4143      self.assertEqual(7, parse_result.error.token.source_location.start.column)
4144    for example in ("[x:-(-3)]", "[x:+(-3)]", "[x:-(+3)]", "[x:+(+3)]"):
4145      parse_result = parser.parse_module(tokenizer.tokenize(example, "")[0])
4146      self.assertFalse(parse_result.error)
4147
4148
4149def _make_superset_tests():
4150
4151  def _make_superset_test(test):
4152
4153    def test_case(self):
4154      ir = module_ir.build_ir(test.parse_tree)
4155      is_superset, error_message = test_util.proto_is_superset(ir, test.ir)
4156
4157      self.assertTrue(
4158          is_superset,
4159          error_message + "\n" + ir_data_utils.IrDataSerializer(ir).to_json(indent=2) + "\n" +
4160          ir_data_utils.IrDataSerializer(test.ir).to_json(indent=2))
4161
4162    return test_case
4163
4164  for test in _get_test_cases():
4165    test_name = "test " + test.name + " proto superset"
4166    assert not hasattr(ModuleIrTest, test_name)
4167    setattr(ModuleIrTest, test_name, _make_superset_test(test))
4168
4169
4170def _make_source_location_tests():
4171
4172  def _make_source_location_test(test):
4173
4174    def test_case(self):
4175      error_list = _check_all_source_locations(
4176          module_ir.build_ir(test.parse_tree))
4177      self.assertFalse(error_list, "\n".join([test.name] + error_list))
4178
4179    return test_case
4180
4181  for test in _get_test_cases():
4182    test_name = "test " + test.name + " source location"
4183    assert not hasattr(ModuleIrTest, test_name)
4184    setattr(ModuleIrTest, test_name, _make_source_location_test(test))
4185
4186
4187def _make_negative_tests():
4188
4189  def _make_negative_test(test):
4190
4191    def test_case(self):
4192      parse_result = parser.parse_module(tokenizer.tokenize(test.text, "")[0])
4193      self.assertEqual(test.error_token, parse_result.error.token.text.strip())
4194
4195    return test_case
4196
4197  for test in _get_negative_test_cases():
4198    test_name = "test " + test.name + " compilation failure"
4199    assert not hasattr(ModuleIrTest, test_name)
4200    setattr(ModuleIrTest, test_name, _make_negative_test(test))
4201
4202_make_negative_tests()
4203_make_superset_tests()
4204_make_source_location_tests()
4205
4206
4207if __name__ == "__main__":
4208  unittest.main()
4209