AP_Scripting: Add literal support to the binding layer
This commit is contained in:
parent
5d3cfcb59c
commit
6caa700c09
@ -36,7 +36,7 @@ include AP_Arming/AP_Arming.h
|
||||
singleton AP_Arming alias arming
|
||||
singleton AP_Arming method disarm boolean
|
||||
singleton AP_Arming method is_armed boolean
|
||||
singleton AP_Arming method arm boolean AP_Arming::Method'enum AP_Arming::Method::RUDDER AP_Arming::Method::MOTORTEST
|
||||
singleton AP_Arming method arm boolean AP_Arming::Method::SCRIPTING'literal
|
||||
|
||||
include AP_BattMonitor/AP_BattMonitor.h
|
||||
|
||||
|
@ -21,8 +21,9 @@ char keyword_userdata[] = "userdata";
|
||||
char keyword_write[] = "write";
|
||||
|
||||
// attributes (should include the leading ' )
|
||||
char keyword_attr_enum[] = "'enum";
|
||||
char keyword_attr_null[] = "'Null";
|
||||
char keyword_attr_enum[] = "'enum";
|
||||
char keyword_attr_literal[] = "'literal";
|
||||
char keyword_attr_null[] = "'Null";
|
||||
|
||||
// type keywords
|
||||
char keyword_boolean[] = "boolean";
|
||||
@ -91,6 +92,7 @@ enum field_type {
|
||||
TYPE_NONE,
|
||||
TYPE_STRING,
|
||||
TYPE_ENUM,
|
||||
TYPE_LITERAL,
|
||||
TYPE_USERDATA,
|
||||
};
|
||||
|
||||
@ -140,6 +142,7 @@ struct type {
|
||||
union {
|
||||
char *userdata_name;
|
||||
char *enum_name;
|
||||
char *literal;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -363,6 +366,7 @@ unsigned int parse_access_flags(struct type * type) {
|
||||
case TYPE_USERDATA:
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_STRING:
|
||||
case TYPE_LITERAL:
|
||||
// a range check is illogical
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
@ -419,6 +423,8 @@ int parse_type(struct type *type, const uint32_t restrictions, enum range_check_
|
||||
if (attribute != NULL) {
|
||||
if (strcmp(attribute, keyword_attr_enum) == 0) {
|
||||
type->flags |= TYPE_FLAGS_ENUM;
|
||||
} else if (strcmp(attribute, keyword_attr_literal) == 0) {
|
||||
type->type = TYPE_LITERAL;
|
||||
} else if (strcmp(attribute, keyword_attr_null) == 0) {
|
||||
if (restrictions & TYPE_RESTRICTION_NOT_NULLABLE) {
|
||||
error(ERROR_USERDATA, "%s is not nullable in this context", data_type);
|
||||
@ -453,6 +459,8 @@ int parse_type(struct type *type, const uint32_t restrictions, enum range_check_
|
||||
} else if (type->flags & TYPE_FLAGS_ENUM) {
|
||||
type->type = TYPE_ENUM;
|
||||
string_copy(&(type->data.enum_name), data_type);
|
||||
} else if (type->type == TYPE_LITERAL) {
|
||||
string_copy(&(type->data.literal), data_type);
|
||||
} else {
|
||||
// assume that this is a user data, we can't validate this until later though
|
||||
type->type = TYPE_USERDATA;
|
||||
@ -475,6 +483,7 @@ int parse_type(struct type *type, const uint32_t restrictions, enum range_check_
|
||||
case TYPE_ENUM:
|
||||
case TYPE_USERDATA:
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
case TYPE_NONE:
|
||||
error(ERROR_USERDATA, "%s types cannot be nullable", data_type);
|
||||
break;
|
||||
@ -498,6 +507,7 @@ int parse_type(struct type *type, const uint32_t restrictions, enum range_check_
|
||||
case TYPE_NONE:
|
||||
case TYPE_STRING:
|
||||
case TYPE_USERDATA:
|
||||
case TYPE_LITERAL:
|
||||
// no sane range checks, so we can ignore this
|
||||
break;
|
||||
}
|
||||
@ -834,6 +844,7 @@ void emit_checker(const struct type t, int arg_number, const char *indentation,
|
||||
fprintf(source, "%suint32_t data_%d = {};\n", indentation, arg_number);
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
case TYPE_LITERAL:
|
||||
return; // nothing to do here, this should potentially be checked outside of this, but it makes an easier implementation to accept it
|
||||
case TYPE_STRING:
|
||||
fprintf(source, "%schar * data_%d = {};\n", indentation, arg_number);
|
||||
@ -892,6 +903,7 @@ void emit_checker(const struct type t, int arg_number, const char *indentation,
|
||||
case TYPE_STRING:
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_USERDATA:
|
||||
case TYPE_LITERAL:
|
||||
// these don't get range checked, so skip the raw_data phase
|
||||
assert(t.range == NULL); // we should have caught this during the parse phase
|
||||
break;
|
||||
@ -917,6 +929,7 @@ void emit_checker(const struct type t, int arg_number, const char *indentation,
|
||||
case TYPE_STRING:
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_USERDATA:
|
||||
case TYPE_LITERAL:
|
||||
// these don't get range checked, so skip the raw_data phase
|
||||
assert(t.range == NULL); // we should have caught this during the parse phase
|
||||
break;
|
||||
@ -952,6 +965,7 @@ void emit_checker(const struct type t, int arg_number, const char *indentation,
|
||||
case TYPE_STRING:
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_USERDATA:
|
||||
case TYPE_LITERAL:
|
||||
assert(t.range == NULL); // we should have caught this during the parse phase
|
||||
break;
|
||||
}
|
||||
@ -1000,6 +1014,9 @@ void emit_checker(const struct type t, int arg_number, const char *indentation,
|
||||
case TYPE_USERDATA:
|
||||
fprintf(source, "%s%s & data_%d = *check_%s(L, %d);\n", indentation, t.data.userdata_name, arg_number, t.data.userdata_name, arg_number);
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
// literals are expected to be done directly later
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
// nothing to do, we've either already emitted a reasonable value, or returned
|
||||
break;
|
||||
@ -1036,6 +1053,9 @@ void emit_userdata_field(const struct userdata *data, const struct userdata_fiel
|
||||
case TYPE_NONE:
|
||||
error(ERROR_INTERNAL, "Can't access a NONE field");
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
error(ERROR_INTERNAL, "Can't access a literal field");
|
||||
break;
|
||||
case TYPE_STRING:
|
||||
fprintf(source, " lua_pushstring(L, ud->%s);\n", field->name);
|
||||
break;
|
||||
@ -1092,7 +1112,7 @@ void emit_userdata_method(const struct userdata *data, const struct method *meth
|
||||
// sanity check number of args called with
|
||||
arg_count = 1;
|
||||
while (arg != NULL) {
|
||||
if (!(arg->type.flags & TYPE_FLAGS_NULLABLE)) {
|
||||
if (!(arg->type.flags & TYPE_FLAGS_NULLABLE) && !(arg->type.type == TYPE_LITERAL)) {
|
||||
arg_count++;
|
||||
}
|
||||
arg = arg->next;
|
||||
@ -1160,12 +1180,35 @@ void emit_userdata_method(const struct userdata *data, const struct method *meth
|
||||
case TYPE_NONE:
|
||||
fprintf(source, " ud->%s(\n", method->name);
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
error(ERROR_USERDATA, "Can't return a literal from a method");
|
||||
break;
|
||||
}
|
||||
|
||||
arg = method->arguments;
|
||||
arg_count = 2;
|
||||
while (arg != NULL) {
|
||||
fprintf(source, " data_%d", arg_count + ((arg->type.flags & TYPE_FLAGS_NULLABLE) ? NULLABLE_ARG_COUNT_BASE : 0));
|
||||
switch (arg->type.type) {
|
||||
case TYPE_BOOLEAN:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_INT8_T:
|
||||
case TYPE_INT16_T:
|
||||
case TYPE_INT32_T:
|
||||
case TYPE_STRING:
|
||||
case TYPE_UINT8_T:
|
||||
case TYPE_UINT16_T:
|
||||
case TYPE_UINT32_T:
|
||||
case TYPE_ENUM:
|
||||
case TYPE_USERDATA:
|
||||
fprintf(source, " data_%d", arg_count + ((arg->type.flags & TYPE_FLAGS_NULLABLE) ? NULLABLE_ARG_COUNT_BASE : 0));
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
fprintf(source, " %s", arg->type.data.literal);
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
error(ERROR_INTERNAL, "Can't pass nil as an argument");
|
||||
break;
|
||||
}
|
||||
arg = arg->next;
|
||||
if (arg != NULL) {
|
||||
fprintf(source, ",\n");
|
||||
@ -1220,6 +1263,9 @@ void emit_userdata_method(const struct userdata *data, const struct method *meth
|
||||
case TYPE_NONE:
|
||||
error(ERROR_INTERNAL, "Attempted to emit a nullable argument of type none");
|
||||
break;
|
||||
case TYPE_LITERAL:
|
||||
error(ERROR_INTERNAL, "Attempted to make a nullable literal");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1257,6 +1303,7 @@ void emit_userdata_method(const struct userdata *data, const struct method *meth
|
||||
fprintf(source, " *check_%s(L, -1) = data;\n", method->return_type.data.userdata_name);
|
||||
break;
|
||||
case TYPE_NONE:
|
||||
case TYPE_LITERAL:
|
||||
// no return value, so don't worry about pushing a value
|
||||
return_count = 0;
|
||||
break;
|
||||
|
@ -1296,12 +1296,9 @@ static int AP_Arming_arm(lua_State *L) {
|
||||
return luaL_argerror(L, 1, "arming not supported on this firmware");
|
||||
}
|
||||
|
||||
binding_argcheck(L, 2);
|
||||
const lua_Integer raw_data_2 = luaL_checkinteger(L, 2);
|
||||
luaL_argcheck(L, ((raw_data_2 >= static_cast<int32_t>(AP_Arming::Method::RUDDER)) && (raw_data_2 <= static_cast<int32_t>(AP_Arming::Method::MOTORTEST))), 2, "argument out of range");
|
||||
const AP_Arming::Method data_2 = static_cast<AP_Arming::Method>(raw_data_2);
|
||||
binding_argcheck(L, 1);
|
||||
const bool data = ud->arm(
|
||||
data_2);
|
||||
AP_Arming::Method::SCRIPTING);
|
||||
|
||||
lua_pushboolean(L, data);
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user