-
Notifications
You must be signed in to change notification settings - Fork 684
A tool in jerry-ext: arg validator for binding #1740
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
A tool in jerry-ext: arg validator for binding #1740
Conversation
41ec130
to
2c55f8f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick first pass at reviewing.
Looking promising :)
@@ -0,0 +1,156 @@ | |||
/* Copyright JS Foundation and other contributors, http://js.foundation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move into a new subdirectory ?
tests/unit/jerry-util/arg-validator/**
jerry-util/CMakeLists.txt
Outdated
|
||
# Source directories | ||
file(GLOB SOURCE_UTIL arg-validator/*.c) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To keep it more modular: I would add another jerry-util/arg-validator/CMakeLists.txt
and just recurse into it from here. I'd also create a new target for each util.
* @return a jerry_arg_t instance. | ||
*/ | ||
static inline jerry_arg_t | ||
jerry_arg_custome (void *dest, /**< points to the native argument */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: custom
|
||
if (c_arg_cnt == 0) | ||
{ | ||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to return jerry_create_undefined()
here and not initialize ret
in line 80?
{ | ||
iterator.c_arg_p = &c_arg_p[c_arg_index]; | ||
|
||
ret = c_arg_p[c_arg_index].func (&iterator); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ret = iterator.c_arg_p->func (&iterator)
?
/* The argument's type must be the primitive, e.g. number, string, boolean. */ | ||
#define JERRY_ARG_STRICT true | ||
/* The validator inside will invoke toNumber, toBoolean or toString */ | ||
#define JERRY_ARG_RELAX false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JERRY_ARG_COERCE
or JERRY_ARG_LOOSE
?
FWIW, MDN talks about "loose equality" and "strict equality": https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
Not sure if it these are the established terms.
|
||
/* Inline functions for initializing jerry_arg_t */ | ||
/* The argument's type must be the primitive, e.g. number, string, boolean. */ | ||
#define JERRY_ARG_STRICT true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strict
may sound like it has something to do with use strict;
? Not sure...
/* The argument is optional */ | ||
#define JERRY_ARG_OPTIOANL true | ||
/* The argument is required */ | ||
#define JERRY_ARG_REQUIRED false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather have typedef'd enums for these instead of macros that are bools under the hood.
They work better with code completion.
It also prevents one from using the true
and false
directly, which makes the code less readable.
#define JERRY_ARG_REQUIRED false | ||
static inline jerry_arg_t jerry_arg_number (double *dest, bool is_strict, bool is_optional); | ||
static inline jerry_arg_t jerry_arg_boolean (bool *dest, bool is_strict, bool is_optional); | ||
static inline jerry_arg_t jerry_arg_string (char *dest, uint32_t size, bool is_strict, bool is_optional); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you planning to create another one for the malloc'd one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but firstly, we'd better have jerry_port_malloc in targets, and the malloc in jerry-libc, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, let's get the base framework merged first and then we can add other transforms like the malloc'd-string one.
#define JERRY_ARG_OPTIOANL true | ||
/* The argument is required */ | ||
#define JERRY_ARG_REQUIRED false | ||
static inline jerry_arg_t jerry_arg_number (double *dest, bool is_strict, bool is_optional); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see specific functions for uint8_t
, uint16_t
, etc. that also perform range checking on the input value.
We can add them later too of course. I think it's nice to have a basic jerry_arg_number
though.
@janjongboom @grgustaf @mjessome any feedback? |
Also @gabrielschulhof any feedback? |
afd278c
to
685d6b9
Compare
There was an interesting idea here: since we consider 'util' as a key part of jerryscript, extension ('ext' in short) could be a better name. It emphasizes the relation better. What do you think? |
So Talking about naming. How about naming it after existing argument validation / transformation utilities? For example Or how about calling it just ...? |
|
@HBehrens any feedback? |
|
My two cents (comments and questions that may lead to more and more questions):
(Seems that some of the ideas above contradict with previous comments from @martijnthe . Still, I hope that at least some of them have some value. ) |
@akosthekiss
Just to verify, do you suggest a folder layers like
+1, some extended feature of jerry-ext may need function of standard libc (e.g. malloc, sprintf), then we can build the tests/uint-ext with --jerry-libc=off before we support those functions in jerry-libc |
+1 for jerryx_. It's good idea to keep jerry_ prefix for jerry_core. |
For paths: I would separate the public and private header of extensions. An example: All public headers would go: /jerry-ext/include/std-module-manager.h All the rest would go: This way people would need to pass -I/jerry-ext/include/ directory for their project, and link it with a single archive. Extensions should not depend on each other by default, and if there is a dependency, it should be clearly stated in the extension readme. This way the linker could easily discard the unneded functions. As for unit tests: I know this require a bit more work initially, but when we have dozens of extensions it will worth it. |
|
Re: "header paths" @jiangzidong @zherczeg #include "jerryscript.h"
#include "jerryscript-port.h"
#include "jerryscript-ext/std-module-manager.h" // might cooperate better with other projects
//#include "std-module-manager.h" // more prone to name collisions That could mean path structure for public headers either |
Good feedback, thanks.
Yeah, that has merit as well, so SGTM.
That gets a bit long... For this particular util, I think it's probably a good idea to group transformer functions + helpers in separate header files, because there are already quite many of them and more can/will be added later.
|
@martijnthe alternative suggestion: #include "jerryscript-ext/args-stdint.h" // note the dash instead of the slash We should be able to manage our own name conflicts, so no need for include paths deeper than 2, IMHO. |
Works for me. |
I think we also need docs with utils. Some options:
|
I'm not sure that |
Every documentation should be created into the |
Can you elaborate what you mean with this? |
@martijnthe Sure. Sorry for my brevity. As it currently stands But I could get both the current setup and the here-presented intent wrong. (Note: and I'm not sure why, having Let me add a fourth option:
|
Gotcha. Thanks for explaining. |
685d6b9
to
77299c8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some extra notes (learned during experiments)
jerry-ext/args/arg-iterator-helper.c
Outdated
} | ||
|
||
jerry_value_t ret = *iterator_p->js_arg_p; | ||
iterator_p->js_arg_index++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO, incrementing the index should happen even if it grows higher than cnt.
#define JERRYX_ARG_TRANSFORM_DEF(type) jerry_value_t \ | ||
jerryx_arg_transform_ ## type (jerryx_arg_iterator_t *iterator_p) \ | ||
{ \ | ||
return jerryx_arg_transform_ ## type ## _impl (iterator_p); \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see no need for these trampolines. The actual implementations don't really need the _impl suffix, they simply don't have to be static.
/** | ||
* Signature of the transform funtion. | ||
*/ | ||
typedef jerry_value_t (*jerryx_arg_transform_func_t) (jerryx_arg_iterator_t *iterator_p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is very personal taste (and signature will change anyway), but the name of the function parameter should not be simply iterator_p
, which just repeats the name of the type of the parameter, but should also tell something about the data (e.g., in the previously mentioned commits, js_args was used to highlight that it's an iterator over the JS arguments -- not necessarily the best name, could be js_arg_it, or ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like your idea about the macro helper. what about the js_arg_iter_p
#define JERRYX_ARG_TRANSFORM_FUNC(NAME) \
jerry_value_t NAME (jerryx_arg_js_iterator_t *js_arg_iter_p, \
const jerryx_arg_t *c_arg_p)
jerry_value_t jerryx_arg_transform_function (jerryx_arg_iterator_t *iterator_p); | ||
jerry_value_t jerryx_arg_transform_function_optional (jerryx_arg_iterator_t *iterator_p); | ||
jerry_value_t jerryx_arg_transform_constructor (jerryx_arg_iterator_t *iterator_p); | ||
jerry_value_t jerryx_arg_transform_constructor_optional (jerryx_arg_iterator_t *iterator_p); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these two functions have no implementation
@akosthekiss I cherry-picked your commits and add patch based on it, so you can see the differences clearly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor comments (starts looking good to me)
an open question: shall we or shall we not split the source files into smaller ones? (pro: one/few-function-per-object helps the linker. con: maintainability.)
* Get the current JS argument from the iterator. | ||
* | ||
* Note: | ||
* Unlike jerryx_arg_iterator_pop, it will not change index and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reference should be updated (jerryx_arg_js_iterator_pop)
|
||
/** | ||
* The common function to deal with optional arguments. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's my bad to remove the @return
comments from most of the functions (because I've changed the return types too often during experiments and couldn't keep them updated). We might consider adding them back as it seems that we have consensus on the signature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I missed this one
} /* JERRYX_ARG_TRANSFORM_FUNC */ | ||
|
||
/** | ||
* Define tranformer for optional argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: transformer
const jerryx_arg_t *c_arg_p); /**< native arg */ | ||
|
||
/** | ||
* Helper macro to declare a transform function with proper signature. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might need to add some note on what parameter names it declares. (As this macro is in a public header, other may also use it, so it becomes part of the public API.)
* @return the current JS argument. | ||
*/ | ||
jerry_value_t | ||
jerryx_arg_js_iterator_pop (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note: I've moved the push and pop functions into this source file only because I've previously deleted the arg-iterator-helper.c file during my experiments and was too lazy to re-add it. right now, no bias towards any approach (keep it here or split it out).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will choose to put those jerryx_arg_js_iterator_xxx functions to a arg_js_iterator to keep the maintainability.
And in the future, if we add lots of builtin transform functions, we may also seperate them into different source file according to some similarity, for example, arg-transform-number.c. arg-transform-string.c ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK with me (just don't use underscores in the reintroduced file name but hyphens)
* The common function to deal with optional arguments. | ||
*/ | ||
static jerry_value_t | ||
jerryx_arg_transform_optional (jerryx_arg_js_iterator_t *js_arg_iter_p, /**< available JS args */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we not expose this function as public API, too? could someone reuse this during custom transform implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea.
I'd suggest squashing the current 4 commits and rebasing to latest master on the next update so that we can get a better look at the PR status. |
@akosthekiss @LaszloLango : re. documentation: I'll be writing some docs for this feature. I can take care of updating the hierarchy of the web page to accommodate for Maybe make "API Reference" a dropdown (like "Documents") and have a "Core" menu option for the Examples for the utils could go on the "API Examples" page, but it's getting a bit long. Maybe also make "API Examples" a menu? |
const jerry_value_t *js_arg_p; /**< the JS arguments */ | ||
const jerry_length_t js_arg_cnt; /**< the total num of JS arguments */ | ||
jerry_length_t js_arg_idx; /**< current index of JS argument */ | ||
} jerryx_arg_js_iterator_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still need to forward declare here in the .h and move the type definition into the .c file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe it is better to stay in the public header, because the custom_transformer_function will use the iterator. If we forward declare it, people can only use the iterator-helpers to handle it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can force users to access the iterator via helpers only, that may not be a big problem, the already implemented transform functions did not need direct access to the fields either. But then we also need a helper function to create an interator instance, because jerryx_arg_transform_args and jerryx_arg_transform_args_with_this do need construction.
#include "jerryscript.h" | ||
|
||
|
||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two newlines.
/** | ||
* Tranform a JS argument to a double. Type coercion is allowed. | ||
*/ | ||
JERRYX_ARG_TRANSFORM_FUNC (jerryx_arg_transform_number) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the point of using a macro here. It makes hard to see the arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akosthekiss what's your opinion about the macro?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, personally, it was a big help. We have cca. 30 functions with identical signature. This macro helped me a lot in ensuring that they are really identical. But I can accept a verdict that function declarations should not be hidden by macros, too. It will be tedious to rewrite, but it will have to be done only once. Hopefully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will rewrite them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The compiler checks function definitions and warns if you pass a wrong function. Since all conversion functions should be covered by tests, we would get a compiler error if something is wrong. If we change the macro, we need to rewrite all function bodies, so probably the header is the least problem.
tests/unit-ext/test-common.h
Outdated
|
||
|
||
|
||
#define TEST_ASSERT(x) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of unneded newlines in this file.
tests/unit-ext/test-ext-args.c
Outdated
return jerry_create_undefined (); | ||
|
||
|
||
} /* test_validator2_handler */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lots of unnecessary newlines here as well.
jerry-ext/args/args.c
Outdated
* jerry error: the validator fails. | ||
*/ | ||
jerry_value_t | ||
jerryx_arg_transform_args_with_this (const jerry_value_t this_val, /**< the this_val for the external function */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to me transform sounds like changing something to something else, like changing a sphere to a cube. This function sounds like conversion (same thing, different form). What about jerryx_arg_get ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm get
is too non-descript if you ask me.
I'd be fine with jerryx_arg_convert_this_and_args
and jerryx_arg_convert_args
.
But I think it's a minimal difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to emphasize the this
? Do we have a variant without this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes: jerryx_arg_transform_args
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a variant without this?
Yes. Having the "primitive" w/o the this
special casing is pretty useful for various reasons.
@jiangzidong BTW, looking at the current name, it's probably best to put this
before args
in the name, because this
is processed as the first value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: it seems the first argument is ignored in this code, which is probably the this
, doesn't it? What is the point of having a variant without this
when it can be skipped easily?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point of having a variant without this when it can be skipped easily?
It's useful, for example:
Generally, if you don't care about this
. No need to pass it, no need to create the "ignore", no need to run the this
handling code, etc...
Another concrete use case: inside a (custom) transform function that converts multiple args (but no this
) in one step by calling jerryx_arg_transform_args
inside the transform.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An extra question to the naming dispute (somewhat unrelated to the above): why do we have jerry-ext/args and jerryscript-ext/args.h but have everything prefixed with jerryx_arg_ ? (Sorry for the late hit.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should be arg
, I will change them
tests/unit-ext/test-ext-args.c
Outdated
/* 3th argument should be string */ | ||
jerryx_arg_string (arg3, 5, JERRYX_ARG_COERCE, JERRYX_ARG_REQUIRED), | ||
/* 4th argument should be function, and it is optional */ | ||
jerryx_arg_function (&arg4, JERRYX_ARG_OPTIONAL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems very clever but also very verbose (requires a lot of instructions to generate this structure). Have you considered a scanf like interface (I haven't read all comments)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean create some specifiers to indicate different types? But in that way, users need to learn the meaning of the specifier, and code is hard to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zherczeg we discussed that idea, but the current solution allows the linker to strip out any logic that's not used. A scanf like function would have a big switch
inside which would pull in all transforms. Plus it's not as easily extensible as this solution.
Re. "lots of instructions": @jiangzidong analyzed this solution and it's not that bad. The break-even point w.r.t. code space at the call-site, compared to manual checking, lies between 1-2 arguments. So if a function needs to check more than 1 argument, this solution is already better from a code size point of view than manually writing the validation.
It's also really simple to add helpers on top to make it less verbose if one really wants to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, no scanf please. All those jerry_arg_TYPE functions are static inlines which do nothing but construct/fill a struct. All the JERRYX_ARG_COERCE,REQUIRED,OPTIONAL parameters will be constant-propagated and optimized out, so no function call overhead is involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that. The problem is that the compiler allocates a big structure on the stack (keeps it until the function exits, although it provides nothing useful after the conversion is completed), initialize it with several instructions (not a setmem zero). However I do understand this is quite user friendly, so we can keep it. We can also add other argument parsers later for less generic cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allocates a big structure on the stack
I thought it might be possible to make the jerryx_arg_t mapping[]
a static const
to avoid the stack issue, because the elements are actually all constant data.
Unfortunately the compiler isn't smart enough: error: initializer element is not a compile-time constant
.
I guess if we went with macros instead of inline functions to create the jerryx_arg_t
s, making it static const
would be possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@martijnthe the addresses of local variables would still not be compile time constants, would they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh duh.. you're right.
* @return the index | ||
*/ | ||
jerry_length_t | ||
jerryx_arg_js_iterator_get_index (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion to shrink the utility function name a bit: _get_index -> _index ?
jerry-ext/args/args-internal.h
Outdated
/** | ||
* The iterator structor for JS arguments. | ||
*/ | ||
struct jerryx_arg_js_iterator_t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another place for declaring the struct would be arg-js-iterator-helper.c and not even having an internal header. This would ensure that even the other components of this library would be blocked from accessing the internals of the data structure and would be forced to use the accessor methods. I'm not insisting but that would be perhaps the "nicest" or "cleanest" approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I don't understand. the other components of this library can access to the internal iterator as long as they include this header args-internal.h
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
((Sure. The question is whether we want to allow them that? Whether we want to have a truly opaque iterator type or one that is only opaque to the users of the library? Even in the current for of the PR, arg-transform-functions.c includes args-internal.h but does not use it (all peeks and pops are performed with the help of helpers). Other than arg-js-iterator-helper.c, only args.c uses the knowledge of the internals of the iterator type, when jerryx_arg_transform_args_with_this and jerryx_arg_transform_args construct iterators. If we had one more helper -- say, jerryx_arg_js_iterator_create,construct,init --, then not even args.c had to know how the iterator type looks like.))
Scratch all that. That's not true. Because jerryx_arg_transform_args_with_this and jerryx_arg_transform_args have the iterator in a local variable (not just a pointer to an iterator), they have to know the size of the type, so they have to see the full declaration.
We do need the internal header. (But we don't necessarily have to include it in arg-transform-functions.c as it's unused there, that still holds.)
After removing the macro and removing those unnecessary newlines (in many files) I am fine with this patch. I will likely not be a user for this which makes judging things a bit difficult. |
@zherczeg @akosthekiss : I addressed the above comments and @martijnthe added the document |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Spotted some doc issues. (But note, I'm not a master of docs.)
@zherczeg @LaszloLango @bzsolt Is that OK with you as is?
docs/09.EXT-REFERENCE-ARG.md
Outdated
|
||
The structure defining a single validation/transformation step. | ||
|
||
*Note*: For commonly used validators, `args.h` provides helpers to create the `jerryx_arg_t`s. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
args.h was renamed to arg.h
docs/09.EXT-REFERENCE-ARG.md
Outdated
a successful transformation into `c_arg_p->dest`. In case the validation did | ||
not pass, the transform should not modify `c_arg_p->dest`. | ||
|
||
Additional parameters can be provided to the function through `c_arg_p->extra_info`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
intentional indentation in these 3 lines?
docs/09.EXT-REFERENCE-ARG.md
Outdated
jerryx_arg_ignore (), | ||
|
||
jerryx_arg_boolean (&required_bool, JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED), | ||
jerryx_arg_string (&required_str, sizeof(required_str) JERRYX_ARG_NO_COERCE, JERRYX_ARG_REQUIRED), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing comma
docs/09.EXT-REFERENCE-ARG.md
Outdated
// Validate and transform: | ||
const jerry_value_t rv = | ||
jerryx_arg_transform_this_and_args (this_val, args_p, args_count, | ||
mapping, ARRAY_LENGTH(mapping)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this statement is out of style (=
and line break, no space before (
)
- return value - the `jerry_value_t` argument that was popped. | ||
- `js_arg_iter_p` - the JS arg iterator from which to pop. | ||
|
||
## jerryx_arg_js_iterator_peek |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should not jerryx_arg_js_iterator_index be documented, too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, will add it soon
* @return the index | ||
*/ | ||
jerry_length_t | ||
jerryx_arg_js_iterator_get_index (jerryx_arg_js_iterator_t *js_arg_iter_p) /**< the JS arg iterator */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keeping the longer name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, forgot to change that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (very well done IMO)
🎉 @zherczeg @LaszloLango @bzsolt OK to merge? |
As I see you've got one LGTM and @zherczeg has an in-progress review, so it depends on him. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. The code is surprisingly complex, so it would still be a good idea to create a simplified, scanf like interface for simple argument parsing.
docs/09.EXT-REFERENCE-ARG.md
Outdated
mapping, | ||
ARRAY_LENGTH (mapping)); | ||
|
||
if (jerry_value_has_error_flag (rv)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move {
to the next line.
@zherczeg What's scanf-like style ? like that? {
int x;
bool y;
char z[10];
void * c_args[3] = {&x, &y, z}
uint8_t type[3] = {NUM_STRICT, BOOL_STRICT_OPTIONAL, STRING_LOCAL} // they are enums
is_ok = transform_args (type, c_args, js_args, 3);
} |
It provides some APIs for binding developers, so that they can validate the type of the js argument and convert/assign them to the native argument. Related Issue: jerryscript-project#1716 JerryScript-DCO-1.0-Signed-off-by: Martijn The [email protected] JerryScript-DCO-1.0-Signed-off-by: Zidong Jiang [email protected]
Something like:
Space would separate parameters to be readable. Flags that can be before a type: i (int), b (bool), s (string) (space follows s as a decimal number), o (object), on (object or null). This would focus on simple cases rater than super generic transformations, but would work 90% of the time. Of course we could use enums as well and combine strings, but this would make this too long:
If there is an error, all data is freed (so you don't need to explicitly free successfully parsed jerry_value_t types). |
Yeah, that's what I understood when you mentioned |
Thanks for your explanation, we will think about that in the following patches. |
@jiangzidong @martijnthe I think you are all set to push the big |
@akosthekiss Haha, thanks :) |
🎆 |
Updated on April 23th
the patch is updated by combining review comments:
The doc is not added yet, since we don't get consensus.
It provides some APIs for binding developers, so that
they can validate the type of the js argument and convert/assign them
to the native argument.
Related Issue: #1716
It is the first patch of this util, and some Notes are listed below:
test/unit-ext/test-ext-args
We use functions like
jerry_arg_string
,jerry_arg_number
to create the jerry_arg_t item for each type.Dont differentiate specific type of number, only
double
, which is the return value ofjerry_get_number_value
. Users should handle the conversion betweendouble
to any other number types (e.g. int32, uint32, ...) for themselves.JERRY_ARG_CONVERSION_YES
means the js argument can be automatically invoked by toNumber, toString or toBoolean, i.e. both "100" and Number(100) will treated as number 100.JERRY_ARG_CONVERSION_NO
only accept the primitive type. i.e. neither "100" nor Number(100) will be treated as number.JERRY_ARG_REQUIRED
/JERRY_ARG_OPTIOANL
indicated whether the argument is mandatory or or optional. If it is optional, then when the js argument isundefined
, it will stop the validator/assign but without returning any error.Currently, string with malloc is not supported, it depends on the implementation of
jerry_port_malloc/free
Currently, the error message is quite simple. The detailed error message depends on the
sprintf
injerry-libc