improve symbol support
authorMichael Wallner <mike@php.net>
Tue, 7 Dec 2021 15:07:08 +0000 (16:07 +0100)
committerMichael Wallner <mike@php.net>
Tue, 7 Dec 2021 15:07:08 +0000 (16:07 +0100)
ion.c
ion.stub.php
ion_arginfo.h
ion_private.h
tests/Symbol.phpt [new file with mode: 0644]
tests/Symbol/equals.phpt [new file with mode: 0644]

diff --git a/ion.c b/ion.c
index 1b8340d192c46dc59361844b9b901571dcd11df1..017e88fda1d232ec5f5af1659b5de97a9472c6d9 100644 (file)
--- a/ion.c
+++ b/ion.c
 
 ZEND_METHOD(ion_Symbol_ImportLocation, __construct)
 {
-       zend_long location;
        php_ion_symbol_iloc *obj = php_ion_obj(symbol_iloc, Z_OBJ_P(ZEND_THIS));
-
        PTR_CHECK(obj);
 
+       zend_long location;
        ZEND_PARSE_PARAMETERS_START(2, 2)
                Z_PARAM_STR(obj->name)
                Z_PARAM_LONG(location)
@@ -53,14 +52,13 @@ ZEND_METHOD(ion_Symbol_ImportLocation, __construct)
 }
 ZEND_METHOD(ion_Symbol, __construct)
 {
-       zend_long sid = -1;
        php_ion_symbol *obj = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS));
-
        PTR_CHECK(obj);
 
-       ZEND_PARSE_PARAMETERS_START(1, 3)
-               Z_PARAM_STR(obj->value)
+       zend_long sid = -1;
+       ZEND_PARSE_PARAMETERS_START(0, 3)
                Z_PARAM_OPTIONAL
+               Z_PARAM_STR_OR_NULL(obj->value)
                Z_PARAM_LONG(sid)
                Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->iloc, ce_Symbol_ImportLocation)
        ZEND_PARSE_PARAMETERS_END();
@@ -70,11 +68,10 @@ ZEND_METHOD(ion_Symbol, __construct)
 }
 ZEND_METHOD(ion_Symbol, equals)
 {
-       zend_object *other_obj;
        php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS));
-
        OBJ_CHECK(sym);
 
+       zend_object *other_obj;
        ZEND_PARSE_PARAMETERS_START(1, 1)
                Z_PARAM_OBJ_OF_CLASS(other_obj, ce_Symbol)
        ZEND_PARSE_PARAMETERS_END();
@@ -86,6 +83,18 @@ ZEND_METHOD(ion_Symbol, equals)
        ION_CHECK(err);
        RETVAL_BOOL(eq);
 }
+ZEND_METHOD(ion_Symbol, __toString)
+{
+       php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(sym);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       if (!sym->value) {
+               RETURN_EMPTY_STRING();
+       }
+       RETURN_STR(sym->value);
+}
 ZEND_METHOD(ion_Timestamp, __construct)
 {
        php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS));
index cbddd8db5eaada5f61be79f9f74c646453af09aa..99eeabd528abac4ab3eff98bb2248d76481a0877 100644 (file)
@@ -76,12 +76,15 @@ enum SID : int {
 namespace ion;
 class Symbol {
     public function __construct(
-        public readonly string $value,
+        public readonly ?string $value = null,
         public readonly int $sid = -1,
         public readonly ?Symbol\ImportLocation $importLocation = null,
     ) {}
 
-    public function equals(Symbol $symbol): bool { }
+    public function equals(Symbol $symbol): bool {}
+    public function __toString() : string {}
+    /** @alias ion\Symbol::__toString */
+    public function toString() : string {}
 }
 
 namespace ion\Symbol;
index 1b600b53408d462fb9674465a66844ee3fd10744..5697c9979d9c02e3cd884f36b469925d933d776d 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 20996b59177d52516ad45582152909be017ba39d */
+ * Stub hash: b634f10fc96ce251beeade7a41bd8531343395d5 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ion_serialize, 0, 1, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, data, IS_MIXED, 0)
@@ -16,8 +16,8 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Symbol_ImportLocation___construct, 0, 0
        ZEND_ARG_TYPE_INFO(0, location, IS_LONG, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Symbol___construct, 0, 0, 1)
