أرى ثلاث مشكلات في نظام الإبلاغ عن الأخطاء الحالي في PEG.js:
null
Reporting using `null` is inflexible (it doesn't allow to carry any information about the kind of error) and makes it impossible to return `null` as a regular value from actions, which would be useful sometimes (for example [in a JSON parser](https://github.com/dmajda/pegjs/blob/791034fad92c9cd7a9d1c71187df03441bbfd521/examples/json.pegjs#L45)).
انظر أيضا # 17.
For example, imagine a HTTP 1.1 parser that wants to report an error about missing `Host` header in a HTTP request with a message like "A HTTP 1.1 request must contain a Host header". Currently the only way to do this is to throw an exception with desired message manually. This is cumbersome and it does not interact well with the backtracking behavior (throwing an exception halts the parsing completely, even when it is possible to backtrack and try another alternatives).
expected
SyntaxError
يصعب معالجتها ميكانيكيًاThe `expected` property of `SyntaxError` is either an array of expectations (each describing one alternative which the parser expected at the position of error) or `null` (meaning that the end of input was expected).
يتم تمثيل كل توقع بواسطة سلسلة. يمكن أن تعني هذه السلسلة حرفيًا متوقعًا (يتم تمثيله باستخدام بناء جملة PEG.js - سلسلة مقتبسة) ، أو فئة الحرف (يتم تمثيلها باستخدام بناء جملة PEG.js - [...]
) ، أو أي حرف (يمثله سلسلة "any"
). للتمييز بين هذه الحالات ، يتعين على المرء تحليل تمثيلات السلسلة يدويًا ، مما يجعل أدوات البناء القائمة على PEG.js مثل أجهزة الإكمال التلقائي صعبة دون داع.
أخطط لإعادة تصميم نظام الإبلاغ عن الأخطاء لإصلاح هذه المشكلات. قبل أن أصف التغييرات التي أفكر فيها ، هناك حاجة إلى وصف بسيط لكيفية عمل النظام الحالي.
عندما يحاول المحلل اللغوي PEG.js مطابقة سلسلة حرفية ، أو فئة حرف ، أو .
، ويفشل ، ينتج عنه _ فشل تطابق_. ويتكون من _وضع_ وتوقع_ (وصف لما حاول المحلل مطابقته).
بعد إنتاج فشل المباراة ، يتراجع المحلل اللغوي وربما يحاول بدائل أخرى. إذا لم ينجح أي منهم ولم يكن هناك المزيد لتجربته ، فسيقوم المحلل اللغوي برمي الاستثناء SyntaxError
. عند تعيين خصائصه (مثل الموقع ، والتوقعات ، ورسالة الخطأ ، وما إلى ذلك) ، يأخذ المحلل اللغوي في الاعتبار فقط أقصى فشل في التطابق (الذي له الموضع الأكبر). إذا كان هناك المزيد من مثل هذه الإخفاقات ، يتم الجمع بين توقعاتهم.
يكون الموقف أكثر تعقيدًا قليلاً إذا تم استخدام القواعد المسماة ، لكن هذا غير ذي صلة بهذه المناقشة.
أفكر في التغييرات التالية في نظام الإبلاغ عن الأخطاء:
SyntaxError.expected
بالسلاسل ، ولكن من خلال الكائنات. ستحتوي الكائنات على خاصية type
(بقيم مثل "literal"
، "class"
، "any"
، "eof"
) والتي ستحدد نوع التوقع. بالنسبة لبعض أنواع التوقع ، ستحتوي الخصائص الأخرى على التفاصيل (على سبيل المثال ، توقع "literal"
حيث ستكون خاصية value
تحتوي على السلسلة المتوقعة). سيؤدي ذلك إلى تبسيط المعالجة الميكانيكية للتوقعات.بديل لخاصية type
هو استخدام الفئات. لكنني أعتقد أن الخاصية type
ستكون أسهل في التعامل مع المستخدمين.
null
. ستكون قيمة عادية ولن تدل على خطأ.error
جديدة. سوف يستغرق الأمر رسالة خطأ كمعلمة. ستتألف حالات الفشل التي تسببها هذه الوظيفة (تسمى _فشل المطابقة المخصصة_) من _وضع_ و _رسالة خطأ_. لن يكون لديهم أي توقعات.لن تقوم الوظيفة error
بمقاطعة تنفيذ الإجراء ، بل ستقوم فقط بتمييزها على أنها فاشلة وحفظ رسالة الخطأ. لن يتم إنتاج الفشل الفعلي إلا بعد انتهاء تنفيذ الإجراء. إذا تم استدعاء الوظيفة error
عدة مرات ، سيفوز الاستدعاء الأخير (سيتم استخدام رسالة الخطأ الخاصة به).
سيتم التعامل مع حالات فشل المطابقة المخصصة مثل حالات فشل المطابقة العادية ، مما يعني أنها لن توقف التحليل تمامًا وتترك المحلل يتراجع وربما يجرب بدائل أخرى. هناك اختلاف واحد - عند طرح استثناء SyntaxError
أخيرًا ، فإن قاعدة مجموعة التوقعات التي تنطبق على حالات فشل المطابقة العادية لن تنطبق على القواعد المخصصة. إذا كان هناك واحد مخصص واحد على الأقل في مجموعة حالات فشل المطابقة ذات المركز الأبعد ، فسيؤدي ذلك ببساطة إلى تجاوز العناصر العادية تمامًا. إذا كان هناك المزيد من حالات الفشل المخصصة ، فستفوز تلك التي تم إنتاجها أخيرًا.
سيختلف استثناء SyntaxError
المستند إلى فشل المطابقة المخصصة عن الاستثناءات التي تستند إلى الإخفاق المعتاد. الخاصية message
ستكون مساوية لرسالة الخطأ الخاصة بالفشل وخاصيتها expected
ستكون null
.
مثال
""
بدء = تسجيل: [+ -]؟ أرقام: [0-9] + {
var نتيجة = parseInt ((علامة || "") + digits.join ("")، 10) ؛
if (result % 2 == 0) {
error("The number must be an odd integer.");
}
return result;
}
""
عند الإدخال 2
، سينتج المحلل اللغوي الناتج عن القواعد النحوية أعلاه SyntaxError
مع تعيين message
على "The number must be an odd integer."
و expected
تم ضبطه على null
expected
. سوف يستغرق وصف القيمة المتوقعة كمعامل. سيتم توفير هذه الوظيفة بشكل أساسي كوسيلة راحة للحالات التي لا يحتاج فيها المرء إلى إنشاء رسالة خطأ كاملة وإنشاء النموذج تلقائيًا "متوقع _X_ ولكن تم العثور على" 2 "." كفى.سيكون استثناء SyntaxError
المستند إلى فشل المطابقة الذي تم إنشاؤه بواسطة الدالة expected
مماثلاً للاستثناءات التي تستند إلى الفشل المنتظم.
مثال
""
بدء = تسجيل: [+ -]؟ أرقام: [0-9] + {
var نتيجة = parseInt ((علامة || "") + digits.join ("")، 10) ؛
if (result % 2 == 0) {
expected("odd integer");
}
return result;
}
""
عند الإدخال 2
، سينتج المحلل اللغوي الناتج عن القواعد النحوية أعلاه مجموعة SyntaxError
مع تعيين message
على "Expected odd integer but "2" found."
و expected
مضبوطة على [ { type: "user", description: "odd integer" } ]
أرحب بأي ملاحظات على التغييرات المقترحة - يرجى إضافتها كتعليقات. أخطط لبدء تنفيذ الاقتراح (أو بعض النسخ المعدلة بناءً على التعليقات) قريبًا.
سيكون من الأفضل أن تؤدي الاستدعاءات المتعددة لوظيفة الخطأ إلى أخطاء متعددة. يمكنك بعد ذلك الاستمرار في التحليل قدر الإمكان.
string = '"' value:(!(eol / '"') .)+ '"' { return value; }
/ '"' value:(!(eol / '"') .)+ { error('unterminated string constant'); return value; }
أوصي أيضًا بإضافة دعم للتحذيرات أيضًا.
سيكون من الأفضل أن تؤدي الاستدعاءات المتعددة لوظيفة الخطأ إلى أخطاء متعددة. يمكنك بعد ذلك الاستمرار في التحليل قدر الإمكان.
هل يمكنك تسمية بعض حالات الاستخدام التي قد تحتاج إليها؟ يبدو لي أن المثال الذي قدمته سيعمل مع اقتراحي أيضًا.
لدي بالفعل بعض حالات الاستخدام ، لكنني لا أعرف مدى تمثيلها ، لذلك أود رؤية المزيد.
أوصي أيضًا بإضافة دعم للتحذيرات أيضًا.
أنا أيضا أفكر في ذلك.
parse
مشكلة في وجود العديد من الأخطاء والتحذيرات وهي أنهم سيحتاجون إلى واجهة مختلفة عن واجهة بسيطة وبديهية. سيحتاج المحلل اللغوي إلى الإبلاغ عن أخطاء متعددة في التحليل غير الناجح ، بالإضافة إلى التحذيرات المتعلقة بالتحليل الناجح وغير الناجح.
ما نوع واجهة برمجة التطبيقات (API) التي ستجدها أكثر عزيمة هنا؟ مرة أخرى ، لدي بعض الأفكار ، لكني أرغب في رؤية ما يعتقده الآخرون.
هل يمكنك تسمية بعض حالات الاستخدام التي قد تحتاج إليها؟ يبدو لي أن المثال الذي قدمته سيعمل مع اقتراحي أيضًا.
حالة الاستخدام الأساسية الخاصة بي هي لأخطاء التحليل غير الفادحة. سلاسل غير منتهية ، ومعرفات تبدأ برقم ، وتعليقات متداخلة ، وفواصل منقوطة مفقودة ، وما إلى ذلك.
بشكل عام ، من الأفضل السماح للمحلل بالتقدم قدر الإمكان ، بحيث يمكن عرض أكبر عدد ممكن من الأخطاء للمستخدم. إذا تمكن المحلل اللغوي من إنهاء التحليل ، وترك الخطوات التالية (مثل التجميع) تبلغ عن الأخطاء أيضًا ، فسيكون ذلك رائعًا.
يتم تنفيذ هذا الآن. يوضح البرنامج النصي tools/impact
تأثير الأداء التالي لمجموعة الالتزامات بالكامل:
Speed impact
------------
Before: 1144.21 kB/s
After: 999.89 kB/s
Difference: -12.62%
Size impact
-----------
Before: 863523 b
After: 1019968 b
Difference: 18.11%
(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
أعتقد أن 12.62٪ عقوبة سرعة و 18.11٪ حجم عقوبة جيدة لحل مثل هذه المجموعة طويلة الأمد من المشاكل.
إغلاق.
@ dmajda : هذه أخبار رائعة! أنا سعيد جدًا لأن null
لم يعد يشير إلى فشل.
إذن ، لا توجد وظيفة "تحذير" حتى الآن؟
يتم تعقب موضوع وظيفة التحذير في # 325
التعليق الأكثر فائدة
إذن ، لا توجد وظيفة "تحذير" حتى الآن؟