diff --git a/Cargo.lock b/Cargo.lock index 1107d5a..a9c467b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.5" @@ -76,30 +61,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - [[package]] name = "bindgen" version = "0.73.2" @@ -116,7 +77,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 3.0.5", + "syn", ] [[package]] @@ -215,7 +176,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] @@ -242,16 +203,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - [[package]] name = "find-msvc-tools" version = "0.1.14" @@ -264,12 +215,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.4" @@ -298,12 +243,6 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -332,12 +271,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - [[package]] name = "log" version = "0.4.34" @@ -350,51 +283,12 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "nom" version = "7.1.3" @@ -405,42 +299,26 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "owo-colors" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" - [[package]] name = "php-ast" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98fd0c5357b164ae192c654b7c9c3f8c1c8c3305c1b6f0686d9b5505145f67" +checksum = "b45af352ac35a7d92ec0830160070894d6de16f4920ec7902dc16ef913e39f8e" dependencies = [ "bumpalo", - "serde", ] [[package]] name = "php-lexer" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc85b0cae487b9c7c819fbb0886ce33424b4d0e21d4ff7cb0f5d26c03050df38" +checksum = "28371e67a39240e9fd1fa02628c963f962e26554712f07fdb501eef12c50bdae" dependencies = [ "memchr", "php-ast", @@ -448,28 +326,17 @@ dependencies = [ [[package]] name = "php-rs-parser" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822458849250ea40699d631eb8d75b7a29d4a43f9d710862db069db5953ca311" +checksum = "73040a5818ac3154cfa7084c39323203ae9a7968236c82c39eff7deb0f6c5485" dependencies = [ "bumpalo", "memchr", - "miette", "php-ast", "php-lexer", - "phpdoc-parser", "thiserror", ] -[[package]] -name = "phpdoc-parser" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d643e450bbf0f3208d160b8d85fcacced884889556d6363d6d9ddcd420a73117" -dependencies = [ - "serde", -] - [[package]] name = "prettyplease" version = "0.3.0" @@ -477,7 +344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" dependencies = [ "proc-macro2", - "syn 3.0.5", + "syn", ] [[package]] @@ -639,31 +506,12 @@ dependencies = [ "rsphp-build-tools", ] -[[package]] -name = "rustc-demangle" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" - [[package]] name = "rustc-hash" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - [[package]] name = "same-file" version = "1.0.6" @@ -680,7 +528,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", - "serde_derive", ] [[package]] @@ -700,7 +547,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] @@ -737,38 +584,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "supports-color" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" -dependencies = [ - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" - -[[package]] -name = "supports-unicode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "3.0.5" @@ -805,26 +620,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal_size" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" -dependencies = [ - "rustix", - "windows-sys", -] - -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" -dependencies = [ - "unicode-linebreak", - "unicode-width 0.2.2", -] - [[package]] name = "thiserror" version = "2.0.20" @@ -842,7 +637,7 @@ checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 3.0.5", + "syn", ] [[package]] @@ -905,24 +700,6 @@ version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - [[package]] name = "utf8parse" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 086750b..81762b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -193,8 +193,8 @@ c_str_macro = "1.0.3" cc = "1.7.0" clap = { version = "4.6.7", features = ["derive"] } diff = "0.1.13" -php-ast = "0.21.0" -php-rs-parser = "0.21.0" +php-ast = "0.26.0" +php-rs-parser = "0.26.0" proc-macro2 = "1.0.107" regex = "1.13.1" rsphp-build-tools = { version = "0.1.1", path = "./crates/build-tools" } diff --git a/crates/stub-parser/src/builder.rs b/crates/stub-parser/src/builder.rs index 09fe291..2f840fa 100644 --- a/crates/stub-parser/src/builder.rs +++ b/crates/stub-parser/src/builder.rs @@ -2,7 +2,7 @@ use crate::VerificationMode; use crate::imports::ImportsUsed; use crate::types::ArgInfoTypeRepr; use crate::verification::{VERIFICATION_RSPHP_SYS_IMPORTS, VerificationData}; -use php_ast::ast::{BuiltinType, Visibility}; +use php_ast::ast::{BuiltinType, NameKind, Visibility}; use php_ast::owned::{ Attribute, ClassConstDecl, ClassDecl, ClassMemberKind, Comment, EnumCase, EnumDecl, EnumMemberKind, Expr, ExprKind, FunctionDecl, Ident, InterfaceDecl, MethodDecl, Name, @@ -38,7 +38,7 @@ enum ClassLikeMember { ClassConst(ClassConstDecl), } impl TryFrom for ClassLikeMember { - type Error = &'static str; + type Error = String; fn try_from(orig: ClassMemberKind) -> Result { match orig { @@ -47,19 +47,29 @@ impl TryFrom for ClassLikeMember { ClassMemberKind::ClassConst(class_const) => { Ok(ClassLikeMember::ClassConst(class_const)) } - ClassMemberKind::TraitUse(_) => Err("PHP does not support traits on internal classes"), + ClassMemberKind::TraitUse(_) => { + Err("PHP does not support traits on internal classes".to_owned()) + } + _ => Err(format!( + "ClassMemberKind is non-exhaustive, unhandled: {orig:?}" + )), } } } impl TryFrom for ClassLikeMember { - type Error = &'static str; + type Error = String; fn try_from(orig: EnumMemberKind) -> Result { match orig { EnumMemberKind::Case(case) => Ok(ClassLikeMember::EnumCase(case)), EnumMemberKind::Method(method) => Ok(ClassLikeMember::Method(method)), EnumMemberKind::ClassConst(class_const) => Ok(ClassLikeMember::ClassConst(class_const)), - EnumMemberKind::TraitUse(_) => Err("PHP does not support traits on internal classes"), + EnumMemberKind::TraitUse(_) => { + Err("PHP does not support traits on internal classes".to_owned()) + } + _ => Err(format!( + "EnumMemberKind is non-exhaustive, unhandled: {orig:?}" + )), } } } @@ -72,7 +82,7 @@ impl ClassLikeType { ClassLikeType::Interface(interface) => &interface.name, ClassLikeType::Class(class) => class.name.as_ref().expect("Not an anonymous class"), }; - ident.as_ref().expect("Valid name") + ident.as_str().expect("Valid name") } /// Body of the class/interface/enum. fn body_members(&self) -> Vec { @@ -108,6 +118,13 @@ impl ClassLikeType { ClassLikeType::Class(class) => &class.attributes, } } + /// If this is a readonly class. + fn is_readonly(&self) -> bool { + match self { + ClassLikeType::Class(class) => class.modifiers.is_readonly, + _ => false, + } + } /// Helper to create variable names for references to zend class entries. fn make_ce_variable_name(type_name: &Name) -> String { "zend_ce_".to_owned() @@ -174,10 +191,7 @@ impl ClassLikeType { program: &str, ) -> Result { let name = self.name(); - let ns_name_segment = match namespace { - Some(ns) => format!("{ns}\\\\"), - None => String::new(), - }; + let ns_name_segment = namespace.map(|ns| format!("{ns}\\\\")).unwrap_or_default(); let (macro_name, macro_ns_arg) = match namespace { Some(ns) => ("INIT_NS_CLASS_ENTRY", format!(" \"{ns}\",")), None => ("INIT_CLASS_ENTRY", String::new()), @@ -193,25 +207,35 @@ impl ClassLikeType { .parent_class_var() .unwrap_or_else(|| "std::ptr::null_mut()".to_owned()); let mut flags = vec![]; + if class.modifiers.is_abstract { + flags.push("ZEND_ACC_ABSTRACT"); + } if class.modifiers.is_final { flags.push("ZEND_ACC_FINAL"); - scope.add_import("rsphp_sys", "ZEND_ACC_FINAL"); + } + if class.modifiers.is_readonly { + flags.push("ZEND_ACC_READONLY_CLASS"); } if let Some(comment) = class.doc_comment.as_ref() { if comment.text.contains("@strict-properties") { flags.push("ZEND_ACC_NO_DYNAMIC_PROPERTIES"); - scope.add_import("rsphp_sys", "ZEND_ACC_NO_DYNAMIC_PROPERTIES"); } if comment.text.contains("@not-serializable") { flags.push("ZEND_ACC_NOT_SERIALIZABLE"); - scope.add_import("rsphp_sys", "ZEND_ACC_NOT_SERIALIZABLE"); } } + if (*class.attributes) + .iter() + .any(|attrib| attrib.name.to_string_repr() == "\\AllowDynamicProperties") + { + flags.push("ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES"); + } let flags_str = if flags.is_empty() { "0".to_owned() } else { flags.join("|") }; + scope.extend_sys_imports(flags.into_iter().map(str::to_owned)); format!( "\n{space}let mut ce: zend_class_entry = unsafe {{ std::mem::zeroed() }};\ \n{space}{init_macro}\ @@ -254,18 +278,16 @@ impl ClassLikeType { space = " ", ) } - ClassLikeType::Interface(_) => { - format!( - "\n{space}let mut ce: zend_class_entry = unsafe {{ std::mem::zeroed() }};\ - \n{space}{init_macro}\ - \n{space}let class_entry: *mut zend_class_entry = unsafe {{\ - \n{space}{space}rsphp_sys::zend_register_internal_interface(\ - \n{space}{space}{space}std::ptr::from_mut::(&mut ce),\ - \n{space}{space})\ - \n{space}}};", - space = " ", - ) - } + ClassLikeType::Interface(_) => format!( + "\n{space}let mut ce: zend_class_entry = unsafe {{ std::mem::zeroed() }};\ + \n{space}{init_macro}\ + \n{space}let class_entry: *mut zend_class_entry = unsafe {{\ + \n{space}{space}rsphp_sys::zend_register_internal_interface(\ + \n{space}{space}{space}std::ptr::from_mut::(&mut ce),\ + \n{space}{space})\ + \n{space}}};", + space = " ", + ), }; Ok(result + &self.interfaces_applied_code(scope)) } @@ -384,6 +406,11 @@ impl ArgInfoBuilder<'_> { self.namespace = old_namespace; result?; } + _ => { + return Err(format!( + "NamespaceBody is non-exhaustive, unhandled: {namespace:?}" + )); + } } Ok(()) } @@ -398,7 +425,7 @@ impl ArgInfoBuilder<'_> { }); let name = param .name - .as_ref() + .as_str() .ok_or_else(|| "Parameter name is missing".to_owned())?; let mut default = param .default @@ -611,14 +638,14 @@ impl ArgInfoBuilder<'_> { /// Generate code for a global function. fn function(&mut self, func: &FunctionDecl) -> Result<(), String> { - let fn_name = func.name.as_ref().expect("No errors"); + let fn_name = func.name.as_str().expect("No errors"); let ns_segment = match &self.namespace { Some(ns) => format!("{}_", ns.to_uppercase()), None => String::new(), }; let doc_name = match &self.namespace { Some(ns) => format!("{ns}\\{fn_name}"), - None => fn_name.to_string(), + None => fn_name.to_owned(), }; let fn_result = self.build_function( &func.params, @@ -633,10 +660,14 @@ impl ArgInfoBuilder<'_> { } /// Generate code for a class property. - fn build_property(&mut self, prop: &PropertyDecl) -> Result { + fn build_property( + &mut self, + prop: &PropertyDecl, + class_readonly: bool, + ) -> Result { self.scope.add_import("rsphp_sys", "zval"); self.scope.add_import("rsphp_sys", "zend_class_entry"); - let prop_name = prop.name.as_ref().ok_or("Property name missing")?; + let prop_name = prop.name.as_str().ok_or("Property name missing")?; let prop_default_create = format!( "{space}let mut property_{name}_default_value: zval = unsafe {{ std::mem::zeroed() }};", name = prop_name, @@ -661,7 +692,7 @@ impl ArgInfoBuilder<'_> { Some(Expr { kind: ExprKind::String(string), span: _, - }) if **string == *"" => ("ZVAL_EMPTY_STRING", None, None), + }) if (**string).is_empty() => ("ZVAL_EMPTY_STRING", None, None), Some(Expr { kind: ExprKind::Array(array), span: _, @@ -671,9 +702,9 @@ impl ArgInfoBuilder<'_> { span: _, }) => ("ZVAL_LONG", Some(num.to_string()), None), Some(Expr { - kind: ExprKind::Identifier(ident), + kind: ExprKind::Name(name), span: _, - }) if **ident == *"E_ERROR" => { + }) if name.kind == NameKind::Unqualified && *name.parts == ["E_ERROR".into()] => { self.scope.add_import("rsphp_sys", "E_ERROR"); ("ZVAL_LONG", Some("E_ERROR".to_owned()), None) } @@ -681,7 +712,7 @@ impl ArgInfoBuilder<'_> { kind: ExprKind::String(string), span: _, }) => { - self.scope.add_import("rsphp_sys", "zend_string_init"); + let real_string = string.to_str().ok_or("Strings must be valid UTF-8")?; ( "ZVAL_INTERNED_STR", Some(format!("property_{prop_name}_default_str")), @@ -689,7 +720,7 @@ impl ArgInfoBuilder<'_> { "{space}let property_{name}_default_str = unsafe {{ zend_string_init(c\"{s}\".as_ptr(), \"{s}\".len(), true) }};\n", name = prop_name, space = " ", - s = string + s = real_string )), ) } @@ -709,12 +740,16 @@ impl ArgInfoBuilder<'_> { ); self.scope.add_import("rsphp_sys", "zend_string"); self.scope.add_import("rsphp_sys", "zend_string_init"); - let vis = match prop.visibility { + let vis = match prop.modifiers.visibility { None | Some(Visibility::Public) => "ZEND_ACC_PUBLIC", Some(Visibility::Protected) => "ZEND_ACC_PROTECTED", Some(Visibility::Private) => "ZEND_ACC_PRIVATE", + Some(unknown) => { + return Err(format!( + "Visibility is non-exhaustive, unhandled: {unknown:?}" + )); + } }; - self.scope.add_import("rsphp_sys", vis); let (type_declaration, type_code) = match prop.type_hint.as_ref() { Some(type_hint) => { ArgInfoTypeRepr::try_from(type_hint.kind.clone(), self.namespace.as_ref())? @@ -724,13 +759,43 @@ impl ArgInfoBuilder<'_> { }; let ptr_for_default = format!("std::ptr::from_mut::(&mut property_{prop_name}_default_value)"); + let mut flags = vec![vis]; + if class_readonly || prop.modifiers.is_readonly { + flags.push("ZEND_ACC_READONLY"); + } + if prop.modifiers.is_static { + flags.push("ZEND_ACC_STATIC"); + } + if prop.modifiers.is_final { + flags.push("ZEND_ACC_FINAL"); + } + if let Some(set_vis) = prop.modifiers.set_visibility { + let set_vis_flag = match set_vis { + Visibility::Public => "ZEND_ACC_PUBLIC_SET", + Visibility::Protected => "ZEND_ACC_PROTECTED_SET", + Visibility::Private => "ZEND_ACC_PRIVATE_SET", + unknown => { + return Err(format!( + "Visibility is non-exhaustive, unhandled: {unknown:?}" + )); + } + }; + flags.push(set_vis_flag); + } + let flags_str = if flags.len() == 1 { + flags[0].to_owned() + } else { + format!("({})", flags.join("|")) + }; + self.scope + .extend_sys_imports(flags.into_iter().map(str::to_owned)); let prop_decl = format!( "{space}unsafe {{\ \n{space}{space}zend_declare_typed_property(\ \n{space}{space}{space}class_entry,\ \n{space}{space}{space}property_{name}_name,\ \n{space}{space}{space}{ptr_for_default},\ - \n{space}{space}{space}{vis} as i32,\ + \n{space}{space}{space}{flags_str} as i32,\ \n{space}{space}{space}std::ptr::null_mut(),\ \n{space}{space}{space}{typemask},\ \n{space}{space});\ @@ -794,7 +859,7 @@ impl ArgInfoBuilder<'_> { for member in wrapped.body_members() { match member { ClassLikeMember::Method(method) => { - let fn_name = method.name.as_ref().expect("No errors"); + let fn_name = method.name.as_str().expect("No errors"); let name_constant = format!("ARGINFO_{}", fn_name.to_uppercase()); module_parts.push(self.build_function( &method.params, @@ -804,10 +869,9 @@ impl ArgInfoBuilder<'_> { method.return_type.as_ref(), &format!("{doc_name}::{fn_name}"), )?); - let mut verification = - VerificationData::new(fn_name.to_string(), name_constant); - verification.add_visibility(method.visibility.as_ref()); - verification.add_flag_if(method.is_static, "ZEND_ACC_STATIC"); + let mut verification = VerificationData::new(fn_name.to_owned(), name_constant); + verification.add_visibility(method.modifiers.visibility.as_ref())?; + verification.add_flag_if(method.modifiers.is_static, "ZEND_ACC_STATIC"); verification.add_flag_if( matches!(wrapped, ClassLikeType::Interface(_)), "ZEND_ACC_ABSTRACT", @@ -823,7 +887,7 @@ impl ArgInfoBuilder<'_> { self.needs_verification = true; } ClassLikeMember::Property(property) => { - properties.push(self.build_property(&property)?); + properties.push(self.build_property(&property, wrapped.is_readonly())?); } ClassLikeMember::ClassConst(class_const) => { constants.push(self.build_constant(&class_const)?); @@ -996,15 +1060,16 @@ impl ArgInfoBuilder<'_> { param_init.push(init); } match &arg - .value + .value() .as_ref() .ok_or("Missing argument value in attribute")? .kind { ExprKind::String(string) => { + let real_string = string.to_str().ok_or("Strings must be valid UTF-8")?; let alloc = format!( - "let arg_{index}_value = zend_string_init(c\"{string}\".as_ptr(), \ - \"{string}\".len(), true);", + "let arg_{index}_value = zend_string_init(c\"{real_string}\".as_ptr(), \ + \"{real_string}\".len(), true);", ); self.scope.add_import("rsphp_sys", "zend_string_init"); param_init.push(alloc); @@ -1088,12 +1153,17 @@ impl ArgInfoBuilder<'_> { fn build_constant(&mut self, constant: &ClassConstDecl) -> Result { let constant_name = constant .name - .as_ref() + .as_str() .ok_or_else(|| "Constant name is missing".to_owned())?; - let vis = match constant.visibility { + let vis = match constant.modifiers.visibility { None | Some(Visibility::Public) => "ZEND_ACC_PUBLIC", Some(Visibility::Protected) => "ZEND_ACC_PROTECTED", Some(Visibility::Private) => "ZEND_ACC_PRIVATE", + Some(unknown) => { + return Err(format!( + "Visibility is non-exhaustive, unhandled: {unknown:?}" + )); + } }; self.scope.add_import("rsphp_sys", vis); let type_repr = ArgInfoTypeRepr::try_from( @@ -1133,7 +1203,9 @@ impl ArgInfoBuilder<'_> { self.scope.add_import("rsphp_macros_c", "ZVAL_NULL"); "ZVAL_NULL!(&mut value);".to_owned() } - ExprKind::Identifier(ident) if *ident == "UNKNOWN".into() => { + ExprKind::Name(name) + if name.kind == NameKind::Unqualified && *name.parts == ["UNKNOWN".into()] => + { let cvalue_re = Regex::new(r"@cvalue (\S+)").map_err(|err| err.to_string())?; let mut cvalue_val = cvalue_re .captures( @@ -1227,7 +1299,8 @@ impl ArgInfoBuilder<'_> { if arg.name.is_some() { return Err("Attributes with named arguments are not supported yet".to_owned()); } - let value = self.get_raw_code(arg.value.as_ref().ok_or("Only missing with PFA")?.span); + let value = + self.get_raw_code(arg.value().as_ref().ok_or("Only missing with PFA")?.span); if attrib_name == "Attribute" || attrib_name == "\\Attribute" { // We can handle these let flags: Vec<&'static str> = value @@ -1280,7 +1353,14 @@ impl ArgInfoBuilder<'_> { self.scope.add_import("rsphp_sys", "zend_string"); self.scope .add_import("rsphp_sys", "zend_string_init_interned"); - self.scope.add_import("rsphp_sys", "zend_attribute"); + if !param_init.is_empty() { + self.scope.add_import("rsphp_sys", "zend_attribute"); + } + let attrib_variable = if param_init.is_empty() { + "" + } else { + "let attrib: *mut zend_attribute = " + }; self.scope .add_import("rsphp_sys", "zend_add_class_attribute"); self.scope.add_import("rsphp_sys", "zend_string_release_ex"); @@ -1291,7 +1371,7 @@ impl ArgInfoBuilder<'_> { \n{space}{space}{space}\"{attrib_name}\".len(),\ \n{space}{space}{space}true,\ \n{space}{space});\ - \n{space}{space}let attrib: *mut zend_attribute = zend_add_class_attribute(class_entry, name, {param_count});\ + \n{space}{space}{attrib_variable}zend_add_class_attribute(class_entry, name, {param_count});\ \n{space}{space}zend_string_release_ex(name, true);\ {param_init}\ \n{space}}}", @@ -1312,7 +1392,7 @@ impl ArgInfoBuilder<'_> { case: &EnumCase, backing: Option<&BuiltinType>, ) -> Result { - let case_name = case.name.as_ref().expect("No errors"); + let case_name = case.name.as_str().expect("No errors"); if let Some(value) = &case.value { if backing.is_none() { return Err(format!( @@ -1321,6 +1401,7 @@ impl ArgInfoBuilder<'_> { } return match &value.kind { ExprKind::String(string) => { + let real_string = string.to_str().ok_or("Strings must be valid UTF-8")?; self.scope.add_import("rsphp_sys", "zval"); self.scope.add_import("rsphp_sys", "zend_string"); self.scope.add_import("rsphp_sys", "zend_string_init"); @@ -1339,7 +1420,7 @@ impl ArgInfoBuilder<'_> { \n{space3}zend_enum_add_case_cstr(class_entry, c\"{name}\".as_ptr(), std::ptr::from_mut::(&mut value));\ \n{space}{space}}}", name = case_name, - val = string, + val = real_string, space = " ", space3 = " ", )) diff --git a/crates/stub-parser/src/types.rs b/crates/stub-parser/src/types.rs index 1aa27f2..0bc78e2 100644 --- a/crates/stub-parser/src/types.rs +++ b/crates/stub-parser/src/types.rs @@ -64,6 +64,7 @@ impl ArgInfoTypeRepr { ArgInfoTypeRepr::FullyQualifiedNamed(ns.to_owned() + "\\" + &joined), ), (NameKind::Error, _) => Err(format!("Type hint name error: {value:?}")), + (_, _) => Err(format!("NameKind is non-exhaustive, unhandled: {kind:?}")), } } TypeHintKind::Nullable(inner) => Ok(ArgInfoTypeRepr::Nullable(Box::new( @@ -79,6 +80,9 @@ impl ArgInfoTypeRepr { TypeHintKind::Intersection(_) => { Err("Intersection type hints not yet supported".to_owned()) } + _ => Err(format!( + "TypeHintKind is non-exhaustive, unhandled: {value:?}" + )), } } @@ -271,10 +275,10 @@ impl ArgInfoTypeRepr { return Err(format!("type_info() called for {self:#?}")); }; match php_type { - BuiltinType::Int | BuiltinType::Integer => Ok(("IS_LONG", "MAY_BE_LONG")), - BuiltinType::Float | BuiltinType::Double => Ok(("IS_DOUBLE", "MAY_BE_DOUBLE")), + BuiltinType::Int => Ok(("IS_LONG", "MAY_BE_LONG")), + BuiltinType::Float => Ok(("IS_DOUBLE", "MAY_BE_DOUBLE")), BuiltinType::String => Ok(("IS_STRING", "MAY_BE_STRING")), - BuiltinType::Bool | BuiltinType::Boolean => Ok(("_IS_BOOL", "MAY_BE_BOOL")), + BuiltinType::Bool => Ok(("_IS_BOOL", "MAY_BE_BOOL")), BuiltinType::Void => Ok(("IS_VOID", "MAY_BE_VOID")), BuiltinType::Never => Ok(("IS_NEVER", "MAY_BE_NEVER")), BuiltinType::Mixed => Ok(("IS_MIXED", "MAY_BE_ANY")), @@ -292,6 +296,9 @@ impl ArgInfoTypeRepr { BuiltinType::Null => Ok(("IS_NULL", "MAY_BE_NULL")), BuiltinType::True => Ok(("IS_TRUE", "MAY_BE_TRUE")), BuiltinType::False => Ok(("IS_FALSE", "MAY_BE_FALSE")), + unknown => Err(format!( + "BuiltinType is non-exhaustive, unhandled: {unknown:?}" + )), } } } diff --git a/crates/stub-parser/src/verification.rs b/crates/stub-parser/src/verification.rs index bf7a0f1..f9ba568 100644 --- a/crates/stub-parser/src/verification.rs +++ b/crates/stub-parser/src/verification.rs @@ -114,13 +114,19 @@ impl VerificationData { } /// Add a `ZEND_ACC_*` flag based on the visibility to the expected flags. - pub(crate) fn add_visibility(&mut self, vis: Option<&Visibility>) { + pub(crate) fn add_visibility(&mut self, vis: Option<&Visibility>) -> Result<(), String> { let flag = match vis { None | Some(Visibility::Public) => "ZEND_ACC_PUBLIC", Some(Visibility::Protected) => "ZEND_ACC_PROTECTED", Some(Visibility::Private) => "ZEND_ACC_PRIVATE", + Some(unknown) => { + return Err(format!( + "Visibility is non-exhaustive, unhandled: {unknown:?}" + )); + } }; self.add_flag(flag); + Ok(()) } /// Add the specified flag to the expected flags. diff --git a/crates/stub-parser/tests/bundled_panic_test.rs b/crates/stub-parser/tests/bundled_panic_test.rs index dc56e51..6e00346 100644 --- a/crates/stub-parser/tests/bundled_panic_test.rs +++ b/crates/stub-parser/tests/bundled_panic_test.rs @@ -29,12 +29,15 @@ fn verify_walker(walker: WalkDir) -> Result<(), Box> { // php_date uses global constants to set the class constant // php_sql.stub.php uses iterable // zend_test splits the doc comment into two for one of the constants + // listformatter.stub.php uses #if conditions to specify the definition + // of IntlListFromatter::TYPE_AND and ::WIDTH_WIDE, skip!( "zend_builtin_functions", "zend_constants", "php_date", "php_spl", "test", + "listformatter", ); let path = entry.into_path(); // We don't care about the actual result, just that .expect() does not diff --git a/crates/stub-parser/tests/cases/class_flags.expected b/crates/stub-parser/tests/cases/class_flags.expected index 9adf97b..57a1482 100644 --- a/crates/stub-parser/tests/cases/class_flags.expected +++ b/crates/stub-parser/tests/cases/class_flags.expected @@ -62,3 +62,75 @@ pub(crate) mod Demo3 { class_entry } } +/// Module for `IsAbstract` class. +pub(crate) mod IsAbstract { + use rsphp_sys::{ZEND_ACC_ABSTRACT, zend_class_entry}; + + + /// Register the `IsAbstract` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "IsAbstract", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + ZEND_ACC_ABSTRACT, + ) + }; + + + class_entry + } +} +/// Module for `IsReadOnly` class. +pub(crate) mod IsReadOnly { + use rsphp_sys::{ZEND_ACC_FINAL, ZEND_ACC_READONLY_CLASS, zend_class_entry}; + + + /// Register the `IsReadOnly` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "IsReadOnly", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + ZEND_ACC_FINAL|ZEND_ACC_READONLY_CLASS, + ) + }; + + + class_entry + } +} +/// Module for `AllowsDynamicProperties` class. +pub(crate) mod AllowsDynamicProperties { + use rsphp_sys::{ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES, zend_add_class_attribute, zend_class_entry, zend_string, zend_string_init_interned, zend_string_release_ex}; + + + /// Register the `AllowsDynamicProperties` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "AllowsDynamicProperties", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES, + ) + }; + + + unsafe { + let name: *mut zend_string = (zend_string_init_interned.expect("zend_string_init_interned should be set"))( + c"AllowDynamicProperties".as_ptr(), + "AllowDynamicProperties".len(), + true, + ); + zend_add_class_attribute(class_entry, name, 0); + zend_string_release_ex(name, true); + } + class_entry + } +} diff --git a/crates/stub-parser/tests/cases/class_flags.stub.php b/crates/stub-parser/tests/cases/class_flags.stub.php index 0e1bad1..8c29d75 100644 --- a/crates/stub-parser/tests/cases/class_flags.stub.php +++ b/crates/stub-parser/tests/cases/class_flags.stub.php @@ -14,4 +14,11 @@ final class Demo2 {} * @strict-properties * @not-serializable */ -final class Demo3 {} \ No newline at end of file +final class Demo3 {} + +abstract class IsAbstract {} + +final readonly class IsReadOnly {} + +#[\AllowDynamicProperties] +class AllowsDynamicProperties {} diff --git a/crates/stub-parser/tests/cases/nullable_property.expected b/crates/stub-parser/tests/cases/nullable_property.expected index 6d00bf1..0b68768 100644 --- a/crates/stub-parser/tests/cases/nullable_property.expected +++ b/crates/stub-parser/tests/cases/nullable_property.expected @@ -2,7 +2,7 @@ /// Module for `Reference` class. pub(crate) mod Reference { use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; - use rsphp_sys::{MAY_BE_NULL, MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + use rsphp_sys::{MAY_BE_NULL, MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, ZEND_ACC_READONLY, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; /// Register the `Reference` class. @@ -31,7 +31,7 @@ pub(crate) mod Reference { class_entry, property_name_name, std::ptr::from_mut::(&mut property_name_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -54,7 +54,7 @@ pub(crate) mod Reference { class_entry, property_shorthand_name, std::ptr::from_mut::(&mut property_shorthand_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -77,7 +77,7 @@ pub(crate) mod Reference { class_entry, property_symbolicTarget_name, std::ptr::from_mut::(&mut property_symbolicTarget_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING|MAY_BE_NULL), ); diff --git a/crates/stub-parser/tests/cases/property_flags.expected b/crates/stub-parser/tests/cases/property_flags.expected new file mode 100644 index 0000000..471803b --- /dev/null +++ b/crates/stub-parser/tests/cases/property_flags.expected @@ -0,0 +1,388 @@ + +/// Module for `Demo` class. +pub(crate) mod Demo { + use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; + use rsphp_sys::{MAY_BE_ANY, ZEND_ACC_FINAL, ZEND_ACC_PRIVATE, ZEND_ACC_PRIVATE_SET, ZEND_ACC_PROTECTED, ZEND_ACC_PROTECTED_SET, ZEND_ACC_PUBLIC, ZEND_ACC_PUBLIC_SET, ZEND_ACC_READONLY, ZEND_ACC_STATIC, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + + + /// Register the `Demo` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "Demo", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + 0, + ) + }; + + let mut property_is_public_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_public_default_value)); } + let property_is_public_name: *mut zend_string = unsafe { + zend_string_init( + c"is_public".as_ptr(), + "is_public".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_public_name, + std::ptr::from_mut::(&mut property_is_public_default_value), + ZEND_ACC_PUBLIC as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_public_name); + } + + let mut property_is_protected_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_protected_default_value)); } + let property_is_protected_name: *mut zend_string = unsafe { + zend_string_init( + c"is_protected".as_ptr(), + "is_protected".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_protected_name, + std::ptr::from_mut::(&mut property_is_protected_default_value), + ZEND_ACC_PROTECTED as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_protected_name); + } + + let mut property_is_private_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_private_default_value)); } + let property_is_private_name: *mut zend_string = unsafe { + zend_string_init( + c"is_private".as_ptr(), + "is_private".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_private_name, + std::ptr::from_mut::(&mut property_is_private_default_value), + ZEND_ACC_PRIVATE as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_private_name); + } + + let mut property_pub_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_readonly_default_value)); } + let property_pub_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_readonly".as_ptr(), + "pub_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_readonly_name, + std::ptr::from_mut::(&mut property_pub_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_readonly_name); + } + + let mut property_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_readonly_default_value)); } + let property_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_readonly".as_ptr(), + "prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_readonly_name, + std::ptr::from_mut::(&mut property_prot_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_readonly_name); + } + + let mut property_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_priv_readonly_default_value)); } + let property_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"priv_readonly".as_ptr(), + "priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_priv_readonly_name, + std::ptr::from_mut::(&mut property_priv_readonly_default_value), + (ZEND_ACC_PRIVATE|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_priv_readonly_name); + } + + let mut property_pub_pub_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_pub_readonly_default_value)); } + let property_pub_pub_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_pub_readonly".as_ptr(), + "pub_pub_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_pub_readonly_name, + std::ptr::from_mut::(&mut property_pub_pub_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PUBLIC_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_pub_readonly_name); + } + + let mut property_pub_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_prot_readonly_default_value)); } + let property_pub_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_prot_readonly".as_ptr(), + "pub_prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_prot_readonly_name, + std::ptr::from_mut::(&mut property_pub_prot_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PROTECTED_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_prot_readonly_name); + } + + let mut property_pub_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_priv_readonly_default_value)); } + let property_pub_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_priv_readonly".as_ptr(), + "pub_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_priv_readonly_name, + std::ptr::from_mut::(&mut property_pub_priv_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_priv_readonly_name); + } + + let mut property_prot_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_prot_readonly_default_value)); } + let property_prot_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_prot_readonly".as_ptr(), + "prot_prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_prot_readonly_name, + std::ptr::from_mut::(&mut property_prot_prot_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY|ZEND_ACC_PROTECTED_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_prot_readonly_name); + } + + let mut property_prot_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_priv_readonly_default_value)); } + let property_prot_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_priv_readonly".as_ptr(), + "prot_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_priv_readonly_name, + std::ptr::from_mut::(&mut property_prot_priv_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_priv_readonly_name); + } + + let mut property_priv_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_priv_priv_readonly_default_value)); } + let property_priv_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"priv_priv_readonly".as_ptr(), + "priv_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_priv_priv_readonly_name, + std::ptr::from_mut::(&mut property_priv_priv_readonly_default_value), + (ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_priv_priv_readonly_name); + } + + let mut property_is_static_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_static_default_value)); } + let property_is_static_name: *mut zend_string = unsafe { + zend_string_init( + c"is_static".as_ptr(), + "is_static".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_static_name, + std::ptr::from_mut::(&mut property_is_static_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_static_name); + } + + let mut property_is_final_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_final_default_value)); } + let property_is_final_name: *mut zend_string = unsafe { + zend_string_init( + c"is_final".as_ptr(), + "is_final".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_final_name, + std::ptr::from_mut::(&mut property_is_final_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_final_name); + } + + class_entry + } +} +/// Module for `ReadonlyClass` class. +pub(crate) mod ReadonlyClass { + use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; + use rsphp_sys::{MAY_BE_ANY, ZEND_ACC_PUBLIC, ZEND_ACC_READONLY, ZEND_ACC_READONLY_CLASS, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + + + /// Register the `ReadonlyClass` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "ReadonlyClass", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + ZEND_ACC_READONLY_CLASS, + ) + }; + + let mut property_is_public_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_public_default_value)); } + let property_is_public_name: *mut zend_string = unsafe { + zend_string_init( + c"is_public".as_ptr(), + "is_public".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_public_name, + std::ptr::from_mut::(&mut property_is_public_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_public_name); + } + + class_entry + } +} diff --git a/crates/stub-parser/tests/cases/property_flags.stub.php b/crates/stub-parser/tests/cases/property_flags.stub.php new file mode 100644 index 0000000..dc76c6b --- /dev/null +++ b/crates/stub-parser/tests/cases/property_flags.stub.php @@ -0,0 +1,31 @@ +(&mut property_id_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_CLASS!(property_id_type, 0, 0), ); @@ -68,7 +68,7 @@ pub(crate) mod RSGit_Commit { class_entry, property_author_name, std::ptr::from_mut::(&mut property_author_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_CLASS!(property_author_type, 0, 0), ); @@ -98,7 +98,7 @@ pub(crate) mod RSGit_Commit { class_entry, property_committer_name, std::ptr::from_mut::(&mut property_committer_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_CLASS!(property_committer_type, 0, 0), ); @@ -114,7 +114,7 @@ pub(crate) mod RSGit_Commit { pub(crate) mod RSGit_Oid { use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; use rsphp_macros_rs::ZEND_ARG_INFO_FOR_FUNCTION_WITH_RETURN_TYPE_MASK; - use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, zend_class_entry, zend_declare_typed_property, zend_function_entry, zend_internal_arg_info, zend_string, zend_string_init, zend_string_release, zval}; + use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, ZEND_ACC_READONLY, zend_class_entry, zend_declare_typed_property, zend_function_entry, zend_internal_arg_info, zend_string, zend_string_init, zend_string_release, zval}; /// Argument information for `RSGit\Oid::__toString()`. pub(crate) const ARGINFO___TOSTRING: [zend_internal_arg_info; 1] = [ @@ -149,7 +149,7 @@ pub(crate) mod RSGit_Oid { class_entry, property_asHex_name, std::ptr::from_mut::(&mut property_asHex_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -164,7 +164,7 @@ pub(crate) mod RSGit_Oid { /// Module for `RSGit\Signature` class. pub(crate) mod RSGit_Signature { use rsphp_macros_c::{ZEND_TYPE_INIT_CLASS, ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; - use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, ZEND_ACC_READONLY, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; /// Register the `RSGit\Signature` class. @@ -193,7 +193,7 @@ pub(crate) mod RSGit_Signature { class_entry, property_name_name, std::ptr::from_mut::(&mut property_name_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -216,7 +216,7 @@ pub(crate) mod RSGit_Signature { class_entry, property_email_name, std::ptr::from_mut::(&mut property_email_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -246,7 +246,7 @@ pub(crate) mod RSGit_Signature { class_entry, property_time_name, std::ptr::from_mut::(&mut property_time_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_CLASS!(property_time_type, 0, 0), ); diff --git a/crates/stub-parser/tests/verification-cases/no_methods.expected b/crates/stub-parser/tests/verification-cases/no_methods.expected index 2c3f968..7b9e24a 100644 --- a/crates/stub-parser/tests/verification-cases/no_methods.expected +++ b/crates/stub-parser/tests/verification-cases/no_methods.expected @@ -2,7 +2,7 @@ /// Module for `Example` class. pub(crate) mod Example { use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; - use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + use rsphp_sys::{MAY_BE_STRING, ZEND_ACC_FINAL, ZEND_ACC_NOT_SERIALIZABLE, ZEND_ACC_NO_DYNAMIC_PROPERTIES, ZEND_ACC_PUBLIC, ZEND_ACC_READONLY, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; /// Register the `Example` class. @@ -31,7 +31,7 @@ pub(crate) mod Example { class_entry, property_first_name, std::ptr::from_mut::(&mut property_first_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); @@ -54,7 +54,7 @@ pub(crate) mod Example { class_entry, property_second_name, std::ptr::from_mut::(&mut property_second_default_value), - ZEND_ACC_PUBLIC as i32, + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, std::ptr::null_mut(), ZEND_TYPE_INIT_MASK!(MAY_BE_STRING), ); diff --git a/example/rust-ext-demo/Cargo.lock b/example/rust-ext-demo/Cargo.lock index 03f21db..b33dc48 100644 --- a/example/rust-ext-demo/Cargo.lock +++ b/example/rust-ext-demo/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.5" @@ -26,30 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - [[package]] name = "bindgen" version = "0.73.2" @@ -66,7 +27,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 3.0.7", + "syn", ] [[package]] @@ -134,138 +95,18 @@ dependencies = [ "libloading", ] -[[package]] -name = "displaydoc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.7", -] - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - [[package]] name = "find-msvc-tools" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "glob" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" -[[package]] -name = "icu_collections" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" -dependencies = [ - "displaydoc", - "potential_utf", - "utf8_iter", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" -dependencies = [ - "displaydoc", - "litemap", - "serde", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locale_fallback" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "251af8e57c9400e3eb58242fe5b8b1152b2a64fdf4cf632f923c38ccee6f2fa9" -dependencies = [ - "icu_locale_core", - "icu_locale_fallback_data", - "icu_provider", - "potential_utf", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locale_fallback_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decf2a22ec8fa68f1a0c1129a3f8583f8f8bc24e8b9ccbe98ead99f62a4dc3a8" - -[[package]] -name = "icu_provider" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" -dependencies = [ - "displaydoc", - "icu_locale_core", - "serde", - "stable_deref_trait", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_segmenter" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d07aafccd67af15d02512a6adf5896fbc5ed00f2e99b471d2efa14016db3db" -dependencies = [ - "icu_collections", - "icu_locale_fallback", - "icu_provider", - "icu_segmenter_data", - "potential_utf", - "smallvec", - "utf8_iter", - "zerovec", -] - -[[package]] -name = "icu_segmenter_data" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae293c039020f9ec10710af98d29ce6aa2051486638b49c9a6409f3b4a9e98ad" - -[[package]] -name = "is_ci" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45" - [[package]] name = "libc" version = "0.2.190" @@ -282,18 +123,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "litemap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" - [[package]] name = "log" version = "0.4.34" @@ -306,51 +135,12 @@ version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" -[[package]] -name = "miette" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" -dependencies = [ - "backtrace", - "backtrace-ext", - "cfg-if", - "miette-derive", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "unicode-width 0.1.14", -] - -[[package]] -name = "miette-derive" -version = "7.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", -] - [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "nom" version = "7.1.3" @@ -361,36 +151,20 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - -[[package]] -name = "owo-colors" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c45bb4a6ae1280ec0803b1ef9d3455eb50f01efbbe1447ab020f1d54fba9d8" - [[package]] name = "php-ast" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98fd0c5357b164ae192c654b7c9c3f8c1c8c3305c1b6f0686d9b5505145f67" +checksum = "b45af352ac35a7d92ec0830160070894d6de16f4920ec7902dc16ef913e39f8e" dependencies = [ "bumpalo", - "serde", ] [[package]] name = "php-lexer" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc85b0cae487b9c7c819fbb0886ce33424b4d0e21d4ff7cb0f5d26c03050df38" +checksum = "28371e67a39240e9fd1fa02628c963f962e26554712f07fdb501eef12c50bdae" dependencies = [ "memchr", "php-ast", @@ -398,39 +172,17 @@ dependencies = [ [[package]] name = "php-rs-parser" -version = "0.21.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822458849250ea40699d631eb8d75b7a29d4a43f9d710862db069db5953ca311" +checksum = "73040a5818ac3154cfa7084c39323203ae9a7968236c82c39eff7deb0f6c5485" dependencies = [ "bumpalo", "memchr", - "miette", "php-ast", "php-lexer", - "phpdoc-parser", "thiserror", ] -[[package]] -name = "phpdoc-parser" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d643e450bbf0f3208d160b8d85fcacced884889556d6363d6d9ddcd420a73117" -dependencies = [ - "serde", -] - -[[package]] -name = "potential_utf" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" -dependencies = [ - "serde_core", - "writeable", - "zerovec", -] - [[package]] name = "prettyplease" version = "0.3.0" @@ -438,7 +190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" dependencies = [ "proc-macro2", - "syn 3.0.7", + "syn", ] [[package]] @@ -551,41 +303,12 @@ dependencies = [ "rsphp-build-tools", ] -[[package]] -name = "rustc-demangle" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" - [[package]] name = "rustc-hash" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" -[[package]] -name = "rustix" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "serde" -version = "1.0.229" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" -dependencies = [ - "serde_core", - "serde_derive", -] - [[package]] name = "serde_core" version = "1.0.229" @@ -603,7 +326,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.7", + "syn", ] [[package]] @@ -612,50 +335,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" -[[package]] -name = "smallvec" -version = "1.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "supports-color" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fc7232dd8d2e4ac5ce4ef302b1d81e0b80d055b9d77c7c4f51f6aa4c867d6" -dependencies = [ - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" - -[[package]] -name = "supports-unicode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2" - -[[package]] -name = "syn" -version = "2.0.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "3.0.7" @@ -667,37 +346,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "synstructure" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.7", -] - -[[package]] -name = "terminal_size" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" -dependencies = [ - "rustix", - "windows-sys", -] - -[[package]] -name = "textwrap" -version = "0.16.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ecfad6c3abc80a577f2b91c1e412ee57e7a060d430b553c1b0c940974ebcd49" -dependencies = [ - "icu_segmenter", - "unicode-width 0.2.2", -] - [[package]] name = "thiserror" version = "2.0.21" @@ -715,18 +363,7 @@ checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 3.0.7", -] - -[[package]] -name = "tinystr" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" -dependencies = [ - "displaydoc", - "serde_core", - "zerovec", + "syn", ] [[package]] @@ -735,118 +372,8 @@ version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link", -] - -[[package]] -name = "writeable" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" - -[[package]] -name = "yoke" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.7", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.7", - "synstructure", -] - -[[package]] -name = "zerotrie" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "zerovec" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" -dependencies = [ - "serde", - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.7", -] diff --git a/example/rust-ext-demo/src/lib.rs b/example/rust-ext-demo/src/lib.rs index b388b34..21c6fcf 100644 --- a/example/rust-ext-demo/src/lib.rs +++ b/example/rust-ext-demo/src/lib.rs @@ -10,9 +10,9 @@ use rsphp_macros_c::{ use rsphp_macros_rs::{ZEND_FE, ZEND_PARSE_ARGS, ZEND_PARSE_PARAMETERS_NONE}; use rsphp_sys::{ HashTable, ZEND_CALL_HAS_EXTRA_NAMED_PARAMS, ZEND_RESULT_CODE, display_ini_entries, - php_output_write, php_printf, php_var_dump, zend_execute_data, zend_function_entry, - zend_module_entry, zend_parse_parameters, zend_register_ini_entries_ex, zend_result, - zend_string, zend_string_init, zend_unregister_ini_entries_ex, zval, + php_output_write, php_printf, php_var_dump, zend_class_entry, zend_execute_data, + zend_function_entry, zend_module_entry, zend_parse_parameters, zend_register_ini_entries_ex, + zend_result, zend_string, zend_string_init, zend_unregister_ini_entries_ex, zval, }; use std::ffi::{c_char, c_int}; @@ -28,8 +28,10 @@ use opaquedata::{ mod ini_demo; use ini_demo::{class_ini_demo_methods, ini_demo_ptr}; +static mut properties_demo_ptr: *mut zend_class_entry = std::ptr::null_mut(); + #[rustfmt::skip] -#[expect(clippy::cast_possible_wrap)] +#[expect(clippy::cast_possible_wrap, clippy::too_many_lines)] mod rustdemo_arginfo; #[rustfmt::skip] mod opaquedata_arginfo; @@ -55,6 +57,8 @@ extern "C" fn my_module_init(type_: c_int, module_number: c_int) -> zend_result ini_demo_ptr = ini_demo_arginfo::IniDemo::register_class(&class_ini_demo_methods); + properties_demo_ptr = rustdemo_arginfo::PropertiesDemo::register_class(); + zend_register_ini_entries_ex(ini_demo::demo_ini_entries.as_ptr(), module_number, type_); } ZEND_RESULT_CODE::SUCCESS diff --git a/example/rust-ext-demo/src/rustdemo.stub.php b/example/rust-ext-demo/src/rustdemo.stub.php index f10a411..87ecbf7 100644 --- a/example/rust-ext-demo/src/rustdemo.stub.php +++ b/example/rust-ext-demo/src/rustdemo.stub.php @@ -48,3 +48,25 @@ public function increment(): void {} public function asString(): string {} } + +class PropertiesDemo { + public mixed $is_public; + protected mixed $is_protected; + private mixed $is_private; + + public readonly mixed $pub_readonly; + protected readonly mixed $prot_readonly; + private readonly mixed $priv_readonly; + + public public(set) readonly mixed $pub_pub_readonly; + public protected(set) readonly mixed $pub_prot_readonly; + public private(set) readonly mixed $pub_priv_readonly; + + protected protected(set) readonly mixed $prot_prot_readonly; + protected private(set) readonly mixed $prot_priv_readonly; + + private private(set) readonly mixed $priv_priv_readonly; + + public static mixed $is_static; + public final mixed $is_final; +} diff --git a/example/rust-ext-demo/src/rustdemo_arginfo.rs b/example/rust-ext-demo/src/rustdemo_arginfo.rs index c98f3e8..42fc1ab 100644 --- a/example/rust-ext-demo/src/rustdemo_arginfo.rs +++ b/example/rust-ext-demo/src/rustdemo_arginfo.rs @@ -343,3 +343,346 @@ pub(crate) mod RSDemo { class_entry } } +/// Module for `PropertiesDemo` class. +pub(crate) mod PropertiesDemo { + use rsphp_macros_c::{ZEND_TYPE_INIT_MASK, ZVAL_UNDEF}; + use rsphp_sys::{MAY_BE_ANY, ZEND_ACC_FINAL, ZEND_ACC_PRIVATE, ZEND_ACC_PRIVATE_SET, ZEND_ACC_PROTECTED, ZEND_ACC_PROTECTED_SET, ZEND_ACC_PUBLIC, ZEND_ACC_PUBLIC_SET, ZEND_ACC_READONLY, ZEND_ACC_STATIC, zend_class_entry, zend_declare_typed_property, zend_string, zend_string_init, zend_string_release, zval}; + + + /// Register the `PropertiesDemo` class. + pub(crate) fn register_class() -> *mut zend_class_entry { + let mut ce: zend_class_entry = unsafe { std::mem::zeroed() }; + rsphp_macros_c::INIT_CLASS_ENTRY!(ce, "PropertiesDemo", NULL); + let class_entry: *mut zend_class_entry = unsafe { + rsphp_sys::zend_register_internal_class_with_flags( + std::ptr::from_mut::(&mut ce), + std::ptr::null_mut(), + 0, + ) + }; + + let mut property_is_public_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_public_default_value)); } + let property_is_public_name: *mut zend_string = unsafe { + zend_string_init( + c"is_public".as_ptr(), + "is_public".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_public_name, + std::ptr::from_mut::(&mut property_is_public_default_value), + ZEND_ACC_PUBLIC as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_public_name); + } + + let mut property_is_protected_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_protected_default_value)); } + let property_is_protected_name: *mut zend_string = unsafe { + zend_string_init( + c"is_protected".as_ptr(), + "is_protected".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_protected_name, + std::ptr::from_mut::(&mut property_is_protected_default_value), + ZEND_ACC_PROTECTED as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_protected_name); + } + + let mut property_is_private_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_private_default_value)); } + let property_is_private_name: *mut zend_string = unsafe { + zend_string_init( + c"is_private".as_ptr(), + "is_private".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_private_name, + std::ptr::from_mut::(&mut property_is_private_default_value), + ZEND_ACC_PRIVATE as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_private_name); + } + + let mut property_pub_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_readonly_default_value)); } + let property_pub_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_readonly".as_ptr(), + "pub_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_readonly_name, + std::ptr::from_mut::(&mut property_pub_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_readonly_name); + } + + let mut property_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_readonly_default_value)); } + let property_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_readonly".as_ptr(), + "prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_readonly_name, + std::ptr::from_mut::(&mut property_prot_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_readonly_name); + } + + let mut property_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_priv_readonly_default_value)); } + let property_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"priv_readonly".as_ptr(), + "priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_priv_readonly_name, + std::ptr::from_mut::(&mut property_priv_readonly_default_value), + (ZEND_ACC_PRIVATE|ZEND_ACC_READONLY) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_priv_readonly_name); + } + + let mut property_pub_pub_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_pub_readonly_default_value)); } + let property_pub_pub_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_pub_readonly".as_ptr(), + "pub_pub_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_pub_readonly_name, + std::ptr::from_mut::(&mut property_pub_pub_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PUBLIC_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_pub_readonly_name); + } + + let mut property_pub_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_prot_readonly_default_value)); } + let property_pub_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_prot_readonly".as_ptr(), + "pub_prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_prot_readonly_name, + std::ptr::from_mut::(&mut property_pub_prot_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PROTECTED_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_prot_readonly_name); + } + + let mut property_pub_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_pub_priv_readonly_default_value)); } + let property_pub_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"pub_priv_readonly".as_ptr(), + "pub_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_pub_priv_readonly_name, + std::ptr::from_mut::(&mut property_pub_priv_readonly_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_pub_priv_readonly_name); + } + + let mut property_prot_prot_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_prot_readonly_default_value)); } + let property_prot_prot_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_prot_readonly".as_ptr(), + "prot_prot_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_prot_readonly_name, + std::ptr::from_mut::(&mut property_prot_prot_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY|ZEND_ACC_PROTECTED_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_prot_readonly_name); + } + + let mut property_prot_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_prot_priv_readonly_default_value)); } + let property_prot_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"prot_priv_readonly".as_ptr(), + "prot_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_prot_priv_readonly_name, + std::ptr::from_mut::(&mut property_prot_priv_readonly_default_value), + (ZEND_ACC_PROTECTED|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_prot_priv_readonly_name); + } + + let mut property_priv_priv_readonly_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_priv_priv_readonly_default_value)); } + let property_priv_priv_readonly_name: *mut zend_string = unsafe { + zend_string_init( + c"priv_priv_readonly".as_ptr(), + "priv_priv_readonly".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_priv_priv_readonly_name, + std::ptr::from_mut::(&mut property_priv_priv_readonly_default_value), + (ZEND_ACC_PRIVATE|ZEND_ACC_READONLY|ZEND_ACC_PRIVATE_SET) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_priv_priv_readonly_name); + } + + let mut property_is_static_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_static_default_value)); } + let property_is_static_name: *mut zend_string = unsafe { + zend_string_init( + c"is_static".as_ptr(), + "is_static".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_static_name, + std::ptr::from_mut::(&mut property_is_static_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_static_name); + } + + let mut property_is_final_default_value: zval = unsafe { std::mem::zeroed() }; + unsafe { ZVAL_UNDEF!(std::ptr::from_mut::(&mut property_is_final_default_value)); } + let property_is_final_name: *mut zend_string = unsafe { + zend_string_init( + c"is_final".as_ptr(), + "is_final".len(), + true, + ) + }; + unsafe { + zend_declare_typed_property( + class_entry, + property_is_final_name, + std::ptr::from_mut::(&mut property_is_final_default_value), + (ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) as i32, + std::ptr::null_mut(), + ZEND_TYPE_INIT_MASK!(MAY_BE_ANY), + ); + } + unsafe { + zend_string_release(property_is_final_name); + } + + class_entry + } +} diff --git a/example/rust-ext-demo/tests/reflection.phpt b/example/rust-ext-demo/tests/reflection.phpt index f15656c..3262989 100644 --- a/example/rust-ext-demo/tests/reflection.phpt +++ b/example/rust-ext-demo/tests/reflection.phpt @@ -82,7 +82,7 @@ Extension [ extension #%d rustdemo version 0.1.0 ] { } } - - Classes [3] { + - Classes [4] { Class [ class RSDemo ] { - Constants [0] { @@ -217,5 +217,37 @@ Extension [ extension #%d rustdemo version 0.1.0 ] { - Methods [0] { } } + + Class [ class PropertiesDemo ] { + + - Constants [0] { + } + + - Static properties [1] { + Property [ public static mixed $is_static ] + } + + - Static methods [0] { + } + + - Properties [13] { + Property [ public mixed $is_public ] + Property [ protected mixed $is_protected ] + Property [ private mixed $is_private ] + Property [ public protected(set) readonly mixed $pub_readonly ] + Property [ protected readonly mixed $prot_readonly ] + Property [ private readonly mixed $priv_readonly ] + Property [ public readonly mixed $pub_pub_readonly ] + Property [ public protected(set) readonly mixed $pub_prot_readonly ] + Property [ final public private(set) readonly mixed $pub_priv_readonly ] + Property [ protected readonly mixed $prot_prot_readonly ] + Property [ final protected private(set) readonly mixed $prot_priv_readonly ] + Property [ private readonly mixed $priv_priv_readonly ] + Property [ final public mixed $is_final ] + } + + - Methods [0] { + } + } } }