Pegjs: قاعدة "غير متوقعة"

تم إنشاؤها على ٢٣ مارس ٢٠١٩  ·  25تعليقات  ·  مصدر: pegjs/pegjs

  • طلب المواصفات:

أضف قاعدة "غير متوقعة" لتجاوز رسالة الخطأ القياسية.

unexpected = 
      keywords { return "Unexpected keyword "+text()+"."; }
    / expression { return "Unexpected expression «"+text()+"»."; }
    / lamdba_function { return "Unexpected lambda function."; } ;

لتنفيذه فقط قم بتغيير peg $ buildError بواسطة:

  function peg$buildError() {
    var expected = peg$expected[0];
    var failPos = expected.pos;

    // if "unexpected" rule exist this might throw the appropriate error.
    if (typeof peg$parseunexpected !== 'undefined') {
      // make peg$expect temporary unavailable, set the cursor position to the fail position
      // next get the output of the rule, if it's a string, return it.
      const tmp = peg$expect;
      peg$expect = new Function();
      peg$currPos = failPos;
      const unexpected = peg$parseunexpected();
      peg$expect = tmp;
      if (typeof unexpected === 'string') {
        const length = peg$currPos - failPos;
        const location = failPos < input.length
        ? peg$computeLocation(failPos, failPos + length)
        : peg$computeLocation(failPos, failPos);
        return new peg$SyntaxError(unexpected, expected.variants, unexpected, location);
      }
    }
    // else return standard error.
    const unexpected = input.charAt(failPos);
    const location = failPos < input.length
        ? peg$computeLocation(failPos, failPos + 1)
        : peg$computeLocation(failPos, failPos);
    return new peg$SyntaxError(
      peg$SyntaxError.buildMessage(expected.variants, unexpected), expected.variants, unexpected, location);
  }

سلوك متوقع:
تحسين معالجة الأخطاء.

إذا لم يكن الأمر أخلاقيًا ، فهل هناك أي شخص يمكنه إخباري بكيفية إنشاء مكون إضافي من شأنه إجراء التغيير؟
شكرا جزيلا

feature

التعليق الأكثر فائدة

فقط بعض مسابقات الدراجات ، ولكن عند تنفيذ هذه الميزة ، يجب السماح للمستخدم باختيار القاعدة ليتم تعريفها على أنها القاعدة "غير المتوقعة" ، على سبيل المثال مع

pegjs.generate( grammar, { unexpected: "unrecognised_token" } )

ال 25 كومينتر

أوافق على إمكانية إضافة هذه الميزة ، ولكن حتى الآن هناك طريقة للقيام بذلك وهي استخدام الوظيفة error(...) .

على سبيل المثال ، لديك شيء لا يمكن أن يطابق:

  = FirstMatch
  / AnotherMatch

يمكنك إضافة التعبير التالي ، ومطابقة كل حرف للتأكد من عدم إجراء أي تطابق آخر:

  =   .+
  {
    error("Unexpected thing: " + text().substring(0,1));
  }

وبعد ذلك يمكنك تسميته عندما لا يتطابق الشيء الذي يجب أن يتطابق معه.

  = FirstMatch
  / AnotherMatch
  / UnexpectedThing

لا تستطيع قاعدة UnexpectedThing التعامل مع الكلمات الرئيسية أو التعبيرات أو الذرات الأخرى لقواعدك اللغوية ، إنها ترجع فقط حرفًا واحدًا: text().substring(0,1) ، لذا فإن ما تفعله هو بالضبط نفس الشيء الذي ينتجه محلل pegjs. الميزة التي اقترحتها مختلفة تمامًا لأنها تتعامل مع جميع القواعد المحددة داخل قاعدة unexpected في أي نقطة من الإدخال ، بشكل ضمني تمامًا وبطريقة غير مكررة.

فيما يلي مثال على ما سينتج عن الكود أعلاه لمحلل الكتابة المطبوعة الخاص بي:
مدخل:

public function some_func(){
     public function wtf_here_func(){
     }
}

