Skip to content

Commit 775fcee

Browse files
authored
Extend TraceOutput to provide vocabulary information (#408)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent b35d9b3 commit 775fcee

4 files changed

Lines changed: 274 additions & 49 deletions

File tree

contrib/trace.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ auto main(int argc, char **argv) noexcept -> int {
4747
const std::filesystem::path instance_path{argv[2]};
4848
const auto instance{sourcemeta::core::read_json(instance_path)};
4949

50-
sourcemeta::blaze::TraceOutput output;
50+
sourcemeta::blaze::TraceOutput output{
51+
sourcemeta::core::schema_official_walker,
52+
sourcemeta::core::schema_official_resolver};
5153
sourcemeta::blaze::Evaluator evaluator;
5254
const auto result{
5355
evaluator.validate(schema_template, instance, std::ref(output))};

src/compiler/compile_output_trace.cc

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,39 @@ static auto step_name(const sourcemeta::blaze::Instruction &instruction)
1212
instruction.type)];
1313
}
1414

15+
static auto try_vocabulary(
16+
const std::optional<
17+
std::reference_wrapper<const sourcemeta::core::SchemaFrame>> &frame,
18+
const sourcemeta::core::WeakPointer &evaluate_path,
19+
const sourcemeta::core::SchemaWalker &walker,
20+
const sourcemeta::core::SchemaResolver &resolver,
21+
const std::string &keyword_location)
22+
-> std::pair<bool, std::optional<std::string>> {
23+
if (!frame.has_value() || evaluate_path.empty() ||
24+
!evaluate_path.back().is_property()) {
25+
return {false, std::nullopt};
26+
}
27+
28+
const auto entry{frame.value().get().traverse(keyword_location)};
29+
if (!entry.has_value()) {
30+
return {false, std::nullopt};
31+
}
32+
33+
const auto vocabularies{
34+
frame.value().get().vocabularies(entry.value().get(), resolver)};
35+
const auto result{walker(evaluate_path.back().to_property(), vocabularies)};
36+
return {true, result.vocabulary};
37+
}
38+
1539
namespace sourcemeta::blaze {
1640

17-
TraceOutput::TraceOutput(const sourcemeta::core::WeakPointer &base)
18-
: base_{base} {}
41+
TraceOutput::TraceOutput(
42+
const sourcemeta::core::SchemaWalker &walker,
43+
const sourcemeta::core::SchemaResolver &resolver,
44+
const sourcemeta::core::WeakPointer &base,
45+
const std::optional<
46+
std::reference_wrapper<const sourcemeta::core::SchemaFrame>> &frame)
47+
: walker_{walker}, resolver_{resolver}, base_{base}, frame_{frame} {}
1948

2049
auto TraceOutput::begin() const -> const_iterator {
2150
return this->output.begin();
@@ -38,27 +67,34 @@ auto TraceOutput::operator()(
3867
const auto short_step_name{step_name(step)};
3968
auto effective_evaluate_path{evaluate_path.resolve_from(this->base_)};
4069

70+
// Attempt to get vocabulary information if we can get it
71+
auto vocabulary{try_vocabulary(this->frame_, evaluate_path, this->walker_,
72+
this->resolver_, step.keyword_location)};
73+
4174
if (is_annotation(step.type)) {
4275
if (type == EvaluationType::Pre) {
4376
return;
4477
} else {
45-
this->output.push_back({EntryType::Annotation, short_step_name,
46-
instance_location,
47-
std::move(effective_evaluate_path),
48-
step.keyword_location, annotation});
78+
this->output.push_back(
79+
{EntryType::Annotation, short_step_name, instance_location,
80+
std::move(effective_evaluate_path), step.keyword_location,
81+
annotation, std::move(vocabulary)});
4982
}
5083
} else if (type == EvaluationType::Pre) {
5184
this->output.push_back({EntryType::Push, short_step_name, instance_location,
5285
std::move(effective_evaluate_path),
53-
step.keyword_location, std::nullopt});
86+
step.keyword_location, std::nullopt,
87+
std::move(vocabulary)});
5488
} else if (result) {
5589
this->output.push_back({EntryType::Pass, short_step_name, instance_location,
5690
std::move(effective_evaluate_path),
57-
step.keyword_location, std::nullopt});
91+
step.keyword_location, std::nullopt,
92+
std::move(vocabulary)});
5893
} else {
5994
this->output.push_back({EntryType::Fail, short_step_name, instance_location,
6095
std::move(effective_evaluate_path),
61-
step.keyword_location, std::nullopt});
96+
step.keyword_location, std::nullopt,
97+
std::move(vocabulary)});
6298
}
6399
}
64100

src/compiler/include/sourcemeta/blaze/compiler_output.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77

88
#include <sourcemeta/core/json.h>
99
#include <sourcemeta/core/jsonpointer.h>
10+
#include <sourcemeta/core/jsonschema.h>
1011

1112
#include <sourcemeta/blaze/evaluator.h>
1213

14+
#include <functional> // std::reference_wrapper
1315
#include <map> // std::map
16+
#include <optional> // std::optional, std::nullopt
1417
#include <set> // std::set
1518
#include <string> // std::string
1619
#include <string_view> // std::string_view
@@ -183,8 +186,14 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT SimpleOutput {
183186
/// ```
184187
class SOURCEMETA_BLAZE_COMPILER_EXPORT TraceOutput {
185188
public:
186-
TraceOutput(const sourcemeta::core::WeakPointer &base =
187-
sourcemeta::core::empty_weak_pointer);
189+
// Passing a frame of the schema is optional, but allows the output
190+
// formatter to give you back additional information
191+
TraceOutput(const sourcemeta::core::SchemaWalker &walker,
192+
const sourcemeta::core::SchemaResolver &resolver,
193+
const sourcemeta::core::WeakPointer &base =
194+
sourcemeta::core::empty_weak_pointer,
195+
const std::optional<std::reference_wrapper<
196+
const sourcemeta::core::SchemaFrame>> &frame = std::nullopt);
188197

189198
// Prevent accidental copies
190199
TraceOutput(const TraceOutput &) = delete;
@@ -199,6 +208,9 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT TraceOutput {
199208
const sourcemeta::core::WeakPointer evaluate_path;
200209
const std::string keyword_location;
201210
const std::optional<sourcemeta::core::JSON> annotation;
211+
// Whether we were able to collect vocabulary information,
212+
// and the vocabulary URI, if any
213+
const std::pair<bool, std::optional<std::string>> vocabulary;
202214
};
203215

204216
auto operator()(const EvaluationType type, const bool result,
@@ -221,7 +233,12 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT TraceOutput {
221233
#if defined(_MSC_VER)
222234
#pragma warning(disable : 4251)
223235
#endif
236+
const sourcemeta::core::SchemaWalker walker_;
237+
const sourcemeta::core::SchemaResolver resolver_;
224238
const sourcemeta::core::WeakPointer base_;
239+
const std::optional<
240+
std::reference_wrapper<const sourcemeta::core::SchemaFrame>>
241+
frame_;
225242
container_type output;
226243
#if defined(_MSC_VER)
227244
#pragma warning(default : 4251)

0 commit comments

Comments
 (0)