Line data Source code
1 : /* Copyright (C) 2025 Robert Schiwon
2 : *
3 : * This file is part of libjdx.
4 : *
5 : * libjdx is free software: you can redistribute it and/or modify it under the
6 : * terms of the GNU Lesser General Public License as published by the Free
7 : * Software Foundation, either version 3 of the License, or (at your option) any
8 : * later version.
9 : *
10 : * libjdx is distributed in the hope that it will be useful, but WITHOUT ANY
11 : * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12 : * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with libjdx. If not, see <https://www.gnu.org/licenses/>.
17 : */
18 : #include "jdx/Page.hpp"
19 : #include "jdx/ParseException.hpp"
20 : #include "util/DataParser.hpp"
21 : #include "util/LdrUtils.hpp"
22 : #include "util/PeakTableParser.hpp"
23 : #include "util/StringUtils.hpp"
24 :
25 71 : libjdx::jdx::Page::Page(std::string& label, std::string pageVar,
26 : const std::vector<NTuplesAttributes>& nTuplesAttributes,
27 : const std::vector<StringLdr>& blockLdrs, io::TextReader& reader,
28 71 : std::optional<std::string>& nextLine)
29 80 : : m_pageVariables{std::move(pageVar)}
30 : {
31 71 : validateInput(label);
32 71 : parse(nTuplesAttributes, blockLdrs, reader, nextLine);
33 68 : }
34 :
35 71 : void libjdx::jdx::Page::validateInput(const std::string& label)
36 : {
37 71 : if (label != s_label)
38 : {
39 0 : throw ParseException("Illegal label at " + std::string{s_label}
40 0 : + " start encountered: " + label);
41 : }
42 71 : }
43 :
44 11 : const std::string& libjdx::jdx::Page::getPageVariables() const
45 : {
46 11 : return m_pageVariables;
47 : }
48 :
49 : const std::vector<libjdx::jdx::StringLdr>&
50 9 : libjdx::jdx::Page::getPageLdrs() const
51 : {
52 9 : return m_pageLdrs;
53 : }
54 :
55 : const std::optional<libjdx::jdx::DataTable>&
56 37 : libjdx::jdx::Page::getDataTable() const
57 : {
58 37 : return m_dataTable;
59 : }
60 :
61 71 : void libjdx::jdx::Page::parse(
62 : const std::vector<NTuplesAttributes>& nTuplesAttributes,
63 : const std::vector<StringLdr>& blockLdrs, io::TextReader& reader,
64 : std::optional<std::string>& nextLine)
65 : {
66 : // skip potential comment lines
67 71 : util::skipPureComments(reader, nextLine, false);
68 71 : m_pageLdrs = parsePageLdrs(reader, nextLine);
69 71 : if (!nextLine.has_value() || !util::isLdrStart(nextLine.value()))
70 : {
71 : throw ParseException(
72 : "Unexpected content found while parsing NTUPLES PAGE: "
73 1 : + nextLine.value_or("<end of file>"));
74 : }
75 :
76 72 : auto [label, value] = util::parseLdrStart(nextLine.value());
77 70 : if (label == "PAGE" || label == "ENDNTUPLES" || label == "END")
78 : {
79 : // end of page, page is empty
80 2 : return;
81 : }
82 68 : if (label != "DATATABLE")
83 : {
84 : throw ParseException(
85 : "Unexpected content found while parsing NTUPLES PAGE: "
86 0 : + nextLine.value());
87 : }
88 :
89 69 : auto [dataTableVarList, plotDesc] = parseDataTableVars(value);
90 136 : m_dataTable.emplace(DataTable(label, dataTableVarList, plotDesc, blockLdrs,
91 133 : nTuplesAttributes, m_pageLdrs, reader, nextLine));
92 : }
93 :
94 71 : std::vector<libjdx::jdx::StringLdr> libjdx::jdx::Page::parsePageLdrs(
95 : io::TextReader& reader, std::optional<std::string>& nextLine)
96 : {
97 71 : std::vector<StringLdr> pageLdrs;
98 100 : while (nextLine.has_value())
99 : {
100 99 : auto [label, value] = util::parseLdrStart(nextLine.value());
101 198 : if (label == "PAGE" || label == "ENDNTUPLES" || label == "END"
102 198 : || label == "DATATABLE")
103 : {
104 : // end of page or start of DATA TABLE
105 70 : break;
106 : }
107 : // LDR is a regular LDR
108 29 : nextLine = parseStringValue(value, reader);
109 29 : pageLdrs.emplace_back(label, value);
110 : }
111 71 : return pageLdrs;
112 : }
113 :
114 : std::pair<std::string, std::optional<std::string>>
115 68 : libjdx::jdx::Page::parseDataTableVars(const std::string& rawPageVars)
116 : {
117 136 : auto rawPageVarsTrimmed = util::stripLineComment(rawPageVars, true).first;
118 68 : if (rawPageVarsTrimmed.empty())
119 : {
120 : // empty
121 : throw ParseException(
122 1 : "Missing variable list in DATA TABLE: " + rawPageVars);
123 : }
124 : // C++ does not support lookbehind syntax R"((?<=\))\s*,\s*)", so instead
125 : // use non capturing group for ")" and split at capturing group
126 : auto segments
127 201 : = util::split(rawPageVarsTrimmed, R"((?:\))(\s*,\s*))", true, 1);
128 67 : if (segments.empty() || segments.size() > 2)
129 : {
130 : throw ParseException(
131 0 : "Unexpected content found at DATA TABLE start: " + rawPageVars);
132 : }
133 :
134 67 : if (segments.size() == 1)
135 : {
136 6 : auto varList = util::stripLineComment(segments.at(0), true).first;
137 3 : return {varList, std::nullopt};
138 : }
139 : // plot descriptor is present
140 128 : auto varList = segments.at(0);
141 64 : util::trim(varList);
142 128 : auto plotDesc = util::stripLineComment(segments.at(1), true).first;
143 64 : return {varList, plotDesc};
144 : }
|