fix valgrind issues during ast serialization
[scilab.git] / scilab / modules / ast / includes / ast / serializervisitor.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2012-2013 - OCAMLPRO INRIA - Fabrice LE FESSANT
4  *  Copyright (C) 2014 - Scilab Enterprises - Antoine ELIAS
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 #ifndef __SERIALIZER_HXX__
15 #define __SERIALIZER_HXX__
16
17 #include "dummyvisitor.hxx"
18 #include "deserializervisitor.hxx"
19 #include "timer.hxx"
20 #include "version.h"
21
22 #define FAGMENT_SIZE 65536
23
24 namespace ast
25 {
26 class SerializeVisitor : public DummyVisitor
27 {
28 private :
29     ast::Exp* ast;
30     unsigned char *buf;
31     int buflen;
32     int bufsize;
33     bool saveNodeNumber;
34
35     unsigned char* get_buf(void)
36     {
37         // set buffer size
38         set_uint32(0, buflen);
39         // set scilab version
40         set_version();
41         return buf;
42     }
43
44     /** @{ Set the file header without modifying the file size. */
45
46     void set_version()
47     {
48         set_byte(4, (unsigned char)SCI_VERSION_MAJOR);
49         set_byte(5, (unsigned char)SCI_VERSION_MINOR);
50         set_byte(6, (unsigned char)SCI_VERSION_MAINTENANCE);
51         set_byte(7, (unsigned char)0);
52     }
53
54     void set_uint32(unsigned int pos, unsigned int n)
55     {
56         buf[pos++] = (n & 0xff);
57         n >>= 8;
58         buf[pos++] = (n & 0xff);
59         n >>= 8;
60         buf[pos++] = (n & 0xff);
61         n >>= 8;
62         buf[pos++] = (n & 0xff);
63     }
64
65     void set_byte(unsigned int pos, unsigned char n)
66     {
67         buf[pos] = n;
68     }
69
70     /** @} */
71
72     void add_location(const Location& loc)
73     {
74         add_uint32(loc.first_line);
75         add_uint32(loc.first_column);
76         add_uint32(loc.last_line);
77         add_uint32(loc.last_column);
78     }
79     void add_ast(unsigned int code, const ast::Exp& e)
80     {
81         add_uint8(code);
82         if (saveNodeNumber)
83         {
84             add_uint64(e.nodeNumber_get());
85         }
86         else
87         {
88             add_uint64((unsigned long long)0);
89         }
90         add_location(e.location_get());
91         add_uint8(e.is_verbose());
92         add_uint8(e.is_break());
93         add_uint8(e.is_breakable());
94         add_uint8(e.is_return());
95         add_uint8(e.is_returnable());
96         add_uint8(e.is_continue());
97         add_uint8(e.is_continuable());
98     }
99
100     /** @{ Low-level append to the buffer functions */
101
102     /* ensure that we have [size] bytes in the buffer */
103     void need(int size)
104     {
105         if ( bufsize - buflen < size )
106         {
107             bufsize = 2 * bufsize + size + FAGMENT_SIZE;
108             unsigned char *newbuf = (unsigned char*) malloc(bufsize * sizeof(unsigned char));
109             // std::cerr << "malloc " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
110             if ( buflen > 0 )
111             {
112                 // std::cerr << "memcpy " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
113                 memcpy(newbuf, buf, buflen);
114             }
115             if ( buf != NULL)
116             {
117                 // std::cerr << "free " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
118                 free(buf);
119             }
120             else
121             {
122                 buflen = 8;    /* Header length. Header =  final size of buf ( 4 bytes ) + scilab version ( 4 bytes )*/
123             }
124             buf = newbuf;
125         }
126
127         // std::cerr << "need " << size << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
128     }
129
130     void add_byte(unsigned char n)
131     {
132         buf[buflen++] = n;
133     }
134
135     void add_uint8(unsigned char n)
136     {
137         need(1);
138         add_byte(n);
139     }
140
141     void add_uint32(unsigned int n)
142     {
143         need(4);
144         add_byte(n & 0xff);
145         add_byte((n >>= 8) & 0xff);
146         add_byte((n >>= 8) & 0xff);
147         add_byte((n >>= 8) & 0xff);
148     }
149
150     void add_uint64(unsigned long long n)
151     {
152         need(8);
153         add_byte(n & 0xff);
154         add_byte((n >>= 8) & 0xff);
155         add_byte((n >>= 8) & 0xff);
156         add_byte((n >>= 8) & 0xff);
157         add_byte((n >>= 8) & 0xff);
158         add_byte((n >>= 8) & 0xff);
159         add_byte((n >>= 8) & 0xff);
160         add_byte((n >>= 8) & 0xff);
161     }
162
163     void add_double(double d)
164     {
165         need(8);
166         *(double*)(buf + buflen) = d;
167         buflen += 8;
168     }
169
170     void add_wstring(const std::wstring &w)
171     {
172         int size = (int)w.size();
173         const wchar_t *c_str = w.c_str();
174         int final_size = size * sizeof(wchar_t);
175         add_uint32(final_size);
176         need(final_size);
177         memcpy(buf + buflen, c_str, final_size);
178         buflen += final_size;
179     }
180
181     /** @} */
182
183     void add_exps(const std::list<Exp *> exps)
184     {
185         add_uint32((unsigned int)exps.size());
186         std::list<Exp *>::const_iterator it;
187         for (it = exps.begin() ; it != exps.end() ; it++)
188         {
189             (*it)->accept(*this);
190         }
191     }
192
193     void add_vars(const ast::ArrayListVar& var)
194     {
195         add_uint32((unsigned int)var.vars_get().size());
196         std::list<Var *>::const_iterator it;
197         for (it = var.vars_get().begin() ; it != var.vars_get().end() ; it++)
198         {
199             (*it)->accept(*this);
200         }
201     }
202
203     void add_Symbol(const symbol::Symbol& e)
204     {
205         add_wstring(e.name_get());
206     }
207
208     void add_exp(const ast::Exp* e)
209     {
210         e->accept(*this);
211     }
212
213     void add_exp(const ast::Exp& e)
214     {
215         e.accept(*this);
216     }
217
218     void add_OpExp_Oper(const ast::OpExp::Oper oper)
219     {
220         int code = 253;
221         switch (oper)
222         {
223             case ast::OpExp::plus :
224                 code = (1);
225                 break;
226             case ast::OpExp::minus:
227                 code = (2);
228                 break;
229             case ast::OpExp::times:
230                 code = (3);
231                 break;
232             case ast::OpExp::rdivide:
233                 code = (4);
234                 break;
235             case ast::OpExp::ldivide:
236                 code = (5);
237                 break;
238             case ast::OpExp::power:
239                 code = (6);
240                 break;
241
242             case ast::OpExp::dottimes:
243                 code = (7);
244                 break;
245             case ast::OpExp::dotrdivide:
246                 code = (8);
247                 break;
248             case ast::OpExp::dotldivide:
249                 code = (9);
250                 break;
251             case ast::OpExp::dotpower:
252                 code = (10);
253                 break;
254
255             case ast::OpExp::krontimes:
256                 code = (11);
257                 break;
258             case ast::OpExp::kronrdivide:
259                 code = (12);
260                 break;
261             case ast::OpExp::kronldivide:
262                 code = (13);
263                 break;
264
265             case ast::OpExp::controltimes:
266                 code = (14);
267                 break;
268             case ast::OpExp::controlrdivide:
269                 code = (15);
270                 break;
271             case ast::OpExp::controlldivide:
272                 code = (16);
273                 break;
274
275             case ast::OpExp::eq:
276                 code = (17);
277                 break;
278             case ast::OpExp::ne:
279                 code = (18);
280                 break;
281             case ast::OpExp::lt:
282                 code = (19);
283                 break;
284             case ast::OpExp::le:
285                 code = (20);
286                 break;
287             case ast::OpExp::gt:
288                 code = (21);
289                 break;
290             case ast::OpExp::ge:
291                 code = (22);
292                 break;
293
294             case ast::OpExp::unaryMinus:
295                 code = (23);
296                 break;
297
298             case ast::OpExp::logicalAnd:
299                 code = (24);
300                 break;
301             case ast::OpExp::logicalOr:
302                 code = (25);
303                 break;
304             case ast::OpExp::logicalShortCutAnd:
305                 code = (26);
306                 break;
307             case ast::OpExp::logicalShortCutOr:
308                 code = (27);
309                 break;
310         }
311         add_uint8(code);
312     }
313
314     void add_IntExp_Prec(const ast::IntExp::Prec prec)
315     {
316         int code = 251;
317         switch (prec)
318         {
319             case ast::IntExp::_8_ :
320                 code = (1);
321                 break;
322             case ast::IntExp::_16_:
323                 code = (2);
324                 break;
325             case ast::IntExp::_32_:
326                 code = (3);
327                 break;
328             case ast::IntExp::_64_:
329                 code = (4);
330                 break;
331         }
332         add_uint8(code);
333     }
334
335     void add_TransposeExp_Kind(const ast::TransposeExp::Kind kind)
336     {
337         int code = 249;
338         switch (kind)
339         {
340             case ast::TransposeExp::_Conjugate_ :
341                 code = (1);
342                 break;
343             case ast::TransposeExp::_NonConjugate_:
344                 code = (2);
345                 break;
346         }
347         add_uint8(code);
348     }
349
350     void add_bool(bool b)
351     {
352         add_uint8(b);
353     }
354
355     void add_varDec(const ast::VarDec& varDec)
356     {
357         add_Symbol(varDec.name_get());
358         add_exp(varDec.init_get());
359     }
360
361     void add_MatrixLines(const  std::list<ast::MatrixLineExp*> *lines)
362     {
363         add_uint32((unsigned int)lines->size());
364         std::list<MatrixLineExp *>::const_iterator it;
365         for (it = lines->begin() ; it != lines->end() ; it++)
366         {
367             add_location((*it)->location_get());
368             add_exps((*it)->columns_get());
369         }
370     }
371
372     virtual void visit (const SeqExp &e)  /* done */
373     {
374         add_ast(1, e);
375         add_exps(e.exps_get());
376     }
377     void visit(const StringExp& e)  /* done */
378     {
379         add_ast(2, e);
380         add_wstring(e.value_get());
381     }
382     void visit(const CommentExp& e)  /* done */
383     {
384         add_ast(3, e);
385         add_wstring(e.comment_get());
386     }
387     void visit(const DoubleExp& e)  /* done */
388     {
389         add_ast(6, e);
390         add_double(e.value_get());
391     }
392     void visit(const BoolExp& e)  /* done */
393     {
394         add_ast(7, e);
395         add_bool(e.value_get());
396     }
397     void visit(const NilExp& e)  /* done */
398     {
399         add_ast(8, e);
400     }
401     void visit(const SimpleVar& e)  /* done */
402     {
403         add_ast(9, e);
404         add_Symbol(e.name_get());
405     }
406     void visit(const ColonVar& e)  /* done */
407     {
408         add_ast(10, e);
409     }
410     void visit(const DollarVar& e)  /* done */
411     {
412         add_ast(11, e);
413     }
414     void visit(const ArrayListVar& e)  /* done */
415     {
416         add_ast(12, e);
417         add_vars(e);
418     }
419     void visit(const FieldExp& e)  /* done */
420     {
421         add_ast(13, e);
422         add_exp(e.head_get());
423         add_exp(e.tail_get());
424     }
425     void visit(const IfExp& e)  /* done */
426     {
427         add_ast(14, e);
428         bool has_else = e.has_else();
429         add_bool(has_else);
430         add_exp(& e.test_get());
431         add_exp(& e.then_get());
432         if ( has_else )
433         {
434             add_exp(& e.else_get());
435         }
436     }
437     void visit(const TryCatchExp& e)  /* done */
438     {
439         add_ast(15, e);
440         add_location(e.try_get().location_get());
441         add_location(e.catch_get().location_get());
442         add_exps(e.try_get().exps_get());
443         add_exps(e.catch_get().exps_get());
444     }
445     void visit(const WhileExp& e)  /* done */
446     {
447         add_ast(16, e);
448         add_exp(& e.test_get());
449         add_exp(& e.body_get());
450     }
451     void visit(const ForExp& e)   /* done */
452     {
453         add_ast(17, e);
454         add_location(e.vardec_get().location_get());
455         add_varDec(e.vardec_get());
456         add_exp(& e.body_get());
457     }
458     void visit(const BreakExp& e)  /* done */
459     {
460         add_ast(18, e);
461     }
462     void visit(const ContinueExp& e)  /* done */
463     {
464         add_ast(19, e);
465     }
466     void visit(const ReturnExp& e)  /* done */
467     {
468         add_ast(20, e);
469         bool is_global = e.is_global();
470         add_bool(is_global);
471         if ( !is_global ) /* otherwise exp is NULL */
472         {
473             add_exp(& e.exp_get());
474         }
475     }
476     void visit(const SelectExp& e)
477     {
478         add_ast(21, e);
479         ast::SeqExp *default_case = e.default_case_get();
480         bool has_default = default_case != NULL;
481         add_bool( has_default );
482         if ( has_default )
483         {
484             add_location(default_case->location_get());
485             add_exps(default_case->exps_get());
486         }
487         add_exp(e.select_get());
488
489         add_uint32((unsigned int)e.cases_get()->size());
490         cases_t::const_iterator it;
491         for (it = e.cases_get()->begin() ; it != e.cases_get()->end() ; it++)
492         {
493             const ast::CaseExp *ce = *it;
494             add_location(ce->location_get() );
495             add_location(ce->body_get()->location_get() );
496             add_exp(ce->test_get());
497             add_exps(ce->body_get()->exps_get() );
498         }
499     }
500     void visit(const CellExp& e)  /* done */
501     {
502         add_ast(23, e);
503         add_MatrixLines(& e.lines_get());
504     }
505     void visit(const ArrayListExp& e)  /* done */
506     {
507         add_ast(24, e);
508         add_exps(e.exps_get());
509     }
510     void visit(const AssignListExp& e)  /* done */
511     {
512         add_ast(25, e);
513         add_exps(e.exps_get());
514     }
515     void visit(const NotExp& e)  /* done */
516     {
517         add_ast(26, e);
518         add_exp(e.exp_get() );
519     }
520     void visit(const TransposeExp& e)  /* done */
521     {
522         add_ast(27, e);
523         add_TransposeExp_Kind(e.conjugate_get());
524         add_exp(e.exp_get());
525     }
526     void visit(const VarDec& e)
527     {
528         add_ast(28, e);
529         add_varDec(e);
530     }
531     void visit(const FunctionDec& e)  /* done */
532     {
533         add_ast(29, e);
534         add_Symbol(e.name_get());
535         add_location(e.args_get().location_get());
536         add_location(e.returns_get().location_get());
537         add_exp(e.body_get());
538         add_vars(e.args_get());
539         add_vars(e.returns_get());
540     }
541     void visit(const ListExp& e)  /* done */
542     {
543         add_ast(30, e);
544         add_exp(e.start_get() );
545         add_exp(e.step_get() );
546         add_exp(e.end_get() );
547     }
548     void visit(const AssignExp& e)
549     {
550         add_ast(31, e);
551         add_exp(e.left_exp_get());
552         add_exp(e.right_exp_get());
553     }
554     void visit(const OpExp& e)  /* done */
555     {
556         add_ast(32, e);
557         add_OpExp_Oper(e.oper_get());
558         e.left_get().accept(*this);
559         e.right_get().accept(*this);
560     }
561     void visit(const LogicalOpExp& e)  /* done */
562     {
563         add_ast(33, e);
564         add_OpExp_Oper(e.oper_get());
565         e.left_get().accept(*this);
566         e.right_get().accept(*this);
567     }
568     void visit(const MatrixExp& e) /* done */
569     {
570         add_ast(34, e);
571         add_MatrixLines(& e.lines_get());
572     }
573     void visit(const CallExp& e)  /* done */
574     {
575         add_ast(35, e);
576         add_exp( e.name_get());
577         add_exps(e.args_get());
578     }
579     void visit(const MatrixLineExp& e)  /* SHOULD NEVER HAPPEN */
580     {
581         add_ast(36, e);
582     }
583     void visit(const CellCallExp& e)  /* done */
584     {
585         add_ast(37, e);
586         add_exp( e.name_get());
587         add_exps(e.args_get());
588     }
589
590 public :
591     SerializeVisitor(ast::Exp* _ast) : ast(_ast), buf(NULL), buflen(0), bufsize(0), saveNodeNumber(true) {}
592
593     unsigned char* serialize(bool _saveNodeNumber = true)
594     {
595         saveNodeNumber = _saveNodeNumber;
596         ast->accept(*this);
597         return get_buf();
598     }
599 };
600 }
601
602 #endif /* !__SERIALIZER_HXX__ */