خطأ الإخراج:

السطر X ، العمود 4: متوقع ... ولكن تم العثور على "p".

خطأ الإخراج: (مع ميزة القاعدة غير المتوقعة)

السطر X ، العمود 4: إعلان أسلوب "wtf_here_func" غير متوقع.

الشيء الوحيد الذي أضفته إلى قواعد اللغة الخاصة بي هو:

unexpected = m:method_declaration { return `Unexpected "${m.identifier}" method declaration.` };

لاحظت أن استخدام الدالة error أكثر أناقة من عبارة الإرجاع ، فأنت على حق. لذلك يجب أن يصبح ما سبق:

unexpected = m:method_declaration { error(`Unexpected "${m.identifier}" method declaration.`) };

جربها بنفسك وسترى كل ما يمكن أن تقدمه لمحللينا.

يمكنك دائمًا كتابة UnexpectedThing كما هو مطلوب. في الواقع ، لقد قمت بذلك بالفعل ، فقط قم بتسميته unexpected . لكن في البديل الضمني الخاص بك لا يمكنك الحصول على قواعد مختلفة غير متوقعة لأجزاء مختلفة من القواعد

تضمين التغريدة
ما تقوله هو خطأ ، يمكنك تجاوز "القاعدة غير المتوقعة" الضمنية الخاصة بي عن طريق إضافة "غير متوقع" في القاعدة المعنية ، كما قلت بنفسك.
القاعدة الضمنية ضرورية تمامًا ، وهنا مثال ملموس ، قاعدة التصريح عن الطريقة:

method_declaration = (privacy __)? "function" _ identifier _ '(' _ args _ ')' _ '{' _ instruction* _ '}';

مع الصريح غير المتوقع في النهاية:

method_declaration = (privacy __)? "function" _ identifier _ '(' _ args _ ')' _ '{' _ instruction* _ '}' / UnexpectedThing;

هذا لا يعمل إذا ظهر الشيء غير المتوقع بين "الوظيفة" والمعرف ، أو بين args و ')' إلخ.
لذلك يجب عليك القيام بذلك:

method_declaration = (privacy __)? ("function"/UnexpectedThing) _ identifier _ ('('/UnexpectedThing) _ args _ (')'/UnexpectedThing) _ ('{'/UnexpectedThing) _ instruction* _ ('}'/UnexpectedThing) / UnexpectedThing;

privacy = ... / UnexpectedThing;
_ = ... / UnexpectedThing;
identifier = ... / UnexpectedThing;
instruction = ... / UnexpectedThing;

...

لماذا هذا سيء؟

  • ينمو التعقيد النحوي O (n * 2) بدلاً من O (n)
  • تخلط رسالة الخطأ بين القواعد المتوقعة والقواعد غير المتوقعة ، مثل:

متوقع ... أو UnlimitedThing1 ، UnlimitedThing2 ... ، لكن تم العثور على "x".

هل تفهم حجتي الآن؟
لا يهم إذا كنت تستخدم الكود الخاص بي أم لا ، فنحن بحاجة إلى قاعدة ضمنية لمحللينا.

إذا كنت تريد فقط بدلاً من رمز واحد في الرسالة " متوقع ... ولكن وجدت X لرؤية كلمة متوقعة ... ولكن وجدت XXX ، تصبح أولية ولا تتطلب أي تغييرات. ما عليك سوى التقاط SyntaxError وإعادة تحليل المدخلات من موضع الخطأ باستخدام المحلل اللغوي "lexer" الخاص. يمكنك حتى تعريفه في نفس الملف مثل القواعد الأساسية وإعادة استخدام بعض القواعد. في الكود:

