@ -21,8 +21,9 @@ char keyword_userdata[] = "userdata";
@@ -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 {
@@ -91,6 +92,7 @@ enum field_type {
TYPE_NONE ,
TYPE_STRING ,
TYPE_ENUM ,
TYPE_LITERAL ,
TYPE_USERDATA ,
} ;
@ -140,6 +142,7 @@ struct type {
@@ -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) {
@@ -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_
@@ -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_
@@ -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_
@@ -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_
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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,
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 ;