Merge pull request #5319 from JonRC/fix/eps-known-composite-key

Fix #5318: `known` answers false for keys no dictionary holds
This commit is contained in:
BFlat
2026-11-03 16:29:40 +07:00
committed by GitHub
2 changed files with 26 additions and 3 deletions
+14 -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,17 @@ fn index(k: &Obj) -> Res<usize> {
}
}
/// `known`: a key may be any object but null (PLRM 3rd ed., §3.3.9, <https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf>),
/// and one that can't be a key here (an array, a dictionary, a real with a fraction) is in no
/// dictionary, since `put` here 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) {
+12
View File
@@ -996,6 +996,18 @@ fn the_standard_dictionaries_are_dictionaries_in_systemdict() {
check("SharedFontDirectory type /dicttype eq");
}
/// A key may be any object but null (PLRM 3rd ed., §3.3.9, <https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf>),
/// 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");