1 #include "Parse.h"
2 
3 #include "ParseImpl.h"
4 #include "EnumParser.h"
5 #include "ValueRefParser.h"
6 #include "EnumValueRefRules.h"
7 #include "EffectParser.h"
8 #include "ConditionParserImpl.h"
9 #include "MovableEnvelope.h"
10 
11 #include "../universe/Condition.h"
12 #include "../universe/Effect.h"
13 #include "../universe/Species.h"
14 #include "../util/Directories.h"
15 
16 #include <boost/spirit/include/phoenix.hpp>
17 
18 
19 #define DEBUG_PARSERS 0
20 
21 #if DEBUG_PARSERS
22 namespace std {
operator <<(ostream & os,const FocusType &)23     inline ostream& operator<<(ostream& os, const FocusType&) { return os; }
operator <<(ostream & os,const std::vector<FocusType> &)24     inline ostream& operator<<(ostream& os, const std::vector<FocusType>&) { return os; }
operator <<(ostream & os,const parse::effects_group_payload &)25     inline ostream& operator<<(ostream& os, const parse::effects_group_payload&) { return os; }
operator <<(ostream & os,const std::pair<PlanetType,PlanetEnvironment> &)26     inline ostream& operator<<(ostream& os, const std::pair<PlanetType, PlanetEnvironment>&) { return os; }
operator <<(ostream & os,const std::pair<const PlanetType,PlanetEnvironment> &)27     inline ostream& operator<<(ostream& os, const std::pair<const PlanetType, PlanetEnvironment>&) { return os; }
operator <<(ostream & os,const std::map<PlanetType,PlanetEnvironment> &)28     inline ostream& operator<<(ostream& os, const std::map<PlanetType, PlanetEnvironment>&) { return os; }
operator <<(ostream & os,const std::pair<const std::string,std::unique_ptr<Species>> &)29     inline ostream& operator<<(ostream& os, const std::pair<const std::string, std::unique_ptr<Species>>&) { return os; }
operator <<(ostream & os,const std::map<std::string,std::unique_ptr<Species>> &)30     inline ostream& operator<<(ostream& os, const std::map<std::string, std::unique_ptr<Species>>&) { return os; }
31 }
32 #endif
33 
34 namespace {
35     const boost::phoenix::function<parse::detail::is_unique> is_unique_;
36 
37     struct SpeciesStuff {
SpeciesStuff__anonf5bd12b80111::SpeciesStuff38         SpeciesStuff(const boost::optional<std::vector<FocusType>>& foci_,
39                      const boost::optional<std::string>& preferred_focus_,
40                      const std::set<std::string>& tags_,
41                      const std::string& graphic_) :
42             foci(foci_),
43             preferred_focus(preferred_focus_),
44             tags(tags_),
45             graphic(graphic_)
46         {}
47 
48         boost::optional<std::vector<FocusType>> foci;
49         boost::optional<std::string>            preferred_focus;
50         std::set<std::string>                   tags;
51         std::string                             graphic;
52     };
53 
54 
insert_species(std::map<std::string,std::unique_ptr<Species>> & species,const SpeciesStrings & strings,const boost::optional<std::map<PlanetType,PlanetEnvironment>> & planet_environments,const boost::optional<parse::effects_group_payload> & effects,boost::optional<parse::detail::MovableEnvelope<Condition::Condition>> & combat_targets,const SpeciesParams & params,const SpeciesStuff & foci_preferred_tags_graphic,bool & pass)55     void insert_species(
56         std::map<std::string, std::unique_ptr<Species>>& species,
57         const SpeciesStrings& strings,
58         const boost::optional<std::map<PlanetType, PlanetEnvironment>>& planet_environments,
59         const boost::optional<parse::effects_group_payload>& effects,
60         boost::optional<parse::detail::MovableEnvelope<Condition::Condition>>& combat_targets,
61         const SpeciesParams& params,
62         const SpeciesStuff& foci_preferred_tags_graphic,
63         bool& pass)
64     {
65         auto species_ptr = std::make_unique<Species>(
66             strings,
67             (foci_preferred_tags_graphic.foci ? *foci_preferred_tags_graphic.foci : std::vector<FocusType>()),
68             (foci_preferred_tags_graphic.preferred_focus ? *foci_preferred_tags_graphic.preferred_focus : std::string()),
69             (planet_environments ? *planet_environments : std::map<PlanetType, PlanetEnvironment>()),
70             (effects ? OpenEnvelopes(*effects, pass) : std::vector<std::unique_ptr<Effect::EffectsGroup>>()),
71             (combat_targets ? (*combat_targets).OpenEnvelope(pass) : nullptr),
72             params,
73             foci_preferred_tags_graphic.tags,
74             foci_preferred_tags_graphic.graphic);
75 
76         species.insert(std::make_pair(species_ptr->Name(), std::move(species_ptr)));
77     }
78 
79     BOOST_PHOENIX_ADAPT_FUNCTION(void, insert_species_, insert_species, 8)
80 
81 
82     using start_rule_payload = std::pair<
83         std::map<std::string, std::unique_ptr<Species>>, // species_by_name
84         std::vector<std::string> // census ordering
85     >;
86     using start_rule_signature = void(start_rule_payload::first_type&);
87 
88     struct grammar : public parse::detail::grammar<start_rule_signature> {
grammar__anonf5bd12b80111::grammar89         grammar(const parse::lexer& tok,
90                 const std::string& filename,
91                 const parse::text_iterator& first, const parse::text_iterator& last) :
92             grammar::base_type(start),
93             condition_parser(tok, label),
94             string_grammar(tok, label, condition_parser),
95             tags_parser(tok, label),
96             effects_group_grammar(tok, label, condition_parser, string_grammar),
97             one_or_more_foci(focus_type),
98             planet_type_rules(tok, label, condition_parser),
99             planet_environment_rules(tok, label, condition_parser)
100         {
101             namespace phoenix = boost::phoenix;
102             namespace qi = boost::spirit::qi;
103 
104             using phoenix::construct;
105             using phoenix::insert;
106             using phoenix::push_back;
107 
108             qi::_1_type _1;
109             qi::_2_type _2;
110             qi::_3_type _3;
111             qi::_4_type _4;
112             qi::_5_type _5;
113             qi::_6_type _6;
114             qi::_7_type _7;
115             qi::_8_type _8;
116             qi::_9_type _9;
117             qi::_pass_type _pass;
118             qi::_r1_type _r1;
119             qi::_val_type _val;
120             qi::eps_type eps;
121             qi::matches_type matches_;
122             qi::omit_type omit_;
123             qi::as_string_type as_string_;
124             const boost::phoenix::function<parse::detail::deconstruct_movable> deconstruct_movable_;
125 
126             focus_type
127                 =  ( omit_[tok.Focus_]
128                 >    label(tok.Name_)        > tok.string
129                 >    label(tok.Description_) > tok.string
130                 >    label(tok.Location_)    > condition_parser
131                 >    label(tok.Graphic_)     > tok.string
132                 ) [ _val = construct<FocusType>(_1, _2, deconstruct_movable_(_3, _pass), _4) ]
133                 ;
134 
135             foci
136                 =    label(tok.Foci_)
137                 >    one_or_more_foci
138                 ;
139 
140             environment_map_element
141                 =  ( label(tok.Type_)        > planet_type_rules.enum_expr
142                 >    label(tok.Environment_) > planet_environment_rules.enum_expr
143                 ) [ _val = construct<std::pair<PlanetType, PlanetEnvironment>>(_1, _2) ]
144                 ;
145 
146             environment_map
147                 =    ('[' > +environment_map_element [ insert(_val, _1) ] > ']')
148                 |     environment_map_element [ insert(_val, _1) ]
149                 ;
150 
151             species_params
152                 =   (matches_[tok.Playable_]
153                 >    matches_[tok.Native_]
154                 >    matches_[tok.CanProduceShips_]
155                 >    matches_[tok.CanColonize_]
156                     ) [ _val = construct<SpeciesParams>(_1, _2, _4, _3) ]
157                 ;
158 
159             species_strings
160                 =  ( tok.Species_
161                 >    label(tok.Name_)                   > tok.string
162                 >    label(tok.Description_)            > tok.string
163                 >    label(tok.Gameplay_Description_)   > tok.string
164                    ) [ _pass = is_unique_(_r1, _1, _2),
165                        _val = construct<SpeciesStrings>(_2, _3, _4) ]
166                 ;
167 
168             species
169                 = ( species_strings(_r1)// _1
170                 >   species_params      // _2
171                 >   tags_parser         // _3
172                 >  -foci                // _4
173                 >  -as_string_[(label(tok.PreferredFocus_)  >   tok.string )]           // _5
174                 > -(label(tok.EffectsGroups_)               >   effects_group_grammar)  // _6
175                 > -(label(tok.CombatTargets_)               >   condition_parser)       // _7
176                 > -(label(tok.Environments_)                >   environment_map)        // _8
177                 >   label(tok.Graphic_)                     >   tok.string              // _9
178                   ) [ insert_species_(_r1, _1, _8, _6, _7, _2,
179                                       construct<SpeciesStuff>(_4, _5, _3, _9),
180                                       _pass) ]
181                 ;
182 
183             start
184                 = +species(_r1)
185                 ;
186 
187             focus_type.name("Focus");
188             foci.name("Foci");
189             environment_map_element.name("Type = <type> Environment = <env>");
190             environment_map.name("Environments");
191             species_params.name("Species Flags");
192             species_strings.name("Species Strings");
193             species.name("Species");
194             start.name("start");
195 
196 #if DEBUG_PARSERS
197             debug(focus_type);
198             debug(foci);
199             debug(environment_map_element);
200             debug(environment_map);
201             debug(species_params);
202             debug(species_strings);
203             debug(species);
204             debug(start);
205 #endif
206 
207             qi::on_error<qi::fail>(start, parse::report_error(filename, first, last, _1, _2, _3, _4));
208         }
209 
210         using focus_type_rule = parse::detail::rule<FocusType ()>;
211         using foci_rule = parse::detail::rule<std::vector<FocusType> ()>;
212         using environment_map_element_rule = parse::detail::rule<std::pair<PlanetType, PlanetEnvironment> ()>;
213         using environment_map_rule = parse::detail::rule<std::map<PlanetType, PlanetEnvironment> ()>;
214         using species_params_rule = parse::detail::rule<SpeciesParams ()>;
215         using species_strings_rule = parse::detail::rule<SpeciesStrings (const start_rule_payload::first_type&)>;
216         using species_rule = parse::detail::rule<void (start_rule_payload::first_type&)>;
217         using start_rule = parse::detail::rule<start_rule_signature>;
218 
219         parse::detail::Labeller                                    label;
220         const parse::conditions_parser_grammar                     condition_parser;
221         const parse::string_parser_grammar                         string_grammar;
222         parse::detail::tags_grammar                                tags_parser;
223         parse::effects_group_grammar                               effects_group_grammar;
224         foci_rule                                                  foci;
225         focus_type_rule                                            focus_type;
226         parse::detail::single_or_bracketed_repeat<focus_type_rule> one_or_more_foci;
227         environment_map_element_rule                               environment_map_element;
228         environment_map_rule                                       environment_map;
229         species_params_rule                                        species_params;
230         species_strings_rule                                       species_strings;
231         species_rule                                               species;
232         start_rule                                                 start;
233         parse::detail::planet_type_parser_rules                    planet_type_rules;
234         parse::detail::planet_environment_parser_rules             planet_environment_rules;
235     };
236 
237     using manifest_start_rule_signature = void (std::vector<std::string>&);
238 
239     struct manifest_grammar : public parse::detail::grammar<manifest_start_rule_signature> {
manifest_grammar__anonf5bd12b80111::manifest_grammar240         manifest_grammar(const parse::lexer& tok,
241                          const std::string& filename,
242                          const parse::text_iterator& first, const parse::text_iterator& last) :
243             manifest_grammar::base_type(start)
244         {
245             namespace phoenix = boost::phoenix;
246             namespace qi = boost::spirit::qi;
247 
248             using phoenix::push_back;
249 
250             qi::_1_type _1;
251             qi::_2_type _2;
252             qi::_3_type _3;
253             qi::_4_type _4;
254             qi::_r1_type _r1;
255             qi::omit_type omit_;
256 
257             species_manifest
258                 =    omit_[tok.SpeciesCensusOrdering_]
259                 >    *(label(tok.Tag_) > tok.string [ push_back(_r1, _1) ])
260                 ;
261 
262             start
263                 =   +species_manifest(_r1)
264                 ;
265 
266             species_manifest.name("ParsedSpeciesCensusOrdering");
267 
268 #if DEBUG_PARSERS
269             debug(species_manifest);
270 #endif
271 
272             qi::on_error<qi::fail>(start, parse::report_error(filename, first, last, _1, _2, _3, _4));
273         }
274 
275         using manifest_rule = parse::detail::rule<void (std::vector<std::string>&)>;
276         using start_rule = parse::detail::rule<manifest_start_rule_signature>;
277 
278         parse::detail::Labeller label;
279         manifest_rule species_manifest;
280         start_rule start;
281     };
282 }
283 
284 namespace parse {
species(const boost::filesystem::path & path)285     start_rule_payload species(const boost::filesystem::path& path) {
286         const lexer lexer;
287         start_rule_payload::first_type species_;
288         start_rule_payload::second_type ordering;
289 
290         boost::filesystem::path manifest_file;
291 
292         for (const auto& file : ListDir(path, IsFOCScript)) {
293             if (file.filename() == "SpeciesCensusOrdering.focs.txt" ) {
294                 manifest_file = file;
295                 continue;
296             }
297 
298             /*auto success =*/ detail::parse_file<grammar, start_rule_payload::first_type>(lexer, file, species_);
299         }
300 
301         if (!manifest_file.empty()) {
302             try {
303                 /*auto success =*/ detail::parse_file<manifest_grammar, start_rule_payload::second_type>(
304                     lexer, manifest_file, ordering);
305 
306             } catch (const std::runtime_error& e) {
307                 ErrorLogger() << "Failed to species census manifest in " << manifest_file << " from " << path
308                               << " because " << e.what();
309             }
310         }
311 
312         return {std::move(species_), ordering};
313     }
314 }
315