11#include " project_parser.hpp"
22
3- #include " enum_helper.hpp"
43#include " fs.hpp"
54#include < deque>
65#include < stdexcept>
76#include < toml.hpp>
87#include < tsl/ordered_map.h>
98
10- template <>
11- std::vector<std::string> enumStrings<cmkr::parser::TargetType>::data{" executable" , " library" , " shared" , " static" ,
12- " interface" , " custom" , " object" , " template" };
13-
149namespace cmkr {
1510namespace parser {
1611
17- using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector> ;
12+ const char *targetTypeNames[target_last] = { " executable " , " library " , " shared " , " static " , " interface " , " custom " , " object " , " template " } ;
1813
19- template <typename EnumType>
20- static EnumType to_enum (const std::string &str, const std::string &help_name) {
21- EnumType value;
22- try {
23- std::stringstream ss (str);
24- ss >> enumFromString (value);
25- } catch (std::invalid_argument &) {
26- std::string supported;
27- for (const auto &s : enumStrings<EnumType>::data) {
28- if (!supported.empty ()) {
29- supported += " , " ;
30- }
31- supported += s;
14+ static TargetType parse_targetType (const std::string &name) {
15+ for (int i = 0 ; i < target_last; i++) {
16+ if (name == targetTypeNames[i]) {
17+ return static_cast <TargetType>(i);
3218 }
33- throw std::runtime_error (" Unknown " + help_name + " '" + str + " '! Supported types are: " + supported);
3419 }
35- return value ;
20+ return target_last ;
3621}
3722
23+ using TomlBasicValue = toml::basic_value<toml::discard_comments, tsl::ordered_map, std::vector>;
24+
3825static std::string format_key_error (const std::string &error, const toml::key &ky, const TomlBasicValue &value) {
3926 auto loc = value.location ();
4027 auto line_number_str = std::to_string (loc.line ());
@@ -43,7 +30,7 @@ static std::string format_key_error(const std::string &error, const toml::key &k
4330
4431 std::ostringstream oss;
4532 oss << " [error] " << error << ' \n ' ;
46- oss << " --> " << loc.file_name () << ' \n ' ;
33+ oss << " --> " << loc.file_name () << ' : ' << loc. line () << ' \n ' ;
4734
4835 oss << std::string (line_width + 2 , ' ' ) << " |\n " ;
4936 oss << ' ' << line_number_str << " | " << line_str << ' \n ' ;
@@ -56,7 +43,6 @@ static std::string format_key_error(const std::string &error, const toml::key &k
5643 if (key_start != std::string::npos) {
5744 oss << std::string (key_start + 1 , ' ' ) << std::string (ky.length (), ' ~' );
5845 }
59- oss << ' \n ' ;
6046
6147 return oss.str ();
6248}
@@ -242,6 +228,7 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
242228 conditions[" x32" ] = R"cmake( CMAKE_SIZEOF_VOID_P EQUAL 4)cmake" ;
243229 } else {
244230 conditions = parent->conditions ;
231+ templates = parent->templates ;
245232 }
246233
247234 if (toml.contains (" conditions" )) {
@@ -387,16 +374,43 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
387374 throw std::runtime_error (" [[bin]] has been renamed to [[target]]" );
388375 }
389376
390- auto parse_target = [&](const std::string &name, TomlChecker& t ) {
377+ auto parse_target = [&](const std::string &name, TomlChecker &t, bool isTemplate ) {
391378 Target target;
392379 target.name = name;
393380
394- t.required (" type" , target.type_string );
381+ t.required (" type" , target.type_name );
382+ target.type = parse_targetType (target.type_name );
395383
396- target.type = to_enum<TargetType>(target.type_string , " target type" );
384+ // Users cannot set this target type
385+ if (target.type == target_template) {
386+ target.type = target_last;
387+ }
397388
398- if (target.type >= target_COUNT) {
399- target.type = target_template;
389+ if (!isTemplate && target.type == target_last) {
390+ for (const auto &tmplate : templates) {
391+ if (target.type_name == tmplate.outline .name ) {
392+ target.type = target_template;
393+ break ;
394+ }
395+ }
396+ }
397+
398+ if (target.type == target_last) {
399+ std::string error = " Unknown target type '" + target.type_name + " '\n " ;
400+ error += " Available types:\n " ;
401+ for (std::string type_name : targetTypeNames) {
402+ if (type_name != " template" ) {
403+ error += " - " + type_name + " \n " ;
404+ }
405+ }
406+ if (!isTemplate && !templates.empty ()) {
407+ error += " Available templates:\n " ;
408+ for (const auto &tmplate : templates) {
409+ error += " - " + tmplate.outline .name + " \n " ;
410+ }
411+ }
412+ error.pop_back (); // Remove last newline
413+ throw std::runtime_error (format_key_error (error, target.type_name , t.find (" type" )));
400414 }
401415
402416 t.optional (" headers" , target.headers );
@@ -477,26 +491,37 @@ Project::Project(const Project *parent, const std::string &path, bool build) {
477491
478492 if (toml.contains (" template" )) {
479493 const auto &ts = toml::find (toml, " template" ).as_table ();
480-
481494 for (const auto &itr : ts) {
495+ auto &t = checker.create (itr.second );
496+ const auto &name = itr.first ;
497+
498+ for (const auto &type_name : targetTypeNames) {
499+ if (name == type_name) {
500+ throw std::runtime_error (format_key_error (" Reserved template name '" + name + " '" , name, itr.second ));
501+ }
502+ }
503+
504+ for (const auto &tmplate : templates) {
505+ if (name == tmplate.outline .name ) {
506+ throw std::runtime_error (format_key_error (" Template '" + name + " ' already defined" , name, itr.second ));
507+ }
508+ }
509+
482510 Template tmplate;
483- auto & t = checker.create (itr.second );
484- tmplate.outline = parse_target (itr.first , t);
511+ tmplate.outline = parse_target (name, t, true );
485512
486513 t.optional (" add-function" , tmplate.add_function );
487514 t.optional (" pass-sources-to-add-function" , tmplate.pass_sources_to_add_function );
488515
489516 templates.push_back (tmplate);
490- enumStrings<TargetType>::data.push_back (tmplate.outline .name );
491517 }
492518 }
493519
494520 if (toml.contains (" target" )) {
495521 const auto &ts = toml::find (toml, " target" ).as_table ();
496-
497522 for (const auto &itr : ts) {
498- auto & t = checker.create (itr.second );
499- targets.push_back (parse_target (itr.first , t));
523+ auto & t = checker.create (itr.second );
524+ targets.push_back (parse_target (itr.first , t, false ));
500525 }
501526 }
502527
0 commit comments