[swift-evolution] [Proposal] Refining Identifier and Operator Symbology

Jonathan S. Shapiro jonathan.s.shapiro at gmail.com
Thu Oct 20 19:20:51 CDT 2016


On Thu, Oct 20, 2016 at 4:02 PM, Brent Royal-Gordon via swift-evolution <
swift-evolution at swift.org> wrote:

> > On Oct 20, 2016, at 12:25 PM, Jonathan Hull via swift-evolution <
> swift-evolution at swift.org> wrote:
> >
> > These can be used as identifiers unless they have been defined as an
> operator somewhere within the project, at which point they switch to being
> only usable as operators.
>
> Imagine you're the compiler and you've been handed this source file:
>
>         let party = πŸŽ‰πŸŽ‚
>         prefix operator πŸŽ‰
>
> You're going to see a keyword "let", an identifier "party", an "="
> operator, and then the sequence "πŸŽ‰πŸŽ‚". How will you interpret that
> sequence? There are a few possibilities:
>
> 1. A two-character variable named "πŸŽ‰πŸŽ‚".
> 2. A prefix "πŸŽ‰" operator followed by a one-character variable name "πŸŽ‚".
> 3. A two-character operator "πŸŽ‰πŸŽ‚" with an operand to follow on the next
> line.
> 4. A one-character variable name "πŸŽ‰" followed by a postfix "πŸŽ‚" operator.
>
> The operator declaration on the next line will make all of this clearβ€”but
> we can't understand the next line until we've parsed this line (see #3).
>

Nope. There is no scenario in which any of this is clarified by an operator
declaration, and certainly one that is not in the lexical scope. What would
happen is this:

1. At the LEXICAL level, the sequences πŸŽ‰πŸŽ‚ will be handled according to
the tokenization rules. If emojis are admitted in Swift, they are
definitely in the identifier space, so both of these are "normal"
identifiers.

2. At the parse level, no operator is in scope when you encounter the πŸŽ‰πŸŽ‚,
so it's simply an identifier.

3. At symbol resolution, no binding is found for that identifier, and an
error is raised.

Now let's consider real examples:

let c = a +++ b  /// +++ is a user infix operator


Fails, because +++ is not defined in the lexical scope.

func +++ (a, b) -> int { ...}
...
let c = a +++ b


fails because this tokenizes as LET ident = ident ident ident, which is a
parse error. So how about:

func +++ (a, b) -> int { ...}
...
let c = +++(a, b)


succeeds. Tokenizes as LET ident = ident ( ident, ident), which is a
function call. OK. Now how about;

infix operator +++ : *SomePrecedence*
...
let c = a +++ b


builds a parse tree in which +++ is bound in the lexical contour of
operator symbols, but fails because +++ is *not* bound in the lexical
contour of identifiers. What was needed was

func +++(a, b) -> int { ... }
infix operator +++ : *SomePrecedence*
...
let c = a +++ b


THIS works. Builds an operator expression parse tree because +++ is bound
in the lexical contour of operator reserved words. Identifier resolution
then succeeds because +++ is *also* bound in the lexical contour of
identifiers.


But this would be very strange in Swift, which is otherwise completely
> insensitive to the order of statements in a declaration scope. And it leads
> to a strange two-phase behavior when parsing multiple files: You would need
> to parse each file through the end of its operator declarations before
> parsing any other code in any of the other files.


If I understand the language reference correctly, what you say is true
within a class definition, but not at file or local scope. Normal scopes
follow the normal rules for lexical contours. Member scopes have something
like the behavior you suggest, but the rules there are more complex than
you are describing.


Jonathan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161020/2231157a/attachment.html>


More information about the swift-evolution mailing list