LCOV - code coverage report
Current view: top level - base - HITParser.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 100.0 % 74 74
Test Date: 2025-06-29 01:25:44 Functions: 100.0 % 5 5

            Line data    Source code
       1              : // Copyright 2024, UChicago Argonne, LLC
       2              : // All Rights Reserved
       3              : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
       4              : // By: Argonne National Laboratory
       5              : // OPEN SOURCE LICENSE (MIT)
       6              : //
       7              : // Permission is hereby granted, free of charge, to any person obtaining a copy
       8              : // of this software and associated documentation files (the "Software"), to deal
       9              : // in the Software without restriction, including without limitation the rights
      10              : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      11              : // copies of the Software, and to permit persons to whom the Software is
      12              : // furnished to do so, subject to the following conditions:
      13              : //
      14              : // The above copyright notice and this permission notice shall be included in
      15              : // all copies or substantial portions of the Software.
      16              : //
      17              : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      18              : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      19              : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      20              : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      21              : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      22              : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      23              : // THE SOFTWARE.
      24              : 
      25              : #include "hit/braceexpr.h"
      26              : 
      27              : #include "neml2/base/HITParser.h"
      28              : #include "neml2/base/Registry.h"
      29              : #include "neml2/base/Factory.h"
      30              : #include "neml2/base/TensorName.h"
      31              : #include "neml2/base/Settings.h"
      32              : #include "neml2/base/EnumSelection.h"
      33              : #include "neml2/base/MultiEnumSelection.h"
      34              : #include "neml2/base/LabeledAxisAccessor.h"
      35              : #include "neml2/tensors/tensors.h"
      36              : #include "neml2/misc/assertions.h"
      37              : #include "neml2/misc/types.h"
      38              : 
      39              : namespace neml2
      40              : {
      41              : InputFile
      42          357 : HITParser::parse(const std::filesystem::path & filename, const std::string & additional_input) const
      43              : {
      44              :   // Open and read the file
      45          357 :   std::ifstream file(filename);
      46          357 :   neml_assert(file.is_open(), "Unable to open file ", filename);
      47              : 
      48              :   // Read the file into a string
      49          357 :   std::stringstream buffer;
      50          357 :   buffer << file.rdbuf();
      51          357 :   std::string input = buffer.str();
      52              : 
      53              :   // Let HIT lex the string
      54          357 :   std::unique_ptr<hit::Node> root(hit::parse(filename, input));
      55          357 :   neml_assert(root.get(), "HIT failed to lex the input file: ", filename);
      56              : 
      57              :   // Handle additional input (they could be coming from cli args)
      58          357 :   std::unique_ptr<hit::Node> cli_root(hit::parse("cliargs", additional_input));
      59          357 :   hit::merge(cli_root.get(), root.get());
      60              : 
      61              :   // Preevaluate the input
      62          357 :   hit::BraceExpander expander;
      63          357 :   hit::EnvEvaler env;
      64          357 :   hit::RawEvaler raw;
      65          714 :   expander.registerEvaler("env", env);
      66          357 :   expander.registerEvaler("raw", raw);
      67          357 :   root->walk(&expander);
      68              : 
      69          711 :   return parse(root.get());
      70          378 : }
      71              : 
      72              : InputFile
      73          357 : HITParser::parse(hit::Node * root) const
      74              : {
      75              :   // Extract global settings
      76          357 :   OptionSet settings = Settings::expected_options();
      77         1071 :   if (auto * const node = root->find("Settings"))
      78           12 :     extract_options(node, settings);
      79              : 
      80              :   // Loop over each known section and extract options for each object
      81          357 :   InputFile inp(settings);
      82         2487 :   for (const auto & section : Parser::sections)
      83              :   {
      84         2133 :     auto * section_node = root->find(section);
      85         2133 :     if (section_node)
      86              :     {
      87          701 :       auto objects = section_node->children(hit::NodeType::Section);
      88         4025 :       for (auto * object : objects)
      89              :       {
      90         3327 :         auto options = extract_object_options(object, section_node);
      91         3324 :         inp[section][options.name()] = options;
      92         3324 :       }
      93          701 :     }
      94              :   }
      95              : 
      96          708 :   return inp;
      97          360 : }
      98              : 
      99              : OptionSet
     100         3327 : HITParser::extract_object_options(hit::Node * object, hit::Node * section) const
     101              : {
     102              :   // There is a special field reserved for object type
     103         6654 :   std::string type = object->param<std::string>("type");
     104              :   // Extract the options
     105         3327 :   auto options = Registry::info(type).expected_options;
     106         3327 :   extract_options(object, options);
     107              : 
     108              :   // Also fill in the metadata
     109         3324 :   options.name() = object->path();
     110         3324 :   options.type() = type;
     111         3324 :   options.path() = section->fullpath();
     112              : 
     113         6648 :   return options;
     114         3330 : }
     115              : 
     116              : void
     117         3339 : HITParser::extract_options(hit::Node * object, OptionSet & options) const
     118              : {
     119        13989 :   for (auto * node : object->children(hit::NodeType::Field))
     120        10653 :     if (node->path() != "type")
     121        10662 :       extract_option(node, options);
     122         3336 : }
     123              : 
     124              : // NOLINTBEGIN
     125              : void
     126         7326 : HITParser::extract_option(hit::Node * n, OptionSet & options) const
     127              : {
     128              : #define extract_option_base(ptype, method)                                                         \
     129              :   else if (option->type() == utils::demangle(typeid(ptype).name()))                                \
     130              :       neml_assert(method(dynamic_cast<Option<ptype> *>(option.get())->set(), n->strVal()),         \
     131              :                   utils::parse_failure_message<ptype>(n->strVal()))
     132              : 
     133              : #define extract_option_t(ptype)                                                                    \
     134              :   extract_option_base(ptype, utils::parse_<ptype>);                                                \
     135              :   extract_option_base(std::vector<ptype>, utils::parse_vector_<ptype>);                            \
     136              :   extract_option_base(std::vector<std::vector<ptype>>, utils::parse_vector_vector_<ptype>)
     137              : 
     138              : #define extract_option_tensor_t(ptype) extract_option_t(TensorName<ptype>)
     139              : 
     140         7326 :   if (n->type() == hit::NodeType::Field)
     141              :   {
     142         7326 :     bool found = false;
     143       104616 :     for (auto & [name, option] : options)
     144       104616 :       if (name == n->path())
     145              :       {
     146         7326 :         neml_assert(!option->suppressed(),
     147              :                     "Option named '",
     148         7326 :                     option->name(),
     149              :                     "' is suppressed, and its value cannot be modified.");
     150              : 
     151         7325 :         found = true;
     152              : 
     153              :         if (false)
     154              :           ;
     155         7325 :         extract_option_t(TensorShape);
     156         5831 :         extract_option_t(bool);
     157         5680 :         extract_option_t(int);
     158         5647 :         extract_option_t(unsigned int);
     159         5608 :         extract_option_t(std::size_t);
     160         5608 :         extract_option_t(Size);
     161         4758 :         extract_option_t(double);
     162         3537 :         extract_option_t(std::string);
     163         2562 :         extract_option_t(VariableName);
     164         1850 :         extract_option_t(EnumSelection);
     165         1825 :         extract_option_t(MultiEnumSelection);
     166         1805 :         FOR_ALL_TENSORBASE(extract_option_tensor_t);
     167           30 :         extract_option_tensor_t(ATensor);
     168           30 :         extract_option_t(Device);
     169              :         // LCOV_EXCL_START
     170              :         else neml_assert(false, "Unsupported option type for option ", n->fullpath());
     171              :         // LCOV_EXCL_STOP
     172              : 
     173         7323 :         option->user_specified() = true;
     174              : 
     175         7323 :         break;
     176              :       }
     177         7323 :     neml_assert(found, "Unused option ", n->fullpath());
     178              :   }
     179         7323 : }
     180              : // NOLINTEND
     181              : } // namespace neml2
        

Generated by: LCOV version 2.0-1