dioptic.profileparser 0.2__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/.github/workflows/pypi-packages.yml +11 -10
- dioptic_profileparser-0.3.0/.github/workflows/web-package.yml +28 -0
- dioptic_profileparser-0.3.0/PKG-INFO +11 -0
- dioptic_profileparser-0.3.0/cpp/CMakeLists.txt +33 -0
- dioptic_profileparser-0.3.0/cpp/include/profileparser/types.hpp +143 -0
- dioptic_profileparser-0.3.0/cpp/include/profileparser/utils.hpp +194 -0
- dioptic_profileparser-0.3.0/cpp/include/profileparser.hpp +58 -0
- dioptic_profileparser-0.3.0/cpp/lineinfo.cpp +21 -0
- dioptic_profileparser-0.3.0/cpp/parser.cpp +505 -0
- dioptic_profileparser-0.3.0/cpp/parser.hpp +12 -0
- dioptic_profileparser-0.3.0/cpp/printers.cpp +325 -0
- dioptic_profileparser-0.3.0/cpp/validation.cpp +128 -0
- dioptic_profileparser-0.3.0/pyproject.toml +24 -0
- dioptic_profileparser-0.3.0/python/CMakeLists.txt +58 -0
- dioptic_profileparser-0.3.0/python/__init__.py +2 -0
- dioptic_profileparser-0.3.0/python/pyprofileparser.cpp +175 -0
- {dioptic.profileparser-0.2/js → dioptic_profileparser-0.3.0/web}/CMakeLists.txt +20 -14
- dioptic_profileparser-0.3.0/web/README.md +11 -0
- dioptic_profileparser-0.3.0/web/binding_api.hpp +201 -0
- dioptic_profileparser-0.3.0/web/binding_ast.hpp +242 -0
- dioptic_profileparser-0.3.0/web/binding_helpers.hpp +41 -0
- dioptic_profileparser-0.3.0/web/profile_parser_js.cpp +20 -0
- dioptic.profileparser-0.2/.gitlab-ci.yml +0 -76
- dioptic.profileparser-0.2/PKG-INFO +0 -11
- dioptic.profileparser-0.2/cpp/processprofile.hpp +0 -926
- dioptic.profileparser-0.2/dioptic.profileparser.egg-info/PKG-INFO +0 -11
- dioptic.profileparser-0.2/dioptic.profileparser.egg-info/SOURCES.txt +0 -17
- dioptic.profileparser-0.2/dioptic.profileparser.egg-info/dependency_links.txt +0 -1
- dioptic.profileparser-0.2/dioptic.profileparser.egg-info/top_level.txt +0 -1
- dioptic.profileparser-0.2/js/profile_parser_js.cpp +0 -255
- dioptic.profileparser-0.2/pyproject.toml +0 -3
- dioptic.profileparser-0.2/python/CMakeLists.txt +0 -37
- dioptic.profileparser-0.2/python/pyprofileparser.cpp +0 -150
- dioptic.profileparser-0.2/setup.cfg +0 -4
- dioptic.profileparser-0.2/setup.py +0 -25
- {dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/.gitignore +0 -0
- {dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/LICENSE +0 -0
- {dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/README.md +0 -0
- {dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/cpp/peglib.h +0 -0
{dioptic.profileparser-0.2 → dioptic_profileparser-0.3.0}/.github/workflows/pypi-packages.yml
RENAMED
|
@@ -11,34 +11,34 @@ jobs:
|
|
|
11
11
|
build-sdist:
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
15
|
- name: Build sdist package
|
|
16
16
|
run: |
|
|
17
17
|
python -m pip install pip build --upgrade
|
|
18
18
|
python -m build --sdist
|
|
19
|
-
- uses: actions/upload-artifact@
|
|
19
|
+
- uses: actions/upload-artifact@v4
|
|
20
20
|
with:
|
|
21
|
-
name: packages
|
|
21
|
+
name: packages-src
|
|
22
22
|
path: "dist/*.tar.gz"
|
|
23
23
|
|
|
24
24
|
build-win64-wheels:
|
|
25
25
|
runs-on: windows-latest
|
|
26
26
|
strategy:
|
|
27
27
|
matrix:
|
|
28
|
-
python-version: ["3.9", "3.10", "3.11"]
|
|
28
|
+
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
|
29
29
|
steps:
|
|
30
|
-
- uses: actions/checkout@
|
|
30
|
+
- uses: actions/checkout@v4
|
|
31
31
|
- uses: ilammy/msvc-dev-cmd@v1
|
|
32
|
-
- uses: actions/setup-python@
|
|
32
|
+
- uses: actions/setup-python@v5
|
|
33
33
|
with:
|
|
34
34
|
python-version: ${{ matrix.python-version }}
|
|
35
35
|
- name: Build wheel for py${{ matrix.python-version }}
|
|
36
36
|
run: |
|
|
37
37
|
python -m pip install pip build --upgrade
|
|
38
38
|
python -m build --wheel
|
|
39
|
-
- uses: actions/upload-artifact@
|
|
39
|
+
- uses: actions/upload-artifact@v4
|
|
40
40
|
with:
|
|
41
|
-
name: packages
|
|
41
|
+
name: packages-win-py${{ matrix.python-version }}
|
|
42
42
|
path: "dist/*.whl"
|
|
43
43
|
|
|
44
44
|
pypi-publish:
|
|
@@ -49,10 +49,11 @@ jobs:
|
|
|
49
49
|
# IMPORTANT: this permission is mandatory for trusted publishing
|
|
50
50
|
id-token: write
|
|
51
51
|
steps:
|
|
52
|
-
- uses: actions/download-artifact@
|
|
52
|
+
- uses: actions/download-artifact@v4
|
|
53
53
|
with:
|
|
54
|
-
name: packages
|
|
55
54
|
path: dist
|
|
55
|
+
pattern: packages-*
|
|
56
|
+
merge-multiple: true
|
|
56
57
|
- name: Test PyPI publish
|
|
57
58
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
58
59
|
with:
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Build WASM/web port
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
tags:
|
|
8
|
+
- v[0-9]+.**
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build-web:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: mymindstorm/setup-emsdk@v14
|
|
16
|
+
with:
|
|
17
|
+
version: 3.1.57
|
|
18
|
+
actions-cache-folder: 'emsdk-cache'
|
|
19
|
+
- name: Build WASM port
|
|
20
|
+
run: |
|
|
21
|
+
cd web
|
|
22
|
+
mkdir build && cd build
|
|
23
|
+
emcmake cmake -DCMAKE_BUILD_TYPE="Release" ..
|
|
24
|
+
cmake --build .
|
|
25
|
+
- uses: actions/upload-artifact@v4
|
|
26
|
+
with:
|
|
27
|
+
name: web
|
|
28
|
+
path: "web/build/ProfileParserJs.*"
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: dioptic.profileparser
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Parser library for ARGOS declarative profiles
|
|
5
|
+
Author-Email: =?utf-8?q?Peter_W=C3=BCrtz?= <pwuertz@gmail.com>
|
|
6
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
7
|
+
Project-URL: Homepage, https://github.com/dioptic/profileparser
|
|
8
|
+
Requires-Python: >=3.9
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# Dioptic declarative profile parser
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.16)
|
|
2
|
+
project(libProfileParser CXX)
|
|
3
|
+
|
|
4
|
+
add_library(libProfileParser STATIC)
|
|
5
|
+
add_library(libProfileParser::libProfileParser ALIAS libProfileParser)
|
|
6
|
+
|
|
7
|
+
target_include_directories(libProfileParser PUBLIC
|
|
8
|
+
"${CMAKE_CURRENT_LIST_DIR}/include"
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
set_target_properties(libProfileParser PROPERTIES
|
|
12
|
+
CXX_STANDARD 20
|
|
13
|
+
CXX_STANDARD_REQUIRED ON
|
|
14
|
+
POSITION_INDEPENDENT_CODE ON
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
if(MSVC)
|
|
18
|
+
target_compile_options(libProfileParser PUBLIC /W3 /permissive- /Zc:__cplusplus)
|
|
19
|
+
else()
|
|
20
|
+
target_compile_options(libProfileParser PRIVATE -Wall -Wextra -Wpedantic)
|
|
21
|
+
endif()
|
|
22
|
+
|
|
23
|
+
target_sources(libProfileParser PRIVATE
|
|
24
|
+
"include/profileparser.hpp"
|
|
25
|
+
"include/profileparser/types.hpp"
|
|
26
|
+
"include/profileparser/utils.hpp"
|
|
27
|
+
"lineinfo.cpp"
|
|
28
|
+
"parser.cpp"
|
|
29
|
+
"parser.hpp"
|
|
30
|
+
"printers.cpp"
|
|
31
|
+
"validation.cpp"
|
|
32
|
+
"peglib.h" # Use FetchContent?
|
|
33
|
+
)
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <variant>
|
|
5
|
+
#include <vector>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <tuple>
|
|
8
|
+
#include <functional>
|
|
9
|
+
#include <unordered_map>
|
|
10
|
+
#include <stdexcept>
|
|
11
|
+
|
|
12
|
+
namespace Profile {
|
|
13
|
+
|
|
14
|
+
// AST elements
|
|
15
|
+
|
|
16
|
+
struct SourceInfo {
|
|
17
|
+
size_t offset;
|
|
18
|
+
size_t length;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
using Boolean = bool;
|
|
22
|
+
using Integer = long;
|
|
23
|
+
using Float = double;
|
|
24
|
+
using String = std::string;
|
|
25
|
+
|
|
26
|
+
struct ListNode;
|
|
27
|
+
using ListNodePtr = std::shared_ptr<ListNode>;
|
|
28
|
+
struct DictNode;
|
|
29
|
+
using DictNodePtr = std::shared_ptr<DictNode>;
|
|
30
|
+
|
|
31
|
+
struct NumericExpressionNode;
|
|
32
|
+
using NumericExpressionNodePtr = std::shared_ptr<NumericExpressionNode>;
|
|
33
|
+
struct StringExpressionNode;
|
|
34
|
+
using StringExpressionNodePtr = std::shared_ptr<StringExpressionNode>;
|
|
35
|
+
|
|
36
|
+
struct ObjectNode;
|
|
37
|
+
using ObjectNodePtr = std::shared_ptr<ObjectNode>;
|
|
38
|
+
struct ReferenceNode;
|
|
39
|
+
using ReferenceNodePtr = std::shared_ptr<ReferenceNode>;
|
|
40
|
+
struct AttributeNode;
|
|
41
|
+
using AttributeNodePtr = std::shared_ptr<AttributeNode>;
|
|
42
|
+
|
|
43
|
+
struct ReferenceNode {
|
|
44
|
+
SourceInfo source_info;
|
|
45
|
+
std::string reference;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
using Value = std::variant<ObjectNodePtr, ReferenceNodePtr, NumericExpressionNodePtr, StringExpressionNodePtr, ListNodePtr, DictNodePtr, Boolean, Integer, Float, String>;
|
|
49
|
+
|
|
50
|
+
struct KeyVal {
|
|
51
|
+
std::string key;
|
|
52
|
+
Value value;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
struct DocString {
|
|
56
|
+
SourceInfo source_info;
|
|
57
|
+
std::vector<std::string> lines;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
struct AttributeNode {
|
|
61
|
+
SourceInfo source_info;
|
|
62
|
+
SourceInfo value_source_info;
|
|
63
|
+
std::string name;
|
|
64
|
+
Value value;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
struct ObjectNode {
|
|
68
|
+
using Item = std::variant<AttributeNodePtr, ObjectNodePtr>;
|
|
69
|
+
|
|
70
|
+
SourceInfo source_info;
|
|
71
|
+
DocString docstring;
|
|
72
|
+
std::string classname;
|
|
73
|
+
std::string id;
|
|
74
|
+
std::vector<ObjectNodePtr> children;
|
|
75
|
+
std::vector<AttributeNodePtr> attributes;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
struct ListNode {
|
|
79
|
+
SourceInfo source_info;
|
|
80
|
+
std::string id;
|
|
81
|
+
std::vector<Value> items;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
struct DictNode {
|
|
85
|
+
SourceInfo source_info;
|
|
86
|
+
std::string id;
|
|
87
|
+
std::vector<KeyVal> items;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
struct NumericExpressionNode {
|
|
91
|
+
SourceInfo source_info;
|
|
92
|
+
std::string value;
|
|
93
|
+
std::vector<ReferenceNodePtr> references;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
using StringFragment = std::variant<String, ReferenceNodePtr>;
|
|
97
|
+
|
|
98
|
+
struct StringExpressionNode {
|
|
99
|
+
SourceInfo source_info;
|
|
100
|
+
std::vector<StringFragment> fragments;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// Parser API
|
|
104
|
+
|
|
105
|
+
using CheckRefCallback = std::function<bool(const std::string&)>;
|
|
106
|
+
static inline const CheckRefCallback default_ref_callback = [](const std::string&) { return false; };
|
|
107
|
+
|
|
108
|
+
struct IdCollection {
|
|
109
|
+
std::unordered_map<std::string, const ObjectNode*> object_ids;
|
|
110
|
+
std::unordered_map<std::string, const AttributeNode*> value_ids;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
struct ParsedProfile {
|
|
114
|
+
std::string source;
|
|
115
|
+
ObjectNodePtr root;
|
|
116
|
+
IdCollection ids;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
struct LineInfo {
|
|
120
|
+
size_t line;
|
|
121
|
+
size_t column;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
struct LineRange {
|
|
125
|
+
LineInfo begin;
|
|
126
|
+
LineInfo end;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
struct ErrorLine {
|
|
130
|
+
LineInfo where;
|
|
131
|
+
std::string message;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
struct ProfileError : public std::runtime_error {
|
|
135
|
+
ProfileError(std::string message, std::vector<ErrorLine> errors)
|
|
136
|
+
: std::runtime_error{std::move(message)}
|
|
137
|
+
, errors{std::move(errors)}
|
|
138
|
+
{}
|
|
139
|
+
|
|
140
|
+
std::vector<ErrorLine> errors;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <algorithm>
|
|
3
|
+
#include <sstream>
|
|
4
|
+
#include <profileparser/types.hpp>
|
|
5
|
+
|
|
6
|
+
namespace Profile {
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @brief Locate line & column number of given source info.
|
|
10
|
+
*/
|
|
11
|
+
LineInfo get_line_info(const std::string_view& source, const size_t offset);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @brief Locate line & column number of given source info.
|
|
15
|
+
*/
|
|
16
|
+
inline LineInfo get_line_info(const std::string_view& source, const SourceInfo& info)
|
|
17
|
+
{
|
|
18
|
+
return get_line_info(source, info.offset);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @brief Locate line & column range of given source info.
|
|
23
|
+
*/
|
|
24
|
+
inline LineRange get_line_range(const std::string_view& source, const SourceInfo& info)
|
|
25
|
+
{
|
|
26
|
+
return LineRange{
|
|
27
|
+
.begin=get_line_info(source, info.offset),
|
|
28
|
+
.end=get_line_info(source, info.offset + info.length),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @brief Find named attribute field in parsed object node.
|
|
34
|
+
*/
|
|
35
|
+
inline AttributeNodePtr find_attribute(const ObjectNode& obj, const std::string& name)
|
|
36
|
+
{
|
|
37
|
+
auto it = std::find_if(obj.attributes.begin(), obj.attributes.end(), [&](const auto& a) {
|
|
38
|
+
return a->name == name;
|
|
39
|
+
});
|
|
40
|
+
if (it == obj.attributes.end()) {
|
|
41
|
+
return nullptr;
|
|
42
|
+
}
|
|
43
|
+
return (*it);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @brief visit_values Visit profile value objects.
|
|
48
|
+
* @param profile Profile object.
|
|
49
|
+
* @param visitor Value object visitor.
|
|
50
|
+
*/
|
|
51
|
+
inline void visit_values(ObjectNodePtr& profile, auto&& visitor)
|
|
52
|
+
{
|
|
53
|
+
const auto isValue = [](const ObjectNodePtr& obj) -> bool {
|
|
54
|
+
return obj->classname == "Value";
|
|
55
|
+
};
|
|
56
|
+
for (auto& obj : profile->children) {
|
|
57
|
+
if (!isValue(obj)) { continue; }
|
|
58
|
+
visitor(obj);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @brief visit_values Visit profile value objects.
|
|
64
|
+
* @param profile Profile object.
|
|
65
|
+
* @param visitor Value object visitor.
|
|
66
|
+
*/
|
|
67
|
+
inline void visit_values(const ObjectNodePtr& profile, auto&& visitor)
|
|
68
|
+
{
|
|
69
|
+
const auto isValue = [](const ObjectNodePtr& obj) -> bool {
|
|
70
|
+
return obj->classname == "Value";
|
|
71
|
+
};
|
|
72
|
+
for (const auto& obj : profile->children) {
|
|
73
|
+
if (!isValue(obj)) { continue; }
|
|
74
|
+
visitor(obj);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @brief Template for implementing Profile AST visitors.
|
|
80
|
+
*/
|
|
81
|
+
template<typename VisitorImpl>
|
|
82
|
+
struct Visitor
|
|
83
|
+
{
|
|
84
|
+
template<typename T>
|
|
85
|
+
void operator()([[maybe_unused]] const T& v) { }
|
|
86
|
+
|
|
87
|
+
template<typename T>
|
|
88
|
+
void operator()(const std::shared_ptr<T>& v) {
|
|
89
|
+
return self()(static_cast<const T&>(*v));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
template<typename... Ts>
|
|
93
|
+
void operator()(const std::variant<Ts...>& v) {
|
|
94
|
+
std::visit([&](const auto& v_) { return self()(v_); }, v);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void operator()(const ListNode& r) {
|
|
98
|
+
for(const auto& v: r.items) { self()(v); };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
void operator()(const DictNode& r) {
|
|
102
|
+
for(const auto& v: r.items) { self()(v); };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
void operator()(const ObjectNode& obj) {
|
|
106
|
+
for (const ObjectNodePtr& child: obj.children) { self()(child); }
|
|
107
|
+
for (const AttributeNodePtr& attr: obj.attributes) { self()(attr->value); }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private:
|
|
111
|
+
inline VisitorImpl& self() { return static_cast<VisitorImpl&>(*this); }
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @brief Visitor for collecting Objects and Values with an identifier
|
|
116
|
+
*/
|
|
117
|
+
struct IdCollector : protected Visitor<IdCollector>
|
|
118
|
+
{
|
|
119
|
+
IdCollection& collection;
|
|
120
|
+
std::string_view source;
|
|
121
|
+
std::vector<ErrorLine>& errors;
|
|
122
|
+
|
|
123
|
+
IdCollector(IdCollection& collection, std::string_view source, std::vector<ErrorLine>& errors)
|
|
124
|
+
: Visitor<IdCollector>{}
|
|
125
|
+
, collection{collection}
|
|
126
|
+
, source{source}
|
|
127
|
+
, errors{errors}
|
|
128
|
+
{ }
|
|
129
|
+
|
|
130
|
+
void operator()(const ObjectNode& obj)
|
|
131
|
+
{
|
|
132
|
+
// Object with id, check for duplicates
|
|
133
|
+
if (!obj.id.empty()) {
|
|
134
|
+
if (!collection.object_ids.emplace(obj.id, &obj).second) {
|
|
135
|
+
add_error("Object id '" + obj.id + "' was declared multiple times", obj.source_info);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// If object is 'Value', store reference to value attribute
|
|
139
|
+
if (obj.classname == "Value") {
|
|
140
|
+
if (obj.id.empty()) {
|
|
141
|
+
add_error("Value object is missing id", obj.source_info);
|
|
142
|
+
}
|
|
143
|
+
auto value_attr = find_attribute(obj, "value");
|
|
144
|
+
if (value_attr == nullptr) {
|
|
145
|
+
add_error("Value object '" + obj.id + "' is missing 'value' attribute", obj.source_info);
|
|
146
|
+
} else
|
|
147
|
+
collection.value_ids.emplace(obj.id, &(*value_attr));
|
|
148
|
+
}
|
|
149
|
+
// Continue search for objects in children and attribute list
|
|
150
|
+
Visitor<IdCollector>::operator()(obj);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
inline void add_error(auto&& message, SourceInfo where)
|
|
154
|
+
{
|
|
155
|
+
errors.emplace_back(ErrorLine{
|
|
156
|
+
.where=get_line_info(source, where),
|
|
157
|
+
.message=std::forward<decltype(message)>(message),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
protected:
|
|
162
|
+
friend struct Visitor<IdCollector>;
|
|
163
|
+
using Visitor::operator();
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
inline ProfileError format_error(const std::string_view& message, std::vector<ErrorLine>&& errors)
|
|
168
|
+
{
|
|
169
|
+
std::stringstream ss;
|
|
170
|
+
ss << std::move(message);
|
|
171
|
+
for (auto& line : errors) {
|
|
172
|
+
ss << '\n' << line.where.column << ':' << line.where.column << ' ' << line.message;
|
|
173
|
+
}
|
|
174
|
+
return ProfileError { ss.str(), std::move(errors) };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @brief Create ID collection from parsed profile.
|
|
179
|
+
*
|
|
180
|
+
* @throws ProfileError Thrown if profile contains invalid ID information.
|
|
181
|
+
*/
|
|
182
|
+
inline IdCollection collect_ids(const ObjectNodePtr& obj, std::string_view source)
|
|
183
|
+
{
|
|
184
|
+
IdCollection collection;
|
|
185
|
+
std::vector<ErrorLine> errors;
|
|
186
|
+
IdCollector collect(collection, source, errors);
|
|
187
|
+
collect(*obj);
|
|
188
|
+
if (!errors.empty()) {
|
|
189
|
+
throw format_error("Error assembling object ID information", std::move(errors));
|
|
190
|
+
}
|
|
191
|
+
return collection;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
} // namespace Profile
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <profileparser/types.hpp>
|
|
3
|
+
|
|
4
|
+
namespace Profile {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @brief Parse profile from source string.
|
|
8
|
+
*
|
|
9
|
+
* @param source Profile source.
|
|
10
|
+
* @throws ProfileError Thrown if parsing profile from source failed.
|
|
11
|
+
* @return Parsed profile.
|
|
12
|
+
*/
|
|
13
|
+
ParsedProfile parse(std::string source);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @brief Get source information from node source reference
|
|
17
|
+
* @param profile Parsed profile.
|
|
18
|
+
* @param info Source reference from node.
|
|
19
|
+
* @return Corresponding line/column source range.
|
|
20
|
+
*/
|
|
21
|
+
LineRange get_source_range(const ParsedProfile& profile, SourceInfo info);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @brief Serialize profile object to profile source.
|
|
25
|
+
* @param profile Parsed profile.
|
|
26
|
+
* @return Profile source serialization.
|
|
27
|
+
*/
|
|
28
|
+
std::string to_profile_source(const ParsedProfile& profile);
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @brief Re-emit profile source with given value substitutions.
|
|
32
|
+
*
|
|
33
|
+
* @param profile Parsed profile.
|
|
34
|
+
* @param values Value substitutions.
|
|
35
|
+
* @return Updated profile source.
|
|
36
|
+
*/
|
|
37
|
+
std::string to_updated_source(const ParsedProfile& profile, const std::unordered_map<std::string, Value>& values);
|
|
38
|
+
std::string to_updated_source(const ParsedProfile& profile, const std::unordered_map<const AttributeNode*, Value>& values);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @brief Serialize profile object to JSON representation.
|
|
42
|
+
* @param profile Parsed profile.
|
|
43
|
+
* @param eval_expressions If true, serialize with expressions evaluated to constants.
|
|
44
|
+
* @return JSON serialization.
|
|
45
|
+
*/
|
|
46
|
+
std::string to_json_ast(const ParsedProfile& profile, const bool eval_expressions);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @brief Validate profile for use in `argosprocess`.
|
|
50
|
+
*
|
|
51
|
+
* @param profile Parsed profile.
|
|
52
|
+
* @param is_allowed_ref Callback for validating external references.
|
|
53
|
+
*
|
|
54
|
+
* @throws ProfileError Thrown if semantic validation failed.
|
|
55
|
+
*/
|
|
56
|
+
void validate_profile(const ParsedProfile& profile, const CheckRefCallback& is_allowed_ref = default_ref_callback);
|
|
57
|
+
|
|
58
|
+
} // namespace Profile
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#include <profileparser.hpp>
|
|
2
|
+
#include <profileparser/utils.hpp>
|
|
3
|
+
#include "peglib.h"
|
|
4
|
+
|
|
5
|
+
namespace Profile
|
|
6
|
+
{
|
|
7
|
+
|
|
8
|
+
LineInfo get_line_info(const std::string_view& source, const size_t offset)
|
|
9
|
+
{
|
|
10
|
+
// TODO: `peg::line_info` correctly counts unicode characters, but lacks line-cache like `vs.line_info`.
|
|
11
|
+
const auto* sourceStart = source.data();
|
|
12
|
+
auto [line, column] = peg::line_info(sourceStart, sourceStart + offset);
|
|
13
|
+
return LineInfo{ .line=line, .column=column };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
LineRange get_source_range(const ParsedProfile& profile, SourceInfo info)
|
|
17
|
+
{
|
|
18
|
+
return get_line_range(profile.source, info);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
} // namespace Profile
|