-       ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0)
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Symbol___construct, 0, 0, 0)
+       ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 1, "null")
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, sid, IS_LONG, 0, "-1")
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, importLocation, ion\\Symbol\\ImportLocation, 1, "null")
 ZEND_END_ARG_INFO()
@@ -26,6 +26,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Symbol_equals, 0, 1, _
        ZEND_ARG_OBJ_INFO(0, symbol, ion\\Symbol, 0)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Symbol___toString, 0, 0, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_ion_Symbol_toString arginfo_class_ion_Symbol___toString
+
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Decimal_Context___construct, 0, 0, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, bits, IS_LONG, 0, "128")
 ZEND_END_ARG_INFO()
@@ -42,10 +47,9 @@ ZEND_END_ARG_INFO()
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_isInt, 0, 0, _IS_BOOL, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal___toString, 0, 0, IS_STRING, 0)
-ZEND_END_ARG_INFO()
+#define arginfo_class_ion_Decimal___toString arginfo_class_ion_Symbol___toString
 
-#define arginfo_class_ion_Decimal_toString arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Decimal_toString arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Decimal_toInt, 0, 0, IS_LONG, 0)
 ZEND_END_ARG_INFO()
@@ -57,7 +61,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Timestamp___construct, 0, 0, 1)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, timezone, DateTimeZone, 1, "null")
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_ion_Timestamp___toString arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Timestamp___toString arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_getType, 0, 0, ion\\Type, 0)
 ZEND_END_ARG_INFO()
@@ -72,7 +76,7 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Reader_isInStruct arginfo_class_ion_Decimal_isInt
 
-#define arginfo_class_ion_Reader_getFieldName arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_getFieldName arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ion_Reader_getFieldNameSymbol, 0, 0, ion\\Symbol, 0)
 ZEND_END_ARG_INFO()
@@ -110,14 +114,14 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Reader_readSymbol arginfo_class_ion_Reader_getFieldNameSymbol
 
-#define arginfo_class_ion_Reader_readString arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_readString arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ion_Reader_readStringPart, 0, 1, _IS_BOOL, 0)
        ZEND_ARG_INFO(1, string)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, length, IS_LONG, 0, "0x1000")
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_ion_Reader_readLob arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_readLob arginfo_class_ion_Symbol___toString
 
 #define arginfo_class_ion_Reader_readLobPart arginfo_class_ion_Reader_readStringPart
 
@@ -177,7 +181,7 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Reader_Reader_isInStruct arginfo_class_ion_Decimal_isInt
 
-#define arginfo_class_ion_Reader_Reader_getFieldName arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_Reader_getFieldName arginfo_class_ion_Symbol___toString
 
 #define arginfo_class_ion_Reader_Reader_getFieldNameSymbol arginfo_class_ion_Reader_getFieldNameSymbol
 
@@ -205,11 +209,11 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Reader_Reader_readSymbol arginfo_class_ion_Reader_getFieldNameSymbol
 
-#define arginfo_class_ion_Reader_Reader_readString arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_Reader_readString arginfo_class_ion_Symbol___toString
 
 #define arginfo_class_ion_Reader_Reader_readStringPart arginfo_class_ion_Reader_readStringPart
 
-#define arginfo_class_ion_Reader_Reader_readLob arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_Reader_readLob arginfo_class_ion_Symbol___toString
 
 #define arginfo_class_ion_Reader_Reader_readLobPart arginfo_class_ion_Reader_readStringPart
 
