berry-lang / berry

A ultra-lightweight embedded scripting language optimized for microcontrollers.
https://berry-lang.github.io
MIT License
807 stars 97 forks source link

FFI: pass list as argument #286

Closed hiperiondev closed 1 year ago

hiperiondev commented 2 years ago

I'm trying to create a function that get a list as argument

I need to make something like this:

a=class() b=[1,2,3] a.set(b)

But I can't create the FFI function I've tryied:

void class_set(data_t data, void values) { (...) } BE_FUNC_CTYPE_DECLARE(class_set, "", "(class) list")

... and many other variants on BE_FUNC_CTYPE_DECLARE but ever have error: value_error: Unexpected 'list'

s-hadinger commented 2 years ago

It should be BE_FUNC_CTYPE_DECLARE(class_set, "", "(list)")

hiperiondev commented 2 years ago

That doesn't work because it first expects a type class (data_t data). Maybe list doesn't return a void? (void *values)

s-hadinger commented 2 years ago

Oh, yes. You are right. The mapping for an instance can only return an internal pointer .p or _p. It cannot work with a list. Anyways a Berry list is not a C object per se, and needs berry apis, so the C mapping doesn't really make sense here.

hiperiondev commented 2 years ago

I understand. So how could I create a function that takes a list as an argument? To be able to carry out the action of the example:

a=class() b=[1,2,3] a.set(b)

s-hadinger commented 2 years ago

You need to do it with a C native function and call Berry APIs to extract arguments, not with the C types mapping.

hiperiondev commented 2 years ago

OK. Then the function will be something like: int class_set(bvm *vm) (like in prototype)

where is then in stack self and list?

I need to retrieve data_t *data saved in var a and access the list. class_set is a method of class

hiperiondev commented 2 years ago

some test: int class_set(bvm *vm) { printf("list0: %d\n", be_islist(vm, 0)); printf("list1: %d\n", be_islist(vm, 1)); printf("list2: %d\n", be_islist(vm, 2)); printf("list3: %d\n", be_islist(vm, 3)); printf("list0: %d\n", be_isinstance(vm, 0)); printf("list1: %d\n", be_isinstance(vm, 1)); printf("list2: %d\n", be_isinstance(vm, 2)); printf("list3: %d\n", be_isinstance(vm, 3));

be_return(vm);

} berry> a=class("int") berry> b=[1,2] berry> a.set(b)

list0: 0 list1: 0 list2: 0 list3: 0 instance0: 0 instance1: 1 instance2: 1 instance3: 0 [1, 2]

Then in stk0 (be_return returns the object at the top of the stack) I have the list and in stk 1 and 2 I have instances It is correct?

s-hadinger commented 2 years ago

Slot 0 is invalid and does not exist. Slot 1 is the first arg, here self Slot 2 is the second argument hence the instance of the list class. This is not a list object. The instance contains a member .p that contains the internal list structure. I know this is confusing and it took me some time to realize that.

be_getmember(vm, 1, ".p") will get you the list object that you can check with be_islist(vm, -1)

hiperiondev commented 2 years ago

Perfect. But a is a pointer to an external data. data_t *data = be_tocomptr(vm, 1); returns NULL

s-hadinger commented 2 years ago

I'm not sure to understand what you mean. be_tocomptr() is only meant to get the value of a comptr argument. What are you trying to do ?

hiperiondev commented 2 years ago

As there is no clear documentation on this, I am guided by the code of berry_int64

I create an external data type with the init method: void class_init(bvm vm) { data_t data = (data_t) be_malloc(vm, sizeof(data_t)); return data; }

Then I want to modify it with the set method passing a list as an argument. In the case of berry_int64 it is simpler because you can map set to ctype by using two int32_t, but this is not possible with a list

s-hadinger commented 2 years ago

You really shouldn't take berry_int64 as a starting point, it uses advanced techniques that you probably don't need. Especially it wraps a C structure into a Berry object.

Take the existing Berry libraries as examples (be_listlib.c, be_introspectlib.c, be_stringlib.c...)

What are you trying to do?

hiperiondev commented 2 years ago

I want to add IEC61131 data types. I already did this for Lua but I find it much more interesting to do it in Berry.

s-hadinger commented 2 years ago

I'm unfamiliar with IEC61131 data types. Do you have examples? Are you using an existing C lib?

hiperiondev commented 2 years ago

IEC 61131-3 defines the programming standard for industrial PLCs. I'm not using any standard library, but something that I did (although at some point I will port all this to something decoupled and more generic)

hiperiondev commented 2 years ago

I have started to decoupling my library for IEC 61131-3: https://github.com/hiperiondev/iec61131lib

Maybe this week could be usable.

hiperiondev commented 1 year ago

Solved