Skip to content

Commit 4570766

Browse files
committed
Don't coerce identifier to string for object access, preserve AST
1 parent 838ec85 commit 4570766

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

libjsonexpr/src/functions.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,38 @@ ast_function_result safe_if_else(
490490
return evaluate(args[2], vars, funs);
491491
}
492492
}
493+
494+
ast_function_result safe_object_access(
495+
std::span<const ast::node> args, const variable_registry& vars, const function_registry& funs) {
496+
if (args.size() != 2u) {
497+
return unexpected(error{
498+
.message =
499+
"function takes 2 arguments, but " + std::to_string(args.size()) + " provided"});
500+
}
501+
502+
// Evaluate object first.
503+
const auto lhs = evaluate(args[0], vars, funs);
504+
if (!lhs.has_value()) {
505+
return unexpected(lhs.error());
506+
}
507+
508+
if (!lhs.value().is_object()) {
509+
return unexpected(node_error(
510+
args[0], std::string("expected object, got ") +
511+
std::string(get_dynamic_type_name(lhs.value()))));
512+
}
513+
514+
const auto& object = lhs.value().get_ref<const object_t&>();
515+
516+
// Find specified field.
517+
const std::string field = std::string{std::get<ast::identifier>(args[1].content).name};
518+
const auto iter = object.find(field);
519+
if (iter == object.end()) {
520+
return unexpected(error{.message = "unknown field '" + field + "'"});
521+
}
522+
523+
return iter->second;
524+
}
493525
} // namespace
494526

495527
void jsonexpr::impl::add_type(std::string& key, std::string_view type) {
@@ -627,6 +659,8 @@ function_registry make_default_functions() {
627659
register_function(freg, "[:]", &safe_range_access<string_t, number_integer_t>);
628660
register_function(freg, "[:]", &safe_range_access<array_t, number_integer_t>);
629661

662+
register_ast_function(freg, ".", &safe_object_access);
663+
630664
register_function(freg, "in", &safe_contains<true, number_integer_t, array_t>);
631665
register_function(freg, "in", &safe_contains<true, number_float_t, array_t>);
632666
register_function(freg, "in", &safe_contains<true, boolean_t, array_t>);

libjsonexpr/src/parse.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,6 @@ try_parse_identifier(depth_counter depth, std::span<const token>& tokens) {
285285
return ast::node{t.location, ast::identifier{t.content}};
286286
}
287287

288-
ast::node identifier_to_string(ast::node id) {
289-
return ast::node{
290-
id.location, ast::literal{json(std::string(std::get<ast::identifier>(id.content).name))}};
291-
}
292-
293288
std::string single_to_double_quote(std::string_view input) {
294289
std::string str;
295290
bool escaped = false;
@@ -749,7 +744,8 @@ try_parse_access(depth_counter depth, std::span<const token>& tokens) {
749744
return unexpected(abort_parse(index.error()));
750745
}
751746

752-
args.push_back(identifier_to_string(index.value()));
747+
function = ".";
748+
args.push_back(std::move(index.value()));
753749
end_location = &args.back().location;
754750
}
755751

0 commit comments

Comments
 (0)