2

Werfen Sie einen Blick auf die folgenden zwei Ausdrücke:Wie unterscheidet Swift Typargumente in Ausdruckskontexten?

baz(Foo<Bar, Bar>(0)) 
baz(Foo < Bar, Bar > (0)) 

Ohne zu wissen, was, baz, Foo und Bar sind (baz ein Typ oder ein Verfahren sein kann, Foo und Bar können Arten oder Variablen sein), gibt es Es gibt keine Möglichkeit zu disambiguieren, ob < eine Typargumentliste oder einen Kleiner-als-Operator darstellt.

// two different outcomes, difference shown with parentheses 
baz((Foo<Bar,Bar>(0)))  // generics 
baz((Foo < Bar), (Bar > 0)) // less-than 

verlassen Jede Sprache sane Programmierung sollte nicht auf, was baz, Foo und Bar werden, wenn diese einen Ausdruck wie das Parsen. Dennoch gelingt es Swift den unten Ausdruck egal eindeutig zu machen, wo ich Leerzeichen setzen:

println(Dictionary<String, String>(0)) 
println(Dictionary < String, String > (0)) 

Wie funktioniert der Compiler diese verwalten? Und, noch wichtiger, gibt es in der Swift-Sprachspezifikation einen Platz. wo die Regeln dafür beschrieben sind. Blick durch den Language Reference Teil des Swift Buchs, fand ich nur diesen Abschnitt:

In bestimmten Konstruktionen, Operatoren mit einem führenden < oder > kann in zwei oder mehr Token aufgeteilt werden. Der Rest wird auf die gleiche Weise behandelt und kann erneut aufgeteilt werden. Daher ist es nicht erforderlich, Leerräume zu verwenden, um zwischen den abschließenden Zeichen in Konstrukten wie Dictionary<String, Array<Int>> zu disambiguieren. In diesem Beispiel werden die abschließenden > Zeichen nicht als ein einzelnes Token behandelt, das dann als Bit-Shift-Operator falsch interpretiert werden kann.

Was bedeutet certain constructs in diesem Zusammenhang? Die eigentliche Grammatik enthält nur eine Produktionsregel, die Typargumente erwähnt:

explizite-Mitglied Ausdruck → Postfix-Ausdruck . identifiergeneric-Argument-Klausel opt

Jede Erklärung oder Ressource wäre sehr geschätzt.

+2

Beachten Sie, dass der Swift-Compiler Open Source ist. Hier finden Sie einen Überblick über die Architektur und Links zum Quellcode: https://swift.org/compiler-stdlib/#compiler-architecture. –

Antwort

4

Dank @Martin R, fand ich den relevanten Teil des Compiler-Quellcodes, der einen Kommentar enthält, der erklärt, wie es die Ambiguität löst.

swift/ParseExpr.cpp, line 1533:

/// The generic-args case is ambiguous with an expression involving '<' 
/// and '>' operators. The operator expression is favored unless a generic 
/// argument list can be successfully parsed, and the closing bracket is 
/// followed by one of these tokens: 
///  lparen_following rparen lsquare_following rsquare lbrace rbrace 
///  period_following comma semicolon 

Grundsätzlich versucht der Compiler eine Liste von Typen zu analysieren, und prüft dann das Token nach dem Schließwinkel.Wenn das Token

  • eine schließende Klammer, Halter oder Orthese,
  • eine öffnende Klammer, Halter oder Periode ohne Leerzeichen zwischen sich und der Schließwinkel (>(, >[, aber nicht > (, > [),
  • eine öffnende Klammer oder
  • ein Komma oder Semikolon

Es analysiert den Ausdruck als Gattungs cal l, sonst analysiert es es als eine oder mehrere relationale Ausdrücke.

Wie in dem Buch Annotated C# beschrieben, wird das Problem in C# in ähnlicher Weise gelöst.

+0

Ihre Antwort hat mir geholfen zu schätzen, wie gut Ihre Frage ist. Ich denke, ich habe in letzter Zeit so viele schlecht formulierte Fragen gesehen, dass ich dir nicht die gebührende Aufmerksamkeit geschenkt habe. +1 für sowohl Q als auch A. Sehr schön in den Parser-Kommentaren gefunden! Das einzige, was ich an dieser Stelle hinzufügen konnte, ist, dass es auch lustig und lehrreich ist, mit dem Compiler direkt von der Kommandozeile aus zu spielen: 'swiftc -dump-parse hello.swift' (oder' -dump-ast', '-dump "Verfeinerungskontexte" usw.). – milos