mirror of
git://git.proxmox.com/git/perlmod.git
synced 2025-01-04 13:17:39 +03:00
improve PVLV handling
For the cases we're most intested in (substr and vivifyable hash indexing) we can use perform "GET" magic to figure out whether it was undef or not, and then simply recurse. We'll have to deal with other cases as we run into them. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
61143f5d12
commit
b5c53f3d37
@ -68,6 +68,7 @@ extern "C" {
|
||||
pub fn RSPL_is_hash(sv: *mut SV) -> bool;
|
||||
pub fn RSPL_type_flags(sv: *mut SV) -> u32;
|
||||
pub fn RSPL_svtype(sv: *mut SV) -> u32;
|
||||
pub fn RSPL_SvOK(sv: *mut SV) -> bool;
|
||||
pub fn RSPL_SvTRUE(sv: *mut SV) -> bool;
|
||||
|
||||
pub fn RSPL_newAV() -> *mut AV;
|
||||
@ -110,7 +111,11 @@ extern "C" {
|
||||
|
||||
pub fn RSPL_PVLV() -> u32;
|
||||
pub fn RSPL_LvTARG(sv: *mut SV) -> *mut SV;
|
||||
//pub fn RSPL_LvTYPE(sv: *mut SV) -> u8;
|
||||
pub fn RSPL_vivify_defelem(sv: *mut SV);
|
||||
|
||||
pub fn RSPL_SvFLAGS(sv: *mut SV) -> u32;
|
||||
pub fn RSPL_SvGETMAGIC(sv: *mut SV) -> bool;
|
||||
}
|
||||
|
||||
/// Argument marker for the stack.
|
||||
|
@ -139,6 +139,10 @@ extern bool RSPL_is_scalar(SV *sv) {
|
||||
return SvTYPE(sv) < SVt_PVAV;
|
||||
}
|
||||
|
||||
extern bool RSPL_SvOK(SV *sv) {
|
||||
return SvOK(sv);
|
||||
}
|
||||
|
||||
extern bool RSPL_SvTRUE(SV *sv) {
|
||||
return SvTRUE(sv);
|
||||
}
|
||||
@ -310,8 +314,25 @@ extern SV* RSPL_LvTARG(SV *sv) {
|
||||
return LvTARG(sv);
|
||||
}
|
||||
|
||||
extern void RSPL_vivify_defelem(SV *sv) {
|
||||
Perl_vivify_defelem(aTHX_ sv);
|
||||
// We prefer this unsigned.
|
||||
//extern unsigned char RSPL_LvTYPE(SV *sv) {
|
||||
// return (unsigned char)LvTYPE(sv);
|
||||
//}
|
||||
|
||||
//extern void RSPL_vivify_defelem(SV *sv) {
|
||||
// Perl_vivify_defelem(aTHX_ sv);
|
||||
//}
|
||||
|
||||
//extern uint32_t RSPL_SvFLAGS(SV *sv) {
|
||||
// return SvFLAGS(sv);
|
||||
//}
|
||||
|
||||
//extern bool RSPL_SvMAGICAL(SV *sv) {
|
||||
// return SvMAGICAL(sv);
|
||||
//}
|
||||
|
||||
extern void RSPL_SvGETMAGIC(SV *sv) {
|
||||
return SvGETMAGIC(sv);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -186,48 +186,49 @@ impl ScalarRef {
|
||||
self as *const ScalarRef as *const SV as *mut SV
|
||||
}
|
||||
|
||||
/// Get some information about the value's type.
|
||||
pub fn ty(&self) -> Type {
|
||||
fn get_type(sv: *mut SV) -> Type {
|
||||
unsafe {
|
||||
if ffi::RSPL_is_reference(self.sv()) {
|
||||
Type::Reference
|
||||
} else {
|
||||
let flags = ffi::RSPL_type_flags(self.sv());
|
||||
if ffi::RSPL_is_array(self.sv()) {
|
||||
Type::Array
|
||||
} else if ffi::RSPL_is_hash(self.sv()) {
|
||||
Type::Hash
|
||||
} else if flags != 0 {
|
||||
// non-scalars will not have any flags:
|
||||
Type::Scalar(Flags::from_bits_truncate(flags as u8))
|
||||
} else {
|
||||
// but `undef` also has no flags, so:
|
||||
let ty = ffi::RSPL_svtype(self.sv());
|
||||
if ty == 0 {
|
||||
Type::Scalar(Flags::empty())
|
||||
} else if ty == ffi::RSPL_PVLV() {
|
||||
self.get_target()
|
||||
.map(|s| s.ty())
|
||||
.unwrap_or(Type::Other(99))
|
||||
} else {
|
||||
Type::Other(ty as u8)
|
||||
}
|
||||
}
|
||||
// These are simple:
|
||||
if ffi::RSPL_is_reference(sv) {
|
||||
return Type::Reference;
|
||||
} else if ffi::RSPL_is_array(sv) {
|
||||
return Type::Array;
|
||||
} else if ffi::RSPL_is_hash(sv) {
|
||||
return Type::Hash;
|
||||
}
|
||||
}
|
||||
|
||||
// Scalars have flags:
|
||||
let flags = ffi::RSPL_type_flags(sv);
|
||||
if flags != 0 {
|
||||
return Type::Scalar(Flags::from_bits_truncate(flags as u8));
|
||||
}
|
||||
|
||||
// Except for undef, but undef is difficult to catch:
|
||||
let ty = ffi::RSPL_svtype(sv);
|
||||
if ty == 0 {
|
||||
// Looks like undef
|
||||
return Type::Scalar(Flags::empty());
|
||||
} else if ty == ffi::RSPL_PVLV() {
|
||||
// We don't support all kinds of magic, but some lvalues are simple:
|
||||
// Try to GET the value and then check for definedness.
|
||||
ffi::RSPL_SvGETMAGIC(sv);
|
||||
if !ffi::RSPL_SvOK(sv) {
|
||||
// This happens when the value points to a non-existing hash element we could
|
||||
// auto-vivify, but we won't:
|
||||
return Type::Scalar(Flags::empty());
|
||||
}
|
||||
|
||||
// Otherwise we just try to "recurse", which will work for substrings.
|
||||
return Self::get_type(ffi::RSPL_LvTARG(sv));
|
||||
} else {
|
||||
return Type::Other(ty as u8);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Dereference this PVLV.
|
||||
pub fn get_target(&self) -> Option<Scalar> {
|
||||
let ptr = unsafe {
|
||||
ffi::RSPL_vivify_defelem(self.sv());
|
||||
ffi::RSPL_LvTARG(self.sv())
|
||||
};
|
||||
if ptr.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { Scalar::from_raw_ref(ptr) })
|
||||
}
|
||||
/// Get some information about the value's type.
|
||||
pub fn ty(&self) -> Type {
|
||||
Self::get_type(self.sv())
|
||||
}
|
||||
|
||||
/// Dereference this reference.
|
||||
@ -400,7 +401,7 @@ impl serde::Serialize for Scalar {
|
||||
}
|
||||
Type::Other(other) => Err(S::Error::custom(format!(
|
||||
"cannot serialize weird magic perl values ({})",
|
||||
other
|
||||
other,
|
||||
))),
|
||||
|
||||
// These are impossible as they are all handled by different Value enum types:
|
||||
|
3
test.pl
3
test.pl
@ -17,7 +17,10 @@ $v->another(54);
|
||||
|
||||
my $param = { a => 1 };
|
||||
my $s = "Hello You";
|
||||
print "These should be called with a valid substr:\n";
|
||||
RSPM::Foo142::test(substr($s, 3, 3));
|
||||
RSPM::Foo142::teststr(substr($s, 3, 3));
|
||||
print "Parameter exists: " . (exists($param->{x}) ? "YES" : "NO") . "\n";
|
||||
RSPM::Foo142::test($param->{x});
|
||||
print "Was auto-vivified: " . (exists($param->{x}) ? "YES" : "NO") . "\n";
|
||||
RSPM::Foo142::teststr($param->{x});
|
||||
|
11
test.pl.expected
Normal file
11
test.pl.expected
Normal file
@ -0,0 +1,11 @@
|
||||
Called something on Bless { "Hello" }!
|
||||
Called 'another(54)' on Bless { "Hello" }!
|
||||
test called with Some("lo ")
|
||||
teststr called with Some("lo ")
|
||||
test called with None
|
||||
teststr called with None
|
||||
Got (17, 32, )
|
||||
Got: 2 values: 17 32
|
||||
These should be called with a valid substr:
|
||||
Parameter exists: NO
|
||||
Was auto-vivified: NO
|
Loading…
Reference in New Issue
Block a user