大概都是要定稿了罷,想了這么久……前人果然是前人啊,C++的concept也好,Haskell的type class也好,C#的generic interface也好,都非常精確地描述出了NativeX的泛型所應(yīng)該有的形式。設(shè)計(jì)語(yǔ)言什么的,還是大部分要抄啊……
接
上一篇文章。昨天晚上
Vczh Library++的泛型結(jié)構(gòu)體以及泛型類(lèi)型重命名已經(jīng)搞定了。這部分先做是因?yàn)榉盒徒Y(jié)構(gòu)體以及泛型類(lèi)型重命名都不需要在鏈接的時(shí)候產(chǎn)生新的指令表,因此完全是編譯器的事情,不需要修改虛擬機(jī)。先來(lái)看看泛型結(jié)構(gòu)體以及泛型類(lèi)型重命名的樣子。這次我仍然在單元測(cè)試用例里面生成了一個(gè)語(yǔ)法樹(shù),然后反編譯成NativeX代碼,然后再一次編譯成語(yǔ)法樹(shù),最后給生成的指令自動(dòng)加注釋?zhuān)?br>
1 /*NativeX Code*/
2 unit nativex_program_generated;
3 generic<T>
4 type Unit = T;
5
6 generic<T>
7 structure Vector
8 {
9 Unit<T> x;
10 Unit<T> y;
11 }
12
13 function Unit<int32> main()
14 {
15 variable Unit<Vector<int32>> v;
16 (v.x=10);
17 (v.y=20);
18 (result=(v.x+v.y));
19 }
20
21
22 /*Assembly*/
23 .data
24 .label
25 0: instruction 3
26 .code
27 // unit nativex_program_generated;
28 0: stack_reserve 0
29 1: stack_reserve 0
30 2: ret 0
31 // function Unit<int32> main()
32 3: stack_reserve 8
33 // (v.x=10);
34 4: push s8 10
35 5: convert s32 s8
36 6: stack_offset -8
37 7: push s32 0
38 8: add s32
39 9: write s32
40 // (v.y=20);
41 10: push s8 20
42 11: convert s32 s8
43 12: stack_offset -8
44 13: push s32 4
45 14: add s32
46 15: write s32
47 // (result=(v.x+v.y));
48 16: stack_offset -8
49 17: push s32 4
50 18: add s32
51 19: read s32
52 20: stack_offset -8
53 21: push s32 0
54 22: add s32
55 23: read s32
56 24: add s32
57 25: resptr
58 26: write s32
59 // function Unit<int32> main()
60 27: stack_reserve -8
61 28: ret 0
62
在這里可以看出實(shí)際上編譯完了之后,指令集里面根本不會(huì)包含有關(guān)反省的任何信息,甚至是原先的類(lèi)型也都丟掉了。當(dāng)然為了解決這個(gè)問(wèn)題,我給Assembly加了“資源”,那是一種通過(guò)C++的技巧封裝之后,你可以不斷地構(gòu)造越來(lái)越大的只讀數(shù)據(jù)結(jié)構(gòu),方便二進(jìn)制形式的序列化和反序列化。所有的信息都存在里面,供以后使用(反正虛擬機(jī)不需要讀)。
但是泛型的全局變量、函數(shù)和契約就不一樣了。泛型全局變量還是很容易做的因此我就忽略掉了。泛型的函數(shù)需要把契約的類(lèi)型完整保留在指令表里面,這樣在特化的時(shí)候才知道哪些地方需要被替換掉??偟膩?lái)說(shuō)最終的設(shè)計(jì)是這個(gè)樣子的:
首先是契約,跟上次差不多,只是命名契約被我刪除了,只剩下匿名契約??偟膩?lái)說(shuō)我只需要在鏈接的時(shí)候進(jìn)行檢查就好了,如果發(fā)現(xiàn)新來(lái)的Assembly重復(fù)實(shí)現(xiàn)了舊Assembly已經(jīng)特化過(guò)的一個(gè)契約,那就會(huì)出現(xiàn)鏈接錯(cuò)誤。至于特化要實(shí)現(xiàn)在哪里,我就不在編譯器上座約束了,因?yàn)檫@個(gè)代價(jià)更大,而且約束了靈活性。
其次是函數(shù)。函數(shù)的泛型頭現(xiàn)在被我修改成了:
1 generic<T>
2 concept Comparable
3 {
4 int Compare(T a, T b);
5 }
6
7 generic<T> with
8 Comparable<T> ct
9 function bool AreEqual(T a, T b)
10 {
11 result = ct::Compare(a, b)==0;
12 }
你會(huì)發(fā)現(xiàn)最終concept變成了對(duì)一個(gè)類(lèi)型或者一組類(lèi)型附加的屬性。泛型的函數(shù)除了這些屬性以外,就只能用一些基本的東西了(當(dāng)然如果你把一個(gè)變量T的地址拿出來(lái),強(qiáng)轉(zhuǎn)……)。這些時(shí)候所有泛型參數(shù)類(lèi)型的參數(shù)、變量和結(jié)構(gòu)體的地址都變成了一個(gè)表達(dá)式,譬如說(shuō)&a == stack_offset+sizeof(int)*4而&b == stack_offset+sizeof(int)*4+sizeof(T)等等。而且如果AreEqual要調(diào)用其它關(guān)于T的泛型函數(shù)的話(huà),如果其他的泛型函數(shù)對(duì)concept的要求比Comparable更多,那么就變成了編譯錯(cuò)誤。當(dāng)然最簡(jiǎn)單的解決辦法就是在AreEqual函數(shù)上把所有用到的concept全部加滿(mǎn)。
當(dāng)然,最后一個(gè)泛型函數(shù)還是可以被編譯成指令表和一組待計(jì)算向量的,只是鏈接的時(shí)候,會(huì)查看新來(lái)的Assembly需要多少還沒(méi)特化的函數(shù),然后一一為他們生成。于是現(xiàn)在最難的問(wèn)題就變成了重構(gòu)已有代碼,以及如何判斷concept instance是否被多個(gè)Assembly重復(fù)特化了……
posted on 2010-06-19 00:07
陳梓瀚(vczh) 閱讀(2426)
評(píng)論(3) 編輯 收藏 引用 所屬分類(lèi):
VL++3.0開(kāi)發(fā)紀(jì)事