| # Copyright 2019 Google LLC |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Tests for module_ir.""" |
| |
| from __future__ import print_function |
| |
| import collections |
| import pkgutil |
| import unittest |
| |
| from compiler.front_end import module_ir |
| from compiler.front_end import parser |
| from compiler.front_end import test_util |
| from compiler.front_end import tokenizer |
| from compiler.util import ir_pb2 |
| |
| _TESTDATA_PATH = "testdata.golden" |
| _MINIMAL_SAMPLE = parser.parse_module( |
| tokenizer.tokenize( |
| pkgutil.get_data(_TESTDATA_PATH, "span_se_log_file_status.emb").decode( |
| encoding="UTF-8"), |
| "")[0]).parse_tree |
| _MINIMAL_SAMPLE_IR = ir_pb2.Module.from_json( |
| pkgutil.get_data(_TESTDATA_PATH, "span_se_log_file_status.ir.txt").decode( |
| encoding="UTF-8") |
| ) |
| |
| # _TEST_CASES contains test cases, separated by '===', that ensure that specific |
| # results show up in the IR for .embs. |
| # |
| # Each test case is of the form: |
| # |
| # name |
| # --- |
| # .emb text |
| # --- |
| # (incomplete) IR text format |
| # |
| # For each test case, the .emb is parsed into a parse tree, which is fed into |
| # module_ir.build_ir(), which should successfully return an IR. The generated |
| # IR is then compared against the incomplete IR in the test case to ensure that |
| # the generated IR is a strict superset of the test case IR -- that is, it is OK |
| # if the generated IR contains fields that are not in the test case, but not if |
| # the test case contains fields that are not in the generated IR, and not if the |
| # test case contains fields whose values differ from the generated IR. |
| # |
| # Additionally, for each test case, a pass is executed to ensure that the source |
| # code location for each node in the IR is strictly contained within the source |
| # location for its parent node. |
| _TEST_CASES = r""" |
| prelude |
| --- |
| external UInt: |
| [fixed_size: false] |
| [byte_order_dependent: true] |
| |
| external Byte: |
| [size: 1] |
| [byte_order_dependent: false] |
| --- |
| { |
| "type": [ |
| { |
| "external": {}, |
| "name": { "name": { "text": "UInt" } }, |
| "attribute": [ |
| { |
| "name": { "text": "fixed_size" }, |
| "value": { "expression": { "boolean_constant": { "value": false } } } |
| }, |
| { |
| "name": { "text": "byte_order_dependent" }, |
| "value": { "expression": { "boolean_constant": { "value": true } } } |
| } |
| ] |
| }, |
| { |
| "external": {}, |
| "name": { "name": { "text": "Byte" } }, |
| "attribute": [ |
| { |
| "name": { "text": "size" }, |
| "value": { "expression": { "constant": { "value": "1" } } } |
| }, |
| { |
| "name": { "text": "byte_order_dependent" }, |
| "value": { "expression": { "boolean_constant": { "value": false } } } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| numbers |
| --- |
| bits Foo: |
| 0000000000 [+0_000_000_003] UInt decimal |
| 0b00000100 [+0b0000_0111] UInt binary |
| 0b00000000_00001000 [+0b0_00001011] UInt binary2 |
| 0b_0_00001100 [+0b_00001111] UInt binary3 |
| 0x00000010 [+0x0000_0013] UInt hex |
| 0x00000000_00000014 [+0x0_00000017] UInt hex2 |
| 0x_0_00000018 [+0x_0000001b] UInt hex3 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "decimal" } }, |
| "location": { |
| "start": { "constant": { "value": "0" } }, |
| "size": { "constant": { "value": "3" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "binary" } }, |
| "location": { |
| "start": { "constant": { "value": "4" } }, |
| "size": { "constant": { "value": "7" } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "binary2" } }, |
| "location": { |
| "start": { "constant": { "value": "8" } }, |
| "size": { "constant": { "value": "11" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "binary3" } }, |
| "location": { |
| "start": { "constant": { "value": "12" } }, |
| "size": { "constant": { "value": "15" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "hex" } }, |
| "location": { |
| "start": { "constant": { "value": "16" } }, |
| "size": { "constant": { "value": "19" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "hex2" } }, |
| "location": { |
| "start": { "constant": { "value": "20" } }, |
| "size": { "constant": { "value": "23" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "hex3" } }, |
| "location": { |
| "start": { "constant": { "value": "24" } }, |
| "size": { "constant": { "value": "27" } } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| enum |
| --- |
| enum Kind: |
| WIDGET = 0 |
| SPROCKET = 1 |
| GEEGAW = 2 # Comment. |
| MAX32 = 4294967295 |
| MAX64 = 9223372036854775807 |
| --- |
| { |
| "type": [ |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { "name": { "text": "WIDGET" } }, |
| "value": { "constant": { "value": "0" } } |
| }, |
| { |
| "name": { "name": { "text": "SPROCKET" } }, |
| "value": { "constant": { "value": "1" } } |
| }, |
| { |
| "name": { "name": { "text": "GEEGAW" } }, |
| "value": { "constant": { "value": "2" } } |
| }, |
| { |
| "name": { "name": { "text": "MAX32" } }, |
| "value": { "constant": { "value": "4294967295" } } |
| }, |
| { |
| "name": { "name": { "text": "MAX64" } }, |
| "value": { "constant": { "value": "9223372036854775807" } } |
| } |
| ] |
| }, |
| "name": { "name": { "text": "Kind" } } |
| } |
| ] |
| } |
| |
| === |
| struct attribute |
| --- |
| struct Foo: |
| [size: 10] |
| 0 [+0] UInt field |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ { "name": { "name": { "text": "field" } } } ] |
| }, |
| "name": { "name": { "text": "Foo" } }, |
| "attribute": [ |
| { |
| "name": { "text": "size" }, |
| "value": { "expression": { "constant": { "value": "10" } } }, |
| "is_default": false |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| $default attribute |
| --- |
| [$default byte_order: "LittleEndian"] |
| --- |
| { |
| "attribute": [ |
| { |
| "name": { "text": "byte_order" }, |
| "value": { "string_constant": { "text": "LittleEndian" } }, |
| "is_default": true |
| } |
| ] |
| } |
| |
| === |
| abbreviations |
| --- |
| struct Foo: |
| 0 [+1] UInt size (s) |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "size" } }, |
| "abbreviation": { "text": "s" } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| expressions |
| --- |
| struct Foo: |
| 0+1 [+2*3] UInt plus_times |
| 4-5 [+(6)] UInt minus_paren |
| nn [+7*(8+9)] UInt name_complex |
| 10+11+12 [+13*14*15] UInt associativity |
| 16+17*18 [+19*20-21] UInt precedence |
| -(+1) [+0-(-10)] UInt unary_plus_minus |
| 1 + + 2 [+3 - -4 - 5] UInt unary_plus_minus_2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "plus_times" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "ADDITION", |
| "function_name": { "text": "+" }, |
| "args": [ |
| { "constant": { "value": "0" } }, |
| { "constant": { "value": "1" } } |
| ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "MULTIPLICATION", |
| "function_name": { "text": "*" }, |
| "args": [ |
| { "constant": { "value": "2" } }, |
| { "constant": { "value": "3" } } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "minus_paren" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "SUBTRACTION", |
| "args": [ |
| { "constant": { "value": "4" } }, |
| { "constant": { "value": "5" } } |
| ] |
| } |
| }, |
| "size": { "constant": { "value": "6" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "name_complex" } }, |
| "location": { |
| "start": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "nn" } ] } ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { "constant": { "value": "7" } }, |
| { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "8" } }, |
| { "constant": { "value": "9" } } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "associativity" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "10" } }, |
| { "constant": { "value": "11" } } |
| ] |
| } |
| }, |
| { "constant": { "value": "12" } } |
| ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { "constant": { "value": "13" } }, |
| { "constant": { "value": "14" } } |
| ] |
| } |
| }, |
| { "constant": { "value": "15" } } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "precedence" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "16" } }, |
| { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { "constant": { "value": "17" } }, |
| { "constant": { "value": "18" } } |
| ] |
| } |
| } |
| ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "SUBTRACTION", |
| "args": [ |
| { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { "constant": { "value": "19" } }, |
| { "constant": { "value": "20" } } |
| ] |
| } |
| }, |
| { "constant": { "value": "21" } } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "unary_plus_minus" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "SUBTRACTION", |
| "function_name": { |
| "text": "-", |
| "source_location": { |
| "start": { "line": 8, "column": 3 }, |
| "end": { "line": 8, "column": 4 } |
| } |
| }, |
| "args": [ |
| { |
| "constant": { |
| "value": "0", |
| "source_location": { |
| "start": { "line": 8, "column": 3 }, |
| "end": { "line": 8, "column": 3 } |
| } |
| }, |
| "source_location": { |
| "start": { "line": 8, "column": 3 }, |
| "end": { "line": 8, "column": 3 } |
| } |
| }, |
| { |
| "function": { |
| "function": "ADDITION", |
| "function_name": { |
| "text": "+", |
| "source_location": { |
| "start": { "line": 8, "column": 5 }, |
| "end": { "line": 8, "column": 6 } |
| } |
| }, |
| "args": [ |
| { |
| "constant": { "value": "0" }, |
| "source_location": { |
| "start": { "line": 8, "column": 5 }, |
| "end": { "line": 8, "column": 5 } |
| } |
| }, |
| { |
| "constant": { "value": "1" }, |
| "source_location": { |
| "start": { "line": 8, "column": 6 }, |
| "end": { "line": 8, "column": 7 } |
| } |
| } |
| ] |
| }, |
| "source_location": { |
| "start": { "line": 8, "column": 4 }, |
| "end": { "line": 8, "column": 8 } |
| } |
| } |
| ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "SUBTRACTION", |
| "function_name": { |
| "text": "-", |
| "source_location": { |
| "start": { "line": 8, "column": 12 }, |
| "end": { "line": 8, "column": 13 } |
| } |
| }, |
| "args": [ |
| { |
| "constant": { |
| "value": "0", |
| "source_location": { |
| "start": { "line": 8, "column": 11 }, |
| "end": { "line": 8, "column": 12 } |
| } |
| }, |
| "source_location": { |
| "start": { "line": 8, "column": 11 }, |
| "end": { "line": 8, "column": 12 } |
| } |
| }, |
| { |
| "function": { |
| "function": "SUBTRACTION", |
| "function_name": { |
| "text": "-", |
| "source_location": { |
| "start": { "line": 8, "column": 14 }, |
| "end": { "line": 8, "column": 15 } |
| } |
| }, |
| "args": [ |
| { |
| "constant": { "value": "0" }, |
| "source_location": { |
| "start": { "line": 8, "column": 14 }, |
| "end": { "line": 8, "column": 14 } |
| } |
| }, |
| { |
| "constant": { "value": "10" }, |
| "source_location": { |
| "start": { "line": 8, "column": 15 }, |
| "end": { "line": 8, "column": 17 } |
| } |
| } |
| ] |
| }, |
| "source_location": { |
| "start": { "line": 8, "column": 13 }, |
| "end": { "line": 8, "column": 18 } |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "unary_plus_minus_2" } }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "1" } }, |
| { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "0" } }, |
| { "constant": { "value": "2" } } |
| ] |
| } |
| } |
| ] |
| } |
| }, |
| "size": { |
| "function": { |
| "function": "SUBTRACTION", |
| "args": [ |
| { |
| "function": { |
| "function": "SUBTRACTION", |
| "args": [ |
| { "constant": { "value": "3" } }, |
| { |
| "function": { |
| "function": "SUBTRACTION", |
| "args": [ |
| { "constant": { "value": "0" } }, |
| { "constant": { "value": "4" } } |
| ] |
| } |
| } |
| ] |
| } |
| }, |
| { "constant": { "value": "5" } } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| auto array size |
| --- |
| struct TenElementArray: |
| 0 [+10] Byte[] bytes |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "array_type": { |
| "base_type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "Byte" } ] } |
| } |
| }, |
| "automatic": { |
| "source_location": { |
| "start": { "line": 3, "column": 16 }, |
| "end": { "line": 3, "column": 18 } |
| } |
| } |
| } |
| }, |
| "name": { "name": { "text": "bytes" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| start [+size] ranges |
| --- |
| struct Foo: |
| 0 [ + 1 ] UInt zero_plus_one |
| s [+2] UInt s_plus_two |
| s [+t] Byte[t] s_plus_t |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "zero_plus_one" } }, |
| "location": { |
| "start": { |
| "constant": { "value": "0" }, |
| "source_location": { |
| "start": { "line": 3, "column": 3 }, |
| "end": { "line": 3, "column": 4 } |
| } |
| }, |
| "size": { |
| "constant": { "value": "1" }, |
| "source_location": { |
| "start": { "line": 3, "column": 9 }, |
| "end": { "line": 3, "column": 10 } |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "s_plus_two" } }, |
| "location": { |
| "start": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "s" } ] } ] |
| } |
| }, |
| "size": { "constant": { "value": "2" } } |
| } |
| }, |
| { |
| "name": { "name": { "text": "s_plus_t" } }, |
| "location": { |
| "start": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "s" } ] } ] |
| } |
| }, |
| "size": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "t" } ] } ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| Using Enum.VALUEs in expressions |
| --- |
| struct Foo: |
| 0 [+0+Number.FOUR] UInt length_four |
| Number.FOUR [+8] UInt start_four |
| 8 [+3*Number.FOUR] UInt end_four |
| 12 [+16] Byte[Number.FOUR] array_size_four |
| |
| enum Number: |
| FOUR = 4 |
| EIGHT = FOUR + Number.FOUR |
| SIXTEEN = Number.FOUR * FOUR |
| INVALID = Number.NaN.FOUR |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "length_four" } }, |
| "location": { |
| "size": { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { "constant": { "value": "0" } }, |
| { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "start_four" } }, |
| "location": { |
| "start": { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "end_four" } }, |
| "location": { |
| "size": { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { "constant": { "value": "3" } }, |
| { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "type": { |
| "array_type": { |
| "element_count": { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| } |
| }, |
| "name": { "name": { "text": "array_size_four" } } |
| } |
| ] |
| } |
| }, |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { "name": { "text": "FOUR" } }, |
| "value": { "constant": { "value": "4" } } |
| }, |
| { |
| "name": { "name": { "text": "EIGHT" } }, |
| "value": { |
| "function": { |
| "function": "ADDITION", |
| "args": [ |
| { |
| "constant_reference": { |
| "source_name": [ { "text": "FOUR" } ] |
| } |
| }, |
| { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "SIXTEEN" } }, |
| "value": { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "FOUR" } |
| ] |
| } |
| }, |
| { |
| "constant_reference": { |
| "source_name": [ { "text": "FOUR" } ] |
| } |
| } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "INVALID" } }, |
| "value": { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "Number" }, |
| { "text": "NaN" }, |
| { "text": "FOUR" } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| Using Type.constants in expressions |
| --- |
| struct Foo: |
| 0 [+Bar.four] UInt length_four |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "length_four" } }, |
| "location": { |
| "size": { |
| "constant_reference": { |
| "source_name": [ { "text": "Bar" }, { "text": "four" } ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| using Type.Subtype |
| --- |
| struct Foo: |
| 0 [+0] Bar.Baz bar_baz |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ { "text": "Bar" }, { "text": "Baz" } ] |
| } |
| } |
| }, |
| "name": { "name": { "text": "bar_baz" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| module.Type |
| --- |
| struct Foo: |
| 0 [+0] bar.Baz bar_baz |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ { "text": "bar" }, { "text": "Baz" } ] |
| } |
| } |
| }, |
| "name": { "name": { "text": "bar_baz" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| module.Type.ENUM_VALUE |
| --- |
| struct Foo: |
| bar.Baz.QUX [+0] UInt i |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "i" } }, |
| "location": { |
| "start": { |
| "constant_reference": { |
| "source_name": [ |
| { "text": "bar" }, |
| { "text": "Baz" }, |
| { "text": "QUX" } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| field attributes |
| --- |
| struct Foo: |
| 0 [+1] UInt field [fixed_size: true] |
| [size: 1] |
| 1 [+2] UInt field2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "field" |
| } |
| }, |
| "attribute": [ |
| { |
| "name": { |
| "text": "fixed_size" |
| }, |
| "value": { |
| "expression": { |
| "boolean_constant": { |
| "value": true |
| } |
| } |
| } |
| }, |
| { |
| "name": { |
| "text": "size" |
| }, |
| "value": { |
| "expression": { |
| "constant": { |
| "value": "1" |
| } |
| } |
| } |
| } |
| ] |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "field2" |
| } |
| } |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Foo" |
| } |
| } |
| } |
| ] |
| } |
| |
| === |
| enum attribute |
| --- |
| enum Foo: |
| [fixed_size: false] |
| NAME = 1 |
| --- |
| { |
| "type": [ |
| { |
| "enumeration": { |
| "value": [ { "name": { "name": { "text": "NAME" } } } ] |
| }, |
| "name": { "name": { "text": "Foo" } }, |
| "attribute": [ |
| { |
| "name": { "text": "fixed_size" }, |
| "value": { |
| "expression": { "boolean_constant": { "value": false } } |
| } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| string attribute |
| --- |
| [abc: "abc"] |
| [bs: "abc\\"] |
| [bsbs: "abc\\\\"] |
| [nl: "abc\nd"] |
| [q: "abc\"d"] |
| [qq: "abc\"\""] |
| --- |
| { |
| "attribute": [ |
| { |
| "name": { "text": "abc" }, |
| "value": { "string_constant": { "text": "abc" } } |
| }, |
| { |
| "name": { "text": "bs" }, |
| "value": { "string_constant": { "text": "abc\\" } } |
| }, |
| { |
| "name": { "text": "bsbs" }, |
| "value": { "string_constant": { "text": "abc\\\\" } } |
| }, |
| { |
| "name": { "text": "nl" }, |
| "value": { "string_constant": { "text": "abc\nd" } } |
| }, |
| { |
| "name": { "text": "q" }, |
| "value": { "string_constant": { "text": "abc\"d" } } |
| }, |
| { |
| "name": { "text": "qq" }, |
| "value": { "string_constant": { "text": "abc\"\"" } } |
| } |
| ] |
| } |
| |
| === |
| back-end-specific attribute |
| --- |
| [(cpp) namespace: "a::b::c"] |
| --- |
| { |
| "attribute": [ |
| { |
| "name": { "text": "namespace" }, |
| "value": { "string_constant": { "text": "a::b::c" } }, |
| "back_end": { "text": "cpp" } |
| } |
| ] |
| } |
| |
| === |
| documentation |
| --- |
| -- module doc |
| -- |
| -- module doc 2 |
| struct Foo: |
| -- foo doc |
| -- foo doc 2 |
| 0 [+1] UInt bar -- bar inline doc |
| -- bar continued doc |
| -- bar continued doc 2 |
| enum Baz: |
| -- baz doc |
| -- baz doc 2 |
| QUX = 1 -- qux inline doc |
| -- qux continued doc |
| -- qux continued doc 2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "documentation": [ |
| { |
| "text": "bar inline doc" |
| }, |
| { |
| "text": "bar continued doc" |
| }, |
| { |
| "text": "bar continued doc 2" |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Foo" |
| } |
| }, |
| "documentation": [ |
| { |
| "text": "foo doc" |
| }, |
| { |
| "text": "foo doc 2" |
| } |
| ] |
| }, |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { |
| "name": { |
| "text": "QUX" |
| } |
| }, |
| "documentation": [ |
| { |
| "text": "qux inline doc" |
| }, |
| { |
| "text": "qux continued doc" |
| }, |
| { |
| "text": "qux continued doc 2" |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Baz" |
| } |
| }, |
| "documentation": [ |
| { |
| "text": "baz doc" |
| }, |
| { |
| "text": "baz doc 2" |
| } |
| ] |
| } |
| ], |
| "documentation": [ |
| { |
| "text": "module doc" |
| }, |
| { |
| "text": "" |
| }, |
| { |
| "text": "module doc 2" |
| } |
| ] |
| } |
| |
| === |
| inline enum |
| --- |
| struct Foo: |
| 0 [+1] enum baz_qux_gibble (bqg): |
| [q: 5] |
| BAR = 1 |
| FOO = 2 |
| bits Bar: |
| 0 [+1] enum baz_qux_gibble (bqg): |
| [q: 5] |
| BAR = 1 |
| FOO = 2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ { "text": "BazQuxGibble" } ], |
| "is_local_name": true |
| } |
| } |
| }, |
| "name": { "name": { "text": "baz_qux_gibble" } }, |
| "abbreviation": { "text": "bqg" }, |
| "attribute": [ |
| { |
| "name": { "text": "q" }, |
| "value": { "expression": { "constant": { "value": "5" } } } |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { "name": { "text": "Foo" } }, |
| "subtype": [ |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { "name": { "text": "BAR" } }, |
| "value": { "constant": { "value": "1" } } |
| }, |
| { |
| "name": { "name": { "text": "FOO" } }, |
| "value": { "constant": { "value": "2" } } |
| } |
| ] |
| }, |
| "name": { "name": { "text": "BazQuxGibble" } } |
| } |
| ] |
| }, |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ { "text": "BazQuxGibble" } ], |
| "is_local_name": true |
| } |
| } |
| }, |
| "name": { "name": { "text": "baz_qux_gibble" } }, |
| "abbreviation": { "text": "bqg" }, |
| "attribute": [ |
| { |
| "name": { "text": "q" }, |
| "value": { "expression": { "constant": { "value": "5" } } } |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { "name": { "text": "Bar" } }, |
| "subtype": [ |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { "name": { "text": "BAR" } }, |
| "value": { "constant": { "value": "1" } } |
| }, |
| { |
| "name": { "name": { "text": "FOO" } }, |
| "value": { "constant": { "value": "2" } } |
| } |
| ] |
| }, |
| "name": { "name": { "text": "BazQuxGibble" } } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| inline struct |
| --- |
| struct Foo: |
| 0 [+1] struct baz_qux_gibble (bqg): |
| [q: 5] |
| 0 [+1] UInt bar |
| 1 [+1] UInt foo |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ { "text": "BazQuxGibble" } ], |
| "is_local_name": true |
| } |
| } |
| }, |
| "name": { "name": { "text": "baz_qux_gibble" } }, |
| "abbreviation": { "text": "bqg" }, |
| "attribute": [ |
| { |
| "name": { "text": "q" }, |
| "value": { "expression": { "constant": { "value": "5" } } } |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { "name": { "text": "Foo" } }, |
| "subtype": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "UInt" } ] } |
| } |
| }, |
| "name": { "name": { "text": "bar" } } |
| }, |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "UInt" } ] } |
| } |
| }, |
| "name": { "name": { "text": "foo" } } |
| } |
| ] |
| }, |
| "name": { "name": { "text": "BazQuxGibble" } } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| inline bits |
| --- |
| struct Foo: |
| 0 [+1] bits baz_qux_gibble (bqg): |
| [q: 5] |
| 0 [+1] UInt bar |
| 1 [+1] UInt foo |
| bits Bar: |
| 0 [+8] bits baz_qux_gibble (bqg): |
| [q: 5] |
| 0 [+1] UInt bar |
| 1 [+1] UInt foo |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "BazQuxGibble" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "baz_qux_gibble" |
| } |
| }, |
| "abbreviation": { |
| "text": "bqg" |
| }, |
| "attribute": [ |
| { |
| "name": { |
| "text": "q" |
| }, |
| "value": { |
| "expression": { |
| "constant": { |
| "value": "5" |
| } |
| } |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Foo" |
| } |
| }, |
| "subtype": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "UInt" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| } |
| }, |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "UInt" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "foo" |
| } |
| } |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "BazQuxGibble" |
| } |
| } |
| } |
| ] |
| }, |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "BazQuxGibble" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "baz_qux_gibble" |
| } |
| }, |
| "abbreviation": { |
| "text": "bqg" |
| }, |
| "attribute": [ |
| { |
| "name": { |
| "text": "q" |
| }, |
| "value": { |
| "expression": { |
| "constant": { |
| "value": "5" |
| } |
| } |
| } |
| } |
| ] |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Bar" |
| } |
| }, |
| "subtype": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "UInt" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| } |
| }, |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { |
| "source_name": [ |
| { |
| "text": "UInt" |
| } |
| ] |
| } |
| } |
| }, |
| "name": { |
| "name": { |
| "text": "foo" |
| } |
| } |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "BazQuxGibble" |
| } |
| } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| subfield |
| --- |
| struct Foo: |
| foo.bar [+1] UInt x |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "x" |
| } |
| }, |
| "location": { |
| "start": { |
| "field_reference": { |
| "path": [ |
| { |
| "source_name": [ |
| { |
| "text": "foo" |
| } |
| ] |
| }, |
| { |
| "source_name": [ |
| { |
| "text": "bar" |
| } |
| ] |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Foo" |
| } |
| } |
| } |
| ] |
| } |
| |
| === |
| anonymous bits |
| --- |
| struct Foo: |
| 0 [+1] bits: |
| 31 [+1] enum high_bit: |
| OFF = 0 |
| ON = 1 |
| 0 [+1] Flag low_bit |
| if false: |
| 16 [+1] UInt mid_high |
| 15 [+1] UInt mid_low |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "is_anonymous": true |
| }, |
| "location": { |
| "start": { |
| "constant": { |
| "value": "0" |
| } |
| }, |
| "size": { |
| "constant": { |
| "value": "1" |
| } |
| } |
| } |
| } |
| ] |
| }, |
| "name": { |
| "name": { |
| "text": "Foo" |
| } |
| }, |
| "subtype": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "high_bit" |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "low_bit" |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "mid_high" |
| } |
| }, |
| "existence_condition": { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "mid_low" |
| } |
| }, |
| "existence_condition": { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| } |
| ] |
| }, |
| "name": { "is_anonymous": true } |
| }, |
| { |
| "enumeration": { |
| "value": [ |
| { |
| "name": { "name": { "text": "OFF" } }, |
| "value": { "constant": { "value": "0" } } |
| }, |
| { |
| "name": { "name": { "text": "ON" } }, |
| "value": { "constant": { "value": "1" } } |
| } |
| ] |
| }, |
| "name": { "name": { "text": "HighBit" } } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| explicit type size |
| --- |
| struct Foo: |
| 0 [+1] Bar:8 bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { "type": { "size_in_bits": { "constant": { "value": "8" } } } } |
| ] |
| }, |
| "name": { "name": { "text": "Foo" } } |
| } |
| ] |
| } |
| |
| === |
| import |
| --- |
| import "xyz.emb" as yqf |
| --- |
| { |
| "foreign_import": [ |
| { "file_name": { "text": "" }, "local_name": { "text": "" } }, |
| { "file_name": { "text": "xyz.emb" }, "local_name": { "text": "yqf" } } |
| ] |
| } |
| |
| === |
| empty file |
| --- |
| --- |
| { |
| "foreign_import": [ |
| { |
| "file_name": { |
| "text": "", |
| "source_location": { |
| "start": { "line": 1, "column": 1 }, |
| "end": { "line": 1, "column": 1 } |
| } |
| }, |
| "local_name": { |
| "text": "", |
| "source_location": { |
| "start": { "line": 1, "column": 1 }, |
| "end": { "line": 1, "column": 1 } |
| } |
| }, |
| "source_location": { |
| "start": { "line": 1, "column": 1 }, |
| "end": { "line": 1, "column": 1 } |
| } |
| } |
| ], |
| "source_location": { |
| "start": { "line": 1, "column": 1 }, |
| "end": { "line": 1, "column": 1 } |
| } |
| } |
| |
| === |
| existence_condition on unconditional field |
| --- |
| struct Foo: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "bar" } }, |
| "existence_condition": { "boolean_constant": { "value": true } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional struct fields |
| --- |
| struct Foo: |
| if true == false: |
| 0 [+1] UInt bar |
| 1 [+1] bits: |
| 0 [+1] UInt xx |
| 1 [+1] UInt yy |
| 2 [+1] enum baz: |
| XX = 1 |
| YY = 2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "bar" } }, |
| "existence_condition": { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| }, |
| { |
| "existence_condition": { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "baz" } }, |
| "existence_condition": { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| } |
| ] |
| }, |
| "subtype": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "xx" } }, |
| "existence_condition": { "boolean_constant": { "value": true } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| negative condition |
| --- |
| struct Foo: |
| if true != false: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "bar" } }, |
| "existence_condition": { |
| "function": { |
| "function": "INEQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional bits fields |
| --- |
| bits Foo: |
| if true == false: |
| 0 [+1] UInt bar |
| 1 [+1] enum baz: |
| XX = 1 |
| YY = 2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "bar" } }, |
| "existence_condition": { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "baz" } }, |
| "existence_condition": { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { "boolean_constant": { "value": true } }, |
| { "boolean_constant": { "value": false } } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with logical and |
| --- |
| struct Foo: |
| if true && false: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with logical or |
| --- |
| struct Foo: |
| if true || false: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "OR", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with multiple logical ands |
| --- |
| struct Foo: |
| if true && false && true: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with multiple logical ors |
| --- |
| struct Foo: |
| if true || false || true: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "OR", |
| "args": [ |
| { |
| "function": { |
| "function": "OR", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": false |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with comparisons and logical or |
| --- |
| struct Foo: |
| if 5 == 6 || 6 == 6: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "OR", |
| "args": [ |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "5" |
| } |
| }, |
| { |
| "constant": { |
| "value": "6" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "6" |
| } |
| }, |
| { |
| "constant": { |
| "value": "6" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| conditional with or-of-ands |
| --- |
| struct Foo: |
| if true || (false && true): |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "OR", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": false |
| } |
| }, |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| less-than comparison |
| --- |
| struct Foo: |
| if 1 < 2: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| less-than-or-equal comparison |
| --- |
| struct Foo: |
| if 1 <= 2: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "LESS_OR_EQUAL", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| greater-than comparison |
| --- |
| struct Foo: |
| if 1 > 2: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| greater-than-or-equal comparison |
| --- |
| struct Foo: |
| if 1 >= 2: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "GREATER_OR_EQUAL", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained less-than comparison |
| --- |
| struct Foo: |
| if 1 < 2 < 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained greater-than comparison |
| --- |
| struct Foo: |
| if 1 > 2 > 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| longer chained less-than comparison |
| --- |
| struct Foo: |
| if 1 < 2 < 3 <= 4: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "LESS_OR_EQUAL", |
| "args": [ |
| { |
| "constant": { |
| "value": "3" |
| } |
| }, |
| { |
| "constant": { |
| "value": "4" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| longer chained greater-than comparison |
| --- |
| struct Foo: |
| if 1 > 2 > 3 >= 4: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "GREATER_OR_EQUAL", |
| "args": [ |
| { |
| "constant": { |
| "value": "3" |
| } |
| }, |
| { |
| "constant": { |
| "value": "4" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained less-than and equal comparison |
| --- |
| struct Foo: |
| if 1 < 2 == 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained greater-than and equal comparison |
| --- |
| struct Foo: |
| if 1 > 2 == 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained equal and less-than comparison |
| --- |
| struct Foo: |
| if 1 == 2 < 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "LESS", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained equal and greater-than comparison |
| --- |
| struct Foo: |
| if 1 == 2 > 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "GREATER", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| chained equality comparison |
| --- |
| struct Foo: |
| if 1 == 2 == 3: |
| 0 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "AND", |
| "args": [ |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "1" |
| } |
| }, |
| { |
| "constant": { |
| "value": "2" |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "function": { |
| "function": "EQUALITY", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| choice operator |
| --- |
| struct Foo: |
| true ? 0 : 1 [+1] UInt bar |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "bar" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "CHOICE", |
| "args": [ |
| { |
| "boolean_constant": { |
| "value": true |
| } |
| }, |
| { |
| "constant": { |
| "value": "0" |
| } |
| }, |
| { |
| "constant": { |
| "value": "1" |
| } |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| max function |
| --- |
| struct Foo: |
| $max() [+1] UInt no_arg |
| $max(0) [+1] UInt one_arg |
| $max(2 * 3) [+1] UInt mul_arg |
| $max(2, 3) [+1] UInt two_arg |
| $max(2, 3, 4, 5, 6) [+1] UInt five_arg |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "no_arg" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "MAXIMUM" |
| } |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "one_arg" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "MAXIMUM", |
| "args": [ |
| { |
| "constant": { |
| "value": "0" |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "mul_arg" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "MAXIMUM", |
| "args": [ |
| { |
| "function": { |
| "function": "MULTIPLICATION", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "two_arg" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "MAXIMUM", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| } |
| ] |
| } |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "five_arg" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "MAXIMUM", |
| "args": [ |
| { |
| "constant": { |
| "value": "2" |
| } |
| }, |
| { |
| "constant": { |
| "value": "3" |
| } |
| }, |
| { |
| "constant": { |
| "value": "4" |
| } |
| }, |
| { |
| "constant": { |
| "value": "5" |
| } |
| }, |
| { |
| "constant": { |
| "value": "6" |
| } |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| has function |
| --- |
| struct Foo: |
| if $present(x): |
| 0 [+1] UInt field |
| if $present(x.y.z): |
| 0 [+1] UInt field2 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "field" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "PRESENCE", |
| "args": [ |
| { |
| "field_reference": { |
| "path": [ |
| { |
| "source_name": [ |
| { |
| "text": "x" |
| } |
| ] |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { |
| "name": { |
| "text": "field2" |
| } |
| }, |
| "existence_condition": { |
| "function": { |
| "function": "PRESENCE", |
| "args": [ |
| { |
| "field_reference": { |
| "path": [ |
| { |
| "source_name": [ |
| { |
| "text": "x" |
| } |
| ] |
| }, |
| { |
| "source_name": [ |
| { |
| "text": "y" |
| } |
| ] |
| }, |
| { |
| "source_name": [ |
| { |
| "text": "z" |
| } |
| ] |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| upper_bound function |
| --- |
| struct Foo: |
| $upper_bound(0) [+1] UInt one |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "one" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "UPPER_BOUND", |
| "args": [ |
| { |
| "constant": { |
| "value": "0" |
| } |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| lower_bound function |
| --- |
| struct Foo: |
| $lower_bound(0) [+1] UInt one |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { |
| "name": { |
| "text": "one" |
| } |
| }, |
| "location": { |
| "start": { |
| "function": { |
| "function": "LOWER_BOUND", |
| "args": [ |
| { |
| "constant": { |
| "value": "0" |
| } |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| struct addressable_unit |
| --- |
| struct Foo: |
| 0 [+1] UInt size |
| --- |
| { "type": [ { "structure": {}, "addressable_unit": "BYTE" } ] } |
| |
| === |
| bits addressable_unit |
| --- |
| bits Foo: |
| 0 [+1] UInt size |
| --- |
| { "type": [ { "structure": {}, "addressable_unit": "BIT" } ] } |
| |
| === |
| enum addressable_unit |
| --- |
| enum Foo: |
| BAR = 0 |
| --- |
| { "type": [ { "enumeration": {}, "addressable_unit": "BIT" } ] } |
| |
| === |
| type size source_location |
| --- |
| struct Foo: |
| 0 [+4] UInt:32 field |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "UInt" } ] } |
| }, |
| "size_in_bits": { |
| "source_location": { |
| "start": { "line": 3, "column": 15 }, |
| "end": { "line": 3, "column": 18 } |
| } |
| }, |
| "source_location": { |
| "start": { "line": 3, "column": 11 }, |
| "end": { "line": 3, "column": 18 } |
| } |
| }, |
| "name": { "name": { "text": "field" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| builtin references |
| --- |
| external Foo: |
| [requires: $is_statically_sized && $static_size_in_bits == 64] |
| --- |
| { |
| "type": [ |
| { |
| "external": {}, |
| "attribute": [ |
| { |
| "name": { "text": "requires" }, |
| "value": { |
| "expression": { |
| "function": { |
| "args": [ |
| { |
| "builtin_reference": { |
| "canonical_name": { |
| "module_file": "", |
| "object_path": [ "$is_statically_sized" ] |
| }, |
| "source_name": [ { "text": "$is_statically_sized" } ] |
| } |
| }, |
| { |
| "function": { |
| "args": [ |
| { |
| "builtin_reference": { |
| "canonical_name": { |
| "module_file": "", |
| "object_path": [ "$static_size_in_bits" ] |
| }, |
| "source_name": [ |
| { "text": "$static_size_in_bits" } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| } |
| } |
| } |
| ] |
| } |
| ] |
| } |
| |
| === |
| $next |
| --- |
| struct Foo: |
| $next [+0] UInt x |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "location": { |
| "start": { |
| "builtin_reference": { "source_name": [ { "text": "$next" } ] } |
| } |
| }, |
| "name": { "name": { "text": "x" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| virtual fields |
| --- |
| struct Foo: |
| let x = 10 |
| bits Bar: |
| let y = 100 |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "x" } }, |
| "read_transform": { "constant": { "value": "10" } } |
| } |
| ] |
| } |
| }, |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "y" } }, |
| "read_transform": { "constant": { "value": "100" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| builtin fields |
| --- |
| struct Foo: |
| let x = $size_in_bytes |
| let y = $max_size_in_bytes |
| let z = $min_size_in_bytes |
| bits Bar: |
| let x = $size_in_bits |
| let y = $max_size_in_bits |
| let z = $min_size_in_bits |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "x" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "$size_in_bytes" } ] } ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "y" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ |
| { "source_name": [ { "text": "$max_size_in_bytes" } ] } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "z" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ |
| { "source_name": [ { "text": "$min_size_in_bytes" } ] } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| }, |
| { |
| "structure": { |
| "field": [ |
| { |
| "name": { "name": { "text": "x" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ { "source_name": [ { "text": "$size_in_bits" } ] } ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "y" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ |
| { "source_name": [ { "text": "$max_size_in_bits" } ] } |
| ] |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "z" } }, |
| "read_transform": { |
| "field_reference": { |
| "path": [ |
| { "source_name": [ { "text": "$min_size_in_bits" } ] } |
| ] |
| } |
| } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| |
| === |
| parameterized type definitions |
| --- |
| struct Foo(a: Flag, b: UInt:32): |
| let x = 10 |
| bits Bar(c: UInt:16): |
| let y = 100 |
| struct Baz(): |
| let x = 10 |
| --- |
| { |
| "type": [ |
| { |
| "runtime_parameter": [ |
| { |
| "name": { "name": { "text": "a" } }, |
| "physical_type_alias": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "Flag" } ] } |
| } |
| } |
| }, |
| { |
| "name": { "name": { "text": "b" } }, |
| "physical_type_alias": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "UInt" } ] } |
| }, |
| "size_in_bits": { "constant": { "value": "32" } } |
| } |
| } |
| ] |
| }, |
| { |
| "runtime_parameter": [ |
| { |
| "name": { "name": { "text": "c" } }, |
| "physical_type_alias": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "UInt" } ] } |
| }, |
| "size_in_bits": { "constant": { "value": "16" } } |
| } |
| } |
| ] |
| }, |
| {} |
| ] |
| } |
| |
| === |
| parameterized type usages |
| --- |
| struct Foo: |
| 0 [+1] Two(1, 2) two |
| 1 [+1] One(3) one |
| 2 [+1] Zero() zero |
| --- |
| { |
| "type": [ |
| { |
| "structure": { |
| "field": [ |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "Two" } ] }, |
| "runtime_parameter": [ |
| { "constant": { "value": "1" } }, |
| { "constant": { "value": "2" } } |
| ] |
| } |
| }, |
| "name": { "name": { "text": "two" } } |
| }, |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "One" } ] }, |
| "runtime_parameter": [ { "constant": { "value": "3" } } ] |
| } |
| }, |
| "name": { "name": { "text": "one" } } |
| }, |
| { |
| "type": { |
| "atomic_type": { |
| "reference": { "source_name": [ { "text": "Zero" } ] } |
| } |
| }, |
| "name": { "name": { "text": "zero" } } |
| } |
| ] |
| } |
| } |
| ] |
| } |
| """ |
| |
| |
| # For each test in _NEGATIVE_TEST_CASES, parsing should fail, and the failure |
| # should indicate the specified token. |
| _NEGATIVE_TEST_CASES = """ |
| anonymous bits does not allow documentation |
| --- |
| -- doc |
| --- |
| struct Foo: |
| 0 [+1] bits: |
| -- doc |
| 0 [+2] UInt bar |
| === |
| anonymous bits does not allow subtypes |
| --- |
| enum |
| --- |
| struct Foo: |
| 0 [+1] bits: |
| enum Bar: |
| X = 1 |
| 0 [+2] Bar bar |
| """ |
| |
| |
| def _get_test_cases(): |
| test_case = collections.namedtuple("test_case", ["name", "parse_tree", "ir"]) |
| result = [] |
| for case in _TEST_CASES.split("==="): |
| name, emb, ir_text = case.split("---") |
| name = name.strip() |
| try: |
| ir = ir_pb2.Module.from_json(ir_text) |
| except Exception: |
| print(name) |
| raise |
| parse_result = parser.parse_module(tokenizer.tokenize(emb, "")[0]) |
| assert not parse_result.error, "{}:\n{}".format(name, parse_result.error) |
| result.append(test_case(name, parse_result.parse_tree, ir)) |
| return result |
| |
| |
| def _get_negative_test_cases(): |
| test_case = collections.namedtuple("test_case", |
| ["name", "text", "error_token"]) |
| result = [] |
| for case in _NEGATIVE_TEST_CASES.split("==="): |
| name, error_token, text = case.split("---") |
| name = name.strip() |
| error_token = error_token.strip() |
| result.append(test_case(name, text, error_token)) |
| return result |
| |
| |
| def _check_source_location(source_location, path, min_start, max_end): |
| """Performs sanity checks on a source_location field. |
| |
| Arguments: |
| source_location: The source_location to check. |
| path: The path, to use in error messages. |
| min_start: A minimum value for source_location.start, or None. |
| max_end: A maximum value for source_location.end, or None. |
| |
| Returns: |
| A list of error messages, or an empty list if no errors. |
| """ |
| if source_location.is_disjoint_from_parent: |
| # If source_location.is_disjoint_from_parent, then this source_location is |
| # allowed to be outside of the parent's source_location. |
| return [] |
| |
| result = [] |
| start = None |
| end = None |
| if not source_location.HasField("start"): |
| result.append("{}.start missing".format(path)) |
| else: |
| start = source_location.start |
| if not source_location.HasField("end"): |
| result.append("{}.end missing".format(path)) |
| else: |
| end = source_location.end |
| |
| if start and end: |
| if start.HasField("line") and end.HasField("line"): |
| if start.line > end.line: |
| result.append("{}.start.line > {}.end.line ({} vs {})".format( |
| path, path, start.line, end.line)) |
| elif start.line == end.line: |
| if (start.HasField("column") and end.HasField("column") and |
| start.column > end.column): |
| result.append("{}.start.column > {}.end.column ({} vs {})".format( |
| path, path, start.column, end.column)) |
| |
| for name, field in (("start", start), ("end", end)): |
| if not field: |
| continue |
| if field.HasField("line"): |
| if field.line <= 0: |
| result.append("{}.{}.line <= 0 ({})".format(path, name, field.line)) |
| else: |
| result.append("{}.{}.line missing".format(path, name)) |
| if field.HasField("column"): |
| if field.column <= 0: |
| result.append("{}.{}.column <= 0 ({})".format(path, name, field.column)) |
| else: |
| result.append("{}.{}.column missing".format(path, name)) |
| |
| if min_start and start: |
| if min_start.line > start.line or ( |
| min_start.line == start.line and min_start.column > start.column): |
| result.append("{}.start before parent start".format(path)) |
| |
| if max_end and end: |
| if max_end.line < end.line or ( |
| max_end.line == end.line and max_end.column < end.column): |
| result.append("{}.end after parent end".format(path)) |
| |
| return result |
| |
| |
| def _check_all_source_locations(proto, path="", min_start=None, max_end=None): |
| """Performs sanity checks on all source_locations in proto. |
| |
| Arguments: |
| proto: The proto to recursively check. |
| path: The path, to use in error messages. |
| min_start: A minimum value for source_location.start, or None. |
| max_end: A maximum value for source_location.end, or None. |
| |
| Returns: |
| A list of error messages, or an empty list if no errors. |
| """ |
| if path: |
| path += "." |
| |
| errors = [] |
| |
| child_start = None |
| child_end = None |
| # Only check the source_location value if this proto message actually has a |
| # source_location field. |
| if "source_location" in proto.raw_fields: |
| errors.extend(_check_source_location(proto.source_location, |
| path + "source_location", |
| min_start, max_end)) |
| child_start = proto.source_location.start |
| child_end = proto.source_location.end |
| |
| for name, spec in proto.field_specs.items(): |
| if name == "source_location": |
| continue |
| if not proto.HasField(name): |
| continue |
| field_path = "{}{}".format(path, name) |
| if isinstance(spec, ir_pb2.Repeated): |
| if issubclass(spec.type, ir_pb2.Message): |
| index = 0 |
| for i in getattr(proto, name): |
| item_path = "{}[{}]".format(field_path, index) |
| index += 1 |
| errors.extend( |
| _check_all_source_locations(i, item_path, child_start, child_end)) |
| else: |
| if issubclass(spec.type, ir_pb2.Message): |
| errors.extend(_check_all_source_locations(getattr(proto, name), |
| field_path, child_start, |
| child_end)) |
| |
| return errors |
| |
| |
| class ModuleIrTest(unittest.TestCase): |
| """Tests the module_ir.build_ir() function.""" |
| |
| def test_build_ir(self): |
| self.assertEqual(module_ir.build_ir(_MINIMAL_SAMPLE), _MINIMAL_SAMPLE_IR) |
| |
| def test_production_coverage(self): |
| """Checks that all grammar productions are used somewhere in tests.""" |
| used_productions = set() |
| module_ir.build_ir(_MINIMAL_SAMPLE, used_productions) |
| for test in _get_test_cases(): |
| module_ir.build_ir(test.parse_tree, used_productions) |
| self.assertEqual(set(module_ir.PRODUCTIONS) - used_productions, set([])) |
| |
| def test_double_negative_non_compilation(self): |
| """Checks that unparenthesized double unary minus/plus is a parse error.""" |
| for example in ("[x: - -3]", "[x: + -3]", "[x: - +3]", "[x: + +3]"): |
| parse_result = parser.parse_module(tokenizer.tokenize(example, "")[0]) |
| self.assertTrue(parse_result.error) |
| self.assertEqual(7, parse_result.error.token.source_location.start.column) |
| for example in ("[x:-(-3)]", "[x:+(-3)]", "[x:-(+3)]", "[x:+(+3)]"): |
| parse_result = parser.parse_module(tokenizer.tokenize(example, "")[0]) |
| self.assertFalse(parse_result.error) |
| |
| |
| def _make_superset_tests(): |
| |
| def _make_superset_test(test): |
| |
| def test_case(self): |
| ir = module_ir.build_ir(test.parse_tree) |
| is_superset, error_message = test_util.proto_is_superset(ir, test.ir) |
| self.assertTrue( |
| is_superset, |
| error_message + "\n" + ir.to_json(indent=2) + "\n" + |
| test.ir.to_json(indent=2)) |
| |
| return test_case |
| |
| for test in _get_test_cases(): |
| test_name = "test " + test.name + " proto superset" |
| assert not hasattr(ModuleIrTest, test_name) |
| setattr(ModuleIrTest, test_name, _make_superset_test(test)) |
| |
| |
| def _make_source_location_tests(): |
| |
| def _make_source_location_test(test): |
| |
| def test_case(self): |
| error_list = _check_all_source_locations( |
| module_ir.build_ir(test.parse_tree)) |
| self.assertFalse(error_list, "\n".join([test.name] + error_list)) |
| |
| return test_case |
| |
| for test in _get_test_cases(): |
| test_name = "test " + test.name + " source location" |
| assert not hasattr(ModuleIrTest, test_name) |
| setattr(ModuleIrTest, test_name, _make_source_location_test(test)) |
| |
| |
| def _make_negative_tests(): |
| |
| def _make_negative_test(test): |
| |
| def test_case(self): |
| parse_result = parser.parse_module(tokenizer.tokenize(test.text, "")[0]) |
| self.assertEqual(test.error_token, parse_result.error.token.text.strip()) |
| |
| return test_case |
| |
| for test in _get_test_cases(): |
| test_name = "test " + test.name + " compilation failure" |
| assert not hasattr(ModuleIrTest, test_name) |
| setattr(ModuleIrTest, test_name, _make_negative_test(test)) |
| |
| |
| _make_superset_tests() |
| _make_source_location_tests() |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |