Pegjs: Fehlerberichterstattung neu gestalten

Erstellt am 14. Aug. 2013  ·  7Kommentare  ·  Quelle: pegjs/pegjs

Ich sehe drei Probleme mit dem aktuellen Fehlermeldesystem in PEG.js:

  1. Aktionen melden Fehler, indem sie null zurückgeben
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)).

Siehe auch Nr. 17.

  1. Es gibt keine Möglichkeit, Fehler mit vollständig benutzerdefinierten Nachrichten zu erzeugen
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).

  1. Die Eigenschaft expected von SyntaxError ist mechanisch schwer zu verarbeiten
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).

Jede Erwartung wird durch eine Zeichenfolge dargestellt. Diese Zeichenfolge kann ein erwartetes Literal (dargestellt durch die PEG.js-Syntax – eine Zeichenfolge in Anführungszeichen), eine Zeichenklasse (dargestellt durch die PEG.js-Syntax – [...] ) oder ein beliebiges Zeichen (dargestellt durch die Zeichenfolge "any" ) bedeuten

Ich plane, das Fehlermeldesystem neu zu gestalten, um diese Probleme zu beheben. Bevor ich die Änderungen beschreibe, über die ich nachdenke, ist eine kleine Beschreibung erforderlich, wie das aktuelle System funktioniert.

Wie funktioniert die Fehlerberichterstattung derzeit?

Wenn ein PEG.js-Parser versucht, ein Zeichenfolgenliteral, eine Zeichenklasse oder . abzugleichen, und fehlschlägt, erzeugt er einen _Match-Fehler_. Es besteht aus einer _Position_ und einer _Erwartung_ (Beschreibung dessen, was der Parser zu finden versucht hat).

Nach dem Erzeugen eines Übereinstimmungsfehlers geht der Parser zurück und versucht möglicherweise andere Alternativen. Wenn keiner von ihnen erfolgreich ist und es nichts mehr zu versuchen gibt, löst der Parser die Ausnahme SyntaxError aus. Beim Festlegen seiner Eigenschaften (wie Position, Erwartungen, Fehlermeldung usw.) berücksichtigt der Parser nur den am weitesten entfernten Übereinstimmungsfehler (denjenigen mit der größten Position). Wenn es mehr solcher Fehler gibt, werden ihre Erwartungen kombiniert.

Die Situation ist etwas komplizierter, wenn benannte Regeln verwendet werden, aber dies ist für diese Diskussion irrelevant.

Vorgeschlagenen Änderungen

Ich denke über folgende Änderungen im Fehlermeldesystem nach:

  1. Erwartungen in SyntaxError.expected werden nicht durch Strings repräsentiert, sondern durch Objekte. Die Objekte haben eine Eigenschaft type (mit Werten wie "literal" , "class" , "any" , "eof" ), die den Erwartungstyp bestimmt. Für einige Erwartungstypen enthalten andere Eigenschaften die Details (z. B. für die "literal" -Erwartung wäre eine value -Eigenschaft, die die erwartete Zeichenfolge enthält). Dies vereinfacht die mechanische Verarbeitung der Erwartungen.

Eine Alternative zur Eigenschaft type ist die Verwendung von Klassen. Aber ich denke, die Eigenschaft type wird für Benutzer einfacher zu handhaben sein.

  1. Aktionen dürfen null zurückgeben. Es handelt sich um einen regulären Wert, der keinen Fehler anzeigt.
  2. Aktionen können mithilfe einer neuen error -Funktion einen Übereinstimmungsfehler auslösen. Als Parameter wird eine Fehlermeldung verwendet. Fehler, die von dieser Funktion ausgelöst werden (sogenannte _benutzerdefinierte Übereinstimmungsfehler_), bestehen aus einer _Position_ und einer _Fehlermeldung_. Sie werden keine Erwartungen haben.

Die Funktion error unterbricht die Ausführung der Aktion nicht, sie markiert sie lediglich als fehlgeschlagen und speichert die Fehlermeldung. Der tatsächliche Fehler wird erst nach Abschluss der Aktionsausführung erzeugt. Wenn die Funktion error mehrmals aufgerufen wird, gewinnt der letzte Aufruf (es wird seine Fehlermeldung verwendet).

Fehler bei benutzerdefinierten Übereinstimmungen werden wie normale Übereinstimmungsfehler behandelt, was bedeutet, dass sie das Parsen nicht vollständig anhalten und den Parser zurückverfolgen und möglicherweise andere Alternativen ausprobieren lassen. Es gibt jedoch einen Unterschied: Wenn schließlich die SyntaxError -Ausnahme ausgelöst wird, gilt die Erwartungskombinationsregel, die für reguläre Übereinstimmungsfehler gilt, nicht für die benutzerdefinierten. Wenn es in der Menge der Übereinstimmungsfehler mit der am weitesten entfernten Position mindestens einen benutzerdefinierten gibt, werden die regulären einfach vollständig überschrieben. Wenn es mehr benutzerdefinierte Fehler gibt, gewinnt der zuletzt produzierte.

Eine SyntaxError -Ausnahme, die auf einem benutzerdefinierten Match-Fehler basiert, unterscheidet sich von Ausnahmen, die auf einem regulären Fehler basieren. Die Eigenschaft message entspricht der Fehlermeldung des Fehlers und die Eigenschaft expected ist null .

Beispiel

```
Start = Zeichen:[+-]? Ziffern:[0-9]+ {
var result = parseInt((sign || "") + digits.join(""), 10);

 if (result % 2 == 0) {
   error("The number must be an odd integer.");
 }

 return result;

}
```

Bei der Eingabe 2 erzeugt der aus der obigen Grammatik generierte Parser ein SyntaxError , wobei message auf "The number must be an odd integer." und expected auf null gesetzt ist

  1. Aktionen werden auch in der Lage sein, einen regulären Übereinstimmungsfehler mit der Funktion expected auszulösen. Als Parameter wird eine erwartete Wertbeschreibung verwendet. Diese Funktion wird hauptsächlich als Bequemlichkeit für Situationen bereitgestellt, in denen man keine vollständige Fehlermeldung und das automatisch generierte Formular "Erwartet _X_, aber "2" gefunden" generieren muss. reicht.

Eine SyntaxError -Ausnahme, die auf einem von der expected -Funktion generierten Übereinstimmungsfehler basiert, ähnelt Ausnahmen, die auf einem regulären Fehler basieren.

Beispiel

```
Start = Zeichen:[+-]? Ziffern:[0-9]+ {
var result = parseInt((sign || "") + digits.join(""), 10);

 if (result % 2 == 0) {
   expected("odd integer");
 }

 return result;

}
```

Bei der Eingabe 2 erzeugt der aus der obigen Grammatik generierte Parser ein SyntaxError , wobei message auf "Expected odd integer but "2" found." und expected auf [ { type: "user", description: "odd integer" } ] gesetzt ist

Nächste Schritte

Ich freue mich über alle Anmerkungen zu den vorgeschlagenen Änderungen – bitte fügen Sie sie als Kommentare hinzu. Ich plane, bald mit der Umsetzung des Vorschlags (oder einer modifizierten Version basierend auf Feedback) zu beginnen.

feature

Hilfreichster Kommentar

Es gibt also noch keine „Warn“-Funktion?

Alle 7 Kommentare

Es wäre besser, wenn mehrere Aufrufe der Fehlerfunktion zu mehreren Fehlern führen würden. Sie könnten dann so viel wie möglich mit dem Parsen fortfahren.

string = '"' value:(!(eol / '"') .)+ '"' { return value; }
       / '"' value:(!(eol / '"') .)+     { error('unterminated string constant'); return value; }

Ich würde auch empfehlen, Unterstützung für Warnungen hinzuzufügen.

Es wäre besser, wenn mehrere Aufrufe der Fehlerfunktion zu mehreren Fehlern führen würden. Sie könnten dann so viel wie möglich mit dem Parsen fortfahren.

Können Sie einige Anwendungsfälle nennen, in denen Sie dies benötigen würden? Es scheint mir, dass das von Ihnen angegebene Beispiel auch mit meinem Vorschlag funktionieren würde.

Ich habe bereits einige Anwendungsfälle, aber ich weiß nicht, wie repräsentativ sie sind, also würde ich gerne mehr sehen.

Ich würde auch empfehlen, Unterstützung für Warnungen hinzuzufügen.

Ich denke auch darüber nach.

Ein Problem mit mehreren Fehlern und Warnungen besteht darin, dass sie eine andere Schnittstelle benötigen würden als die einfache und intuitive „ parse gibt bei Erfolg einen Wert oder bei einem Fehler eine Ausnahme zurück“. Der Parser müsste mehrere Fehler bei nicht erfolgreicher Analyse sowie Warnungen sowohl bei erfolgreicher als auch bei nicht erfolgreicher Analyse melden.

Welche Art von API würden Sie hier am intuitivsten finden? Auch hier habe ich einige Ideen, aber ich würde gerne sehen, was andere denken.

Können Sie einige Anwendungsfälle nennen, in denen Sie dies benötigen würden? Es scheint mir, dass das von Ihnen angegebene Beispiel auch mit meinem Vorschlag funktionieren würde.

Mein primärer Anwendungsfall sind nicht schwerwiegende Parsing-Fehler. Nicht abgeschlossene Zeichenfolgen, Bezeichner, die mit einer Zahl beginnen, verschachtelte Kommentare, fehlende Semikolons usw.

Im Allgemeinen ist es am besten, den Parser so weit wie möglich vorrücken zu lassen, damit dem Benutzer so viele Fehler wie möglich angezeigt werden können. Wenn der Parser das Parsen überhaupt beenden könnte und die nächsten Schritte (z. B. Kompilierung) ebenfalls Fehler melden könnten, wäre das großartig.

Dies wird nun umgesetzt . Das Skript tools/impact meldet die folgenden Auswirkungen auf die Leistung des gesamten Satzes von Commits:

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.)

Ich denke, dass 12,62 % Geschwindigkeitseinbußen und 18,11 % Größeneinbußen in Ordnung sind, um eine so lange bestehende Reihe von Problemen zu lösen.

Schließen.

@dmajda : Das sind großartige Neuigkeiten! Ich bin so froh, dass null keinen Fehler mehr signalisiert.

Es gibt also noch keine „Warn“-Funktion?

Das Thema Warnfunktion wird bei #325 verfolgt

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

futagoza picture futagoza  ·  13Kommentare

futagoza picture futagoza  ·  6Kommentare

dmajda picture dmajda  ·  20Kommentare

mikeaustin picture mikeaustin  ·  7Kommentare

richb-hanover picture richb-hanover  ·  7Kommentare