From 88a4cf86597dda2ef71209dcd8a2af954f2771b1 Mon Sep 17 00:00:00 2001 From: Sergey Prokhorov Date: Sat, 14 Mar 2020 23:15:04 +0100 Subject: [PATCH] Allow any type inside array and map; fix single-letter namespaced IDs --- src/avro_idl_lexer.xrl | 2 +- src/avro_idl_parser.yrl | 8 +++--- test/avro_idl_parse_tests.erl | 46 ++++++++++++++++++++++++++++++++++- test/avro_idl_tests.erl | 21 ++++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/avro_idl_lexer.xrl b/src/avro_idl_lexer.xrl index d1cd5df..6650125 100644 --- a/src/avro_idl_lexer.xrl +++ b/src/avro_idl_lexer.xrl @@ -57,7 +57,7 @@ error|throws|oneway|void|import|idl|protocol|schema : {token, {list_to_atom(Toke [A-Za-z_][A-Za-z0-9_]* : {token, {id, TokenLine, TokenChars}}. %% namespaced will only be allowed in data type spec -[A-Za-z_][A-Za-z0-9_]+(\.[A-Za-z_][A-Za-z0-9_]+)+ : {token, {ns_id, TokenLine, TokenChars}}. +[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)+ : {token, {ns_id, TokenLine, TokenChars}}. %% https://blog.ostermiller.org/finding-comments-in-source-code-using-regular-expressions/ %% `/** .. */` is a docstring for the following object diff --git a/src/avro_idl_parser.yrl b/src/avro_idl_parser.yrl index d2c33b0..2a8d0cd 100644 --- a/src/avro_idl_parser.yrl +++ b/src/avro_idl_parser.yrl @@ -210,13 +210,13 @@ union_tail -> %% -- Array typedef array -> - array_t '<' primitive_t '>' : - {array, value_of('$3')}. %FIXME: not just primitives! + array_t '<' type '>' : + {array, '$3'}. %% -- Map typedef map -> - map_t '<' primitive_t '>' : - {map, value_of('$3')}. %FIXME: not just primitives! + map_t '<' type '>' : + {map, '$3'}. %% == Function (message) definitions diff --git a/test/avro_idl_parse_tests.erl b/test/avro_idl_parse_tests.erl index 24fece5..1aee084 100644 --- a/test/avro_idl_parse_tests.erl +++ b/test/avro_idl_parse_tests.erl @@ -142,10 +142,54 @@ protocol_with_typedefs_test() -> #function{name = "ping", extra = undefined}]}, parse_idl("protocol_with_typedefs")). +array_types_test() -> + Probes = + [{int, "int"}, + {{decimal, 1, 2}, "decimal(1, 2)"}, + {null, "null"}, + {{custom, "MyType"}, "MyType"}, + {{custom, "my_ns.MyType"}, "my_ns.MyType"}, + {{union, [int, null]}, "union{int, null}"}, + {{array, int}, "array"}, + {{map, int}, "map"}], + lists:foreach( + fun({ExpectType, IdlType}) -> + test_field_type({array, ExpectType}, "array<" ++ IdlType ++ ">") + end, Probes). + +map_types_test() -> + Probes = + [{int, "int"}, + {{custom, "MyType"}, "MyType"}, + {{array, int}, "array"}, + {{map, int}, "map"}], + lists:foreach( + fun({ExpectType, IdlType}) -> + test_field_type({map, ExpectType}, "map<" ++ IdlType ++ ">") + end, Probes). + +%% Helpers + +test_field_type(ExpectType, IdlType) -> + Idl = ("protocol P {" + " record R { " ++ IdlType ++ " f; }" + "}"), + #protocol{ + definitions = + [#record{ + fields = + [#field{type = Type}]}]} = parse_str(Idl), + ?assertEqual(ExpectType, Type, + #{proto => Idl, + type => IdlType}). + parse_idl(Name) -> File = "test/data/" ++ Name ++ ".avdl", {ok, B} = file:read_file(File), - {ok, T0, _} = avro_idl_lexer:string(binary_to_list(B)), + parse_str(binary_to_list(B)). + +parse_str(Str) -> + {ok, T0, _} = avro_idl_lexer:string(Str), %% ?debugFmt("Name: ~p~nTokens:~n~p", [Name, T0]), T = avro_idl_lexer:preprocess(T0, [drop_comments, trim_doc]), {ok, Tree} = avro_idl_parser:parse(T), diff --git a/test/avro_idl_tests.erl b/test/avro_idl_tests.erl index 148392f..ec94b7e 100644 --- a/test/avro_idl_tests.erl +++ b/test/avro_idl_tests.erl @@ -119,6 +119,27 @@ duplicate_annotation_test() -> "@my_decorator(\"a\") @my_decorator(\"b\") protocol MyProto{}", "") ). +nested_complex_types_test() -> + ?assertEqual( + #{protocol => "P", + messages => [], + types => + [#{type => record, + name => "R", + fields => + [#{name => "f", + type => + #{type => array, + items => + #{type => map, + values => [null, "ns.T"]} + } + } + ]}]}, + avro_idl:str_to_avpr( + "protocol P { record R { array> f; }}", "") + ). + %% Helpers idl_to_avpr(Name) ->