Skip to content

Commit

Permalink
Implement user-defined functions (native_function)
Browse files Browse the repository at this point in the history
Summary:
This diff implementation the lowest-level API for user-defined functions: `native_function`.

The implementation here matches the existing whisker spec. A lot of the details are covered in doc blocks within the code.

A future diff / project will build a DSL on top of `native_function` to make it more ergonomic / declarative when authoring in C++.

The parser was built in {D67587583} and literals in {D67608814}.

Reviewed By: iahs

Differential Revision: D67617014

fbshipit-source-id: 993bb5781dfa9293b65755e03d6d75642521abbd
  • Loading branch information
praihan authored and facebook-github-bot committed Dec 28, 2024
1 parent 1411e8e commit b508667
Show file tree
Hide file tree
Showing 5 changed files with 605 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const object* find_property(const object& o, std::string_view identifier) {
}
return nullptr;
},
[](const native_function::ptr&) -> result { return nullptr; },
[identifier](const map& m) -> result {
if (auto it = m.find(identifier); it != m.end()) {
return &it->second;
Expand Down
55 changes: 55 additions & 0 deletions third-party/thrift/src/thrift/compiler/whisker/object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@

#include <cassert>
#include <ostream>
#include <set>
#include <sstream>
#include <type_traits>

#include <fmt/core.h>
#include <fmt/ranges.h>

namespace whisker {

Expand All @@ -41,6 +46,9 @@ class to_string_visitor {
[&](const native_object::ptr& o) {
visit_maybe_truncate(o, std::move(scope));
},
[&](const native_function::ptr& f) {
visit_maybe_truncate(f, std::move(scope));
},
// All other types are printed inline so no truncation is necessary.
[&](auto&& alternative) { visit(alternative, std::move(scope)); });
}
Expand Down Expand Up @@ -105,6 +113,11 @@ class to_string_visitor {
o->print_to(std::move(scope), opts_);
}

void visit(const native_function::ptr& f, tree_printer::scope scope) const {
require_within_max_depth(scope);
f->print_to(std::move(scope), opts_);
}

[[nodiscard]] bool at_max_depth(const tree_printer::scope& scope) const {
return scope.semantic_depth() == opts_.max_depth;
}
Expand All @@ -128,6 +141,48 @@ bool native_object::operator==(const native_object& other) const {
return &other == this;
}

maybe_managed_ptr<object> native_function::context::named_argument(
std::string_view name, named_argument_presence presence) const {
auto arg = named_args_.find(name);
if (arg == named_args_.end()) {
if (presence == named_argument_presence::optional) {
return nullptr;
}
error("Missing named argument '{}'.", name);
}
return arg->second;
}

void native_function::context::do_warning(std::string msg) const {
diags_.get().warning(loc_.begin, "{}", std::move(msg));
}

void native_function::context::declare_arity(std::size_t expected) const {
if (arity() != expected) {
error("Expected {} argument(s) but got {}", expected, arity());
}
}

void native_function::context::declare_named_arguments(
std::initializer_list<std::string_view> expected) const {
// Using std::set so that the error message is deterministic.
std::set<std::string_view> names;
for (const auto& [name, _] : named_args_) {
names.insert(name);
}
for (const auto& name : expected) {
names.erase(name);
}
if (!names.empty()) {
error("Unknown named argument(s) provided: {}.", fmt::join(names, ", "));
}
}

void native_function::print_to(
tree_printer::scope scope, const object_print_options&) const {
scope.println("<native_function>");
}

std::string to_string(const object& obj, const object_print_options& options) {
std::ostringstream out;
print_to(obj, tree_printer::scope::make_root(out), options);
Expand Down
Loading

0 comments on commit b508667

Please sign in to comment.