let parser = PEG.generate(<main grammar>);
// For correct work this parser must parse any input and return string as result
let lexer = PEG.generate(<lexer grammar>);
try {
  return parser.parse(<input>);
} catch (e) {
  if (!(e instanceof parser.SyntaxError)) throw e;

  // lexer must return string
  let found = lexer.parse(input.substr(e.location.start.offset));
  // Or you can use specific rule from the same parser
  //let found = parser.parse(input.substr(e.location.start.offset), { startRule: "unexpected" });
  throw new parser.SyntaxError(
    parser.SyntaxError.buildMessage(e.expected, found),
    e.expected,
    found,
    e.location
  );
  // or you can throw you own exception type
}

لتقديم بعض الدعم الخاص في المولد لهذا الغرض ، أرى أنه مفرط على الرغم من أنني لست ضد ذلك كان هناك تعليق توضيحي سيميز القاعدة كنقطة دخول lexer ~ عندما يتم تنفيذ التعليقات التوضيحية.

إنه حل بالتأكيد ، لكن الوصول إليه ضئيل للغاية ويصعب الحفاظ عليه. على أي حال ، شكرًا لك على التعليمات البرمجية الخاصة بك ، من الجيد دائمًا أن تأخذها.

أوافق على أن التنفيذ المباشر لـ lexer في المولد سيكون موضع ترحيب.
ما هي مخاوفك حتى لا يتم تنفيذ التعليقات التوضيحية؟

ما هي مخاوفك حتى لا يتم تنفيذ التعليقات التوضيحية؟

لسوء الحظ ، كما ترى ، فإن المشروع ميت أو ، على الأقل ، في حالة ركود عميق

تعجبني بالفعل فكرة قاعدة unexpected ، لكنني أفكر في وضعها كخيار اختياري عبر الخيار features . هل هذا جيد معك @ log4b0at؟

تضمين التغريدة

@ log4b0at - القاعدة unexpected موجودة بالفعل.

مشكلة وجود قاعدة غير متوقعة تتخصص في طبيعة الشيء الذي فشلت في تحليله هي أنها لا تعرف ما هو ، لأنها فشلت في تحليلها.

ضع في اعتبارك القواعد التالية:

Document = (DadJoke "\n"?)+

Kind = [a-zA-Z0-9 ]+

Car    = "car: "    Kind ".";
Insect = "insect: " Kind ".";
Annoy  = "annoy: "  Kind ".";

DadJoke = Car / Insect / Annoy

(هذه مزحة لأبي لأنه من الواضح أن الإجابة الصحيحة لكل قاعدة هي "خطأ".)

هذا ينبغي دون مشاكل تحليل المدخلات مثل

car: Honda
insect: Beetle
annoy: Whine

هناك طريقتان لقراءة التعامل مع unexpected . إما أن تكون قاعدة الناقل خاطئة وأنك ستتعامل مع ذلك ، أو أن القاعدة المدرجة خاطئة وستتعامل مع ذلك.

كما أفهمها ، فإن ما تطلبه هو قاعدة لـ unexpected تسمح لك بإعطاء مخرجات مختلفة بناءً على ما إذا كان ما هو غير متوقع هو سيارة أو حشرة أو مصدر إزعاج.

لنفترض أن لديك تخصصًا مثل:

const UnexpectedCustoms = { // no, not shoes off
  'annoy'  : 'Unexpected annoyance',
  'insect' : 'Unexpected insect',
  'car'    : 'Unexpected car'
};

إذن ما الذي يجب أن تقدمه كرسالة خطأ عندما أعطيها هذا الإدخال؟

defect: bug
microphone: bug
disease: bug
hobbyist: bug

أي من هؤلاء سيارات؟

ما يجب أن تكون رسائل الخطأ هناك؟

هذا غير قابل للحل. هذه المشكلة تعادل قول "مرحبًا ، نظرًا لأن الشيء التالي لا يمكن تفسيره ، فلماذا لا تخبرني ما هو حتى يمكنني إخبار شخص ما؟"

تحتاج أولاً إلى تعليمه كيفية تفسير ذلك. بعد ذلك لا تحتاج إلى أي شيء.

