Vczh Library++3.0的山寨C#的ManagedX今天完成了一个功能,就是编译器检查一个类型在他上下文里面是否可用。这个过程足够复杂,我写了足足3个小时。
ManagedX的符号表里面的类型已经被大大简化了。函数指针是类,基本数字类型也是类,所以归根结底只有
1:子类型
2:类
3:模板类型
因为某些关系,对于类型别名没有直接在符号表里面体现出来。举个例子:
2 class A
3 {
4 generic < inout U >
5 public using S = B < T, U > ;
6 }
7
8 generic < inout T, inout U >
9 class B
10 {
11 public using T = Dictionary < T, U > ;
12 }
下面的类型与符号表中类型结构的展开后关系是:
2 A < int > ->
3 TypeSymbol(A < int > )
4 {
5 GetSymbol() = A
6 GetParentType() = 0
7 GetGenericDeclaration() = TypeSymbol(A)
8 {
9 GetSymbol() = A
10 GetParentType() = 0
11 GetGenericDeclaration() = 0
12 GetGenericArguments() = []
13 }
14 GetGenericArguments() = [ int ]
15 }
16 ================================================
17 A < int > .S < string > ->
18 TypeSymbol(A < int > .S < string > )
19 {
20 GetSymbol() = A.S
21 GetParentType() = 0
22 GetGenericDeclaration() = TypeSymbol(A < int > .S)
23 {
24 GetSymbol() = A.S
25 GetParentType() = TypeSymbol(A < int > )
26 GetGenericDeclaration() = 0
27 GetGenericArguments() = []
28 }
29 GetGenericArguments() = [ string ]
30 }
31 ================================================
32 A < int > .S < string > .T ->
33 TypeSymbol(Dictionary < int , string > )
34 {
35 GetSymbol() = Dictionary
36 GetParentType() = 0
37 GetGenericDeclaration() = TypeSymbol(Dictionary)
38 GetGenericArguments() = [ int , string ]
39 }
40 ================================================
对于展开前的类型结构,A<int>.S<string>.T其实上是指向了GetSymbol()是A<T>.S<U>.T,而ParentType()是A<int>.S<string>的这样一个结构。然后再经过符号表把所有类型别名的目标类型(譬如A.S就是B<T,U>)拿出来,替换掉必要的模板参数,最后获得展开后的类型。
因为有了继承关系、父子类型和类型别名,所以在判断他们的accessor(也就是public、protected、private、internal和protected internal)是否可见的时候,就非常复杂。代码已经上传到Vczh Library++3.0的主页了,下面是核心函数的代码:
2 ManagedLanguageElement * languageElement,
3 ManagedTypeSymbol * type,
4 const MAP & argument,
5 List < ManagedTypeSymbol *>& thisTypes,
6 List < ManagedTypeSymbol *>& baseTypes
7 )
8 {
9 List < ManagedTypeSymbol *> typeLevels;
10 {
11 ManagedTypeSymbol * currentType = type;
12 while (currentType)
13 {
14 typeLevels.Add(currentType);
15 currentType = currentType -> GetGenericDeclaration()
16 ? currentType -> GetGenericDeclaration() -> GetParentType()
17 :currentType -> GetParentType()
18 ;
19 }
20 }
21
22 ManagedTypeSymbol * parentType = 0 ;
23 for (vint i = typeLevels.Count() - 1 ;i >= 0 ;i -- )
24 {
25 ManagedTypeSymbol * currentType = typeLevels[i];
26 ManagedTypeSymbol * currentDeclaration = currentType -> GetGenericDeclaration()
27 ? currentType -> GetGenericDeclaration()
28 :currentType
29 ;
30 if (currentType -> GetGenericDeclaration())
31 {
32 FOREACH(ManagedTypeSymbol * , genericArgument, currentType -> GetGenericArguments())
33 {
34 EnsureTypeVisibility(languageElement, genericArgument, argument, thisTypes, baseTypes);
35 }
36 }
37
38 ManagedSymbolItem * currentSymbol = currentDeclaration -> GetSymbol();
39 declatt::Accessor currentAccessor = declatt::Public;
40 switch (currentSymbol -> GetSymbolType())
41 {
42 case ManagedSymbolItem::Class:
43 case ManagedSymbolItem::Structure:
44 case ManagedSymbolItem::Interface:
45 {
46 ManagedSymbolDeclaration * symbol = dynamic_cast < ManagedSymbolDeclaration *> (currentSymbol);
47 currentAccessor = symbol -> accessor;
48 }
49 break ;
50 case ManagedSymbolItem::TypeRename:
51 {
52 ManagedSymbolTypeRename * symbol = dynamic_cast < ManagedSymbolTypeRename *> (currentSymbol);
53 currentAccessor = symbol -> accessor;
54 }
55 break ;
56 case ManagedSymbolItem::GenericParameter:
57 break ;
58 default :
59 argument.errors.Add(ManagedLanguageCodeException::GetTypeInvisible(languageElement, currentType));
60 return ;
61 }
62
63 if ( ! parentType)
64 {
65 ManagedSymbolItem * parentSymbol = currentSymbol -> GetParentItem();
66 switch (parentSymbol -> GetSymbolType())
67 {
68 case ManagedSymbolItem::Class:
69 case ManagedSymbolItem::Structure:
70 case ManagedSymbolItem::Interface:
71 {
72 ManagedSymbolDeclaration * parentDeclaration = dynamic_cast < ManagedSymbolDeclaration *> (parentSymbol);
73 parentType = argument.symbolManager -> GetThisType(parentDeclaration);
74 }
75 break ;
76 }
77 }
78 if (parentType && ! thisTypes.Contains(parentType))
79 {
80 if (baseTypes.Contains(parentType))
81 {
82 switch (currentAccessor)
83 {
84 case declatt::Public:
85 case declatt::Protected:
86 case declatt::Internal:
87 case declatt::ProtectedInternal:
88 break ;
89 default :
90 argument.errors.Add(ManagedLanguageCodeException::GetTypeInvisible(languageElement, currentType));
91 return ;
92 }
93 }
94 else
95 {
96 switch (currentAccessor)
97 {
98 case declatt::Public:
99 case declatt::Internal:
100 case declatt::ProtectedInternal:
101 break ;
102 default :
103 argument.errors.Add(ManagedLanguageCodeException::GetTypeInvisible(languageElement, currentType));
104 return ;
105 }
106 }
107 }
108
109 if (currentSymbol -> GetSymbolType() == ManagedSymbolItem::TypeRename)
110 {
111 ManagedSymbolTypeRename * symbol = dynamic_cast < ManagedSymbolTypeRename *> (currentSymbol);
112 if (currentType -> GetGenericDeclaration())
113 {
114 Dictionary < ManagedTypeSymbol * , ManagedTypeSymbol *> replacement;
115 for (vint i = 0 ;i < symbol -> orderedGenericParameterNames.Count();i ++ )
116 {
117 ManagedTypeSymbol * key = argument.symbolManager -> GetType(symbol -> ItemGroup(symbol -> orderedGenericParameterNames[i]) -> Items()[ 0 ]);
118 ManagedTypeSymbol * value = currentType -> GetGenericArguments()[i];
119 replacement.Add(key, value);
120 }
121 parentType = argument.symbolManager -> ReplaceGenericArguments(currentType, replacement.Wrap());
122 }
123 else
124 {
125 parentType = symbol -> type;
126 }
127 }
128 else
129 {
130 parentType = currentType;
131 }
132 }
133 }
134
135 void CollectBaseTypes(ManagedTypeSymbol * thisType, List < ManagedTypeSymbol *>& baseTypes, const MAP & argument)
136 {
137 vint oldCount = baseTypes.Count();
138 if (thisType -> GetGenericDeclaration())
139 {
140 ManagedSymbolDeclaration * symbol = dynamic_cast < ManagedSymbolDeclaration *> (thisType -> GetGenericDeclaration() -> GetSymbol());
141
142 Dictionary < ManagedTypeSymbol * , ManagedTypeSymbol *> replacement;
143 for (vint i = 0 ;i < symbol -> orderedGenericParameterNames.Count();i ++ )
144 {
145 ManagedTypeSymbol * key = argument.symbolManager -> GetType(symbol -> ItemGroup(symbol -> orderedGenericParameterNames[i]) -> Items()[ 0 ]);
146 ManagedTypeSymbol * value = thisType -> GetGenericArguments()[i];
147 replacement.Add(key, value);
148 }
149
150 FOREACH(ManagedTypeSymbol * , baseType, symbol -> baseTypes.Wrap())
151 {
152 ManagedTypeSymbol * translatedBaseType = argument.symbolManager -> ReplaceGenericArguments(baseType, replacement.Wrap());
153 if ( ! baseTypes.Contains(translatedBaseType))
154 {
155 baseTypes.Add(translatedBaseType);
156 }
157 }
158 }
159 else
160 {
161 ManagedSymbolDeclaration * symbol = dynamic_cast < ManagedSymbolDeclaration *> (thisType -> GetSymbol());
162 FOREACH(ManagedTypeSymbol * , baseType, symbol -> baseTypes.Wrap())
163 {
164 if ( ! baseTypes.Contains(baseType))
165 {
166 baseTypes.Add(baseType);
167 }
168 }
169 }
170 for (vint i = oldCount;i < baseTypes.Count();i ++ )
171 {
172 CollectBaseTypes(baseTypes[i], baseTypes, argument);
173 }
174 }
175
176 void EnsureTypeVisibility(ManagedLanguageElement * languageElement, ManagedTypeSymbol * type, ManagedSymbolItem * scopeItem, const MAP & argument)
177 {
178 CHECK_ERROR(
179 ! scopeItem
180 || scopeItem -> GetSymbolType() == ManagedSymbolItem::Class
181 || scopeItem -> GetSymbolType() == ManagedSymbolItem::Structure
182 || scopeItem -> GetSymbolType() == ManagedSymbolItem::Interface,
183 L " EnsureTypeVisibility(ManagedLanguageElement*, ManagedTypeSymbol*, ManagedSymbolItem*, const MAP&)#scopeItem内容非法。 "
184 );
185
186 List < ManagedTypeSymbol *> thisTypes, baseTypes;
187 {
188 ManagedSymbolDeclaration * currentDeclaration = dynamic_cast < ManagedSymbolDeclaration *> (scopeItem);
189 while (currentDeclaration)
190 {
191 thisTypes.Add(argument.symbolManager -> GetThisType(currentDeclaration));
192 currentDeclaration = dynamic_cast < ManagedSymbolDeclaration *> (currentDeclaration -> GetParentItem());
193 }
194 }
195 FOREACH(ManagedTypeSymbol * , thisType, thisTypes.Wrap())
196 {
197 CollectBaseTypes(thisType, baseTypes, argument);
198 }
199 EnsureTypeVisibility(languageElement, type, argument, thisTypes, baseTypes);
200 }
主要方法就是,判断A<int>.S<string>.T是否可见有下面两个判断:
1:A<int>.S<string>是否可见
2:A<int>.S<string>扩展后的类型是B<int, string>,判断B<int, string>.T是否可见。
至于为什么这里不需要判断B<int, string>是否可见,是因为在using S=xxx这条声明的语义分析里面已经查过了,如果不可见就会有错误信息产生。因此这里可以当B<int, string>是可见的,减少多余的错误信息。
然后判断A<int>.S<string>是否可见比较简单,主要就是判断A<int>.S和string是否可见。
一直这么递归下去,就把整个类型都检查完了。