AP_Scripting: Allow the bindings to descirbe any build dependencies needed

Scripting has a hard requirement on AP_Terrain being available, this
allows us to emit a cleaner error message if you have disabled terrain
but not scripting
This commit is contained in:
Michael du Breuil 2019-08-20 17:18:16 -07:00 committed by Andrew Tridgell
parent 0ce3cd06b0
commit 1e66457755
4 changed files with 76 additions and 2 deletions

View File

@ -113,6 +113,8 @@ singleton RangeFinder method num_sensors uint8_t
include AP_Terrain/AP_Terrain.h
depends AP_TERRAIN_AVAILABLE 1 Scripting requires terrain to be available
singleton AP_Terrain alias terrain
singleton AP_Terrain method enabled boolean
singleton AP_Terrain enum TerrainStatusDisabled TerrainStatusUnhealthy TerrainStatusOK

View File

@ -9,6 +9,7 @@
char keyword_alias[] = "alias";
char keyword_comment[] = "--";
char keyword_depends[] = "depends";
char keyword_enum[] = "enum";
char keyword_field[] = "field";
char keyword_include[] = "include";
@ -45,6 +46,7 @@ enum error_codes {
ERROR_INTERNAL = 5, // internal error of some form
ERROR_GENERAL = 6, // general error
ERROR_SINGLETON = 7, // singletons
ERROR_DEPENDS = 8, // dependencies
};
struct header {
@ -73,6 +75,7 @@ enum trace_level {
TRACE_GENERAL = (1 << 2),
TRACE_USERDATA = (1 << 3),
TRACE_SINGLETON = (1 << 4),
TRACE_DEPENDS = (1 << 5),
};
enum access_flags {
@ -310,6 +313,15 @@ struct userdata {
static struct userdata *parsed_userdata = NULL;
struct dependency {
struct dependency * next;
char *symbol; // dependency symbol to check
char *value; // value to target
char *error_msg; // message if the check fails
};
static struct dependency *parsed_dependencies = NULL;
// lazy helper that allocates a storage buffer and does strcpy for us
void string_copy(char **dest, const char * src) {
*dest = (char *)allocate(strlen(src) + 1);
@ -678,7 +690,7 @@ void handle_userdata(void) {
// read type
char *type = next_token();
if (type == NULL) {
error(ERROR_USERDATA, "Expected an access type for userdata %s", name);
error(ERROR_USERDATA, "Expected a access type for userdata %s", name);
}
// match type
@ -724,7 +736,7 @@ void handle_singleton(void) {
// read type
char *type = next_token();
if (type == NULL) {
error(ERROR_SINGLETON, "Expected an access type for userdata %s", name);
error(ERROR_SINGLETON, "Expected a access type for userdata %s", name);
}
if (strcmp(type, keyword_alias) == 0) {
@ -754,6 +766,36 @@ void handle_singleton(void) {
}
}
void handle_depends(void) {
trace(TRACE_DEPENDS, "Adding a dependency");
char *symbol = next_token();
if (symbol == NULL) {
error(ERROR_DEPENDS, "Expected a name symbol for the dependency");
}
// read value
char *value = next_token();
if (value == NULL) {
error(ERROR_DEPENDS, "Expected a required value for dependency on %s", symbol);
}
char *error_msg = strtok(NULL, "");
if (error_msg == NULL) {
error(ERROR_DEPENDS, "Expected a error message for dependency on %s", symbol);
}
trace(TRACE_SINGLETON, "Allocating new dependency for %s", symbol);
struct dependency * node = (struct dependency *)allocate(sizeof(struct dependency));
node->symbol = (char *)allocate(strlen(symbol) + 1);
strcpy(node->symbol, symbol);
node->value = (char *)allocate(strlen(value) + 1);
strcpy(node->value, value);
node->error_msg = (char *)allocate(strlen(error_msg) + 1);
strcpy(node->error_msg, error_msg);
node->next = parsed_dependencies;
parsed_dependencies = node;
}
void sanity_check_userdata(void) {
struct userdata * node = parsed_userdata;
while(node) {
@ -772,6 +814,16 @@ void emit_headers(FILE *f) {
}
}
void emit_dependencies(FILE *f) {
struct dependency *node = parsed_dependencies;
while (node) {
fprintf(f, "#if !defined(%s) || (%s != %s)\n", node->symbol, node->symbol, node->value);
fprintf(f, " #error %s\n", node->error_msg);
fprintf(f, "#endif // !defined(%s) || (%s != %s)\n", node->symbol, node->symbol, node->value);
node = node->next;
}
}
void emit_userdata_allocators(void) {
struct userdata * node = parsed_userdata;
while (node) {
@ -1647,6 +1699,8 @@ int main(int argc, char **argv) {
handle_userdata();
} else if (strcmp (state.token, keyword_singleton) == 0){
handle_singleton();
} else if (strcmp (state.token, keyword_depends) == 0){
handle_depends();
} else {
error(ERROR_UNKNOWN_KEYWORD, "Expected a keyword, got: %s", state.token);
}
@ -1681,6 +1735,10 @@ int main(int argc, char **argv) {
fprintf(source, "\n\n");
emit_dependencies(source);
fprintf(source, "\n\n");
emit_argcheck_helper();
emit_userdata_allocators();
@ -1715,6 +1773,8 @@ int main(int argc, char **argv) {
emit_headers(header);
fprintf(header, "#include \"lua/src/lua.hpp\"\n");
fprintf(header, "#include <new>\n\n");
emit_dependencies(header);
fprintf(header, "\n\n");
emit_userdata_declarations();

View File

@ -14,6 +14,12 @@
#include <AP_Common/Location.h>
#if !defined(AP_TERRAIN_AVAILABLE) || (AP_TERRAIN_AVAILABLE != 1)
#error Scripting requires terrain to be available
#endif // !defined(AP_TERRAIN_AVAILABLE) || (AP_TERRAIN_AVAILABLE != 1)
static int binding_argcheck(lua_State *L, int expected_arg_count) {
const int args = lua_gettop(L);
if (args > expected_arg_count) {

View File

@ -14,6 +14,12 @@
#include "lua/src/lua.hpp"
#include <new>
#if !defined(AP_TERRAIN_AVAILABLE) || (AP_TERRAIN_AVAILABLE != 1)
#error Scripting requires terrain to be available
#endif // !defined(AP_TERRAIN_AVAILABLE) || (AP_TERRAIN_AVAILABLE != 1)
int new_Vector2f(lua_State *L);
Vector2f * check_Vector2f(lua_State *L, int arg);
int new_Vector3f(lua_State *L);