תקרת אורך מזהה (Identifier too long)#

ניסוח המקור#

perl5-upstream/pod/perlvar.pod קובע, בקטע Syntax of Variable Names:

שמות משתנים ב־Perl יכולים להיות בפורמטים מספר. בדרך כלל, עליהם להתחיל באות או קו תחתון, ובמקרה זה הם יכולים להיות באורך שרירותי (עד מגבלה פנימית של 251 תווים) ועשויים להכיל אותיות, ספרות, קווים תחתונים, או הרצף המיוחד :: או '.

ניסוח זה מטעה משתי בחינות.

תיקון#

הקביעה הנכונה, נכון לסדרת היציבה Perl 5.42, היא:

מזהים יכולים להיות באורך של עד 251 בתים. שמות החורגים מאורך זה גורמים לשגיאה בזמן ניתוח התחביר: Identifier too long.

שני דברים חשוב להבין מכך:

  1. בתים, לא תווים. התקרה נמדדת בבתים של ייצוג המקור, לא בנקודות קוד של Unicode. מזהי UTF-8 מגיעים לפיכך לגבול בפחות תווים:

    רוחב תו

    התקבל אחרון

    נדחה ראשון

    1 בית (ASCII)

    251 תווים

    252 תווים

    2 בתים (למשל é)

    125 תווים

    126 תווים

    3 בתים (למשל )

    83 תווים

    84 תווים

    4 בתים (למשל 𐌰 — גותית)

    62 תווים

    63 תווים

    בכל מקרה הדחייה מתרחשת כאשר אורך הבתים חורג לראשונה מ־251. ה־“251 תווים“ בטקסט המקור נכון רק עבור מקרה ה־ASCII.

  2. שגיאה קשה, לא ”מגבלה פנימית“. הניסוח ”עד מגבלה פנימית“ מרמז על משהו רך. זה לא — מנתח התחביר של perl5 מעלה חריגה פטאלית Identifier too long. ההודעה היא הדבר היחיד שהמשתמש רואה; אין קיצוץ, אזהרה, או נסיגה.

הסיבה הקרובה ב־5.42 היא ה־buffer ‏tokenbuf[256] ב־state של מנתח התחביר, יחד עם e = dest_end - 3 (בית sigil + ‏\0 בסוף + שולי בטיחות) הנלקחים בחשבון בתוך S_parse_ident. הצירוף מניב 252 בתים בסך הכל פחות sigil = 251 בתים של שם המזהה עצמו.

המקור blead כבר הגדיל את התקרה#

ללא קשר ל־errata זה, פיתוח perl5 (לאחר 5.42) כבר הגדיל את התקרה. ה־commit ‏8785c114b5 (”parser.h Allow up to 256 characters in a token“), המופיע לראשונה ב־development tag v5.43.4, מחליף את ה־tokenbuf בן 256 הבתים ב־buffer בן 1024 בתים. סדרת היציבה הבאה (Perl 5.44) צפויה לפיכך לאפשר מזהים באורך של עד כ־1020 בתים כברירת מחדל. תקרת 251 הבתים היא מאפיין של 5.42 ומה שלפניה.

סביבת ריצה p5#

סביבת הריצה p5 של PetaPerl היא ה־transpilation דרך c2rust של מפרש C של perl5. ההתנהגות שלה לגבי אורך מזהה היא:

אורך

perl5 5.42.2

pperl --p5

251 בתים

מקבל

מקבל

252 בתים

דוחה

מקבל (סטייה)

1019 בתים

דוחה

מקבל (סטייה)

1020 בתים

דוחה

דוחה

1024 בתים

דוחה

דוחה

הסטייה אמיתית וניתנת לראייה מקוד המשתמש. הסיבה אינה ב־transpilation של c2rust עצמו. פלט c2rust הוא שיקוף נאמן, שורה־לשורה, של מקור ה־C המוזן לו. הסיבה היא drift של ה־upstream-checkout: ‏perl5-upstream/ מוצמד כעת ל־snapshot של blead (לאחר 5.43.4) ולא ל־maintenance tag של 5.42.x. ל־blead יש את ה־tokenbuf המוגדל — שיקוף c2rust יורש אותו.

זוהי דוגמה לקטגוריה רחבה יותר של סטיות סמויות: ל־blead במקור הצטברו מעל 140 commits ל־toke.c בלבד מאז tag 5.42.2, ואותה אריתמטיקה — מה ש־blead עושה הוא מה ש־pperl --p5 עושה — חלה על כל אחד מהם. אזורים נוספים שצפויים להיות מושפעים (גלויים למנתח התחביר בלבד):

  • qr/.../xx משופר ‏(PPC 0026) נוחת ב־blead; הטיפול ברווחים/הערות בתוך character classes שונה מ־5.42.

  • תיקוני באגים ב־intuit_more (commits מרובים): מקרי קצה בפתרון העמימות בין $foo[bar] לבין $foo{bar} מתנהגים טוב יותר ב־pperl --p5 מאשר ב־5.42.

  • שכתוב API של S_parse_ident: מיקום השגיאה המדווח על ידי שגיאות תחביר הקשורות במזהים זז בין 5.42 ו־blead.

הפתרון אינו תיקון פלט c2rust; אלא הצמדת perl5-upstream/ ל־v5.42.2 והרצה מחדש של pipeline ה־transpile.

עד שזה ייעשה, סביבת הריצה p5 היא — במובן המדויק — ”perl5 next“ ולא ”perl5 5.42 stable“. עבור רוב קוד המשתמש זה בלתי נראה; עבור מקרי הקצה לעיל, ההתנהגות תואמת ל־blead, לא ל־5.42.

סביבת ריצה pp#

סביבת הריצה pp ‏(pperl --pp) משתמשת במנתח התחביר המקורי שלה ‏(src/parser/lexer.rs). היא אינה אוכפת כל תקרה — הסורק של מזהים מבצע לולאה על תווי המזהה ללא גבול אורך. שמות באורך שרירותי (10,000 בתים ומעלה) מתקבלים בשקט.

זוהי סטייה מכוונת. סביבת הריצה pp אינה כבולה לתאימות בית־לבית של perl5 המקורי; היכן ש־pp מתנהג טוב יותר מהמקור — ו“ללא תקרה שרירותית של 251 בתים“ הוא בסבירות גבוהה טוב יותר — הפרויקט שומר על השיפור הזה. יש לציין ש־blead במקור עצמו נע באותו כיוון (העלאת ה־buffer מ־256 ל־1024), המעיד שדאגה זו משותפת באופן רחב.

בדיקות#

בדיקות התאימות המכסות errata זה נמצאות ב:

  • t/01-parsing/090-identifier-length-ascii.t

  • t/01-parsing/091-identifier-length-utf8.t

הן בודקות את הגבול ב־251 בתים (ASCII ו־UTF-8 של 2/3/4 בתים) ובחתך משני של upstream-blead סמוך ל־1024 בתים, וכן אורכים רלוונטיים לסביבת ריצה pp עד 10,000 בתים. כל subtest מקודד ציפייה של perl5 5.42; pperl נכשלת כיום בקבוצות חלקיות של הסוויטה כפי שמתואר לעיל. ה־subtests הנכשלים הם רשומת המעקב התפעולית לערך errata זה.