cesanta / v7

Embedded JavaScript engine for C/C++
Other
1.42k stars 177 forks source link

v7_next_prop - No property attributes being returned #571

Closed ScriptBasic closed 7 years ago

ScriptBasic commented 7 years ago

I'm unable to return any property attributes with the v7_next_prop() function. Always returns a zero.

BTW: The Docs for this function are wrong and had to refer to the v7.h file for the correct use.

void v7_destruct_prop_iter_ctx(struct v7 *v7, struct prop_iter_ctx *ctx);

/*
 * Iterate over the `obj`'s properties.
 *
 * Usage example (here we assume we have some `v7_val_t obj`):
 *
 *     struct prop_iter_ctx ctx;
 *     v7_val_t name, val;
 *     v7_prop_attr_t attrs;
 *
 *     v7_init_prop_iter_ctx(v7, obj, &ctx);
 *     while (v7_next_prop(v7, &ctx, &name, &val, &attrs)) {
 *       ...
 *     }
 *     v7_destruct_prop_iter_ctx(v7, &ctx);
 */
int v7_next_prop(struct v7 *v7, struct prop_iter_ctx *ctx, v7_val_t *name,
                 v7_val_t *value, v7_prop_attr_t *attrs);
mkmik commented 7 years ago

could you please provide a minimal but full example of how you use this call ?

ScriptBasic commented 7 years ago

Here is my JS (V7) extension module code and Script BASIC code calling it.

http://www.allbasic.info/forum/index.php?topic=450.msg4858#msg4858

mkmik commented 7 years ago

hmm, it works for me.

Could you just try this simple C file? :

#include <stdio.h>
#include "v7.h"

int main(void) {
  enum v7_err rcode = V7_OK;
  struct v7 *v7 = v7_create();

  v7_val_t obj = v7_mk_object(v7);
  v7_def(v7, obj, "foo", ~0, 0, v7_mk_number(v7, 42));
  v7_def(v7, obj, "bar", ~0, V7_DESC_ENUMERABLE(0), v7_mk_number(v7, 42));

  printf("obj stringifies as: ");
  v7_println(v7, obj);

  printf("iterating properties with v7_next_prop:\n");
  struct prop_iter_ctx ctx;
  v7_val_t name, val;
  v7_prop_attr_t attrs;

  v7_init_prop_iter_ctx(v7, obj, &ctx);
  while (v7_next_prop(v7, &ctx, &name, &val, &attrs)) {
    printf("prop name: ");
    v7_print(v7, name);
    printf(", attrs: %d\n", attrs);
  }
  v7_destruct_prop_iter_ctx(v7, &ctx);

  v7_destroy(v7);
  return (int) rcode;
}
ScriptBasic commented 7 years ago
jrs@laptop:~/sb/source/extensions/js$ gcc nextprop.c v7.c -o nextprop -lm
jrs@laptop:~/sb/source/extensions/js$ ./nextprop
obj stringifies as: {"foo":42}
iterating properties with v7_next_prop:
prop name: "bar", attrs: 2
prop name: "foo", attrs: 0
jrs@laptop:~/sb/source/extensions/js$ 

It looks how I'm defining the attribute is the problem. Hard coding 'V7_DESC_ENUMERABLE(0)' is returning a pointer and a value.

Thanks for your help!

mkmik commented 7 years ago

I don't know :-( sorry, I cannot help you further. Just a quick hunch: are you sure that your v7_def wrapper is correct? What happens if you create the properties from javascript Object.defineProperty; does your next_prop wrapper work for them?

ScriptBasic commented 7 years ago

Here are a few test I ran to establish property attribute settings. Can you take a peek to make sure V7 is doing what it's suppose to be doing?

http://www.allbasic.info/forum/index.php?topic=450.msg4862#msg4862

mkmik commented 7 years ago

Please read this:

/*
 * Property attributes bitmask
 */
