Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Functions for operating on Maps from C #725

Merged
merged 12 commits into from Jun 14, 2020
Merged

Conversation

avivbeeri
Copy link
Contributor

I found myself wanting to pass structured data from Wren to C, but I didn't want to define a foreign class specifically to do that, so I thought having access to Maps from the C slot API made sense.

@mhermier
Copy link
Contributor

mhermier commented Jan 17, 2020 via email

@avivbeeri
Copy link
Contributor Author

Added something to handle UNDEFINED_VAL.

I suppose the major error case is trying to use an invalid type of object as a map key? Preventing that shouldn't be too difficult, I just need to establish which types are allowed.

@avivbeeri
Copy link
Contributor Author

Although for what it's worth, I can't see anything in the Wren VM which does error checking like that... so does it even enforce what can be used as a key?

@bjorn
Copy link
Contributor

bjorn commented Jan 17, 2020

does it even enforce what can be used as a key?

bool validateKey(WrenVM* vm, Value arg)
{
if (IS_BOOL(arg) || IS_CLASS(arg) || IS_NULL(arg) ||
IS_NUM(arg) || IS_RANGE(arg) || IS_STRING(arg))
{
return true;
}
RETURN_ERROR("Key must be a value type.");
}

@avivbeeri
Copy link
Contributor Author

Ah, pardon me. I guess I can call validateKey before allowing the value to be set.

@avivbeeri
Copy link
Contributor Author

Seem that function isn't exposed to wren_vm.h. is it okay to import wren_primitive.h just for this function call?

I don't want to duplicate it, in case the criteria for valid keys changes in the future.

@avivbeeri
Copy link
Contributor Author

Added in the key-type validation, which hopefully helps cover the potential error scenarios.

Copy link
Contributor

@bjorn bjorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nitpicks.

src/vm/wren_vm.c Outdated Show resolved Hide resolved
src/vm/wren_value.h Outdated Show resolved Hide resolved
src/include/wren.h Outdated Show resolved Hide resolved
@bjorn
Copy link
Contributor

bjorn commented Jan 17, 2020

I think it's a nice addition.

@mhermier
Copy link
Contributor

mhermier commented Jan 17, 2020 via email

@avivbeeri
Copy link
Contributor Author

By "all these functions", do you mean (1) the new ones introduced by this PR, or (2) the whole Wren<->C api?

For (1), the functions I've added here are based on the existing API, which is why they have limited fail-modes.

If your concern is (2), there's a high amount of assumption built into the FFI that you know what you are doing, or are performing your own verification, which I believe is done for performance purposes. Trying to address those shortcoming would be out of scope for this PR.

@ruby0x1
Copy link
Member

ruby0x1 commented Jan 17, 2020

Yes you're correct @avivbeeri, this PR is consistent with the code base as is, and that's reasonable.

@ruby0x1 ruby0x1 added the 0.4.0 The 0.4.0 tag release label Jan 17, 2020
@ruby0x1 ruby0x1 mentioned this pull request Jun 10, 2020
@vladimyr
Copy link
Contributor

@avivbeeri I've accidentally duplicated your effort in #760 🤦
After @ruby0x1 pointed me here I went through your code and figured you might want to add few things:

/* wren.h */

// Returns the number of entries in the map stored in [slot].
int wrenGetMapCount(WrenVM* vm, int slot);
/* wren_vm.c */

int wrenGetMapCount(WrenVM* vm, int slot)
{
  validateApiSlot(vm, slot);
  ASSERT(IS_MAP(vm->apiStack[slot]), "Slot must hold a map.");

  ObjMap* map = AS_MAP(vm->apiStack[slot]);
  return map->count;
}

The reason I'm suggesting it because there is already wrenGetListCount so we keep parity between List and Map API.

Aside from that, kudos for great work 🏆

test/api/maps.h Outdated

WrenForeignMethodFn mapsBindMethod(const char* signature);
void mapBindClass(
const char* className, WrenForeignClassMethods* methods);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing a new line here.

@vladimyr
Copy link
Contributor

@avivbeeri I've rebased your work on top of current master and added wrenGetMapCount. I had to regenerate projects to include new test sources. You can see result here: master...vladimyr:mapFFI

It would be awesome if you could take a look and update this PR accordingly.

@avivbeeri
Copy link
Contributor Author

I figured this would need some maintenance once 0.3.0 dropped.

I'll get onto it when I have a moment, which will likely be this coming weekend.

@ruby0x1 ruby0x1 closed this Jun 12, 2020
@ruby0x1 ruby0x1 reopened this Jun 13, 2020
@ruby0x1 ruby0x1 changed the base branch from master to main June 13, 2020 21:17
@ruby0x1 ruby0x1 merged commit de6a312 into wren-lang:main Jun 14, 2020
@mode777
Copy link
Contributor

mode777 commented Nov 7, 2020

Am I missing something or is it not possible to iterate keys of a map with the implemented functionality? This would be important e.g. for serialization.
We at least need a another method void wrenGetMapKey(WrenVM* vm, int mapSlot, int index, int keySlot); right?

@avivbeeri
Copy link
Contributor Author

At the time I wrote this, you were assumed to know which keys you wanted to extract. The side-step solution is to pass map.keys to your foreign method along with the map you want to act upon.

@ruby0x1
Copy link
Member

ruby0x1 commented Nov 7, 2020

I had some more functions for iteration coming, I just merged the PR with the foundation :)

@mode777
Copy link
Contributor

mode777 commented Nov 7, 2020

@ruby0x1 I'm highly interested in this. Can you give me a hint of how the api will look like. My example from above won't work from what I've learned by now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
0.4.0 The 0.4.0 tag release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants