module FoodFishParser::Strict::Grammar
grammar Root include Common include FishName include CatchArea include CatchMethod include AquacArea include AquacMethod # Regular root node that requires all text to match fish details. # # Note that here we prefer fish with catch or aquaculture info, # then try fish names, and finally only catch or aquaculture info. # # The assumption is that all declared fish would have the same amount # of information. Hence we first try for all info, then resort to partial # info. rule root ( ( fish_with_info ( ws* fish_sep ws* fish_with_info )* ) / ( fish_names_both ( ws* fish_sep ws* fish_names_both )* ) / ( fish_names_latin ( ws* fish_sep ws* fish_names_latin )* ) / ( fish_only_info ( ws* fish_sep ws* fish_only_info )* ) / ( fish_names_nl ( ws* fish_sep ws* fish_names_nl )* ) ) ws* '.'? ws* <RootNode> end # Alternate root node that allows fish details to be interspaced with other text. # # Note that this can be a much more expensive operation. rule root_anywhere ( ( ( !char . )* ( !fish_with_info char+ ( !char . )+ )+ )* fish_with_info ( ( !char . )+ ( !fish_with_info char+ ( !char . )+ )* fish_with_info )* !char / ( ( !char . )* ( !fish_names_both char+ ( !char . )+ )+ )* fish_names_both ( ( !char . )+ ( !fish_names_both char+ ( !char . )+ )* fish_names_both )* !char / ( ( !char . )* ( !fish_names_latin char+ ( !char . )+ )+ )* fish_names_latin ( ( !char . )+ ( !fish_names_latin char+ ( !char . )+ )* fish_names_latin )* !char / ( ( !char . )* ( !fish_only_info char+ ( !char . )+ )+ )* fish_only_info ( ( !char . )+ ( !fish_only_info char+ ( !char . )+ )* fish_only_info )* !char / ( ( !char . )* ( !fish_names_nl char+ ( !char . )+ )+ )* fish_names_nl ( ( !char . )+ ( !fish_names_nl char+ ( !char . )+ )* fish_names_nl )* !char ) <RootNode> end # separator between fish declarations rule fish_sep and_or / '.' / ';' / comma end # fish with catch or aquaculture info rule fish_with_info ( # @todo move optional '(' after common fish name to root and properly match start and end brackets ( fish_name_any_list ( ws* ( comma / ':' ) )? ws+ fish_catch_info ( ws* ')' )? ) / ( fish_name_any_list ( ws* ( comma / ':' ) )? ws+ fish_aquac_info ( ws* ')' )? ) ) <FishNode> end # fish names common and latin rule fish_names_both fish_name_both_list <FishNode> end # fish names Latin only rule fish_names_latin fish_name_latin_list <FishNode> end # fish names NL only rule fish_names_nl fish_name_nl_list <FishNode> end # catch or aquaculture info only (no names) rule fish_only_info ( fish_catch_info / fish_aquac_info ) <FishNode> end rule fish_catch_info ( catch_method_indicator ws* catch_method_content ( ( ws* comma )? ws+ catch_area_indicator_short ws* catch_area_content )? ) / ( catch_area_indicator ws* catch_area_content ( ( ws* comma )? ws+ catch_method_indicator_short ws* catch_method_content )? ) end rule fish_aquac_info ( aquac_area_indicator ws* aquac_area_content ws* '.' ws* aquac_method_indicator ws* aquac_method_content ) / ( aquac_area_indicator ws* aquac_area_content ( ( ws* comma )? ws+ aquac_method_indicator ws* aquac_method_content )? ) / ( aquac_method_indicator ws* aquac_method_content ( ( ws* comma )? ws+ aquac_area_indicator_short ws* aquac_area_content )? ) end end
end