هذا ، في جوهره ، سبب إعداد بعض الأشياء كرمز رمزي ثم معجم. ما عليك سوى استخدام peg كرمز ، في هذه الحالة ، اكتب lexer الذي يحلل AST المُنشأ ويقول "آه ، أنت ... لا يُسمح لك بالحصول على قوس إغلاق بدون قوس مفتوح "


بالتناوب ، إذا كان الأمر يتعلق بالقاعدة الفرعية ، بدلاً من قاعدة الناقل ، فعندئذٍ يكون لديك إدخال من النموذج بدلاً من ذلك

car: car: car: ...

هل هناك أي طريقة لـ pegjs لمعرفة أن هذه سيارة ، بخلاف كتابة القاعدة التي يمكنك كتابتها بالفعل لمطابقة ذلك ، ثم التعامل معها؟

من السهل جدًا التعامل مع القواعد النحوية اليوم ، والعديد من القواعد النحوية تفعل ذلك. لماذا تريد ميزات إضافية لذلك؟

ما عليك سوى كتابة قاعدة باسم الميزة التي تطلبها. الأسرى: انتهى.

لا حاجة إلى تعقيد إضافي peg.js .


ها هي الطريقة الأخرى لقول ذلك.

لإعطاء رسالة خطأ للتحليل غير الصحيح المحدد ، ستحتاج إلى تحليل صحيح للأشياء غير الصحيحة لتفسيرها. إما أن تكتب محللًا يقبل الأشياء الخاطئة ويرفضها في المعالجات ، أو تكتب محللًا ثانويًا للتعامل مع الجزء الجزئي ، أو تكتب AST الذي يمكنه قبول الشيء الخطأ ثم يفسر AST على أنه خطأ. "


أخيرًا ، لا ينبغي فعل ذلك ، لأن unknown هو الاسم الخامس أو السادس الأكثر شيوعًا للقاعدة ، بعد أشياء مثل document و operator

أضمن أن أكثر من ثلث القواعد النحوية لديها هذا بالفعل ، لأن اللغة قادرة بالفعل على التعبير عنها بدون ميزات

إذا حاولت إضافة هذا ، فكل ما عليك فعله هو كسر القواعد النحوية الحالية لإضافة شيء لدينا بالفعل

يجب رفض هذا

Mingun - أريد إحياء هذا المشروع. ليس هناك سبب وجيه لموتها

أعتقد أن هذه الميزة تهدف إلى جعل الأخطاء أكثر وضوحًا ، حتى لو لم تكن القاعدة unexpected هي الطريقة الصحيحة لتنفيذ هذا النوع من الأشياء.

النقطة المهمة هي أن وجود خطأ Unexpected X يبدو أنه يجعل من العملي اكتشاف أخطاء التحليل (على الأقل في كثير من الحالات) بدلاً من وجود Expected A, B, C, D, E, X, Y or Z أو Expected expression .

سيكون من الرائع رؤية PEG.js قادرة على فعل شيء كهذا.

إذن كيف تحدد ما هو X غير المتوقع؟

ربما تكون هذه هي مشكلة هذه الميزة: القدرة على تحديد الخطأ بوضوح.

لا تكمن المشكلة هنا في محاولة تحديد ما يمكن أن يكون X ، ولكن التأكد من ماهية X.

كما حاولت أن أشرح أعلاه ، هذا يسمى "التحليل" ، وطريقة القيام بذلك هي تحديده في القواعد

لا أفهم جيدًا المشكلة التي تحاول إثارتها ، هل يمكنك أن تعطيني المزيد من الأمثلة عنها؟

ستكون متطابقة حرفيًا مع القائمة الحالية.

حاول الإجابة على السؤال. هناك سقراطيا وخطابيا. يجب أن تعرف ما هي المشكلة في محاولة الإجابة.


ضع في اعتبارك القواعد التالية:

Document = (DadJoke "\n"?)+

Kind = [a-zA-Z0-9 ]+

Car    = "car: "    Kind ".";
Insect = "insect: " Kind ".";
Annoy  = "annoy: "  Kind ".";

DadJoke = Car / Insect / Annoy

