* Bug 16365 fixed: median(m,'r'|'c') was wrong after 5dc990
[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  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17 #ifndef __SERIALIZER_HXX__
18 #define __SERIALIZER_HXX__
19
20 #include "dummyvisitor.hxx"
21 #include "deserializervisitor.hxx"
22 #include "timer.hxx"
23 #include "charEncoding.h"
24 #include "version.h"
25
26 #define FAGMENT_SIZE 65536
27
28 namespace ast
29 {
30 class SerializeVisitor : public DummyVisitor
31 {
32 private :
33     Exp* ast;
34     unsigned char *buf;
35     int buflen;
36     int bufsize;
37     bool saveNodeNumber;
38     bool saveLocation;
39
40     unsigned char* get_buf(void)
41     {
42         // set buffer size
43         set_uint32(0, buflen);
44         // set scilab version
45         set_version();
46         return buf;
47     }
48
49     /** @{ Set the file header without modifying the file size. */
50
51     void set_version()
52     {
53         set_byte(4, (unsigned char)SCI_VERSION_MAJOR);
54         set_byte(5, (unsigned char)SCI_VERSION_MINOR);
55         set_byte(6, (unsigned char)SCI_VERSION_MAINTENANCE);
56         set_byte(7, (unsigned char)0);
57     }
58
59     void set_uint32(unsigned int pos, unsigned int n)
60     {
61         buf[pos++] = (n & 0xff);
62         n >>= 8;
63         buf[pos++] = (n & 0xff);
64         n >>= 8;
65         buf[pos++] = (n & 0xff);
66         n >>= 8;
67         buf[pos++] = (n & 0xff);
68     }
69
70     void set_byte(unsigned int pos, unsigned char n)
71     {
72         buf[pos] = n;
73     }
74
75     /** @} */
76
77     void add_location(const Location& loc)
78     {
79         if (saveLocation)
80         {
81             add_uint32(loc.first_line);
82             add_uint32(loc.first_column);
83             add_uint32(loc.last_line);
84             add_uint32(loc.last_column);
85         }
86         else
87         {
88             add_uint32(0);
89             add_uint32(0);
90             add_uint32(0);
91             add_uint32(0);
92         }
93     }
94     void add_ast(unsigned int code, const Exp& e)
95     {
96         add_uint8(code);
97         if (saveNodeNumber)
98         {
99             add_uint64(e.getNodeNumber());
100         }
101         else
102         {
103             add_uint64((unsigned long long)0);
104         }
105
106         add_location(e.getLocation());
107         add_uint8(e.isVerbose());
108     }
109
110     /** @{ Low-level append to the buffer functions */
111
112     /* ensure that we have [size] bytes in the buffer */
113     void need(int size)
114     {
115         if (bufsize - buflen < size)
116         {
117             bufsize = 2 * bufsize + size + FAGMENT_SIZE;
118             unsigned char *newbuf = (unsigned char*) malloc(bufsize * sizeof(unsigned char));
119             // std::cerr << "malloc " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
120             if (buflen > 0)
121             {
122                 // std::cerr << "memcpy " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
123                 memcpy(newbuf, buf, buflen);
124             }
125             if (buf != NULL)
126             {
127                 // std::cerr << "free " << (void*) newbuf << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
128                 free(buf);
129             }
130             else
131             {
132                 buflen = 8;    /* Header length. Header =  final size of buf (4 bytes) + scilab version (4 bytes)*/
133             }
134             buf = newbuf;
135         }
136
137         // std::cerr << "need " << size << " " << bufsize << " " << (void*) buf << " " << buflen << std::endl;
138     }
139
140     void add_byte(unsigned char n)
141     {
142         buf[buflen++] = n;
143     }
144
145     void add_uint8(unsigned char n)
146     {
147         need(1);
148         add_byte(n);
149     }
150
151     void add_uint32(unsigned int n)
152     {
153         need(4);
154         add_byte(n & 0xff);
155         add_byte((n >>= 8) & 0xff);
156         add_byte((n >>= 8) & 0xff);
157         add_byte((n >>= 8) & 0xff);
158     }
159
160     void add_uint64(unsigned long long n)
161     {
162         need(8);
163         add_byte(n & 0xff);
164         add_byte((n >>= 8) & 0xff);
165         add_byte((n >>= 8) & 0xff);
166         add_byte((n >>= 8) & 0xff);
167         add_byte((n >>= 8) & 0xff);
168         add_byte((n >>= 8) & 0xff);
169         add_byte((n >>= 8) & 0xff);
170         add_byte((n >>= 8) & 0xff);
171     }
172
173     void add_double(double d)
174     {
175         need(8);
176         *(double*)(buf + buflen) = d;
177         buflen += 8;
178     }
179
180     void add_wstring(const std::wstring &w)
181     {
182         char *c_str = wide_string_to_UTF8(w.c_str());
183         int size = strlen(c_str);
184         int final_size = size * sizeof(char);
185         add_uint32(final_size);
186         need(final_size);
187         memcpy(buf + buflen, c_str, final_size);
188         FREE(c_str);
189         buflen += final_size;
190     }
191
192     /** @} */
193
194     void add_exps(const exps_t& exps)
195     {
196         add_uint32((unsigned int)exps.size());
197         if (exps.size() != 0)
198         {
199             for (auto exp : exps)
200             {
201                 exp->getOriginal()->accept(*this);
202             }
203         }
204     }
205
206     void add_vars(const ArrayListVar& var)
207     {
208         exps_t vars = var.getVars();
209         add_uint32((unsigned int)vars.size());
210         for (exps_t::const_iterator it = vars.begin (), itEnd = vars.end(); it != itEnd; ++it)
211         {
212             (*it)->getOriginal()->accept(*this);
213         }
214     }
215
216     void add_Symbol(const symbol::Symbol& e)
217     {
218         add_wstring(e.getName());
219     }
220
221     void add_exp(const Exp* e)
222     {
223         e->getOriginal()->accept(*this);
224     }
225
226     void add_exp(const Exp& e)
227     {
228         e.getOriginal()->accept(*this);
229     }
230
231     void add_OpExp_Oper(const OpExp::Oper oper)
232     {
233         int code = 253;
234         switch (oper)
235         {
236             case OpExp::plus :
237                 code = (1);
238                 break;
239             case OpExp::minus:
240                 code = (2);
241                 break;
242             case OpExp::times:
243                 code = (3);
244                 break;
245             case OpExp::rdivide:
246                 code = (4);
247                 break;
248             case OpExp::ldivide:
249                 code = (5);
250                 break;
251             case OpExp::power:
252                 code = (6);
253                 break;
254
255             case OpExp::dottimes:
256                 code = (7);
257                 break;
258             case OpExp::dotrdivide:
259                 code = (8);
260                 break;
261             case OpExp::dotldivide:
262                 code = (9);
263                 break;
264             case OpExp::dotpower:
265                 code = (10);
266                 break;
267
268             case OpExp::krontimes:
269                 code = (11);
270                 break;
271             case OpExp::kronrdivide:
272                 code = (12);
273                 break;
274             case OpExp::kronldivide:
275                 code = (13);
276                 break;
277
278             case OpExp::controltimes:
279                 code = (14);
280                 break;
281             case OpExp::controlrdivide:
282                 code = (15);
283                 break;
284             case OpExp::controlldivide:
285                 code = (16);
286                 break;
287
288             case OpExp::eq:
289                 code = (17);
290                 break;
291             case OpExp::ne:
292                 code = (18);
293                 break;
294             case OpExp::lt:
295                 code = (19);
296                 break;
297             case OpExp::le:
298                 code = (20);
299                 break;
300             case OpExp::gt:
301                 code = (21);
302                 break;
303             case OpExp::ge:
304                 code = (22);
305                 break;
306
307             case OpExp::unaryMinus:
308                 code = (23);
309                 break;
310
311             case OpExp::logicalAnd:
312                 code = (24);
313                 break;
314             case OpExp::logicalOr:
315                 code = (25);
316                 break;
317             case OpExp::logicalShortCutAnd:
318                 code = (26);
319                 break;
320             case OpExp::logicalShortCutOr:
321                 code = (27);
322                 break;
323
324             case OpExp::unaryPlus:
325                 code = (28);
326                 break;
327         }
328         add_uint8(code);
329     }
330
331     void add_TransposeExp_Kind(const TransposeExp::Kind kind)
332     {
333         int code = 249;
334         switch (kind)
335         {
336             case TransposeExp::_Conjugate_ :
337                 code = (1);
338                 break;
339             case TransposeExp::_NonConjugate_:
340                 code = (2);
341                 break;
342         }
343         add_uint8(code);
344     }
345
346     void add_bool(bool b)
347     {
348         add_uint8(b);
349     }
350
351     void add_varDec(const VarDec& varDec)
352     {
353         add_Symbol(varDec.getSymbol());
354         add_exp(varDec.getInit());
355     }
356
357     void add_MatrixLines(const exps_t* lines)
358     {
359         add_uint32((unsigned int)lines->size());
360         for (exps_t::const_iterator it = lines->begin(), itEnd = lines->end(); it != itEnd ; ++it)
361         {
362             add_location((*it)->getLocation());
363             add_exps((*it)->getAs<MatrixLineExp>()->getColumns());
364         }
365     }
366
367     virtual void visit (const SeqExp &e)  /* done */
368     {
369         add_ast(1, e);
370         add_exps(e.getExps());
371     }
372     void visit(const StringExp& e)  /* done */
373     {
374         add_ast(2, e);
375         add_wstring(e.getValue());
376     }
377     void visit(const CommentExp& e)  /* done */
378     {
379         add_ast(3, e);
380         add_wstring(e.getComment());
381     }
382     void visit(const DoubleExp& e)  /* done */
383     {
384         add_ast(6, e);
385         add_double(e.getValue());
386     }
387     void visit(const BoolExp& e)  /* done */
388     {
389         add_ast(7, e);
390         add_bool(e.getValue());
391     }
392     void visit(const NilExp& e)  /* done */
393     {
394         add_ast(8, e);
395     }
396     void visit(const SimpleVar& e)  /* done */
397     {
398         add_ast(9, e);
399         add_Symbol(e.getSymbol());
400     }
401     void visit(const ColonVar& e)  /* done */
402     {
403         add_ast(10, e);
404     }
405     void visit(const DollarVar& e)  /* done */
406     {
407         add_ast(11, e);
408     }
409     void visit(const ArrayListVar& e)  /* done */
410     {
411         add_ast(12, e);
412         add_vars(e);
413     }
414     void visit(const FieldExp& e)  /* done */
415     {
416         add_ast(13, e);
417         add_exp(e.getHead());
418         add_exp(e.getTail());
419     }
420     void visit(const IfExp& e)  /* done */
421     {
422         add_ast(14, e);
423         bool hasElse = e.hasElse();
424         add_bool(hasElse);
425         add_exp(& e.getTest());
426         add_exp(& e.getThen());
427         if (hasElse)
428         {
429             add_exp(& e.getElse());
430         }
431     }
432     void visit(const TryCatchExp& e)  /* done */
433     {
434         add_ast(15, e);
435         add_location(e.getTry().getLocation());
436         add_location(e.getCatch().getLocation());
437         add_exps(e.getTry().getAs<SeqExp>()->getExps());
438         add_exps(e.getCatch().getAs<SeqExp>()->getExps());
439     }
440     void visit(const WhileExp& e)  /* done */
441     {
442         add_ast(16, e);
443         add_exp(& e.getTest());
444         add_exp(& e.getBody());
445     }
446     void visit(const ForExp& e)   /* done */
447     {
448         add_ast(17, e);
449         add_location(e.getVardec().getLocation());
450         add_varDec(*e.getAs<ForExp>()->getVardec().getAs<VarDec>());
451         add_exp(&e.getBody());
452     }
453     void visit(const BreakExp& e)  /* done */
454     {
455         add_ast(18, e);
456     }
457     void visit(const ContinueExp& e)  /* done */
458     {
459         add_ast(19, e);
460     }
461     void visit(const ReturnExp& e)  /* done */
462     {
463         add_ast(20, e);
464         bool is_global = e.isGlobal();
465         add_bool(is_global);
466         if (!is_global) /* otherwise exp is NULL */
467         {
468             add_exp(& e.getExp());
469         }
470     }
471     void visit(const SelectExp& e)
472     {
473         add_ast(21, e);
474         Exp *default_case = e.getDefaultCase();
475         add_bool(e.hasDefault());
476         if (e.hasDefault())
477         {
478             add_location(default_case->getLocation());
479             add_exps(default_case->getAs<SeqExp>()->getExps());
480         }
481         add_exp(e.getSelect());
482
483         exps_t cases = e.getCases();
484         add_uint32((unsigned int)cases.size());
485
486         for (auto exp : cases)
487         {
488             const CaseExp *ce = exp->getAs<CaseExp>();
489             add_location(ce->getLocation());
490             add_location(ce->getBody()->getLocation());
491             add_exp(ce->getTest());
492             add_exps(ce->getBody()->getAs<SeqExp>()->getExps());
493         }
494     }
495     void visit(const CellExp& e)  /* done */
496     {
497         add_ast(23, e);
498         add_MatrixLines(& e.getLines());
499     }
500     void visit(const ArrayListExp& e)  /* done */
501     {
502         add_ast(24, e);
503         add_exps(e.getExps());
504     }
505     void visit(const AssignListExp& e)  /* done */
506     {
507         add_ast(25, e);
508         add_exps(e.getExps());
509     }
510     void visit(const NotExp& e)  /* done */
511     {
512         add_ast(26, e);
513         add_exp(e.getExp());
514     }
515     void visit(const TransposeExp& e)  /* done */
516     {
517         add_ast(27, e);
518         add_TransposeExp_Kind(e.getConjugate());
519         add_exp(e.getExp());
520     }
521     void visit(const VarDec& e)
522     {
523         add_ast(28, e);
524         add_varDec(e);
525     }
526     void visit(const FunctionDec& e)  /* done */
527     {
528         add_ast(29, e);
529         add_Symbol(e.getSymbol());
530         add_location(e.getArgs().getLocation());
531         add_location(e.getReturns().getLocation());
532         add_exp(e.getBody());
533         add_vars(*e.getArgs().getAs<ArrayListVar>());
534         add_vars(*e.getReturns().getAs<ArrayListVar>());
535     }
536     void visit(const ListExp& e)  /* done */
537     {
538         add_ast(30, e);
539         add_exp(e.getStart());
540         add_exp(e.getStep());
541         add_exp(e.getEnd());
542     }
543     void visit(const AssignExp& e)
544     {
545         add_ast(31, e);
546         add_exp(e.getLeftExp());
547         add_exp(e.getRightExp());
548     }
549     void visit(const OpExp& e)  /* done */
550     {
551         add_ast(32, e);
552         add_OpExp_Oper(e.getOper());
553         e.getLeft().getOriginal()->accept(*this);
554         e.getRight().getOriginal()->accept(*this);
555     }
556     void visit(const LogicalOpExp& e)  /* done */
557     {
558         add_ast(33, e);
559         add_OpExp_Oper(e.getOper());
560         e.getLeft().getOriginal()->accept(*this);
561         e.getRight().getOriginal()->accept(*this);
562     }
563     void visit(const MatrixExp& e) /* done */
564     {
565         add_ast(34, e);
566         add_MatrixLines(& e.getLines());
567     }
568     void visit(const CallExp& e)  /* done */
569     {
570         add_ast(35, e);
571         add_exp(e.getName());
572         ast::exps_t args = e.getArgs();
573         add_exps(args);
574     }
575     void visit(const MatrixLineExp& e)  /* SHOULD NEVER HAPPEN */
576     {
577         add_ast(36, e);
578     }
579     void visit(const CellCallExp& e)  /* done */
580     {
581         add_ast(37, e);
582         add_exp(e.getName());
583         ast::exps_t args = e.getArgs();
584         add_exps(args);
585     }
586
587     /* optimized */
588     void visit(const OptimizedExp& e)
589     {
590         e.getOriginal()->accept(*this);
591     }
592
593     void visit(const MemfillExp& e)
594     {
595         e.getOriginal()->accept(*this);
596     }
597
598     void visit(const DAXPYExp& e)
599     {
600         e.getOriginal()->accept(*this);
601     }
602
603     void visit(const IntSelectExp& e)
604     {
605         e.getOriginal()->accept(*this);
606     }
607
608     void visit(const StringSelectExp& e)
609     {
610         e.getOriginal()->accept(*this);
611     }
612
613 public :
614     SerializeVisitor(Exp* _ast) : ast(_ast), buf(NULL), buflen(0), bufsize(0), saveNodeNumber(true), saveLocation(true) {}
615     ~SerializeVisitor()
616     {
617         if(buf) free(buf);
618     }
619
620     SerializeVisitor* clone()
621     {
622         return new SerializeVisitor(ast);
623     }
624
625     unsigned char* serialize(bool _saveNodeNumber = true, bool _saveLocation = true)
626     {
627         saveNodeNumber = _saveNodeNumber;
628         saveLocation = _saveLocation;
629         ast->getOriginal()->accept(*this);
630         return get_buf();
631     }
632 };
633 }
634
635 #endif /* !__SERIALIZER_HXX__ */