Skip to content

Commit

Permalink
Don't coerce identifier to string for object access, preserve AST
Browse files Browse the repository at this point in the history
  • Loading branch information
cschreib committed Sep 4, 2024
1 parent 838ec85 commit 4570766
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
34 changes: 34 additions & 0 deletions libjsonexpr/src/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,38 @@ ast_function_result safe_if_else(
return evaluate(args[2], vars, funs);
}
}

ast_function_result safe_object_access(
std::span<const ast::node> args, const variable_registry& vars, const function_registry& funs) {
if (args.size() != 2u) {
return unexpected(error{
.message =
"function takes 2 arguments, but " + std::to_string(args.size()) + " provided"});
}

// Evaluate object first.
const auto lhs = evaluate(args[0], vars, funs);
if (!lhs.has_value()) {
return unexpected(lhs.error());
}

if (!lhs.value().is_object()) {
return unexpected(node_error(
args[0], std::string("expected object, got ") +
std::string(get_dynamic_type_name(lhs.value()))));
}

const auto& object = lhs.value().get_ref<const object_t&>();

// Find specified field.
const std::string field = std::string{std::get<ast::identifier>(args[1].content).name};
const auto iter = object.find(field);
if (iter == object.end()) {
return unexpected(error{.message = "unknown field '" + field + "'"});
}

return iter->second;
}
} // namespace

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

register_ast_function(freg, ".", &safe_object_access);

register_function(freg, "in", &safe_contains<true, number_integer_t, array_t>);
register_function(freg, "in", &safe_contains<true, number_float_t, array_t>);
register_function(freg, "in", &safe_contains<true, boolean_t, array_t>);
Expand Down
8 changes: 2 additions & 6 deletions libjsonexpr/src/parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,6 @@ try_parse_identifier(depth_counter depth, std::span<const token>& tokens) {
return ast::node{t.location, ast::identifier{t.content}};
}

ast::node identifier_to_string(ast::node id) {
return ast::node{
id.location, ast::literal{json(std::string(std::get<ast::identifier>(id.content).name))}};
}

std::string single_to_double_quote(std::string_view input) {
std::string str;
bool escaped = false;
Expand Down Expand Up @@ -749,7 +744,8 @@ try_parse_access(depth_counter depth, std::span<const token>& tokens) {
return unexpected(abort_parse(index.error()));
}

args.push_back(identifier_to_string(index.value()));
function = ".";
args.push_back(std::move(index.value()));
end_location = &args.back().location;
}

Expand Down

0 comments on commit 4570766

Please sign in to comment.