Как Swift устраняет неоднозначность аргументов типа в контексте выражения?

Взгляните на следующие два выражения:

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

Не зная, что такое baz, Foo и Bar (baz может быть типом или методом, Foo и Bar могут быть типами или переменными), невозможно устранить неоднозначность, представляет ли < список аргументов типа или оператор «меньше». .

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

Любой разумный язык программирования не должен полагаться на то, что такое baz, Foo и Bar при разборе такого выражения. Тем не менее, Swift удается устранить неоднозначность приведенного ниже выражения независимо от того, где я размещаю пробелы:

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

Как компилятор справляется с этим? И, что более важно, есть ли место в спецификации языка Swift. где описаны правила для этого. Просматривая Language Reference часть книги Swift, я нашел только этот раздел:

В некоторых конструкциях операторы с ведущими < или > могут быть разделены на две или более лексем. Остаток обрабатывается таким же образом и может быть снова разделен. В результате нет необходимости использовать пробелы для устранения неоднозначности между закрывающими символами > в таких конструкциях, как Dictionary<String, Array<Int>>. В этом примере закрывающие символы > не обрабатываются как одиночный токен, который затем может быть неправильно истолкован как оператор битового сдвига >>.

Что означает certain constructs в этом контексте? Фактическая грамматика содержит только одно производственное правило, в котором упоминаются аргументы типа:

явное-членное-выражение → постфиксное-выражение . идентификаторобщее-аргумент-предложениеopt

Любое объяснение или ресурс будет принят с благодарностью.


person Clashsoft    schedule 03.04.2016    source источник
comment
Обратите внимание, что компилятор Swift имеет открытый исходный код. Вот отправная точка с обзором архитектуры и ссылками на исходный код: swift.org /compiler-stdlib/#compiler-architecture.   -  person Martin R    schedule 03.04.2016


Ответы (1)


Благодаря @Martin R я нашел соответствующую часть исходного кода компилятора, которая содержит комментарий, объясняющий, как он разрешает двусмысленность.

swift/ParseExpr.cpp, строка 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

По сути, компилятор пытается проанализировать список типов, а затем проверяет токен после закрывающей угловой скобки. Если этот токен

  • закрывающая скобка, скобка или фигурная скобка,
  • открывающая скобка, квадратная скобка или точка без пробела между собой и закрывающей угловой скобкой (>(, >[, но не > (, > [),
  • открывающая скобка или
  • запятая или точка с запятой

Он анализирует выражение как общий вызов, в противном случае он анализирует его как одно или несколько реляционных выражений.

Как описано в книге Annotated C#, задача решается аналогичным образом в C#.

person Clashsoft    schedule 03.04.2016
comment
Ваш ответ помог мне оценить, насколько хорош ваш вопрос. Думаю, в последнее время я видел так много плохо сформулированных вопросов, что не уделил вашему должного внимания. +1 и за вопрос, и за ответ. Очень хорошая находка в комментариях парсера! Единственное, что я мог бы добавить на данный момент, это то, что также весело и поучительно играть с компилятором прямо из командной строки: swiftc -dump-parse hello.swift (или -dump-ast, -dump-type-refinement-contexts и т. д.). - person Milos; 04.04.2016