divine 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +122 -0
- data/Rakefile +1 -0
- data/divine.gemspec +22 -0
- data/lib/divine.rb +22 -0
- data/lib/divine/code_generators/code_generator.rb +49 -0
- data/lib/divine/code_generators/java.rb +414 -0
- data/lib/divine/code_generators/javascript.rb +512 -0
- data/lib/divine/code_generators/ruby.rb +360 -0
- data/lib/divine/dsl.rb +153 -0
- data/lib/divine/version.rb +3 -0
- metadata +90 -0
@@ -0,0 +1,512 @@
|
|
1
|
+
# Some notes on Javascript and numbers:
|
2
|
+
# . The bitwise operators and shift operators operate on 32-bit ints.
|
3
|
+
# . Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type (indeed, the integer 0 has two representations, +0 and −0).
|
4
|
+
# . They are 64-bit floating point values, the largest exact integral value is 2^53, or 9007199254740992 (-9007199254740992 to 9007199254740992)
|
5
|
+
|
6
|
+
|
7
|
+
require 'pp'
|
8
|
+
|
9
|
+
module Divine
|
10
|
+
$debug_javascript = false
|
11
|
+
|
12
|
+
class JavascriptHelperMethods < BabelHelperMethods
|
13
|
+
def javascript_base_class_template_str
|
14
|
+
<<EOS
|
15
|
+
// ------------------------------------------------------------ BabelDataReader
|
16
|
+
function BabelDataReader(data) {
|
17
|
+
this.data = data;
|
18
|
+
this.index = 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
BabelDataReader.prototype.getbyte = function () {
|
22
|
+
return this.data[this.index++];
|
23
|
+
};
|
24
|
+
|
25
|
+
BabelDataReader.prototype.read = function (items) {
|
26
|
+
var from = this.index;
|
27
|
+
this.index += items
|
28
|
+
return this.data.subarray(from, this.index)
|
29
|
+
};
|
30
|
+
|
31
|
+
|
32
|
+
// ------------------------------------------------------------ BabelDataWriter
|
33
|
+
function BabelDataWriter(data) {
|
34
|
+
this.data = data;
|
35
|
+
this.index = 0;
|
36
|
+
this.data = new Uint8Array(4096);
|
37
|
+
}
|
38
|
+
|
39
|
+
BabelDataWriter.prototype._realloc = function (size) {
|
40
|
+
size = size || 4096;
|
41
|
+
var old_data = this.data;
|
42
|
+
this.data = new Uint8Array(Math.max(size, 4096) + this.data.length);
|
43
|
+
this.data.set(old_data, 0);
|
44
|
+
};
|
45
|
+
|
46
|
+
BabelDataWriter.prototype.writeByte = function (a_byte) {
|
47
|
+
if (this.index + 1 >= this.data.length) this._realloc();
|
48
|
+
this.data[this.index++] = a_byte;
|
49
|
+
};
|
50
|
+
|
51
|
+
BabelDataWriter.prototype.write = function (bytes) {
|
52
|
+
if (this.index + bytes.length >= this.data.length) this._realloc(bytes.length);
|
53
|
+
this.data.set(bytes, this.index);
|
54
|
+
this.index += bytes.length;
|
55
|
+
};
|
56
|
+
|
57
|
+
BabelDataWriter.prototype.get_data = function () {
|
58
|
+
return this.data.subarray(0, this.index);
|
59
|
+
};
|
60
|
+
|
61
|
+
|
62
|
+
// ------------------------------------------------------------ BabelHelper
|
63
|
+
function BabelHelper() {}
|
64
|
+
|
65
|
+
BabelHelper.prototype.serialize = function () {
|
66
|
+
var out = new BabelDataWriter();
|
67
|
+
this.serialize_internal(out);
|
68
|
+
return out.get_data();
|
69
|
+
}
|
70
|
+
|
71
|
+
BabelHelper.prototype.read_int8 = function (data) {
|
72
|
+
return data.getbyte();
|
73
|
+
};
|
74
|
+
|
75
|
+
BabelHelper.prototype.read_int16 = function (data) {
|
76
|
+
return (data.getbyte() << 8) | this.read_int8(data);
|
77
|
+
};
|
78
|
+
|
79
|
+
BabelHelper.prototype.read_int24 = function (data) {
|
80
|
+
return (data.getbyte() << 16) | this.read_int16(data);
|
81
|
+
};
|
82
|
+
|
83
|
+
BabelHelper.prototype.read_int32 = function (data) {
|
84
|
+
// return (data.getbyte() << 24) | this.read_int24(data); // See notes about numbers above
|
85
|
+
return (data.getbyte() * (256*256*256)) + this.read_int24(data);
|
86
|
+
};
|
87
|
+
|
88
|
+
BabelHelper.prototype.read_binary = function (data) {
|
89
|
+
return data.read(this.read_int32(data));
|
90
|
+
};
|
91
|
+
|
92
|
+
BabelHelper.prototype.read_short_binary = function (data) {
|
93
|
+
return data.read(this.read_int8(data));
|
94
|
+
};
|
95
|
+
|
96
|
+
BabelHelper.prototype.read_ip_number = function (data) {
|
97
|
+
var ip_array = this.read_short_binary(data);
|
98
|
+
ip = "";
|
99
|
+
for (i = 0, len = ip_array.length; i < len; i++) {
|
100
|
+
b = ip_array[i];
|
101
|
+
if (ip.length > 0) {
|
102
|
+
ip += ".";
|
103
|
+
}
|
104
|
+
ip += b.toString();
|
105
|
+
}
|
106
|
+
return ip;
|
107
|
+
};
|
108
|
+
|
109
|
+
BabelHelper.prototype.read_string = function (data) {
|
110
|
+
return this.decode_utf8(data.read(this.read_int16(data)))
|
111
|
+
};
|
112
|
+
|
113
|
+
BabelHelper.prototype.write_int8 = function (v, out) {
|
114
|
+
if (v > 0xFF) // Max 255
|
115
|
+
this.raise_error("Too large int8 number: " + v);
|
116
|
+
out.writeByte(v);
|
117
|
+
}
|
118
|
+
|
119
|
+
BabelHelper.prototype.write_int16 = function (v, out) {
|
120
|
+
if (v > 0xFFFF) // Max 65.535
|
121
|
+
this.raise_error("Too large int16 number: " + v);
|
122
|
+
this.write_int8(v >> 8 & 0xFF, out);
|
123
|
+
this.write_int8(v & 0xFF, out);
|
124
|
+
}
|
125
|
+
|
126
|
+
BabelHelper.prototype.write_int24 = function (v, out) {
|
127
|
+
if (v > 0xFFFFFF) // Max 16.777.215
|
128
|
+
this.raise_error("Too large int24 number: " + v);
|
129
|
+
this.write_int8(v >> 16 & 0xFF, out);
|
130
|
+
this.write_int16(v & 0xFFFF, out);
|
131
|
+
}
|
132
|
+
|
133
|
+
BabelHelper.prototype.write_int32 = function (v, out) {
|
134
|
+
if (v > 0xFFFFFFFF) // Max 4.294.967.295
|
135
|
+
this.raise_error("Too large int32 number: " + v);
|
136
|
+
this.write_int8(v >> 24 & 0xFF, out);
|
137
|
+
this.write_int24(v & 0xFFFFFF, out);
|
138
|
+
}
|
139
|
+
|
140
|
+
BabelHelper.prototype.write_bool = function (v, out) {
|
141
|
+
this.write_int8(v ? 1 : 0, out)
|
142
|
+
}
|
143
|
+
|
144
|
+
BabelHelper.prototype.write_bool = function (v, out) {
|
145
|
+
this.write_int8(v ? 1 : 0, out)
|
146
|
+
}
|
147
|
+
|
148
|
+
BabelHelper.prototype.write_string = function (v, out) {
|
149
|
+
var s = this.encode_utf8(v);
|
150
|
+
if (s.length > 0xFFFF) this.raise_error("Too large string: " + s.length + " bytes");
|
151
|
+
this.write_int16(s.length, out);
|
152
|
+
out.write(s);
|
153
|
+
}
|
154
|
+
|
155
|
+
BabelHelper.prototype.write_binary = function (v, out) {
|
156
|
+
if ((v instanceof Array) || (v instanceof Uint8Array)) {
|
157
|
+
if (v.length > 0xFFFFFFFF) this.raise_error("Too large binary: " + v.length + " (" + v.constructor.name + ")");
|
158
|
+
this.write_int32(v.length, out)
|
159
|
+
out.write(v);
|
160
|
+
} else if (v.constructor == String) {
|
161
|
+
if (v.length > 0xFFFFFFFF) this.raise_error("Too large binary: " + v.length + " (" + v.constructor.name + ")");
|
162
|
+
this.write_int32(v.length, out)
|
163
|
+
out.write(v);
|
164
|
+
} else if (v == null) {
|
165
|
+
this.raise_error("Unsupported binary 'null'");
|
166
|
+
} else {
|
167
|
+
this.raise_error("Unsupported binary of type '" + v.constructor.name + "'");
|
168
|
+
}
|
169
|
+
}
|
170
|
+
|
171
|
+
BabelHelper.prototype.write_short_binary = function (v, out) {
|
172
|
+
if ((v instanceof Array) || (v instanceof Uint8Array)) {
|
173
|
+
if (v.length > 0xFF) this.raise_error("Too large binary: " + v.length + " (" + v.constructor.name + ")");
|
174
|
+
this.write_int8(v.length, out)
|
175
|
+
out.write(v);
|
176
|
+
} else if (v.constructor == String) {
|
177
|
+
if (v.length > 0xFF) this.raise_error("Too large binary: " + v.length + " (" + v.constructor.name + ")");
|
178
|
+
this.write_int8(v.length, out)
|
179
|
+
out.write(v);
|
180
|
+
} else if (v == null) {
|
181
|
+
this.raise_error("Unsupported binary 'null'");
|
182
|
+
} else {
|
183
|
+
this.raise_error("Unsupported binary of type '" + v.constructor.name + "'");
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
BabelHelper.prototype.write_ip_number = function (v, out) {
|
188
|
+
if ((v instanceof Array) || (v instanceof Uint8Array)) {
|
189
|
+
if (v.length != 4 && v.length != 0) this.raise_error("Unknown IP v4 number " + v);
|
190
|
+
this.write_short_binary(v, out)
|
191
|
+
} else if (v.constructor == String) {
|
192
|
+
var ss = [];
|
193
|
+
if (v.length > 0) {
|
194
|
+
ss = v.split(".").map(Number);
|
195
|
+
}
|
196
|
+
this.write_ip_number(ss, out);
|
197
|
+
} else {
|
198
|
+
this.raise_error("Unknown IP number '" + v + "'");
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
BabelHelper.prototype.encode_utf8 = function (str) {
|
203
|
+
var utf8 = [];
|
204
|
+
var chr, next_chr;
|
205
|
+
var x, y, z;
|
206
|
+
for (var i = 0; i < str.length; i++) {
|
207
|
+
chr = str.charCodeAt(i);
|
208
|
+
if ((chr & 0xFF80) == 0) {
|
209
|
+
utf8.push(chr);
|
210
|
+
} else {
|
211
|
+
if ((chr & 0xFC00) == 0xD800) {
|
212
|
+
next_chr = str.charCodeAt(i + 1);
|
213
|
+
if ((next_chr & 0xFC00) == 0xDC00) {
|
214
|
+
// UTF-16 surrogate pair
|
215
|
+
chr = (((chr & 0x03FF) << 10) | (next_chr & 0X3FF)) + 0x10000;
|
216
|
+
i++;
|
217
|
+
} else {
|
218
|
+
this.raise_error("Error decoding surrogate pair: " + chr + ", " + next_chr);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
x = chr & 0xFF;
|
222
|
+
y = chr & 0xFF00;
|
223
|
+
z = chr & 0xFF0000;
|
224
|
+
|
225
|
+
if (chr <= 0x0007FF) {
|
226
|
+
utf8.push(0xC0 | (y >> 6) | (x >> 6));
|
227
|
+
utf8.push(0x80 | (x & 63));
|
228
|
+
} else if (chr <= 0x00FFFF) {
|
229
|
+
utf8.push(0xe0 | (y >> 12));
|
230
|
+
utf8.push(0x80 | ((y >> 6) & 63) | (x >> 6));
|
231
|
+
utf8.push(0x80 | (x & 63));
|
232
|
+
} else if (chr <= 0x10FFFF) {
|
233
|
+
utf8.push(0xF0 | (z >> 18));
|
234
|
+
utf8.push(0x80 | ((z >> 12) & 63) | (y >> 12));
|
235
|
+
utf8.push(0x80 | ((y >> 6) & 63) | (x >> 6));
|
236
|
+
utf8.push(0x80 | (x & 63));
|
237
|
+
} else {
|
238
|
+
this.raise_error("Error encoding to UTF8: " + chr + " is greater than U+10FFFF");
|
239
|
+
}
|
240
|
+
}
|
241
|
+
}
|
242
|
+
return utf8;
|
243
|
+
}
|
244
|
+
|
245
|
+
BabelHelper.prototype.decode_utf8 = function (utf8_data) {
|
246
|
+
var str = "";
|
247
|
+
var chr, b2, b3, b4;
|
248
|
+
for (var i = 0; i < utf8_data.length; i++) {
|
249
|
+
chr = utf8_data[i];
|
250
|
+
if ((chr & 0x80) == 0x00) {}
|
251
|
+
else if ((chr & 0xF8) == 0xF0) {
|
252
|
+
// 4 bytes: U+10000 - U+10FFFF
|
253
|
+
b2 = utf8_data[i + 1];
|
254
|
+
b3 = utf8_data[i + 2];
|
255
|
+
b4 = utf8_data[i + 3];
|
256
|
+
if ((b2 & 0xc0) == 0x80 && (b3 & 0xC0) == 0x80 && (b4 & 0xC0) == 0x80) {
|
257
|
+
chr = (chr & 7) << 18 | (b2 & 63) << 12 | (b3 & 63) << 6 | (b4 & 63);
|
258
|
+
i += 3;
|
259
|
+
} else {
|
260
|
+
this.raise_error("Error decoding from UTF8: " + chr + "," + b2 + "," + b3 + "," + b4);
|
261
|
+
}
|
262
|
+
} else if ((chr & 0xF0) == 0xE0) {
|
263
|
+
// 3 bytes: U+0800 - U+FFFF
|
264
|
+
b2 = utf8_data[i + 1];
|
265
|
+
b3 = utf8_data[i + 2];
|
266
|
+
if ((b2 & 0xC0) == 0x80 && (b3 & 0xC0) == 0x80) {
|
267
|
+
chr = (chr & 15) << 12 | (b2 & 63) << 6 | (b3 & 63);
|
268
|
+
i += 2;
|
269
|
+
} else {
|
270
|
+
this.raise_error("Error decoding from UTF8: " + chr + "," + b2 + "," + b3);
|
271
|
+
}
|
272
|
+
} else if ((chr & 0xE0) == 0xC0) {
|
273
|
+
// 2 bytes: U+0080 - U+07FF
|
274
|
+
b2 = utf8_data[i + 1];
|
275
|
+
if ((b2 & 0xC0) == 0x80) {
|
276
|
+
chr = (chr & 31) << 6 | (b2 & 63);
|
277
|
+
i += 1;
|
278
|
+
} else {
|
279
|
+
this.raise_error("Error decoding from UTF8: " + chr + "," + b2);
|
280
|
+
}
|
281
|
+
} else {
|
282
|
+
// 80-BF: Second, third, or fourth byte of a multi-byte sequence
|
283
|
+
// F5-FF: Start of 4, 5, or 6 byte sequence
|
284
|
+
this.raise_error("Error decoding from UTF8: " + chr + " encountered not in multi-byte sequence");
|
285
|
+
}
|
286
|
+
if (chr <= 0xFFFF) {
|
287
|
+
str += String.fromCharCode(chr);
|
288
|
+
} else if (chr > 0xFFFF && chr <= 0x10FFFF) {
|
289
|
+
// Must be encoded into UTF-16 surrogate pair.
|
290
|
+
chr -= 0x10000;
|
291
|
+
str += (String.fromCharCode(0xD800 | (chr >> 10)) + String.fromCharCode(0xDC00 | (chr & 1023)));
|
292
|
+
} else {
|
293
|
+
this.raise_error("Error encoding surrogate pair: " + chr + " is greater than U+10ffff");
|
294
|
+
}
|
295
|
+
}
|
296
|
+
return str;
|
297
|
+
}
|
298
|
+
|
299
|
+
BabelHelper.prototype.raise_error = function (msg) {
|
300
|
+
throw "[" + this.constructor.name + "] " + msg;
|
301
|
+
}
|
302
|
+
EOS
|
303
|
+
end
|
304
|
+
|
305
|
+
def javascript_class_template_str
|
306
|
+
<<EOS2
|
307
|
+
// ------------------------------------------------------------ <%= c.name %>
|
308
|
+
function <%= c.name %>() {
|
309
|
+
BabelHelper.call(this);
|
310
|
+
<% c.fields.each do |f| %>
|
311
|
+
this.<%= f.name %> = <%= this.javascript_get_empty_declaration(f) %>;
|
312
|
+
<% end %>
|
313
|
+
}
|
314
|
+
|
315
|
+
// Inherit BabelHelper
|
316
|
+
<%= c.name %>.prototype = new BabelHelper();
|
317
|
+
|
318
|
+
// Correct the constructor pointer because it points to BabelHelper
|
319
|
+
<%= c.name %>.prototype.constructor = <%= c.name %>;
|
320
|
+
|
321
|
+
// Define the methods of <%= c.name %>
|
322
|
+
<%= c.name %>.prototype.deserialize = function (data) {
|
323
|
+
<% c.simple_fields.each do |f| %>
|
324
|
+
this.<%= f.name %> = this.read_<%= f.type %>(data);
|
325
|
+
<% end %>
|
326
|
+
<% c.complex_fields.each do |f| %>
|
327
|
+
<%= this.javascript_deserialize_complex f %>
|
328
|
+
<% end %>
|
329
|
+
}
|
330
|
+
|
331
|
+
<%= c.name %>.prototype.serialize_internal = function(out) {
|
332
|
+
<% c.simple_fields.each do |f| %>
|
333
|
+
this.write_<%= f.type %>(this.<%= f.name %>, out);
|
334
|
+
<% end %>
|
335
|
+
<% c.complex_fields.each do |f| %>
|
336
|
+
<%= this.javascript_serialize_complex f %>
|
337
|
+
<% end %>
|
338
|
+
}
|
339
|
+
EOS2
|
340
|
+
end
|
341
|
+
|
342
|
+
def javascript_get_empty_declaration(field)
|
343
|
+
case field.type
|
344
|
+
when :list, :binary, :short_binary
|
345
|
+
"[]"
|
346
|
+
when :map
|
347
|
+
"{}"
|
348
|
+
when :int8, :int16, :int32
|
349
|
+
"0"
|
350
|
+
when :string, :ip_number
|
351
|
+
"\"\""
|
352
|
+
else
|
353
|
+
raise "Unkown field type #{field.type}"
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def javascript_serialize_complex(field)
|
358
|
+
types = field.referenced_types
|
359
|
+
as = [
|
360
|
+
"// Serialize #{field.type} '#{field.name}'",
|
361
|
+
$debug_javascript ? "console.log(\"Serialize '#{field.name}'\");" : nil,
|
362
|
+
javascript_serialize_internal("this.#{field.name}", types)
|
363
|
+
]
|
364
|
+
format_src(4, 4, as)
|
365
|
+
end
|
366
|
+
|
367
|
+
def javascript_serialize_internal(var, types)
|
368
|
+
if types.respond_to? :first
|
369
|
+
case types.first
|
370
|
+
when :list
|
371
|
+
nv = get_fresh_variable_name
|
372
|
+
idx = get_fresh_variable_name
|
373
|
+
return [
|
374
|
+
"this.write_int32(#{var}.length, out);",
|
375
|
+
"for(var #{idx}=0; #{idx}<#{var}.length; #{idx}++) {",
|
376
|
+
:indent,
|
377
|
+
"var #{nv} = #{var}[#{idx}];",
|
378
|
+
javascript_serialize_internal(nv, types[1]),
|
379
|
+
:deindent,
|
380
|
+
"}"
|
381
|
+
]
|
382
|
+
when :map
|
383
|
+
len = get_fresh_variable_name
|
384
|
+
nv1 = get_fresh_variable_name
|
385
|
+
nv2 = get_fresh_variable_name
|
386
|
+
key = get_fresh_variable_name
|
387
|
+
return [
|
388
|
+
"var #{len} = Object.keys(#{var}).length;",
|
389
|
+
"this.write_int32(#{len}, out);",
|
390
|
+
"for(var #{nv1} in #{var}) {",
|
391
|
+
:indent,
|
392
|
+
"var #{nv2} = #{var}[#{nv1}];",
|
393
|
+
javascript_serialize_internal(nv1, types[1]),
|
394
|
+
javascript_serialize_internal(nv2, types[2]),
|
395
|
+
:deindent,
|
396
|
+
"}"
|
397
|
+
]
|
398
|
+
else
|
399
|
+
raise "Missing serialization for #{var}"
|
400
|
+
end
|
401
|
+
else
|
402
|
+
if $all_structs[types]
|
403
|
+
"#{var}.serialize_internal(out)"
|
404
|
+
|
405
|
+
elsif $available_types[types] && $available_types[types].ancestors.include?(SimpleDefinition)
|
406
|
+
"this.write_#{types}(#{var}, out)"
|
407
|
+
|
408
|
+
else
|
409
|
+
raise "Missing code generation case #{types}"
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def javascript_deserialize_complex(field)
|
415
|
+
types = field.referenced_types
|
416
|
+
as = [
|
417
|
+
"// Deserialize #{field.type} '#{field.name}'",
|
418
|
+
$debug_javascript ? "console.log(\"Deserialize '#{field.name}'\");" : nil,
|
419
|
+
javascript_deserialize_internal("this.#{field.name}", types)
|
420
|
+
]
|
421
|
+
format_src(4, 4, as)
|
422
|
+
end
|
423
|
+
|
424
|
+
def javascript_deserialize_internal(var, types)
|
425
|
+
if types.respond_to? :first
|
426
|
+
case types.first
|
427
|
+
when :list
|
428
|
+
count = get_fresh_variable_name
|
429
|
+
nv = get_fresh_variable_name
|
430
|
+
iter = get_fresh_variable_name
|
431
|
+
return [
|
432
|
+
"#{"var " unless var.include? "this."}#{var} = [];",
|
433
|
+
"var #{count} = this.read_int32(data);",
|
434
|
+
"for(var #{iter}=0; #{iter}<#{count}; #{iter}++) {",
|
435
|
+
:indent,
|
436
|
+
javascript_deserialize_internal(nv, types[1]),
|
437
|
+
"#{var}.push(#{nv});",
|
438
|
+
:deindent,
|
439
|
+
"}"
|
440
|
+
]
|
441
|
+
when :map
|
442
|
+
count = get_fresh_variable_name
|
443
|
+
nv1 = get_fresh_variable_name
|
444
|
+
nv2 = get_fresh_variable_name
|
445
|
+
iter = get_fresh_variable_name
|
446
|
+
return ["#{"var " unless var.include? "this."}#{var} = {};",
|
447
|
+
"var #{count} = this.read_int32(data);",
|
448
|
+
"for(var #{iter}=0; #{iter}<#{count}; #{iter}++) {",
|
449
|
+
:indent,
|
450
|
+
javascript_deserialize_internal(nv1, types[1]),
|
451
|
+
javascript_deserialize_internal(nv2, types[2]),
|
452
|
+
"#{var}[#{nv1}] = #{nv2};",
|
453
|
+
:deindent,
|
454
|
+
"}"
|
455
|
+
]
|
456
|
+
else
|
457
|
+
raise "Missing serialization for #{var}"
|
458
|
+
end
|
459
|
+
else
|
460
|
+
case types
|
461
|
+
when :map
|
462
|
+
"#{"var " unless var.include? "this."}#{var} = {}"
|
463
|
+
when :list
|
464
|
+
"#{"var " unless var.include? "this."}#{var} = []"
|
465
|
+
else
|
466
|
+
if $all_structs.key? types
|
467
|
+
[
|
468
|
+
"#{"var " unless var.include? "this."}#{var} = new #{types}();",
|
469
|
+
"#{var}.deserialize(data);"
|
470
|
+
]
|
471
|
+
else
|
472
|
+
"#{"var " unless var.include? "this."}#{var} = this.read_#{types}(data);"
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
|
480
|
+
|
481
|
+
class JavascriptGenerator < JavascriptHelperMethods
|
482
|
+
def generate_code(structs, opts)
|
483
|
+
pp opts
|
484
|
+
$debug_javascript = true if opts[:debug]
|
485
|
+
base_template = Erubis::Eruby.new(javascript_base_class_template_str)
|
486
|
+
class_template = Erubis::Eruby.new(javascript_class_template_str)
|
487
|
+
keys = structs.keys.sort
|
488
|
+
src = keys.map do |k|
|
489
|
+
ss = structs[k]
|
490
|
+
# TODO: Should we merge different versions and deduce deprecated methods, warn for incompatible changes, etc?
|
491
|
+
raise "Duplicate definitions of struct #{k}" if ss.size > 1
|
492
|
+
class_template.result( c: ss.first, this: self )
|
493
|
+
end
|
494
|
+
|
495
|
+
# User defined super class?
|
496
|
+
toplevel = opts[:parent_class] || nil
|
497
|
+
toplevel = " < #{toplevel}" if toplevel
|
498
|
+
return "#{javascript_get_begin_module(opts)}#{base_template.result({ toplevel_class: toplevel })}\n\n#{src.join("\n\n")}#{javascript_get_end_module(opts)}"
|
499
|
+
end
|
500
|
+
|
501
|
+
def javascript_get_begin_module(opts)
|
502
|
+
nil
|
503
|
+
end
|
504
|
+
|
505
|
+
def javascript_get_end_module(opts)
|
506
|
+
nil
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
|
511
|
+
$language_generators[:javascript] = JavascriptGenerator.new
|
512
|
+
end
|