jak-project/common/goos/ParseHelpers.cpp

116 lines
3.5 KiB
C++
Raw Normal View History

#include "ParseHelpers.h"
#include "third-party/fmt/core.h"
namespace goos {
bool get_va(const goos::Object& rest, std::string* err_string, goos::Arguments* result) {
goos::Arguments args;
// loop over forms in list
goos::Object current = rest;
while (!current.is_empty_list()) {
auto arg = current.as_pair()->car;
// did we get a ":keyword"
if (arg.is_symbol() && arg.as_symbol()->name.at(0) == ':') {
auto key_name = arg.as_symbol()->name.substr(1);
// check for multiple definition of key
if (args.named.find(key_name) != args.named.end()) {
*err_string = "Key argument " + key_name + " multiply defined";
return false;
}
// check for well-formed :key value expression
current = current.as_pair()->cdr;
if (current.is_empty_list()) {
*err_string = "Key argument didn't have a value";
return false;
}
args.named[key_name] = current.as_pair()->car;
} else {
// not a keyword. Add to unnamed or rest, depending on what we expect
args.unnamed.push_back(arg);
}
current = current.as_pair()->cdr;
}
*result = args;
return true;
}
void get_va_no_named(const goos::Object& rest, goos::Arguments* result) {
goos::Arguments args;
// loop over forms in list
goos::Object current = rest;
while (!current.is_empty_list()) {
args.unnamed.push_back(current.as_pair()->car);
current = current.as_pair()->cdr;
}
*result = args;
}
bool va_check(
const goos::Arguments& args,
const std::vector<std::optional<goos::ObjectType>>& unnamed,
const std::unordered_map<std::string, std::pair<bool, std::optional<goos::ObjectType>>>& named,
std::string* err_string) {
ASSERT(args.rest.empty());
if (unnamed.size() != args.unnamed.size()) {
*err_string = fmt::format("Got {} arguments, but expected {}",
std::to_string(args.unnamed.size()), std::to_string(unnamed.size()));
return false;
}
for (size_t i = 0; i < unnamed.size(); i++) {
if (unnamed[i].has_value() && unnamed[i] != args.unnamed[i].type) {
docs: Automatically generate documentation from goal_src code (#2214) This automatically generates documentation from goal_src docstrings, think doxygen/java-docs/rust docs/etc. It mostly supports everything already, but here are the following things that aren't yet complete: - file descriptions - high-level documentation to go along with this (think pure markdown docs describing overall systems that would be co-located in goal_src for organizational purposes) - enums - states - std-lib functions (all have empty strings right now for docs anyway) The job of the new `gen-docs` function is solely to generate a bunch of JSON data which should give you everything you need to generate some decent documentation (outputting markdown/html/pdf/etc). It is not it's responsibility to do that nice formatting -- this is by design to intentionally delegate that responsibility elsewhere. Side-note, this is about 12-15MB of minified json for jak 2 so far :) In our normal "goal_src has changed" action -- we will generate this data, and the website can download it -- use the information to generate the documentation at build time -- and it will be included in the site. Likewise, if we wanted to include docs along with releases for offline viewing, we could do so in a similar fashion (just write a formatting script to generate said documentation). Lastly this work somewhat paves the way for doing more interesting things in the LSP like: - whats the docstring for this symbol? - autocompleting function arguments - type checking function arguments - where is this symbol defined? - etc Fixes #2215
2023-02-20 19:49:37 -05:00
// special case -- an empty list is a valid pair
*err_string = fmt::format("Argument {} has type {} but {} was expected\nArgument is: {}", i,
object_type_to_string(args.unnamed[i].type),
object_type_to_string(unnamed[i].value()), args.unnamed[i].print());
return false;
}
}
for (const auto& kv : named) {
auto kv2 = args.named.find(kv.first);
if (kv2 == args.named.end()) {
// argument not given.
if (kv.second.first) {
// but was required
*err_string = "Required named argument \"" + kv.first + "\" was not found";
return false;
}
} else {
// argument given.
if (kv.second.second.has_value() && kv.second.second != kv2->second.type) {
// but is wrong type
*err_string = "Argument \"" + kv.first + "\" has type " +
object_type_to_string(kv2->second.type) + " but " +
object_type_to_string(kv.second.second.value()) + " was expected";
return false;
}
}
}
for (const auto& kv : args.named) {
if (named.find(kv.first) == named.end()) {
*err_string = "Got unrecognized keyword argument \"" + kv.first + "\"";
return false;
}
}
return true;
}
int list_length(const goos::Object& list) {
int len = 0;
for_each_in_list(list, [&](const goos::Object& x) {
(void)x;
len++;
});
return len;
}
} // namespace goos