考虑以下Swift表达式
println(Generic<Foo, Bar>(1))
通常情况下,人们会将其视为对构造函数Generic<Foo, Bar>
的通用调用,其参数为(1)
。
println( Generic<Foo,Bar>(1) )
然而,当重新安排令牌时,它也可能代表两个单独的比较,例如,如果Generic
和Foo
是一些命名不佳的数字变量:
println(Generic < Foo, Bar > (1))
// or, with proper parenthesis
println((Generic < Foo), (Bar > 1))
我们在这里可以观察到,具有这样的通用构造函数的表达式非常模糊,即使对于人类也不容易消除歧义。这里的问题是Swift没有构造函数的new
关键字,这使得它们在某些情况下与方法调用和运算符不一致。因此,我感兴趣的是Swift编译器(解析器)如何设法消除上述表达式的歧义。解析依赖于上下文(类型,变量,函数)的方式是否可以解析?
答案 0 :(得分: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))
在另一个源文件中创建变量或类型声明,当前声明“覆盖”另一个。
答案 1 :(得分:0)
至少有三种方法可以解决这个问题(也许还有更多)。
结合使用符号表进行解析。当解析器遇到通用类型时,它将被添加到符号表中。当解析器随后遇到通用类型符号时,它将切换为解析通用参数,而不是比较运算符。
第二个(由JS ++使用并描述了here)是使用GLR解析器并解析两个分支。然后在类型分析阶段,选择通用分析分支。
任意提前匹配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 .