@@ -223,14 +227,14 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Reader_Reader_getValueLength arginfo_class_ion_Decimal_toInt
 
-#define arginfo_class_ion_Reader_Buffer_getBuffer arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_Buffer_getBuffer arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Buffer_Reader___construct, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(0, buffer, IS_STRING, 0)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Reader\\Options, 1, "null")
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_ion_Reader_Buffer_Reader_getBuffer arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Reader_Buffer_Reader_getBuffer arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Reader_Stream_getStream, 0, 0, 0)
 ZEND_END_ARG_INFO()
@@ -391,14 +395,14 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Writer_Writer_writeAll arginfo_class_ion_Writer_writeOne
 
-#define arginfo_class_ion_Writer_Buffer_getBuffer arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Writer_Buffer_getBuffer arginfo_class_ion_Symbol___toString
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Buffer_Writer___construct, 0, 0, 1)
        ZEND_ARG_TYPE_INFO(1, buffer, IS_STRING, 1)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Writer\\Options, 1, "null")
 ZEND_END_ARG_INFO()
 
-#define arginfo_class_ion_Writer_Buffer_Writer_getBuffer arginfo_class_ion_Decimal___toString
+#define arginfo_class_ion_Writer_Buffer_Writer_getBuffer arginfo_class_ion_Symbol___toString
 
 #define arginfo_class_ion_Writer_Stream_getStream arginfo_class_ion_Reader_Stream_getStream
 
@@ -437,6 +441,7 @@ ZEND_FUNCTION(ion_unserialize);
 ZEND_METHOD(ion_Symbol_ImportLocation, __construct);
 ZEND_METHOD(ion_Symbol, __construct);
 ZEND_METHOD(ion_Symbol, equals);
+ZEND_METHOD(ion_Symbol, __toString);
 ZEND_METHOD(ion_Decimal_Context, __construct);
 ZEND_METHOD(ion_Decimal, __construct);
 ZEND_METHOD(ion_Decimal, equals);
@@ -559,6 +564,8 @@ static const zend_function_entry class_ion_Symbol_System_SID_methods[] = {
 static const zend_function_entry class_ion_Symbol_methods[] = {
        ZEND_ME(ion_Symbol, __construct, arginfo_class_ion_Symbol___construct, ZEND_ACC_PUBLIC)
        ZEND_ME(ion_Symbol, equals, arginfo_class_ion_Symbol_equals, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Symbol, __toString, arginfo_class_ion_Symbol___toString, ZEND_ACC_PUBLIC)
+       ZEND_MALIAS(ion_Symbol, toString, __toString, arginfo_class_ion_Symbol_toString, ZEND_ACC_PUBLIC)
        ZEND_FE_END
 };
 
@@ -1074,7 +1081,7 @@ static zend_class_entry *register_class_ion_Symbol(void)
        zval property_value_default_value;
        ZVAL_UNDEF(&property_value_default_value);
        zend_string *property_value_name = zend_string_init("value", sizeof("value") - 1, 1);
-       zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
+       zend_declare_typed_property(class_entry, property_value_name, &property_value_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL));
        zend_string_release(property_value_name);
 
        zval property_sid_default_value;
