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