typedef unsigned short v7_prop_attr_t;
#define V7_PROPERTY_NON_WRITABLE (1 << 0)
#define V7_PROPERTY_NON_ENUMERABLE (1 << 1)
#define V7_PROPERTY_NON_CONFIGURABLE (1 << 2)
#define V7_PROPERTY_GETTER (1 << 3)
#define V7_PROPERTY_SETTER (1 << 4)
#define _V7_PROPERTY_HIDDEN (1 << 5)
/* property not managed by V7 HEAP */
#define _V7_PROPERTY_OFF_HEAP (1 << 6)
/* special property holding user data and destructor cb */
#define _V7_PROPERTY_USER_DATA_AND_DESTRUCTOR (1 << 7)
/*
 * not a property attribute, but a flag for `v7_def()`. It's here in order to
 * keep all offsets in one place
 */
#define _V7_DESC_PRESERVE_VALUE (1 << 8)

/*
 * Internal helpers for `V7_DESC_...` macros
 */
#define _V7_DESC_SHIFT 16
#define _V7_DESC_MASK ((1 << _V7_DESC_SHIFT) - 1)
#define _V7_MK_DESC(v, n) \
  (((v7_prop_attr_desc_t)(n)) << _V7_DESC_SHIFT | ((v) ? (n) : 0))
#define _V7_MK_DESC_INV(v, n) _V7_MK_DESC(!(v), (n))

/*
 * Property attribute descriptors that may be given to `v7_def()`: for each
 * attribute (`v7_prop_attr_t`), there is a corresponding macro, which takes
 * param: either 1 (set attribute) or 0 (clear attribute). If some particular
 * attribute isn't mentioned at all, it's left unchanged (or default, if the
 * property is being created)
 *
 * There is additional flag: `V7_DESC_PRESERVE_VALUE`. If it is set, the
 * property value isn't changed (or set to `undefined` if the property is being
 * created)
 */
typedef unsigned long v7_prop_attr_desc_t;
#define V7_DESC_WRITABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_WRITABLE)
#define V7_DESC_ENUMERABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_ENUMERABLE)
#define V7_DESC_CONFIGURABLE(v) _V7_MK_DESC_INV(v, V7_PROPERTY_NON_CONFIGURABLE)
#define V7_DESC_GETTER(v) _V7_MK_DESC(v, V7_PROPERTY_GETTER)
#define V7_DESC_SETTER(v) _V7_MK_DESC(v, V7_PROPERTY_SETTER)
#define V7_DESC_PRESERVE_VALUE _V7_DESC_PRESERVE_VALUE

.....

static v7_prop_attr_t apply_attrs_desc(v7_prop_attr_desc_t attrs_desc,
                                       v7_prop_attr_t old_attrs) {
  v7_prop_attr_t ret = old_attrs;
  if (old_attrs & V7_PROPERTY_NON_CONFIGURABLE) {
    /*
     * The property is non-configurable: we can only change it from being
     * writable to non-writable
     */

    if ((attrs_desc >> _V7_DESC_SHIFT) & V7_PROPERTY_NON_WRITABLE &&
        (attrs_desc & V7_PROPERTY_NON_WRITABLE)) {
      ret |= V7_PROPERTY_NON_WRITABLE;
    }

  } else {
    /* The property is configurable: we can change any attributes */
    ret = (old_attrs & ~(attrs_desc >> _V7_DESC_SHIFT)) |
          (attrs_desc & _V7_DESC_MASK);
  }

  return ret;
}

The DESC flags passed to v7_def mirrors the JavaScript standard Object.defineProperty API. But internally we follow an inverse polarity. e.g. a bit is true if the object is not-writeable, or non-configurable; while in the user facing API of v7_def the user decides whether a property is writable or configurable etc...

ScriptBasic commented 7 years ago

I think I have it working now. Please have a look.

http://www.allbasic.info/forum/index.php?topic=450.msg4863#msg4863

mkmik commented 7 years ago

I'm curious: could you please share the rationale for embedding a JS interpreter inside a BASIC interpreter?

ScriptBasic commented 7 years ago

Adding OOP functionality seamlessly to Script BASIC is the main goal. Everything else is icing.

I have embedded Tiny Scheme, Perl and even added a BBC BASIC graphic ext. in SDL.