[njs] Moving value methods to njs_value.c.
Dmitry Volyntsev
xeioex at nginx.com
Mon Jul 8 12:46:39 UTC 2019
details: https://hg.nginx.org/njs/rev/5c774a8c8332
branches:
changeset: 1031:5c774a8c8332
user: hongzhidao <hongzhidao at gmail.com>
date: Sat Jul 06 10:27:14 2019 -0400
description:
Moving value methods to njs_value.c.
diffstat:
auto/sources | 1 +
njs/njs_core.h | 1 +
njs/njs_value.c | 418 +++++++++++++++++++++++++++++++++++
njs/njs_value.h | 660 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
njs/njs_vm.c | 431 +-----------------------------------
njs/njs_vm.h | 652 +-------------------------------------------------------
6 files changed, 1091 insertions(+), 1072 deletions(-)
diffs (truncated from 2351 to 1000 lines):
diff -r e03f3e12589e -r 5c774a8c8332 auto/sources
--- a/auto/sources Tue Jul 02 22:18:56 2019 -0400
+++ b/auto/sources Sat Jul 06 10:27:14 2019 -0400
@@ -30,6 +30,7 @@ NXT_TEST_SRCS=" \
NJS_LIB_SRCS=" \
njs/njs.c \
+ njs/njs_value.c \
njs/njs_vm.c \
njs/njs_boolean.c \
njs/njs_number.c \
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_core.h
--- a/njs/njs_core.h Tue Jul 02 22:18:56 2019 -0400
+++ b/njs/njs_core.h Sat Jul 06 10:27:14 2019 -0400
@@ -32,6 +32,7 @@
#include <nxt_sprintf.h>
#include <njs.h>
+#include <njs_value.h>
#include <njs_vm.h>
#include <njs_variable.h>
#include <njs_lexer.h>
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_value.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_value.c Sat Jul 06 10:27:14 2019 -0400
@@ -0,0 +1,418 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <njs_core.h>
+#include <string.h>
+
+
+const njs_value_t njs_value_null = njs_value(NJS_NULL, 0, 0.0);
+const njs_value_t njs_value_undefined = njs_value(NJS_UNDEFINED, 0, NAN);
+const njs_value_t njs_value_false = njs_value(NJS_BOOLEAN, 0, 0.0);
+const njs_value_t njs_value_true = njs_value(NJS_BOOLEAN, 1, 1.0);
+const njs_value_t njs_value_zero = njs_value(NJS_NUMBER, 0, 0.0);
+const njs_value_t njs_value_nan = njs_value(NJS_NUMBER, 0, NAN);
+const njs_value_t njs_value_invalid = njs_value(NJS_INVALID, 0, 0.0);
+
+const njs_value_t njs_string_empty = njs_string("");
+const njs_value_t njs_string_comma = njs_string(",");
+const njs_value_t njs_string_null = njs_string("null");
+const njs_value_t njs_string_undefined = njs_string("undefined");
+const njs_value_t njs_string_boolean = njs_string("boolean");
+const njs_value_t njs_string_false = njs_string("false");
+const njs_value_t njs_string_true = njs_string("true");
+const njs_value_t njs_string_number = njs_string("number");
+const njs_value_t njs_string_minus_zero = njs_string("-0");
+const njs_value_t njs_string_minus_infinity =
+ njs_string("-Infinity");
+const njs_value_t njs_string_plus_infinity =
+ njs_string("Infinity");
+const njs_value_t njs_string_nan = njs_string("NaN");
+const njs_value_t njs_string_string = njs_string("string");
+const njs_value_t njs_string_object = njs_string("object");
+const njs_value_t njs_string_function = njs_string("function");
+const njs_value_t njs_string_memory_error = njs_string("MemoryError");
+
+
+void
+njs_value_retain(njs_value_t *value)
+{
+ njs_string_t *string;
+
+ if (njs_is_string(value)) {
+
+ if (value->long_string.external != 0xff) {
+ string = value->long_string.data;
+
+ nxt_thread_log_debug("retain:%uxD \"%*s\"", string->retain,
+ value->long_string.size, string->start);
+
+ if (string->retain != 0xffff) {
+ string->retain++;
+ }
+ }
+ }
+}
+
+
+void
+njs_value_release(njs_vm_t *vm, njs_value_t *value)
+{
+ njs_string_t *string;
+
+ if (njs_is_string(value)) {
+
+ if (value->long_string.external != 0xff) {
+ string = value->long_string.data;
+
+ nxt_thread_log_debug("release:%uxD \"%*s\"", string->retain,
+ value->long_string.size, string->start);
+
+ if (string->retain != 0xffff) {
+ string->retain--;
+
+#if 0
+ if (string->retain == 0) {
+ if ((u_char *) string + sizeof(njs_string_t)
+ != string->start)
+ {
+ nxt_memcache_pool_free(vm->mem_pool,
+ string->start);
+ }
+
+ nxt_memcache_pool_free(vm->mem_pool, string);
+ }
+#endif
+ }
+ }
+ }
+}
+
+
+nxt_bool_t
+njs_values_strict_equal(const njs_value_t *val1, const njs_value_t *val2)
+{
+ size_t size, length1, length2;
+ const u_char *start1, *start2;
+
+ if (val1->type != val2->type) {
+ return 0;
+ }
+
+ if (njs_is_numeric(val1)) {
+
+ if (njs_is_undefined(val1)) {
+ return 1;
+ }
+
+ /* Infinities are handled correctly by comparision. */
+ return (val1->data.u.number == val2->data.u.number);
+ }
+
+ if (njs_is_string(val1)) {
+ size = val1->short_string.size;
+
+ if (size != val2->short_string.size) {
+ return 0;
+ }
+
+ if (size != NJS_STRING_LONG) {
+ length1 = val1->short_string.length;
+ length2 = val2->short_string.length;
+
+ /*
+ * Using full memcmp() comparison if at least one string
+ * is a Byte string.
+ */
+ if (length1 != 0 && length2 != 0 && length1 != length2) {
+ return 0;
+ }
+
+ start1 = val1->short_string.start;
+ start2 = val2->short_string.start;
+
+ } else {
+ size = val1->long_string.size;
+
+ if (size != val2->long_string.size) {
+ return 0;
+ }
+
+ length1 = val1->long_string.data->length;
+ length2 = val2->long_string.data->length;
+
+ /*
+ * Using full memcmp() comparison if at least one string
+ * is a Byte string.
+ */
+ if (length1 != 0 && length2 != 0 && length1 != length2) {
+ return 0;
+ }
+
+ start1 = val1->long_string.data->start;
+ start2 = val2->long_string.data->start;
+ }
+
+ return (memcmp(start1, start2, size) == 0);
+ }
+
+ return (val1->data.u.object == val2->data.u.object);
+}
+
+
+/*
+ * A hint value is 0 for numbers and 1 for strings. The value chooses
+ * method calls order specified by ECMAScript 5.1: "valueOf", "toString"
+ * for numbers and "toString", "valueOf" for strings.
+ */
+
+njs_ret_t
+njs_value_to_primitive(njs_vm_t *vm, njs_value_t *value, nxt_uint_t hint)
+{
+ njs_ret_t ret;
+ njs_value_t *retval;
+ njs_function_t *function;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+
+ static const uint32_t hashes[] = {
+ NJS_VALUE_OF_HASH,
+ NJS_TO_STRING_HASH,
+ };
+
+ static const nxt_str_t names[] = {
+ nxt_string("valueOf"),
+ nxt_string("toString"),
+ };
+
+ if (!njs_is_primitive(value)) {
+ retval = &vm->top_frame->trap_scratch;
+
+ if (!njs_is_primitive(retval)) {
+
+ for ( ;; ) {
+ ret = NXT_ERROR;
+
+ if (njs_is_object(value) && vm->top_frame->trap_tries < 2) {
+ hint ^= vm->top_frame->trap_tries++;
+
+ lhq.key_hash = hashes[hint];
+ lhq.key = names[hint];
+
+ prop = njs_object_property(vm, value->data.u.object, &lhq);
+
+ if (nxt_fast_path(prop != NULL)) {
+
+ if (!njs_is_function(&prop->value)) {
+ /* Try the second method. */
+ continue;
+ }
+
+ function = prop->value.data.u.function;
+
+ ret = njs_function_apply(vm, function, value, 1,
+ (njs_index_t) retval);
+ /*
+ * njs_function_apply() can return
+ * NXT_OK, NJS_APPLIED, NXT_ERROR, NXT_AGAIN.
+ */
+ if (nxt_fast_path(ret == NXT_OK)) {
+
+ if (njs_is_primitive(&vm->retval)) {
+ retval = &vm->retval;
+ break;
+ }
+
+ /* Try the second method. */
+ continue;
+ }
+
+ if (ret == NJS_APPLIED) {
+ /*
+ * A user-defined method or continuation have
+ * been prepared to run. The method will return
+ * to the current instruction and will restart it.
+ */
+ ret = 0;
+ }
+ }
+ }
+
+ if (ret == NXT_ERROR) {
+ njs_type_error(vm,
+ "Cannot convert object to primitive value");
+ }
+
+ return ret;
+ }
+ }
+
+ *value = *retval;
+
+ njs_set_invalid(retval);
+ }
+
+ vm->top_frame->trap_tries = 0;
+
+ return 1;
+}
+
+
+njs_array_t *
+njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
+ njs_object_enum_t kind, nxt_bool_t all)
+{
+ njs_object_value_t obj_val;
+
+ if (njs_is_object(value)) {
+ return njs_object_enumerate(vm, value->data.u.object, kind, all);
+ }
+
+ if (value->type != NJS_STRING) {
+ return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
+ }
+
+ obj_val.object = vm->string_object;
+ obj_val.value = *value;
+
+ return njs_object_enumerate(vm, (njs_object_t *) &obj_val, kind, all);
+}
+
+
+njs_array_t *
+njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
+ njs_object_enum_t kind, nxt_bool_t all)
+{
+ njs_object_value_t obj_val;
+
+ if (njs_is_object(value)) {
+ return njs_object_own_enumerate(vm, value->data.u.object, kind, all);
+ }
+
+ if (value->type != NJS_STRING) {
+ return njs_array_alloc(vm, 0, NJS_ARRAY_SPARE);
+ }
+
+ obj_val.object = vm->string_object;
+ obj_val.value = *value;
+
+ return njs_object_own_enumerate(vm, (njs_object_t *) &obj_val, kind, all);
+}
+
+
+const char *
+njs_type_string(njs_value_type_t type)
+{
+ switch (type) {
+ case NJS_NULL:
+ return "null";
+
+ case NJS_UNDEFINED:
+ return "undefined";
+
+ case NJS_BOOLEAN:
+ return "boolean";
+
+ case NJS_NUMBER:
+ return "number";
+
+ case NJS_STRING:
+ return "string";
+
+ case NJS_EXTERNAL:
+ return "external";
+
+ case NJS_INVALID:
+ return "invalid";
+
+ case NJS_OBJECT:
+ return "object";
+
+ case NJS_ARRAY:
+ return "array";
+
+ case NJS_OBJECT_BOOLEAN:
+ return "object boolean";
+
+ case NJS_OBJECT_NUMBER:
+ return "object number";
+
+ case NJS_OBJECT_STRING:
+ return "object string";
+
+ case NJS_FUNCTION:
+ return "function";
+
+ case NJS_REGEXP:
+ return "regexp";
+
+ case NJS_DATE:
+ return "date";
+
+ case NJS_OBJECT_ERROR:
+ return "error";
+
+ case NJS_OBJECT_EVAL_ERROR:
+ return "eval error";
+
+ case NJS_OBJECT_INTERNAL_ERROR:
+ return "internal error";
+
+ case NJS_OBJECT_RANGE_ERROR:
+ return "range error";
+
+ case NJS_OBJECT_REF_ERROR:
+ return "reference error";
+
+ case NJS_OBJECT_SYNTAX_ERROR:
+ return "syntax error";
+
+ case NJS_OBJECT_TYPE_ERROR:
+ return "type error";
+
+ case NJS_OBJECT_URI_ERROR:
+ return "uri error";
+
+ default:
+ return NULL;
+ }
+}
+
+
+const char *
+njs_arg_type_string(uint8_t arg)
+{
+ switch (arg) {
+ case NJS_SKIP_ARG:
+ return "skip";
+
+ case NJS_NUMBER_ARG:
+ return "number";
+
+ case NJS_INTEGER_ARG:
+ return "integer";
+
+ case NJS_STRING_ARG:
+ return "string";
+
+ case NJS_OBJECT_ARG:
+ return "object";
+
+ case NJS_STRING_OBJECT_ARG:
+ return "string object";
+
+ case NJS_FUNCTION_ARG:
+ return "function";
+
+ case NJS_REGEXP_ARG:
+ return "regexp";
+
+ case NJS_DATE_ARG:
+ return "date";
+
+ default:
+ return "unknown";
+ }
+}
diff -r e03f3e12589e -r 5c774a8c8332 njs/njs_value.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/njs/njs_value.h Sat Jul 06 10:27:14 2019 -0400
@@ -0,0 +1,660 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_VALUE_H_INCLUDED_
+#define _NJS_VALUE_H_INCLUDED_
+
+
+#include <nxt_trace.h>
+#include <nxt_queue.h>
+#include <nxt_regex.h>
+#include <nxt_random.h>
+#include <nxt_djb_hash.h>
+#include <nxt_mp.h>
+
+#include <math.h>
+
+
+/*
+ * The order of the enum is used in njs_vmcode_typeof()
+ * and njs_object_prototype_to_string().
+ */
+
+typedef enum {
+ NJS_NULL = 0x00,
+ NJS_UNDEFINED = 0x01,
+
+ /* The order of the above type is used in njs_is_null_or_undefined(). */
+
+ NJS_BOOLEAN = 0x02,
+ /*
+ * The order of the above type is used in
+ * njs_is_null_or_undefined_or_boolean().
+ */
+ NJS_NUMBER = 0x03,
+ /*
+ * The order of the above type is used in njs_is_numeric().
+ * Booleans, null and void values can be used in mathematical operations:
+ * a numeric value of the true value is one,
+ * a numeric value of the null and false values is zero,
+ * a numeric value of the void value is NaN.
+ */
+ NJS_STRING = 0x04,
+
+ /* The order of the above type is used in njs_is_primitive(). */
+
+ NJS_DATA = 0x05,
+
+ /* The type is external code. */
+ NJS_EXTERNAL = 0x06,
+
+ /*
+ * The invalid value type is used:
+ * for uninitialized array members,
+ * to detect non-declared explicitly or implicitly variables,
+ * for native property getters.
+ */
+ NJS_INVALID = 0x07,
+
+ /*
+ * The object types are >= NJS_OBJECT, this is used in njs_is_object().
+ * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be
+ * in the same order as NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING. It is
+ * used in njs_primitive_prototype_index(). The order of object types
+ * is used in vm->prototypes and vm->constructors arrays.
+ */
+ NJS_OBJECT = 0x10,
+ NJS_ARRAY = 0x11,
+ NJS_OBJECT_BOOLEAN = 0x12,
+ NJS_OBJECT_NUMBER = 0x13,
+ NJS_OBJECT_STRING = 0x14,
+ NJS_FUNCTION = 0x15,
+ NJS_REGEXP = 0x16,
+ NJS_DATE = 0x17,
+ NJS_OBJECT_ERROR = 0x18,
+ NJS_OBJECT_EVAL_ERROR = 0x19,
+ NJS_OBJECT_INTERNAL_ERROR = 0x1a,
+ NJS_OBJECT_RANGE_ERROR = 0x1b,
+ NJS_OBJECT_REF_ERROR = 0x1c,
+ NJS_OBJECT_SYNTAX_ERROR = 0x1d,
+ NJS_OBJECT_TYPE_ERROR = 0x1e,
+ NJS_OBJECT_URI_ERROR = 0x1f,
+ NJS_OBJECT_VALUE = 0x20,
+#define NJS_TYPE_MAX (NJS_OBJECT_VALUE + 1)
+} njs_value_type_t;
+
+
+/*
+ * njs_prop_handler_t operates as a property getter and/or setter.
+ * The handler receives NULL setval if it is invoked in GET context and
+ * non-null otherwise.
+ *
+ * njs_prop_handler_t is expected to return:
+ * NXT_OK - handler executed successfully;
+ * NXT_ERROR - some error, vm->retval contains appropriate exception;
+ * NXT_DECLINED - handler was applied to inappropriate object.
+ */
+typedef njs_ret_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *setval, njs_value_t *retval);
+typedef njs_ret_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
+ nxt_uint_t nargs, njs_index_t retval);
+
+
+typedef struct njs_string_s njs_string_t;
+typedef struct njs_object_s njs_object_t;
+typedef struct njs_object_value_s njs_object_value_t;
+typedef struct njs_function_lambda_s njs_function_lambda_t;
+typedef struct njs_regexp_pattern_s njs_regexp_pattern_t;
+typedef struct njs_array_s njs_array_t;
+typedef struct njs_regexp_s njs_regexp_t;
+typedef struct njs_date_s njs_date_t;
+typedef struct njs_property_next_s njs_property_next_t;
+typedef struct njs_object_init_s njs_object_init_t;
+
+
+union njs_value_s {
+ /*
+ * The njs_value_t size is 16 bytes and must be aligned to 16 bytes
+ * to provide 4 bits to encode scope in njs_index_t. This space is
+ * used to store short strings. The maximum size of a short string
+ * is 14 (NJS_STRING_SHORT). If the short_string.size field is 15
+ * (NJS_STRING_LONG) then the size is in the long_string.size field
+ * and the long_string.data field points to a long string.
+ *
+ * The number of the string types is limited to 2 types to minimize
+ * overhead of processing string fields. It is also possible to add
+ * strings with size from 14 to 254 which size and length are stored in
+ * the string_size and string_length byte wide fields. This will lessen
+ * the maximum size of short string to 13.
+ */
+ struct {
+ njs_value_type_t type:8; /* 6 bits */
+ /*
+ * The truth field is set during value assignment and then can be
+ * quickly tested by logical and conditional operations regardless
+ * of value type. The truth field coincides with short_string.size
+ * and short_string.length so when string size and length are zero
+ * the string's value is false.
+ */
+ uint8_t truth;
+
+ uint16_t _spare1;
+ uint32_t _spare2;
+
+ union {
+ double number;
+ njs_object_t *object;
+ njs_array_t *array;
+ njs_object_value_t *object_value;
+ njs_function_t *function;
+ njs_function_lambda_t *lambda;
+ njs_regexp_t *regexp;
+ njs_date_t *date;
+ njs_prop_handler_t prop_handler;
+ njs_value_t *value;
+ njs_property_next_t *next;
+ void *data;
+ } u;
+ } data;
+
+ struct {
+ njs_value_type_t type:8; /* 6 bits */
+
+#define NJS_STRING_SHORT 14
+#define NJS_STRING_LONG 15
+
+ uint8_t size:4;
+ uint8_t length:4;
+
+ u_char start[NJS_STRING_SHORT];
+ } short_string;
+
+ struct {
+ njs_value_type_t type:8; /* 6 bits */
+ uint8_t truth;
+
+ /* 0xff if data is external string. */
+ uint8_t external;
+ uint8_t _spare;
+
+ uint32_t size;
+ njs_string_t *data;
+ } long_string;
+
+ struct {
+ njs_value_type_t type:8; /* 6 bits */
+ uint8_t truth;
+
+ uint16_t _spare;
+
+ uint32_t index;
+ const njs_extern_t *proto;
+ } external;
+
+ njs_value_type_t type:8; /* 6 bits */
+};
+
+
+struct njs_object_s {
+ /* A private hash of njs_object_prop_t. */
+ nxt_lvlhsh_t hash;
+
+ /* A shared hash of njs_object_prop_t. */
+ nxt_lvlhsh_t shared_hash;
+
+ /* An object __proto__. */
+ njs_object_t *__proto__;
+
+ /* The type is used in constructor prototypes. */
+ njs_value_type_t type:8;
+ uint8_t shared; /* 1 bit */
+ uint8_t extensible; /* 1 bit */
+};
+
+
+struct njs_object_value_s {
+ njs_object_t object;
+ /* The value can be unaligned since it never used in nJSVM operations. */
+ njs_value_t value;
+};
+
+
+struct njs_array_s {
+ njs_object_t object;
+ uint32_t size;
+ uint32_t length;
+ njs_value_t *start;
+ njs_value_t *data;
+};
+
+
+typedef struct {
+ union {
+ uint32_t count;
+ njs_value_t values;
+ } u;
+
+ njs_value_t values[1];
+} njs_closure_t;
+
+
+#define NJS_ARGS_TYPES_MAX 5
+
+struct njs_function_s {
+ njs_object_t object;
+
+ uint8_t args_types[NJS_ARGS_TYPES_MAX];
+ uint8_t args_offset;
+ uint8_t continuation_size;
+
+ /* Function is a closure. */
+ uint8_t closure:1;
+
+ uint8_t native:1;
+ uint8_t ctor:1;
+
+ union {
+ njs_function_lambda_t *lambda;
+ njs_function_native_t native;
+ } u;
+
+ njs_value_t *bound;
+#if (NXT_SUNC)
+ njs_closure_t *closures[1];
+#else
+ njs_closure_t *closures[];
+#endif
+};
+
+
+struct njs_regexp_s {
+ njs_object_t object;
+ uint32_t last_index;
+ njs_regexp_pattern_t *pattern;
+ /*
+ * This string value can be unaligned since
+ * it never used in nJSVM operations.
+ */
+ njs_value_t string;
+};
+
+
+struct njs_date_s {
+ njs_object_t object;
+ double time;
+};
+
+
+typedef union {
+ njs_object_t object;
+ njs_object_value_t object_value;
+ njs_array_t array;
+ njs_function_t function;
+ njs_regexp_t regexp;
+ njs_date_t date;
+} njs_object_prototype_t;
+
+
+typedef enum {
+ NJS_ENUM_KEYS,
+ NJS_ENUM_VALUES,
+ NJS_ENUM_BOTH,
+} njs_object_enum_t;
+
+
+#define njs_value(_type, _truth, _number) { \
+ .data = { \
+ .type = _type, \
+ .truth = _truth, \
+ .u.number = _number, \
+ } \
+}
+
+
+#define njs_string(s) { \
+ .short_string = { \
+ .type = NJS_STRING, \
+ .size = nxt_length(s), \
+ .length = nxt_length(s), \
+ .start = s, \
+ } \
+}
+
+
+/* NJS_STRING_LONG is set for both big and little endian platforms. */
+
+#define njs_long_string(s) { \
+ .long_string = { \
+ .type = NJS_STRING, \
+ .truth = (NJS_STRING_LONG << 4) | NJS_STRING_LONG, \
+ .size = nxt_length(s), \
+ .data = & (njs_string_t) { \
+ .start = (u_char *) s, \
+ .length = nxt_length(s), \
+ } \
+ } \
+}
+
+
+#define njs_native_function(_function, _size, ...) { \
+ .data = { \
+ .type = NJS_FUNCTION, \
+ .truth = 1, \
+ .u.function = & (njs_function_t) { \
+ .native = 1, \
+ .continuation_size = _size, \
+ .args_types = { __VA_ARGS__ }, \
+ .args_offset = 1, \
+ .u.native = _function, \
+ .object = { .type = NJS_FUNCTION, \
+ .shared = 1, \
+ .extensible = 1 }, \
+ } \
+ } \
+}
+
+
+#define njs_prop_handler(_handler) { \
+ .data = { \
+ .type = NJS_INVALID, \
+ .truth = 1, \
+ .u = { .prop_handler = _handler } \
+ } \
+}
+
+
+#define njs_is_null(value) \
+ ((value)->type == NJS_NULL)
+
+
+#define njs_is_undefined(value) \
+ ((value)->type == NJS_UNDEFINED)
+
+
+#define njs_is_null_or_undefined(value) \
+ ((value)->type <= NJS_UNDEFINED)
+
+
+#define njs_is_boolean(value) \
+ ((value)->type == NJS_BOOLEAN)
+
+
+#define njs_is_null_or_undefined_or_boolean(value) \
+ ((value)->type <= NJS_BOOLEAN)
+
+
+#define njs_is_true(value) \
+ ((value)->data.truth != 0)
+
+
+#define njs_is_number(value) \
+ ((value)->type == NJS_NUMBER)
+
+
+/* Testing for NaN first generates a better code at least on i386/amd64. */
+
+#define njs_is_number_true(num) \
+ (!isnan(num) && num != 0)
+
+
+#define njs_is_numeric(value) \
+ ((value)->type <= NJS_NUMBER)
+
+
+#define njs_is_string(value) \
+ ((value)->type == NJS_STRING)
+
+#define njs_is_error(value) \
+ ((value)->type >= NJS_OBJECT_ERROR \
+ && (value)->type <= NJS_OBJECT_URI_ERROR)
+
+
+/*
+ * The truth field coincides with short_string.size and short_string.length
+ * so when string size and length are zero the string's value is false and
+ * otherwise is true.
+ */
+#define njs_string_truth(value, size)
+
+
+#define njs_string_get(value, str) \
+ do { \
+ if ((value)->short_string.size != NJS_STRING_LONG) { \
+ (str)->length = (value)->short_string.size; \
+ (str)->start = (u_char *) (value)->short_string.start; \
+ \
+ } else { \
+ (str)->length = (value)->long_string.size; \
+ (str)->start = (u_char *) (value)->long_string.data->start; \
+ } \
+ } while (0)
+
+
+#define njs_string_short_start(value) \
+ (value)->short_string.start
+
+
+#define njs_string_short_set(value, _size, _length) \
+ do { \
+ (value)->type = NJS_STRING; \
+ njs_string_truth(value, _size); \
+ (value)->short_string.size = _size; \
+ (value)->short_string.length = _length; \
+ } while (0)
+
+
+#define njs_string_length_set(value, _length) \
+ do { \
+ if ((value)->short_string.size != NJS_STRING_LONG) { \
+ (value)->short_string.length = length; \
+ \
+ } else { \
+ (value)->long_string.data->length = length; \
+ } \
+ } while (0)
+
+#define njs_is_primitive(value) \
+ ((value)->type <= NJS_STRING)
+
+
+#define njs_is_data(value) \
+ ((value)->type == NJS_DATA)
+
+
+#define njs_is_object(value) \
+ ((value)->type >= NJS_OBJECT)
+
+
+#define njs_is_object_value(value) \
+ ((value)->type == NJS_OBJECT_VALUE)
+
+
+#define njs_object_value_type(type) \
+ (type + NJS_OBJECT)
+
+
+#define njs_is_array(value) \
+ ((value)->type == NJS_ARRAY)
+
+
+#define njs_is_function(value) \
+ ((value)->type == NJS_FUNCTION)
+
+
+#define njs_is_regexp(value) \
+ ((value)->type == NJS_REGEXP)
+
+
+#define njs_is_date(value) \
+ ((value)->type == NJS_DATE)
+
+
+#define njs_is_external(value) \
+ ((value)->type == NJS_EXTERNAL)
+
+
+#define njs_is_valid(value) \
+ ((value)->type != NJS_INVALID)
+
+
+#define njs_bool(value) \
+ ((value)->data.truth)
+
+
+#define njs_number(value) \
+ ((value)->data.u.number)
+
+
+#define njs_data(value) \
+ ((value)->data.u.data)
+
+
+#define njs_function(value) \
+ ((value)->data.u.function)
+
+
+#define njs_object(value) \
+ ((value)->data.u.object)
+
+
+#define njs_object_hash(value) \
+ (&(value)->data.u.object->hash)
+
+
+#define njs_array(value) \
+ ((value)->data.u.array)
+
+
+#define njs_array_len(value) \
+ ((value)->data.u.array->length)
+
+
+#define njs_array_start(value) \
+ ((value)->data.u.array->start)
+
+
+#define njs_set_undefined(value) \
+ *(value) = njs_value_undefined
+
+
+#define njs_set_boolean(value, yn) \
+ *(value) = yn ? njs_value_true : njs_value_false
+
+
+#define njs_set_true(value) \
+ *(value) = njs_value_true
+
+
+#define njs_set_false(value) \
+ *(value) = njs_value_false
More information about the nginx-devel
mailing list