إذن ما الذي يجب أن تقدمه كرسالة خطأ عندما أعطيها هذا الإدخال؟

defect: bug
microphone: bug
disease: bug
hobbyist: bug

كما أفهم طلبك ، من المفترض أن يقول المحلل شيئًا مثل "وجدت مرضًا عندما كنت أتوقع سيارة أو حشرة أو مصدر إزعاج."

كيف من المفترض أن تعرف أن هذا مرض؟

فشل التحليل عندما لا يعرف المحلل اللغوي ما هو الشيء التالي.

رسالة خطأ لتحليل الفشل تتطلب معرفة الشيء التالي الذي يتعارض مع الموقف السياقي

defect: bug
microphone: bug
disease: bug
hobbyist: bug

"ما يجب أن تكون رسائل الخطأ هناك؟"

تحصل على ذلك من خلال معالجة الخطأ الفعلي:

السطر 1 ، العمود 1: تم العثور على "إزعاج:" متوقع ، أو "سيارة:" ، أو "حشرة:" ولكن "د".

إذا قمت بتحديد قاعدة غير متوقعة من هذا القبيل

Identifier = [a-zA-Z]+;

unexpected = 
    DadJoke { error("Unexpected dad joke here"); }
/ i:$Identifier { error(`Unexpected identifier "${i}"`); };

سأجلب

السطر 1 ، العمود 1: معرف غير متوقع "عيب"

"بدلاً من ذلك ، إذا كان الأمر يتعلق بالقاعدة الفرعية ، بدلاً من قاعدة شركة النقل ، فبدلاً من ذلك يكون لديك إدخال في النموذج"
car: car: car:

هنا ستحصل على الرسالة الافتراضية ، لأنه لا يوجد تطابق غير متوقع للقاعدة ":" علامة الترقيم

السطر 1 ، العمود 8: متوقع ... blabla ... لكن تم العثور على ":"

علاوة على ذلك ، فإن عملية اكتشاف الأشياء غير المتوقعة تكون سلبية تمامًا وتحدث فقط عندما تكتشف pegjs خطأً ، ولا تضيف أي نفقات إضافية من حيث الأداء.

هل هذا يجيب على سؤالك بشكل صحيح؟

إذا كنت تريد أن تجرب بنفسك ، فقد قمت بسرعة بإنشاء رمز لإصدار 0.10 من pegjs ، واستبدل (في المحلل اللغوي) peg$buildStructuredError بواسطة

function peg$buildStructuredError(expected, found, location) {
    if (typeof peg$parseunexpected !== 'undefined') {
        peg$fail = new Function();
        peg$currPos = location.start.offset;
        peg$parseunexpected();
    }
    return new peg$SyntaxError(peg$SyntaxError.buildMessage(expected, found), expected, found, location);
}

أليس هذا تقريبًا ما قاله مينغون في عام 2019؟

الآن أشعر بالقلق لأنني أسيء فهم شيء ما هنا

استخدام الرمز المميز له تكلفة.
هذه الميزة سهلة التنفيذ ولا تكلف أي شخص

حسنًا ، هذه نقطة عادلة

فقط بعض مسابقات الدراجات ، ولكن عند تنفيذ هذه الميزة ، يجب السماح للمستخدم باختيار القاعدة ليتم تعريفها على أنها القاعدة "غير المتوقعة" ، على سبيل المثال مع

pegjs.generate( grammar, { unexpected: "unrecognised_token" } )

مرحبًا ، لقد تقدمت للتو بطلب سحب لهذه الوظيفة ، باتباع النصائح الخاصة بك ، أي استخدام وظيفة الخطأ ، أكثر اتساقًا من الإرجاع ، الذي اقترحهnorech.
واستخدام خيار لتغيير اسم القاعدة اقترحه @ Seb35
كما قال futagoza ، الميزة اختيارية ويتم تعطيلها افتراضيًا. (لا أعرف عن خيار الميزات ولكن افتراضيًا لا توجد قاعدة غير متوقعة)
انظر # 661 سحب

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات