diff --git a/include/mgba/script/macros.h b/include/mgba/script/macros.h index bbde17b07..09ef58df0 100644 --- a/include/mgba/script/macros.h +++ b/include/mgba/script/macros.h @@ -212,20 +212,30 @@ CXX_GUARD_START } \ }, -#define mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) { \ +#define _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, RO) { \ .type = mSCRIPT_CLASS_INIT_INSTANCE_MEMBER, \ .info = { \ .member = { \ .name = #EXPORTED_NAME, \ .type = mSCRIPT_TYPE_MS_ ## TYPE, \ - .offset = offsetof(struct STRUCT, NAME) \ + .offset = offsetof(struct STRUCT, NAME), \ + .readonly = RO \ } \ } \ }, +#define mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) \ + _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, false) + +#define mSCRIPT_DEFINE_STRUCT_CONST_MEMBER_NAMED(STRUCT, TYPE, EXPORTED_NAME, NAME) \ + _mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, EXPORTED_NAME, NAME, true) + #define mSCRIPT_DEFINE_STRUCT_MEMBER(STRUCT, TYPE, NAME) \ mSCRIPT_DEFINE_STRUCT_MEMBER_NAMED(STRUCT, TYPE, NAME, NAME) +#define mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(STRUCT, TYPE, NAME) \ + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER_NAMED(STRUCT, TYPE, NAME, NAME) + #define mSCRIPT_DEFINE_INHERIT(PARENT) { \ .type = mSCRIPT_CLASS_INIT_INHERIT, \ .info = { \ diff --git a/include/mgba/script/types.h b/include/mgba/script/types.h index da13883d2..a771e42c0 100644 --- a/include/mgba/script/types.h +++ b/include/mgba/script/types.h @@ -231,6 +231,7 @@ struct mScriptClassMember { const char* docstring; const struct mScriptType* type; size_t offset; + bool readonly; }; struct mScriptClassCastMember { diff --git a/src/script/docgen.c b/src/script/docgen.c index 502baa705..6c5d553df 100644 --- a/src/script/docgen.c +++ b/src/script/docgen.c @@ -188,6 +188,9 @@ void explainClass(struct mScriptTypeClass* cls, int level) { } docstring = NULL; } + if (details->info.member.readonly) { + fprintf(out, "%s readonly: true\n", indent); + } fprintf(out, "%s type: %s\n", indent, details->info.member.type->name); break; case mSCRIPT_CLASS_INIT_END: diff --git a/src/script/test/classes.c b/src/script/test/classes.c index f4dec7722..ac25ec279 100644 --- a/src/script/test/classes.c +++ b/src/script/test/classes.c @@ -54,6 +54,11 @@ struct TestG { const char* c; }; +struct TestH { + int32_t i; + int32_t j; +}; + static int32_t testAi0(struct TestA* a) { return a->i; } @@ -198,6 +203,12 @@ mSCRIPT_DEFINE_STRUCT(TestG) mSCRIPT_DEFINE_STRUCT_DEFAULT_SET(TestG, setC) mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(TestH) + mSCRIPT_DEFINE_STRUCT_MEMBER(TestH, S32, i) + mSCRIPT_DEFINE_STRUCT_CONST_MEMBER(TestH, S32, j) +mSCRIPT_DEFINE_END; + M_TEST_DEFINE(testALayout) { struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestA)->details.cls; assert_false(cls->init); @@ -1134,6 +1145,47 @@ M_TEST_DEFINE(testGSet) { assert_false(cls->init); } +M_TEST_DEFINE(testHSet) { + struct mScriptTypeClass* cls = mSCRIPT_TYPE_MS_S(TestH)->details.cls; + + struct TestH s = { + .i = 1, + .j = 2, + }; + + struct mScriptValue sval = mSCRIPT_MAKE_S(TestH, &s); + struct mScriptValue val; + struct mScriptValue compare; + + compare = mSCRIPT_MAKE_S32(1); + assert_true(mScriptObjectGet(&sval, "i", &val)); + assert_true(compare.type->equal(&compare, &val)); + + compare = mSCRIPT_MAKE_S32(2); + assert_true(mScriptObjectGet(&sval, "j", &val)); + assert_true(compare.type->equal(&compare, &val)); + + val = mSCRIPT_MAKE_S32(3); + assert_true(mScriptObjectSet(&sval, "i", &val)); + assert_int_equal(s.i, 3); + + val = mSCRIPT_MAKE_S32(4); + assert_false(mScriptObjectSet(&sval, "j", &val)); + assert_int_equal(s.j, 2); + + compare = mSCRIPT_MAKE_S32(3); + assert_true(mScriptObjectGet(&sval, "i", &val)); + assert_true(compare.type->equal(&compare, &val)); + + compare = mSCRIPT_MAKE_S32(2); + assert_true(mScriptObjectGet(&sval, "j", &val)); + assert_true(compare.type->equal(&compare, &val)); + + assert_true(cls->init); + mScriptClassDeinit(cls); + assert_false(cls->init); +} + M_TEST_SUITE_DEFINE(mScriptClasses, cmocka_unit_test(testALayout), cmocka_unit_test(testASignatures), @@ -1150,4 +1202,5 @@ M_TEST_SUITE_DEFINE(mScriptClasses, cmocka_unit_test(testEGet), cmocka_unit_test(testFDeinit), cmocka_unit_test(testGSet), + cmocka_unit_test(testHSet), ) diff --git a/src/script/types.c b/src/script/types.c index bbfb016dc..7382d0411 100644 --- a/src/script/types.c +++ b/src/script/types.c @@ -1472,6 +1472,10 @@ bool mScriptObjectSet(struct mScriptValue* obj, const char* member, struct mScri return true; } + if (m->readonly) { + return false; + } + void* rawMember = (void *)((uintptr_t) obj->value.opaque + m->offset); if (m->type != val->type) { if (!mScriptCast(m->type, val, val)) {