UNPKG

@foxglove/omgidl-parser

Version:

Parse OMG IDL to flattened definitions for serialization

1,788 lines (1,771 loc) 54.5 kB
import { parseIDLToAST } from "./parseIDLToAST"; describe("IDL grammar", () => { it("parses a simple IDL", () => { const schema = ` struct MyAction_Goal { int32 input_value; }; `; expect(parseIDLToAST(schema)).toEqual([ { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "input_value", type: "int32" }, ], name: "MyAction_Goal", }, ]); }); it("parses a nested IDL with constants", () => { const schema = ` module idl_parser { module action { module MyAction_Goal_Constants { const short SHORT_CONSTANT = -23; }; struct MyAction_Goal { int32 input_value; }; }; }; `; expect(parseIDLToAST(schema)).toEqual([ { name: "idl_parser", declarator: "module", definitions: [ { name: "action", declarator: "module", definitions: [ { name: "MyAction_Goal_Constants", declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "SHORT_CONSTANT", type: "short", value: -23, valueText: "-23", }, ], }, { name: "MyAction_Goal", declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "input_value", type: "int32", }, ], }, ], }, ], }, ]); }); it("parses all numerical types", () => { const schema = ` struct All_Numbers { unsigned short unsigned_short_value; long long_value; unsigned long unsigned_long_value; long long long_long_value; unsigned long long unsigned_long_long_value; float float_value; double double_value; char char_value; wchar wchar_value; boolean boolean_value; octet octet_value; int8 int8_value; uint8 uint8_value; int16 int16_value; uint16 uint16_value; int32 int32_value; uint32 uint32_value; int64 int64_value; uint64 uint64_value; }; `; expect(parseIDLToAST(schema)).toEqual([ { name: "All_Numbers", declarator: "struct", definitions: [ { type: "unsigned short", name: "unsigned_short_value", isComplex: false, declarator: "struct-member", }, { type: "long", name: "long_value", isComplex: false, declarator: "struct-member", }, { type: "unsigned long", name: "unsigned_long_value", isComplex: false, declarator: "struct-member", }, { type: "long long", name: "long_long_value", isComplex: false, declarator: "struct-member", }, { type: "unsigned long long", name: "unsigned_long_long_value", isComplex: false, declarator: "struct-member", }, { type: "float", name: "float_value", isComplex: false, declarator: "struct-member", }, { type: "double", name: "double_value", isComplex: false, declarator: "struct-member", }, { type: "char", name: "char_value", isComplex: false, declarator: "struct-member", }, { type: "wchar", name: "wchar_value", isComplex: false, declarator: "struct-member", }, { type: "bool", name: "boolean_value", isComplex: false, declarator: "struct-member", }, { type: "octet", name: "octet_value", isComplex: false, declarator: "struct-member", }, { type: "int8", name: "int8_value", isComplex: false, declarator: "struct-member", }, { type: "uint8", name: "uint8_value", isComplex: false, declarator: "struct-member", }, { type: "int16", name: "int16_value", isComplex: false, declarator: "struct-member", }, { type: "uint16", name: "uint16_value", isComplex: false, declarator: "struct-member", }, { type: "int32", name: "int32_value", isComplex: false, declarator: "struct-member", }, { type: "uint32", name: "uint32_value", isComplex: false, declarator: "struct-member", }, { type: "int64", name: "int64_value", isComplex: false, declarator: "struct-member", }, { type: "uint64", name: "uint64_value", isComplex: false, declarator: "struct-member", }, ], }, ]); }); it("parses a module full of numeric constants", () => { const types = parseIDLToAST( ` module idl_parser { module msg { module MyMessage_Constants { const short SHORT_CONSTANT = -23; const unsigned long UNSIGNED_LONG_CONSTANT = 42; const float FLOAT_CONSTANT = 1.25; const double EXP_DOUBLE_CONSTANT = 1.25e-3; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "SHORT_CONSTANT", type: "short", value: -23, valueText: "-23", }, { isComplex: false, isConstant: true, declarator: "const", name: "UNSIGNED_LONG_CONSTANT", type: "unsigned long", value: 42, valueText: "42", }, { isComplex: false, isConstant: true, declarator: "const", name: "FLOAT_CONSTANT", type: "float", value: 1.25, valueText: "1.25", }, { isComplex: false, isConstant: true, declarator: "const", name: "EXP_DOUBLE_CONSTANT", type: "double", value: 0.00125, valueText: "1.25e-3", }, ], name: "MyMessage_Constants", }, ], name: "msg", }, ], name: "idl_parser", }, ]); }); it("parses a module with various floating point default values", () => { const types = parseIDLToAST( ` module idl_parser { module msg { struct MyMessage { @default ( value=1.9e10 ) float int_and_frac_with_positive_scientific; @default ( value=1.9e+10 ) float int_and_frac_with_explicit_positive_scientific; @default ( value=1.1e-10) float int_and_frac_with_negative_scientific; @default ( value=0.00009 ) float int_and_frac; @default ( value = 1. ) float int_with_empty_frac; @default ( value = .1 ) float frac_only; @default ( value=9e05 ) float int_with_positive_scientific; @default ( value=9e+05 ) float int_with_explicit_positive_scientific; @default ( value=9e-05 ) float int_with_negative_scientific; @default ( value=8.7d ) float fixed_int_and_frac; @default ( value=4.d ) float fixed_int_with_dot_only; @default ( value=.3d ) float fixed_frac_only; @default ( value=7d ) float fixed_int_only; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "struct", definitions: [ { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 19000000000 }, }, }, isComplex: false, declarator: "struct-member", name: "int_and_frac_with_positive_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 19000000000 }, }, }, isComplex: false, declarator: "struct-member", name: "int_and_frac_with_explicit_positive_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 1.1e-10 }, }, }, isComplex: false, declarator: "struct-member", name: "int_and_frac_with_negative_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 0.00009 }, }, }, isComplex: false, declarator: "struct-member", name: "int_and_frac", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 1 }, }, }, isComplex: false, declarator: "struct-member", name: "int_with_empty_frac", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 0.1 }, }, }, isComplex: false, declarator: "struct-member", name: "frac_only", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 900000 }, }, }, isComplex: false, declarator: "struct-member", name: "int_with_positive_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 900000 }, }, }, isComplex: false, declarator: "struct-member", name: "int_with_explicit_positive_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 0.00009 }, }, }, isComplex: false, declarator: "struct-member", name: "int_with_negative_scientific", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 8.7 }, }, }, isComplex: false, declarator: "struct-member", name: "fixed_int_and_frac", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 4 }, }, }, isComplex: false, declarator: "struct-member", name: "fixed_int_with_dot_only", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 0.3 }, }, }, isComplex: false, declarator: "struct-member", name: "fixed_frac_only", type: "float", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 7 }, }, }, isComplex: false, declarator: "struct-member", name: "fixed_int_only", type: "float", }, ], name: "MyMessage", }, ], name: "msg", }, ], name: "idl_parser", }, ]); }); it("parses a module with customTypes", () => { const types = parseIDLToAST( ` module idl_parser { module msg { struct MyMessage { geometry::msg::Point single_point; geometry::msg::Point points_with_length[10]; sequence<geometry::msg::Point> points_with_length_sequence; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "struct", definitions: [ { declarator: "struct-member", name: "single_point", type: "geometry::msg::Point", }, { declarator: "struct-member", arrayLengths: [10], isArray: true, name: "points_with_length", type: "geometry::msg::Point", }, { declarator: "struct-member", arrayUpperBound: undefined, isArray: true, name: "points_with_length_sequence", type: "geometry::msg::Point", }, ], name: "MyMessage", }, ], name: "msg", }, ], name: "idl_parser", }, ]); }); it("parses a module with arbitrary annotations including default values", () => { const types = parseIDLToAST( ` module idl_parser { module msg { @verbatim ( language="comment", text="Documentation of MyMessage." "Adjacent string literal." ) @transfer_mode(SHMEM_REF) struct MyMessage { @default ( value=123 ) unsigned short unsigned_short_value; @key @range ( min=-10, max=10 ) long long_value; @verbatim (language="comment", text="") @arbitrary_annotation ( key1="value1", key2=TRUE, key3=0.0, key4=10 ) @key unsigned long unsigned_long_value; @id(100) @default(100) uint32 uint32_with_default; }; }; }; `, ); expect(types).toEqual([ { name: "idl_parser", declarator: "module", definitions: [ { name: "msg", declarator: "module", definitions: [ { name: "MyMessage", declarator: "struct", annotations: { verbatim: { name: "verbatim", type: "named-params", namedParams: { language: "comment", text: "Documentation of MyMessage.Adjacent string literal.", }, }, transfer_mode: { name: "transfer_mode", type: "const-param", value: { usesConstant: true, name: "SHMEM_REF" }, }, }, definitions: [ { name: "unsigned_short_value", isComplex: false, declarator: "struct-member", type: "unsigned short", annotations: { default: { name: "default", type: "named-params", namedParams: { value: 123 }, }, }, }, { name: "long_value", isComplex: false, declarator: "struct-member", type: "long", annotations: { key: { name: "key", type: "no-params", }, range: { name: "range", type: "named-params", namedParams: { min: -10, max: 10, }, }, }, }, { name: "unsigned_long_value", isComplex: false, declarator: "struct-member", type: "unsigned long", annotations: { verbatim: { name: "verbatim", type: "named-params", namedParams: { language: "comment", text: "", }, }, arbitrary_annotation: { name: "arbitrary_annotation", type: "named-params", namedParams: { key1: "value1", key2: true, key3: 0.0, key4: 10, }, }, key: { name: "key", type: "no-params", }, }, }, { isComplex: false, declarator: "struct-member", name: "uint32_with_default", type: "uint32", annotations: { id: { name: "id", type: "const-param", value: 100, }, default: { name: "default", type: "const-param", value: 100, }, }, }, ], }, ], }, ], }, ]); }); it("parses a module with a typedefs used in a struct", () => { const types = parseIDLToAST( ` module idl_parser { module action { typedef sequence<int32, 10> int32arr; @default (value=5) typedef short shortWithDefault; struct MyAction_Goal { int32arr intArray; shortWithDefault short5; }; }; }; `, ); expect(types).toEqual([ { name: "idl_parser", declarator: "module", definitions: [ { name: "action", declarator: "module", definitions: [ { arrayUpperBound: 10, declarator: "typedef", isArray: true, isComplex: false, name: "int32arr", type: "int32", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 5 } }, }, declarator: "typedef", isComplex: false, name: "shortWithDefault", type: "short", }, { name: "MyAction_Goal", declarator: "struct", definitions: [ { declarator: "struct-member", name: "intArray", type: "int32arr", }, { declarator: "struct-member", name: "short5", type: "shortWithDefault", }, ], }, ], }, ], }, ]); }); it("parses a module with an multiple enclosed structs and modules", () => { const types = parseIDLToAST( ` module idl_parser { module action { module MyAction_Goal_Constants { const short SHORT_CONSTANT = -23; }; struct MyAction_Goal { int32 input_value; }; module MyAction_Result_Constants { const unsigned long UNSIGNED_LONG_CONSTANT = 42; }; struct MyAction_Result { uint32 output_value; }; module MyAction_Feedback_Constants { const float FLOAT_CONSTANT = 1.25; }; struct MyAction_Feedback { float progress_value; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "SHORT_CONSTANT", type: "short", value: -23, valueText: "-23", }, ], name: "MyAction_Goal_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "input_value", type: "int32", }, ], name: "MyAction_Goal", }, { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "UNSIGNED_LONG_CONSTANT", type: "unsigned long", value: 42, valueText: "42", }, ], name: "MyAction_Result_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "output_value", type: "uint32", }, ], name: "MyAction_Result", }, { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "FLOAT_CONSTANT", type: "float", value: 1.25, valueText: "1.25", }, ], name: "MyAction_Feedback_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "progress_value", type: "float", }, ], name: "MyAction_Feedback", }, ], name: "action", }, ], name: "idl_parser", }, ]); }); it("ignore #include statements in AST", () => { const types = parseIDLToAST( ` #include "OtherMessage.idl" #include <pkgname/msg/OtherMessage.idl> module idl_parser { module action { module MyAction_Goal_Constants { const short SHORT_CONSTANT = -23; }; struct MyAction_Goal { int32 input_value; }; }; }; `, ); // same as above expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "SHORT_CONSTANT", type: "short", value: -23, valueText: "-23", }, ], name: "MyAction_Goal_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "input_value", type: "int32", }, ], name: "MyAction_Goal", }, ], name: "action", }, ], name: "idl_parser", }, ]); }); it("parses a module full of string constants", () => { const types = parseIDLToAST( ` module idl_parser { module msg { module MyMessage_Constants { const string STRING_CONSTANT = "string_value"; const wstring WSTRING_CONSTANT = "wstring_value_\u2122"; const string EMPTY_STRING_CONSTANT = ""; const string COMBINED_STRING_CONSTANT = "part1 " "part2" " part3"; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "STRING_CONSTANT", type: "string", upperBound: undefined, value: "string_value", valueText: "string_value", }, { isComplex: false, isConstant: true, declarator: "const", name: "WSTRING_CONSTANT", type: "wstring", upperBound: undefined, value: "wstring_value_™", valueText: "wstring_value_™", }, { isComplex: false, isConstant: true, declarator: "const", name: "EMPTY_STRING_CONSTANT", type: "string", upperBound: undefined, value: "", valueText: "", }, { isComplex: false, isConstant: true, declarator: "const", name: "COMBINED_STRING_CONSTANT", type: "string", upperBound: undefined, value: "part1 part2 part3", valueText: "part1 part2 part3", }, ], name: "MyMessage_Constants", }, ], name: "msg", }, ], name: "idl_parser", }, ]); }); it("parses a module of all array types", () => { const types = parseIDLToAST( ` module idl_parser { module msg { module MyMessage_Constants { const unsigned long UNSIGNED_LONG_CONSTANT = 42; }; struct MyMessage { string<5> bounded_string_value; wstring wstring_value; wstring<23> bounded_wstring_value; wstring<UNSIGNED_LONG_CONSTANT> constant_bounded_wstring_value; sequence<short> unbounded_short_values; sequence<short, 5> bounded_short_values; sequence<string<3>> unbounded_values_of_bounded_strings; sequence<string<3>, 4> bounded_values_of_bounded_strings; short array_short_values[23]; }; }; }; `, ); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "UNSIGNED_LONG_CONSTANT", type: "unsigned long", value: 42, valueText: "42", }, ], name: "MyMessage_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "bounded_string_value", type: "string", upperBound: 5, }, { isComplex: false, declarator: "struct-member", name: "wstring_value", type: "wstring", upperBound: undefined, }, { isComplex: false, declarator: "struct-member", name: "bounded_wstring_value", type: "wstring", upperBound: 23, }, { isComplex: false, declarator: "struct-member", name: "constant_bounded_wstring_value", type: "wstring", upperBound: { name: "UNSIGNED_LONG_CONSTANT", usesConstant: true }, }, { arrayUpperBound: undefined, isArray: true, isComplex: false, declarator: "struct-member", name: "unbounded_short_values", type: "short", }, { arrayUpperBound: 5, isArray: true, isComplex: false, declarator: "struct-member", name: "bounded_short_values", type: "short", }, { arrayUpperBound: undefined, isArray: true, isComplex: false, declarator: "struct-member", name: "unbounded_values_of_bounded_strings", type: "string", upperBound: 3, }, { arrayUpperBound: 4, isArray: true, isComplex: false, declarator: "struct-member", name: "bounded_values_of_bounded_strings", type: "string", upperBound: 3, }, { arrayLengths: [23], isArray: true, isComplex: false, declarator: "struct-member", name: "array_short_values", type: "short", }, ], name: "MyMessage", }, ], name: "msg", }, ], name: "idl_parser", }, ]); }); it("can parse comments", () => { const msgDef = ` // All of these comments should be ignored module action { /** another comment */ module MyAction_Goal_Constants /** maybe a sneaky one here */ { // two here of the same type // _another one_ const string tricky = "/** is this a comment? */ // hopefully not"; // like I'm not even here }; /** a multi * line * comment */ struct MyAction_Goal { // two here of different types /** maybe one more that */ int32 input_value; /** inline */ }; }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "module", definitions: [ { declarator: "module", definitions: [ { isComplex: false, isConstant: true, declarator: "const", name: "tricky", type: "string", upperBound: undefined, value: "/** is this a comment? */ // hopefully not", valueText: "/** is this a comment? */ // hopefully not", }, ], name: "MyAction_Goal_Constants", }, { declarator: "struct", definitions: [ { isComplex: false, declarator: "struct-member", name: "input_value", type: "int32", }, ], name: "MyAction_Goal", }, ], name: "action", }, ]); }); it("can parse multiple forward declarations on same line with default annotation", () => { const msgDef = ` struct MyAction_Goal { @default(value=5) int32 int1, int2; }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "struct", definitions: [ { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 5 } }, }, isComplex: false, declarator: "struct-member", name: "int1", type: "int32", }, { annotations: { default: { name: "default", type: "named-params", namedParams: { value: 5 } }, }, isComplex: false, declarator: "struct-member", name: "int2", type: "int32", }, ], name: "MyAction_Goal", }, ]); }); it("parses enums", () => { const msgDef = ` enum COLORS { RED, GREEN, BLUE }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "enum", name: "COLORS", enumerators: [{ name: "RED" }, { name: "GREEN" }, { name: "BLUE" }], }, ]); }); it("parses enums with value overrides", () => { const msgDef = ` enum COLORS { RED, @value(5) GREEN, BLUE }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "enum", name: "COLORS", enumerators: [ { name: "RED" }, { name: "GREEN", annotations: { value: { name: "value", type: "const-param", value: 5 } }, }, { name: "BLUE" }, ], }, ]); }); it("parses enums in modules", () => { const msgDef = ` module Scene { enum COLORS { RED, GREEN, BLUE }; }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "module", name: "Scene", definitions: [ { declarator: "enum", name: "COLORS", enumerators: [{ name: "RED" }, { name: "GREEN" }, { name: "BLUE" }], }, ], }, ]); }); it("parses enums used as constants", () => { const msgDef = ` enum COLORS { RED, GREEN, BLUE }; module Scene { module DefaultColors { const COLORS red = COLORS::RED; }; struct Line { @default(value=COLORS::GREEN) COLORS color; }; }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { declarator: "enum", name: "COLORS", enumerators: [{ name: "RED" }, { name: "GREEN" }, { name: "BLUE" }], }, { declarator: "module", name: "Scene", definitions: [ { name: "DefaultColors", declarator: "module", definitions: [ { isConstant: true, isComplex: false, declarator: "const", name: "red", type: "COLORS", value: { name: "COLORS::RED", usesConstant: true, }, valueText: "COLORS::RED", }, ], }, { name: "Line", declarator: "struct", definitions: [ { annotations: { default: { name: "default", type: "named-params", namedParams: { value: { usesConstant: true, name: "COLORS::GREEN" }, }, }, }, declarator: "struct-member", name: "color", type: "COLORS", }, ], }, ], }, ]); }); it("parses multiple top level typedefs referencing each other", () => { const msgDef = ` typedef sequence<short> shortSeq; typedef sequence<shortSeq> shortSeqSeq; `; expect(parseIDLToAST(msgDef)).toEqual([ { name: "shortSeq", declarator: "typedef", isArray: true, arrayUpperBound: undefined, isComplex: false, type: "short", }, { name: "shortSeqSeq", declarator: "typedef", isArray: true, type: "shortSeq", }, ]); }); it("can parse basic multi-dimensional arrays in typedefs", () => { const msgDef = ` typedef float matrix[3][2]; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { name: "matrix", arrayLengths: [3, 2], declarator: "typedef", isArray: true, isComplex: false, type: "float", }, ]); }); it("can parse basic multi-dimensional arrays in struct members", () => { const msgDef = ` struct Camera { float matrix[3][2]; }; `; const types = parseIDLToAST(msgDef); expect(types).toEqual([ { name: "Camera", declarator: "struct", definitions: [ { name: "matrix", arrayLengths: [3, 2], declarator: "struct-member", isArray: true, isComplex: false, type: "float", }, ], }, ]); }); it("can parse simple union declaration", () => { const msgDef = ` union MyUnion switch (long) { case 1: long long_branch; case 3: float float_branch; case 4: char char_branch; default: uint8 default; }; struct Foo { MyUnion my_union; }; `; const ast = parseIDLToAST(msgDef); expect(ast).toEqual([ { name: "MyUnion", declarator: "union", switchType: "long", cases: [ { predicates: [1], type: { name: "long_branch", isComplex: false, type: "long", }, }, { predicates: [3], type: { name: "float_branch", isComplex: false, type: "float", }, }, { predicates: [4], type: { name: "char_branch", isComplex: false, type: "char", }, }, ], defaultCase: { name: "default", isComplex: false, type: "uint8", }, }, { name: "Foo", declarator: "struct", definitions: [ { name: "my_union", declarator: "struct-member", type: "MyUnion", }, ], }, ]); }); it("can parse simple union declaration that has annotations on definitions", () => { const msgDef = ` union MyUnion switch (long) { case 1: @id(100) long long_branch; case 3: @id(200) float float_branch; case 4: @id(300) char char_branch; default: @id(400) uint8 default; }; struct Foo { MyUnion my_union; }; `; const ast = parseIDLToAST(msgDef); expect(ast).toEqual([ { name: "MyUnion", declarator: "union", switchType: "long", cases: [ { predicates: [1], type: { name: "long_branch", isComplex: false, type: "long", annotations: { id: { name: "id", type: "const-param", value: 100, }, }, }, }, { predicates: [3], type: { name: "float_branch", isComplex: false, type: "float", annotations: { id: { name: "id", type: "const-param", value: 200, }, }, }, }, { predicates: [4], type: { name: "char_branch", isComplex: false, type: "char", annotations: { id: { name: "id", type: "const-param", value: 300, }, }, }, }, ], defaultCase: { name: "default", isComplex: false, type: "uint8", annotations: { id: { name: "id", type: "const-param", value: 400, }, }, }, }, { name: "Foo", declarator: "struct", definitions: [ { name: "my_union", declarator: "struct-member", type: "MyUnion", }, ], }, ]); }); it("can parse union that uses enums", () => { const msgDef = ` enum ColorMode { GRAY, RGBA, RGB }; union Color switch (ColorMode) { case ColorMode::GRAY: uint8 gray; case ColorMode::RGBA: uint8 rgba[4]; default: uint8 rgb[3]; }; struct ColorSettings { Color chosenColor; }; `; const ast = parseIDLToAST(msgDef); expect(ast).toEqual([ { declarator: "enum", enumerators: [{ name: "GRAY" }, { name: "RGBA" }, { name: "RGB" }], name: "ColorMode", }, { name: "Color", declarator: "union", switchType: "ColorMode", cases: [ { predicates: [ { name: "ColorMode::GRAY", usesConstant: true, }, ], type: { isComplex: false, name: "gray", type: "uint8", }, }, { predicates: [ { name: "ColorMode::RGBA", usesConstant: true, }, ], type: { arrayLengths: [4], isArray: true, isComplex: false, name: "rgba", type: "uint8", }, }, ], defaultCase: { arrayLengths: [3], isArray: true, isComplex: false, name: "rgb", type: "uint8", }, }, { name: "ColorSettings", declarator: "struct", definitions: [ { declarator: "struct-member", name: "chosenColor", type: "Color", }, ], }, ]); }); it("can parse union that uses boolean", () => { const msgDef = ` typedef boolean usesColor; union Color switch (usesColor) { case TRUE: uint8 rgba[4]; case FALSE: uint8 gray; }; struct ColorSettings { Color chosenColor; }; `; const ast = parseIDLToAST(msgDef); expect(ast).toEqual([ { name: "usesColor", isComplex: false, declarator: "typedef", type: "bool", }, { name: "Color", declarator: "union", switchType: "usesColor", cases: [ { predicates: [true], type: { name: "rgba", arrayLengths: [4], isArray: true, isComplex: false, type: "uint8", }, }, { predicates: [false], type: { name: "gray", isComplex: false, type: "uint8", }, }, ], }, { name: "ColorSettings", declarator: "struct", definitions: [ { name: "chosenColor", declarator: "struct-member", type: "Color", }, ], }, ]); }); it("can parse struct with member of the same name", () => { const msgDef = ` struct ColorSettings { uint8 ColorSettings; }; `; const ast = parseIDLToAST(msgDef); expect(ast).toEqual([ { name: "ColorSettings"