From: Igor Sysoev Date: Mon, 23 Nov 2015 19:36:52 +0000 (+0300) Subject: Boolean objects support. X-Git-Tag: 0.1.0~113 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=bb9431b8913ef7f6fc5383a1f0cfc6a117d3359f;p=njs.git Boolean objects support. --- diff --git a/Makefile b/Makefile index 68a6bfb4..b6c7a20e 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/njscript.o \ $(NXT_BUILDDIR)/njs_vm.o \ + $(NXT_BUILDDIR)/njs_boolean.o \ $(NXT_BUILDDIR)/njs_number.o \ $(NXT_BUILDDIR)/njs_string.o \ $(NXT_BUILDDIR)/njs_object.o \ @@ -38,6 +39,7 @@ $(NXT_BUILDDIR)/libnjs.a: \ ar -r -c $(NXT_BUILDDIR)/libnjs.a \ $(NXT_BUILDDIR)/njscript.o \ $(NXT_BUILDDIR)/njs_vm.o \ + $(NXT_BUILDDIR)/njs_boolean.o \ $(NXT_BUILDDIR)/njs_number.o \ $(NXT_BUILDDIR)/njs_string.o \ $(NXT_BUILDDIR)/njs_object.o \ @@ -115,6 +117,19 @@ $(NXT_BUILDDIR)/njs_vm.o: \ -I$(NXT_LIB) -Injs \ njs/njs_vm.c +$(NXT_BUILDDIR)/njs_boolean.o: \ + $(NXT_BUILDDIR)/libnxt.a \ + njs/njscript.h \ + njs/njs_vm.h \ + njs/njs_boolean.h \ + njs/njs_object.h \ + njs/njs_function.h \ + njs/njs_boolean.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/njs_boolean.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) -Injs \ + njs/njs_boolean.c + $(NXT_BUILDDIR)/njs_number.o: \ $(NXT_BUILDDIR)/libnxt.a \ njs/njscript.h \ @@ -233,6 +248,7 @@ $(NXT_BUILDDIR)/njs_shared.o: \ $(NXT_BUILDDIR)/libnxt.a \ njs/njscript.h \ njs/njs_vm.h \ + njs/njs_boolean.h \ njs/njs_number.h \ njs/njs_string.h \ njs/njs_object.h \ diff --git a/njs/njs_boolean.c b/njs/njs_boolean.c new file mode 100644 index 00000000..86ddcaa7 --- /dev/null +++ b/njs/njs_boolean.c @@ -0,0 +1,149 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +njs_ret_t +njs_boolean_function(njs_vm_t *vm, njs_param_t *param) +{ + njs_object_t *object; + const njs_value_t *value; + + if (param->nargs == 0) { + value = &njs_value_false; + + } else { + value = njs_is_true(¶m->args[0]) ? &njs_value_true: + &njs_value_false; + } + + if (vm->frame->ctor) { + /* value->type is the same as prototype offset. */ + object = njs_object_value_alloc(vm, value, value->type); + if (nxt_slow_path(object == NULL)) { + return NXT_ERROR; + } + + vm->retval.data.u.object = object; + vm->retval.type = NJS_OBJECT_BOOLEAN; + vm->retval.data.truth = 1; + + } else { + vm->retval = *value; + } + + return NXT_OK; +} + + +static const njs_object_prop_t njs_boolean_function_properties[] = +{ + /* Boolean.name == "Boolean". */ + { njs_string("Boolean"), + njs_string("name"), + NJS_PROPERTY, 0, 0, 0, }, + + /* Boolean.length == 1. */ + { njs_value(NJS_NUMBER, 1, 1.0), + njs_string("length"), + NJS_PROPERTY, 0, 0, 0, }, + + /* Boolean.prototype. */ + { njs_getter(njs_object_prototype_create_prototype), + njs_string("prototype"), + NJS_NATIVE_GETTER, 0, 0, 0, }, +}; + + +nxt_int_t +njs_boolean_function_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash) +{ + return njs_object_hash_create(vm, hash, njs_boolean_function_properties, + nxt_nitems(njs_boolean_function_properties)); +} + + +static njs_ret_t +njs_boolean_prototype_value_of(njs_vm_t *vm, njs_param_t *param) +{ + njs_value_t *value; + + value = param->object; + + if (value->type != NJS_BOOLEAN) { + + if (value->type == NJS_OBJECT_BOOLEAN) { + value = &value->data.u.object_value->value; + + } else { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + } + + vm->retval = *value; + + return NXT_OK; +} + + +static njs_ret_t +njs_boolean_prototype_to_string(njs_vm_t *vm, njs_param_t *param) +{ + njs_value_t *value; + + value = param->object; + + if (value->type != NJS_BOOLEAN) { + + if (value->type == NJS_OBJECT_BOOLEAN) { + value = &value->data.u.object_value->value; + + } else { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + } + + vm->retval = njs_is_true(value) ? njs_string_true : njs_string_false; + + return NXT_OK; +} + + +static const njs_object_prop_t njs_boolean_prototype_properties[] = +{ + { njs_getter(njs_primitive_prototype_get_proto), + njs_string("__proto__"), + NJS_NATIVE_GETTER, 0, 0, 0, }, + + { njs_native_function(njs_boolean_prototype_value_of, 0), + njs_string("valueOf"), + NJS_METHOD, 0, 0, 0, }, + + { njs_native_function(njs_boolean_prototype_to_string, 0), + njs_string("toString"), + NJS_METHOD, 0, 0, 0, }, +}; + + +nxt_int_t +njs_boolean_prototype_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash) +{ + return njs_object_hash_create(vm, hash, njs_boolean_prototype_properties, + nxt_nitems(njs_boolean_prototype_properties)); +} diff --git a/njs/njs_boolean.h b/njs/njs_boolean.h new file mode 100644 index 00000000..ec0652f7 --- /dev/null +++ b/njs/njs_boolean.h @@ -0,0 +1,16 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NJS_BOOLEAN_H_INCLUDED_ +#define _NJS_BOOLEAN_H_INCLUDED_ + + +njs_ret_t njs_boolean_function(njs_vm_t *vm, njs_param_t *param); +nxt_int_t njs_boolean_function_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash); +nxt_int_t njs_boolean_prototype_hash(njs_vm_t *vm, nxt_lvlhsh_t *hash); + + +#endif /* _NJS_BOOLEAN_H_INCLUDED_ */ diff --git a/njs/njs_shared.c b/njs/njs_shared.c index 01660ce1..b6d064b3 100644 --- a/njs/njs_shared.c +++ b/njs/njs_shared.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ njs_shared_objects_create(njs_vm_t *vm) static const njs_shared_hash_t prototype_hash[] = { njs_object_prototype_hash, njs_array_prototype_hash, - njs_stub_hash, + njs_boolean_prototype_hash, njs_number_prototype_hash, njs_string_prototype_hash, njs_function_prototype_hash, @@ -60,7 +61,7 @@ njs_shared_objects_create(njs_vm_t *vm) static const njs_shared_hash_t function_hash[] = { njs_object_function_hash, njs_array_function_hash, - njs_stub_hash, + njs_boolean_function_hash, njs_number_function_hash, njs_string_function_hash, njs_function_function_hash, @@ -71,7 +72,7 @@ njs_shared_objects_create(njs_vm_t *vm) static const njs_native_t native_functions[] = { njs_object_function, njs_array_function, - njs_stub_function, + njs_boolean_function, njs_number_function, njs_string_ctor_function, njs_stub_function, diff --git a/njs/njs_vm.c b/njs/njs_vm.c index 562180fe..8f9d99d3 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -845,7 +845,7 @@ njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object, * NXT_OK property has been found in object, * NXT_DECLINED property was not found in object, * NJS_PRIMITIVE_VALUE property operation was applied to a numeric - * or undefined value, + * or boolean value, * NJS_STRING_VALUE property operation was applied to a string, * NJS_ARRAY_VALUE object is array, * NJS_EXTERNAL_VALUE object is external entity, @@ -868,17 +868,13 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, switch (object->type) { - case NJS_NULL: - case NJS_VOID: - vm->exception = &njs_exception_type_error; - return NXT_ERROR; - + case NJS_BOOLEAN: case NJS_NUMBER: if (pq->query != NJS_PROPERTY_QUERY_GET) { return NJS_PRIMITIVE_VALUE; } - obj = &vm->prototypes[NJS_PROTOTYPE_NUMBER]; + obj = &vm->prototypes[object->type]; break; case NJS_STRING: @@ -928,8 +924,9 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object, obj = NULL; break; - default: - return NJS_PRIMITIVE_VALUE; + default: /* NJS_VOID, NJS_NULL. */ + vm->exception = &njs_exception_type_error; + return NXT_ERROR; } if (nxt_fast_path(njs_is_primitive(property))) { diff --git a/njs/njs_vm.h b/njs/njs_vm.h index d3f7c78d..5bbe0acc 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -59,9 +59,9 @@ typedef enum { * The object types have the third bit set. It is used in njs_is_object(). * NJS_OBJECT_BOOLEAN, NJS_OBJECT_NUMBER, and NJS_OBJECT_STRING must be * equal to NJS_BOOLEAN, NJS_NUMBER, and NJS_STRING respectively with - * the third bit set. It is used in njs_primitive_prototype_get_proto(). - * The order of object types is used in vm->prototypes and vm->functions - * arrays. + * the third bit set. It is used in njs_primitive_prototype_get_proto() + * and in njs_property_query(). The order of object types is used in + * vm->prototypes and vm->functions arrays. */ NJS_OBJECT = 0x08, NJS_ARRAY = 0x09, diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 9868a37b..67908912 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -1420,6 +1420,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = 1; b = { x:2 }; a = b.x += (a = 1)"), nxt_string("3") }, + { nxt_string("a = undefined; a.b++; a.b"), + nxt_string("TypeError") }, + + { nxt_string("a = null; a.b++; a.b"), + nxt_string("TypeError") }, + + { nxt_string("a = true; a.b++; a.b"), + nxt_string("undefined") }, + { nxt_string("a = 1; a.b++; a.b"), nxt_string("undefined") }, @@ -1534,6 +1543,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = 1; 1 in a"), nxt_string("TypeError") }, + { nxt_string("a = true; 1 in a"), + nxt_string("TypeError") }, + { nxt_string("var n = { toString: function() { return 'a' } };" "var o = { a: 5 }; o[n]"), nxt_string("5") }, @@ -2565,6 +2577,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = { valueOf: function() { return 'OK' } } o.valueOf()"), nxt_string("OK") }, + { nxt_string("false.__proto__ === true.__proto__"), + nxt_string("true") }, + { nxt_string("0..__proto__ === 1..__proto__"), nxt_string("true") }, @@ -2697,7 +2712,56 @@ static njs_unit_test_t njs_test[] = { nxt_string("[].constructor === Array"), nxt_string("true") }, - /* TODO: Boolean */ + { nxt_string("Boolean()"), + nxt_string("false") }, + + { nxt_string("Boolean(0)"), + nxt_string("false") }, + + { nxt_string("Boolean('')"), + nxt_string("false") }, + + { nxt_string("Boolean(1)"), + nxt_string("true") }, + + { nxt_string("Boolean('a')"), + nxt_string("true") }, + + { nxt_string("Boolean({})"), + nxt_string("true") }, + + { nxt_string("Boolean([])"), + nxt_string("true") }, + + { nxt_string("typeof Boolean(1)"), + nxt_string("boolean") }, + + { nxt_string("typeof new Boolean(1)"), + nxt_string("object") }, + + { nxt_string("Boolean.name"), + nxt_string("Boolean") }, + + { nxt_string("Boolean.length"), + nxt_string("1") }, + + { nxt_string("Boolean.__proto__ === Function.prototype"), + nxt_string("true") }, + + { nxt_string("Boolean.prototype.constructor === Boolean"), + nxt_string("true") }, + + { nxt_string("Boolean.prototype.__proto__ === Object.prototype"), + nxt_string("true") }, + + { nxt_string("Boolean.constructor === Function"), + nxt_string("true") }, + + { nxt_string("true.__proto__ === Boolean.prototype"), + nxt_string("true") }, + + { nxt_string("false.__proto__ === Boolean.prototype"), + nxt_string("true") }, { nxt_string("Number()"), nxt_string("0") },