index 5b6a4614510e435148fbc35188aa70976d279687..98a3291d0a5d51373d610b25141b4b6706fcda37 100644 (file)
@@ -242,8 +242,8 @@ static inline ION_STRING *ion_string_from_cstr(ION_STRING *is, const char *s, si
 
 static inline ION_STRING *ion_string_from_zend(ION_STRING *is, const zend_string *zs)
 {
-       is->length = ZSTR_LEN(zs);
-       is->value = (BYTE *) ZSTR_VAL(zs);
+       is->length = zs ? zs->len : 0;
+       is->value = (BYTE *) (zs ? zs->val : NULL);
        return is;
 }
 
@@ -312,7 +312,11 @@ static inline void php_ion_symbol_ctor(php_ion_symbol *obj)
 {
        zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("sid"),
                obj->sym.sid);
-       zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("value"), obj->value);
+       if (obj->value) {
+               zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("value"), obj->value);
+       } else{
+               zend_update_property_null(obj->std.ce, &obj->std, ZEND_STRL("value"));
+       }
        ion_string_from_zend(&obj->sym.value, obj->value);
        if (obj->iloc) {
                update_property_obj(&obj->std, ZEND_STRL("importLocation"), obj->iloc);
@@ -324,7 +328,9 @@ static inline void php_ion_symbol_ctor(php_ion_symbol *obj)
 
 static inline void php_ion_symbol_dtor(php_ion_symbol *obj)
 {
-       zend_string_release(obj->value);
+       if (obj->value) {
+               zend_string_release(obj->value);
+       }
 }
 
 static inline void php_ion_symbol_zval(ION_SYMBOL *sym_ptr, zval *return_value)
@@ -493,7 +499,7 @@ static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContex
        }
 
        if (fmt) {
-               fmt = php_dt_format_from_precision(ts->precision);
+               *fmt = php_dt_format_from_precision(ts->precision);
        }
        return time;
 }
diff --git a/tests/Symbol.phpt b/tests/Symbol.phpt
new file mode 100644 (file)
index 0000000..7c0adaa
--- /dev/null
@@ -0,0 +1,73 @@
+--TEST--
+ion\Symbol
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+use ion\Symbol;
+
+try {
+       var_dump(new Symbol);
+} catch (Throwable) {
+       echo "caught empty\n";
+}
+
+var_dump($s=new Symbol, (string)$s, $s->sid);
+var_dump($s=new Symbol("s"), (string)$s, $s->sid);
+var_dump($s=new Symbol("s", 1), (string)$s, $s->sid);
+var_dump($s=new Symbol(1, 2), (string)$s, $s->sid);
+
+?>
+DONE
+--EXPECTF--
+TEST
+object(ion\Symbol)#%d (3) {
+  ["value"]=>
+  NULL
+  ["sid"]=>
+  int(-1)
+  ["importLocation"]=>
+  NULL
+}
+object(ion\Symbol)#%d (3) {
+  ["value"]=>
+  NULL
+  ["sid"]=>
+  int(-1)
+  ["importLocation"]=>
+  NULL
+}
+string(0) ""
+int(-1)
+object(ion\Symbol)#%d (3) {
+  ["value"]=>
+  string(1) "s"
+  ["sid"]=>
+  int(-1)
+  ["importLocation"]=>
+  NULL
+}
+string(1) "s"
+int(-1)
+object(ion\Symbol)#%d (3) {
+  ["value"]=>
+  string(1) "s"
+  ["sid"]=>
+  int(1)
+  ["importLocation"]=>
+  NULL
+}
+string(1) "s"
+int(1)
+object(ion\Symbol)#%d (3) {
+  ["value"]=>
+  string(1) "1"
+  ["sid"]=>
+  int(2)
+  ["importLocation"]=>
+  NULL
+}
+string(1) "1"
+int(2)
+DONE
diff --git a/tests/Symbol/equals.phpt b/tests/Symbol/equals.phpt
new file mode 100644 (file)
index 0000000..45571ab
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+ion\Symbol::equals
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+use ion\Symbol;
+
+var_dump(new Symbol(1) == new Symbol("1"));
+var_dump((new Symbol(1))->equals(new Symbol("1")));
+
+var_dump((new Symbol(1, 123))->equals(new Symbol("1", 321)));
+
+var_dump(new Symbol(1) == new Symbol(2));
+var_dump((new Symbol(1))->equals(new Symbol(2)));
+
+// All local symbols with unknown text are equivalent to each other (and to symbol zero).
+var_dump((new Symbol(sid:123))->equals(new Symbol(sid:321)));
+
+?>
+DONE
+--EXPECT--
+TEST
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+DONE