Vczh Library++3.0的山寨C#的ManagedX今天完成了一個功能,就是編譯器檢查一個類型在他上下文裡面是否可用。這個過程足夠復雜,我寫了足足3個小時。
ManagedX的符號表裡面的類型已經被大大簡化了。函數指針是類,基本數字類型也是類,所以歸根結底只有
1:子類型
2:類
3:模板類型
因為某些關系,對於類型別名沒有直接在符號表裡面體現出來。舉個例子:
1 generic<inout T>
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 }
下面的類型與符號表中類型結構的展開後關系是:
1 ================================================
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的主頁了,下面是核心函數的代碼:
1 void EnsureTypeVisibility(
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是否可見。
一直這麼遞歸下去,就把整個類型都檢查完了。