/[publicrep]/ezc/trunk/src/generator.h
ViewVC logotype

Contents of /ezc/trunk/src/generator.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1139 - (show annotations)
Thu Nov 1 21:52:33 2018 UTC (4 years, 4 months ago) by tomek
Content type: text/x-csrc
File size: 42338 byte(s)
fixed: program_mode was not set in cctor
fixed: container was not correctly parsed (in template mode)



1 /*
2 * This file is a part of EZC -- Easy templating in C++ library
3 * and is distributed under the BSD 3-Clause licence.
4 * Author: Tomasz Sowa <t.sowa@ttmath.org>
5 */
6
7 /*
8 * Copyright (c) 2007-2018, Tomasz Sowa
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * * Neither the name Tomasz Sowa nor the names of contributors to this
22 * project may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38
39 #ifndef headerfile_ezc_generator
40 #define headerfile_ezc_generator
41
42 #include "blocks.h"
43 #include "pattern.h"
44 #include "functions.h"
45 #include "objects.h"
46 #include "outstreams.h"
47 #include <sstream>
48 #include <fstream>
49 #include <vector>
50 #include "expressionparser.h"
51
52
53 namespace Ezc
54 {
55
56
57
58 /*
59 StreamType
60 we use only method write(const wchar_t * str, size_t len) from the stream
61 */
62 template<class StreamType>
63 class Generator
64 {
65 public:
66
67 Generator();
68 Generator(const Generator & n);
69 Generator & operator=(const Generator & n);
70 ~Generator();
71
72 void SetPattern(Pattern & pattern);
73 void SetBlocks(Blocks & blocks);
74 void SetFunctions(Functions<StreamType> & functions);
75 void SetObjects(Objects<StreamType> & objects);
76
77
78 void SetMax(size_t max_items_, size_t max_for_items_);
79
80 // recognizing some special characters in text patterns (item_text in Patterns)
81 // \r will be a carriage return (13)
82 // \n will be a new line (10)
83 // \t will be a tabulator (9)
84 // \s will be a space
85 // \\ will be one '\'
86 // if the second character is different from those shown above the first slash will be printed
87 // so "\x" gives "\x"
88 // default: false
89 void RecognizeSpecialChars(bool spec);
90
91 // trimming white characters (at the beginning and at the end of an item_text)
92 // (special char \s if enabled is not treated as a white character here)
93 // default: false
94 void TrimWhite(bool trim);
95
96 // skipping new line characters (from the whole string in an item_text)
97 // but you can use a new line character written as "\n" (if special chars are turn on)
98 // default: false
99 void SkipNewLine(bool skip);
100
101 // default: 20
102 void SetMaxFilters(size_t new_len);
103
104 // default stack size: 300
105 void SetStackSize(size_t new_stack_size);
106
107 // set whether or not we can use cache for functions or blocks
108 // true by default
109 void CanUseCache(bool can_use_cache);
110
111 // set whether or not we can use variables: [def ...] statement
112 // true by default
113 void CanUseVars(bool can_use_variables);
114
115 void SetProgramMode(bool program_mode);
116
117 void SetExpressionParser(ExpressionParser * expression_parser);
118
119
120 // the main methods for generating
121 void Generate(StreamType & out);
122 void Generate(StreamType & out, OutStreams<StreamType> & out_streams);
123 void Generate(OutStreams<StreamType> & out_streams);
124
125
126 void SetCommentary(const char * com_start, const char * com_stop);
127 void SetCommentary(const std::string & com_start, const std::string & com_stop);
128 void SetCommentary(const wchar_t * com_start, const wchar_t * com_stop);
129 void SetCommentary(const std::wstring & com_start, const std::wstring & com_stop);
130
131 private:
132
133
134 // variables set
135 typedef std::map<std::wstring, Var> Vars;
136 Vars vars;
137
138
139 struct BlockStack
140 {
141 std::vector<Var> args;
142 StreamType * out_stream;
143 bool was_return;
144 };
145
146 std::vector<BlockStack> block_stack_tab;
147 size_t block_stack_index;
148 size_t block_stack_size;
149
150 // current output stream (can be null)
151 // at the beginning it is pointing to the main stream (to the StreamType argument passsed to Generate method)
152 StreamType * output_stream;
153
154 Pattern * ppattern;
155 Blocks * pblocks;
156 Functions<StreamType> * pfunctions;
157 Objects<StreamType> * pobjects;
158
159 // pointer to the output streams map (can be null)
160 // output stream will be created when [ezc out "stream_name"] statement is found
161 OutStreams<StreamType> * output_stream_map;
162
163 // temporary error messages
164 std::wstring temp_msg;
165
166 bool break_generating;
167 size_t current_item;
168 size_t max_items;
169 size_t max_for_items;
170 bool special_chars;
171 bool trim_white;
172 bool skip_new_line;
173
174 size_t ezc_out_stack_index;
175 size_t ezc_out_stack_size;
176
177 size_t stack_index;
178 size_t stack_size;
179
180 size_t filter_index;
181 size_t filter_size;
182 // we have to use a pointers table because standard streams such
183 // as std::wostringstream are not copyable
184 std::vector<StreamType*> filter_tab;
185 std::vector<StreamType*> ezc_out_stack_tab;
186 const StreamType empty_stream;
187
188 // used in [0] [1] [2] when there is no such argument defined
189 std::wstring empty_argument;
190
191 // temporary streams used in [if..] [for...] or [def ...]
192 // or if output_stream is null and an ezc function should be called
193 StreamType stream_temp1, stream_temp_define;
194
195 // last result from a user function (FunInfo::res)
196 bool last_res;
197
198 // true if this Generator is working now
199 bool is_generator_working;
200
201 // true if the Generator is working with [for ...], [if ...] etc.
202 bool is_generating_for;
203 bool is_generating_if;
204 bool is_generating_normal;
205 bool is_generating_filter;
206
207 // an empty string for FunInfo objects
208 // when there is no any parameters
209 const std::wstring empty;
210
211 // a stack for [for] statements
212 std::vector<Stack> stack_tab;
213
214 std::wstring commentary_start, commentary_stop;
215
216 bool can_use_vars;
217 bool can_find_in_cache;
218 bool program_mode;
219
220 ExpressionParser * expression_parser;
221
222
223
224 void ResizeStreamStack(std::vector<StreamType*> & stream_tab, size_t stream_tab_max_size);
225 void ResizeFilterTab();
226 void ResizeStack();
227 void ResizeBlockStack();
228 void ResizeEzcOutStack();
229
230 void ClearStreamStack(std::vector<StreamType*> & stream_tab);
231 void ClearFilterTab();
232 void ClearForStack();
233 void ClearBlockStack();
234 void ClearEzcOutTab();
235
236 void ClearStream(StreamType & str);
237 void RemoveStackFunData(Stack & sitem);
238
239 bool ConvertToBool(const std::wstring & str);
240
241 template<class CharType>
242 CharType ToLower(CharType c);
243
244
245 bool CheckBlockArgument(Item::Function & item_fun, std::wstring ** variable);
246
247 bool FindInCache(Item::Function & item_fun,
248 BaseObj<StreamType> ** base_obj,
249 int * method_index,
250 typename Functions<StreamType>::UserFunction ** function,
251 Item ** item_block);
252
253 bool FindInFunctionsAndBlocks(const std::wstring & name,
254 BaseObj<StreamType> ** base_obj,
255 int * method_index,
256 typename Functions<StreamType>::UserFunction ** function,
257 Item ** item_block);
258
259 bool FindInVariables(const std::wstring & name,
260 std::wstring ** variable);
261
262
263 bool Find(Item::Function & item_fun,
264 BaseObj<StreamType> ** base_obj,
265 int * method_index,
266 typename Functions<StreamType>::UserFunction ** function,
267 Item ** item_block,
268 std::wstring ** variable);
269
270 void CallFunction(typename Functions<StreamType>::UserFunction * function,
271 FunInfo<StreamType> & info);
272
273 void CallFunction(typename Functions<StreamType>::UserFunction * function,
274 std::vector<Var> & parameters,
275 StreamType & out_stream,
276 const StreamType & in_stream);
277
278 bool CallBlock(Item & item_block,
279 std::vector<Var> & parameters,
280 StreamType & out_stream);
281
282
283 void CallObject(BaseObj<StreamType> * base_obj, int method_index, FunInfo<StreamType> & info);
284
285
286 void CallObject(BaseObj<StreamType> * base_obj,
287 int method_index,
288 std::vector<Var> & parameters,
289 StreamType & out_stream,
290 const StreamType & in_stream);
291
292
293 bool Call(Item::Function & item_fun,
294 StreamType & out_stream,
295 bool clear_out_stream,
296 const StreamType & in_stream);
297
298 bool Call(Item::Function & item_fun);
299
300 wchar_t CreateSpecialChar(wchar_t c);
301 const wchar_t * PrintSpecialChar(const wchar_t * start, const wchar_t * end);
302 void PrintSpecialText(const wchar_t * start, const wchar_t * end);
303 void PrintNormalText(const wchar_t * start, const wchar_t * end);
304 bool IsWhite(wchar_t c);
305 void TrimWhite(const wchar_t *& start, const wchar_t *& end);
306 void SkipWhite(const wchar_t *& str);
307 size_t StrToSize(const wchar_t * str, const wchar_t ** str_end = 0);
308
309
310 void CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream);
311 void CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg = 0);
312 void CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg = 0);
313 void CreateMsg(const wchar_t * type, const wchar_t * arg = 0);
314 void CreateMsg(const std::wstring & type, const std::wstring & arg);
315 void CreateMsg(const std::wstring & type);
316 void CreateUnknownMsg(const std::wstring & fun);
317 bool LimitAchieved();
318
319 void EvaluateProgramNode(Item & item);
320
321 void MakeTextIf_go(Item & item, bool result);
322 void MakeTextIf(Item & item);
323 void MakeTextFor(Item & item);
324 void MakeItemText(Item & item);
325 void MakeTextContainer(Item & item);
326 void MakeTextNormal(Item & item);
327 void MakeTextDefine(Item & item);
328 void MakeTextFilter(Item & item);
329 void MakeTextEzc(Item & item);
330 void MakeTextReturn(Item & item);
331 void MakeText(Item & item);
332 void MakeEzcOut(Item & item);
333
334 void Generate();
335
336
337
338 }; // class Generator
339
340
341
342
343
344
345 template<class StreamType>
346 Generator<StreamType>::Generator() : empty_stream()
347 {
348 ppattern = 0;
349 pblocks = 0;
350 pfunctions = 0;
351 pobjects = 0;
352
353 max_items = 50000;
354 max_for_items = 5000;
355 filter_size = 20;
356 special_chars = false;
357 trim_white = false;
358 skip_new_line = false;
359 is_generator_working = false;
360 stack_size = 300;
361 block_stack_size = 64;
362 ezc_out_stack_size = 16;
363 can_find_in_cache = true;
364 can_use_vars = true;
365 expression_parser = nullptr;
366 program_mode = false;
367 }
368
369
370 template<class StreamType>
371 Generator<StreamType>::Generator(const Generator<StreamType> & n)
372 {
373 operator=(n);
374 }
375
376
377
378 template<class StreamType>
379 Generator<StreamType> & Generator<StreamType>::operator=(const Generator<StreamType> & n)
380 {
381 ppattern = n.ppattern;
382 pblocks = n.pblocks;
383 pfunctions = n.pfunctions;
384 pobjects = n.pobjects;
385
386 max_items = n.max_items;
387 max_for_items = n.max_for_items;
388 special_chars = n.special_chars;
389 trim_white = n.trim_white;
390 skip_new_line = n.skip_new_line;
391 can_find_in_cache = n.can_find_in_cache;
392 can_use_vars = n.can_use_vars;
393
394 // filter, stack and block_stack will be auto resized when calling Generate() method
395 filter_size = n.filter_size;
396 stack_size = n.stack_size;
397 block_stack_size = n.block_stack_size;
398 ezc_out_stack_size = n.ezc_out_stack_size;
399 expression_parser = n.expression_parser;
400 program_mode = n.program_mode;
401
402 // vars doesn't have to be copied
403
404 // don't copy filter tab
405 // don't copy stack
406 // don't copy ezc_out_stack_tab
407 // don't copy output_stream and output_stream_map
408
409 // !! CHECK ME
410 // may copying should be denied when generator is working?
411 // don't copy 'is_generator_working' flag
412 is_generator_working = false;
413
414 return *this;
415 }
416
417
418
419 template<class StreamType>
420 Generator<StreamType>::~Generator()
421 {
422 ClearFilterTab();
423 ClearForStack();
424 ClearBlockStack();
425 ClearEzcOutTab();
426 }
427
428
429 template<class StreamType>
430 void Generator<StreamType>::SetCommentary(const char * com_start, const char * com_stop)
431 {
432 PT::UTF8ToWide(com_start, commentary_start);
433 PT::UTF8ToWide(com_stop, commentary_stop);
434 }
435
436
437
438 template<class StreamType>
439 void Generator<StreamType>::SetCommentary(const std::string & com_start, const std::string & com_stop)
440 {
441 PT::UTF8ToWide(com_start, commentary_start);
442 PT::UTF8ToWide(com_stop, commentary_stop);
443 }
444
445
446
447 template<class StreamType>
448 void Generator<StreamType>::SetCommentary(const wchar_t * com_start, const wchar_t * com_stop)
449 {
450 commentary_start = com_start;
451 commentary_stop = com_stop;
452 }
453
454
455
456 template<class StreamType>
457 void Generator<StreamType>::SetCommentary(const std::wstring & com_start, const std::wstring & com_stop)
458 {
459 commentary_start = com_start;
460 commentary_stop = com_stop;
461 }
462
463
464
465 template<class StreamType>
466 void Generator<StreamType>::SetPattern(Pattern & pattern)
467 {
468 ppattern = &pattern;
469 }
470
471
472
473
474 template<class StreamType>
475 void Generator<StreamType>::SetBlocks(Blocks & blocks)
476 {
477 pblocks = &blocks;
478 }
479
480
481 template<class StreamType>
482 void Generator<StreamType>::SetFunctions(Functions<StreamType> & functions)
483 {
484 pfunctions = &functions;
485 }
486
487
488 template<class StreamType>
489 void Generator<StreamType>::SetObjects(Objects<StreamType> & objects)
490 {
491 pobjects = &objects;
492 }
493
494 template<class StreamType>
495 void Generator<StreamType>::CanUseCache(bool can_use_cache)
496 {
497 can_find_in_cache = can_use_cache;
498 }
499
500
501 template<class StreamType>
502 void Generator<StreamType>::CanUseVars(bool can_use_variables)
503 {
504 can_use_vars = can_use_variables;
505 }
506
507 template<class StreamType>
508 void Generator<StreamType>::SetProgramMode(bool set_program_mode)
509 {
510 this->program_mode = set_program_mode;
511 }
512
513 template<class StreamType>
514 void Generator<StreamType>::SetExpressionParser(ExpressionParser * expression_parser)
515 {
516 this->expression_parser = expression_parser;
517 }
518
519
520
521
522 template<class StreamType>
523 void Generator<StreamType>::ResizeStack()
524 {
525 if( stack_tab.size() != stack_size )
526 {
527 if( stack_tab.size() > stack_size )
528 {
529 for(size_t i=stack_size ; i<stack_tab.size() ; ++i)
530 RemoveStackFunData(stack_tab[i]);
531 }
532
533 stack_tab.resize(stack_size);
534 }
535 }
536
537
538
539 template<class StreamType>
540 void Generator<StreamType>::ResizeStreamStack(std::vector<StreamType*> & stream_tab, size_t stream_tab_max_size)
541 {
542 if( stream_tab.size() != stream_tab_max_size )
543 {
544 if( stream_tab.size() < stream_tab_max_size )
545 {
546 size_t i = stream_tab.size();
547 stream_tab.resize(stream_tab_max_size);
548
549 for( ; i<stream_tab.size() ; ++i)
550 stream_tab[i] = new StreamType();
551 }
552 else
553 {
554 for(size_t i=stream_tab_max_size ; i<stream_tab.size() ; ++i)
555 delete stream_tab[i];
556
557 stream_tab.resize(stream_tab_max_size);
558 }
559 }
560 }
561
562
563 template<class StreamType>
564 void Generator<StreamType>::ResizeFilterTab()
565 {
566 ResizeStreamStack(filter_tab, filter_size);
567 }
568
569
570 template<class StreamType>
571 void Generator<StreamType>::ResizeEzcOutStack()
572 {
573 ResizeStreamStack(ezc_out_stack_tab, ezc_out_stack_size);
574 }
575
576
577 template<class StreamType>
578 void Generator<StreamType>::ResizeBlockStack()
579 {
580 if( block_stack_tab.size() != block_stack_size )
581 {
582 if( block_stack_tab.size() < block_stack_size )
583 {
584 size_t i = block_stack_tab.size();
585 block_stack_tab.resize(block_stack_size);
586
587 for( ; i<block_stack_tab.size() ; ++i)
588 block_stack_tab[i].out_stream = new StreamType();
589 }
590 else
591 {
592 for(size_t i=block_stack_size ; i<block_stack_tab.size() ; ++i)
593 delete block_stack_tab[i].out_stream;
594
595 block_stack_tab.resize(block_stack_size);
596 }
597 }
598 }
599
600
601
602
603
604 template<class StreamType>
605 void Generator<StreamType>::ClearStreamStack(std::vector<StreamType*> & stream_tab)
606 {
607 for(size_t i=0 ; i<stream_tab.size() ; ++i)
608 delete stream_tab[i];
609
610 stream_tab.clear();
611 }
612
613
614 template<class StreamType>
615 void Generator<StreamType>::ClearFilterTab()
616 {
617 ClearStreamStack(filter_tab);
618 }
619
620
621 template<class StreamType>
622 void Generator<StreamType>::ClearEzcOutTab()
623 {
624 ClearStreamStack(ezc_out_stack_tab);
625 }
626
627
628 template<class StreamType>
629 void Generator<StreamType>::ClearBlockStack()
630 {
631 for(size_t i=0 ; i<block_stack_tab.size() ; ++i)
632 delete block_stack_tab[i].out_stream;
633
634 block_stack_tab.clear();
635 }
636
637
638 template<class StreamType>
639 void Generator<StreamType>::ClearForStack()
640 {
641 for(size_t i=0 ; i<stack_tab.size() ; ++i)
642 RemoveStackFunData(stack_tab[i]);
643 }
644
645
646 template<class StreamType>
647 void Generator<StreamType>::ClearStream(StreamType & str)
648 {
649 #ifdef EZC_HAS_SPECIAL_STREAM
650 str.Clear();
651 #else
652 str.str(L"");
653 #endif
654 }
655
656
657 template<class StreamType>
658 void Generator<StreamType>::RemoveStackFunData(Stack & s)
659 {
660 if( s.fun_data && s.auto_remove )
661 {
662 delete s.fun_data;
663 s.fun_data = 0;
664 }
665 }
666
667
668 template<class StreamType>
669 template<class CharType>
670 CharType Generator<StreamType>::ToLower(CharType c)
671 {
672 if( c>='A' && c<='Z' )
673 return c - 'A' + 'a';
674
675 return c;
676 }
677
678
679 template<class StreamType>
680 bool Generator<StreamType>::ConvertToBool(const std::wstring & str)
681 {
682 if( str == L"true" )
683 return true;
684
685 return false;
686 }
687
688
689 template<class StreamType>
690 void Generator<StreamType>::SetMax(size_t max_items_, size_t max_for_items_)
691 {
692 max_items = max_items_;
693 max_for_items = max_for_items_;
694 }
695
696
697 template<class StreamType>
698 void Generator<StreamType>::RecognizeSpecialChars(bool spec)
699 {
700 special_chars = spec;
701 }
702
703
704 template<class StreamType>
705 void Generator<StreamType>::TrimWhite(bool trim)
706 {
707 trim_white = trim;
708 }
709
710
711 template<class StreamType>
712 void Generator<StreamType>::SkipNewLine(bool skip)
713 {
714 skip_new_line = skip;
715 }
716
717
718 template<class StreamType>
719 void Generator<StreamType>::SetMaxFilters(size_t new_len)
720 {
721 // the table will be resized when Generate() method is called
722 filter_size = new_len;
723 }
724
725
726 template<class StreamType>
727 void Generator<StreamType>::SetStackSize(size_t new_stack_size)
728 {
729 // the stack will be resized when Generate() method is called
730 stack_size = new_stack_size;
731 }
732
733
734
735 template<class StreamType>
736 void Generator<StreamType>::Generate()
737 {
738 if( is_generator_working )
739 {
740 CreateMsg(L"generator busy");
741 return;
742 }
743
744 break_generating = false;
745 current_item = 0;
746
747 // in the case that there something has left on the stack
748 // from previous call to Generate()
749 // (an exception could have been thrown)
750 ClearForStack();
751
752 ResizeFilterTab();
753 ResizeStack();
754 ResizeBlockStack();
755 ResizeEzcOutStack();
756 filter_index = 0;
757 stack_index = 0;
758 block_stack_index = 0;
759 vars.clear();
760
761 if( ppattern )
762 {
763 try
764 {
765 is_generator_working = true;
766 MakeText( ppattern->item_root );
767 // !! IMPROVE ME we can print an error message if the stacks are not empty
768 // (some [end] statements has been omited)
769 vars.clear();
770 is_generator_working = false;
771 }
772 catch(...)
773 {
774 is_generator_working = false;
775 throw;
776 }
777 }
778 }
779
780
781 template<class StreamType>
782 void Generator<StreamType>::Generate(StreamType & out)
783 {
784 output_stream = &out;
785 output_stream_map = 0;
786 Generate();
787 }
788
789
790
791 template<class StreamType>
792 void Generator<StreamType>::Generate(StreamType & out, OutStreams<StreamType> & out_streams)
793 {
794 output_stream = &out;
795 output_stream_map = &out_streams;
796 Generate();
797 }
798
799
800 template<class StreamType>
801 void Generator<StreamType>::Generate(OutStreams<StreamType> & out_streams)
802 {
803 output_stream = 0;
804 output_stream_map = &out_streams;
805 Generate();
806 }
807
808
809
810 template<class StreamType>
811 bool Generator<StreamType>::CheckBlockArgument(Item::Function & item_fun, std::wstring ** variable)
812 {
813 if( item_fun.arg < 0 )
814 return false;
815
816 empty_argument.clear();
817 *variable = &empty_argument;
818 last_res = ConvertToBool(empty_argument);
819
820 // it's a numeric function -- an argument to a block e.g.: [1]
821 if( block_stack_index > 0 )
822 {
823 BlockStack & block_stack = block_stack_tab[block_stack_index-1];
824
825 if( size_t(item_fun.arg) < block_stack.args.size() )
826 {
827 *variable = &block_stack.args[item_fun.arg].str;
828 last_res = block_stack.args[item_fun.arg].res;
829 }
830 }
831
832 return true;
833 }
834
835
836
837 template<class StreamType>
838 bool Generator<StreamType>::FindInCache(Item::Function & item_fun,
839 BaseObj<StreamType> ** base_obj,
840 int * method_index,
841 typename Functions<StreamType>::UserFunction ** function,
842 Item ** item_block)
843 {
844 if( can_find_in_cache )
845 {
846 if( item_fun.base_obj )
847 {
848 *base_obj = reinterpret_cast<BaseObj<StreamType> * >(item_fun.base_obj);
849 *method_index = item_fun.method_index;
850 return true;
851 }
852
853 if( item_fun.fun_cache )
854 {
855 *function = reinterpret_cast<typename Functions<StreamType>::UserFunction*>(item_fun.fun_cache);
856 return true;
857 }
858
859 if( item_fun.item_block )
860 {
861 *item_block = item_fun.item_block;
862 return true;
863 }
864 }
865
866 return false;
867 }
868
869
870
871 template<class StreamType>
872 bool Generator<StreamType>::FindInFunctionsAndBlocks(const std::wstring & name,
873 BaseObj<StreamType> ** base_obj,
874 int * method_index,
875 typename Functions<StreamType>::UserFunction ** function,
876 Item ** item_block)
877 {
878 if( pobjects )
879 {
880 typename Objects<StreamType>::Iterator i = pobjects->Find(name, *method_index);
881
882 if( i != pobjects->End() )
883 {
884 *base_obj = *i;
885 return true;
886 }
887 }
888
889 if( pfunctions )
890 {
891 typename Functions<StreamType>::Iterator i = pfunctions->Find(name);
892
893 if( i != pfunctions->End() )
894 {
895 *function = &i->second;
896 return true;
897 }
898 }
899
900 if( pblocks )
901 {
902 Blocks::Iterator i = pblocks->Find(name);
903
904 if( i != pblocks->End() )
905 {
906 *item_block = &i->second;
907 return true;
908 }
909 }
910
911 return false;
912 }
913
914
915 template<class StreamType>
916 bool Generator<StreamType>::FindInVariables(const std::wstring & name,
917 std::wstring ** variable)
918 {
919 Vars::iterator i = vars.find(name);
920
921 if( i != vars.end() )
922 {
923 Var & var = i->second;
924
925 *variable = &var.str;
926 last_res = var.res;
927 return true;
928 }
929
930 return false;
931 }
932
933
934 template<class StreamType>
935 bool Generator<StreamType>::Find(Item::Function & item_fun,
936 BaseObj<StreamType> ** base_obj,
937 int * method_index,
938 typename Functions<StreamType>::UserFunction ** function,
939 Item ** item_block,
940 std::wstring ** variable)
941 {
942 *base_obj = 0;
943 *method_index = -1;
944 *function = 0;
945 *item_block = 0;
946 *variable = 0;
947
948 if( CheckBlockArgument(item_fun, variable) )
949 return true;
950
951 if( FindInCache(item_fun, base_obj, method_index, function, item_block) )
952 return true;
953
954 if( FindInFunctionsAndBlocks(item_fun.name, base_obj, method_index, function, item_block) )
955 return true;
956
957 if( FindInVariables(item_fun.name, variable) )
958 return true;
959
960 CreateUnknownMsg(item_fun.name);
961
962 return false;
963 }
964
965
966
967 template<class StreamType>
968 void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFunction * function, FunInfo<StreamType> & info)
969 {
970 info.Clear();
971
972 info.is_for = is_generating_for;
973 info.is_if = is_generating_if;
974 info.is_normal = is_generating_normal;
975 info.is_filter = is_generating_filter;
976 info.iter = info.stack.iter;
977 info.stack_tab = &stack_tab[0];//stack_tab.data();/////////////////////////////////////////////////////////
978 info.stack_index = stack_index-1;
979
980 (*function)(info);
981
982 last_res = info.res;
983 }
984
985
986
987 template<class StreamType>
988 void Generator<StreamType>::CallFunction(typename Functions<StreamType>::UserFunction * function,
989 std::vector<Var> & parameters,
990 StreamType & out_stream,
991 const StreamType & in_stream)
992 {
993 if( parameters.empty() )
994 {
995 FunInfo<StreamType> info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item);
996 CallFunction(function, info);
997 }
998 else
999 {
1000 FunInfo<StreamType> info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item);
1001 CallFunction(function, info);
1002 }
1003 }
1004
1005
1006
1007
1008
1009
1010
1011 template<class StreamType>
1012 void Generator<StreamType>::CallObject(BaseObj<StreamType> * base_obj, int method_index, FunInfo<StreamType> & info)
1013 {
1014 info.Clear();
1015
1016 info.is_for = is_generating_for;
1017 info.is_if = is_generating_if;
1018 info.is_normal = is_generating_normal;
1019 info.is_filter = is_generating_filter;
1020 info.iter = info.stack.iter;
1021 info.stack_tab = &stack_tab[0];//stack_tab.data();/////////////////////////////////////////////////////////
1022 info.stack_index = stack_index-1;
1023
1024 base_obj->CallFun(method_index, info);
1025
1026 last_res = info.res;
1027 }
1028
1029
1030
1031 template<class StreamType>
1032 void Generator<StreamType>::CallObject(BaseObj<StreamType> * base_obj,
1033 int method_index,
1034 std::vector<Var> & parameters,
1035 StreamType & out_stream,
1036 const StreamType & in_stream)
1037 {
1038 if( parameters.empty() )
1039 {
1040 FunInfo<StreamType> info(out_stream, parameters, empty, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item);
1041 CallObject(base_obj, method_index, info);
1042 }
1043 else
1044 {
1045 FunInfo<StreamType> info(out_stream, parameters, parameters[0].str, in_stream, stack_tab[stack_index-1], *stack_tab[stack_index-1].item);
1046 CallObject(base_obj, method_index, info);
1047 }
1048 }
1049
1050
1051
1052 template<class StreamType>
1053 bool Generator<StreamType>::CallBlock(Item & item_block,
1054 std::vector<Var> & parameters,
1055 StreamType & out_stream)
1056 {
1057 if( block_stack_index >= block_stack_tab.size() )
1058 {
1059 CreateMsg(L"Generator exceeded allowed number of blocks");
1060 return false;
1061 }
1062
1063 StreamType * old_stream = output_stream;
1064 BlockStack & block_stack = block_stack_tab[block_stack_index];
1065
1066 block_stack.was_return = false;
1067 block_stack.args = parameters;
1068
1069 output_stream = block_stack.out_stream;
1070 ClearStream(*output_stream);
1071 block_stack_index += 1;
1072
1073 MakeText(item_block);
1074
1075 #ifdef EZC_HAS_SPECIAL_STREAM
1076 const std::wstring & str = output_stream->Str();
1077 #else
1078 const std::wstring & str = output_stream->str();
1079 #endif
1080
1081 out_stream.write(str.c_str(), str.size());
1082 // last_res is set by [return ...] statement or other last evaluated function
1083
1084 ClearStream(*output_stream);
1085 output_stream = old_stream;
1086 block_stack_index -= 1;
1087
1088 return true;
1089 }
1090
1091
1092 // return: true if a function, variable or block was found and called
1093 template<class StreamType>
1094 bool Generator<StreamType>::Call(Item::Function & item_fun,
1095 StreamType & out_stream,
1096 bool clear_out_stream,
1097 const StreamType & in_stream)
1098 {
1099 BaseObj<StreamType> * base_obj;
1100 int method_index;
1101 typename Functions<StreamType>::UserFunction * fun;
1102 Item * item_block;
1103 std::wstring * variable;
1104 std::vector<Var> parameters;
1105
1106 if( clear_out_stream )
1107 ClearStream(out_stream);
1108
1109 if( !Find(item_fun, &base_obj, &method_index, &fun, &item_block, &variable) )
1110 return false;
1111
1112 parameters.resize(item_fun.parameters.size());
1113
1114 for(size_t i=0 ; i<item_fun.parameters.size() ; ++i)
1115 {
1116 Item::Function & fun_child = *item_fun.parameters[i];
1117
1118 if( fun_child.is_function )
1119 {
1120 StreamType local_temp_stream;
1121 Call(fun_child, local_temp_stream, true, empty_stream);
1122
1123 #ifdef EZC_HAS_SPECIAL_STREAM
1124 parameters[i].str = local_temp_stream.Str();
1125 #else
1126 parameters[i].str = local_temp_stream.str();
1127 #endif
1128
1129 parameters[i].res = last_res;
1130 }
1131 else
1132 {
1133 parameters[i].str = fun_child.name;
1134 parameters[i].res = ConvertToBool(fun_child.name);
1135 }
1136 }
1137
1138 if( base_obj )
1139 CallObject(base_obj, method_index, parameters, out_stream, in_stream);
1140 else
1141 if( fun )
1142 CallFunction(fun, parameters, out_stream, in_stream);
1143 else
1144 if( item_block )
1145 return CallBlock(*item_block, parameters, out_stream);
1146 else
1147 if( variable )
1148 out_stream.write(variable->c_str(), variable->size());
1149
1150 return true;
1151 }
1152
1153
1154
1155 // return: true if a function or variable was found and called
1156 template<class StreamType>
1157 bool Generator<StreamType>::Call(Item::Function & item_fun)
1158 {
1159 return Call(item_fun, stream_temp1, true, empty_stream);
1160 }
1161
1162
1163
1164
1165 template<class StreamType>
1166 wchar_t Generator<StreamType>::CreateSpecialChar(wchar_t c)
1167 {
1168 wchar_t res = 0;
1169
1170 if( c == 'r' )
1171 res = '\r';
1172 else
1173 if( c == 'n' )
1174 res = '\n';
1175 else
1176 if( c == 't' )
1177 res = '\t';
1178 else
1179 if( c == 's' )
1180 res = ' ';
1181 else
1182 if( c == '\\' )
1183 res = '\\';
1184
1185 return res;
1186 }
1187
1188
1189
1190 // a special character is precedeed by a slash '\'
1191 // if the special character is unknown the first slash is printing
1192 // so "\t" gives one character of code 9
1193 // and "\x" gives "\x"
1194 template<class StreamType>
1195 const wchar_t * Generator<StreamType>::PrintSpecialChar(const wchar_t * start, const wchar_t * end)
1196 {
1197 wchar_t special = 0;
1198
1199 if( *start == '\\' && (start+1) != end )
1200 special = CreateSpecialChar(*(start+1));
1201
1202 if( special )
1203 {
1204 output_stream->write(&special, 1);
1205 start += 2;
1206 }
1207 else
1208 {
1209 if( !skip_new_line || *start != 10 )
1210 output_stream->write(start, 1);
1211
1212 start += 1;
1213 }
1214
1215 return start;
1216 }
1217
1218
1219 template<class StreamType>
1220 void Generator<StreamType>::PrintSpecialText(const wchar_t * start, const wchar_t * end)
1221 {
1222 if( output_stream )
1223 {
1224 while( start != end )
1225 {
1226 const wchar_t * end2 = start;
1227
1228 // looking for a first new line character or a special char
1229 // (for new line only if skip_new_line is true)
1230 while( end2 != end && *end2 != '\\' && (!skip_new_line || *end2 != 10) )
1231 end2 += 1;
1232
1233 // printing the first part of the text
1234 if( start != end2 )
1235 output_stream->write(start, end2 - start);
1236
1237 start = end2;
1238
1239 // skipping one or more new line characters or special chars
1240 // (new lines only if skip_new_line is true)
1241 while( start != end && (*start == '\\' || (skip_new_line && *start == 10)) )
1242 start = PrintSpecialChar(start, end);
1243 }
1244 }
1245 }
1246
1247
1248 template<class StreamType>
1249 void Generator<StreamType>::PrintNormalText(const wchar_t * start, const wchar_t * end)
1250 {
1251 if( output_stream )
1252 {
1253 if( skip_new_line )
1254 {
1255 while( start != end )
1256 {
1257 const wchar_t * end2 = start;
1258
1259 // looking for a first new line character
1260 while( end2 != end && *end2 != 10 )
1261 end2 += 1;
1262
1263 // printing the first part of the text (until the new line)
1264 if( start != end2 )
1265 output_stream->write(start, end2 - start);
1266
1267 start = end2;
1268
1269 // skipping one or more new line characters
1270 while( start != end && *start == 10 )
1271 start += 1;
1272 }
1273 }
1274 else
1275 {
1276 if( start != end )
1277 output_stream->write(start, end - start);
1278 }
1279 }
1280 }
1281
1282
1283 template<class StreamType>
1284 bool Generator<StreamType>::IsWhite(wchar_t c)
1285 {
1286 // 13 (\r) is from a dos file at the end of a line (\r\n)
1287 // 160 is a non-breaking space
1288
1289 if( c==' ' || c=='\t' || c==13 || c==160 || c==10 )
1290 return true;
1291
1292 return false;
1293 }
1294
1295
1296 template<class StreamType>
1297 void Generator<StreamType>::TrimWhite(const wchar_t *& start, const wchar_t *& end)
1298 {
1299 while( start != end && IsWhite(*start) )
1300 ++start;
1301
1302 while( start != end && IsWhite(*(end-1)) )
1303 --end;
1304 }
1305
1306
1307 template<class StreamType>
1308 void Generator<StreamType>::SkipWhite(const wchar_t *& str)
1309 {
1310 while( IsWhite(*str) )
1311 str += 1;
1312 }
1313
1314
1315
1316 template<class StreamType>
1317 size_t Generator<StreamType>::StrToSize(const wchar_t * str, const wchar_t ** str_end)
1318 {
1319 size_t res = 0;
1320
1321 SkipWhite(str);
1322
1323 // !! IMPROVE ME
1324 // overflow is not checked
1325
1326 while( *str>='0' && *str<='9' )
1327 {
1328 res *= 10;
1329 res += *str - '0';
1330 str += 1;
1331 }
1332
1333 SkipWhite(str);
1334
1335 if( str_end )
1336 *str_end = str;
1337
1338 return res;
1339 }
1340
1341
1342 template<class StreamType>
1343 void Generator<StreamType>::CopyTmpStreamToOutputStreams(Item::Function & fun, StreamType & ezc_out_tmp_stream, StreamType & previous_stream)
1344 {
1345 if( output_stream_map )
1346 {
1347 #ifdef EZC_HAS_SPECIAL_STREAM
1348 const std::wstring & str = ezc_out_tmp_stream.Str();
1349 #else
1350 const std::wstring & str = ezc_out_tmp_stream.str();
1351 #endif
1352
1353 if( !str.empty() )
1354 {
1355 previous_stream.write(str.c_str(), str.size());
1356
1357 for(size_t s=0 ; s < fun.parameters.size() ; ++s)
1358 {
1359 std::wstring & name = fun.parameters[s]->name;
1360 auto imap = output_stream_map->streams_map.find(name);
1361
1362 if( imap == output_stream_map->streams_map.end() )
1363 {
1364 if( output_stream_map->streams_map.size() < output_stream_map->streams_tab.size() )
1365 {
1366 /* a new stream from the pool (output_stream_tab) is taken */
1367 StreamType * stream = output_stream_map->streams_tab[ output_stream_map->streams_map.size() ];
1368 output_stream_map->streams_map.insert(std::make_pair(name, stream));
1369 ClearStream(*stream);
1370 stream->write(str.c_str(), str.size());
1371 }
1372 else
1373 {
1374 CreateMsg(previous_stream, L"limit of output streams in OutStreams<> has been reached");
1375 }
1376 }
1377 else
1378 {
1379 StreamType * stream = imap->second;
1380 stream->write(str.c_str(), str.size());
1381 }
1382 }
1383 }
1384 }
1385 }
1386
1387
1388
1389 template<class StreamType>
1390 void Generator<StreamType>::CreateMsg(std::wstring & out, const wchar_t * type, const wchar_t * arg)
1391 {
1392 out = commentary_start;
1393 out += L"Ezc runtime error: ";
1394 out += type;
1395
1396 if( arg )
1397 {
1398 out += ' ';
1399 out += arg;
1400 }
1401
1402 out += commentary_stop;
1403 }
1404
1405
1406 template<class StreamType>
1407 void Generator<StreamType>::CreateMsg(StreamType & stream, const wchar_t * type, const wchar_t * arg)
1408 {
1409 CreateMsg(temp_msg, type, arg);
1410 stream.write(temp_msg.c_str(), temp_msg.size());
1411 temp_msg.clear();
1412 }
1413
1414
1415 template<class StreamType>
1416 void Generator<StreamType>::CreateMsg(const wchar_t * type, const wchar_t * arg)
1417 {
1418 if( output_stream )
1419 CreateMsg(*output_stream, type, arg);
1420 }
1421
1422
1423
1424 template<class StreamType>
1425 void Generator<StreamType>::CreateMsg(const std::wstring & type, const std::wstring & arg)
1426 {
1427 CreateMsg(type.c_str(), arg.c_str());
1428 }
1429
1430
1431
1432 template<class StreamType>
1433 void Generator<StreamType>::CreateMsg(const std::wstring & type)
1434 {
1435 CreateMsg(type.c_str());
1436 }
1437
1438
1439 template<class StreamType>
1440 void Generator<StreamType>::CreateUnknownMsg(const std::wstring & fun)
1441 {
1442 CreateMsg(L"unknown function", fun.c_str());
1443 }
1444
1445
1446
1447 template<class StreamType>
1448 void Generator<StreamType>::EvaluateProgramNode(Item & item)
1449 {
1450 if( output_stream )
1451 {
1452 if( item.type == Item::item_function )
1453 *output_stream << " expression: " << item.text;
1454
1455 if( item.type == Item::item_if )
1456 *output_stream << " if: " << item.text;
1457
1458 if( item.type == Item::item_for )
1459 *output_stream << " for: " << item.text;
1460 }
1461
1462 last_res = false;
1463
1464 if( expression_parser )
1465 {
1466 if( expression_parser->Parse(item.text) )
1467 {
1468 last_res = expression_parser->LastResultToBool();
1469
1470 if( output_stream )
1471 {
1472 *output_stream << " -> " << expression_parser->LastResult();
1473 }
1474 }
1475 else
1476 {
1477 if( output_stream )
1478 {
1479 *output_stream << " -> syntax error when evaluating expression: error code: " << (int)expression_parser->LastError();
1480 }
1481 }
1482 }
1483
1484 if( output_stream )
1485 {
1486 *output_stream << "\n";
1487 }
1488 }
1489
1490
1491
1492 template<class StreamType>
1493 void Generator<StreamType>::MakeItemText(Item & item)
1494 {
1495 const wchar_t * start = item.text.c_str();
1496 const wchar_t * end = item.text.c_str() + item.text.size();
1497
1498 if( trim_white )
1499 TrimWhite(start, end);
1500
1501 if( special_chars )
1502 PrintSpecialText(start, end);
1503 else
1504 PrintNormalText(start, end);
1505 }
1506
1507
1508 template<class StreamType>
1509 void Generator<StreamType>::MakeTextContainer(Item & item)
1510 {
1511 std::vector<Item*>::iterator i = item.item_tab.begin();
1512
1513 for( ; i != item.item_tab.end() && !break_generating ; ++i )
1514 MakeText(**i);
1515 }
1516
1517
1518
1519 template<class StreamType>
1520 void Generator<StreamType>::MakeTextNormal(Item & item)
1521 {
1522 is_generating_normal = true;
1523
1524 if( program_mode )
1525 {
1526 EvaluateProgramNode(item);
1527 }
1528 else
1529 {
1530 if( output_stream )
1531 {
1532 Call(item.function, *output_stream, false, empty_stream);
1533 }
1534 else
1535 {
1536 Call(item.function, stream_temp1, false, empty_stream);
1537 ClearStream(stream_temp1);
1538 }
1539 }
1540 }
1541
1542
1543
1544 template<class StreamType>
1545 void Generator<StreamType>::MakeTextIf_go(Item & item, bool result)
1546 {
1547 if( result )
1548 {
1549 if( item.item_tab.size() > 0 )
1550 MakeText( *item.item_tab[0] );
1551 }
1552 else
1553 {
1554 // second element can be (or not -- it's from [else])
1555 if( item.item_tab.size() > 1 )
1556 MakeText( *item.item_tab[1] );
1557 }
1558 }
1559
1560
1561
1562 template<class StreamType>
1563 void Generator<StreamType>::MakeTextIf(Item & item)
1564 {
1565 is_generating_if = true;
1566
1567 if( program_mode )
1568 {
1569 EvaluateProgramNode(item);
1570 }
1571 else
1572 {
1573 if( !Call(item.function) )
1574 return;
1575 }
1576
1577 MakeTextIf_go(item, last_res);
1578 }
1579
1580
1581
1582
1583 template<class StreamType>
1584 void Generator<StreamType>::MakeTextFor(Item & item)
1585 {
1586 stack_tab[stack_index-1].is_for = true;
1587
1588 for( ; !break_generating ; stack_tab[stack_index-1].iter += 1 )
1589 {
1590 if( stack_tab[stack_index-1].iter >= max_for_items )
1591 {
1592 CreateMsg(item.function.name.c_str(),
1593 L"function exceeded a limit for a [for] statement");
1594 break;
1595 }
1596
1597 // is_generating_for will be changed by next call to MakeText()
1598 // so we should set it in each iterations
1599 is_generating_for = true;
1600
1601 if( program_mode )
1602 {
1603 EvaluateProgramNode(item);
1604 }
1605 else
1606 {
1607 Call(item.function, stream_temp1, true, empty_stream);
1608 }
1609
1610 if( !last_res )
1611 break;
1612
1613 if( !item.item_tab.empty() )
1614 MakeText( *item.item_tab[0] ); // should be only one item
1615 }
1616 }
1617
1618
1619
1620 template<class StreamType>
1621 void Generator<StreamType>::MakeTextDefine(Item & item)
1622 {
1623 if( !can_use_vars )
1624 {
1625 CreateMsg(L"[def] statement not available");
1626 return;
1627 }
1628
1629 Var & var = vars[item.function.name];
1630 var.str.clear();
1631 var.res = false;
1632
1633 for(size_t i=0 ; i < item.function.parameters.size() ; ++i)
1634 {
1635 if( !item.function.parameters[i]->is_function )
1636 {
1637 var.str += item.function.parameters[i]->name;
1638 var.res = ConvertToBool(item.function.parameters[i]->name);
1639 }
1640 else
1641 {
1642 // it is a function parameter
1643 if( Call(*item.function.parameters[i], stream_temp_define, true, empty_stream) )
1644 {
1645 #ifdef EZC_HAS_SPECIAL_STREAM
1646 var.str += stream_temp_define.Str();
1647 #else
1648 var.str += stream_temp_define.str();
1649 #endif
1650
1651 var.res = last_res;
1652 }
1653 else
1654 {
1655 CreateMsg(L"[def] unknown function/block/variable", item.function.name);
1656 }
1657 }
1658 }
1659 }
1660
1661
1662
1663
1664 template<class StreamType>
1665 void Generator<StreamType>::MakeTextFilter(Item & item)
1666 {
1667 if( filter_index >= filter_tab.size() )
1668 {
1669 CreateMsg(L"Generator exceeded allowed number of filters");
1670 return;
1671 }
1672
1673 StreamType * old_stream = output_stream;
1674 output_stream = filter_tab[filter_index];
1675 ClearStream(*output_stream);
1676
1677 filter_index += 1;
1678
1679 if( !item.item_tab.empty() )
1680 MakeText( *item.item_tab[0] ); // should be only one item - item_container
1681
1682 is_generating_filter = true;
1683
1684 if( old_stream )
1685 {
1686 Call(item.function, *old_stream, false, *output_stream);
1687 }
1688 else
1689 {
1690 Call(item.function, stream_temp1, true, *output_stream);
1691 ClearStream(stream_temp1);
1692 }
1693
1694 ClearStream(*output_stream);
1695 output_stream = old_stream;
1696 filter_index -= 1;
1697 }
1698
1699
1700
1701
1702
1703 /*
1704 although we are using a stack for [etc out] there is no need for the stack now
1705 because the output is only a one-level map (not nested structure)
1706 but in the future we can use more complicated class like PT::Space
1707 and then nested [ezc out] statements can product a better output
1708 */
1709 template<class StreamType>
1710 void Generator<StreamType>::MakeEzcOut(Item & item)
1711 {
1712 std::vector<std::wstring*> output_stream_names;
1713 StreamType * old_stream;
1714 bool stream_added = true;
1715
1716 if( ezc_out_stack_index >= ezc_out_stack_tab.size() )
1717 {
1718 CreateMsg(L"Generator exceeded allowed number of [ezc out] statements");
1719 return;
1720 }
1721
1722 /*
1723 if we encounter the first ezc_out statement without arguments e.g. [ezc out] or just [out]
1724 then we can simply ignore it
1725 */
1726 if( item.function.parameters.empty() && ezc_out_stack_index == 0 )
1727 stream_added = false;
1728
1729 if( stream_added )
1730 {
1731 old_stream = output_stream;
1732 output_stream = ezc_out_stack_tab[ezc_out_stack_index];
1733 ClearStream(*output_stream);
1734 ezc_out_stack_index += 1;
1735 }
1736
1737 if( !item.item_tab.empty() )
1738 MakeText( *item.item_tab[0] ); // should be only one item - item_container
1739
1740 if( stream_added )
1741 {
1742 CopyTmpStreamToOutputStreams(item.function, *output_stream, *old_stream);
1743 ClearStream(*output_stream);
1744 output_stream = old_stream;
1745 ezc_out_stack_index -= 1;
1746 }
1747 }
1748
1749
1750
1751 template<class StreamType>
1752 void Generator<StreamType>::MakeTextEzc(Item & item)
1753 {
1754 if( item.function.name == L"out" )
1755 MakeEzcOut(item);
1756
1757 // in the future we can use more builtin functions
1758 }
1759
1760
1761 template<class StreamType>
1762 void Generator<StreamType>::MakeTextReturn(Item & item)
1763 {
1764 last_res = false;
1765
1766 if( block_stack_index == 0 )
1767 {
1768 // the [return] statement is not called from a [block]
1769 CreateMsg(L"[return] should be called from a [block]");
1770 return;
1771 }
1772
1773 BlockStack & block_stack = block_stack_tab[block_stack_index - 1];
1774 block_stack.was_return = true;
1775
1776 if( item.has_function )
1777 {
1778 // output stream in [return] statement is ignored (we use only the stream produced by the whole block)
1779 // this Call() sets last_res which is used later when we return to CallBlock()
1780 Call(item.function, stream_temp1, false, empty_stream);
1781 ClearStream(stream_temp1);
1782 }
1783 }
1784
1785
1786 template<class StreamType>
1787 bool Generator<StreamType>::LimitAchieved()
1788 {
1789 if( break_generating )
1790 return true;
1791
1792 if( current_item >= max_items )
1793 {
1794 break_generating = true;
1795 CreateMsg(L"Generator exceeded allowed number of elements");
1796 return true;
1797 }
1798
1799 if( stack_index >= stack_tab.size() )
1800 {
1801 break_generating = true;
1802 CreateMsg(L"Generator exceeded the stack size");
1803 return true;
1804 }
1805
1806 if( block_stack_index > 0 )
1807 {
1808 BlockStack & block_stack = block_stack_tab[block_stack_index - 1];
1809
1810 if( block_stack.was_return )
1811 return true;
1812 }
1813
1814 return false;
1815 }
1816
1817
1818 template<class StreamType>
1819 void Generator<StreamType>::MakeText(Item & item)
1820 {
1821 if( LimitAchieved() )
1822 return;
1823
1824 current_item += 1;
1825 stack_index += 1;
1826 is_generating_for = false;
1827 is_generating_if = false;
1828 is_generating_normal = false;
1829 is_generating_filter = false;
1830
1831 stack_tab[stack_index-1].Clear();
1832 stack_tab[stack_index-1].item = &item;
1833
1834 if ( item.type == Item::item_text ) MakeItemText(item);
1835 else if( item.type == Item::item_container )MakeTextContainer(item);
1836 else if( item.type == Item::item_function ) MakeTextNormal(item);
1837 else if( item.type == Item::item_if ) MakeTextIf(item);
1838 else if( item.type == Item::item_def ) MakeTextDefine(item);
1839 else if( item.type == Item::item_for ) MakeTextFor(item);
1840 else if( item.type == Item::item_filter ) MakeTextFilter(item);
1841 else if( item.type == Item::item_ezc ) MakeTextEzc(item);
1842 else if( item.type == Item::item_return ) MakeTextReturn(item);
1843 else if( item.type == Item::item_err )
1844 CreateMsg(L"a wrong directive");
1845
1846 RemoveStackFunData(stack_tab[stack_index-1]);
1847 stack_index -=1;
1848 }
1849
1850
1851
1852
1853 } // namespace Ezc
1854
1855
1856 #endif
1857
1858

svnadmin@ttmath.org
ViewVC Help
Powered by ViewVC 1.2.1