如
上一篇文章所说,
Vczh Library++3.0的NativeX语言实现了
计划的所有泛型语法。让我们来看一个简单的例子:我们为类型写一个Equals函数。我们可以为普通类型,譬如int32写一个Equals函数。我们有Vector<T>类型,只要T类型拥有一个Equals函数,那么Vector<T>显然也可以有Equals函数。问题来了,我们在VectorEquals<T>函数里面怎么知道T的Equals函数究竟是那一个呢?在这里我们用concept和instance,其实也就是haskell的type class在C语言上仅有的一种形式,来表达。
首先我们定义一个叫Eq的concept,里面包含Equals和NotEquals两个函数的原型。这两个函数规定了参数的类型和返回值类型:
1 concept T : Eq
2 {
3 Equals = function bool(T, T);
4 NotEquals = function bool(T, T);
5 }
其次,我们为int32实现这两个函数。实现的方法很直接,首先我们写IntEquals和IntNotEquals两个函数,其次将int32、Eq和这两个函数绑定起来:
1 instance int32 : Eq
2 {
3 Equals = IntEquals;
4 NotEquals = IntNotEquals;
5 }
6
7 function bool IntEquals(int32 a, int32 b)
8 (result = (a == b));
9
10 function bool IntNotEquals(int32 a, int32 b)
11 (result = (a != b));
因为绑定在Eq上的T的Equals和NotEquals函数的参数是T,因此IntEquals和IntNotEquals的参数必然就是int32了。接下来我们声明一个Vector<T>类型,然后实现这两个函数:
1 generic<U>
2 structure Vector
3 {
4 U X;
5 U Y;
6 }
7
8 generic<V> where
9 V : Eq
10 instance Vector : Eq
11 {
12 Equals = VectorEquals<V>;
13 NotEquals = VectorNotEquals<V>;
14 }
15
16 generic<W> where
17 W : Eq
18 function bool VectorEquals(Vector<W> a, Vector<W> b)
19 {
20 variable bool x_equals = Eq<W>::Equals(a.X, b.X);
21 variable bool y_equals = Eq<W>::Equals(a.Y, b.Y);
22 (result = (x_equals && y_equals));
23 }
24
25 generic<W> where
26 W : Eq
27 function bool VectorNotEquals(Vector<W> a, Vector<W> b)
28 (result = ( ! VectorEquals<W>(a, b)));
我们看得出来这跟普通的函数没什么区别,而且在给Vector<T>绑定Eq的时候,我们还可以规定T必须也存在一个到Eq的绑定。因此我们不仅可以有Vector<int32>,还能有Vector<Vector<int32>>。而且在VectorEquals内部使用Eq<W>::Equals函数的时候,如果函数声明没有where W:Eq的标记那么就无法通过编译。因此所有调用VectorEquals<W>函数的W都需要有一个到Eq的绑定。如此下去,只要你漏绑定了什么,都会得到编译错误的提示。
最后就剩下main函数了:
1 function int32 main1()
2 {
3 variable Vector<int32> v1;
4 variable Vector<int32> v2;
5 (v1.X = 0s32);
6 (v1.Y = 1s32);
7 (v2.X = 2s32);
8 (v2.Y = 3s32);
9 if(Eq<Vector<int32>>::Equals(v1, v2))
10 (result = 1s32);
11 else
12 (result = 0s32);
13 }
我们可以main函数和VectorEquals函数看到一个Equals函数是如何被调用的。当然这个代码编译成二进制代码之后,虚拟机将会在适当的时候搜索、展开并实例化这些具体的函数。我们可以看看编译器在执行完这些代码之后究竟产生了什么数据结构:
1 -----------------------------------------------
2 Loaded Assemblies[0]
3 -----------------------------------------------
4 .data
5 .label
6 .code
7 0: stack_reserve 2
8 1: stack_offset 24
9 2: push s32 0
10 3: add s32
11 4: readmem 4
12 5: stack_offset 16
13 6: push s32 0
14 7: add s32
15 8: readmem 4
16 9: stack_offset -1
17 10: call 46 1
18 11: stack_offset 24
19 12: push s32 4
20 13: add s32
21 14: readmem 4
22 15: stack_offset 16
23 16: push s32 4
24 17: add s32
25 18: readmem 4
26 19: stack_offset -2
27 20: call 46 1
28 21: stack_offset -2
29 22: read u8
30 23: convert u32 u8
31 24: stack_offset -1
32 25: read u8
33 26: convert u32 u8
34 27: and u32
35 28: push u32 0
36 29: ne u32
37 30: resptr
38 31: write u8
39 32: stack_reserve -2
40 33: ret 16
41
42 -----------------------------------------------
43 Loaded Assemblies[1]
44 -----------------------------------------------
45 .data
46 .label
47 0: instruction 3
48 1: instruction 8
49 2: instruction 46
50 3: instruction 56
51 4: instruction 66
52 5: instruction 100
53 .code
54 0: stack_reserve 0
55 1: stack_reserve 0
56 2: ret 0
57 3: stack_reserve 0
58 4: resptr
59 5: call 8 1
60 6: stack_reserve 0
61 7: ret 0
62 8: stack_reserve 16
63 9: push s32 0
64 10: stack_offset -8
65 11: push s32 0
66 12: add s32
67 13: write s32
68 14: push s32 1
69 15: stack_offset -8
70 16: push s32 4
71 17: add s32
72 18: write s32
73 19: push s32 2
74 20: stack_offset -16
75 21: push s32 0
76 22: add s32
77 23: write s32
78 24: push s32 3
79 25: stack_offset -16
80 26: push s32 4
81 27: add s32
82 28: write s32
83 29: stack_reserve 1
84 30: stack_offset -16
85 31: readmem 8
86 32: stack_offset -8
87 33: readmem 8
88 34: stack_top 16
89 35: call 0 0
90 36: jumpfalse 41 1
91 37: push s32 1
92 38: resptr
93 39: write s32
94 40: jump 44 1
95 41: push s32 0
96 42: resptr
97 43: write s32
98 44: stack_reserve -16
99 45: ret 0
100 46: stack_reserve 0
101 47: stack_offset 20
102 48: read s32
103 49: stack_offset 16
104 50: read s32
105 51: eq s32
106 52: resptr
107 53: write u8
108 54: stack_reserve 0
109 55: ret 8
110 56: stack_reserve 0
111 57: stack_offset 20
112 58: read s32
113 59: stack_offset 16
114 60: read s32
115 61: ne s32
116 62: resptr
117 63: write u8
118 64: stack_reserve 0
119 65: ret 8
120 66: stack_reserve 2
121 67: stack_offset 0[Linear]
122 68: push s32 0
123 69: add s32
124 70: readmem 1[Linear]
125 71: stack_offset 16
126 72: push s32 0
127 73: add s32
128 74: readmem 1[Linear]
129 75: stack_offset -1
130 76: generic_instance_callfunc 1
131 77: stack_offset 0[Linear]
132 78: push s32 1[Linear]
133 79: add s32
134 80: readmem 1[Linear]
135 81: stack_offset 16
136 82: push s32 1[Linear]
137 83: add s32
138 84: readmem 1[Linear]
139 85: stack_offset -2
140 86: generic_instance_callfunc 1
141 87: stack_offset -2
142 88: read u8
143 89: convert u32 u8
144 90: stack_offset -1
145 91: read u8
146 92: convert u32 u8
147 93: and u32
148 94: push u32 0
149 95: ne u32
150 96: resptr
151 97: write u8
152 98: stack_reserve -2
153 99: ret 2[Linear]
154 100: stack_reserve 0
155 101: stack_reserve 1
156 102: stack_offset 0[Linear]
157 103: readmem 3[Linear]
158 104: stack_offset 16
159 105: readmem 3[Linear]
160 106: stack_top 2[Linear]
161 107: generic_callfunc 0
162 108: push s8 1
163 109: xor u8
164 110: resptr
165 111: write u8
166 112: stack_reserve 0
167 113: ret 2[Linear]
168 .exports
169 Assembly Name: assembly_generated
170 Exports[0] = (3, main)
171 Exports[1] = (8, main1)
172 Exports[2] = (46, IntEquals)
173 Exports[3] = (56, IntNotEquals)
174 Function Entries[0] = {
175 Name = VectorEquals
176 Arguments = 1
177 Instruction = 66
178 Length = 34
179 UniqueName = [assembly_generated]::[VectorEquals]
180 }
181 Function Entries[1] = {
182 Name = VectorNotEquals
183 Arguments = 1
184 Instruction = 100
185 Length = 14
186 UniqueName = [assembly_generated]::[VectorNotEquals]
187 }
188 Targets[0] = {
189 AssemblyName = assembly_generated
190 SymbolName = VectorEquals
191 Argument[0] = {0} : 1*T0 + 0
192 }
193 Linears[0] = 2*T0 + 16
194 Linears[1] = 1*T0 + 0
195 Linears[2] = 4*T0 + 0
196 Linears[3] = 2*T0 + 0
197 Concepts[0] = {
198 Name = Eq
199 Functions[0] = Equals
200 Functions[1] = NotEquals
201 }
202 Instances[0] = {
203 ConcpetAssemblyName = assembly_generated
204 ConceptSymbolName = Eq
205 TypeUniqueName = s32
206 Arguments = 0
207 Functions[0] = {
208 FunctionName = Equals
209 AssemblyName = assembly_generated
210 SymbolName = IntEquals
211 }
212 Functions[1] = {
213 FunctionName = NotEquals
214 AssemblyName = assembly_generated
215 SymbolName = IntNotEquals
216 }
217 }
218 Instances[1] = {
219 ConcpetAssemblyName = assembly_generated
220 ConceptSymbolName = Eq
221 TypeUniqueName = [assembly_generated]::[Vector]
222 Arguments = 1
223 Functions[0] = {
224 FunctionName = Equals
225 AssemblyName = assembly_generated
226 SymbolName = VectorEquals
227 Argument[0] = {0} : 1*T0 + 0
228 }
229 Functions[1] = {
230 FunctionName = NotEquals
231 AssemblyName = assembly_generated
232 SymbolName = VectorNotEquals
233 Argument[0] = {0} : 1*T0 + 0
234 }
235 }
236 Instance Targets[0] = {
237 AssemblyName = assembly_generated
238 SymbolName = Eq
239 FunctionName = Equals
240 Argument = [assembly_generated]::[Vector] : 8 {
241 s32 : 4
242 }
243 }
244 Instance Targets[1] = {
245 AssemblyName = assembly_generated
246 SymbolName = Eq
247 FunctionName = Equals
248 Argument = {0} : 1*T0 + 0
249 }
250
251 -----------------------------------------------
252 Assembly Name Map
253 -----------------------------------------------
254 assembly_generated = 1
255
256 -----------------------------------------------
257 Function Pointer Map
258 -----------------------------------------------
259 0 = Assemblies[-1].Instructions[-1]
260 1 = Assemblies[1].Instructions[3]
261 2 = Assemblies[1].Instructions[8]
262 3 = Assemblies[1].Instructions[46]
263 4 = Assemblies[1].Instructions[56]
264 5 = Assemblies[1].Instructions[66]
265 6 = Assemblies[1].Instructions[100]
266 7 = Assemblies[0].Instructions[0]
267
268 -----------------------------------------------
269 Loaded Symbol Names
270 -----------------------------------------------
271 assembly_generated.IntEquals
272 assembly_generated.IntNotEquals
273 assembly_generated.main
274 assembly_generated.main1
275
276 -----------------------------------------------
277 Generic Function Entry Map
278 -----------------------------------------------
279 assembly_generated.VectorEquals
280 Instruction = 66
281 Count = 34
282 Assembly = 1
283 Generic Argument Count = 1
284 Unique Entry ID = [assembly_generated]::[VectorEquals]
285 assembly_generated.VectorNotEquals
286 Instruction = 100
287 Count = 14
288 Assembly = 1
289 Generic Argument Count = 1
290 Unique Entry ID = [assembly_generated]::[VectorNotEquals]
291
292 -----------------------------------------------
293 Generic Variable Entry Map
294 -----------------------------------------------
295
296 -----------------------------------------------
297 Instanciated Generic Function Map
298 -----------------------------------------------
299 [assembly_generated]::[VectorEquals]<s32> = 7
300
301 -----------------------------------------------
302 Instanciated Generic Variable Map
303 -----------------------------------------------
304
305 -----------------------------------------------
306 Cached Generic Target List
307 -----------------------------------------------
308 Assembly Name = assembly_generated
309 Symbol Name = VectorEquals
310 Arguments = {
311 Argument[0] = {
312 Name = s32
313 Size = 4
314 }
315 }
316
317 -----------------------------------------------
318 Generic Concept Map
319 -----------------------------------------------
320 assembly_generated.Eq
321
322 -----------------------------------------------
323 Generic Instance Map
324 -----------------------------------------------
325 assembly_generated.Eq<[assembly_generated]::[Vector]>
326 Generic Argument Count = 1
327 Resource Index = 1
328 Function Equals = 0
329 Function NotEquals = 1
330 assembly_generated.Eq<s32>
331 Generic Argument Count = 0
332 Resource Index = 0
333 Function Equals = 0
334 Function NotEquals = 1
335
336
Assembly[0]是专门用来保存模板函数的展开结果的,当然这里面只有一个模板函数被使用了:VectorEquals<int32>。其他的Assembly都是代码编译出来的。
接下来只需要测试一下,然后就可以着手开发最后一个语法了:异常处理。
posted on 2010-08-26 03:09
陈梓瀚(vczh) 阅读(3083)
评论(3) 编辑 收藏 引用 所属分类:
VL++3.0开发纪事