5

考虑以下 Swift 表达式

println(Generic<Foo, Bar>(1))

Generic<Foo, Bar>通常,人们会将其解读为对带有参数的构造函数的通用调用(1)

println( Generic<Foo,Bar>(1) )

但是,当稍微重新排列标记时,它也可以表示两个单独的比较,例如 ifGenericFooare 一些命名不佳的数字变量:

println(Generic < Foo, Bar > (1))
// or, with proper parenthesis
println((Generic < Foo), (Bar > 1))

在这里我们可以观察到,具有像这样的通用构造函数的表达式是高度模棱两可的,即使对人类来说也不容易消除歧义。这里的问题是 Swift 没有new构造函数的关键字,这使得它们在某些情况下与方法调用和操作符有歧义。因此,我对 Swift 编译器(解析器)如何设法消除上述表达式的歧义很感兴趣。它的解析方式是依赖于上下文(类型、变量、函数)还是可以由解析器解析?

4

2 回答 2

1

答案很简单:编译器根本不允许你声明这些变量:

struct Generic<T, U> {

    init(_ i: Int) {}
}
struct Foo {}
struct Bar {}

print(Generic<Foo, Bar>(1))

// error
let Foo = 0      // invalid redeclaration of Foo
let Bar = 3      // invalid redeclaration of Bar
let Generic = 5  // invalid redeclaration of Generic
print(Generic<Foo, Bar>(1))

使另一个源文件中的变量或类型声明成为当前声明“覆盖”另一个。

于 2015-07-27T13:34:04.427 回答
0

至少有三种方法可以解决这个问题(可能还有更多)。

  1. 将解析与符号表结合起来。当解析器遇到泛型类型时,会将其添加到符号表中。当解析器随后遇到泛型类型符号时,它会切换到解析泛型参数而不是比较运算符。

  2. 第二个(由 JS++ 使用并在此处描述)是使用 GLR 解析器并解析两个分支。然后在类型分析阶段,选择泛型解析分支。

  3. 任意前瞻匹配Constructor = Symbol "<" GenericParameters ">" "(" CallParameters ")" .(即>(...)始终通用构造函数调用)。

有趣的是,这段代码:

struct A<T, U> {
    init(_ i: Int) {}
}

struct B {}
struct C {}

print(A<B, C>(1))

成功,而这段代码:

struct A<T, U> {
    init(_ i: Int) {}
}

struct B {}
struct C {}

print(A<B, C>1)

给出这个错误:

error: binary operator '<' cannot be applied to operands of type 'A<_, _>.Type' and 'B.Type'
print(A<B, C>1)
      ~^~

这很有趣,因为它表明 Swift 使用了第三个选项:任意前瞻。他们的语法大概是这样的(大大简化了):

Constructor = Symbol "<" GenericParameters ">" "(" CallParameters ")" .
Less = Terminal "<" Terminal .

Expr = Constructor | Less .
于 2020-01-05T05:46:00.143 回答