diff --git a/deps/amqp10_client/include/amqp10_client.hrl b/deps/amqp10_client/include/amqp10_client.hrl new file mode 100644 index 000000000000..70c9316904e7 --- /dev/null +++ b/deps/amqp10_client/include/amqp10_client.hrl @@ -0,0 +1,11 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. +%% + +-record(filter, { + descriptor :: binary() | non_neg_integer(), + value :: term() + }). diff --git a/deps/amqp10_client/src/amqp10_client.erl b/deps/amqp10_client/src/amqp10_client.erl index 6b4a368908a3..d587d9a417a6 100644 --- a/deps/amqp10_client/src/amqp10_client.erl +++ b/deps/amqp10_client/src/amqp10_client.erl @@ -7,7 +7,7 @@ -module(amqp10_client). --include("amqp10_client.hrl"). +-include("amqp10_client_internal.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). -export([open_connection/1, diff --git a/deps/amqp10_client/src/amqp10_client_connection.erl b/deps/amqp10_client/src/amqp10_client_connection.erl index 89a3396d85c1..ac1d8a263cf1 100644 --- a/deps/amqp10_client/src/amqp10_client_connection.erl +++ b/deps/amqp10_client/src/amqp10_client_connection.erl @@ -9,7 +9,7 @@ -behaviour(gen_statem). --include("amqp10_client.hrl"). +-include("amqp10_client_internal.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). -include_lib("amqp10_common/include/amqp10_types.hrl"). diff --git a/deps/amqp10_client/src/amqp10_client_frame_reader.erl b/deps/amqp10_client/src/amqp10_client_frame_reader.erl index 89c67d6a6516..1ef0836049e0 100644 --- a/deps/amqp10_client/src/amqp10_client_frame_reader.erl +++ b/deps/amqp10_client/src/amqp10_client_frame_reader.erl @@ -8,7 +8,7 @@ -behaviour(gen_statem). --include("amqp10_client.hrl"). +-include("amqp10_client_internal.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). -ifdef(TEST). diff --git a/deps/amqp10_client/src/amqp10_client.hrl b/deps/amqp10_client/src/amqp10_client_internal.hrl similarity index 100% rename from deps/amqp10_client/src/amqp10_client.hrl rename to deps/amqp10_client/src/amqp10_client_internal.hrl diff --git a/deps/amqp10_client/src/amqp10_client_session.erl b/deps/amqp10_client/src/amqp10_client_session.erl index 3cb766e81e80..b3f80e2f0dc3 100644 --- a/deps/amqp10_client/src/amqp10_client_session.erl +++ b/deps/amqp10_client/src/amqp10_client_session.erl @@ -9,6 +9,7 @@ -behaviour(gen_statem). -include("amqp10_client.hrl"). +-include("amqp10_client_internal.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). -include_lib("amqp10_common/include/amqp10_types.hrl"). @@ -86,7 +87,7 @@ -type attach_role() :: {sender, target_def()} | {receiver, source_def(), pid()}. % http://www.amqp.org/specification/1.0/filters --type filter() :: #{binary() => binary() | map() | list(binary())}. +-type filter() :: #{binary() => #filter{} | binary() | map() | list(binary())}. -type max_message_size() :: undefined | non_neg_integer(). -type footer_opt() :: crc32 | adler32. @@ -781,29 +782,39 @@ translate_filters(Filters) when map_size(Filters) =:= 0 -> undefined; translate_filters(Filters) -> - {map, - maps:fold( - fun - (<<"apache.org:legacy-amqp-headers-binding:map">> = K, V, Acc) when is_map(V) -> - %% special case conversion - Key = sym(K), - [{Key, {described, Key, translate_legacy_amqp_headers_binding(V)}} | Acc]; - (K, V, Acc) when is_binary(K) -> - %% try treat any filter value generically - Key = sym(K), - Value = filter_value_type(V), - [{Key, {described, Key, Value}} | Acc] - end, [], Filters)}. - -filter_value_type(V) when is_binary(V) -> + {map, lists:map( + fun({Name, #filter{descriptor = Desc, + value = V}}) + when is_binary(Name) -> + Descriptor = if is_binary(Desc) -> {symbol, Desc}; + is_integer(Desc) -> {ulong, Desc} + end, + {{symbol, Name}, {described, Descriptor, V}}; + ({<<"apache.org:legacy-amqp-headers-binding:map">> = K, V}) + when is_map(V) -> + %% special case conversion + Key = sym(K), + Val = translate_legacy_amqp_headers_binding(V), + {Key, {described, Key, Val}}; + ({K, V}) + when is_binary(K) -> + Key = {symbol, K}, + Val = filter_value_type(V), + {Key, {described, Key, Val}} + end, maps:to_list(Filters))}. + +filter_value_type(V) + when is_binary(V) -> %% this is clearly not always correct {utf8, V}; filter_value_type(V) when is_integer(V) andalso V >= 0 -> {uint, V}; -filter_value_type(VList) when is_list(VList) -> +filter_value_type(VList) + when is_list(VList) -> {list, [filter_value_type(V) || V <- VList]}; -filter_value_type({T, _} = V) when is_atom(T) -> +filter_value_type({T, _} = V) + when is_atom(T) -> %% looks like an already tagged type, just pass it through V. diff --git a/deps/amqp10_client/test/mock_server.erl b/deps/amqp10_client/test/mock_server.erl index ed3ffea17826..fdcd42e494ac 100644 --- a/deps/amqp10_client/test/mock_server.erl +++ b/deps/amqp10_client/test/mock_server.erl @@ -16,7 +16,7 @@ recv_amqp_header_step/1 ]). --include("src/amqp10_client.hrl"). +-include("src/amqp10_client_internal.hrl"). start(Port) -> {ok, LSock} = gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]), diff --git a/deps/amqp10_common/include/amqp10_filter.hrl b/deps/amqp10_common/include/amqp10_filter.hrl new file mode 100644 index 000000000000..0a08fa82df6b --- /dev/null +++ b/deps/amqp10_common/include/amqp10_filter.hrl @@ -0,0 +1,31 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +%% A filter with this name contains a JMS message selector. +%% We use the same name as sent by the Qpid JMS client in +%% https://github.com/apache/qpid-jms/blob/2.7.0/qpid-jms-client/src/main/java/org/apache/qpid/jms/provider/amqp/AmqpSupport.java#L75 +-define(FILTER_NAME_JMS, <<"jms-selector">>). + +%% A filter with this name contains an SQL expression. +%% In the current version, such a filter must comply with the JMS message selector syntax. +%% However, we use a name other than "jms-selector" in case we want to extend the allowed syntax +%% in the future, for example allowing for some of the extended grammar described in +%% §6 "SQL Filter Expressions" of +%% https://groups.oasis-open.org/higherlogic/ws/public/document?document_id=66227 +-define(FILTER_NAME_SQL, <<"sql-filter">>). + +%% SQL-based filtering syntax +%% These descriptors are defined in +%% https://www.amqp.org/specification/1.0/filters +-define(DESCRIPTOR_NAME_SELECTOR_FILTER, <<"apache.org:selector-filter:string">>). +-define(DESCRIPTOR_CODE_SELECTOR_FILTER, 16#0000468C00000004). + +%% AMQP Filter Expressions Version 1.0 Working Draft 09 +%% https://groups.oasis-open.org/higherlogic/ws/public/document?document_id=66227 +-define(DESCRIPTOR_NAME_PROPERTIES_FILTER, <<"amqp:properties-filter">>). +-define(DESCRIPTOR_CODE_PROPERTIES_FILTER, 16#173). +-define(DESCRIPTOR_NAME_APPLICATION_PROPERTIES_FILTER, <<"amqp:application-properties-filter">>). +-define(DESCRIPTOR_CODE_APPLICATION_PROPERTIES_FILTER, 16#174). diff --git a/deps/amqp10_common/include/amqp10_filtex.hrl b/deps/amqp10_common/include/amqp10_filtex.hrl deleted file mode 100644 index d2c99d2dfa6e..000000000000 --- a/deps/amqp10_common/include/amqp10_filtex.hrl +++ /dev/null @@ -1,15 +0,0 @@ -%% This Source Code Form is subject to the terms of the Mozilla Public -%% License, v. 2.0. If a copy of the MPL was not distributed with this -%% file, You can obtain one at https://mozilla.org/MPL/2.0/. -%% -%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. - - -%% AMQP Filter Expressions Version 1.0 Working Draft 09 -%% https://groups.oasis-open.org/higherlogic/ws/public/document?document_id=66227 - --define(DESCRIPTOR_NAME_PROPERTIES_FILTER, <<"amqp:properties-filter">>). --define(DESCRIPTOR_CODE_PROPERTIES_FILTER, 16#173). - --define(DESCRIPTOR_NAME_APPLICATION_PROPERTIES_FILTER, <<"amqp:application-properties-filter">>). --define(DESCRIPTOR_CODE_APPLICATION_PROPERTIES_FILTER, 16#174). diff --git a/deps/rabbit/Makefile b/deps/rabbit/Makefile index 0a786304751c..7e820c5ba2fb 100644 --- a/deps/rabbit/Makefile +++ b/deps/rabbit/Makefile @@ -258,7 +258,7 @@ define ct_master.erl endef PARALLEL_CT_SET_1_A = unit_rabbit_ssl unit_cluster_formation_locking_mocks unit_cluster_formation_sort_nodes unit_collections unit_config_value_encryption unit_connection_tracking -PARALLEL_CT_SET_1_B = amqp_address amqp_auth amqp_credit_api_v2 amqp_filtex amqp_dotnet amqp_jms signal_handling single_active_consumer unit_access_control_authn_authz_context_propagation unit_access_control_credential_validation unit_amqp091_content_framing unit_amqp091_server_properties unit_app_management +PARALLEL_CT_SET_1_B = amqp_address amqp_auth amqp_credit_api_v2 amqp_filter_prop amqp_filter_sql amqp_jms_unit amqp_dotnet amqp_jms signal_handling single_active_consumer unit_access_control_authn_authz_context_propagation unit_access_control_credential_validation unit_amqp091_content_framing unit_amqp091_server_properties unit_app_management PARALLEL_CT_SET_1_C = amqp_proxy_protocol amqpl_consumer_ack amqpl_direct_reply_to backing_queue bindings rabbit_db_maintenance rabbit_db_msup rabbit_db_policy rabbit_db_queue rabbit_db_topic_exchange rabbit_direct_reply_to_prop cluster_limit cluster_minority term_to_binary_compat_prop topic_permission transactions unicode unit_access_control PARALLEL_CT_SET_1_D = amqqueue_backward_compatibility channel_interceptor channel_operation_timeout classic_queue classic_queue_prop config_schema peer_discovery_dns peer_discovery_tmp_hidden_node per_node_limit per_user_connection_channel_limit @@ -363,6 +363,9 @@ ifdef TRACE_SUPERVISOR2 RMQ_ERLC_OPTS += -DTRACE_SUPERVISOR2=true endif +# https://www.erlang.org/doc/apps/parsetools/leex.html#file/2 +export ERL_COMPILER_OPTIONS := deterministic + # -------------------------------------------------------------------- # Documentation. # -------------------------------------------------------------------- diff --git a/deps/rabbit/src/mc.erl b/deps/rabbit/src/mc.erl index 9dec628b7091..8d753bfae7f2 100644 --- a/deps/rabbit/src/mc.erl +++ b/deps/rabbit/src/mc.erl @@ -45,7 +45,7 @@ -type str() :: atom() | string() | binary(). -type internal_ann_key() :: atom(). -type x_ann_key() :: binary(). %% should begin with x- or ideally x-opt- --type x_ann_value() :: str() | integer() | float() | TaggedValue :: tuple() | [x_ann_value()]. +-type x_ann_value() :: str() | number() | TaggedValue :: tuple() | [x_ann_value()]. -type protocol() :: module(). -type annotations() :: #{internal_ann_key() => term(), x_ann_key() => x_ann_value()}. @@ -76,8 +76,7 @@ -type property_value() :: undefined | string() | binary() | - integer() | - float() | + number() | boolean(). -type tagged_value() :: {uuid, binary()} | {utf8, binary()} | @@ -155,9 +154,9 @@ init(Proto, Data, Anns) -> -spec init(protocol(), term(), annotations(), environment()) -> state(). init(Proto, Data, Anns0, Env) -> {ProtoData, ProtoAnns} = Proto:init(Data), - Anns1 = case map_size(Env) =:= 0 of - true -> Anns0; - false -> Anns0#{env => Env} + Anns1 = case map_size(Env) of + 0 -> Anns0; + _ -> Anns0#{env => Env} end, Anns2 = maps:merge(ProtoAnns, Anns1), Anns = ensure_received_at_timestamp(Anns2), diff --git a/deps/rabbit/src/rabbit_amqp_filter.erl b/deps/rabbit/src/rabbit_amqp_filter.erl new file mode 100644 index 000000000000..e7704f9f8b26 --- /dev/null +++ b/deps/rabbit/src/rabbit_amqp_filter.erl @@ -0,0 +1,24 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +-module(rabbit_amqp_filter). + +-export([eval/2]). + +-type expression() :: undefined | + {property, rabbit_amqp_filter_prop:parsed_expressions()} | + {jms, rabbit_amqp_filter_jms:parsed_expression()}. + +-export_type([expression/0]). + +-spec eval(expression(), mc:state()) -> boolean(). +eval(undefined, _Mc) -> + %% A receiver without filter wants all messages. + true; +eval({property, Expr}, Mc) -> + rabbit_amqp_filter_prop:eval(Expr, Mc); +eval({jms, Expr}, Mc) -> + rabbit_amqp_filter_jms:eval(Expr, Mc). diff --git a/deps/rabbit/src/rabbit_amqp_filter_jms.erl b/deps/rabbit/src/rabbit_amqp_filter_jms.erl new file mode 100644 index 000000000000..c1b85c463646 --- /dev/null +++ b/deps/rabbit/src/rabbit_amqp_filter_jms.erl @@ -0,0 +1,490 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +-module(rabbit_amqp_filter_jms). +-feature(maybe_expr, enable). + +-include_lib("amqp10_common/include/amqp10_filter.hrl"). + +-type parsed_expression() :: {ApplicationProperties :: boolean(), + rabbit_jms_ast:ast()}. + +-export_type([parsed_expression/0]). + +-export([parse/1, + eval/2]). + +-spec parse(tuple()) -> + {ok, parsed_expression()} | error. +parse({described, Descriptor, {utf8, JmsSelector}}) -> + maybe + ok ?= check_descriptor(Descriptor), + {ok, String} ?= jms_selector_to_list(JmsSelector), + {ok, Tokens} ?= tokenize(String, JmsSelector), + {ok, Ast0} ?= parse(Tokens, JmsSelector), + {ok, Ast} ?= transform_ast(Ast0, JmsSelector), + AppProps = has_binary_identifier(Ast), + % rabbit_log:debug( + % "~s:~s~nJmsSelector: ~p~nTokens: ~p~n~Ast0: ~p~n~ast: ~p~nAppProps: ~p", + % [?MODULE, ?FUNCTION_NAME, JmsSelector, Tokens, Ast0, Ast, AppProps]), + {ok, {AppProps, Ast}} + end. + +%% Evaluates a parsed JMS message selector expression. +-spec eval(parsed_expression(), mc:state()) -> boolean(). +eval({ApplicationProperties, Ast}, Msg) -> + State = case ApplicationProperties of + true -> + %% This AST references application-properties. + %% Since we will probably dereference during evaluation, + %% for performance reasons let's parse them here only once. + AppProps = mc:routing_headers(Msg, []), + {AppProps, Msg}; + false -> + Msg + end, + eval0(Ast, State) =:= true. + +%% Literals +eval0({Type, Value}, _Msg) + when Type =:= integer orelse + Type =:= float orelse + Type =:= string orelse + Type =:= boolean -> + Value; + +%% Identifier lookup +eval0({identifier, Key}, State) when is_binary(Key) -> + {AppProps, _Msg} = State, + maps:get(Key, AppProps, undefined); +eval0({identifier, FieldName}, State) when is_atom(FieldName) -> + Msg = case mc:is(State) of + true -> + State; + false -> + {_AppProps, Mc} = State, + Mc + end, + get_field_value(FieldName, Msg); + +%% Logical operators +%% +%% Table 3-4 in +%% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#null-values +eval0({'and', Expr1, Expr2}, Msg) -> + case eval0(Expr1, Msg) of + true -> + case eval0(Expr2, Msg) of + true -> true; + false -> false; + _Unknown -> undefined + end; + false -> + % Short-circuit + false; + _Unknown -> + case eval0(Expr2, Msg) of + false -> false; + _ -> undefined + end + end; +%% Table 3-5 in +%% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#null-values +eval0({'or', Expr1, Expr2}, Msg) -> + case eval0(Expr1, Msg) of + true -> + %% Short-circuit + true; + false -> + case eval0(Expr2, Msg) of + true -> true; + false -> false; + _Unknown -> undefined + end; + _Unknown -> + case eval0(Expr2, Msg) of + true -> true; + _ -> undefined + end + end; +%% Table 3-6 in +%% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#null-values +eval0({'not', Expr}, Msg) -> + case eval0(Expr, Msg) of + true -> false; + false -> true; + _Unknown -> undefined + end; + +%% Comparison operators +eval0({'=' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'<>' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'>' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'<' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'>=' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'<=' = Op, Expr1, Expr2}, Msg) -> + compare(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); + +%% Arithmetic operators +eval0({'+' = Op, Expr1, Expr2}, Msg) -> + arithmetic(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'-' = Op, Expr1, Expr2}, Msg) -> + arithmetic(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'*' = Op, Expr1, Expr2}, Msg) -> + arithmetic(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); +eval0({'/' = Op, Expr1, Expr2}, Msg) -> + arithmetic(Op, eval0(Expr1, Msg), eval0(Expr2, Msg)); + +%% Unary operators +eval0({unary_plus, Expr}, Msg) -> + Val = eval0(Expr, Msg), + case is_number(Val) of + true -> Val; + false -> undefined + end; +eval0({unary_minus, Expr}, Msg) -> + Val = eval0(Expr, Msg), + case is_number(Val) of + true -> -Val; + false -> undefined + end; + +%% Special operators +eval0({'between', Expr, From, To}, Msg) -> + Value = eval0(Expr, Msg), + FromVal = eval0(From, Msg), + ToVal = eval0(To, Msg), + between(Value, FromVal, ToVal); + +eval0({'not_between', Expr, From, To}, Msg) -> + case eval0({'between', Expr, From, To}, Msg) of + true -> false; + false -> true; + _ -> undefined + end; + +eval0({'in', Expr, ValueList}, Msg) -> + Value = eval0(Expr, Msg), + is_in(Value, ValueList); + +eval0({'not_in', Expr, ValueList}, Msg) -> + case eval0({'in', Expr, ValueList}, Msg) of + true -> false; + false -> true; + _ -> undefined + end; + +eval0({'is_null', Expr}, Msg) -> + eval0(Expr, Msg) =:= undefined; + +eval0({'is_not_null', Expr}, Msg) -> + eval0(Expr, Msg) =/= undefined; + +eval0({'like', Expr, {pattern, Pattern}}, Msg) -> + Subject = eval0(Expr, Msg), + case is_binary(Subject) of + true -> like(Subject, Pattern); + false -> undefined + end; + +eval0({'not_like', Expr, Pattern}, Msg) -> + case eval0({'like', Expr, Pattern}, Msg) of + true -> false; + false -> true; + _ -> undefined + end. + +%% Helper functions + +%% "Comparison or arithmetic with an unknown value always yields an unknown value." +compare(_, undefined, _) -> + undefined; +compare(_, _, undefined) -> + undefined; +%% "Only like type values can be compared. +%% One exception is that it is valid to compare exact numeric values and approximate numeric values. +%% String and Boolean comparison is restricted to = and <>." +compare('=', Left, Right) -> + Left == Right; +compare('<>', Left, Right) -> + Left /= Right; +compare('>', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left > Right; +compare('<', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left < Right; +compare('>=', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left >= Right; +compare('<=', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left =< Right; +compare(_, _, _) -> + %% "If the comparison of non-like type values is attempted, + %% the value of the operation is false." + false. + +arithmetic(_, undefined, _) -> + undefined; +arithmetic(_, _, undefined) -> + undefined; +arithmetic('+', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left + Right; +arithmetic('-', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left - Right; +arithmetic('*', Left, Right) when is_number(Left) andalso is_number(Right) -> + Left * Right; +arithmetic('/', Left, Right) when is_number(Left) andalso is_number(Right) andalso Right /= 0 -> + Left / Right; +arithmetic(_, _, _) -> + undefined. + +between(Value, From, To) + when Value =:= undefined orelse + From =:= undefined orelse + To =:= undefined -> + undefined; +between(Value, From, To) + when is_number(Value) andalso + is_number(From) andalso + is_number(To) -> + From =< Value andalso Value =< To; +between(_, _, _) -> + %% BETWEEN requires arithmetic expressions + %% "a string cannot be used in an arithmetic expression" + false. + +is_in(undefined, _) -> + undefined; +is_in(Value, List) -> + lists:member(Value, List). + +like(Subject, {exact, Pattern}) -> + Subject =:= Pattern; +like(Subject, {prefix, PrefixSize, Prefix}) -> + case Subject of + <> -> + true; + _ -> + false + end; +like(Subject, {suffix, SuffixSize, Suffix}) -> + case Subject of + <<_:(byte_size(Subject) - SuffixSize)/binary, Suffix:SuffixSize/binary>> -> + true; + _ -> + false + end; +like(Subject,{{prefix, PrefixSize, _} = Prefix, + {suffix, SuffixSize, _} = Suffix}) -> + byte_size(Subject) >= PrefixSize + SuffixSize andalso + like(Subject, Prefix) andalso + like(Subject, Suffix); +like(Subject, CompiledRe) + when element(1, CompiledRe) =:= re_pattern -> + try re:run(Subject, CompiledRe, [{capture, none}]) of + match -> + true; + _ -> + false + catch error:badarg -> + %% This branch is hit if Subject is not a UTF-8 string. + undefined + end. + +%% defined in both AMQP and JMS +-define(DEFAULT_MSG_PRIORITY, 4). + +get_field_value(priority, Msg) -> + case mc:priority(Msg) of + undefined -> + ?DEFAULT_MSG_PRIORITY; + P -> + P + end; +get_field_value(creation_time, Msg) -> + mc:timestamp(Msg); +get_field_value(Name, Msg) -> + case mc:property(Name, Msg) of + {_Type, Val} -> + Val; + undefined -> + undefined + end. + +check_descriptor({symbol, ?DESCRIPTOR_NAME_SELECTOR_FILTER}) -> + ok; +check_descriptor({ulong, ?DESCRIPTOR_CODE_SELECTOR_FILTER}) -> + ok; +check_descriptor(_) -> + error. + +jms_selector_to_list(JmsSelector) -> + case unicode:characters_to_list(JmsSelector) of + String when is_list(String) -> + {ok, String}; + Error -> + rabbit_log:warning("JMS message selector ~p is not UTF-8: ~p", + [JmsSelector, Error]), + error + end. + +tokenize(String, JmsSelector) -> + case rabbit_jms_selector_lexer:string(String) of + {ok, Tokens, _EndLocation} -> + {ok, Tokens}; + {error, {_Line, _Mod, ErrDescriptor}, _Location} -> + rabbit_log:warning("failed to scan JMS message selector '~ts': ~tp", + [JmsSelector, ErrDescriptor]), + error + end. + +parse(Tokens, JmsSelector) -> + case rabbit_jms_selector_parser:parse(Tokens) of + {error, Reason} -> + rabbit_log:warning("failed to parse JMS message selector '~ts': ~p", + [JmsSelector, Reason]), + error; + Ok -> + Ok + end. + +transform_ast(Ast0, JmsSelector) -> + try rabbit_jms_ast:map( + fun({identifier, Ident}) + when is_binary(Ident) -> + {identifier, rabbit_amqp_util:section_field_name_to_atom(Ident)}; + ({Op, _Ident, _Pattern, _Escape} = Node) + when Op =:= 'like' orelse + Op =:= 'not_like' -> + transform_pattern(Node); + (Node) -> + Node + end, Ast0) of + Ast -> + {ok, Ast} + catch {invalid_pattern, Reason} -> + rabbit_log:warning( + "failed to parse LIKE pattern for JMS message selector ~tp: ~tp", + [JmsSelector, Reason]), + error + end. + +has_binary_identifier(Ast) -> + rabbit_jms_ast:search(fun({identifier, Val}) -> + is_binary(Val); + (_Node) -> + false + end, Ast). + +%% If the Pattern contains no wildcard or a single % wildcard, +%% we will optimise message evaluation by using Erlang pattern matching. +%% Otherwise, we will match with a regex. Even though we compile regexes, +%% they are slower compared to Erlang pattern matching. +transform_pattern({Op, Ident, Pattern, Escape}) -> + Pat = case analyze_pattern(Pattern, Escape) of + regex -> + Re = jms_pattern_to_regex(Pattern, Escape, []), + case re:compile("^" ++ Re ++ "$", [unicode]) of + {ok, CompiledRe} -> + CompiledRe; + {error, Reason} -> + throw({invalid_pattern, Reason}) + end; + NoRegex -> + NoRegex + end, + {Op, Ident, {pattern, Pat}}. + +analyze_pattern(Pattern, Escape) -> + case scan_wildcards(Pattern, Escape) of + {none, Chars} -> + {exact, unicode:characters_to_binary(Chars)}; + {single_percent, Chars, PercentPos} -> + analyze_percent(Chars, PercentPos); + regex -> + regex + end. + +scan_wildcards(Pattern, Escape) -> + scan_wildcards_1(Pattern, Escape, [], -1). + +scan_wildcards_1([], _, Acc, -1) -> + {none, lists:reverse(Acc)}; +scan_wildcards_1([], _, Acc, PctPos) -> + {single_percent, lists:reverse(Acc), PctPos}; +scan_wildcards_1([EscapeChar | Rest], EscapeChar, Acc, PctPos) -> + case Rest of + [] -> + throw({invalid_pattern, invalid_escape_at_end}); + [NextChar | Rest1] -> + scan_wildcards_1(Rest1, EscapeChar, [check_char(NextChar) | Acc], PctPos) + end; +scan_wildcards_1([$_ | _Rest], _, _, _) -> + regex; +scan_wildcards_1([$% | Rest], Escape, Acc, -1) -> + %% This is the 1st % character. + Pos = length(Acc), + scan_wildcards_1(Rest, Escape, Acc, Pos); +scan_wildcards_1([$% | _], _, _, _) -> + %% This is the 2nd % character. + regex; +scan_wildcards_1([Char | Rest], Escape, Acc, PctPos) -> + scan_wildcards_1(Rest, Escape, [check_char(Char) | Acc], PctPos). + +analyze_percent(Chars, 0) -> + %% % at start - suffix match + Bin = unicode:characters_to_binary(Chars), + {suffix, byte_size(Bin), Bin}; +analyze_percent(Chars, Pos) when length(Chars) =:= Pos -> + %% % at end - prefix match + Bin = unicode:characters_to_binary(Chars), + {prefix, byte_size(Bin), Bin}; +analyze_percent(Chars, Pos) -> + %% % in middle - prefix and suffix match + {Prefix, Suffix} = lists:split(Pos, Chars), + PrefixBin = unicode:characters_to_binary(Prefix), + SuffixBin = unicode:characters_to_binary(Suffix), + {{prefix, byte_size(PrefixBin), PrefixBin}, + {suffix, byte_size(SuffixBin), SuffixBin}}. + +jms_pattern_to_regex([], _Escape, Acc) -> + lists:reverse(Acc); +jms_pattern_to_regex([EscapeChar | Rest], EscapeChar, Acc) -> + case Rest of + [] -> + throw({invalid_pattern, invalid_escape_at_end}); + [NextChar | Rest1] -> + jms_pattern_to_regex(Rest1, EscapeChar, escape_regex_char(NextChar) ++ Acc) + end; +jms_pattern_to_regex([$% | Rest], Escape, Acc) -> + %% % matches any sequence of characters (0 or more) + jms_pattern_to_regex(Rest, Escape, [$*, $. | Acc]); +jms_pattern_to_regex([$_ | Rest], Escape, Acc) -> + %% _ matches exactly one character + jms_pattern_to_regex(Rest, Escape, [$. | Acc]); +jms_pattern_to_regex([Char | Rest], Escape, Acc) -> + jms_pattern_to_regex(Rest, Escape, escape_regex_char(Char) ++ Acc). + +%% Escape user provided characters that have special meaning in Erlang regex. +escape_regex_char(Char0) -> + Char = check_char(Char0), + case lists:member(Char, ".\\|()[]{}^$*+?#") of + true -> + [Char, $\\]; + false -> + [Char] + end. + +-define(IS_CONTROL_CHAR(C), C < 32 orelse C =:= 127). + +%% Let's disallow control characters in the user provided pattern. +check_char(C) when ?IS_CONTROL_CHAR(C) -> + throw({invalid_pattern, {prohibited_control_character, C}}); +check_char(C) -> + C. diff --git a/deps/rabbit/src/rabbit_amqp_filtex.erl b/deps/rabbit/src/rabbit_amqp_filter_prop.erl similarity index 63% rename from deps/rabbit/src/rabbit_amqp_filtex.erl rename to deps/rabbit/src/rabbit_amqp_filter_prop.erl index 4ee767cba428..b16a596c245b 100644 --- a/deps/rabbit/src/rabbit_amqp_filtex.erl +++ b/deps/rabbit/src/rabbit_amqp_filter_prop.erl @@ -5,13 +5,14 @@ %% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. %% AMQP Filter Expressions Version 1.0 Working Draft 09 +%% §4: Property Filter Expressions %% https://groups.oasis-open.org/higherlogic/ws/public/document?document_id=66227 --module(rabbit_amqp_filtex). +-module(rabbit_amqp_filter_prop). --include_lib("amqp10_common/include/amqp10_filtex.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). --export([validate/1, - filter/2]). +-export([parse/1, + eval/2]). %% "Impose a limit on the complexity of each filter expression." %% [filtex-v1.0-wd09 7.1] @@ -20,38 +21,38 @@ -type simple_type() :: number() | binary() | atom(). -type affix() :: {suffix, non_neg_integer(), binary()} | {prefix, non_neg_integer(), binary()}. --type filter_expression_value() :: simple_type() | affix(). --type filter_expression() :: {properties, [{FieldName :: atom(), filter_expression_value()}, ...]} | - {application_properties, [{binary(), filter_expression_value()}, ...]}. --type filter_expressions() :: [filter_expression()]. --export_type([filter_expressions/0]). - --spec validate(tuple()) -> - {ok, filter_expression()} | error. -validate({described, Descriptor, {map, KVList}}) +-type parsed_expression_value() :: simple_type() | affix(). +-type parsed_expression() :: {properties, [{FieldName :: atom(), parsed_expression_value()}, ...]} | + {application_properties, [{binary(), parsed_expression_value()}, ...]}. +-type parsed_expressions() :: [parsed_expression()]. +-export_type([parsed_expressions/0]). + +-spec parse(tuple()) -> + {ok, parsed_expression()} | error. +parse({described, Descriptor, {map, KVList}}) when KVList =/= [] andalso length(KVList) =< ?MAX_FILTER_FIELDS -> - try validate0(Descriptor, KVList) + try parse0(Descriptor, KVList) catch throw:{?MODULE, _, _} -> error end; -validate(_) -> +parse(_) -> error. --spec filter(filter_expressions(), mc:state()) -> +-spec eval(parsed_expressions(), mc:state()) -> boolean(). -filter(Filters, Mc) -> +eval(Filters, Mc) -> %% "A message will pass through a filter-set if and only if %% it passes through each of the named filters." [3.5.8] lists:all(fun(Filter) -> - filter0(Filter, Mc) + filter(Filter, Mc) end, Filters). %%%%%%%%%%%%%%%% %%% Internal %%% %%%%%%%%%%%%%%%% -filter0({properties, KVList}, Mc) -> +filter({properties, KVList}, Mc) -> %% "The filter evaluates to true if all properties enclosed in the filter expression %% match the respective properties in the message." %% [filtex-v1.0-wd09 4.2.4] @@ -60,7 +61,7 @@ filter0({properties, KVList}, Mc) -> Val = unwrap(TaggedVal), match_simple_type(RefVal, Val) end, KVList); -filter0({application_properties, KVList}, Mc) -> +filter({application_properties, KVList}, Mc) -> AppProps = mc:routing_headers(Mc, []), %% "The filter evaluates to true if all properties enclosed in the filter expression %% match the respective entries in the application-properties section in the message." @@ -113,56 +114,56 @@ match_simple_type(RefVal, Val) -> %% and the values are equal when treated as a floating-point" RefVal == Val. -validate0(Descriptor, KVList) when +parse0(Descriptor, KVList) when Descriptor =:= {symbol, ?DESCRIPTOR_NAME_PROPERTIES_FILTER} orelse Descriptor =:= {ulong, ?DESCRIPTOR_CODE_PROPERTIES_FILTER} -> - validate_props(KVList, []); -validate0(Descriptor, KVList) when + parse_props(KVList, []); +parse0(Descriptor, KVList) when Descriptor =:= {symbol, ?DESCRIPTOR_NAME_APPLICATION_PROPERTIES_FILTER} orelse Descriptor =:= {ulong, ?DESCRIPTOR_CODE_APPLICATION_PROPERTIES_FILTER} -> - validate_app_props(KVList, []); -validate0(_, _) -> + parse_app_props(KVList, []); +parse0(_, _) -> error. -validate_props([], Acc) -> +parse_props([], Acc) -> {ok, {properties, lists:reverse(Acc)}}; -validate_props([{{symbol, <<"message-id">>}, TaggedVal} | Rest], Acc) -> +parse_props([{{symbol, <<"message-id">>}, TaggedVal} | Rest], Acc) -> case parse_message_id(TaggedVal) of {ok, Val} -> - validate_props(Rest, [{message_id, Val} | Acc]); + parse_props(Rest, [{message_id, Val} | Acc]); error -> error end; -validate_props([{{symbol, <<"user-id">>}, {binary, Val}} | Rest], Acc) -> - validate_props(Rest, [{user_id, Val} | Acc]); -validate_props([{{symbol, <<"to">>}, {utf8, Val}} | Rest], Acc) -> - validate_props(Rest, [{to, parse_string_modifier_prefix(Val)} | Acc]); -validate_props([{{symbol, <<"subject">>}, {utf8, Val}} | Rest], Acc) -> - validate_props(Rest, [{subject, parse_string_modifier_prefix(Val)} | Acc]); -validate_props([{{symbol, <<"reply-to">>}, {utf8, Val}} | Rest], Acc) -> - validate_props(Rest, [{reply_to, parse_string_modifier_prefix(Val)} | Acc]); -validate_props([{{symbol, <<"correlation-id">>}, TaggedVal} | Rest], Acc) -> +parse_props([{{symbol, <<"user-id">>}, {binary, Val}} | Rest], Acc) -> + parse_props(Rest, [{user_id, Val} | Acc]); +parse_props([{{symbol, <<"to">>}, {utf8, Val}} | Rest], Acc) -> + parse_props(Rest, [{to, parse_string_modifier_prefix(Val)} | Acc]); +parse_props([{{symbol, <<"subject">>}, {utf8, Val}} | Rest], Acc) -> + parse_props(Rest, [{subject, parse_string_modifier_prefix(Val)} | Acc]); +parse_props([{{symbol, <<"reply-to">>}, {utf8, Val}} | Rest], Acc) -> + parse_props(Rest, [{reply_to, parse_string_modifier_prefix(Val)} | Acc]); +parse_props([{{symbol, <<"correlation-id">>}, TaggedVal} | Rest], Acc) -> case parse_message_id(TaggedVal) of {ok, Val} -> - validate_props(Rest, [{correlation_id, Val} | Acc]); + parse_props(Rest, [{correlation_id, Val} | Acc]); error -> error end; -validate_props([{{symbol, <<"content-type">>}, {symbol, Val}} | Rest], Acc) -> - validate_props(Rest, [{content_type, Val} | Acc]); -validate_props([{{symbol, <<"content-encoding">>}, {symbol, Val}} | Rest], Acc) -> - validate_props(Rest, [{content_encoding, Val} | Acc]); -validate_props([{{symbol, <<"absolute-expiry-time">>}, {timestamp, Val}} | Rest], Acc) -> - validate_props(Rest, [{absolute_expiry_time, Val} | Acc]); -validate_props([{{symbol, <<"creation-time">>}, {timestamp, Val}} | Rest], Acc) -> - validate_props(Rest, [{creation_time, Val} | Acc]); -validate_props([{{symbol, <<"group-id">>}, {utf8, Val}} | Rest], Acc) -> - validate_props(Rest, [{group_id, parse_string_modifier_prefix(Val)} | Acc]); -validate_props([{{symbol, <<"group-sequence">>}, {uint, Val}} | Rest], Acc) -> - validate_props(Rest, [{group_sequence, Val} | Acc]); -validate_props([{{symbol, <<"reply-to-group-id">>}, {utf8, Val}} | Rest], Acc) -> - validate_props(Rest, [{reply_to_group_id, parse_string_modifier_prefix(Val)} | Acc]); -validate_props(_, _) -> +parse_props([{{symbol, <<"content-type">>}, {symbol, Val}} | Rest], Acc) -> + parse_props(Rest, [{content_type, Val} | Acc]); +parse_props([{{symbol, <<"content-encoding">>}, {symbol, Val}} | Rest], Acc) -> + parse_props(Rest, [{content_encoding, Val} | Acc]); +parse_props([{{symbol, <<"absolute-expiry-time">>}, {timestamp, Val}} | Rest], Acc) -> + parse_props(Rest, [{absolute_expiry_time, Val} | Acc]); +parse_props([{{symbol, <<"creation-time">>}, {timestamp, Val}} | Rest], Acc) -> + parse_props(Rest, [{creation_time, Val} | Acc]); +parse_props([{{symbol, <<"group-id">>}, {utf8, Val}} | Rest], Acc) -> + parse_props(Rest, [{group_id, parse_string_modifier_prefix(Val)} | Acc]); +parse_props([{{symbol, <<"group-sequence">>}, {uint, Val}} | Rest], Acc) -> + parse_props(Rest, [{group_sequence, Val} | Acc]); +parse_props([{{symbol, <<"reply-to-group-id">>}, {utf8, Val}} | Rest], Acc) -> + parse_props(Rest, [{reply_to_group_id, parse_string_modifier_prefix(Val)} | Acc]); +parse_props(_, _) -> error. parse_message_id({ulong, Val}) -> @@ -176,13 +177,13 @@ parse_message_id({utf8, Val}) -> parse_message_id(_) -> error. -validate_app_props([], Acc) -> +parse_app_props([], Acc) -> {ok, {application_properties, lists:reverse(Acc)}}; -validate_app_props([{{utf8, Key}, {utf8, String}} | Rest], Acc) -> - validate_app_props(Rest, [{Key, parse_string_modifier_prefix(String)} | Acc]); -validate_app_props([{{utf8, Key}, TaggedVal} | Rest], Acc) -> - validate_app_props(Rest, [{Key, unwrap(TaggedVal)} | Acc]); -validate_app_props(_, _) -> +parse_app_props([{{utf8, Key}, {utf8, String}} | Rest], Acc) -> + parse_app_props(Rest, [{Key, parse_string_modifier_prefix(String)} | Acc]); +parse_app_props([{{utf8, Key}, TaggedVal} | Rest], Acc) -> + parse_app_props(Rest, [{Key, unwrap(TaggedVal)} | Acc]); +parse_app_props(_, _) -> error. %% [filtex-v1.0-wd09 4.1.1] diff --git a/deps/rabbit/src/rabbit_amqp_session.erl b/deps/rabbit/src/rabbit_amqp_session.erl index caa2024fa1e9..2ef13b82ec31 100644 --- a/deps/rabbit/src/rabbit_amqp_session.erl +++ b/deps/rabbit/src/rabbit_amqp_session.erl @@ -14,6 +14,7 @@ -include_lib("kernel/include/logger.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). -include_lib("amqp10_common/include/amqp10_types.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). -include("rabbit_amqp.hrl"). -include("mc.hrl"). @@ -3187,10 +3188,10 @@ parse_attach_properties({map, KVList}) -> end. parse_filter(undefined) -> - {undefined, [], []}; + {undefined, undefined, []}; parse_filter({map, DesiredKVList}) -> {EffectiveKVList, ConsusumerFilter, ConsumerArgs} = - lists:foldr(fun parse_filters/2, {[], [], []}, DesiredKVList), + lists:foldr(fun parse_filters/2, {[], undefined, []}, DesiredKVList), {{map, EffectiveKVList}, ConsusumerFilter, ConsumerArgs}. parse_filters(Filter = {{symbol, _Key}, {described, {symbol, <<"rabbitmq:stream-offset-spec">>}, Value}}, @@ -3200,7 +3201,9 @@ parse_filters(Filter = {{symbol, _Key}, {described, {symbol, <<"rabbitmq:stream- %% 0.9.1 uses second based timestamps Arg = {<<"x-stream-offset">>, timestamp, Ts div 1000}, {[Filter | EffectiveFilters], ConsumerFilter, [Arg | ConsumerArgs]}; - {utf8, Spec} -> + {Type, Spec} + when Type =:= utf8 orelse + Type =:= symbol -> %% next, last, first and "10m" etc Arg = {<<"x-stream-offset">>, longstr, Spec}, {[Filter | EffectiveFilters], ConsumerFilter, [Arg | ConsumerArgs]}; @@ -3242,19 +3245,44 @@ parse_filters({Symbol = {symbol, <<"rabbitmq:stream-", _/binary>>}, Value}, Acc) false -> Acc end; +parse_filters(Filter = {{symbol, ?FILTER_NAME_SQL}, Value}, + Acc = {EffectiveFilters, ConsumerFilter, ConsumerArgs}) -> + case ConsumerFilter of + undefined -> + case rabbit_amqp_filter_jms:parse(Value) of + {ok, ParsedSql} -> + {[Filter | EffectiveFilters], {jms, ParsedSql}, ConsumerArgs}; + error -> + Acc + end; + _ -> + %% SQL filter expression is mutually exclusive with AMQP property filter expressions. + Acc + end; parse_filters(Filter = {{symbol, _Key}, Value}, Acc = {EffectiveFilters, ConsumerFilter, ConsumerArgs}) -> - case rabbit_amqp_filtex:validate(Value) of - {ok, FilterExpression = {FilterType, _}} -> - case proplists:is_defined(FilterType, ConsumerFilter) of - true -> - %% For now, let's prohibit multiple top level filters of the same type - %% (properties or application-properties). There should be no use case. - %% In future, we can allow multiple times the same top level grouping - %% filter expression type (all/any/not). - Acc; - false -> - {[Filter | EffectiveFilters], [FilterExpression | ConsumerFilter], ConsumerArgs} + case rabbit_amqp_filter_prop:parse(Value) of + {ok, ParsedExpression = {Section, _}} -> + case ConsumerFilter of + undefined -> + {[Filter | EffectiveFilters], + {property, [ParsedExpression]}, + ConsumerArgs}; + {property, ParsedExpressions} -> + case proplists:is_defined(Section, ParsedExpressions) of + true -> + %% Let's prohibit multiple top level filters of the + %% same section (properties or application-properties). + Acc; + false -> + {[Filter | EffectiveFilters], + {property, [ParsedExpression | ParsedExpressions]}, + ConsumerArgs} + end; + {jms, _} -> + %% SQL filter expression is mutually exclusive with + %% AMQP property filter expressions. + Acc end; error -> Acc diff --git a/deps/rabbit/src/rabbit_amqp_util.erl b/deps/rabbit/src/rabbit_amqp_util.erl index d573261a5167..0db0a7b14a26 100644 --- a/deps/rabbit/src/rabbit_amqp_util.erl +++ b/deps/rabbit/src/rabbit_amqp_util.erl @@ -9,7 +9,18 @@ -include("rabbit_amqp.hrl"). -export([protocol_error/3, - capabilities/1]). + capabilities/1, + section_field_name_to_atom/1 + % jms_header_to_amqp_field_name/1 + ]). + +-type field_name() :: durable | priority | + message_id | user_id | to | subject | reply_to | + correlation_id | content_type | content_encoding | + absolute_expiry_time | creation_time | group_id | + group_sequence | reply_to_group_id. + +-export_type([field_name/0]). -spec protocol_error(term(), io:format(), [term()]) -> no_return(). @@ -26,3 +37,43 @@ capabilities([]) -> capabilities(Capabilities) -> Caps = [{symbol, C} || C <- Capabilities], {array, symbol, Caps}. + +-spec section_field_name_to_atom(binary()) -> field_name(). +%% header section +% section_field_name_to_atom(<<"durable">>) -> durable; +section_field_name_to_atom(<<"header.priority">>) -> priority; +%% ttl, first-acquirer, and delivery-count are unsupported +%% because setting a JMS message selector on these fields is invalid. + +%% properties section +section_field_name_to_atom(<<"properties.message-id">>) -> message_id; +section_field_name_to_atom(<<"properties.user-id">>) -> user_id; +section_field_name_to_atom(<<"properties.to">>) -> to; +section_field_name_to_atom(<<"properties.subject">>) -> subject; +section_field_name_to_atom(<<"properties.reply-to">>) -> reply_to; +section_field_name_to_atom(<<"properties.correlation-id">>) -> correlation_id; +section_field_name_to_atom(<<"properties.content-type">>) -> content_type; +section_field_name_to_atom(<<"properties.content-encoding">>) -> content_encoding; +section_field_name_to_atom(<<"properties.absolute-expiry-time">>) -> absolute_expiry_time; +section_field_name_to_atom(<<"properties.creation-time">>) -> creation_time; +section_field_name_to_atom(<<"properties.group-id">>) -> group_id; +section_field_name_to_atom(<<"properties.group-sequence">>) -> group_sequence; +section_field_name_to_atom(<<"properties.reply-to-group-id">>) -> reply_to_group_id; +section_field_name_to_atom(Other) -> Other. + +% -spec jms_header_to_amqp_field_name(binary()) -> field_name() | binary(). +% %% "Message header field references are restricted to +% %% JMSDeliveryMode, JMSPriority, JMSMessageID, JMSTimestamp, JMSCorrelationID, and JMSType." +% %% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#message-selector-syntax +% %% amqp-bindmap-jms-v1.0-wd10 § 3.2.1 JMS Headers +% jms_header_to_amqp_field_name(<<"JMSDeliveryMode">>) -> durable; +% jms_header_to_amqp_field_name(<<"JMSPriority">>) -> priority; +% jms_header_to_amqp_field_name(<<"JMSMessageID">>) -> message_id; +% jms_header_to_amqp_field_name(<<"JMSTimestamp">>) -> creation_time; +% jms_header_to_amqp_field_name(<<"JMSCorrelationID">>) -> correlation_id; +% jms_header_to_amqp_field_name(<<"JMSType">>) -> subject; +% %% amqp-bindmap-jms-v1.0-wd10 § 3.2.2 JMS-defined ’JMSX’ Properties +% jms_header_to_amqp_field_name(<<"JMSXUserID">>) -> user_id; +% jms_header_to_amqp_field_name(<<"JMSXGroupID">>) -> group_id; +% jms_header_to_amqp_field_name(<<"JMSXGroupSeq">>) -> group_sequence; +% jms_header_to_amqp_field_name(Other) -> Other. diff --git a/deps/rabbit/src/rabbit_jms_ast.erl b/deps/rabbit/src/rabbit_jms_ast.erl new file mode 100644 index 000000000000..4e6c15242e43 --- /dev/null +++ b/deps/rabbit/src/rabbit_jms_ast.erl @@ -0,0 +1,111 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +%% Helper functions operating on the Abstract Syntax Tree (AST) +%% as returned by rabbit_jms_selector_parser:parse/1 +-module(rabbit_jms_ast). + +-export([search/2, + map/2]). + +-type ast() :: tuple(). + +-export_type([ast/0]). + +-spec search(fun((term()) -> boolean()), ast()) -> boolean(). +search(Pred, Node) -> + case Pred(Node) of + true -> + true; + false -> + case Node of + {Op, Arg} when is_atom(Op) -> + search(Pred, Arg); + {Op, Arg1, Arg2} when is_atom(Op) -> + search(Pred, Arg1) orelse + search(Pred, Arg2); + {Op, Arg1, Arg2, Arg3} when is_atom(Op) -> + search(Pred, Arg1) orelse + search(Pred, Arg2) orelse + search(Pred, Arg3); + _Other -> + false + end + end. + +-spec map(fun((tuple()) -> tuple()), ast()) -> + ast(). +map(Fun, Ast) when is_function(Fun, 1) -> + map_1(Ast, Fun). + +map_1(Pattern, _Fun) when element(1, Pattern) =:= pattern -> + Pattern; +map_1(Node, Fun) when is_atom(element(1, Node)) -> + map_2(Fun(Node), Fun); +map_1(Other, _Fun) -> + Other. + +map_2({Op, Arg1}, Fun) -> + {Op, map_1(Arg1, Fun)}; +map_2({Op, Arg1, Arg2}, Fun) -> + {Op, map_1(Arg1, Fun), map_1(Arg2, Fun)}; +map_2({Op, Arg1, Arg2, Arg3}, Fun) -> + {Op, map_1(Arg1, Fun), map_1(Arg2, Fun), map_1(Arg3, Fun)}. + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +has_binary_identifier_test() -> + false = has_binary_identifier("TRUE"), + true = has_binary_identifier("user_key_1 <> 'fake'"), + false = has_binary_identifier("properties.subject = 'fake'"), + + false = has_binary_identifier("NOT properties.group-id = 'test'"), + false = has_binary_identifier("properties.group-sequence IS NULL"), + false = has_binary_identifier("properties.group-sequence IS NOT NULL"), + true = has_binary_identifier("NOT user_key = 'test'"), + true = has_binary_identifier("custom_field IS NULL"), + + false = has_binary_identifier("properties.group-id = 'g1' AND header.priority > 5"), + false = has_binary_identifier("properties.group-sequence * 10 < 100"), + false = has_binary_identifier("properties.creation-time >= 12345 OR properties.subject = 'test'"), + true = has_binary_identifier("user_key = 'g1' AND header.priority > 5"), + true = has_binary_identifier("header.priority > 5 and user_key = 'g1'"), + true = has_binary_identifier("custom_metric * 10 < 100"), + true = has_binary_identifier("properties.creation-time >= 12345 OR user_data = 'test'"), + + false = has_binary_identifier("properties.group-sequence BETWEEN 1 AND 10"), + true = has_binary_identifier("user_score BETWEEN 1 AND 10"), + + false = has_binary_identifier("properties.group-id LIKE 'group_%' ESCAPE '!'"), + true = has_binary_identifier("user_tag LIKE 'group_%' ESCAPE '!'"), + + false = has_binary_identifier("properties.group-id IN ('g1', 'g2', 'g3')"), + true = has_binary_identifier("user_category IN ('g1', 'g2', 'g3')"), + + false = has_binary_identifier( + "(properties.group-sequence + 1) * 2 <= 100 AND " ++ + "(properties.group-id LIKE 'prod_%' OR header.priority BETWEEN 5 AND 10)"), + true = has_binary_identifier( + "(properties.group-sequence + 1) * 2 <= 100 AND " ++ + "(user_value LIKE 'prod_%' OR properties.absolute-expiry-time BETWEEN 5 AND 10)"), + ok. + +has_binary_identifier(Selector) -> + {ok, Tokens, _EndLocation} = rabbit_jms_selector_lexer:string(Selector), + {ok, Ast0} = rabbit_jms_selector_parser:parse(Tokens), + Ast = map(fun({identifier, Ident}) when is_binary(Ident) -> + {identifier, rabbit_amqp_util:section_field_name_to_atom(Ident)}; + (Node) -> + Node + end, Ast0), + search(fun({identifier, Val}) -> + is_binary(Val); + (_Node) -> + false + end, Ast). + +-endif. diff --git a/deps/rabbit/src/rabbit_jms_selector_lexer.erl b/deps/rabbit/src/rabbit_jms_selector_lexer.erl new file mode 100644 index 000000000000..a769fb808c8a --- /dev/null +++ b/deps/rabbit/src/rabbit_jms_selector_lexer.erl @@ -0,0 +1,1816 @@ +-file("leexinc.hrl", 0). +%% The source of this file is part of leex distribution, as such it +%% has the same Copyright as the other files in the leex +%% distribution. The Copyright is defined in the accompanying file +%% COPYRIGHT. However, the resultant scanner generated by leex is the +%% property of the creator of the scanner and is not covered by that +%% Copyright. + +-module(rabbit_jms_selector_lexer). + +-export([string/1,string/2,token/2,token/3,tokens/2,tokens/3]). +-export([format_error/1]). + +%% User code. This is placed here to allow extra attributes. +-file("rabbit_jms_selector_lexer.xrl", 70). + +%% "Approximate literals use the Java floating-point literal syntax." +to_float([$. | _] = Chars) -> + %% . Digits [ExponentPart] + "0" ++ Chars; +to_float(Chars) -> + %% Digits . [Digits] [ExponentPart] + case lists:last(Chars) of + $. -> + Chars ++ "0"; + _ -> + Chars1 = string:lowercase(Chars), + Chars2 = string:replace(Chars1, ".e", ".0e"), + lists:flatten(Chars2) + end. + +parse_scientific_notation(Chars) -> + Str = string:lowercase(Chars), + {Before, After0} = lists:splitwith(fun(C) -> C =/= $e end, Str), + [$e | After] = After0, + Base = list_to_integer(Before), + Exp = list_to_integer(After), + Base * math:pow(10, Exp). + +process_string(Chars) -> + %% remove surrounding quotes + Chars1 = lists:sublist(Chars, 2, length(Chars) - 2), + Bin = unicode:characters_to_binary(Chars1), + process_escaped_quotes(Bin). + +process_escaped_quotes(Binary) -> + binary:replace(Binary, <<"''">>, <<"'">>, [global]). + +-file("leexinc.hrl", 14). + +format_error({illegal,S}) -> ["illegal characters ",io_lib:write_string(S)]; +format_error({user,S}) -> S. + +%% string(InChars) -> +%% string(InChars, Loc) -> +%% {ok,Tokens,EndLoc} | {error,ErrorInfo,EndLoc}. +%% Loc is the starting location of the token, while EndLoc is the first not scanned +%% location. Location is either Line or {Line,Column}, depending on the "error_location" option. + +string(Ics) -> + string(Ics,1). +string(Ics,L0) -> + string(Ics, L0, 1, Ics, []). +string(Ics, L0, C0, Tcs, Ts) -> + case do_string(Ics, L0, C0, Tcs, Ts) of + {ok, T, {L,_}} -> {ok, T, L}; + {error, {{EL,_},M,D}, {L,_}} -> + EI = {EL,M,D}, + {error, EI, L} + end. + +do_string([], L, C, [], Ts) -> % No partial tokens! + {ok,yyrev(Ts),{L,C}}; +do_string(Ics0, L0, C0, Tcs, Ts) -> + case yystate(yystate(), Ics0, L0, C0, 0, reject, 0) of + {A,Alen,Ics1,L1,_C1} -> % Accepting end state + C2 = adjust_col(Tcs, Alen, C0), + string_cont(Ics1, L1, C2, yyaction(A, Alen, Tcs, L0, C0), Ts); + {A,Alen,Ics1,L1,_C1,_S1} -> % Accepting transition state + C2 = adjust_col(Tcs, Alen, C0), + string_cont(Ics1, L1, C2, yyaction(A, Alen, Tcs, L0, C0), Ts); + {reject,_Alen,Tlen,_Ics1,_L1,_C1,_S1} -> % After a non-accepting state + {error,{{L0, C0} ,?MODULE,{illegal,yypre(Tcs, Tlen+1)}},{L0, C0}}; + {A,Alen,Tlen,_Ics1,L1, C1,_S1}-> + Tcs1 = yysuf(Tcs, Alen), + L2 = adjust_line(Tlen, Alen, Tcs1, L1), + C2 = adjust_col(Tcs, Alen, C1), + string_cont(Tcs1, L2, C2, yyaction(A, Alen, Tcs, L0,C0), Ts) + end. + +%% string_cont(RestChars, Line, Col, Token, Tokens) +%% Test for and remove the end token wrapper. Push back characters +%% are prepended to RestChars. + +-dialyzer({nowarn_function, string_cont/5}). + +string_cont(Rest, Line, Col, {token,T}, Ts) -> + do_string(Rest, Line, Col, Rest, [T|Ts]); +string_cont(Rest, Line, Col, {token,T,Push}, Ts) -> + NewRest = Push ++ Rest, + do_string(NewRest, Line, Col, NewRest, [T|Ts]); +string_cont(Rest, Line, Col, {end_token,T}, Ts) -> + do_string(Rest, Line, Col, Rest, [T|Ts]); +string_cont(Rest, Line, Col, {end_token,T,Push}, Ts) -> + NewRest = Push ++ Rest, + do_string(NewRest, Line, Col, NewRest, [T|Ts]); +string_cont(Rest, Line, Col, skip_token, Ts) -> + do_string(Rest, Line, Col, Rest, Ts); +string_cont(Rest, Line, Col, {skip_token,Push}, Ts) -> + NewRest = Push ++ Rest, + do_string(NewRest, Line, Col, NewRest, Ts); +string_cont(_Rest, Line, Col, {error,S}, _Ts) -> + {error,{{Line, Col},?MODULE,{user,S}},{Line,Col}}. + +%% token(Continuation, Chars) -> +%% token(Continuation, Chars, Loc) -> +%% {more,Continuation} | {done,ReturnVal,RestChars}. +%% Must be careful when re-entering to append the latest characters to the +%% after characters in an accept. The continuation is: +%% {token,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCol,AccAction,AccLen} + +token(Cont,Chars) -> + token(Cont,Chars,1). +token(Cont, Chars, Line) -> + case do_token(Cont,Chars,Line,1) of + {more, _} = C -> C; + {done, Ret0, R} -> + Ret1 = case Ret0 of + {ok, T, {L,_}} -> {ok, T, L}; + {eof, {L,_}} -> {eof, L}; + {error, {{EL,_},M,D},{L,_}} -> {error, {EL,M,D},L} + end, + {done, Ret1, R} + end. + +do_token([], Chars, Line, Col) -> + token(yystate(), Chars, Line, Col, Chars, 0, Line, Col, reject, 0); +do_token({token,State,Line,Col,Tcs,Tlen,Tline,Tcol,Action,Alen}, Chars, _, _) -> + token(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Action, Alen). + +%% token(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol +%% AcceptAction, AcceptLen) -> +%% {more,Continuation} | {done,ReturnVal,RestChars}. +%% The argument order is chosen to be more efficient. + +token(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of + %% Accepting end state, we have a token. + {A1,Alen1,Ics1,L1,C1} -> + C2 = adjust_col(Tcs, Alen1, C1), + token_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol)); + %% Accepting transition state, can take more chars. + {A1,Alen1,[],L1,C1,S1} -> % Need more chars to check + {more,{token,S1,L1,C1,Tcs,Alen1,Tline,Tcol,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> % Take what we got + C2 = adjust_col(Tcs, Alen1, C1), + token_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol)); + %% After a non-accepting state, maybe reach accept state later. + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % Need more chars to check + {more,{token,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,A1,Alen1}}; + {reject,_Alen1,Tlen1,eof,L1,C1,_S1} -> % No token match + %% Check for partial token which is error. + Ret = if Tlen1 > 0 -> {error,{{Tline,Tcol},?MODULE, + %% Skip eof tail in Tcs. + {illegal,yypre(Tcs, Tlen1)}},{L1,C1}}; + true -> {eof,{L1,C1}} + end, + {done,Ret,eof}; + {reject,_Alen1,Tlen1,Ics1,_L1,_C1,_S1} -> % No token match + Error = {{Tline,Tcol},?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, + {done,{error,Error,{Tline,Tcol}},Ics1}; + {A1,Alen1,Tlen1,_Ics1,L1,_C1,_S1} -> % Use last accept match + Tcs1 = yysuf(Tcs, Alen1), + L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), + C2 = C0 + Alen1, + token_cont(Tcs1, L2, C2, yyaction(A1, Alen1, Tcs, Tline, Tcol)) + end. + +%% token_cont(RestChars, Line, Col, Token) +%% If we have a token or error then return done, else if we have a +%% skip_token then continue. + +-dialyzer({nowarn_function, token_cont/4}). + +token_cont(Rest, Line, Col, {token,T}) -> + {done,{ok,T,{Line,Col}},Rest}; +token_cont(Rest, Line, Col, {token,T,Push}) -> + NewRest = Push ++ Rest, + {done,{ok,T,{Line,Col}},NewRest}; +token_cont(Rest, Line, Col, {end_token,T}) -> + {done,{ok,T,{Line,Col}},Rest}; +token_cont(Rest, Line, Col, {end_token,T,Push}) -> + NewRest = Push ++ Rest, + {done,{ok,T,{Line,Col}},NewRest}; +token_cont(Rest, Line, Col, skip_token) -> + token(yystate(), Rest, Line, Col, Rest, 0, Line, Col, reject, 0); +token_cont(Rest, Line, Col, {skip_token,Push}) -> + NewRest = Push ++ Rest, + token(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, reject, 0); +token_cont(Rest, Line, Col, {error,S}) -> + {done,{error,{{Line, Col},?MODULE,{user,S}},{Line, Col}},Rest}. + +%% tokens(Continuation, Chars) -> +%% tokens(Continuation, Chars, Loc) -> +%% {more,Continuation} | {done,ReturnVal,RestChars}. +%% Must be careful when re-entering to append the latest characters to the +%% after characters in an accept. The continuation is: +%% {tokens,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCur,Tokens,AccAction,AccLen} +%% {skip_tokens,State,CurrLine,CurrCol,TokenChars,TokenLen,TokenLine,TokenCur,Error,AccAction,AccLen} + +tokens(Cont,Chars) -> + tokens(Cont,Chars,1). +tokens(Cont, Chars, Line) -> + case do_tokens(Cont,Chars,Line,1) of + {more, _} = C -> C; + {done, Ret0, R} -> + Ret1 = case Ret0 of + {ok, T, {L,_}} -> {ok, T, L}; + {eof, {L,_}} -> {eof, L}; + {error, {{EL,_},M,D},{L,_}} -> {error, {EL,M,D},L} + end, + {done, Ret1, R} + end. + +do_tokens([], Chars, Line, Col) -> + tokens(yystate(), Chars, Line, Col, Chars, 0, Line, Col, [], reject, 0); +do_tokens({tokens,State,Line,Col,Tcs,Tlen,Tline,Tcol,Ts,Action,Alen}, Chars, _,_) -> + tokens(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Ts, Action, Alen); +do_tokens({skip_tokens,State,Line, Col, Tcs,Tlen,Tline,Tcol,Error,Action,Alen}, Chars, _,_) -> + skip_tokens(State, Chars, Line, Col, Tcs ++ Chars, Tlen, Tline, Tcol, Error, Action, Alen). + +%% tokens(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol,Tokens, +%% AcceptAction, AcceptLen) -> +%% {more,Continuation} | {done,ReturnVal,RestChars}. + +tokens(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, Ts, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of + %% Accepting end state, we have a token. + {A1,Alen1,Ics1,L1,C1} -> + C2 = adjust_col(Tcs, Alen1, C1), + tokens_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline, Tcol), Ts); + %% Accepting transition state, can take more chars. + {A1,Alen1,[],L1,C1,S1} -> % Need more chars to check + {more,{tokens,S1,L1,C1,Tcs,Alen1,Tline,Tcol,Ts,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> % Take what we got + C2 = adjust_col(Tcs, Alen1, C1), + tokens_cont(Ics1, L1, C2, yyaction(A1, Alen1, Tcs, Tline,Tcol), Ts); + %% After a non-accepting state, maybe reach accept state later. + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % Need more chars to check + {more,{tokens,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,Ts,A1,Alen1}}; + {reject,_Alen1,Tlen1,eof,L1,C1,_S1} -> % No token match + %% Check for partial token which is error, no need to skip here. + Ret = if Tlen1 > 0 -> {error,{{Tline,Tcol},?MODULE, + %% Skip eof tail in Tcs. + {illegal,yypre(Tcs, Tlen1)}},{L1,C1}}; + Ts == [] -> {eof,{L1,C1}}; + true -> {ok,yyrev(Ts),{L1,C1}} + end, + {done,Ret,eof}; + {reject,_Alen1,Tlen1,_Ics1,L1,C1,_S1} -> + %% Skip rest of tokens. + Error = {{L1,C1},?MODULE,{illegal,yypre(Tcs, Tlen1+1)}}, + skip_tokens(yysuf(Tcs, Tlen1+1), L1, C1, Error); + {A1,Alen1,Tlen1,_Ics1,L1,_C1,_S1} -> + Token = yyaction(A1, Alen1, Tcs, Tline,Tcol), + Tcs1 = yysuf(Tcs, Alen1), + L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), + C2 = C0 + Alen1, + tokens_cont(Tcs1, L2, C2, Token, Ts) + end. + +%% tokens_cont(RestChars, Line, Column, Token, Tokens) +%% If we have an end_token or error then return done, else if we have +%% a token then save it and continue, else if we have a skip_token +%% just continue. + +-dialyzer({nowarn_function, tokens_cont/5}). + +tokens_cont(Rest, Line, Col, {token,T}, Ts) -> + tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, [T|Ts], reject, 0); +tokens_cont(Rest, Line, Col, {token,T,Push}, Ts) -> + NewRest = Push ++ Rest, + tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, [T|Ts], reject, 0); +tokens_cont(Rest, Line, Col, {end_token,T}, Ts) -> + {done,{ok,yyrev(Ts, [T]),{Line,Col}},Rest}; +tokens_cont(Rest, Line, Col, {end_token,T,Push}, Ts) -> + NewRest = Push ++ Rest, + {done,{ok,yyrev(Ts, [T]),{Line, Col}},NewRest}; +tokens_cont(Rest, Line, Col, skip_token, Ts) -> + tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Ts, reject, 0); +tokens_cont(Rest, Line, Col, {skip_token,Push}, Ts) -> + NewRest = Push ++ Rest, + tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Ts, reject, 0); +tokens_cont(Rest, Line, Col, {error,S}, _Ts) -> + skip_tokens(Rest, Line, Col, {{Line,Col},?MODULE,{user,S}}). + +%% skip_tokens(InChars, Line, Col, Error) -> {done,{error,Error,{Line,Col}},Ics}. +%% Skip tokens until an end token, junk everything and return the error. + +skip_tokens(Ics, Line, Col, Error) -> + skip_tokens(yystate(), Ics, Line, Col, Ics, 0, Line, Col, Error, reject, 0). + +%% skip_tokens(State, InChars, Line, Col, TokenChars, TokenLen, TokenLine, TokenCol, Tokens, +%% AcceptAction, AcceptLen) -> +%% {more,Continuation} | {done,ReturnVal,RestChars}. + +skip_tokens(S0, Ics0, L0, C0, Tcs, Tlen0, Tline, Tcol, Error, A0, Alen0) -> + case yystate(S0, Ics0, L0, C0, Tlen0, A0, Alen0) of + {A1,Alen1,Ics1,L1, C1} -> % Accepting end state + skip_cont(Ics1, L1, C1, yyaction(A1, Alen1, Tcs, Tline, Tcol), Error); + {A1,Alen1,[],L1,C1, S1} -> % After an accepting state + {more,{skip_tokens,S1,L1,C1,Tcs,Alen1,Tline,Tcol,Error,A1,Alen1}}; + {A1,Alen1,Ics1,L1,C1,_S1} -> + skip_cont(Ics1, L1, C1, yyaction(A1, Alen1, Tcs, Tline, Tcol), Error); + {A1,Alen1,Tlen1,[],L1,C1,S1} -> % After a non-accepting state + {more,{skip_tokens,S1,L1,C1,Tcs,Tlen1,Tline,Tcol,Error,A1,Alen1}}; + {reject,_Alen1,_Tlen1,eof,L1,C1,_S1} -> + {done,{error,Error,{L1,C1}},eof}; + {reject,_Alen1,Tlen1,_Ics1,L1,C1,_S1} -> + skip_tokens(yysuf(Tcs, Tlen1+1), L1, C1,Error); + {A1,Alen1,Tlen1,_Ics1,L1,C1,_S1} -> + Token = yyaction(A1, Alen1, Tcs, Tline, Tcol), + Tcs1 = yysuf(Tcs, Alen1), + L2 = adjust_line(Tlen1, Alen1, Tcs1, L1), + skip_cont(Tcs1, L2, C1, Token, Error) + end. + +%% skip_cont(RestChars, Line, Col, Token, Error) +%% Skip tokens until we have an end_token or error then return done +%% with the original rror. + +-dialyzer({nowarn_function, skip_cont/5}). + +skip_cont(Rest, Line, Col, {token,_T}, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {token,_T,Push}, Error) -> + NewRest = Push ++ Rest, + skip_tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {end_token,_T}, Error) -> + {done,{error,Error,{Line,Col}},Rest}; +skip_cont(Rest, Line, Col, {end_token,_T,Push}, Error) -> + NewRest = Push ++ Rest, + {done,{error,Error,{Line,Col}},NewRest}; +skip_cont(Rest, Line, Col, skip_token, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {skip_token,Push}, Error) -> + NewRest = Push ++ Rest, + skip_tokens(yystate(), NewRest, Line, Col, NewRest, 0, Line, Col, Error, reject, 0); +skip_cont(Rest, Line, Col, {error,_S}, Error) -> + skip_tokens(yystate(), Rest, Line, Col, Rest, 0, Line, Col, Error, reject, 0). + +-compile({nowarn_unused_function, [yyrev/1, yyrev/2, yypre/2, yysuf/2]}). + +yyrev(List) -> lists:reverse(List). +yyrev(List, Tail) -> lists:reverse(List, Tail). +yypre(List, N) -> lists:sublist(List, N). +yysuf(List, N) -> lists:nthtail(N, List). + +%% adjust_line(TokenLength, AcceptLength, Chars, Line) -> NewLine +%% Make sure that newlines in Chars are not counted twice. +%% Line has been updated with respect to newlines in the prefix of +%% Chars consisting of (TokenLength - AcceptLength) characters. + +-compile({nowarn_unused_function, adjust_line/4}). + +adjust_line(N, N, _Cs, L) -> L; +adjust_line(T, A, [$\n|Cs], L) -> + adjust_line(T-1, A, Cs, L-1); +adjust_line(T, A, [_|Cs], L) -> + adjust_line(T-1, A, Cs, L). + +%% adjust_col(Chars, AcceptLength, Col) -> NewCol +%% Handle newlines, tabs and unicode chars. +adjust_col(_, 0, Col) -> + Col; +adjust_col([$\n | R], L, _) -> + adjust_col(R, L-1, 1); +adjust_col([$\t | R], L, Col) -> + adjust_col(R, L-1, tab_forward(Col)+1); +adjust_col([C | R], L, Col) when C>=0 andalso C=< 16#7F -> + adjust_col(R, L-1, Col+1); +adjust_col([C | R], L, Col) when C>= 16#80 andalso C=< 16#7FF -> + adjust_col(R, L-1, Col+2); +adjust_col([C | R], L, Col) when C>= 16#800 andalso C=< 16#FFFF -> + adjust_col(R, L-1, Col+3); +adjust_col([C | R], L, Col) when C>= 16#10000 andalso C=< 16#10FFFF -> + adjust_col(R, L-1, Col+4). + +tab_forward(C) -> + D = C rem tab_size(), + A = tab_size()-D, + C+A. + +tab_size() -> 8. + +%% yystate() -> InitialState. +%% yystate(State, InChars, Line, Col, CurrTokLen, AcceptAction, AcceptLen) -> +%% {Action, AcceptLen, RestChars, Line, Col} | +%% {Action, AcceptLen, RestChars, Line, Col, State} | +%% {reject, AcceptLen, CurrTokLen, RestChars, Line, Col, State} | +%% {Action, AcceptLen, CurrTokLen, RestChars, Line, Col, State}. +%% Generated state transition functions. The non-accepting end state +%% return signal either an unrecognised character or end of current +%% input. + +-file("rabbit_jms_selector_lexer.erl", 371). +yystate() -> 66. + +yystate(69, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(67, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(67, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(69, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,69}; +yystate(68, Ics, Line, Col, Tlen, _, _) -> + {30,Tlen,Ics,Line,Col}; +yystate(67, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(63, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(63, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(67, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,67}; +yystate(66, [116|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(62, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [111|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(46, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [110|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(38, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [109|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [108|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(14, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [106|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [107|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [105|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(1, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [103|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [104|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [102|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(13, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [101|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(33, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [99|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [100|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [98|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(57, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [97|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(55, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [96|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [95|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [84|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(62, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [79|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(46, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [78|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(38, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [77|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [76|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(14, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [74|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [75|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [73|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(1, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [71|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [72|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [70|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(13, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [69|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(33, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [67|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [68|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [66|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(57, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [65|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(55, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [63|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [64|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [62|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(43, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [61|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(35, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [60|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(31, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [58|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [59|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [47|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(12, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [46|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(16, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [45|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(24, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [44|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(28, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [43|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(32, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [42|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(36, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [41|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(40, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [40|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(44, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [39|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(48, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [37|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [38|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [36|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [32|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(64, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [12|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(64, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [13|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(64, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [11|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [10|Ics], Line, _, Tlen, Action, Alen) -> + yystate(64, Ics, Line+1, 1, Tlen+1, Action, Alen); +yystate(66, [9|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(64, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 0, C =< 8 -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 14, C =< 31 -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 33, C =< 35 -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 48, C =< 57 -> + yystate(7, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 80, C =< 83 -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 85, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 91, C =< 94 -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 112, C =< 115 -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 117, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 123 -> + yystate(68, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(66, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,66}; +yystate(65, [119|Ics], Line, Col, Tlen, _, _) -> + yystate(69, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [87|Ics], Line, Col, Tlen, _, _) -> + yystate(69, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 86 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [C|Ics], Line, Col, Tlen, _, _) when C >= 88, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 118 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, [C|Ics], Line, Col, Tlen, _, _) when C >= 120, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(65, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,65}; +yystate(64, [32|Ics], Line, Col, Tlen, _, _) -> + yystate(64, Ics, Line, Col, Tlen+1, 0, Tlen); +yystate(64, [12|Ics], Line, Col, Tlen, _, _) -> + yystate(64, Ics, Line, Col, Tlen+1, 0, Tlen); +yystate(64, [13|Ics], Line, Col, Tlen, _, _) -> + yystate(64, Ics, Line, Col, Tlen+1, 0, Tlen); +yystate(64, [9|Ics], Line, Col, Tlen, _, _) -> + yystate(64, Ics, Line, Col, Tlen+1, 0, Tlen); +yystate(64, [10|Ics], Line, _, Tlen, _, _) -> + yystate(64, Ics, Line+1, 1, Tlen+1, 0, Tlen); +yystate(64, Ics, Line, Col, Tlen, _, _) -> + {0,Tlen,Ics,Line,Col,64}; +yystate(63, [110|Ics], Line, Col, Tlen, _, _) -> + yystate(59, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [78|Ics], Line, Col, Tlen, _, _) -> + yystate(59, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 77 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [C|Ics], Line, Col, Tlen, _, _) when C >= 79, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 109 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, [C|Ics], Line, Col, Tlen, _, _) when C >= 111, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(63, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,63}; +yystate(62, [114|Ics], Line, Col, Tlen, _, _) -> + yystate(58, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [82|Ics], Line, Col, Tlen, _, _) -> + yystate(58, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 81 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [C|Ics], Line, Col, Tlen, _, _) when C >= 83, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 113 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, [C|Ics], Line, Col, Tlen, _, _) when C >= 115, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(62, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,62}; +yystate(61, [116|Ics], Line, Col, Tlen, _, _) -> + yystate(65, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [84|Ics], Line, Col, Tlen, _, _) -> + yystate(65, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 83 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [C|Ics], Line, Col, Tlen, _, _) when C >= 85, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 115 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, [C|Ics], Line, Col, Tlen, _, _) when C >= 117, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(61, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,61}; +yystate(60, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(60, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,60}; +yystate(59, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 4, Tlen); +yystate(59, Ics, Line, Col, Tlen, _, _) -> + {4,Tlen,Ics,Line,Col,59}; +yystate(58, [117|Ics], Line, Col, Tlen, _, _) -> + yystate(54, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [85|Ics], Line, Col, Tlen, _, _) -> + yystate(54, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 84 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [C|Ics], Line, Col, Tlen, _, _) when C >= 86, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 116 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, [C|Ics], Line, Col, Tlen, _, _) when C >= 118, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(58, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,58}; +yystate(57, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(61, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(61, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(57, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,57}; +yystate(56, [39|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(52, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(56, [10|Ics], Line, _, Tlen, Action, Alen) -> + yystate(56, Ics, Line+1, 1, Tlen+1, Action, Alen); +yystate(56, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 0, C =< 9 -> + yystate(56, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(56, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 11, C =< 38 -> + yystate(56, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(56, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 40 -> + yystate(56, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(56, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,56}; +yystate(55, [110|Ics], Line, Col, Tlen, _, _) -> + yystate(51, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [78|Ics], Line, Col, Tlen, _, _) -> + yystate(51, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 77 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [C|Ics], Line, Col, Tlen, _, _) when C >= 79, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 109 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, [C|Ics], Line, Col, Tlen, _, _) when C >= 111, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(55, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,55}; +yystate(54, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(50, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(50, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(54, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,54}; +yystate(53, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 9, Tlen); +yystate(53, Ics, Line, Col, Tlen, _, _) -> + {9,Tlen,Ics,Line,Col,53}; +yystate(52, [39|Ics], Line, Col, Tlen, _, _) -> + yystate(56, Ics, Line, Col, Tlen+1, 28, Tlen); +yystate(52, Ics, Line, Col, Tlen, _, _) -> + {28,Tlen,Ics,Line,Col,52}; +yystate(51, [100|Ics], Line, Col, Tlen, _, _) -> + yystate(47, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [68|Ics], Line, Col, Tlen, _, _) -> + yystate(47, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 67 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [C|Ics], Line, Col, Tlen, _, _) when C >= 69, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 99 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, [C|Ics], Line, Col, Tlen, _, _) when C >= 101, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(51, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,51}; +yystate(50, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 10, Tlen); +yystate(50, Ics, Line, Col, Tlen, _, _) -> + {10,Tlen,Ics,Line,Col,50}; +yystate(49, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(53, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(53, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(49, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,49}; +yystate(48, [39|Ics], Line, Col, Tlen, _, _) -> + yystate(52, Ics, Line, Col, Tlen+1, 30, Tlen); +yystate(48, [10|Ics], Line, _, Tlen, _, _) -> + yystate(56, Ics, Line+1, 1, Tlen+1, 30, Tlen); +yystate(48, [C|Ics], Line, Col, Tlen, _, _) when C >= 0, C =< 9 -> + yystate(56, Ics, Line, Col, Tlen+1, 30, Tlen); +yystate(48, [C|Ics], Line, Col, Tlen, _, _) when C >= 11, C =< 38 -> + yystate(56, Ics, Line, Col, Tlen+1, 30, Tlen); +yystate(48, [C|Ics], Line, Col, Tlen, _, _) when C >= 40 -> + yystate(56, Ics, Line, Col, Tlen+1, 30, Tlen); +yystate(48, Ics, Line, Col, Tlen, _, _) -> + {30,Tlen,Ics,Line,Col,48}; +yystate(47, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 1, Tlen); +yystate(47, Ics, Line, Col, Tlen, _, _) -> + {1,Tlen,Ics,Line,Col,47}; +yystate(46, [114|Ics], Line, Col, Tlen, _, _) -> + yystate(42, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [82|Ics], Line, Col, Tlen, _, _) -> + yystate(42, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 81 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [C|Ics], Line, Col, Tlen, _, _) when C >= 83, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 113 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, [C|Ics], Line, Col, Tlen, _, _) when C >= 115, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(46, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,46}; +yystate(45, [112|Ics], Line, Col, Tlen, _, _) -> + yystate(49, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [80|Ics], Line, Col, Tlen, _, _) -> + yystate(49, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 79 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [C|Ics], Line, Col, Tlen, _, _) when C >= 81, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 111 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, [C|Ics], Line, Col, Tlen, _, _) when C >= 113, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(45, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,45}; +yystate(44, Ics, Line, Col, Tlen, _, _) -> + {22,Tlen,Ics,Line,Col}; +yystate(43, [61|Ics], Line, Col, Tlen, _, _) -> + yystate(39, Ics, Line, Col, Tlen+1, 16, Tlen); +yystate(43, Ics, Line, Col, Tlen, _, _) -> + {16,Tlen,Ics,Line,Col,43}; +yystate(42, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 2, Tlen); +yystate(42, Ics, Line, Col, Tlen, _, _) -> + {2,Tlen,Ics,Line,Col,42}; +yystate(41, [97|Ics], Line, Col, Tlen, _, _) -> + yystate(45, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [65|Ics], Line, Col, Tlen, _, _) -> + yystate(45, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [C|Ics], Line, Col, Tlen, _, _) when C >= 66, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, [C|Ics], Line, Col, Tlen, _, _) when C >= 98, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(41, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,41}; +yystate(40, Ics, Line, Col, Tlen, _, _) -> + {23,Tlen,Ics,Line,Col}; +yystate(39, Ics, Line, Col, Tlen, _, _) -> + {14,Tlen,Ics,Line,Col}; +yystate(38, [117|Ics], Line, Col, Tlen, _, _) -> + yystate(34, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [111|Ics], Line, Col, Tlen, _, _) -> + yystate(22, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [85|Ics], Line, Col, Tlen, _, _) -> + yystate(34, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [79|Ics], Line, Col, Tlen, _, _) -> + yystate(22, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 78 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 80, C =< 84 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 86, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 110 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 112, C =< 116 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, [C|Ics], Line, Col, Tlen, _, _) when C >= 118, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(38, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,38}; +yystate(37, [99|Ics], Line, Col, Tlen, _, _) -> + yystate(41, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [97|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [98|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [67|Ics], Line, Col, Tlen, _, _) -> + yystate(41, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [65|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [66|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [C|Ics], Line, Col, Tlen, _, _) when C >= 68, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, [C|Ics], Line, Col, Tlen, _, _) when C >= 100, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(37, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,37}; +yystate(36, Ics, Line, Col, Tlen, _, _) -> + {20,Tlen,Ics,Line,Col}; +yystate(35, Ics, Line, Col, Tlen, _, _) -> + {12,Tlen,Ics,Line,Col}; +yystate(34, [108|Ics], Line, Col, Tlen, _, _) -> + yystate(30, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [76|Ics], Line, Col, Tlen, _, _) -> + yystate(30, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 75 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [C|Ics], Line, Col, Tlen, _, _) when C >= 77, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 107 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, [C|Ics], Line, Col, Tlen, _, _) when C >= 109, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(34, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,34}; +yystate(33, [115|Ics], Line, Col, Tlen, _, _) -> + yystate(37, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [83|Ics], Line, Col, Tlen, _, _) -> + yystate(37, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 82 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [C|Ics], Line, Col, Tlen, _, _) when C >= 84, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 114 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, [C|Ics], Line, Col, Tlen, _, _) when C >= 116, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(33, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,33}; +yystate(32, Ics, Line, Col, Tlen, _, _) -> + {18,Tlen,Ics,Line,Col}; +yystate(31, [62|Ics], Line, Col, Tlen, _, _) -> + yystate(27, Ics, Line, Col, Tlen+1, 17, Tlen); +yystate(31, [61|Ics], Line, Col, Tlen, _, _) -> + yystate(23, Ics, Line, Col, Tlen+1, 17, Tlen); +yystate(31, Ics, Line, Col, Tlen, _, _) -> + {17,Tlen,Ics,Line,Col,31}; +yystate(30, [108|Ics], Line, Col, Tlen, _, _) -> + yystate(26, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [76|Ics], Line, Col, Tlen, _, _) -> + yystate(26, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 75 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [C|Ics], Line, Col, Tlen, _, _) when C >= 77, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 107 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, [C|Ics], Line, Col, Tlen, _, _) when C >= 109, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(30, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,30}; +yystate(29, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 11, Tlen); +yystate(29, Ics, Line, Col, Tlen, _, _) -> + {11,Tlen,Ics,Line,Col,29}; +yystate(28, Ics, Line, Col, Tlen, _, _) -> + {24,Tlen,Ics,Line,Col}; +yystate(27, Ics, Line, Col, Tlen, _, _) -> + {13,Tlen,Ics,Line,Col}; +yystate(26, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 8, Tlen); +yystate(26, Ics, Line, Col, Tlen, _, _) -> + {8,Tlen,Ics,Line,Col,26}; +yystate(25, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(29, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(29, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(25, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,25}; +yystate(24, Ics, Line, Col, Tlen, _, _) -> + {19,Tlen,Ics,Line,Col}; +yystate(23, Ics, Line, Col, Tlen, _, _) -> + {15,Tlen,Ics,Line,Col}; +yystate(22, [116|Ics], Line, Col, Tlen, _, _) -> + yystate(18, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [84|Ics], Line, Col, Tlen, _, _) -> + yystate(18, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 83 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [C|Ics], Line, Col, Tlen, _, _) when C >= 85, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 115 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, [C|Ics], Line, Col, Tlen, _, _) when C >= 117, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(22, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,22}; +yystate(21, [115|Ics], Line, Col, Tlen, _, _) -> + yystate(25, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [83|Ics], Line, Col, Tlen, _, _) -> + yystate(25, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 82 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [C|Ics], Line, Col, Tlen, _, _) when C >= 84, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 114 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, [C|Ics], Line, Col, Tlen, _, _) when C >= 116, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(21, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,21}; +yystate(20, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(3, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(20, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(3, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(20, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(20, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(20, Ics, Line, Col, Tlen, _, _) -> + {26,Tlen,Ics,Line,Col,20}; +yystate(19, [45|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(11, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(19, [43|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(11, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(19, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 48, C =< 57 -> + yystate(15, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(19, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,19}; +yystate(18, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 3, Tlen); +yystate(18, Ics, Line, Col, Tlen, _, _) -> + {3,Tlen,Ics,Line,Col,18}; +yystate(17, [108|Ics], Line, Col, Tlen, _, _) -> + yystate(21, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [76|Ics], Line, Col, Tlen, _, _) -> + yystate(21, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 75 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [C|Ics], Line, Col, Tlen, _, _) when C >= 77, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 107 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, [C|Ics], Line, Col, Tlen, _, _) when C >= 109, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(17, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,17}; +yystate(16, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(20, Ics, Line, Col, Tlen+1, 30, Tlen); +yystate(16, Ics, Line, Col, Tlen, _, _) -> + {30,Tlen,Ics,Line,Col,16}; +yystate(15, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(15, Ics, Line, Col, Tlen+1, 27, Tlen); +yystate(15, Ics, Line, Col, Tlen, _, _) -> + {27,Tlen,Ics,Line,Col,15}; +yystate(14, [105|Ics], Line, Col, Tlen, _, _) -> + yystate(10, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [73|Ics], Line, Col, Tlen, _, _) -> + yystate(10, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 72 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [C|Ics], Line, Col, Tlen, _, _) when C >= 74, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 104 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, [C|Ics], Line, Col, Tlen, _, _) when C >= 106, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(14, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,14}; +yystate(13, [97|Ics], Line, Col, Tlen, _, _) -> + yystate(17, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [65|Ics], Line, Col, Tlen, _, _) -> + yystate(17, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [C|Ics], Line, Col, Tlen, _, _) when C >= 66, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, [C|Ics], Line, Col, Tlen, _, _) when C >= 98, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(13, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,13}; +yystate(12, Ics, Line, Col, Tlen, _, _) -> + {21,Tlen,Ics,Line,Col}; +yystate(11, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 48, C =< 57 -> + yystate(15, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(11, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,11}; +yystate(10, [107|Ics], Line, Col, Tlen, _, _) -> + yystate(6, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [75|Ics], Line, Col, Tlen, _, _) -> + yystate(6, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 74 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [C|Ics], Line, Col, Tlen, _, _) when C >= 76, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 106 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, [C|Ics], Line, Col, Tlen, _, _) when C >= 108, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(10, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,10}; +yystate(9, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 6, Tlen); +yystate(9, Ics, Line, Col, Tlen, _, _) -> + {6,Tlen,Ics,Line,Col,9}; +yystate(8, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(3, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(8, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(3, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(8, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(8, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(8, Ics, Line, Col, Tlen, _, _) -> + {26,Tlen,Ics,Line,Col,8}; +yystate(7, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(19, Ics, Line, Col, Tlen+1, 25, Tlen); +yystate(7, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(19, Ics, Line, Col, Tlen+1, 25, Tlen); +yystate(7, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(8, Ics, Line, Col, Tlen+1, 25, Tlen); +yystate(7, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(7, Ics, Line, Col, Tlen+1, 25, Tlen); +yystate(7, Ics, Line, Col, Tlen, _, _) -> + {25,Tlen,Ics,Line,Col,7}; +yystate(6, [101|Ics], Line, Col, Tlen, _, _) -> + yystate(2, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [69|Ics], Line, Col, Tlen, _, _) -> + yystate(2, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 68 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [C|Ics], Line, Col, Tlen, _, _) when C >= 70, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 100 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, [C|Ics], Line, Col, Tlen, _, _) when C >= 102, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(6, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,6}; +yystate(5, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 7, Tlen); +yystate(5, Ics, Line, Col, Tlen, _, _) -> + {7,Tlen,Ics,Line,Col,5}; +yystate(4, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 48, C =< 57 -> + yystate(0, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(4, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,4}; +yystate(3, [45|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(4, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(3, [43|Ics], Line, Col, Tlen, Action, Alen) -> + yystate(4, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(3, [C|Ics], Line, Col, Tlen, Action, Alen) when C >= 48, C =< 57 -> + yystate(0, Ics, Line, Col, Tlen+1, Action, Alen); +yystate(3, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,3}; +yystate(2, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 5, Tlen); +yystate(2, Ics, Line, Col, Tlen, _, _) -> + {5,Tlen,Ics,Line,Col,2}; +yystate(1, [115|Ics], Line, Col, Tlen, _, _) -> + yystate(5, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [110|Ics], Line, Col, Tlen, _, _) -> + yystate(9, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [95|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [83|Ics], Line, Col, Tlen, _, _) -> + yystate(5, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [78|Ics], Line, Col, Tlen, _, _) -> + yystate(9, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [45|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [46|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [36|Ics], Line, Col, Tlen, _, _) -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 65, C =< 77 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 79, C =< 82 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 84, C =< 90 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 97, C =< 109 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 111, C =< 114 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, [C|Ics], Line, Col, Tlen, _, _) when C >= 116, C =< 122 -> + yystate(60, Ics, Line, Col, Tlen+1, 29, Tlen); +yystate(1, Ics, Line, Col, Tlen, _, _) -> + {29,Tlen,Ics,Line,Col,1}; +yystate(0, [C|Ics], Line, Col, Tlen, _, _) when C >= 48, C =< 57 -> + yystate(0, Ics, Line, Col, Tlen+1, 26, Tlen); +yystate(0, Ics, Line, Col, Tlen, _, _) -> + {26,Tlen,Ics,Line,Col,0}; +yystate(S, Ics, Line, Col, Tlen, Action, Alen) -> + {Action,Alen,Tlen,Ics,Line,Col,S}. + +%% yyaction(Action, TokenLength, TokenChars, TokenLine, TokenCol) -> +%% {token,Token} | {end_token, Token} | skip_token | {error,String}. +%% Generated action function. + +yyaction(0, _, _, _, _) -> + yyaction_0(); +yyaction(1, _, _, TokenLine, _) -> + yyaction_1(TokenLine); +yyaction(2, _, _, TokenLine, _) -> + yyaction_2(TokenLine); +yyaction(3, _, _, TokenLine, _) -> + yyaction_3(TokenLine); +yyaction(4, _, _, TokenLine, _) -> + yyaction_4(TokenLine); +yyaction(5, _, _, TokenLine, _) -> + yyaction_5(TokenLine); +yyaction(6, _, _, TokenLine, _) -> + yyaction_6(TokenLine); +yyaction(7, _, _, TokenLine, _) -> + yyaction_7(TokenLine); +yyaction(8, _, _, TokenLine, _) -> + yyaction_8(TokenLine); +yyaction(9, _, _, TokenLine, _) -> + yyaction_9(TokenLine); +yyaction(10, _, _, TokenLine, _) -> + yyaction_10(TokenLine); +yyaction(11, _, _, TokenLine, _) -> + yyaction_11(TokenLine); +yyaction(12, _, _, TokenLine, _) -> + yyaction_12(TokenLine); +yyaction(13, _, _, TokenLine, _) -> + yyaction_13(TokenLine); +yyaction(14, _, _, TokenLine, _) -> + yyaction_14(TokenLine); +yyaction(15, _, _, TokenLine, _) -> + yyaction_15(TokenLine); +yyaction(16, _, _, TokenLine, _) -> + yyaction_16(TokenLine); +yyaction(17, _, _, TokenLine, _) -> + yyaction_17(TokenLine); +yyaction(18, _, _, TokenLine, _) -> + yyaction_18(TokenLine); +yyaction(19, _, _, TokenLine, _) -> + yyaction_19(TokenLine); +yyaction(20, _, _, TokenLine, _) -> + yyaction_20(TokenLine); +yyaction(21, _, _, TokenLine, _) -> + yyaction_21(TokenLine); +yyaction(22, _, _, TokenLine, _) -> + yyaction_22(TokenLine); +yyaction(23, _, _, TokenLine, _) -> + yyaction_23(TokenLine); +yyaction(24, _, _, TokenLine, _) -> + yyaction_24(TokenLine); +yyaction(25, TokenLen, YYtcs, TokenLine, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_25(TokenChars, TokenLine); +yyaction(26, TokenLen, YYtcs, TokenLine, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_26(TokenChars, TokenLine); +yyaction(27, TokenLen, YYtcs, TokenLine, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_27(TokenChars, TokenLine); +yyaction(28, TokenLen, YYtcs, TokenLine, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_28(TokenChars, TokenLine); +yyaction(29, TokenLen, YYtcs, TokenLine, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_29(TokenChars, TokenLine); +yyaction(30, TokenLen, YYtcs, _, _) -> + TokenChars = yypre(YYtcs, TokenLen), + yyaction_30(TokenChars); +yyaction(_, _, _, _, _) -> error. + +-compile({inline,yyaction_0/0}). +-file("rabbit_jms_selector_lexer.xrl", 20). +yyaction_0() -> + skip_token . + +-compile({inline,yyaction_1/1}). +-file("rabbit_jms_selector_lexer.xrl", 23). +yyaction_1(TokenLine) -> + { token, { 'AND', TokenLine } } . + +-compile({inline,yyaction_2/1}). +-file("rabbit_jms_selector_lexer.xrl", 24). +yyaction_2(TokenLine) -> + { token, { 'OR', TokenLine } } . + +-compile({inline,yyaction_3/1}). +-file("rabbit_jms_selector_lexer.xrl", 25). +yyaction_3(TokenLine) -> + { token, { 'NOT', TokenLine } } . + +-compile({inline,yyaction_4/1}). +-file("rabbit_jms_selector_lexer.xrl", 28). +yyaction_4(TokenLine) -> + { token, { 'BETWEEN', TokenLine } } . + +-compile({inline,yyaction_5/1}). +-file("rabbit_jms_selector_lexer.xrl", 29). +yyaction_5(TokenLine) -> + { token, { 'LIKE', TokenLine } } . + +-compile({inline,yyaction_6/1}). +-file("rabbit_jms_selector_lexer.xrl", 30). +yyaction_6(TokenLine) -> + { token, { 'IN', TokenLine } } . + +-compile({inline,yyaction_7/1}). +-file("rabbit_jms_selector_lexer.xrl", 31). +yyaction_7(TokenLine) -> + { token, { 'IS', TokenLine } } . + +-compile({inline,yyaction_8/1}). +-file("rabbit_jms_selector_lexer.xrl", 32). +yyaction_8(TokenLine) -> + { token, { 'NULL', TokenLine } } . + +-compile({inline,yyaction_9/1}). +-file("rabbit_jms_selector_lexer.xrl", 33). +yyaction_9(TokenLine) -> + { token, { 'ESCAPE', TokenLine } } . + +-compile({inline,yyaction_10/1}). +-file("rabbit_jms_selector_lexer.xrl", 36). +yyaction_10(TokenLine) -> + { token, { boolean, TokenLine, true } } . + +-compile({inline,yyaction_11/1}). +-file("rabbit_jms_selector_lexer.xrl", 37). +yyaction_11(TokenLine) -> + { token, { boolean, TokenLine, false } } . + +-compile({inline,yyaction_12/1}). +-file("rabbit_jms_selector_lexer.xrl", 40). +yyaction_12(TokenLine) -> + { token, { '=', TokenLine } } . + +-compile({inline,yyaction_13/1}). +-file("rabbit_jms_selector_lexer.xrl", 41). +yyaction_13(TokenLine) -> + { token, { '<>', TokenLine } } . + +-compile({inline,yyaction_14/1}). +-file("rabbit_jms_selector_lexer.xrl", 42). +yyaction_14(TokenLine) -> + { token, { '>=', TokenLine } } . + +-compile({inline,yyaction_15/1}). +-file("rabbit_jms_selector_lexer.xrl", 43). +yyaction_15(TokenLine) -> + { token, { '<=', TokenLine } } . + +-compile({inline,yyaction_16/1}). +-file("rabbit_jms_selector_lexer.xrl", 44). +yyaction_16(TokenLine) -> + { token, { '>', TokenLine } } . + +-compile({inline,yyaction_17/1}). +-file("rabbit_jms_selector_lexer.xrl", 45). +yyaction_17(TokenLine) -> + { token, { '<', TokenLine } } . + +-compile({inline,yyaction_18/1}). +-file("rabbit_jms_selector_lexer.xrl", 48). +yyaction_18(TokenLine) -> + { token, { '+', TokenLine } } . + +-compile({inline,yyaction_19/1}). +-file("rabbit_jms_selector_lexer.xrl", 49). +yyaction_19(TokenLine) -> + { token, { '-', TokenLine } } . + +-compile({inline,yyaction_20/1}). +-file("rabbit_jms_selector_lexer.xrl", 50). +yyaction_20(TokenLine) -> + { token, { '*', TokenLine } } . + +-compile({inline,yyaction_21/1}). +-file("rabbit_jms_selector_lexer.xrl", 51). +yyaction_21(TokenLine) -> + { token, { '/', TokenLine } } . + +-compile({inline,yyaction_22/1}). +-file("rabbit_jms_selector_lexer.xrl", 54). +yyaction_22(TokenLine) -> + { token, { '(', TokenLine } } . + +-compile({inline,yyaction_23/1}). +-file("rabbit_jms_selector_lexer.xrl", 55). +yyaction_23(TokenLine) -> + { token, { ')', TokenLine } } . + +-compile({inline,yyaction_24/1}). +-file("rabbit_jms_selector_lexer.xrl", 56). +yyaction_24(TokenLine) -> + { token, { ',', TokenLine } } . + +-compile({inline,yyaction_25/2}). +-file("rabbit_jms_selector_lexer.xrl", 59). +yyaction_25(TokenChars, TokenLine) -> + { token, { integer, TokenLine, list_to_integer (TokenChars) } } . + +-compile({inline,yyaction_26/2}). +-file("rabbit_jms_selector_lexer.xrl", 60). +yyaction_26(TokenChars, TokenLine) -> + { token, { float, TokenLine, list_to_float (to_float (TokenChars)) } } . + +-compile({inline,yyaction_27/2}). +-file("rabbit_jms_selector_lexer.xrl", 61). +yyaction_27(TokenChars, TokenLine) -> + { token, { float, TokenLine, parse_scientific_notation (TokenChars) } } . + +-compile({inline,yyaction_28/2}). +-file("rabbit_jms_selector_lexer.xrl", 62). +yyaction_28(TokenChars, TokenLine) -> + { token, { string, TokenLine, process_string (TokenChars) } } . + +-compile({inline,yyaction_29/2}). +-file("rabbit_jms_selector_lexer.xrl", 63). +yyaction_29(TokenChars, TokenLine) -> + { token, { identifier, TokenLine, unicode : characters_to_binary (TokenChars) } } . + +-compile({inline,yyaction_30/1}). +-file("rabbit_jms_selector_lexer.xrl", 66). +yyaction_30(TokenChars) -> + { error, { illegal_character, TokenChars } } . +-file("leexinc.hrl", 344). diff --git a/deps/rabbit/src/rabbit_jms_selector_lexer.xrl b/deps/rabbit/src/rabbit_jms_selector_lexer.xrl new file mode 100644 index 000000000000..423a0f2b8d0d --- /dev/null +++ b/deps/rabbit/src/rabbit_jms_selector_lexer.xrl @@ -0,0 +1,102 @@ +%%% This is the definitions file for JMS message selectors: +%%% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#message-selector +%%% +%%% To manually generate the scanner file rabbit_jms_selector_lexer.erl run: +%%% leex:file("rabbit_jms_selector_lexer.xrl", [deterministic]). + +Definitions. +WHITESPACE = [\s\t\f\n\r] +DIGIT = [0-9] +INT = {DIGIT}+ +% Approximate numeric literal with a decimal +FLOAT = ({DIGIT}+\.{DIGIT}*|\.{DIGIT}+)([eE][\+\-]?{INT})? +% Approximate numeric literal in scientific notation without a decimal +EXPONENT = {DIGIT}+[eE][\+\-]?{DIGIT}+ +% We extend the allowed JMS identifier syntax with '.' and '-' even though +% these two characters return false for Character.isJavaIdentifierPart() +% to allow identifiers such as properties.group-id +IDENTIFIER = [a-zA-Z_$][a-zA-Z0-9_$.\-]* +STRING = '([^']|'')*' + +Rules. +{WHITESPACE}+ : skip_token. + +% Logical operators (case insensitive) +[aA][nN][dD] : {token, {'AND', TokenLine}}. +[oO][rR] : {token, {'OR', TokenLine}}. +[nN][oO][tT] : {token, {'NOT', TokenLine}}. + +% Special operators (case insensitive) +[bB][eE][tT][wW][eE][eE][nN] : {token, {'BETWEEN', TokenLine}}. +[lL][iI][kK][eE] : {token, {'LIKE', TokenLine}}. +[iI][nN] : {token, {'IN', TokenLine}}. +[iI][sS] : {token, {'IS', TokenLine}}. +[nN][uU][lL][lL] : {token, {'NULL', TokenLine}}. +[eE][sS][cC][aA][pP][eE] : {token, {'ESCAPE', TokenLine}}. + +% Boolean literals (case insensitive) +[tT][rR][uU][eE] : {token, {boolean, TokenLine, true}}. +[fF][aA][lL][sS][eE] : {token, {boolean, TokenLine, false}}. + +% Comparison operators += : {token, {'=', TokenLine}}. +<> : {token, {'<>', TokenLine}}. +>= : {token, {'>=', TokenLine}}. +<= : {token, {'<=', TokenLine}}. +> : {token, {'>', TokenLine}}. +< : {token, {'<', TokenLine}}. + +% Arithmetic operators +\+ : {token, {'+', TokenLine}}. +- : {token, {'-', TokenLine}}. +\* : {token, {'*', TokenLine}}. +/ : {token, {'/', TokenLine}}. + +% Parentheses and comma +\( : {token, {'(', TokenLine}}. +\) : {token, {')', TokenLine}}. +, : {token, {',', TokenLine}}. + +% Literals +{INT} : {token, {integer, TokenLine, list_to_integer(TokenChars)}}. +{FLOAT} : {token, {float, TokenLine, list_to_float(to_float(TokenChars))}}. +{EXPONENT} : {token, {float, TokenLine, parse_scientific_notation(TokenChars)}}. +{STRING} : {token, {string, TokenLine, process_string(TokenChars)}}. +{IDENTIFIER} : {token, {identifier, TokenLine, unicode:characters_to_binary(TokenChars)}}. + +% Catch any other characters as errors +. : {error, {illegal_character, TokenChars}}. + +Erlang code. + +%% "Approximate literals use the Java floating-point literal syntax." +to_float([$. | _] = Chars) -> + %% . Digits [ExponentPart] + "0" ++ Chars; +to_float(Chars) -> + %% Digits . [Digits] [ExponentPart] + case lists:last(Chars) of + $. -> + Chars ++ "0"; + _ -> + Chars1 = string:lowercase(Chars), + Chars2 = string:replace(Chars1, ".e", ".0e"), + lists:flatten(Chars2) + end. + +parse_scientific_notation(Chars) -> + Str = string:lowercase(Chars), + {Before, After0} = lists:splitwith(fun(C) -> C =/= $e end, Str), + [$e | After] = After0, + Base = list_to_integer(Before), + Exp = list_to_integer(After), + Base * math:pow(10, Exp). + +process_string(Chars) -> + %% remove surrounding quotes + Chars1 = lists:sublist(Chars, 2, length(Chars) - 2), + Bin = unicode:characters_to_binary(Chars1), + process_escaped_quotes(Bin). + +process_escaped_quotes(Binary) -> + binary:replace(Binary, <<"''">>, <<"'">>, [global]). diff --git a/deps/rabbit/src/rabbit_jms_selector_parser.erl b/deps/rabbit/src/rabbit_jms_selector_parser.erl new file mode 100644 index 000000000000..6868f3f61907 --- /dev/null +++ b/deps/rabbit/src/rabbit_jms_selector_parser.erl @@ -0,0 +1,1830 @@ +-file("rabbit_jms_selector_parser.yrl", 0). +-module(rabbit_jms_selector_parser). +-file("rabbit_jms_selector_parser.erl", 3). +-export([parse/1, parse_and_scan/1, format_error/1]). +-file("rabbit_jms_selector_parser.yrl", 122). + +extract_value({_Token, _Line, Value}) -> Value. + +process_like_pattern({string, Line, Value}) -> + case unicode:characters_to_list(Value) of + L when is_list(L) -> + L; + _ -> + return_error(Line, "pattern-value in LIKE must be valid Unicode") + end. + +process_escape_char({string, Line, Value}) -> + case unicode:characters_to_list(Value) of + [SingleChar] -> + SingleChar; + _ -> + return_error(Line, "ESCAPE must be a single-character string literal") + end. + +-file("yeccpre.hrl", 0). +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2024. All Rights Reserved. +%% +%% 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 +%% +%% http://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. +%% +%% %CopyrightEnd% +%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The parser generator will insert appropriate declarations before this line.% + +-type yecc_ret() :: {'error', _} | {'ok', _}. + +-ifdef (YECC_PARSE_DOC). +-doc ?YECC_PARSE_DOC. +-endif. +-spec parse(Tokens :: list()) -> yecc_ret(). +parse(Tokens) -> + yeccpars0(Tokens, {no_func, no_location}, 0, [], []). + +-ifdef (YECC_PARSE_AND_SCAN_DOC). +-doc ?YECC_PARSE_AND_SCAN_DOC. +-endif. +-spec parse_and_scan({function() | {atom(), atom()}, [_]} + | {atom(), atom(), [_]}) -> yecc_ret(). +parse_and_scan({F, A}) -> + yeccpars0([], {{F, A}, no_location}, 0, [], []); +parse_and_scan({M, F, A}) -> + Arity = length(A), + yeccpars0([], {{fun M:F/Arity, A}, no_location}, 0, [], []). + +-ifdef (YECC_FORMAT_ERROR_DOC). +-doc ?YECC_FORMAT_ERROR_DOC. +-endif. +-spec format_error(any()) -> [char() | list()]. +format_error(Message) -> + case io_lib:deep_char_list(Message) of + true -> + Message; + _ -> + io_lib:write(Message) + end. + +%% To be used in grammar files to throw an error message to the parser +%% toplevel. Doesn't have to be exported! +-compile({nowarn_unused_function, return_error/2}). +-spec return_error(erl_anno:location(), any()) -> no_return(). +return_error(Location, Message) -> + throw({error, {Location, ?MODULE, Message}}). + +-define(CODE_VERSION, "1.4"). + +yeccpars0(Tokens, Tzr, State, States, Vstack) -> + try yeccpars1(Tokens, Tzr, State, States, Vstack) + catch + error: Error: Stacktrace -> + try yecc_error_type(Error, Stacktrace) of + Desc -> + erlang:raise(error, {yecc_bug, ?CODE_VERSION, Desc}, + Stacktrace) + catch _:_ -> erlang:raise(error, Error, Stacktrace) + end; + %% Probably thrown from return_error/2: + throw: {error, {_Location, ?MODULE, _M}} = Error -> + Error + end. + +yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs,_} | _]) -> + case atom_to_list(F) of + "yeccgoto_" ++ SymbolL -> + {ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL), + State = case ArityOrArgs of + [S,_,_,_,_,_,_] -> S; + _ -> state_is_unknown + end, + {Symbol, State, missing_in_goto_table} + end. + +yeccpars1([Token | Tokens], Tzr, State, States, Vstack) -> + yeccpars2(State, element(1, Token), States, Vstack, Token, Tokens, Tzr); +yeccpars1([], {{F, A},_Location}, State, States, Vstack) -> + case apply(F, A) of + {ok, Tokens, EndLocation} -> + yeccpars1(Tokens, {{F, A}, EndLocation}, State, States, Vstack); + {eof, EndLocation} -> + yeccpars1([], {no_func, EndLocation}, State, States, Vstack); + {error, Descriptor, _EndLocation} -> + {error, Descriptor} + end; +yeccpars1([], {no_func, no_location}, State, States, Vstack) -> + Line = 999999, + yeccpars2(State, '$end', States, Vstack, yecc_end(Line), [], + {no_func, Line}); +yeccpars1([], {no_func, EndLocation}, State, States, Vstack) -> + yeccpars2(State, '$end', States, Vstack, yecc_end(EndLocation), [], + {no_func, EndLocation}). + +%% yeccpars1/7 is called from generated code. +%% +%% When using the {includefile, Includefile} option, make sure that +%% yeccpars1/7 can be found by parsing the file without following +%% include directives. yecc will otherwise assume that an old +%% yeccpre.hrl is included (one which defines yeccpars1/5). +yeccpars1(State1, State, States, Vstack, Token0, [Token | Tokens], Tzr) -> + yeccpars2(State, element(1, Token), [State1 | States], + [Token0 | Vstack], Token, Tokens, Tzr); +yeccpars1(State1, State, States, Vstack, Token0, [], {{_F,_A}, _Location}=Tzr) -> + yeccpars1([], Tzr, State, [State1 | States], [Token0 | Vstack]); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, no_location}) -> + Location = yecctoken_end_location(Token0), + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Location), [], {no_func, Location}); +yeccpars1(State1, State, States, Vstack, Token0, [], {no_func, Location}) -> + yeccpars2(State, '$end', [State1 | States], [Token0 | Vstack], + yecc_end(Location), [], {no_func, Location}). + +%% For internal use only. +yecc_end(Location) -> + {'$end', Location}. + +yecctoken_end_location(Token) -> + try erl_anno:end_location(element(2, Token)) of + undefined -> yecctoken_location(Token); + Loc -> Loc + catch _:_ -> yecctoken_location(Token) + end. + +-compile({nowarn_unused_function, yeccerror/1}). +yeccerror(Token) -> + Text = yecctoken_to_string(Token), + Location = yecctoken_location(Token), + {error, {Location, ?MODULE, ["syntax error before: ", Text]}}. + +-compile({nowarn_unused_function, yecctoken_to_string/1}). +yecctoken_to_string(Token) -> + try erl_scan:text(Token) of + undefined -> yecctoken2string(Token); + Txt -> Txt + catch _:_ -> yecctoken2string(Token) + end. + +yecctoken_location(Token) -> + try erl_scan:location(Token) + catch _:_ -> element(2, Token) + end. + +-compile({nowarn_unused_function, yecctoken2string/1}). +yecctoken2string(Token) -> + try + yecctoken2string1(Token) + catch + _:_ -> + io_lib:format("~tp", [Token]) + end. + +-compile({nowarn_unused_function, yecctoken2string1/1}). +yecctoken2string1({atom, _, A}) -> io_lib:write_atom(A); +yecctoken2string1({integer,_,N}) -> io_lib:write(N); +yecctoken2string1({float,_,F}) -> io_lib:write(F); +yecctoken2string1({char,_,C}) -> io_lib:write_char(C); +yecctoken2string1({var,_,V}) -> io_lib:format("~s", [V]); +yecctoken2string1({string,_,S}) -> io_lib:write_string(S); +yecctoken2string1({reserved_symbol, _, A}) -> io_lib:write(A); +yecctoken2string1({_Cat, _, Val}) -> io_lib:format("~tp", [Val]); +yecctoken2string1({dot, _}) -> "'.'"; +yecctoken2string1({'$end', _}) -> []; +yecctoken2string1({Other, _}) when is_atom(Other) -> + io_lib:write_atom(Other); +yecctoken2string1(Other) -> + io_lib:format("~tp", [Other]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +-file("rabbit_jms_selector_parser.erl", 213). + +-dialyzer({nowarn_function, yeccpars2/7}). +-compile({nowarn_unused_function, yeccpars2/7}). +yeccpars2(0=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(1=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_1(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(2=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_2(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(3=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_3(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(4=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_4(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(5=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_5(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(6=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_6(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(7=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_7(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(8=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_8(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(9=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_9(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(10=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_10(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(11=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_11(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(12=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_12(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(13=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_13(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(14=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_14(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(15=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(16=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_16(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(17=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_16(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(18=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(19=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_19(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(20=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_20(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(21=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_21(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(22=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_22(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(23=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_23(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(24=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_24(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(25=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(26=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(27=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_27(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(28=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_28(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(29=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_29(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(30=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_30(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(31=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_31(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(32=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_32(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(33=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_33(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(34=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(35=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(36=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(37=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(38=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(39=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(40=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(41=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(42=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(43=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_43(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(44=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_44(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(45=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_45(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(46=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(47=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_47(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(48=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_48(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(49=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_49(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(50=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_50(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(51=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_51(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(52=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_52(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(53=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_53(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(54=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_54(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(55=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_55(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(56=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_52(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(57=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_57(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(58=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_58(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(59=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_59(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(60=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(61=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_61(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(62=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_62(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(63=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_63(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(64=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_64(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(65=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_52(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(66=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_66(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(67=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_67(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(68=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_68(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(69=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(70=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_70(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(71=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_71(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(72=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_72(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(73=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_73(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(74=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_74(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(75=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_75(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(76=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_76(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(77=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_77(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(78=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(79=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(80=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_80(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(81=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_81(S, Cat, Ss, Stack, T, Ts, Tzr); +%% yeccpars2(82=S, Cat, Ss, Stack, T, Ts, Tzr) -> +%% yeccpars2_82(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(83=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_83(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(84=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_84(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(85=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_85(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(86=S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_86(S, Cat, Ss, Stack, T, Ts, Tzr); +yeccpars2(Other, _, _, _, _, _, _) -> + erlang:error({yecc_bug,"1.4",{missing_state_in_action_table, Other}}). + +yeccpars2_0(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 16, Ss, Stack, T, Ts, Tzr); +yeccpars2_0(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 17, Ss, Stack, T, Ts, Tzr); +yeccpars2_0(S, 'NOT', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 18, Ss, Stack, T, Ts, Tzr); +yeccpars2_0(S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_16(S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_1/7}). +-compile({nowarn_unused_function, yeccpars2_1/7}). +yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_1_(Stack), + yeccgoto_multiplicative_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_2/7}). +-compile({nowarn_unused_function, yeccpars2_2/7}). +yeccpars2_2(_S, '$end', _Ss, Stack, _T, _Ts, _Tzr) -> + {ok, hd(Stack)}; +yeccpars2_2(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_3/7}). +-compile({nowarn_unused_function, yeccpars2_3/7}). +yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_3_(Stack), + yeccgoto_unary_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_4/7}). +-compile({nowarn_unused_function, yeccpars2_4/7}). +yeccpars2_4(S, '*', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 78, Ss, Stack, T, Ts, Tzr); +yeccpars2_4(S, '/', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 79, Ss, Stack, T, Ts, Tzr); +yeccpars2_4(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_4_(Stack), + yeccgoto_additive_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_5/7}). +-compile({nowarn_unused_function, yeccpars2_5/7}). +yeccpars2_5(S, 'AND', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 25, Ss, Stack, T, Ts, Tzr); +yeccpars2_5(S, 'OR', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 26, Ss, Stack, T, Ts, Tzr); +yeccpars2_5(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_5_(Stack), + yeccgoto_conditional_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_6/7}). +-compile({nowarn_unused_function, yeccpars2_6/7}). +yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_6_(Stack), + yeccgoto_primary(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_7/7}). +-compile({nowarn_unused_function, yeccpars2_7/7}). +yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_7_(Stack), + yeccgoto_comparison_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_8/7}). +-compile({nowarn_unused_function, yeccpars2_8/7}). +yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_8_(Stack), + yeccgoto_comparison_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_9/7}). +-compile({nowarn_unused_function, yeccpars2_9/7}). +yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_9_(Stack), + yeccgoto_comparison_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_10/7}). +-compile({nowarn_unused_function, yeccpars2_10/7}). +yeccpars2_10(S, 'IS', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 83, Ss, Stack, T, Ts, Tzr); +yeccpars2_10(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_10_(Stack), + yeccgoto_primary(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_11/7}). +-compile({nowarn_unused_function, yeccpars2_11/7}). +yeccpars2_11(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_11_(Stack), + yeccgoto_selector(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_12/7}). +-compile({nowarn_unused_function, yeccpars2_12/7}). +yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_12_(Stack), + yeccgoto_logical_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_13/7}). +-compile({nowarn_unused_function, yeccpars2_13/7}). +yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_13_(Stack), + yeccgoto_comparison_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_14/7}). +-compile({nowarn_unused_function, yeccpars2_14/7}). +yeccpars2_14(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '<', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 36, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '<=', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 37, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '<>', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 38, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '=', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 39, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '>', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 40, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, '>=', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 41, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, 'BETWEEN', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 42, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, 'IN', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 43, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, 'LIKE', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 44, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(S, 'NOT', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 45, Ss, Stack, T, Ts, Tzr); +yeccpars2_14(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_14_(Stack), + yeccgoto_comparison_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +%% yeccpars2_15: see yeccpars2_0 + +-dialyzer({nowarn_function, yeccpars2_16/7}). +-compile({nowarn_unused_function, yeccpars2_16/7}). +yeccpars2_16(S, '(', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 15, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(S, 'boolean', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 19, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(S, 'float', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 20, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(S, 'identifier', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 21, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(S, 'integer', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 22, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 23, Ss, Stack, T, Ts, Tzr); +yeccpars2_16(_, _, _, _, T, _, _) -> + yeccerror(T). + +%% yeccpars2_17: see yeccpars2_16 + +%% yeccpars2_18: see yeccpars2_0 + +-dialyzer({nowarn_function, yeccpars2_19/7}). +-compile({nowarn_unused_function, yeccpars2_19/7}). +yeccpars2_19(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_19_(Stack), + yeccgoto_literal(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_20/7}). +-compile({nowarn_unused_function, yeccpars2_20/7}). +yeccpars2_20(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_20_(Stack), + yeccgoto_literal(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_21/7}). +-compile({nowarn_unused_function, yeccpars2_21/7}). +yeccpars2_21(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_21_(Stack), + yeccgoto_identifier_expr(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_22/7}). +-compile({nowarn_unused_function, yeccpars2_22/7}). +yeccpars2_22(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_22_(Stack), + yeccgoto_literal(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_23/7}). +-compile({nowarn_unused_function, yeccpars2_23/7}). +yeccpars2_23(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_23_(Stack), + yeccgoto_literal(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_24/7}). +-compile({nowarn_unused_function, yeccpars2_24/7}). +yeccpars2_24(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_|Nss] = Ss, + NewStack = yeccpars2_24_(Stack), + yeccgoto_logical_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +%% yeccpars2_25: see yeccpars2_0 + +%% yeccpars2_26: see yeccpars2_0 + +-dialyzer({nowarn_function, yeccpars2_27/7}). +-compile({nowarn_unused_function, yeccpars2_27/7}). +yeccpars2_27(S, 'AND', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 25, Ss, Stack, T, Ts, Tzr); +yeccpars2_27(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_27_(Stack), + yeccgoto_logical_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_28/7}). +-compile({nowarn_unused_function, yeccpars2_28/7}). +yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_28_(Stack), + yeccgoto_logical_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_29/7}). +-compile({nowarn_unused_function, yeccpars2_29/7}). +yeccpars2_29(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_|Nss] = Ss, + NewStack = yeccpars2_29_(Stack), + yeccgoto_unary_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_30/7}). +-compile({nowarn_unused_function, yeccpars2_30/7}). +yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_30_(Stack), + yeccgoto_primary(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_31/7}). +-compile({nowarn_unused_function, yeccpars2_31/7}). +yeccpars2_31(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_|Nss] = Ss, + NewStack = yeccpars2_31_(Stack), + yeccgoto_unary_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_32/7}). +-compile({nowarn_unused_function, yeccpars2_32/7}). +yeccpars2_32(S, ')', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 33, Ss, Stack, T, Ts, Tzr); +yeccpars2_32(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_33/7}). +-compile({nowarn_unused_function, yeccpars2_33/7}). +yeccpars2_33(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_33_(Stack), + yeccgoto_primary(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +yeccpars2_34(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 16, Ss, Stack, T, Ts, Tzr); +yeccpars2_34(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 17, Ss, Stack, T, Ts, Tzr); +yeccpars2_34(S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_16(S, Cat, Ss, Stack, T, Ts, Tzr). + +%% yeccpars2_35: see yeccpars2_34 + +%% yeccpars2_36: see yeccpars2_34 + +%% yeccpars2_37: see yeccpars2_34 + +%% yeccpars2_38: see yeccpars2_34 + +%% yeccpars2_39: see yeccpars2_34 + +%% yeccpars2_40: see yeccpars2_34 + +%% yeccpars2_41: see yeccpars2_34 + +%% yeccpars2_42: see yeccpars2_34 + +-dialyzer({nowarn_function, yeccpars2_43/7}). +-compile({nowarn_unused_function, yeccpars2_43/7}). +yeccpars2_43(S, '(', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 65, Ss, Stack, T, Ts, Tzr); +yeccpars2_43(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_44/7}). +-compile({nowarn_unused_function, yeccpars2_44/7}). +yeccpars2_44(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 62, Ss, Stack, T, Ts, Tzr); +yeccpars2_44(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_45/7}). +-compile({nowarn_unused_function, yeccpars2_45/7}). +yeccpars2_45(S, 'BETWEEN', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 46, Ss, Stack, T, Ts, Tzr); +yeccpars2_45(S, 'IN', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 47, Ss, Stack, T, Ts, Tzr); +yeccpars2_45(S, 'LIKE', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 48, Ss, Stack, T, Ts, Tzr); +yeccpars2_45(_, _, _, _, T, _, _) -> + yeccerror(T). + +%% yeccpars2_46: see yeccpars2_34 + +-dialyzer({nowarn_function, yeccpars2_47/7}). +-compile({nowarn_unused_function, yeccpars2_47/7}). +yeccpars2_47(S, '(', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 52, Ss, Stack, T, Ts, Tzr); +yeccpars2_47(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_48/7}). +-compile({nowarn_unused_function, yeccpars2_48/7}). +yeccpars2_48(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 49, Ss, Stack, T, Ts, Tzr); +yeccpars2_48(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_49/7}). +-compile({nowarn_unused_function, yeccpars2_49/7}). +yeccpars2_49(S, 'ESCAPE', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 50, Ss, Stack, T, Ts, Tzr); +yeccpars2_49(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_|Nss] = Ss, + NewStack = yeccpars2_49_(Stack), + yeccgoto_like_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_50/7}). +-compile({nowarn_unused_function, yeccpars2_50/7}). +yeccpars2_50(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 51, Ss, Stack, T, Ts, Tzr); +yeccpars2_50(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_51/7}). +-compile({nowarn_unused_function, yeccpars2_51/7}). +yeccpars2_51(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_51_(Stack), + yeccgoto_like_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_52/7}). +-compile({nowarn_unused_function, yeccpars2_52/7}). +yeccpars2_52(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 55, Ss, Stack, T, Ts, Tzr); +yeccpars2_52(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_53/7}). +-compile({nowarn_unused_function, yeccpars2_53/7}). +yeccpars2_53(S, ')', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 58, Ss, Stack, T, Ts, Tzr); +yeccpars2_53(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_54/7}). +-compile({nowarn_unused_function, yeccpars2_54/7}). +yeccpars2_54(S, ',', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 56, Ss, Stack, T, Ts, Tzr); +yeccpars2_54(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_54_(Stack), + yeccgoto_string_list(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_55/7}). +-compile({nowarn_unused_function, yeccpars2_55/7}). +yeccpars2_55(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + NewStack = yeccpars2_55_(Stack), + yeccgoto_string_item(hd(Ss), Cat, Ss, NewStack, T, Ts, Tzr). + +%% yeccpars2_56: see yeccpars2_52 + +-dialyzer({nowarn_function, yeccpars2_57/7}). +-compile({nowarn_unused_function, yeccpars2_57/7}). +yeccpars2_57(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_57_(Stack), + yeccgoto_string_list(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_58/7}). +-compile({nowarn_unused_function, yeccpars2_58/7}). +yeccpars2_58(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_58_(Stack), + yeccgoto_in_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_59/7}). +-compile({nowarn_unused_function, yeccpars2_59/7}). +yeccpars2_59(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_59(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_59(S, 'AND', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 60, Ss, Stack, T, Ts, Tzr); +yeccpars2_59(_, _, _, _, T, _, _) -> + yeccerror(T). + +%% yeccpars2_60: see yeccpars2_34 + +-dialyzer({nowarn_function, yeccpars2_61/7}). +-compile({nowarn_unused_function, yeccpars2_61/7}). +yeccpars2_61(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_61(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_61(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_61_(Stack), + yeccgoto_between_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_62/7}). +-compile({nowarn_unused_function, yeccpars2_62/7}). +yeccpars2_62(S, 'ESCAPE', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 63, Ss, Stack, T, Ts, Tzr); +yeccpars2_62(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_62_(Stack), + yeccgoto_like_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_63/7}). +-compile({nowarn_unused_function, yeccpars2_63/7}). +yeccpars2_63(S, 'string', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 64, Ss, Stack, T, Ts, Tzr); +yeccpars2_63(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_64/7}). +-compile({nowarn_unused_function, yeccpars2_64/7}). +yeccpars2_64(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_64_(Stack), + yeccgoto_like_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +%% yeccpars2_65: see yeccpars2_52 + +-dialyzer({nowarn_function, yeccpars2_66/7}). +-compile({nowarn_unused_function, yeccpars2_66/7}). +yeccpars2_66(S, ')', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 67, Ss, Stack, T, Ts, Tzr); +yeccpars2_66(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_67/7}). +-compile({nowarn_unused_function, yeccpars2_67/7}). +yeccpars2_67(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_67_(Stack), + yeccgoto_in_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_68/7}). +-compile({nowarn_unused_function, yeccpars2_68/7}). +yeccpars2_68(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_68(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_68(S, 'AND', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 69, Ss, Stack, T, Ts, Tzr); +yeccpars2_68(_, _, _, _, T, _, _) -> + yeccerror(T). + +%% yeccpars2_69: see yeccpars2_34 + +-dialyzer({nowarn_function, yeccpars2_70/7}). +-compile({nowarn_unused_function, yeccpars2_70/7}). +yeccpars2_70(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_70(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_70(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_,_|Nss] = Ss, + NewStack = yeccpars2_70_(Stack), + yeccgoto_between_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_71/7}). +-compile({nowarn_unused_function, yeccpars2_71/7}). +yeccpars2_71(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_71(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_71(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_71_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_72/7}). +-compile({nowarn_unused_function, yeccpars2_72/7}). +yeccpars2_72(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_72(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_72(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_72_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_73/7}). +-compile({nowarn_unused_function, yeccpars2_73/7}). +yeccpars2_73(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_73(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_73(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_73_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_74/7}). +-compile({nowarn_unused_function, yeccpars2_74/7}). +yeccpars2_74(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_74(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_74(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_74_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_75/7}). +-compile({nowarn_unused_function, yeccpars2_75/7}). +yeccpars2_75(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_75(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_75(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_75_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_76/7}). +-compile({nowarn_unused_function, yeccpars2_76/7}). +yeccpars2_76(S, '+', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 34, Ss, Stack, T, Ts, Tzr); +yeccpars2_76(S, '-', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 35, Ss, Stack, T, Ts, Tzr); +yeccpars2_76(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_76_(Stack), + yeccgoto_comparison_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_77/7}). +-compile({nowarn_unused_function, yeccpars2_77/7}). +yeccpars2_77(S, '*', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 78, Ss, Stack, T, Ts, Tzr); +yeccpars2_77(S, '/', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 79, Ss, Stack, T, Ts, Tzr); +yeccpars2_77(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_77_(Stack), + yeccgoto_additive_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +%% yeccpars2_78: see yeccpars2_34 + +%% yeccpars2_79: see yeccpars2_34 + +-dialyzer({nowarn_function, yeccpars2_80/7}). +-compile({nowarn_unused_function, yeccpars2_80/7}). +yeccpars2_80(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_80_(Stack), + yeccgoto_multiplicative_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_81/7}). +-compile({nowarn_unused_function, yeccpars2_81/7}). +yeccpars2_81(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_81_(Stack), + yeccgoto_multiplicative_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_82/7}). +-compile({nowarn_unused_function, yeccpars2_82/7}). +yeccpars2_82(S, '*', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 78, Ss, Stack, T, Ts, Tzr); +yeccpars2_82(S, '/', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 79, Ss, Stack, T, Ts, Tzr); +yeccpars2_82(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_82_(Stack), + yeccgoto_additive_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_83/7}). +-compile({nowarn_unused_function, yeccpars2_83/7}). +yeccpars2_83(S, 'NOT', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 84, Ss, Stack, T, Ts, Tzr); +yeccpars2_83(S, 'NULL', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 85, Ss, Stack, T, Ts, Tzr); +yeccpars2_83(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_84/7}). +-compile({nowarn_unused_function, yeccpars2_84/7}). +yeccpars2_84(S, 'NULL', Ss, Stack, T, Ts, Tzr) -> + yeccpars1(S, 86, Ss, Stack, T, Ts, Tzr); +yeccpars2_84(_, _, _, _, T, _, _) -> + yeccerror(T). + +-dialyzer({nowarn_function, yeccpars2_85/7}). +-compile({nowarn_unused_function, yeccpars2_85/7}). +yeccpars2_85(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_|Nss] = Ss, + NewStack = yeccpars2_85_(Stack), + yeccgoto_is_null_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccpars2_86/7}). +-compile({nowarn_unused_function, yeccpars2_86/7}). +yeccpars2_86(_S, Cat, Ss, Stack, T, Ts, Tzr) -> + [_,_,_|Nss] = Ss, + NewStack = yeccpars2_86_(Stack), + yeccgoto_is_null_expr(hd(Nss), Cat, Nss, NewStack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_additive_expr/7}). +-compile({nowarn_unused_function, yeccgoto_additive_expr/7}). +yeccgoto_additive_expr(0, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(15, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(18, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(25, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(26, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_14(14, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(36, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_76(76, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(37, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_75(75, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(38, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_74(74, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(39, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_73(73, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(40, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_72(72, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(41, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_71(71, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(42, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_68(68, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(46, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_59(59, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(60, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_61(61, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_additive_expr(69, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_70(70, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_between_expr/7}). +-compile({nowarn_unused_function, yeccgoto_between_expr/7}). +yeccgoto_between_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_between_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_between_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_between_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_between_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_13(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_comparison_expr/7}). +-compile({nowarn_unused_function, yeccgoto_comparison_expr/7}). +yeccgoto_comparison_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_comparison_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_comparison_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_comparison_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_comparison_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_12(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_conditional_expr/7}). +-compile({nowarn_unused_function, yeccgoto_conditional_expr/7}). +yeccgoto_conditional_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_11(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_conditional_expr(15, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_32(32, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_identifier_expr/7}). +-compile({nowarn_unused_function, yeccgoto_identifier_expr/7}). +yeccgoto_identifier_expr(0, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_10(10, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(15, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_10(10, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(16=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(17=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(18, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_10(10, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(25, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_10(10, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(26, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_10(10, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(34=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(35=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(36=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(37=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(38=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(39=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(40=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(41=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(42=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(46=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(60=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(69=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(78=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_identifier_expr(79=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_30(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_in_expr/7}). +-compile({nowarn_unused_function, yeccgoto_in_expr/7}). +yeccgoto_in_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_in_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_in_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_in_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_in_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_9(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_is_null_expr/7}). +-compile({nowarn_unused_function, yeccgoto_is_null_expr/7}). +yeccgoto_is_null_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_is_null_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_is_null_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_is_null_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_is_null_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_8(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_like_expr/7}). +-compile({nowarn_unused_function, yeccgoto_like_expr/7}). +yeccgoto_like_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_like_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_like_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_like_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_like_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_7(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_literal/7}). +-compile({nowarn_unused_function, yeccgoto_literal/7}). +yeccgoto_literal(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(16=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(17=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(34=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(35=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(36=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(37=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(38=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(39=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(40=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(41=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(42=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(46=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(60=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(69=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(78=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_literal(79=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_6(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_logical_expr/7}). +-compile({nowarn_unused_function, yeccgoto_logical_expr/7}). +yeccgoto_logical_expr(0, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_5(5, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_logical_expr(15, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_5(5, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_logical_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_24(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_logical_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_28(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_logical_expr(26, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_27(27, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_multiplicative_expr/7}). +-compile({nowarn_unused_function, yeccgoto_multiplicative_expr/7}). +yeccgoto_multiplicative_expr(0, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(15, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(18, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(25, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(26, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(34, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_82(82, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(35, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_77(77, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(36, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(37, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(38, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(39, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(40, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(41, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(42, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(46, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(60, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_multiplicative_expr(69, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_4(4, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_primary/7}). +-compile({nowarn_unused_function, yeccgoto_primary/7}). +yeccgoto_primary(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(16=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_31(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(17=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_29(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(34=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(35=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(36=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(37=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(38=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(39=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(40=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(41=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(42=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(46=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(60=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(69=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(78=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_primary(79=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_3(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_selector/7}). +-compile({nowarn_unused_function, yeccgoto_selector/7}). +yeccgoto_selector(0, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_2(2, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_string_item/7}). +-compile({nowarn_unused_function, yeccgoto_string_item/7}). +yeccgoto_string_item(52, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_54(54, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_string_item(56, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_54(54, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_string_item(65, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_54(54, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_string_list/7}). +-compile({nowarn_unused_function, yeccgoto_string_list/7}). +yeccgoto_string_list(52, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_53(53, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_string_list(56=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_57(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_string_list(65, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_66(66, Cat, Ss, Stack, T, Ts, Tzr). + +-dialyzer({nowarn_function, yeccgoto_unary_expr/7}). +-compile({nowarn_unused_function, yeccgoto_unary_expr/7}). +yeccgoto_unary_expr(0=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(15=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(18=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(25=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(26=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(34=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(35=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(36=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(37=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(38=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(39=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(40=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(41=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(42=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(46=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(60=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(69=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_1(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(78=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_81(_S, Cat, Ss, Stack, T, Ts, Tzr); +yeccgoto_unary_expr(79=_S, Cat, Ss, Stack, T, Ts, Tzr) -> + yeccpars2_80(_S, Cat, Ss, Stack, T, Ts, Tzr). + +-compile({inline,yeccpars2_1_/1}). +-dialyzer({nowarn_function, yeccpars2_1_/1}). +-compile({nowarn_unused_function, yeccpars2_1_/1}). +-file("rabbit_jms_selector_parser.yrl", 96). +yeccpars2_1_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_3_/1}). +-dialyzer({nowarn_function, yeccpars2_3_/1}). +-compile({nowarn_unused_function, yeccpars2_3_/1}). +-file("rabbit_jms_selector_parser.yrl", 101). +yeccpars2_3_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_4_/1}). +-dialyzer({nowarn_function, yeccpars2_4_/1}). +-compile({nowarn_unused_function, yeccpars2_4_/1}). +-file("rabbit_jms_selector_parser.yrl", 92). +yeccpars2_4_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_5_/1}). +-dialyzer({nowarn_function, yeccpars2_5_/1}). +-compile({nowarn_unused_function, yeccpars2_5_/1}). +-file("rabbit_jms_selector_parser.yrl", 43). +yeccpars2_5_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_6_/1}). +-dialyzer({nowarn_function, yeccpars2_6_/1}). +-compile({nowarn_unused_function, yeccpars2_6_/1}). +-file("rabbit_jms_selector_parser.yrl", 105). +yeccpars2_6_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_7_/1}). +-dialyzer({nowarn_function, yeccpars2_7_/1}). +-compile({nowarn_unused_function, yeccpars2_7_/1}). +-file("rabbit_jms_selector_parser.yrl", 59). +yeccpars2_7_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_8_/1}). +-dialyzer({nowarn_function, yeccpars2_8_/1}). +-compile({nowarn_unused_function, yeccpars2_8_/1}). +-file("rabbit_jms_selector_parser.yrl", 61). +yeccpars2_8_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_9_/1}). +-dialyzer({nowarn_function, yeccpars2_9_/1}). +-compile({nowarn_unused_function, yeccpars2_9_/1}). +-file("rabbit_jms_selector_parser.yrl", 60). +yeccpars2_9_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_10_/1}). +-dialyzer({nowarn_function, yeccpars2_10_/1}). +-compile({nowarn_unused_function, yeccpars2_10_/1}). +-file("rabbit_jms_selector_parser.yrl", 106). +yeccpars2_10_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_11_/1}). +-dialyzer({nowarn_function, yeccpars2_11_/1}). +-compile({nowarn_unused_function, yeccpars2_11_/1}). +-file("rabbit_jms_selector_parser.yrl", 40). +yeccpars2_11_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_12_/1}). +-dialyzer({nowarn_function, yeccpars2_12_/1}). +-compile({nowarn_unused_function, yeccpars2_12_/1}). +-file("rabbit_jms_selector_parser.yrl", 49). +yeccpars2_12_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_13_/1}). +-dialyzer({nowarn_function, yeccpars2_13_/1}). +-compile({nowarn_unused_function, yeccpars2_13_/1}). +-file("rabbit_jms_selector_parser.yrl", 58). +yeccpars2_13_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_14_/1}). +-dialyzer({nowarn_function, yeccpars2_14_/1}). +-compile({nowarn_unused_function, yeccpars2_14_/1}). +-file("rabbit_jms_selector_parser.yrl", 62). +yeccpars2_14_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_19_/1}). +-dialyzer({nowarn_function, yeccpars2_19_/1}). +-compile({nowarn_unused_function, yeccpars2_19_/1}). +-file("rabbit_jms_selector_parser.yrl", 116). +yeccpars2_19_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + {boolean, extract_value(___1)} + end | __Stack]. + +-compile({inline,yeccpars2_20_/1}). +-dialyzer({nowarn_function, yeccpars2_20_/1}). +-compile({nowarn_unused_function, yeccpars2_20_/1}). +-file("rabbit_jms_selector_parser.yrl", 114). +yeccpars2_20_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + {float, extract_value(___1)} + end | __Stack]. + +-compile({inline,yeccpars2_21_/1}). +-dialyzer({nowarn_function, yeccpars2_21_/1}). +-compile({nowarn_unused_function, yeccpars2_21_/1}). +-file("rabbit_jms_selector_parser.yrl", 109). +yeccpars2_21_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + + {identifier, extract_value(___1)} + end | __Stack]. + +-compile({inline,yeccpars2_22_/1}). +-dialyzer({nowarn_function, yeccpars2_22_/1}). +-compile({nowarn_unused_function, yeccpars2_22_/1}). +-file("rabbit_jms_selector_parser.yrl", 113). +yeccpars2_22_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + {integer, extract_value(___1)} + end | __Stack]. + +-compile({inline,yeccpars2_23_/1}). +-dialyzer({nowarn_function, yeccpars2_23_/1}). +-compile({nowarn_unused_function, yeccpars2_23_/1}). +-file("rabbit_jms_selector_parser.yrl", 115). +yeccpars2_23_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + {string, extract_value(___1)} + end | __Stack]. + +-compile({inline,yeccpars2_24_/1}). +-dialyzer({nowarn_function, yeccpars2_24_/1}). +-compile({nowarn_unused_function, yeccpars2_24_/1}). +-file("rabbit_jms_selector_parser.yrl", 48). +yeccpars2_24_(__Stack0) -> + [___2,___1 | __Stack] = __Stack0, + [begin + {'not', ___2} + end | __Stack]. + +-compile({inline,yeccpars2_27_/1}). +-dialyzer({nowarn_function, yeccpars2_27_/1}). +-compile({nowarn_unused_function, yeccpars2_27_/1}). +-file("rabbit_jms_selector_parser.yrl", 47). +yeccpars2_27_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'or', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_28_/1}). +-dialyzer({nowarn_function, yeccpars2_28_/1}). +-compile({nowarn_unused_function, yeccpars2_28_/1}). +-file("rabbit_jms_selector_parser.yrl", 46). +yeccpars2_28_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'and', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_29_/1}). +-dialyzer({nowarn_function, yeccpars2_29_/1}). +-compile({nowarn_unused_function, yeccpars2_29_/1}). +-file("rabbit_jms_selector_parser.yrl", 100). +yeccpars2_29_(__Stack0) -> + [___2,___1 | __Stack] = __Stack0, + [begin + {unary_minus, ___2} + end | __Stack]. + +-compile({inline,yeccpars2_30_/1}). +-dialyzer({nowarn_function, yeccpars2_30_/1}). +-compile({nowarn_unused_function, yeccpars2_30_/1}). +-file("rabbit_jms_selector_parser.yrl", 106). +yeccpars2_30_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + ___1 + end | __Stack]. + +-compile({inline,yeccpars2_31_/1}). +-dialyzer({nowarn_function, yeccpars2_31_/1}). +-compile({nowarn_unused_function, yeccpars2_31_/1}). +-file("rabbit_jms_selector_parser.yrl", 99). +yeccpars2_31_(__Stack0) -> + [___2,___1 | __Stack] = __Stack0, + [begin + {unary_plus, ___2} + end | __Stack]. + +-compile({inline,yeccpars2_33_/1}). +-dialyzer({nowarn_function, yeccpars2_33_/1}). +-compile({nowarn_unused_function, yeccpars2_33_/1}). +-file("rabbit_jms_selector_parser.yrl", 104). +yeccpars2_33_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + ___2 + end | __Stack]. + +-compile({inline,yeccpars2_49_/1}). +-dialyzer({nowarn_function, yeccpars2_49_/1}). +-compile({nowarn_unused_function, yeccpars2_49_/1}). +-file("rabbit_jms_selector_parser.yrl", 73). +yeccpars2_49_(__Stack0) -> + [___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + + {'not_like', ___1, process_like_pattern(___4), no_escape} + end | __Stack]. + +-compile({inline,yeccpars2_51_/1}). +-dialyzer({nowarn_function, yeccpars2_51_/1}). +-compile({nowarn_unused_function, yeccpars2_51_/1}). +-file("rabbit_jms_selector_parser.yrl", 75). +yeccpars2_51_(__Stack0) -> + [___6,___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + + {'not_like', ___1, process_like_pattern(___4), process_escape_char(___6)} + end | __Stack]. + +-compile({inline,yeccpars2_54_/1}). +-dialyzer({nowarn_function, yeccpars2_54_/1}). +-compile({nowarn_unused_function, yeccpars2_54_/1}). +-file("rabbit_jms_selector_parser.yrl", 81). +yeccpars2_54_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + [___1] + end | __Stack]. + +-compile({inline,yeccpars2_55_/1}). +-dialyzer({nowarn_function, yeccpars2_55_/1}). +-compile({nowarn_unused_function, yeccpars2_55_/1}). +-file("rabbit_jms_selector_parser.yrl", 83). +yeccpars2_55_(__Stack0) -> + [___1 | __Stack] = __Stack0, + [begin + extract_value(___1) + end | __Stack]. + +-compile({inline,yeccpars2_57_/1}). +-dialyzer({nowarn_function, yeccpars2_57_/1}). +-compile({nowarn_unused_function, yeccpars2_57_/1}). +-file("rabbit_jms_selector_parser.yrl", 82). +yeccpars2_57_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + [___1|___3] + end | __Stack]. + +-compile({inline,yeccpars2_58_/1}). +-dialyzer({nowarn_function, yeccpars2_58_/1}). +-compile({nowarn_unused_function, yeccpars2_58_/1}). +-file("rabbit_jms_selector_parser.yrl", 80). +yeccpars2_58_(__Stack0) -> + [___6,___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + {'not_in', ___1, ___5} + end | __Stack]. + +-compile({inline,yeccpars2_61_/1}). +-dialyzer({nowarn_function, yeccpars2_61_/1}). +-compile({nowarn_unused_function, yeccpars2_61_/1}). +-file("rabbit_jms_selector_parser.yrl", 66). +yeccpars2_61_(__Stack0) -> + [___6,___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + {'not_between', ___1, ___4, ___6} + end | __Stack]. + +-compile({inline,yeccpars2_62_/1}). +-dialyzer({nowarn_function, yeccpars2_62_/1}). +-compile({nowarn_unused_function, yeccpars2_62_/1}). +-file("rabbit_jms_selector_parser.yrl", 69). +yeccpars2_62_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + + {'like', ___1, process_like_pattern(___3), no_escape} + end | __Stack]. + +-compile({inline,yeccpars2_64_/1}). +-dialyzer({nowarn_function, yeccpars2_64_/1}). +-compile({nowarn_unused_function, yeccpars2_64_/1}). +-file("rabbit_jms_selector_parser.yrl", 71). +yeccpars2_64_(__Stack0) -> + [___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + + {'like', ___1, process_like_pattern(___3), process_escape_char(___5)} + end | __Stack]. + +-compile({inline,yeccpars2_67_/1}). +-dialyzer({nowarn_function, yeccpars2_67_/1}). +-compile({nowarn_unused_function, yeccpars2_67_/1}). +-file("rabbit_jms_selector_parser.yrl", 79). +yeccpars2_67_(__Stack0) -> + [___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + {'in', ___1, ___4} + end | __Stack]. + +-compile({inline,yeccpars2_70_/1}). +-dialyzer({nowarn_function, yeccpars2_70_/1}). +-compile({nowarn_unused_function, yeccpars2_70_/1}). +-file("rabbit_jms_selector_parser.yrl", 65). +yeccpars2_70_(__Stack0) -> + [___5,___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + {'between', ___1, ___3, ___5} + end | __Stack]. + +-compile({inline,yeccpars2_71_/1}). +-dialyzer({nowarn_function, yeccpars2_71_/1}). +-compile({nowarn_unused_function, yeccpars2_71_/1}). +-file("rabbit_jms_selector_parser.yrl", 56). +yeccpars2_71_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'>=', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_72_/1}). +-dialyzer({nowarn_function, yeccpars2_72_/1}). +-compile({nowarn_unused_function, yeccpars2_72_/1}). +-file("rabbit_jms_selector_parser.yrl", 54). +yeccpars2_72_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'>', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_73_/1}). +-dialyzer({nowarn_function, yeccpars2_73_/1}). +-compile({nowarn_unused_function, yeccpars2_73_/1}). +-file("rabbit_jms_selector_parser.yrl", 52). +yeccpars2_73_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'=', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_74_/1}). +-dialyzer({nowarn_function, yeccpars2_74_/1}). +-compile({nowarn_unused_function, yeccpars2_74_/1}). +-file("rabbit_jms_selector_parser.yrl", 53). +yeccpars2_74_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'<>', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_75_/1}). +-dialyzer({nowarn_function, yeccpars2_75_/1}). +-compile({nowarn_unused_function, yeccpars2_75_/1}). +-file("rabbit_jms_selector_parser.yrl", 57). +yeccpars2_75_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'<=', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_76_/1}). +-dialyzer({nowarn_function, yeccpars2_76_/1}). +-compile({nowarn_unused_function, yeccpars2_76_/1}). +-file("rabbit_jms_selector_parser.yrl", 55). +yeccpars2_76_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'<', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_77_/1}). +-dialyzer({nowarn_function, yeccpars2_77_/1}). +-compile({nowarn_unused_function, yeccpars2_77_/1}). +-file("rabbit_jms_selector_parser.yrl", 91). +yeccpars2_77_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'-', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_80_/1}). +-dialyzer({nowarn_function, yeccpars2_80_/1}). +-compile({nowarn_unused_function, yeccpars2_80_/1}). +-file("rabbit_jms_selector_parser.yrl", 95). +yeccpars2_80_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'/', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_81_/1}). +-dialyzer({nowarn_function, yeccpars2_81_/1}). +-compile({nowarn_unused_function, yeccpars2_81_/1}). +-file("rabbit_jms_selector_parser.yrl", 94). +yeccpars2_81_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'*', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_82_/1}). +-dialyzer({nowarn_function, yeccpars2_82_/1}). +-compile({nowarn_unused_function, yeccpars2_82_/1}). +-file("rabbit_jms_selector_parser.yrl", 90). +yeccpars2_82_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'+', ___1, ___3} + end | __Stack]. + +-compile({inline,yeccpars2_85_/1}). +-dialyzer({nowarn_function, yeccpars2_85_/1}). +-compile({nowarn_unused_function, yeccpars2_85_/1}). +-file("rabbit_jms_selector_parser.yrl", 86). +yeccpars2_85_(__Stack0) -> + [___3,___2,___1 | __Stack] = __Stack0, + [begin + {'is_null', ___1} + end | __Stack]. + +-compile({inline,yeccpars2_86_/1}). +-dialyzer({nowarn_function, yeccpars2_86_/1}). +-compile({nowarn_unused_function, yeccpars2_86_/1}). +-file("rabbit_jms_selector_parser.yrl", 87). +yeccpars2_86_(__Stack0) -> + [___4,___3,___2,___1 | __Stack] = __Stack0, + [begin + {'is_not_null', ___1} + end | __Stack]. + + +-file("rabbit_jms_selector_parser.yrl", 141). diff --git a/deps/rabbit/src/rabbit_jms_selector_parser.yrl b/deps/rabbit/src/rabbit_jms_selector_parser.yrl new file mode 100644 index 000000000000..0495f52fd8bc --- /dev/null +++ b/deps/rabbit/src/rabbit_jms_selector_parser.yrl @@ -0,0 +1,140 @@ +%%% This is the grammar file for JMS message selectors: +%%% https://jakarta.ee/specifications/messaging/3.1/jakarta-messaging-spec-3.1#message-selector +%%% +%%% To manually generate the parser file rabbit_jms_selector_parser.erl run: +%%% yecc:file("rabbit_jms_selector_parser.yrl", [deterministic]). + +Nonterminals + selector + conditional_expr + comparison_expr + logical_expr + additive_expr + multiplicative_expr + unary_expr + primary + literal + identifier_expr + string_list + string_item + between_expr + in_expr + like_expr + is_null_expr. + +Terminals + integer float boolean string identifier + '=' '<>' '>' '<' '>=' '<=' + '+' '-' '*' '/' + 'AND' 'OR' 'NOT' + 'BETWEEN' 'LIKE' 'IN' 'IS' 'NULL' 'ESCAPE' + '(' ')' ','. + +Rootsymbol selector. + +%% operator precedences (lowest to highest) +Left 100 'OR'. +Left 200 'AND'. +Nonassoc 300 '=' '<>' '>' '<' '>=' '<='. +Left 400 '+' '-'. +Left 500 '*' '/'. +Unary 600 'NOT'. + +%% "A selector is a conditional expression" +selector -> conditional_expr : '$1'. + +%% Conditional expressions +conditional_expr -> logical_expr : '$1'. + +%% Logical expressions +logical_expr -> logical_expr 'AND' logical_expr : {'and', '$1', '$3'}. +logical_expr -> logical_expr 'OR' logical_expr : {'or', '$1', '$3'}. +logical_expr -> 'NOT' logical_expr : {'not', '$2'}. +logical_expr -> comparison_expr : '$1'. + +%% Comparison expressions +comparison_expr -> additive_expr '=' additive_expr : {'=', '$1', '$3'}. +comparison_expr -> additive_expr '<>' additive_expr : {'<>', '$1', '$3'}. +comparison_expr -> additive_expr '>' additive_expr : {'>', '$1', '$3'}. +comparison_expr -> additive_expr '<' additive_expr : {'<', '$1', '$3'}. +comparison_expr -> additive_expr '>=' additive_expr : {'>=', '$1', '$3'}. +comparison_expr -> additive_expr '<=' additive_expr : {'<=', '$1', '$3'}. +comparison_expr -> between_expr : '$1'. +comparison_expr -> like_expr : '$1'. +comparison_expr -> in_expr : '$1'. +comparison_expr -> is_null_expr : '$1'. +comparison_expr -> additive_expr : '$1'. + +%% BETWEEN expression +between_expr -> additive_expr 'BETWEEN' additive_expr 'AND' additive_expr : {'between', '$1', '$3', '$5'}. +between_expr -> additive_expr 'NOT' 'BETWEEN' additive_expr 'AND' additive_expr : {'not_between', '$1', '$4', '$6'}. + +%% LIKE expression +like_expr -> additive_expr 'LIKE' string : + {'like', '$1', process_like_pattern('$3'), no_escape}. +like_expr -> additive_expr 'LIKE' string 'ESCAPE' string : + {'like', '$1', process_like_pattern('$3'), process_escape_char('$5')}. +like_expr -> additive_expr 'NOT' 'LIKE' string : + {'not_like', '$1', process_like_pattern('$4'), no_escape}. +like_expr -> additive_expr 'NOT' 'LIKE' string 'ESCAPE' string : + {'not_like', '$1', process_like_pattern('$4'), process_escape_char('$6')}. + +%% IN expression +in_expr -> additive_expr 'IN' '(' string_list ')' : {'in', '$1', '$4'}. +in_expr -> additive_expr 'NOT' 'IN' '(' string_list ')' : {'not_in', '$1', '$5'}. +string_list -> string_item : ['$1']. +string_list -> string_item ',' string_list : ['$1'|'$3']. +string_item -> string : extract_value('$1'). + +%% IS NULL expression +is_null_expr -> identifier_expr 'IS' 'NULL' : {'is_null', '$1'}. +is_null_expr -> identifier_expr 'IS' 'NOT' 'NULL' : {'is_not_null', '$1'}. + +%% Arithmetic expressions +additive_expr -> additive_expr '+' multiplicative_expr : {'+', '$1', '$3'}. +additive_expr -> additive_expr '-' multiplicative_expr : {'-', '$1', '$3'}. +additive_expr -> multiplicative_expr : '$1'. + +multiplicative_expr -> multiplicative_expr '*' unary_expr : {'*', '$1', '$3'}. +multiplicative_expr -> multiplicative_expr '/' unary_expr : {'/', '$1', '$3'}. +multiplicative_expr -> unary_expr : '$1'. + +%% Handle unary operators through grammar structure instead of precedence +unary_expr -> '+' primary : {unary_plus, '$2'}. +unary_expr -> '-' primary : {unary_minus, '$2'}. +unary_expr -> primary : '$1'. + +%% Primary expressions +primary -> '(' conditional_expr ')' : '$2'. +primary -> literal : '$1'. +primary -> identifier_expr : '$1'. + +%% Identifiers (header fields or property references) +identifier_expr -> identifier : + {identifier, extract_value('$1')}. + +%% Literals +literal -> integer : {integer, extract_value('$1')}. +literal -> float : {float, extract_value('$1')}. +literal -> string : {string, extract_value('$1')}. +literal -> boolean : {boolean, extract_value('$1')}. + +Erlang code. + +extract_value({_Token, _Line, Value}) -> Value. + +process_like_pattern({string, Line, Value}) -> + case unicode:characters_to_list(Value) of + L when is_list(L) -> + L; + _ -> + return_error(Line, "pattern-value in LIKE must be valid Unicode") + end. + +process_escape_char({string, Line, Value}) -> + case unicode:characters_to_list(Value) of + [SingleChar] -> + SingleChar; + _ -> + return_error(Line, "ESCAPE must be a single-character string literal") + end. diff --git a/deps/rabbit/src/rabbit_queue_type.erl b/deps/rabbit/src/rabbit_queue_type.erl index d11b1ec14fa8..7728d0c71687 100644 --- a/deps/rabbit/src/rabbit_queue_type.erl +++ b/deps/rabbit/src/rabbit_queue_type.erl @@ -133,7 +133,7 @@ consumer_tag := rabbit_types:ctag(), exclusive_consume => boolean(), args => rabbit_framing:amqp_table(), - filter => rabbit_amqp_filtex:filter_expressions(), + filter => rabbit_amqp_filter:expression(), ok_msg := term(), acting_user := rabbit_types:username()}. -type cancel_reason() :: cancel | remove. diff --git a/deps/rabbit/src/rabbit_stream_queue.erl b/deps/rabbit/src/rabbit_stream_queue.erl index dc240e04eee1..8421cd0b432d 100644 --- a/deps/rabbit/src/rabbit_stream_queue.erl +++ b/deps/rabbit/src/rabbit_stream_queue.erl @@ -93,7 +93,7 @@ %% were part of an uncompressed sub batch, and are buffered in %% reversed order until the consumer has more credits to consume them. buffer_msgs_rev = [] :: [rabbit_amqqueue:qmsg()], - filter :: rabbit_amqp_filtex:filter_expressions(), + filter :: rabbit_amqp_filter:expression(), reader_options :: map()}). -record(stream_client, {stream_id :: string(), @@ -358,7 +358,7 @@ consume(Q, Spec, #stream_client{} = QState0) %% begins sending maybe_send_reply(ChPid, OkMsg), _ = rabbit_stream_coordinator:register_local_member_listener(Q), - Filter = maps:get(filter, Spec, []), + Filter = maps:get(filter, Spec, undefined), begin_stream(QState, ConsumerTag, OffsetSpec, Mode, AckRequired, Filter, filter_spec(Args)); {error, Reason} -> @@ -1319,7 +1319,7 @@ entry_to_msg(Entry, Offset, #resource{kind = queue, name = QName}, Mc = mc_amqp:init_from_stream(Entry, #{?ANN_EXCHANGE => <<>>, ?ANN_ROUTING_KEYS => [QName], <<"x-stream-offset">> => Offset}), - case rabbit_amqp_filtex:filter(Filter, Mc) of + case rabbit_amqp_filter:eval(Filter, Mc) of true -> {Name, LocalPid, Offset, false, Mc}; false -> diff --git a/deps/rabbit/test/amqp_filtex_SUITE.erl b/deps/rabbit/test/amqp_filter_prop_SUITE.erl similarity index 98% rename from deps/rabbit/test/amqp_filtex_SUITE.erl rename to deps/rabbit/test/amqp_filter_prop_SUITE.erl index 2d4f34bd1883..383d55915563 100644 --- a/deps/rabbit/test/amqp_filtex_SUITE.erl +++ b/deps/rabbit/test/amqp_filter_prop_SUITE.erl @@ -5,12 +5,14 @@ %% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. %% -%% Test suite for +%% Test suite for §4 Property Filter Expressions of %% AMQP Filter Expressions Version 1.0 Working Draft 09 --module(amqp_filtex_SUITE). +%% filtering from a stream. +-module(amqp_filter_prop_SUITE). -include_lib("eunit/include/eunit.hrl"). --include_lib("amqp10_common/include/amqp10_filtex.hrl"). +-include_lib("amqp10_client/include/amqp10_client.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). -compile([nowarn_export_all, @@ -53,9 +55,7 @@ init_per_suite(Config) -> {ok, _} = application:ensure_all_started(amqp10_client), rabbit_ct_helpers:log_environment(), rabbit_ct_helpers:merge_app_env( - Config, {rabbit, [{quorum_tick_interval, 1000}, - {stream_tick_interval, 1000} - ]}). + Config, {rabbit, [{stream_tick_interval, 1000}]}). end_per_suite(Config) -> Config. @@ -148,8 +148,10 @@ properties_section(Config) -> {{symbol, <<"group-sequence">>}, {uint, 16#ff_ff_ff_ff}}, {{symbol, <<"reply-to-group-id">>}, {utf8, <<"other group ID">>}} ], - Filter1 = #{<<"rabbitmq:stream-offset-spec">> => <<"first">>, - ?DESCRIPTOR_NAME_PROPERTIES_FILTER => {map, PropsFilter1}}, + Filter1 = #{<<"from start">> => #filter{descriptor = <<"rabbitmq:stream-offset-spec">>, + value = {symbol, <<"first">>}}, + <<"props">> => #filter{descriptor = ?DESCRIPTOR_NAME_PROPERTIES_FILTER, + value = {map, PropsFilter1}}}, {ok, Receiver1} = amqp10_client:attach_receiver_link( Session, <<"receiver 1">>, Address, settled, configuration, Filter1), diff --git a/deps/rabbit/test/amqp_filter_sql_SUITE.erl b/deps/rabbit/test/amqp_filter_sql_SUITE.erl new file mode 100644 index 000000000000..97820f6c66ea --- /dev/null +++ b/deps/rabbit/test/amqp_filter_sql_SUITE.erl @@ -0,0 +1,441 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. +%% + +%% Test suite for SQL expressions filtering from a stream. +-module(amqp_filter_sql_SUITE). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("amqp10_client/include/amqp10_client.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). +-include_lib("amqp10_common/include/amqp10_framing.hrl"). + +-compile([nowarn_export_all, + export_all]). + +-import(rabbit_ct_broker_helpers, + [rpc/4]). +-import(rabbit_ct_helpers, + [eventually/1]). +-import(amqp_utils, + [init/1, + connection_config/1, + flush/1, + wait_for_credit/1, + wait_for_accepts/1, + send_messages/3, + detach_link_sync/1, + end_session_sync/1, + close_connection_sync/1]). + +all() -> + [ + {group, cluster_size_1} + ]. + +groups() -> + [ + {cluster_size_1, [shuffle], + [ + multiple_sections, + filter_few_messages_from_many, + sql_and_bloom_filter, + invalid_filter + ]} + ]. + +init_per_suite(Config) -> + {ok, _} = application:ensure_all_started(amqp10_client), + rabbit_ct_helpers:log_environment(), + rabbit_ct_helpers:merge_app_env( + Config, {rabbit, [{stream_tick_interval, 1000}]}). + +end_per_suite(Config) -> + Config. + +init_per_group(_Group, Config) -> + Suffix = rabbit_ct_helpers:testcase_absname(Config, "", "-"), + Config1 = rabbit_ct_helpers:set_config( + Config, [{rmq_nodename_suffix, Suffix}]), + rabbit_ct_helpers:run_setup_steps( + Config1, + rabbit_ct_broker_helpers:setup_steps() ++ + rabbit_ct_client_helpers:setup_steps()). + +end_per_group(_, Config) -> + rabbit_ct_helpers:run_teardown_steps(Config, + rabbit_ct_client_helpers:teardown_steps() ++ + rabbit_ct_broker_helpers:teardown_steps()). + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +end_per_testcase(Testcase, Config) -> + %% Assert that every testcase cleaned up. + eventually(?_assertEqual([], rpc(Config, rabbit_amqqueue, list, []))), + %% Wait for sessions to terminate before starting the next test case. + eventually(?_assertEqual([], rpc(Config, rabbit_amqp_session, list_local, []))), + rabbit_ct_helpers:testcase_finished(Config, Testcase). + +multiple_sections(Config) -> + Stream = atom_to_binary(?FUNCTION_NAME), + Address = rabbitmq_amqp_address:queue(Stream), + + OpnConf = connection_config(Config), + {ok, Connection} = amqp10_client:open_connection(OpnConf), + {ok, Session} = amqp10_client:begin_session_sync(Connection), + {ok, LinkPair} = rabbitmq_amqp_client:attach_management_link_pair_sync(Session, <<"my link pair">>), + {ok, #{}} = rabbitmq_amqp_client:declare_queue( + LinkPair, Stream, + #{arguments => #{<<"x-queue-type">> => {utf8, <<"stream">>}}}), + {ok, Sender} = amqp10_client:attach_sender_link(Session, <<"sender">>, Address), + ok = wait_for_credit(Sender), + + Now = erlang:system_time(millisecond), + To = rabbitmq_amqp_address:exchange(<<"some exchange">>, <<"routing key">>), + ReplyTo = rabbitmq_amqp_address:queue(<<"some queue">>), + + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:new(<<"t1">>, <<"m1">>)), + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:set_headers( + #{priority => 200}, + amqp10_msg:set_properties( + #{message_id => {ulong, 999}, + user_id => <<"guest">>, + to => To, + subject => <<"🐇"/utf8>>, + reply_to => ReplyTo, + correlation_id => <<"corr-123">>, + content_type => <<"text/plain">>, + content_encoding => <<"some encoding">>, + absolute_expiry_time => Now + 100_000, + creation_time => Now, + group_id => <<"my group ID">>, + group_sequence => 16#ff_ff_ff_ff, + reply_to_group_id => <<"other group ID">>}, + amqp10_msg:set_application_properties( + #{<<"k1">> => -3, + <<"k2">> => false, + <<"k3">> => true, + <<"k4">> => <<"hey👋"/utf8>>}, + amqp10_msg:new(<<"t2">>, <<"m2">>))))), + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:set_properties( + #{group_id => <<"my group ID">>}, + amqp10_msg:set_application_properties( + #{<<"k1">> => -4}, + amqp10_msg:new(<<"t3">>, <<"m3">>)))), + + ok = wait_for_accepts(3), + ok = detach_link_sync(Sender), + flush(sent), + + Filter1 = filter(<<"k1 <= -3">>), + {ok, R1} = amqp10_client:attach_receiver_link( + Session, <<"receiver 1">>, Address, + settled, configuration, Filter1), + ok = amqp10_client:flow_link_credit(R1, 10, never, true), + receive {amqp10_msg, R1, R1M2} -> + ?assertEqual([<<"m2">>], amqp10_msg:body(R1M2)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + receive {amqp10_msg, R1, R1M3} -> + ?assertEqual([<<"m3">>], amqp10_msg:body(R1M3)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + ok = assert_credit_exhausted(R1, ?LINE), + ok = detach_link_sync(R1), + + Filter2 = filter( + <<"header.priority = 200 AND " + "properties.message-id = 999 AND " + "properties.user-id = 'guest' AND " + "properties.to LIKE '/exch_nges/some=%20exchange/rout%' ESCAPE '=' AND " + "properties.subject = '🐇' AND " + "properties.reply-to LIKE '/queues/some%' AND " + "properties.correlation-id IN ('corr-345', 'corr-123') AND " + "properties.content-type = 'text/plain' AND " + "properties.content-encoding = 'some encoding' AND " + "properties.absolute-expiry-time > 0 AND " + "properties.creation-time > 0 AND " + "properties.group-id IS NOT NULL AND " + "properties.group-sequence = 4294967295 AND " + "properties.reply-to-group-id = 'other group ID' AND " + "k1 < 0 AND " + "NOT k2 AND " + "k3 AND " + "k4 NOT LIKE 'hey' AND " + "k5 IS NULL" + /utf8>>), + {ok, R2} = amqp10_client:attach_receiver_link( + Session, <<"receiver 2">>, Address, + settled, configuration, Filter2), + ok = amqp10_client:flow_link_credit(R2, 10, never, true), + receive {amqp10_msg, R2, R2M2} -> + ?assertEqual([<<"m2">>], amqp10_msg:body(R2M2)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + ok = assert_credit_exhausted(R2, ?LINE), + ok = detach_link_sync(R2), + + Filter3 = filter(<<"absent IS NULL">>), + {ok, R3} = amqp10_client:attach_receiver_link( + Session, <<"receiver 3">>, Address, + settled, configuration, Filter3), + ok = amqp10_client:flow_link_credit(R3, 10, never, true), + receive {amqp10_msg, R3, R3M1} -> + ?assertEqual([<<"m1">>], amqp10_msg:body(R3M1)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + receive {amqp10_msg, R3, R3M2} -> + ?assertEqual([<<"m2">>], amqp10_msg:body(R3M2)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + receive {amqp10_msg, R3, R3M3} -> + ?assertEqual([<<"m3">>], amqp10_msg:body(R3M3)) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + ok = assert_credit_exhausted(R3, ?LINE), + ok = detach_link_sync(R3), + + {ok, _} = rabbitmq_amqp_client:delete_queue(LinkPair, Stream), + ok = rabbitmq_amqp_client:detach_management_link_pair_sync(LinkPair), + ok = end_session_sync(Session), + ok = close_connection_sync(Connection). + +%% Filter a small subset from many messages. +%% We test here that flow control still works correctly. +filter_few_messages_from_many(Config) -> + Stream = atom_to_binary(?FUNCTION_NAME), + Address = rabbitmq_amqp_address:queue(Stream), + {Connection, Session, LinkPair} = init(Config), + {ok, #{}} = rabbitmq_amqp_client:declare_queue( + LinkPair, Stream, + #{arguments => #{<<"x-queue-type">> => {utf8, <<"stream">>}}}), + {ok, Sender} = amqp10_client:attach_sender_link(Session, <<"sender">>, Address), + ok = wait_for_credit(Sender), + + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:set_properties( + #{group_id => <<"my group ID">>}, + amqp10_msg:new(<<"t1">>, <<"first msg">>))), + ok = send_messages(Sender, 1000, false), + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:set_properties( + #{group_id => <<"my group ID">>}, + amqp10_msg:new(<<"t2">>, <<"last msg">>))), + ok = wait_for_accepts(1002), + ok = detach_link_sync(Sender), + flush(sent), + + %% Our filter should cause us to receive only the first and + %% last message out of the 1002 messages in the stream. + Filter = filter(<<"properties.group-id is not null">>), + {ok, Receiver} = amqp10_client:attach_receiver_link( + Session, <<"receiver">>, Address, + unsettled, configuration, Filter), + + ok = amqp10_client:flow_link_credit(Receiver, 2, never, true), + receive {amqp10_msg, Receiver, M1} -> + ?assertEqual([<<"first msg">>], amqp10_msg:body(M1)), + ok = amqp10_client:accept_msg(Receiver, M1) + after 30000 -> ct:fail({missing_msg, ?LINE}) + end, + receive {amqp10_msg, Receiver, M2} -> + ?assertEqual([<<"last msg">>], amqp10_msg:body(M2)), + ok = amqp10_client:accept_msg(Receiver, M2) + after 30000 -> ct:fail({missing_msg, ?LINE}) + end, + ok = assert_credit_exhausted(Receiver, ?LINE), + ok = detach_link_sync(Receiver), + + {ok, _} = rabbitmq_amqp_client:delete_queue(LinkPair, Stream), + ok = rabbitmq_amqp_client:detach_management_link_pair_sync(LinkPair), + ok = end_session_sync(Session), + ok = close_connection_sync(Connection). + +%% Test that SQL and Bloom filters can be used together. +sql_and_bloom_filter(Config) -> + Stream = atom_to_binary(?FUNCTION_NAME), + Address = rabbitmq_amqp_address:queue(Stream), + OpnConf0 = connection_config(Config), + OpnConf = OpnConf0#{notify_with_performative => true}, + {ok, Connection} = amqp10_client:open_connection(OpnConf), + {ok, Session} = amqp10_client:begin_session_sync(Connection), + {ok, LinkPair} = rabbitmq_amqp_client:attach_management_link_pair_sync(Session, <<"my link pair">>), + {ok, #{}} = rabbitmq_amqp_client:declare_queue( + LinkPair, Stream, + #{arguments => #{<<"x-queue-type">> => {utf8, <<"stream">>}}}), + {ok, Sender} = amqp10_client:attach_sender_link(Session, <<"sender">>, Address), + ok = wait_for_credit(Sender), + + ok = amqp10_client:send_msg( + Sender, + amqp10_msg:set_message_annotations( + #{<<"x-stream-filter-value">> => <<"v1">>}, + amqp10_msg:set_headers( + #{priority => 12}, + amqp10_msg:set_properties( + #{subject => <<"v1">>}, + amqp10_msg:new(<<"t1">>, <<"msg">>))))), + receive {amqp10_disposition, {accepted, <<"t1">>}} -> ok + after 9000 -> ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Sender), + flush(sent), + + Filter = filter(<<"properties.subject = 'v1' AND header.priority > 10">>), + DesiredFilter = maps:put(<<"my bloom filter">>, + #filter{descriptor = <<"rabbitmq:stream-filter">>, + value = {utf8, <<"v1">>}}, + Filter), + {ok, Receiver} = amqp10_client:attach_receiver_link( + Session, <<"receiver">>, Address, + unsettled, configuration, DesiredFilter), + receive {amqp10_event, + {link, Receiver, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter}}}}}} -> + DesiredFilterNames = lists:sort(maps:keys(DesiredFilter)), + ActualFilterNames = lists:sort([Name || {{symbol, Name}, _} <- ActualFilter]), + ?assertEqual(DesiredFilterNames, ActualFilterNames) + after 9000 -> ct:fail({missing_event, ?LINE}) + end, + + ok = amqp10_client:flow_link_credit(Receiver, 1, never), + receive {amqp10_msg, Receiver, M1} -> + ?assertEqual([<<"msg">>], amqp10_msg:body(M1)), + ok = amqp10_client:accept_msg(Receiver, M1) + after 9000 -> ct:fail({missing_msg, ?LINE}) + end, + ok = detach_link_sync(Receiver), + + {ok, _} = rabbitmq_amqp_client:delete_queue(LinkPair, Stream), + ok = rabbitmq_amqp_client:detach_management_link_pair_sync(LinkPair), + ok = end_session_sync(Session), + ok = close_connection_sync(Connection). + +invalid_filter(Config) -> + Stream = atom_to_binary(?FUNCTION_NAME), + Address = rabbitmq_amqp_address:queue(Stream), + + OpnConf0 = connection_config(Config), + OpnConf = OpnConf0#{notify_with_performative => true}, + {ok, Connection} = amqp10_client:open_connection(OpnConf), + {ok, Session} = amqp10_client:begin_session_sync(Connection), + {ok, LinkPair} = rabbitmq_amqp_client:attach_management_link_pair_sync(Session, <<"my link pair">>), + {ok, #{}} = rabbitmq_amqp_client:declare_queue( + LinkPair, Stream, + #{arguments => #{<<"x-queue-type">> => {utf8, <<"stream">>}}}), + + %% Trigger a lexer error. + Filter1 = #{?FILTER_NAME_SQL => #filter{descriptor = ?DESCRIPTOR_CODE_SELECTOR_FILTER, + value = {utf8, <<"@#$%^&">>}}}, + {ok, Receiver1} = amqp10_client:attach_receiver_link( + Session, <<"receiver 1">>, Address, + unsettled, configuration, Filter1), + receive {amqp10_event, + {link, Receiver1, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter1}}}}}} -> + %% RabbitMQ should exclude this filter in its reply attach frame because + %% "the sending endpoint [RabbitMQ] sets the filter actually in place". + ?assertMatch([], ActualFilter1) + after 9000 -> + ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Receiver1), + + %% Trigger a parser error. We use allowed tokens here, but the grammar is incorrect. + Filter2 = #{?FILTER_NAME_SQL => #filter{descriptor = ?DESCRIPTOR_CODE_SELECTOR_FILTER, + value = {utf8, <<"FALSE FALSE">>}}}, + {ok, Receiver2} = amqp10_client:attach_receiver_link( + Session, <<"receiver 2">>, Address, + unsettled, configuration, Filter2), + receive {amqp10_event, + {link, Receiver2, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter2}}}}}} -> + ?assertMatch([], ActualFilter2) + after 9000 -> + ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Receiver2), + + %% SQL filtering should be mutually exclusive with AMQP property filtering + PropsFilter = [{{symbol, <<"subject">>}, {utf8, <<"some subject">>}}], + Filter3 = #{<<"prop name">> => #filter{descriptor = ?DESCRIPTOR_NAME_PROPERTIES_FILTER, + value = {map, PropsFilter}}, + ?FILTER_NAME_SQL => #filter{descriptor = ?DESCRIPTOR_CODE_SELECTOR_FILTER, + value = {utf8, <<"TRUE">>}}}, + {ok, Receiver3} = amqp10_client:attach_receiver_link( + Session, <<"receiver 3">>, Address, + unsettled, configuration, Filter3), + receive {amqp10_event, + {link, Receiver3, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter3}}}}}} -> + %% We expect only one of the two filters to be actually in place. + ?assertMatch([_], ActualFilter3) + after 9000 -> + ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Receiver3), + + %% Send invalid UTF-8 in the SQL expression. + InvalidUTF8 = <<255>>, + Filter4 = #{?FILTER_NAME_SQL => #filter{descriptor = ?DESCRIPTOR_CODE_SELECTOR_FILTER, + value = {utf8, InvalidUTF8}}}, + {ok, Receiver4} = amqp10_client:attach_receiver_link( + Session, <<"receiver 4">>, Address, + unsettled, configuration, Filter4), + receive {amqp10_event, + {link, Receiver4, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter4}}}}}} -> + ?assertMatch([], ActualFilter4) + after 9000 -> + ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Receiver4), + + %% Send invalid descriptor + Filter5 = #{?FILTER_NAME_SQL => #filter{descriptor = <<"apache.org:invalid:string">>, + value = {utf8, <<"TRUE">>}}}, + {ok, Receiver5} = amqp10_client:attach_receiver_link( + Session, <<"receiver 5">>, Address, + unsettled, configuration, Filter5), + receive {amqp10_event, + {link, Receiver5, + {attached, #'v1_0.attach'{ + source = #'v1_0.source'{filter = {map, ActualFilter5}}}}}} -> + ?assertMatch([], ActualFilter5) + after 9000 -> + ct:fail({missing_event, ?LINE}) + end, + ok = detach_link_sync(Receiver5), + + {ok, _} = rabbitmq_amqp_client:delete_queue(LinkPair, Stream), + ok = rabbitmq_amqp_client:detach_management_link_pair_sync(LinkPair), + ok = close_connection_sync(Connection). + +filter(String) + when is_binary(String) -> + #{<<"from start">> => #filter{descriptor = <<"rabbitmq:stream-offset-spec">>, + value = {symbol, <<"first">>}}, + ?FILTER_NAME_SQL => #filter{descriptor = ?DESCRIPTOR_NAME_SELECTOR_FILTER, + value = {utf8, String}}}. + +assert_credit_exhausted(Receiver, Line) -> + receive {amqp10_event, {link, Receiver, credit_exhausted}} -> ok + after 9000 -> ct:fail({missing_credit_exhausted, Line}) + end. diff --git a/deps/rabbit/test/amqp_jms_unit_SUITE.erl b/deps/rabbit/test/amqp_jms_unit_SUITE.erl new file mode 100644 index 000000000000..95d4be0319f2 --- /dev/null +++ b/deps/rabbit/test/amqp_jms_unit_SUITE.erl @@ -0,0 +1,858 @@ +%% This Source Code Form is subject to the terms of the Mozilla Public +%% License, v. 2.0. If a copy of the MPL was not distributed with this +%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%% +%% Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved. + +-module(amqp_jms_unit_SUITE). + +-compile([export_all, nowarn_export_all]). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). +-include_lib("amqp10_common/include/amqp10_framing.hrl"). + +%%%=================================================================== +%%% Common Test callbacks +%%%=================================================================== + +all() -> + [ + {group, tests} + ]. + +groups() -> + [{tests, [shuffle], + [ + logical_operators, + comparison_operators, + arithmetic_operators, + string_comparison, + like_operator, + in_operator, + between_operator, + null_handling, + literals, + scientific_notation, + precedence_and_parentheses, + type_handling, + complex_expressions, + case_sensitivity, + whitespace_handling, + identifier_rules, + header_section, + properties_section, + multiple_sections, + parse_errors + ] + }]. + +%%%=================================================================== +%%% Test cases +%%%=================================================================== + +logical_operators(_Config) -> + %% Basic logical operators + true = match("country = 'UK' AND weight = 5", app_props()), + true = match("'UK' = country AND 5 = weight", app_props()), + true = match("country = 'France' OR weight < 6", app_props()), + true = match("NOT country = 'France'", app_props()), + false = match("country = 'UK' AND weight > 5", app_props()), + false = match("missing AND premium", app_props()), + false = match("active AND absent", app_props()), + false = match("NOT absent", app_props()), + false = match("premium OR absent", app_props()), + true = match("absent OR active", app_props()), + true = match("active OR absent", app_props()), + + %% The JMS spec isn't very clear on whether the following should match. + %% Option 1: + %% The conditional expression is invalid because percentage + %% is an identifier returning an integer instead of a boolean. + %% Therefore, arguably the conditional expression is invalid and should not match. + %% Option 2: + %% This integer could be interpreted as UNKNOWN such that + %% "UNKNOWN OR TRUE" evalutes to TRUE as per table Table 3‑5. + %% Qpid Broker-J and ActiveMQ Artemis implement option 2. + %% That's why we also expect option 2 here. + true = match("percentage OR active", app_props()), + true = match("active OR percentage", app_props()), + + %% Compound logical expressions + true = match("country = 'UK' AND (weight > 3 OR price < 20)", app_props()), + true = match("NOT (country = 'France' OR country = 'Germany')", app_props()), + false = match("country = 'UK' AND NOT active = TRUE", app_props()), + true = match("(country = 'US' OR country = 'UK') AND (weight > 2 AND weight < 10)", app_props()). + +comparison_operators(_Config) -> + %% Equality + true = match("country = 'UK'", app_props()), + false = match("country = 'US'", app_props()), + + %% Inequality + true = match("country <> 'US'", app_props()), + false = match("country <> 'UK'", app_props()), + + %% Greater than + true = match("weight > 3", app_props()), + false = match("weight > 5", app_props()), + + %% Less than + true = match("weight < 10", app_props()), + false = match("weight < 5", app_props()), + + %% Greater than or equal + true = match("weight >= 5", app_props()), + true = match("weight >= 4", app_props()), + false = match("weight >= 6", app_props()), + %% "Only like type values can be compared. One exception is that it is + %% valid to compare exact numeric values and approximate numeric value" + true = match("weight >= 5.0", app_props()), + true = match("weight >= 4.99", app_props()), + false = match("weight >= 5.01", app_props()), + true = match("price >= 10.5", app_props()), + false = match("price >= 10.51", app_props()), + true = match("price >= 10.4", app_props()), + true = match("price >= 10", app_props()), + false = match("price >= 11", app_props()), + + %% Less than or equal + true = match("weight <= 5", app_props()), + true = match("weight <= 6", app_props()), + false = match("weight <= 4", app_props()), + true = match("price <= 10.6", app_props()), + false = match("price <= 10", app_props()), + + %% "String and Boolean comparison is restricted to = and <>." + %% "If the comparison of non-like type values is attempted, the value of the operation is false." + true = match("active = true", app_props()), + true = match("premium = false", app_props()), + false = match("premium <> false", app_props()), + false = match("premium >= 'false'", app_props()), + false = match("premium <= 'false'", app_props()), + false = match("premium >= 0", app_props()), + false = match("premium <= 0", app_props()), + + false = match("country >= 'UK'", app_props()), + false = match("country > 'UA'", app_props()), + false = match("country >= 'UA'", app_props()), + false = match("country < 'UA'", app_props()), + false = match("country <= 'UA'", app_props()), + false = match("country < 'UL'", app_props()), + false = match("country < true", app_props()), + + false = match("weight = '5'", app_props()), + false = match("weight >= '5'", app_props()), + false = match("weight <= '5'", app_props()), + false = match("country > 1", app_props()), + false = match("country < 1", app_props()). + +arithmetic_operators(_Config) -> + %% Addition + true = match("weight + 5 = 10", app_props()), + true = match("price + 4.5 = 15", app_props()), + + %% Subtraction + true = match("weight - 2 = 3", app_props()), + true = match("price - 0.5 = 10", app_props()), + + %% Multiplication + true = match("weight * 2 = 10", app_props()), + true = match("quantity * price * discount = 262.5", app_props()), + + %% Division + true = match("weight / 2 = 2.5", app_props()), + true = match("price / 2 = 5.25", app_props()), + true = match("quantity / 10 = 10", app_props()), + true = match("quantity / 10 = 10.000", app_props()), + + %% Nested arithmetic + true = match("(weight + 5) * 2 = 20", app_props()), + true = match("price / (weight - 3) = 5.25", app_props()), + + %% Unary operators + true = match("+temperature = -5", app_props()), + true = match("-temperature = 5", app_props()), + true = match("+weight = 5", app_props()), + true = match("-weight = -5", app_props()), + true = match("6 + -weight = 1", app_props()), + true = match("6 - +weight = 1", app_props()), + true = match("6 + +weight = 11", app_props()), + true = match("6 - -weight = 11", app_props()), + true = match("+(-weight) = -5", app_props()), + true = match("-(+weight) = -5", app_props()), + true = match("-(-weight) = 5", app_props()), + true = match("+(+weight) = 5", app_props()), + false = match("+weight", app_props()), + + %% Unary operators followed by identifiers with non-numeric values are invalid + %% and should therefore not match. + false = match("+city", app_props()), + false = match("+city = 'London'", app_props()), + false = match("-absent", app_props()), + + %% "Comparison or arithmetic with an unknown value always yields an unknown value." + false = match("absent + 4 = 5", app_props()), + false = match("2 * absent = 0", app_props()). + +string_comparison(_Config) -> + %% "Two strings are equal if and only if they contain the same sequence of characters." + false = match("country = '🇬🇧'", app_props()), + true = match("country = '🇬🇧'", [{{utf8, <<"country">>}, {utf8, <<"🇬🇧"/utf8>>}}]), + + %% "A string literal is enclosed in single quotes, with an included + %% single quote represented by doubled single quote" + true = match("'UK''s' = 'UK''s'", app_props()), + true = match("country = 'UK''s'", [{{utf8, <<"country">>}, {utf8, <<"UK's">>}}]), + true = match("country = '🇬🇧''s'", [{{utf8, <<"country">>}, {utf8, <<"🇬🇧's"/utf8>>}}]), + true = match("country = ''", [{{utf8, <<"country">>}, {utf8, <<>>}}]), + true = match("country = ''''", [{{utf8, <<"country">>}, {utf8, <<$'>>}}]). + +like_operator(_Config) -> + %% Basic LIKE operations + true = match("description LIKE '%test%'", app_props()), + true = match("description LIKE 'This is a %'", app_props()), + true = match("description LIKE '%a test message'", app_props()), + true = match("description LIKE 'T_i% a %e_%e_sa%'", app_props()), + false = match("description LIKE 'T_i% a %e_%e_sa'", app_props()), + false = match("description LIKE 'is a test message'", app_props()), + true = match("country LIKE 'UK'", app_props()), + true = match("country LIKE 'U_'", app_props()), + true = match("country LIKE '_K'", app_props()), + true = match("country LIKE 'UK%'", app_props()), + true = match("country LIKE '%UK'", app_props()), + true = match("country LIKE 'U%K'", app_props()), + false = match("country LIKE 'US'", app_props()), + false = match("country LIKE '_UK'", app_props()), + false = match("country LIKE 'UK_'", app_props()), + false = match("country LIKE 'U_K'", app_props()), + false = match("city LIKE 'New%'", app_props()), + true = match("key LIKE 'a%a'", [{{utf8, <<"key">>}, {utf8, <<"aa">>}}]), + false = match("key LIKE 'a%a'", [{{utf8, <<"key">>}, {utf8, <<"a">>}}]), + + %% identifier with empty string value + Empty = [{{utf8, <<"empty">>}, {utf8, <<"">>}}], + true = match("empty LIKE ''", Empty), + true = match("empty LIKE '%'", Empty), + true = match("empty LIKE '%%'", Empty), + true = match("empty LIKE '%%%'", Empty), + false = match("empty LIKE 'x'", Empty), + false = match("empty LIKE '%x'", Empty), + false = match("empty LIKE '%x%'", Empty), + false = match("empty LIKE '_'", Empty), + + %% LIKE operations with UTF8 + Utf8 = [{{utf8, <<"food">>}, {utf8, <<"car🥕rot"/utf8>>}}], + true = match("food LIKE 'car🥕rot'", Utf8), + true = match("food LIKE 'car_rot'", Utf8), + true = match("food LIKE '___🥕___'", Utf8), + true = match("food LIKE '%🥕%'", Utf8), + true = match("food LIKE '%_🥕_%'", Utf8), + true = match("food LIKE '_%🥕%_'", Utf8), + false = match("food LIKE 'car__rot'", Utf8), + false = match("food LIKE 'carrot'", Utf8), + false = match("food LIKE 'car🥕to'", Utf8), + + false = match("invalid_utf8 LIKE '%a'", [{{utf8, <<"invalid_utf8">>}, {binary, <<0, 1, 128>>}}]), + false = match("invalid_utf8 LIKE '_a'", [{{utf8, <<"invalid_utf8">>}, {binary, <<255>>}}]), + true = match("key LIKE '_#.\\|()[]{} ^$*+?%'", [{{utf8, <<"key">>}, {utf8, <<"##.\\|()[]{} ^$*+???">>}}]), + true = match("key LIKE '##.\\|()[]{} ^$*+???'", [{{utf8, <<"key">>}, {utf8, <<"##.\\|()[]{} ^$*+???">>}}]), + + %% Escape character + true = match("key LIKE 'z_%' ESCAPE 'z'", [{{utf8, <<"key">>}, {utf8, <<"_foo">>}}]), + false = match("key LIKE 'z_%' ESCAPE 'z'", [{{utf8, <<"key">>}, {utf8, <<"foo">>}}]), + true = match("key LIKE '$_%' ESCAPE '$'", [{{utf8, <<"key">>}, {utf8, <<"_foo">>}}]), + false = match("key LIKE '$_%' ESCAPE '$'", [{{utf8, <<"key">>}, {utf8, <<"foo">>}}]), + true = match("key LIKE '_$%' ESCAPE '$'", [{{utf8, <<"key">>}, {utf8, <<"5%">>}}]), + true = match("key LIKE '_$%' ESCAPE '$'", [{{utf8, <<"key">>}, {utf8, <<"🥕%"/utf8>>}}]), + true = match("key LIKE '🍰@%🥕' ESCAPE '@'", [{{utf8, <<"key">>}, {utf8, <<"🍰%🥕"/utf8>>}}]), + false = match("key LIKE '🍰@%🥕' ESCAPE '@'", [{{utf8, <<"key">>}, {utf8, <<"🍰other🥕"/utf8>>}}]), + false = match("key LIKE '🍰@%🥕' ESCAPE '@'", [{{utf8, <<"key">>}, {utf8, <<"🍰🥕"/utf8>>}}]), + true = match("key LIKE '!_#.\\|()[]{} ^$*+?!%' ESCAPE '!'", [{{utf8, <<"key">>}, {utf8, <<"_#.\\|()[]{} ^$*+?%">>}}]), + false = match("key LIKE '!_#.\\|()[]{} ^$*+?!%' ESCAPE '!'", [{{utf8, <<"key">>}, {utf8, <<"##.\\|()[]{} ^$*+?%">>}}]), + + true = match("product_id LIKE 'ABC\\_%' ESCAPE '\\'", app_props()), + false = match("product_id LIKE 'ABC\\%' ESCAPE '\\'", app_props()), + false = match("product_id LIKE 'ABC\\_\\%' ESCAPE '\\'", app_props()), + true = match("product_id LIKE 'ABC🥕_123' ESCAPE '🥕'", app_props()), + false = match("product_id LIKE 'ABC🥕%123' ESCAPE '🥕'", app_props()), + + %% NOT LIKE + true = match("country NOT LIKE 'US'", app_props()), + false = match("country NOT LIKE 'U_'", app_props()), + false = match("country NOT LIKE '%U%'", app_props()), + false = match("country NOT LIKE 'U%K'", app_props()), + true = match("country NOT LIKE 'U%S'", app_props()), + true = match("country NOT LIKE 'z_🇬🇧' ESCAPE 'z'", [{{utf8, <<"country">>}, {utf8, <<"a🇬🇧"/utf8>>}}]), + false = match("country NOT LIKE 'z_🇬🇧' ESCAPE 'z'", [{{utf8, <<"country">>}, {utf8, <<"_🇬🇧"/utf8>>}}]), + + %% "If identifier of a LIKE or NOT LIKE operation is NULL, the value of the operation is unknown." + false = match("absent LIKE '%'", app_props()), + false = match("absent NOT LIKE '%'", app_props()), + false = match("missing LIKE '%'", app_props()), + false = match("missing NOT LIKE '%'", app_props()), + + %% Combined with other operators + true = match("description LIKE '%test%' AND country = 'UK'", app_props()), + true = match("(city LIKE 'Paris') OR (description LIKE '%test%')", app_props()), + true = match("city LIKE 'Paris' OR description LIKE '%test%'", app_props()). + +in_operator(_Config) -> + AppPropsUtf8 = [{{utf8, <<"country">>}, {utf8, <<"🇬🇧"/utf8>>}}], + + %% Basic IN operations + true = match("country IN ('US', 'UK', 'France')", app_props()), + true = match("country IN ('UK')", app_props()), + true = match("country IN ('🇫🇷', '🇬🇧')", AppPropsUtf8), + false = match("country IN ('US', 'France')", app_props()), + + %% NOT IN + true = match("country NOT IN ('US', 'France', 'Germany')", app_props()), + true = match("country NOT IN ('🇬🇧')", app_props()), + false = match("country NOT IN ('🇫🇷', '🇬🇧')", AppPropsUtf8), + false = match("country NOT IN ('US', 'UK', 'France')", app_props()), + + %% Combined with other operators + true = match("country IN ('UK', 'US') AND weight > 3", app_props()), + true = match("city IN ('Berlin', 'Paris') OR country IN ('UK', 'US')", app_props()), + + %% "If identifier of an IN or NOT IN operation is NULL, the value of the operation is unknown." + false = match("missing IN ('UK', 'US')", app_props()), + false = match("absent IN ('UK', 'US')", app_props()), + false = match("missing NOT IN ('UK', 'US')", app_props()), + false = match("absent NOT IN ('UK', 'US')", app_props()). + +between_operator(_Config) -> + %% Basic BETWEEN operations + true = match("weight BETWEEN 3 AND 7", app_props()), + true = match("weight BETWEEN 5 AND 7", app_props()), + true = match("weight BETWEEN 3 AND 5", app_props()), + false = match("weight BETWEEN 6 AND 10", app_props()), + true = match("price BETWEEN 10 AND 11", app_props()), + true = match("price BETWEEN 10 AND 10.5", app_props()), + false = match("price BETWEEN -1 AND 10", app_props()), + false = match("score BETWEEN tiny_value AND quantity", app_props()), + true = match("score BETWEEN -tiny_value AND quantity", app_props()), + + %% NOT BETWEEN + true = match("weight NOT BETWEEN 6 AND 10", app_props()), + false = match("weight NOT BETWEEN 3 AND 7", app_props()), + false = match("weight NOT BETWEEN 3 AND 5", app_props()), + true = match("score NOT BETWEEN tiny_value AND quantity", app_props()), + false = match("score NOT BETWEEN -tiny_value AND quantity", app_props()), + + %% Combined with other operators + true = match("weight BETWEEN 4 AND 6 AND country = 'UK'", app_props()), + true = match("(price BETWEEN 20 AND 30) OR (weight BETWEEN 5 AND 6)", app_props()), + + %% "a string cannot be used in an arithmetic expression" + false = match("weight BETWEEN 1 AND 'Z'", app_props()), + false = match("country BETWEEN 'A' AND 'Z'", app_props()), + + %% "Comparison or arithmetic with an unknown value always yields an unknown value." + false = match("weight BETWEEN absent AND 10", app_props()), + false = match("weight BETWEEN 2 AND absent", app_props()), + false = match("weight BETWEEN absent AND absent", app_props()), + false = match("absent BETWEEN 2 AND 10", app_props()), + false = match("weight NOT BETWEEN absent AND 10", app_props()), + false = match("weight NOT BETWEEN 2 AND absent", app_props()), + false = match("weight NOT BETWEEN absent AND absent", app_props()), + false = match("absent NOT BETWEEN 2 AND 10", app_props()). + +null_handling(_Config) -> + %% IS NULL / IS NOT NULL + true = match("missing IS NULL", app_props()), + true = match("absent IS NULL", app_props()), + false = match("country IS NULL", app_props()), + true = match("country IS NOT NULL", app_props()), + false = match("missing IS NOT NULL", app_props()), + false = match("absent IS NOT NULL", app_props()), + true = match("country = 'UK' AND missing IS NULL", app_props()), + true = match("country = 'France' OR weight IS NOT NULL", app_props()), + + %% "SQL treats a NULL value as unknown. + %% Comparison or arithmetic with an unknown value always yields an unknown value." + false = match("missing > 0", app_props()), + false = match("0 < missing", app_props()), + false = match("0 > absent", app_props()), + false = match("0 = missing", app_props()), + false = match("missing >= 0", app_props()), + false = match("missing < 0", app_props()), + false = match("missing <= 0", app_props()), + false = match("missing = 0", app_props()), + false = match("missing <> 0", app_props()), + false = match("missing = missing", app_props()), + false = match("absent = absent", app_props()), + false = match("missing AND true", app_props()), + false = match("missing OR false", app_props()). + +literals(_Config) -> + %% Exact numeric literals + true = match("5 = 5", app_props()), + true = match("weight = 5", app_props()), + + %% "Approximate literals use the Java floating-point literal syntax." + true = match("10.5 = 10.5", app_props()), + true = match("price = 10.5", app_props()), + true = match("5.0 > 4.999", app_props()), + true = match("10 = 10.", app_props()), + true = match("0 = 0.0", app_props()), + true = match("0 = 0.", app_props()), + true = match("0 = .0", app_props()), + + true = match("weight = 5.0", app_props()), % int = float + true = match("5. = weight", app_props()), % float = int + + %% String literals + true = match("'UK' = 'UK'", app_props()), + true = match("country = 'UK'", app_props()), + + %% Boolean literals + true = match("TRUE = TRUE", app_props()), + true = match("active = TRUE", app_props()), + true = match("TRUE", app_props()), + true = match("active", app_props()), + true = match("FALSE = FALSE", app_props()), + true = match("premium = FALSE", app_props()), + false = match("FALSE", app_props()), + false = match("premium", app_props()), + + %% Literals in expressions + true = match("weight + 2 > 6", app_props()), + true = match("price * 2 > 20.0", app_props()), + true = match("'UK' <> 'US'", app_props()). + +scientific_notation(_Config) -> + %% Basic scientific notation comparisons + true = match("distance = 1.2E6", app_props()), + true = match("distance = 1200000.0", app_props()), + true = match("tiny_value = 3.5E-4", app_props()), + true = match("tiny_value = 0.00035", app_props()), + + %% Scientific notation literals in expressions + true = match("1.2E3 = 1200", app_props()), + true = match("5E2 = 500", app_props()), + true = match("5.E2 = 500", app_props()), + true = match("-5E-2 = -0.05", app_props()), + true = match("-5.E-2 = -0.05", app_props()), + true = match(".5E-1 = 0.05", app_props()), + true = match("-.5E-1 = -0.05", app_props()), + true = match("1E0 = 1", app_props()), + + %% Arithmetic with scientific notation + true = match("distance / 1.2E5 = 10", app_props()), + true = match("tiny_value * 1E6 = 350", app_props()), + true = match("1.5E2 + 2.5E2 = 400", app_props()), + true = match("3E3 - 2E3 = 1000", app_props()), + + %% Comparisons with scientific notation + true = match("distance > 1E6", app_props()), + true = match("tiny_value < 1E-3", app_props()), + true = match("distance BETWEEN 1E6 AND 2E6", app_props()), + + %% Mixed numeric formats + true = match("distance / 1200 = 1000", app_props()), + true = match("large_value + tiny_value >= large_value", app_props()), + true = match("large_value + large_value > large_value", app_props()). + +precedence_and_parentheses(_Config) -> + %% Arithmetic precedence + true = match("weight + 2 * 3 = 11", app_props()), + true = match("(weight + 2) * 3 = 21", app_props()), + true = match("weight + weight * quantity - -temperature / 2 = 502.5", app_props()), + + %% "Logical operators in precedence order: NOT, AND, OR" + true = match("NOT country = 'US' AND weight > 3", app_props()), + true = match("weight > 3 AND NOT country = 'US'", app_props()), + true = match("NOT (country = 'US' AND weight > 3)", app_props()), + true = match("NOT country = 'US' OR country = 'France' AND weight > 3", app_props()), + true = match("country = 'France' AND weight > 3 OR NOT country = 'US'", app_props()), + + %% Mixed precedence + true = match("weight * 2 > 5 + 3", app_props()), + true = match("price < 20 OR country = 'US' AND weight > 3", app_props()), + true = match("weight > 3 AND price < 20 OR country = 'US'", app_props()), + false = match("weight > 3 AND (price > 20 OR country = 'US')", app_props()), + + %% Complex parentheses nesting + true = match("((weight > 3) AND (price < -1)) OR ((country = 'UK') AND (city = 'London'))", app_props()), + true = match("weight > 3 AND price < -1 OR country = 'UK' AND city = 'London'", app_props()), + true = match("(weight + (price * 2)) > (score + 15)", app_props()). + +%% "Only like type values can be compared. One exception is that it is +%% valid to compare exact numeric values and approximate numeric values. +%% If the comparison of non-like type values is attempted, the value of the operation is false." +type_handling(_Config) -> + %% Numeric comparisons + true = match("weight = 5", app_props()), % int = int + true = match("weight = 5.0", app_props()), % int = float + true = match("price = 10.5", app_props()), % float = float + + %% String and numeric + false = match("country = 5", app_props()), % string != number + false = match("weight = 'UK'", app_props()), % number != string + + %% Boolean comparisons + true = match("active = TRUE", app_props()), + true = match("active <> FALSE", app_props()), + false = match("TRUE = 1", app_props()), % boolean != number + false = match("active = 1", app_props()), % boolean != number + false = match("TRUE = 'TRUE'", app_props()), % boolean != string + false = match("active = 'TRUE'", app_props()), % boolean != string + + %% Type-specific operators + true = match("description LIKE '%test%'", app_props()), % LIKE only works on strings + false = match("weight LIKE '5'", app_props()), % LIKE doesn't work on numbers + + %% Arithmetic with different types + true = match("weight + price = 15.5", app_props()), % int + float = float + true = match("weight * discount = 1.25", app_props()), % int * float = float + + %% Division by zero is undefined + false = match("weight / 0 > 0", app_props()), + false = match("weight / score = 5", app_props()), + false = match("0 / 0 = 0", app_props()), + false = match("0 / 0.0 = 0", app_props()), + false = match("0 / 0. = 0", app_props()), + false = match("-1 / 0 = 0", app_props()), + false = match("score / score = score", app_props()), + + true = match("0.0 / 1 = 0", app_props()), + + %% Type incompatibility + false = match("country + weight = 'UK5'", app_props()), % can't add string and number + false = match("active + premium = 1", app_props()). % can't add booleans + +complex_expressions(_Config) -> + true = match( + "country = 'UK' AND price > 10.0 AND (weight BETWEEN 4 AND 6) AND description LIKE '%test%'", + app_props() + ), + true = match( + "(country IN ('UK', 'US') OR city = 'London') AND (weight * 2 >= 10) AND NOT premium", + app_props() + ), + true = match( + "price * quantity * (1 - discount) > 500", + app_props() + ), + true = match( + "country = 'UK' AND (city = 'London' OR description LIKE '%test%') AND" ++ + "(weight > 3 OR premium = TRUE) AND price <= 20", + app_props() + ), + true = match( + "percentage >= 0 AND percentage <= 100 AND weight + temperature = 0", + app_props() + ), + true = match( + "((country = 'UK' OR country = 'US') AND (city IN ('London', 'New York', 'Paris'))) OR " ++ + "(price * (1 - discount) < 10.0 AND quantity > 50 AND description LIKE '%test%') OR " ++ + "(active = TRUE AND premium = FALSE AND (weight BETWEEN 4 AND 10))", + app_props() + ). + +%% "Predefined selector literals and operator names are [...] case insensitive." +%% "Identifiers are case sensitive." +case_sensitivity(_Config) -> + AppProps = app_props(), + + %% 1. Test that operators and literals are case insensitive + true = match("country = 'UK' AnD weight = 5", AppProps), + true = match("country = 'UK' and weight = 5", AppProps), + true = match("country = 'France' Or weight < 6", AppProps), + true = match("country = 'France' or weight < 6", AppProps), + true = match("NoT country = 'France'", AppProps), + true = match("not country = 'France'", AppProps), + true = match("weight BeTwEeN 3 AnD 7", AppProps), + true = match("weight between 3 AnD 7", AppProps), + true = match("description LiKe '%test%'", AppProps), + true = match("description like '%test%'", AppProps), + true = match("country In ('US', 'UK', 'France')", AppProps), + true = match("country in ('US', 'UK', 'France')", AppProps), + true = match("missing Is NuLl", AppProps), + true = match("missing is null", AppProps), + true = match("active = TrUe", AppProps), + true = match("active = true", AppProps), + true = match("premium = FaLsE", AppProps), + true = match("premium = false", AppProps), + true = match("distance = 1.2e6", app_props()), + true = match("tiny_value = 3.5e-4", app_props()), + true = match("3 = 3e0", app_props()), + true = match("3 = 3e-0", app_props()), + true = match("300 = 3e2", app_props()), + true = match("0.03 = 3e-2", app_props()), + + %% 2. Test that identifiers are case sensitive + AppPropsCaseSensitiveKeys = AppProps ++ [{{utf8, <<"COUNTRY">>}, {utf8, <<"France">>}}, + {{utf8, <<"Weight">>}, {uint, 10}}], + + true = match("country = 'UK'", AppPropsCaseSensitiveKeys), + true = match("COUNTRY = 'France'", AppPropsCaseSensitiveKeys), + true = match("Weight = 10", AppPropsCaseSensitiveKeys), + + false = match("COUNTRY = 'UK'", AppPropsCaseSensitiveKeys), + false = match("country = 'France'", AppPropsCaseSensitiveKeys), + false = match("weight = 10", AppPropsCaseSensitiveKeys), + false = match("WEIGHT = 5", AppPropsCaseSensitiveKeys), + + true = match( + "country = 'UK' aNd COUNTRY = 'France' and (weight Between 4 AnD 6) AND Weight = 10", + AppPropsCaseSensitiveKeys + ). + +%% "Whitespace is the same as that defined for Java: +%% space, horizontal tab, form feed and line terminator." +whitespace_handling(_Config) -> + %% 1. Space + true = match("country = 'UK'", app_props()), + + %% 2. Multiple spaces + true = match("country = 'UK'", app_props()), + + %% 3. Horizontal tab (\t) + true = match("country\t=\t'UK'", app_props()), + + %% 4. Form feed (\f) + true = match("country\f=\f'UK'", app_props()), + + %% 5. Line terminators (\n line feed, \r carriage return) + true = match("country\n=\n'UK'", app_props()), + true = match("country\r=\r'UK'", app_props()), + + %% 6. Mixed whitespace + true = match("country \t\f\n\r = \t\f\n\r 'UK'", app_props()), + + %% 7. Complex expression with various whitespace + true = match("country\t=\t'UK'\nAND\rweight\f>\t3", app_props()), + + %% 8. Ensure whitespace is not required + true = match("country='UK'AND weight=5", app_props()), + + %% 9. Whitespace inside string literals should be preserved + true = match("description = 'This is a test message'", app_props()), + + %% 10. Whitespace at beginning and end of expression + true = match(" \t\n\r country = 'UK' \t\n\r ", app_props()). + +%% "An identifier is an unlimited-length character sequence that must begin with a +%% Java identifier start character; all following characters must be Java identifier +%% part characters. An identifier start character is any character for which the method +%% Character.isJavaIdentifierStart returns true. This includes '_' and '$'. An +%% identifier part character is any character for which the method +%% Character.isJavaIdentifierPart returns true." +identifier_rules(_Config) -> + Identifiers = [<<"simple">>, + <<"a1b2c3">>, + <<"x">>, + <<"_underscore">>, + <<"$dollar">>, + <<"_">>, + <<"$">>, + <<"with_underscore">>, + <<"with$dollar">>, + <<"mixed_$_identifiers_$_123">>], + AppProps = [{{utf8, Id}, {utf8, <<"value">>}} || Id <- Identifiers], + true = match("simple = 'value'", AppProps), + true = match("a1b2c3 = 'value'", AppProps), + true = match("x = 'value'", AppProps), + true = match("_underscore = 'value'", AppProps), + true = match("$dollar = 'value'", AppProps), + true = match("_ = 'value'", AppProps), + true = match("$ = 'value'", AppProps), + true = match("with_underscore = 'value'", AppProps), + true = match("with$dollar = 'value'", AppProps), + true = match("mixed_$_identifiers_$_123 = 'value'", AppProps). + +header_section(_Config) -> + Hdr = #'v1_0.header'{priority = {ubyte, 7}}, + Ps = #'v1_0.properties'{}, + APs = [], + true = match("header.priority > 5", Hdr, Ps, APs), + true = match("header.priority = 7", Hdr, Ps, APs), + false = match("header.priority < 7", Hdr, Ps, APs), + + %% Since the default priority is 4 in both AMQP and JMS, we expect the + %% following expression to evaluate to true if matched against a message + %% without an explicit priority level set. + true = match("header.priority = 4", []). + +properties_section(_Config) -> + Ps = #'v1_0.properties'{ + message_id = {utf8, <<"id-123">>}, + user_id = {binary,<<"some user ID">>}, + to = {utf8, <<"to some queue">>}, + subject = {utf8, <<"some subject">>}, + reply_to = {utf8, <<"reply to some topic">>}, + correlation_id = {ulong, 789}, + content_type = {symbol, <<"text/plain">>}, + content_encoding = {symbol, <<"deflate">>}, + absolute_expiry_time = {timestamp, 1311999988888}, + creation_time = {timestamp, 1311704463521}, + group_id = {utf8, <<"some group ID">>}, + group_sequence = {uint, 999}, + reply_to_group_id = {utf8, <<"other group ID">>}}, + APs = [], + + true = match("properties.message-id = 'id-123'", Ps, APs), + false = match("'id-123' <> properties.message-id", Ps, APs), + true = match("properties.message-id LIKE 'id-%'", Ps, APs), + true = match("properties.message-id IN ('id-123', 'id-456')", Ps, APs), + + true = match("properties.user-id = 'some user ID'", Ps, APs), + true = match("properties.user-id LIKE '%user%'", Ps, APs), + false = match("properties.user-id = 'other user ID'", Ps, APs), + + true = match("properties.to = 'to some queue'", Ps, APs), + true = match("properties.to LIKE 'to some%'", Ps, APs), + true = match("properties.to NOT LIKE '%topic'", Ps, APs), + + true = match("properties.subject = 'some subject'", Ps, APs), + true = match("properties.subject LIKE '%subject'", Ps, APs), + true = match("properties.subject IN ('some subject', 'other subject')", Ps, APs), + + true = match("properties.reply-to = 'reply to some topic'", Ps, APs), + true = match("properties.reply-to LIKE 'reply%topic'", Ps, APs), + false = match("properties.reply-to LIKE 'reply%queue'", Ps, APs), + + true = match("properties.correlation-id = 789", Ps, APs), + true = match("500 < properties.correlation-id", Ps, APs), + true = match("properties.correlation-id BETWEEN 700 AND 800", Ps, APs), + false = match("properties.correlation-id < 700", Ps, APs), + + true = match("properties.content-type = 'text/plain'", Ps, APs), + true = match("properties.content-type LIKE 'text/%'", Ps, APs), + true = match("properties.content-type IN ('text/plain', 'text/html')", Ps, APs), + + true = match("'deflate' = properties.content-encoding", Ps, APs), + false = match("properties.content-encoding = 'gzip'", Ps, APs), + true = match("properties.content-encoding NOT IN ('gzip', 'compress')", Ps, APs), + + true = match("properties.absolute-expiry-time = 1311999988888", Ps, APs), + true = match("properties.absolute-expiry-time > 1311999988000", Ps, APs), + true = match("properties.absolute-expiry-time BETWEEN 1311999988000 AND 1311999989000", Ps, APs), + + true = match("properties.creation-time = 1311704463521", Ps, APs), + true = match("properties.creation-time < 1311999988888", Ps, APs), + true = match("properties.creation-time NOT BETWEEN 1311999988000 AND 1311999989000", Ps, APs), + + true = match("properties.group-id = 'some group ID'", Ps, APs), + true = match("properties.group-id LIKE 'some%ID'", Ps, APs), + false = match("properties.group-id = 'other group ID'", Ps, APs), + + true = match("properties.group-sequence = 999", Ps, APs), + true = match("properties.group-sequence >= 999", Ps, APs), + true = match("properties.group-sequence BETWEEN 900 AND 1000", Ps, APs), + false = match("properties.group-sequence > 999", Ps, APs), + + true = match("properties.reply-to-group-id = 'other group ID'", Ps, APs), + true = match("properties.reply-to-group-id LIKE '%group ID'", Ps, APs), + true = match("properties.reply-to-group-id <> 'some group ID'", Ps, APs), + true = match("properties.reply-to-group-id IS NOT NULL", Ps, APs), + false = match("properties.reply-to-group-id IS NULL", Ps, APs), + + true = match("properties.message-id = 'id-123' and 'some subject' = properties.subject", Ps, APs), + true = match("properties.group-sequence < 500 or properties.correlation-id > 700", Ps, APs), + true = match("(properties.content-type LIKE 'text/%') AND properties.content-encoding = 'deflate'", Ps, APs), + + true = match("properties.subject IS NULL", #'v1_0.properties'{}, APs), + false = match("properties.subject IS NOT NULL", #'v1_0.properties'{}, APs). + +multiple_sections(_Config) -> + Hdr = #'v1_0.header'{durable = true, + priority = {ubyte, 7}}, + Ps = #'v1_0.properties'{ + message_id = {utf8, <<"id-123">>}, + user_id = {binary,<<"some user ID">>}, + to = {utf8, <<"to some queue">>}, + subject = {utf8, <<"some subject">>}, + reply_to = {utf8, <<"reply to some topic">>}, + correlation_id = {ulong, 789}, + content_type = {symbol, <<"text/plain">>}, + content_encoding = {symbol, <<"deflate">>}, + absolute_expiry_time = {timestamp, 1311999988888}, + creation_time = {timestamp, 1311704463521}, + group_id = {utf8, <<"some group ID">>}, + group_sequence = {uint, 999}, + reply_to_group_id = {utf8, <<"other group ID">>}}, + APs = [{{utf8, <<"key_1">>}, {byte, -1}}], + + true = match("-1.0 = key_1 AND 4 < header.priority AND properties.group-sequence > 90", Hdr, Ps, APs), + false = match("-1.0 = key_1 AND 4 < header.priority AND properties.group-sequence < 90", Hdr, Ps, APs). + +parse_errors(_Config) -> + %% Parsing a non-UTF-8 encoded message selector should fail. + ?assertEqual(error, parse([255])), + %% Invalid token. + ?assertEqual(error, parse("!!!")), + %% Invalid grammar. + ?assertEqual(error, parse("AND NOT")), + %% Escape charater at end of pattern hould fail because it doesn't make any sense. + ?assertEqual(error, parse("id LIKE 'pattern*' ESCAPE '*'")), + ?assertEqual(error, parse("id LIKE '_pattern*' ESCAPE '*'")), + %% Control characters in user provided pattern shouldn't be allowed. + ?assertEqual(error, parse("id LIKE '\n'")), + ?assertEqual(error, parse("id LIKE '\r'")), + ?assertEqual(error, parse("id LIKE '_\n'")), + ?assertEqual(error, parse("id LIKE '%\r'")), + ?assertEqual(error, parse("id LIKE '!\r' ESCAPE '!'")), + ?assertEqual(error, parse("id LIKE '_!\r' ESCAPE '!'")), + ok. + +%%%=================================================================== +%%% Helpers +%%%=================================================================== + +app_props() -> + [ + %% String or symbolic values + {{utf8, <<"country">>}, {symbol, <<"UK">>}}, + {{utf8, <<"city">>}, {utf8, <<"London">>}}, + {{utf8, <<"description">>}, {utf8, <<"This is a test message">>}}, + {{utf8, <<"currency">>}, {symbol, <<"GBP">>}}, + {{utf8, <<"product_id">>}, {symbol, <<"ABC_123">>}}, + + %% Numeric values + {{utf8, <<"weight">>}, {ushort, 5}}, + {{utf8, <<"price">> }, {double, 10.5}}, + {{utf8, <<"quantity">>}, {uint, 100}}, + {{utf8, <<"discount">>}, {double, 0.25}}, + {{utf8, <<"temperature">>}, {int, -5}}, + {{utf8, <<"score">>}, {ulong, 0}}, + %% Scientific notation values + {{utf8, <<"distance">>}, {float, 1.2E6}}, % 1,200,000 + {{utf8, <<"tiny_value">>}, {double, 3.5E-4}}, % 0.00035 + {{utf8, <<"large_value">>}, {double, 6.02E23}}, % Avogadro's number + + %% Boolean values + {{utf8, <<"active">>}, true}, + {{utf8, <<"premium">>}, {boolean, false}}, + + %% Special cases + {{utf8, <<"missing">>}, null}, + {{utf8, <<"percentage">>}, {ubyte, 75}} + ]. + +match(Selector, AppProps) -> + match(Selector, #'v1_0.properties'{}, AppProps). + +match(Selector, Props, AppProps) -> + match(Selector, #'v1_0.header'{}, Props, AppProps). + +match(Selector, Header, Props, AppProps) + when is_list(AppProps) -> + {ok, ParsedSelector} = parse(Selector), + AP = #'v1_0.application_properties'{content = AppProps}, + Body = #'v1_0.amqp_value'{content = {symbol, <<"some message body">>}}, + Sections = [Header, Props, AP, Body], + Payload = amqp_encode_bin(Sections), + Mc = mc_amqp:init_from_stream(Payload, #{}), + rabbit_amqp_filter_jms:eval(ParsedSelector, Mc). + +parse(Selector) -> + Descriptor = {ulong, ?DESCRIPTOR_CODE_SELECTOR_FILTER}, + Filter = {described, Descriptor, {utf8, Selector}}, + rabbit_amqp_filter_jms:parse(Filter). + +amqp_encode_bin(L) when is_list(L) -> + iolist_to_binary([amqp10_framing:encode_bin(X) || X <- L]). diff --git a/deps/rabbitmq_stream/test/protocol_interop_SUITE.erl b/deps/rabbitmq_stream/test/protocol_interop_SUITE.erl index 3db855f55e2d..c5932d8ce351 100644 --- a/deps/rabbitmq_stream/test/protocol_interop_SUITE.erl +++ b/deps/rabbitmq_stream/test/protocol_interop_SUITE.erl @@ -14,7 +14,7 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). -include_lib("amqp10_common/include/amqp10_framing.hrl"). --include_lib("amqp10_common/include/amqp10_filtex.hrl"). +-include_lib("amqp10_common/include/amqp10_filter.hrl"). all() -> [{group, tests}].