1 /**
2 * Authors: k.inaba
3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4 *
5 * Convert values between Polemy and D
6 */
7 module polemy.valueconv;
8 import polemy._common;
9 import polemy.failure;
10 import polemy.ast;
11 import polemy.layer;
12 import polemy.value;
13 import std.string;
14
15 LexPosition extractPos( Table t )
16 {
17 if(auto tt = t.access!Table(ValueLayer, "pos"))
18 {
19 auto fn = tt.access!StrValue(ValueLayer, "filename");
20 auto ln = tt.access!IntValue(ValueLayer, "lineno");
21 auto cl = tt.access!IntValue(ValueLayer, "column");
22 if(fn !is null && ln !is null && cl !is null)
23 return new LexPosition(fn.data,cast(int)ln.data.toInt,cast(int)cl.data.toInt);
24 }
25 return LexPosition.dummy;
26 }
27
28 /// Experimental!! Convert Polemy value to D Value
29
30 T polemy2d(T)(Value _v, LexPosition callpos=null)
31 {
32 static if(is(T==BigInt))
33 {
34 if(auto v = cast(IntValue)_v)
35 return v.data;
36 }
37 else
38 static if(isIntegral!(T))
39 {
40 if(auto v = cast(IntValue)_v)
41 return cast(T) v.data.toLong();
42 }
43 else
44 static if(is(T==string))
45 {
46 if(auto v = cast(StrValue)_v)
47 return v.data;
48 }
49 else
50 static if(is(T S : S[]))
51 {
52 if(auto t = cast(Table)_v)
53 {
54 S[] result;
55 foreach(e; t.toList())
56 result ~= polemy2d!(S)(e, callpos);
57 return result;
58 }
59 }
60 else
61 static if(is(T == AST))
62 {
63 if(auto t = cast(Table)_v)
64 {
65 LexPosition pos = extractPos(t);
66
67 StrValue typ = cast(StrValue) t.access!StrValue(ValueLayer, "is");
68 if( typ is null )
69 throw genex!RuntimeException(callpos, text(`Invalid AST (no "is" field): `, _v));
70
71 foreach(AT; ListOfASTTypes)
72 if(typ.data == typeid(AT).name.split(".")[$-1])
73 {
74 typeof(AT.tupleof) mems;
75 foreach(i,m; mems)
76 {
77 string name = AT.tupleof[i].stringof.split(".")[$-1];
78 Value vm = t.access!Value(ValueLayer, name);
79 if( vm is null )
80 throw genex!RuntimeException(callpos,
81 text(`Invalid AST (no "`,name,`" field) for "`, typ, `" node: `, _v));
82 mems[i] = polemy2d!(typeof(m))(vm, callpos);
83 }
84 return new AT(pos,mems);
85 }
86 throw genex!RuntimeException(callpos, text(`Invalid AST (unknown "is" field): `, typ));
87 }
88 throw genex!RuntimeException(callpos, text(`Invalid AST (not a table): `, _v));
89 }
90 else
91 static if(is(T == class))
92 {
93 if(auto t = cast(Table)_v)
94 {
95 typeof(T.tupleof) mems;
96 foreach(i,m; mems)
97 mems[i] = polemy2d!(typeof(m))(t.get(T.tupleof[i].stringof.split(".")[$-1], ValueLayer), callpos);
98 return new T(mems);
99 }
100 }
101 else
102 static assert(false, "unknown type <"~T.stringof~"> during polemy2d decoding");
103 throw genex!RuntimeException(callpos, text("Cannot convert ",_v," to ",T.stringof));
104 }
105
106 /// Cons of two pairs
107
108 Table makeCons(Value a, Value d)
109 {
110 Table t = new Table;
111 t.set("car", ValueLayer, a);
112 t.set("cdr", ValueLayer, d);
113 return t;
114 }
115
116 /// Experimental!! Convert D value (except AST) to Polemy Value
117
118 Value d2polemy(T)(T e)
119 {
120 return ast2table(e, delegate Value(AST){ assert(false); });
121 }
122
123 /// Convert AST to Table so that it can be used in Polemy
124
125 Value ast2table(T)(T e, Value delegate(AST) rec)
126 {
127 static if(is(T==BigInt) || isIntegral!(T))
128 return new IntValue(e);
129 else
130 static if(is(Unqual!(T)==string))
131 return new StrValue(e);
132 else
133 static if(is(T S : S[]))
134 {
135 Table lst = new Table;
136 foreach_reverse(a; e)
137 static if(is(S : AST))
138 lst = makeCons(rec(a), lst);
139 else
140 lst = makeCons(ast2table(a,rec), lst);
141 return lst;
142 }
143 else
144 static if(is(T : AST))
145 {
146 assert( typeid(e) == typeid(T), text("abstracted: ", typeid(e), " vs ", typeid(T)) );
147 auto t = new Table;
148 if(e.pos is null) // special treatment
149 {
150 Table post = new Table;
151 post.set("filename", ValueLayer, new StrValue("nullpo"));
152 post.set("lineno", ValueLayer, new IntValue(0));
153 post.set("column", ValueLayer, new IntValue(0));
154 t.set("pos", ValueLayer, post);
155 }
156 else
157 t.set("pos", ValueLayer, ast2table(e.pos,rec));
158 t.set("is" , ValueLayer, new StrValue(typeid(e).name.split(".")[$-1]));
159 foreach(i,m; e.tupleof)
160 static if(is(typeof(m) : AST))
161 t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, rec(m));
162 else
163 t.set(e.tupleof[i].stringof.split(".")[$-1], ValueLayer, ast2table(m,rec));
164 return t;
165 }
166 else
167 static if(is(T == class))
168 {
169 auto t = new Table;
170 foreach(i,m; e.tupleof)
171 static if(is(typeof(m) : AST))
172 t.set(e.tupleof[i].stringof[2..$], ValueLayer, rec(m));
173 else
174 t.set(e.tupleof[i].stringof[2..$], ValueLayer, ast2table(m,rec));
175 return t;
176 }
177 else
178 static assert(false, "unknown type <"~T.stringof~"> during AST encoding");
179 }