The Gaudi Framework  master (82fdf313)
Loading...
Searching...
No Matches
Parser.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#include "Parser.h"
12#include "Grammar.h"
13#include "IncludedFiles.h"
14#include "Iterator.h"
15#include "Messages.h"
16#include "Node.h"
17#include "Utils.h"
19#include <boost/filesystem.hpp>
20#include <fmt/format.h>
21#include <fstream>
22#include <sstream>
23
24namespace bf = boost::filesystem;
25namespace gp = Gaudi::Parsers;
26namespace gpu = Gaudi::Parsers::Utils;
27namespace qi = boost::spirit::qi;
28
29namespace {
30 // Return last line and column number of text in `s` with newline delimiter `delim`
31 std::pair<int, int> GetLastLineAndColumn( std::string_view s, const char delim = '\n' ) {
32 size_t line = 1;
33 for ( size_t p = s.find( delim ); p != s.npos; p = s.find( delim ) ) {
34 s.remove_prefix( p + 1 );
35 ++line;
36 }
37 return { line, s.size() + 1 };
38 }
39
40 template <typename Grammar>
41 bool ParseStream( std::ifstream& stream, const std::string& stream_name, gp::Messages* messages, gp::Node* root ) {
42 // Load input stream
43 const std::string input = ( std::ostringstream{} << stream.rdbuf() ).str();
44
45 auto [last_line, last_column] = GetLastLineAndColumn( input );
46
47 BaseIterator in_begin( input.begin() );
48 // convert input iterator to forward iterator, usable by spirit parser
49 ForwardIterator fwd_begin = boost::spirit::make_default_multi_pass( in_begin );
50 ForwardIterator fwd_end;
51
52 // wrap forward iterator with position iterator, to record the position
53 Iterator position_begin( fwd_begin, fwd_end, stream_name );
54 Iterator position_end;
55
56 Grammar gr;
57 gp::SkipperGrammar<Iterator> skipper;
58
59 root->value = stream_name;
60 bool result = qi::phrase_parse( position_begin, position_end, gr, skipper, *root );
61
62 const IteratorPosition& pos = position_begin.get_position();
63 if ( result && ( pos.line == last_line ) && ( pos.column == last_column ) ) { return true; }
64
65 messages->AddError( gp::Position( stream_name, pos.line, pos.column ), "parse error" );
66 return false;
67 }
68
69 template <typename Grammar>
70 bool ParseFile( const gp::Position& from, std::string_view filename, std::string_view search_path,
71 gp::IncludedFiles* included, gp::Messages* messages, gp::Node* root ) {
72 std::string search_path_with_current_dir = gpu::replaceEnvironments( search_path );
73 if ( !from.filename().empty() ) { // Add current file directory to search_path
74 bf::path file_path( from.filename() );
75 search_path_with_current_dir =
76 file_path.parent_path().string() +
77 ( search_path_with_current_dir.empty() ? "" : ( "," + search_path_with_current_dir ) );
78 }
79 std::string absolute_path =
80 System::PathResolver::find_file_from_list( gpu::replaceEnvironments( filename ), search_path_with_current_dir );
81
82 if ( absolute_path.empty() ) {
83 messages->AddError( from, "Couldn't find a file " + std::string{ filename } + " in search path '" +
84 search_path_with_current_dir + "'" );
85 return false;
86 }
87 const gp::Position* included_from;
88 if ( !included->GetPosition( absolute_path, &included_from ) ) {
89 included->AddFile( absolute_path, from );
90 std::ifstream file{ absolute_path };
91 if ( !file.is_open() ) {
92 messages->AddError( from, std::string{ "Couldn't open a file " }.append( filename ) );
93 return false;
94 }
95 return ParseStream<Grammar>( file, absolute_path, messages, root );
96 } else {
97 assert( included_from != nullptr );
98 messages->AddWarning(
99 from, fmt::format( "File {} already included from {}", absolute_path, included_from->ToString() ) );
100 return true;
101 }
102 }
103} // namespace
104
105bool gp::Parse( std::string_view filename, std::string_view search_path, IncludedFiles* included, Messages* messages,
106 Node* root ) {
107 return Parse( Position(), filename, search_path, included, messages, root );
108}
109
110bool gp::Parse( const Position& from, std::string_view filename, std::string_view search_path, IncludedFiles* included,
111 Messages* messages, Node* root ) {
113 return ParseFile<Grammar>( from, filename, search_path, included, messages, root );
114}
115
116bool gp::ParseUnits( const Position& from, std::string_view filename, std::string_view search_path,
117 IncludedFiles* included, Messages* messages, Node* root ) {
119 return ParseFile<Grammar>( from, filename, search_path, included, messages, root );
120}
std::string::const_iterator BaseIterator
Definition Iterator.h:16
boost::spirit::multi_pass< BaseIterator > ForwardIterator
Definition Iterator.h:17
boost::spirit::classic::file_position_base< std::string > IteratorPosition
Definition Iterator.h:19
boost::spirit::classic::position_iterator2< ForwardIterator > Iterator
Definition Iterator.h:18
bool GetPosition(std::string_view filename, const Position **pos) const
bool AddFile(std::string filename, Position from)
void AddError(std::string_view error)
Definition Messages.h:28
void AddWarning(std::string_view warning)
Definition Messages.h:26
std::string ToString() const
Definition Position.cpp:14
const std::string & filename() const
Definition Position.h:22
static std::string find_file_from_list(const std::string &logical_file_name, const std::string &search_list, SearchType search_type=LocalSearch)
std::string replaceEnvironments(std::string_view input)
Definition Utils.cpp:17
bool ParseUnits(const Position &from, std::string_view filename, std::string_view search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition Parser.cpp:116
bool Parse(std::string_view filename, std::string_view search_path, IncludedFiles *included, Messages *messages, Node *root)
Definition Parser.cpp:105
stream
Definition Write.py:32