]> git.kaiwu.me - njs.git/commitdiff
Boolean objects support.
authorIgor Sysoev <igor@sysoev.ru>
Mon, 23 Nov 2015 19:36:52 +0000 (22:36 +0300)
committerIgor Sysoev <igor@sysoev.ru>
Mon, 23 Nov 2015 19:36:52 +0000 (22:36 +0300)
Makefile
njs/njs_boolean.c [new file with mode: 0644]
njs/njs_boolean.h [new file with mode: 0644]
njs/njs_shared.c
njs/njs_vm.c
njs/njs_vm.h
njs/test/njs_unit_test.c

index 68a6bfb41d14f5ec7e87c592fa60cf2ad785c758..b6c7a20ee8956d2184dddbc0667f63c35d5e3cb2 100644 (file)
--- 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 (file)
index 0000000..86ddcaa
--- /dev/null
@@ -0,0 +1,149 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_types.h>
+#include <nxt_clang.h>
+#include <nxt_stub.h>
+#include <nxt_array.h>
+#include <nxt_lvlhsh.h>
+#include <nxt_mem_cache_pool.h>
+#include <njscript.h>
+#include <njs_vm.h>
+#include <njs_boolean.h>
+#include <njs_object.h>
+#include <njs_function.h>
+
+
+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(&param->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 (file)
index 0000000..ec0652f
--- /dev/null
@@ -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_ */
index 01660ce14076f03a95f242b632b6d488f4870be6..b6d064b3458331835d9eb7113d05fea55a8fa21b 100644 (file)
@@ -12,6 +12,7 @@
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <njs_vm.h>
+#include <njs_boolean.h>
 #include <njs_number.h>
 #include <njs_string.h>
 #include <njs_object.h>
@@ -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,
index 562180fe6fa654da347aa5bd0c84fa5c935af84a..8f9d99d3d5929e6182fe4dfa3c70927f680ed5d4 100644 (file)
@@ -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))) {
index d3f7c78db3291f73871fee030050f3fbef6c1e92..5bbe0acc73f68a9786a53bd96683a59aa9bb9dc3 100644 (file)
@@ -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,
index 9868a37b37de826dd70a2bd1551a7edab800971a..679089121e6df13d5abe322498148c2253be5252 100644 (file)
@@ -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") },