Fix #5318: known answers false for keys no dictionary holds

`known` raised a typecheck for any key that can't be a key here (an
array, a dictionary, a real with a fraction). The PLRM allows any
object but null as a key, and since `put` refuses such keys, no
dictionary holds one: `known` now answers false, and null still raises
the typecheck. Ghostscript's eps2write prolog looks each inline-image
value up in a dictionary of abbreviations, and an image with two
filters has an array there.
This commit is contained in:
JonRC
2026-11-03 15:57:00 +07:00
committed by bflatastic
parent eca414044b
commit 8fb394ca16
2 changed files with 24 additions and 3 deletions
+13 -3
View File
@@ -1050,10 +1050,10 @@ impl<'a> Interp<'a> {
self.insert(&d, k, Some(v))?;
}
Known => {
let k = self.pop()?.key().ok_or(PsError::Ps("typecheck", String::new()))?;
let k = self.pop()?;
let d = self.pop_dict()?;
let known = d.borrow().contains_key(&k);
self.push(Obj::Bool(known))?;
let found = known(&d, &k)?;
self.push(Obj::Bool(found))?;
}
Where => {
let k = self.pop()?.key().ok_or(PsError::Ps("typecheck", String::new()))?;
@@ -1418,6 +1418,16 @@ fn index(k: &Obj) -> Res<usize> {
}
}
/// `known`: a key may be any object but null (PLRM 3rd ed.), and one that can't be a key here (an
/// array, a dictionary, a real with a fraction) is in no dictionary, since `put` refuses it.
fn known(d: &DictRef, k: &Obj) -> Res<bool> {
match k.key() {
Some(key) => Ok(d.borrow().contains_key(&key)),
None if matches!(k, Obj::Null) => ps_err("typecheck", "known"),
None => Ok(false),
}
}
/// `eq`: numbers by value, strings and names by text, composites by identity.
fn equal(a: &Obj, b: &Obj) -> bool {
match (a, b) {
+11
View File
@@ -996,6 +996,17 @@ fn the_standard_dictionaries_are_dictionaries_in_systemdict() {
check("SharedFontDirectory type /dicttype eq");
}
/// A key may be any object but null (PLRM 3rd ed.), so `known` answers for every other key.
/// Ghostscript's `eps2write` looks an inline image's filter up in a dictionary of abbreviations,
/// and the filter may be an array of them.
#[test]
fn known_answers_false_for_keys_no_dictionary_holds() {
check("<< /A85 /ASCII85Decode >> [ /A85 /LZW ] known not");
check("1 dict 1 dict known not 1 dict 1.5 known not and 1 dict mark known not and");
check("<< /A85 /ASCII85Decode >> /A85 known << 1 2 >> 1.0 known and");
check("{ 1 dict null known } stopped");
}
#[test]
fn dictstack_and_internaldict_answer() {
check("10 array dictstack length countdictstack eq");