tests: xor peephole optimization regression test
[xonotic/gmqcc.git] / ast.h
1 #ifndef GMQCC_AST_HDR
2 #define GMQCC_AST_HDR
3 #include <vector>
4 #include "ir.h"
5
6 typedef uint16_t ast_flag_t;
7
8 /* Note: I will not be using a _t suffix for the
9  * "main" ast node types for now.
10  */
11
12 struct ast_node;
13 struct ast_expression;
14 struct ast_value;
15 struct ast_function;
16 struct ast_block;
17 struct ast_binary;
18 struct ast_store;
19 struct ast_binstore;
20 struct ast_entfield;
21 struct ast_ifthen;
22 struct ast_ternary;
23 struct ast_loop;
24 struct ast_call;
25 struct ast_unary;
26 struct ast_return;
27 struct ast_member;
28 struct ast_array_index;
29 struct ast_breakcont;
30 struct ast_switch;
31 struct ast_label;
32 struct ast_goto;
33 struct ast_argpipe;
34 struct ast_state;
35
36 enum {
37     AST_FLAG_VARIADIC       = 1 << 0,
38     AST_FLAG_NORETURN       = 1 << 1,
39     AST_FLAG_INLINE         = 1 << 2,
40     AST_FLAG_INITIALIZED    = 1 << 3,
41     AST_FLAG_DEPRECATED     = 1 << 4,
42     AST_FLAG_INCLUDE_DEF    = 1 << 5,
43     AST_FLAG_IS_VARARG      = 1 << 6,
44     AST_FLAG_ALIAS          = 1 << 7,
45     AST_FLAG_ERASEABLE      = 1 << 8,
46     AST_FLAG_NOERASE        = 1 << 9, /* Never allow it to be erased, even if ERASEABLE is present */
47     AST_FLAG_ACCUMULATE     = 1 << 10,
48
49     /* An array declared as []
50      * so that the size is taken from the initializer
51      */
52     AST_FLAG_ARRAY_INIT     = 1 << 11,
53
54     AST_FLAG_FINAL_DECL     = 1 << 12,
55
56     /* Several coverage options
57      * AST_FLAG_COVERAGE means there was an explicit [[coverage]] attribute,
58      * which will overwrite the default set via the commandline switches.
59      * BLOCK_COVERAGE inserts coverage() calls into every basic block.
60      * In the future there might be more options like tracking variable access
61      * by creating get/set wrapper functions.
62      */
63     AST_FLAG_COVERAGE       = 1 << 13,
64     AST_FLAG_BLOCK_COVERAGE = 1 << 14,
65
66     /*
67      * Propagates norefness to the IR so the unused (read/write) check can be
68      * more intelligently done.
69      */
70     AST_FLAG_NOREF          = 1 << 15,
71
72     AST_FLAG_LAST,
73     AST_FLAG_TYPE_MASK      = (AST_FLAG_VARIADIC | AST_FLAG_NORETURN),
74     AST_FLAG_COVERAGE_MASK  = (AST_FLAG_BLOCK_COVERAGE)
75 };
76
77 enum {
78     TYPE_ast_node,        /*  0 */
79     TYPE_ast_expression,  /*  1 */
80     TYPE_ast_value,       /*  2 */
81     TYPE_ast_function,    /*  3 */
82     TYPE_ast_block,       /*  4 */
83     TYPE_ast_binary,      /*  5 */
84     TYPE_ast_store,       /*  6 */
85     TYPE_ast_binstore,    /*  7 */
86     TYPE_ast_entfield,    /*  8 */
87     TYPE_ast_ifthen,      /*  9 */
88     TYPE_ast_ternary,     /* 10 */
89     TYPE_ast_loop,        /* 11 */
90     TYPE_ast_call,        /* 12 */
91     TYPE_ast_unary,       /* 13 */
92     TYPE_ast_return,      /* 14 */
93     TYPE_ast_member,      /* 15 */
94     TYPE_ast_array_index, /* 16 */
95     TYPE_ast_breakcont,   /* 17 */
96     TYPE_ast_switch,      /* 18 */
97     TYPE_ast_label,       /* 19 */
98     TYPE_ast_goto,        /* 20 */
99     TYPE_ast_argpipe,     /* 21 */
100     TYPE_ast_state        /* 22 */
101 };
102
103 #define ast_istype(x, t) ( (x)->m_node_type == (TYPE_##t) )
104
105 struct ast_node
106 {
107     ast_node() = delete;
108     ast_node(lex_ctx_t, int nodetype);
109     virtual ~ast_node();
110
111     lex_ctx_t m_context;
112     /* I don't feel comfortable using keywords like 'delete' as names... */
113     int              m_node_type;
114     /* keep_node: if a node contains this node, 'keep_node'
115      * prevents its dtor from destroying this node as well.
116      */
117     bool             m_keep_node;
118     bool             m_side_effects;
119
120     void propagateSideEffects(const ast_node *other);
121 };
122
123 #define ast_unref(x) do        \
124 {                              \
125     if (! (x)->m_keep_node ) { \
126         delete (x);            \
127     }                          \
128 } while(0)
129
130 enum class ast_copy_type_t { value };
131 static const ast_copy_type_t ast_copy_type = ast_copy_type_t::value;
132
133 /* TODO: the codegen function should take an output-type parameter
134  * indicating whether a variable, type, label etc. is expected, and
135  * an environment!
136  * Then later an ast_ident could have a codegen using this to figure
137  * out what to look for.
138  * eg. in code which uses a not-yet defined variable, the expression
139  * would take an ast_ident, and the codegen would be called with
140  * type `expression`, so the ast_ident's codegen would search for
141  * variables through the environment (or functions, constants...).
142  */
143 struct ast_expression : ast_node {
144     ast_expression() = delete;
145     ast_expression(lex_ctx_t ctx, int nodetype, qc_type vtype);
146     ast_expression(lex_ctx_t ctx, int nodetype);
147     ~ast_expression();
148
149     ast_expression(ast_copy_type_t, const ast_expression&);
150     ast_expression(ast_copy_type_t, lex_ctx_t ctx, const ast_expression&);
151     ast_expression(ast_copy_type_t, int nodetype, const ast_expression&);
152     ast_expression(ast_copy_type_t, int nodetype, lex_ctx_t ctx, const ast_expression&);
153
154     static ast_expression *shallowType(lex_ctx_t ctx, qc_type vtype);
155
156     bool compareType(const ast_expression &other) const;
157     void adoptType(const ast_expression &other);
158
159     qc_type                 m_vtype = TYPE_VOID;
160     ast_expression         *m_next = nullptr;
161     /* arrays get a member-count */
162     size_t                  m_count = 0;
163     std::vector<std::unique_ptr<ast_value>> m_type_params;
164
165     ast_flag_t              m_flags = 0;
166     /* void foo(string...) gets varparam set as a restriction
167      * for variadic parameters
168      */
169     ast_expression         *m_varparam = nullptr;
170     /* The codegen functions should store their output values
171      * so we can call it multiple times without re-evaluating.
172      * Store lvalue and rvalue seperately though. So that
173      * ast_entfield for example can generate both if required.
174      */
175     ir_value               *m_outl = nullptr;
176     ir_value               *m_outr = nullptr;
177
178     virtual bool codegen(ast_function *current, bool lvalue, ir_value **out);
179 };
180
181 /* Value
182  *
183  * Types are also values, both have a type and a name.
184  * especially considering possible constructs like typedefs.
185  * typedef float foo;
186  * is like creating a 'float foo', foo serving as the type's name.
187  */
188 union basic_value_t {
189     qcfloat_t     vfloat;
190     int           vint;
191     vec3_t        vvec;
192     const char   *vstring;
193     int           ventity;
194     ast_function *vfunc;
195     ast_value    *vfield;
196 };
197
198 struct ast_value : ast_expression
199 {
200     ast_value() = delete;
201     ast_value(lex_ctx_t ctx, const std::string &name, qc_type qctype);
202     ~ast_value();
203
204     ast_value(ast_copy_type_t, const ast_expression&, const std::string&);
205     ast_value(ast_copy_type_t, const ast_value&);
206     ast_value(ast_copy_type_t, const ast_value&, const std::string&);
207
208     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
209
210     void addParam(ast_value*);
211
212     bool generateGlobal(ir_builder*, bool isfield);
213     bool generateLocal(ir_function*, bool param);
214     bool generateAccessors(ir_builder*);
215
216     std::string m_name;
217     std::string m_desc;
218
219     const char *m_argcounter = nullptr;
220
221     int m_cvq = CV_NONE;     /* const/var qualifier */
222     bool m_isfield = false; /* this declares a field */
223     bool m_isimm = false;   /* an immediate, not just const */
224     bool m_hasvalue = false;
225     bool m_inexact = false; /* inexact coming from folded expression */
226     basic_value_t m_constval;
227     /* for TYPE_ARRAY we have an optional vector
228      * of constants when an initializer list
229      * was provided.
230      */
231     std::vector<basic_value_t> m_initlist;
232
233     ir_value *m_ir_v = nullptr;
234     std::vector<ir_value*> m_ir_values;
235     size_t m_ir_value_count = 0;
236
237     /* ONLY for arrays in progs version up to 6 */
238     ast_value *m_setter = nullptr;
239     ast_value *m_getter = nullptr;
240
241     bool m_intrinsic = false; /* true if associated with intrinsic */
242
243 private:
244     bool generateGlobalFunction(ir_builder*);
245     bool generateGlobalField(ir_builder*);
246     ir_value *prepareGlobalArray(ir_builder*);
247     bool setGlobalArray();
248     bool checkArray(const ast_value &array) const;
249 };
250
251 void ast_type_to_string(const ast_expression *e, char *buf, size_t bufsize);
252
253 enum ast_binary_ref {
254     AST_REF_NONE  = 0,
255     AST_REF_LEFT  = 1 << 1,
256     AST_REF_RIGHT = 1 << 2,
257     AST_REF_ALL   = (AST_REF_LEFT | AST_REF_RIGHT)
258 };
259
260
261 /* Binary
262  *
263  * A value-returning binary expression.
264  */
265 struct ast_binary : ast_expression
266 {
267     ast_binary() = delete;
268     ast_binary(lex_ctx_t ctx, int op, ast_expression *l, ast_expression *r);
269     ~ast_binary();
270
271     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
272
273     int m_op;
274     ast_expression *m_left;
275     ast_expression *m_right;
276     ast_binary_ref m_refs;
277     bool m_right_first;
278 };
279
280 /* Binstore
281  *
282  * An assignment including a binary expression with the source as left operand.
283  * Eg. a += b; is a binstore { INSTR_STORE, INSTR_ADD, a, b }
284  */
285 struct ast_binstore : ast_expression
286 {
287     ast_binstore() = delete;
288     ast_binstore(lex_ctx_t ctx, int storeop, int mathop, ast_expression *l, ast_expression *r);
289     ~ast_binstore();
290
291     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
292
293     int m_opstore;
294     int m_opbin;
295     ast_expression *m_dest;
296     ast_expression *m_source;
297     /* for &~= which uses the destination in a binary in source we can use this */
298     bool m_keep_dest;
299 };
300
301 /* Unary
302  *
303  * Regular unary expressions: not,neg
304  */
305 struct ast_unary : ast_expression
306 {
307     ast_unary() = delete;
308     ~ast_unary();
309
310     static ast_unary* make(lex_ctx_t ctx, int op, ast_expression *expr);
311
312     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
313
314     int m_op;
315     ast_expression *m_operand;
316
317 private:
318     ast_unary(lex_ctx_t ctx, int op, ast_expression *expr);
319 };
320
321 /* Return
322  *
323  * Make sure 'return' only happens at the end of a block, otherwise the IR
324  * will refuse to create further instructions.
325  * This should be honored by the parser.
326  */
327 struct ast_return : ast_expression
328 {
329     ast_return() = delete;
330     ast_return(lex_ctx_t ctx, ast_expression *expr);
331     ~ast_return();
332
333     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
334
335     ast_expression *m_operand;
336 };
337
338 /* Entity-field
339  *
340  * This must do 2 things:
341  * -) Provide a way to fetch an entity field value. (Rvalue)
342  * -) Provide a pointer to an entity field. (Lvalue)
343  * The problem:
344  * In original QC, there's only a STORE via pointer, but
345  * no LOAD via pointer.
346  * So we must know beforehand if we are going to read or assign
347  * the field.
348  * For this we will have to extend the codegen() functions with
349  * a flag saying whether or not we need an L or an R-value.
350  */
351 struct ast_entfield : ast_expression
352 {
353     ast_entfield() = delete;
354     ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field);
355     ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype);
356     ~ast_entfield();
357
358     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
359
360     // The entity can come from an expression of course.
361     ast_expression *m_entity;
362     // As can the field, it just must result in a value of TYPE_FIELD
363     ast_expression *m_field;
364 };
365
366 /* Member access:
367  *
368  * For now used for vectors. If we get structs or unions
369  * we can have them handled here as well.
370  */
371 struct ast_member : ast_expression
372 {
373     static ast_member *make(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const std::string &name);
374     ~ast_member();
375
376     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
377
378     ast_expression *m_owner;
379     unsigned int m_field;
380     std::string m_name;
381     bool m_rvalue;
382
383 private:
384     ast_member() = delete;
385     ast_member(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const std::string &name);
386 };
387
388 /* Array index access:
389  *
390  * QC forces us to take special action on arrays:
391  * an ast_store on an ast_array_index must not codegen the index,
392  * but call its setter - unless we have an instruction set which supports
393  * what we need.
394  * Any other array index access will be codegened to a call to the getter.
395  * In any case, accessing an element via a compiletime-constant index will
396  * result in quick access to that variable.
397  */
398 struct ast_array_index : ast_expression
399 {
400     static ast_array_index* make(lex_ctx_t ctx, ast_expression *array, ast_expression *index);
401     ~ast_array_index();
402
403     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
404
405     ast_expression *m_array;
406     ast_expression *m_index;
407 private:
408     ast_array_index() = delete;
409     ast_array_index(lex_ctx_t ctx, ast_expression *array, ast_expression *index);
410 };
411
412 /* Vararg pipe node:
413  *
414  * copy all varargs starting from a specific index
415  */
416 struct ast_argpipe : ast_expression
417 {
418     ast_argpipe() = delete;
419     ast_argpipe(lex_ctx_t ctx, ast_expression *index);
420
421     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
422
423     ~ast_argpipe();
424     ast_expression *m_index;
425 };
426
427 /* Store
428  *
429  * Stores left<-right and returns left.
430  * Specialized binary expression node
431  */
432 struct ast_store : ast_expression
433 {
434     ast_store() = delete;
435     ast_store(lex_ctx_t ctx, int op, ast_expression *d, ast_expression *s);
436     ~ast_store();
437
438     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
439
440     int m_op;
441     ast_expression *m_dest;
442     ast_expression *m_source;
443 };
444
445 /* If
446  *
447  * A general 'if then else' statement, either side can be nullptr and will
448  * thus be omitted. It is an error for *both* cases to be nullptr at once.
449  *
450  * During its 'codegen' it'll be changing the ast_function's block.
451  *
452  * An if is also an "expression". Its codegen will put nullptr into the
453  * output field though. For ternary expressions an ast_ternary will be
454  * added.
455  */
456 struct ast_ifthen : ast_expression
457 {
458     ast_ifthen() = delete;
459     ast_ifthen(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
460     ~ast_ifthen();
461
462     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
463
464     ast_expression *m_cond;
465     /* It's all just 'expressions', since an ast_block is one too. */
466     ast_expression *m_on_true;
467     ast_expression *m_on_false;
468 };
469
470 /* Ternary expressions...
471  *
472  * Contrary to 'if-then-else' nodes, ternary expressions actually
473  * return a value, otherwise they behave the very same way.
474  * The difference in 'codegen' is that it'll return the value of
475  * a PHI node.
476  *
477  * The other difference is that in an ast_ternary, NEITHER side
478  * must be nullptr, there's ALWAYS an else branch.
479  *
480  * This is the only ast_node beside ast_value which contains
481  * an ir_value. Theoretically we don't need to remember it though.
482  */
483 struct ast_ternary : ast_expression
484 {
485     ast_ternary() = delete;
486     ast_ternary(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse);
487     ~ast_ternary();
488
489     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
490
491     ast_expression *m_cond;
492     /* It's all just 'expressions', since an ast_block is one too. */
493     ast_expression *m_on_true;
494     ast_expression *m_on_false;
495 };
496
497 /* A general loop node
498  *
499  * For convenience it contains 4 parts:
500  * -) (ini) = initializing expression
501  * -) (pre) = pre-loop condition
502  * -) (pst) = post-loop condition
503  * -) (inc) = "increment" expression
504  * The following is a psudo-representation of this loop
505  * note that '=>' bears the logical meaning of "implies".
506  * (a => b) equals (!a || b)
507
508 {ini};
509 while (has_pre => {pre})
510 {
511     {body};
512
513 continue:      // a 'continue' will jump here
514     if (has_pst => {pst})
515         break;
516
517     {inc};
518 }
519  */
520 struct ast_loop : ast_expression
521 {
522     ast_loop() = delete;
523     ast_loop(lex_ctx_t ctx,
524              ast_expression *initexpr,
525              ast_expression *precond, bool pre_not,
526              ast_expression *postcond, bool post_not,
527              ast_expression *increment,
528              ast_expression *body);
529     ~ast_loop();
530
531     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
532
533     ast_expression *m_initexpr;
534     ast_expression *m_precond;
535     ast_expression *m_postcond;
536     ast_expression *m_increment;
537     ast_expression *m_body;
538     /* For now we allow a seperate flag on whether or not the condition
539      * is supposed to be true or false.
540      * That way, the parser can generate a 'while not(!x)' for `while(x)`
541      * if desired, which is useful for the new -f{true,false}-empty-strings
542      * flag.
543      */
544     bool m_pre_not;
545     bool m_post_not;
546 };
547
548 /* Break/Continue
549  */
550 struct ast_breakcont : ast_expression
551 {
552     ast_breakcont() = delete;
553     ast_breakcont(lex_ctx_t ctx, bool iscont, unsigned int levels);
554     ~ast_breakcont();
555
556     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
557
558
559     bool         m_is_continue;
560     unsigned int m_levels;
561 };
562
563 /* Switch Statements
564  *
565  * A few notes about this: with the original QCVM, no real optimization
566  * is possible. The SWITCH instruction set isn't really helping a lot, since
567  * it only collapes the EQ and IF instructions into one.
568  * Note: Declaring local variables inside caseblocks is normal.
569  * Since we don't have to deal with a stack there's no unnatural behaviour to
570  * be expected from it.
571  * TODO: Ticket #20
572  */
573 struct ast_switch_case {
574     ast_expression *m_value; /* #20 will replace this */
575     ast_expression *m_code;
576 };
577
578 struct ast_switch : ast_expression
579 {
580     ast_switch() = delete;
581     ast_switch(lex_ctx_t ctx, ast_expression *op);
582     ~ast_switch();
583
584     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
585
586     ast_expression *m_operand;
587     std::vector<ast_switch_case> m_cases;
588 };
589
590
591 /* Label nodes
592  *
593  * Introduce a label which can be used together with 'goto'
594  */
595 struct ast_label : ast_expression
596 {
597     ast_label() = delete;
598     ast_label(lex_ctx_t ctx, const std::string &name, bool undefined);
599     ~ast_label();
600
601     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
602
603     std::string m_name;
604     ir_block *m_irblock;
605     std::vector<ast_goto*> m_gotos;
606
607     /* means it has not yet been defined */
608     bool m_undefined;
609
610 private:
611     void registerGoto(ast_goto*);
612     friend struct ast_goto;
613 };
614
615 /* GOTO nodes
616  *
617  * Go to a label, the label node is filled in at a later point!
618  */
619 struct ast_goto : ast_expression
620 {
621     ast_goto() = delete;
622     ast_goto(lex_ctx_t ctx, const std::string &name);
623     ~ast_goto();
624
625     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
626
627     void setLabel(ast_label*);
628
629     std::string m_name;
630     ast_label *m_target;
631     ir_block *m_irblock_from;
632 };
633
634 /* STATE node
635  *
636  * For frame/think state updates: void foo() [framenum, nextthink] {}
637  */
638 struct ast_state : ast_expression
639 {
640     ast_state() = delete;
641     ast_state(lex_ctx_t ctx, ast_expression *frame, ast_expression *think);
642     ~ast_state();
643
644     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
645
646     ast_expression *m_framenum;
647     ast_expression *m_nextthink;
648 };
649
650 /* CALL node
651  *
652  * Contains an ast_expression as target, rather than an ast_function/value.
653  * Since it's how QC works, every ast_function has an ast_value
654  * associated anyway - in other words, the VM contains function
655  * pointers for every function anyway. Thus, this node will call
656  * expression.
657  * Additionally it contains a list of ast_expressions as parameters.
658  * Since calls can return values, an ast_call is also an ast_expression.
659  */
660 struct ast_call : ast_expression
661 {
662     ast_call() = delete;
663     static ast_call *make(lex_ctx_t, ast_expression*);
664     ~ast_call();
665
666     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
667
668     bool checkTypes(ast_expression *this_func_va_type) const;
669
670     ast_expression *m_func;
671     std::vector<ast_expression *> m_params;
672     ast_expression *m_va_count;
673
674 private:
675     ast_call(lex_ctx_t ctx, ast_expression *funcexpr);
676     bool checkVararg(ast_expression *va_type, ast_expression *exp_type) const;
677 };
678
679 /* Blocks
680  *
681  */
682 struct ast_block : ast_expression
683 {
684     ast_block() = delete;
685     ast_block(lex_ctx_t ctx);
686     ~ast_block();
687
688     bool codegen(ast_function *current, bool lvalue, ir_value **out) override;
689
690     std::vector<ast_value*>      m_locals;
691     std::vector<ast_expression*> m_exprs;
692     std::vector<ast_expression*> m_collect;
693
694     void setType(const ast_expression &from);
695     bool GMQCC_WARN addExpr(ast_expression*);
696     void collect(ast_expression*);
697 };
698
699 /* Function
700  *
701  * Contains a list of blocks... at least in theory.
702  * Usually there's just the main block, other blocks are inside that.
703  *
704  * Technically, functions don't need to be an AST node, since we have
705  * neither functions inside functions, nor lambdas, and function
706  * pointers could just work with a name. However, this way could be
707  * more flexible, and adds no real complexity.
708  *
709  * The destructor will NOT delete the underlying ast_value
710  *
711  */
712 struct ast_function : ast_node
713 {
714     ast_function() = delete;
715     static ast_function *make(lex_ctx_t ctx, const std::string &name, ast_value *vtype);
716     ~ast_function();
717
718     const char* makeLabel(const char *prefix);
719     virtual bool generateFunction(ir_builder*);
720
721     ast_value  *m_function_type = nullptr;
722     std::string m_name;
723
724     int m_builtin = 0;
725
726     /* list of used-up names for statics without the count suffix */
727     std::vector<std::string> m_static_names;
728     /* number of static variables, by convention this includes the
729      * ones without the count-suffix - remember this when dealing
730      * with savegames. uint instead of size_t as %zu in printf is
731      * C99, so no windows support. */
732     unsigned int m_static_count = 0;
733
734     ir_function *m_ir_func = nullptr;
735     ir_block *m_curblock = nullptr;
736     std::vector<ir_block*> m_breakblocks;
737     std::vector<ir_block*> m_continueblocks;
738
739     size_t m_labelcount = 0;
740     /* in order for thread safety - for the optional
741      * channel abesed multithreading... keeping a buffer
742      * here to use in ast_function_label.
743      */
744     std::vector<std::unique_ptr<ast_block>> m_blocks;
745     std::unique_ptr<ast_value> m_varargs;
746     std::unique_ptr<ast_value> m_argc;
747     ast_value *m_fixedparams = nullptr; // these use unref()
748     ast_value *m_return_value = nullptr;
749
750 private:
751     ast_function(lex_ctx_t ctx, const std::string &name, ast_value *vtype);
752
753     char m_labelbuf[64];
754 };
755
756 /*
757  * If the condition creates a situation where this becomes -1 size it means there are
758  * more AST_FLAGs than the type ast_flag_t is capable of holding. So either eliminate
759  * the AST flag count or change the ast_flag_t typedef to a type large enough to accomodate
760  * all the flags.
761  */
762 typedef int static_assert_is_ast_flag_safe [((AST_FLAG_LAST) <= (ast_flag_t)(-1)) ? 1 : -1];
763 #endif