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是否可见。
一直这么递归下去,就把整个类型都检查完了。
posted on 2011-07-16 01:38
陈梓瀚(vczh) 阅读(2835)
评论(1) 编辑 收藏 引用 所属分类:
VL++3.0开发纪事