1 /**
2  * MojoShader; generate shader programs from bytecode of compiled
3  *  Direct3D shaders.
4  *
5  * Please see the file LICENSE.txt in the source's root directory.
6  *
7  *  This file written by Ryan C. Gordon.
8  */
9 
10 // !!! FIXME: this needs to be split into separate source files:
11 // !!! FIXME:  parse, AST, IR, etc. The problem is we need to deal with the
12 // !!! FIXME:  "Context" struct being passed around everywhere.
13 
14 #define __MOJOSHADER_INTERNAL__ 1
15 #include "mojoshader_internal.h"
16 
17 #if DEBUG_COMPILER_PARSER
18 #define LEMON_SUPPORT_TRACING 1
19 #endif
20 
21 // !!! FIXME: I'd like to lose this. It's really inefficient. Just keep a
22 // !!! FIXME:  (tail) on these list structures instead?
23 #define REVERSE_LINKED_LIST(typ, head) { \
24     if ((head) && (head->next)) { \
25         typ *tmp = NULL; \
26         typ *tmp1 = NULL; \
27         while (head != NULL) { \
28             tmp = head; \
29             head = head->next; \
30             tmp->next = tmp1; \
31             tmp1 = tmp; \
32         } \
33         head = tmp; \
34     } \
35 }
36 
operator_is_unary(const MOJOSHADER_astNodeType op)37 static inline int operator_is_unary(const MOJOSHADER_astNodeType op)
38 {
39     return ( (op > MOJOSHADER_AST_OP_START_RANGE_UNARY) &&
40              (op < MOJOSHADER_AST_OP_END_RANGE_UNARY) );
41 } // operator_is_unary
42 
operator_is_binary(const MOJOSHADER_astNodeType op)43 static inline int operator_is_binary(const MOJOSHADER_astNodeType op)
44 {
45     return ( (op > MOJOSHADER_AST_OP_START_RANGE_BINARY) &&
46              (op < MOJOSHADER_AST_OP_END_RANGE_BINARY) );
47 } // operator_is_binary
48 
operator_is_ternary(const MOJOSHADER_astNodeType op)49 static inline int operator_is_ternary(const MOJOSHADER_astNodeType op)
50 {
51     return ( (op > MOJOSHADER_AST_OP_START_RANGE_TERNARY) &&
52              (op < MOJOSHADER_AST_OP_END_RANGE_TERNARY) );
53 } // operator_is_ternary
54 
55 
56 typedef union TokenData
57 {
58     int64 i64;
59     double dbl;
60     const char *string;
61     const MOJOSHADER_astDataType *datatype;
62 } TokenData;
63 
64 
65 // This tracks data types and variables, and notes when they enter/leave scope.
66 
67 typedef struct SymbolScope
68 {
69     const char *symbol;
70     const MOJOSHADER_astDataType *datatype;
71     int index;  // unique positive value within a function, negative if global.
72     int referenced;  // non-zero if something looked for this symbol (so we know it's used).
73     struct SymbolScope *next;
74 } SymbolScope;
75 
76 typedef struct SymbolMap
77 {
78     HashTable *hash;
79     SymbolScope *scope;
80 } SymbolMap;
81 
82 typedef struct LoopLabels
83 {
84     int start;  // loop's start label during IR build.
85     int end;    // loop's end label during IR build.
86     struct LoopLabels *prev;
87 } LoopLabels;
88 
89 // Compile state, passed around all over the place.
90 
91 typedef struct Context
92 {
93     int isfail;
94     int out_of_memory;
95     MOJOSHADER_malloc malloc;
96     MOJOSHADER_free free;
97     void *malloc_data;
98     ErrorList *errors;
99     ErrorList *warnings;
100     StringCache *strcache;
101     const char *sourcefile;  // current source file that we're parsing.
102     unsigned int sourceline; // current line in sourcefile that we're parsing.
103     SymbolMap usertypes;
104     SymbolMap variables;
105     MOJOSHADER_astNode *ast;  // Abstract Syntax Tree
106     const char *source_profile;
107     int is_func_scope; // non-zero if semantic analysis is in function scope.
108     int loop_count;
109     int switch_count;
110     int var_index;  // next variable index for current function.
111     int global_var_index;  // next variable index for global scope.
112     int user_func_index;  // next function index for user-defined functions.
113     int intrinsic_func_index;  // next function index for intrinsic functions.
114 
115     MOJOSHADER_irStatement **ir;  // intermediate representation.
116     int ir_label_count;  // next unused IR label index.
117     int ir_temp_count;  // next unused IR temporary value index.
118     int ir_end; // current function's end label during IR build.
119     int ir_ret; // temp that holds current function's retval during IR build.
120     LoopLabels *ir_loop;  // nested loop boundary labels during IR build.
121 
122     // Cache intrinsic types for fast lookup and consistent pointer values.
123     MOJOSHADER_astDataType dt_none;
124     MOJOSHADER_astDataType dt_bool;
125     MOJOSHADER_astDataType dt_int;
126     MOJOSHADER_astDataType dt_uint;
127     MOJOSHADER_astDataType dt_float;
128     MOJOSHADER_astDataType dt_float_snorm;
129     MOJOSHADER_astDataType dt_float_unorm;
130     MOJOSHADER_astDataType dt_half;
131     MOJOSHADER_astDataType dt_double;
132     MOJOSHADER_astDataType dt_string;
133     MOJOSHADER_astDataType dt_sampler1d;
134     MOJOSHADER_astDataType dt_sampler2d;
135     MOJOSHADER_astDataType dt_sampler3d;
136     MOJOSHADER_astDataType dt_samplercube;
137     MOJOSHADER_astDataType dt_samplerstate;
138     MOJOSHADER_astDataType dt_samplercompstate;
139     MOJOSHADER_astDataType dt_buf_bool;
140     MOJOSHADER_astDataType dt_buf_int;
141     MOJOSHADER_astDataType dt_buf_uint;
142     MOJOSHADER_astDataType dt_buf_half;
143     MOJOSHADER_astDataType dt_buf_float;
144     MOJOSHADER_astDataType dt_buf_double;
145     MOJOSHADER_astDataType dt_buf_float_snorm;
146     MOJOSHADER_astDataType dt_buf_float_unorm;
147 
148     Buffer *garbage;  // this is sort of hacky.
149 } Context;
150 
151 
152 // !!! FIXME: cut and paste between every damned source file follows...
153 // !!! FIXME: We need to make some sort of ContextBase that applies to all
154 // !!! FIXME:  files and move this stuff to mojoshader_common.c ...
155 
156 // Convenience functions for allocators...
157 
out_of_memory(Context * ctx)158 static inline void out_of_memory(Context *ctx)
159 {
160     ctx->isfail = ctx->out_of_memory = 1;
161 } // out_of_memory
162 
Malloc(Context * ctx,const size_t len)163 static inline void *Malloc(Context *ctx, const size_t len)
164 {
165     void *retval = ctx->malloc((int) len, ctx->malloc_data);
166     if (retval == NULL)
167         out_of_memory(ctx);
168     return retval;
169 } // Malloc
170 
StrDup(Context * ctx,const char * str)171 static inline char *StrDup(Context *ctx, const char *str)
172 {
173     char *retval = (char *) Malloc(ctx, strlen(str) + 1);
174     if (retval != NULL)
175         strcpy(retval, str);
176     return retval;
177 } // StrDup
178 
Free(Context * ctx,void * ptr)179 static inline void Free(Context *ctx, void *ptr)
180 {
181     ctx->free(ptr, ctx->malloc_data);
182 } // Free
183 
MallocBridge(int bytes,void * data)184 static void *MallocBridge(int bytes, void *data)
185 {
186     return Malloc((Context *) data, (size_t) bytes);
187 } // MallocBridge
188 
FreeBridge(void * ptr,void * data)189 static void FreeBridge(void *ptr, void *data)
190 {
191     Free((Context *) data, ptr);
192 } // FreeBridge
193 
194 static void failf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
failf(Context * ctx,const char * fmt,...)195 static void failf(Context *ctx, const char *fmt, ...)
196 {
197     ctx->isfail = 1;
198     if (ctx->out_of_memory)
199         return;
200 
201     va_list ap;
202     va_start(ap, fmt);
203     errorlist_add_va(ctx->errors, ctx->sourcefile, ctx->sourceline, fmt, ap);
204     va_end(ap);
205 } // failf
206 
fail(Context * ctx,const char * reason)207 static inline void fail(Context *ctx, const char *reason)
208 {
209     failf(ctx, "%s", reason);
210 } // fail
211 
212 static void warnf(Context *ctx, const char *fmt, ...) ISPRINTF(2,3);
warnf(Context * ctx,const char * fmt,...)213 static void warnf(Context *ctx, const char *fmt, ...)
214 {
215     if (ctx->out_of_memory)
216         return;
217 
218     va_list ap;
219     va_start(ap, fmt);
220     errorlist_add_va(ctx->warnings, ctx->sourcefile, ctx->sourceline, fmt, ap);
221     va_end(ap);
222 } // warnf
223 
warn(Context * ctx,const char * reason)224 static inline void warn(Context *ctx, const char *reason)
225 {
226     warnf(ctx, "%s", reason);
227 } // warn
228 
isfail(const Context * ctx)229 static inline int isfail(const Context *ctx)
230 {
231     return ctx->isfail;
232 } // isfail
233 
234 
symbolmap_nuke(const void * k,const void * v,void * d)235 static void symbolmap_nuke(const void *k, const void *v, void *d) {/*no-op*/}
236 
create_symbolmap(Context * ctx,SymbolMap * map)237 static int create_symbolmap(Context *ctx, SymbolMap *map)
238 {
239     // !!! FIXME: should compare string pointer, with string in cache.
240     map->scope = NULL;
241     map->hash = hash_create(ctx, hash_hash_string, hash_keymatch_string,
242                             symbolmap_nuke, 1, MallocBridge, FreeBridge, ctx);
243     return (map->hash != NULL);
244 } // create_symbolmap
245 
datatypes_match(const MOJOSHADER_astDataType * a,const MOJOSHADER_astDataType * b)246 static int datatypes_match(const MOJOSHADER_astDataType *a,
247                            const MOJOSHADER_astDataType *b)
248 {
249     int i;
250 
251     if (a == b)
252         return 1;
253     else if (a->type != b->type)
254         return 0;
255 
256     switch (a->type)
257     {
258         case MOJOSHADER_AST_DATATYPE_STRUCT:
259             if (a->structure.member_count != b->structure.member_count)
260                 return 0;
261             for (i = 0; i < a->structure.member_count; i++)
262             {
263                 if (!datatypes_match(a->structure.members[i].datatype,
264                                      b->structure.members[i].datatype))
265                     return 0;
266                 // stringcache'd, pointer compare is safe.
267                 else if (a->structure.members[i].identifier !=
268                          b->structure.members[i].identifier)
269                     return 0;
270             } // for
271             return 1;
272 
273         case MOJOSHADER_AST_DATATYPE_ARRAY:
274             if (a->array.elements != b->array.elements)
275                 return 0;
276             else if (!datatypes_match(a->array.base, b->array.base))
277                 return 0;
278             return 1;
279 
280         case MOJOSHADER_AST_DATATYPE_VECTOR:
281             if (a->vector.elements != b->vector.elements)
282                 return 0;
283             else if (!datatypes_match(a->vector.base, b->vector.base))
284                 return 0;
285             return 1;
286 
287         case MOJOSHADER_AST_DATATYPE_MATRIX:
288             if (a->matrix.rows != b->matrix.rows)
289                 return 0;
290             else if (a->matrix.columns != b->matrix.columns)
291                 return 0;
292             else if (!datatypes_match(a->matrix.base, b->matrix.base))
293                 return 0;
294             return 1;
295 
296         case MOJOSHADER_AST_DATATYPE_BUFFER:
297             return datatypes_match(a->buffer.base, b->buffer.base);
298 
299         case MOJOSHADER_AST_DATATYPE_FUNCTION:
300             if (a->function.num_params != b->function.num_params)
301                 return 0;
302             else if (a->function.intrinsic != b->function.intrinsic)
303                 return 0;
304             else if (!datatypes_match(a->function.retval, b->function.retval))
305                 return 0;
306             for (i = 0; i < a->function.num_params; i++)
307             {
308                 if (!datatypes_match(a->function.params[i], b->function.params[i]))
309                     return 0;
310             } // for
311             return 1;
312 
313         case MOJOSHADER_AST_DATATYPE_USER:
314             return 0;  // pointers must match, this clearly didn't.
315 
316         default:
317             assert(0 && "unexpected case");
318             return 0;
319     } // switch
320 
321     return 0;
322 } // datatypes_match
323 
push_symbol(Context * ctx,SymbolMap * map,const char * sym,const MOJOSHADER_astDataType * dt,const int index,const int check_dupes)324 static void push_symbol(Context *ctx, SymbolMap *map, const char *sym,
325                         const MOJOSHADER_astDataType *dt, const int index,
326                         const int check_dupes)
327 {
328     if (ctx->out_of_memory)
329         return;
330 
331     // Decide if this symbol is defined, and if it's in the current scope.
332     SymbolScope *item = NULL;
333     const void *value = NULL;
334     if ((check_dupes) && (sym != NULL) && (hash_find(map->hash, sym, &value)))
335     {
336         // check the current scope for a dupe.
337         // !!! FIXME: note current scope's starting index, see if found
338         // !!! FIXME:  item is < index (and thus, a previous scope).
339         item = map->scope;
340         while ((item) && (item->symbol))
341         {
342             if ( ((const void *) item) == value )
343             {
344                 failf(ctx, "Symbol '%s' already defined", sym);
345                 return;
346             } // if
347             item = item->next;
348         } // while
349     } // if
350 
351     // Add the symbol to our map and scope stack.
352     item = (SymbolScope *) Malloc(ctx, sizeof (SymbolScope));
353     if (item == NULL)
354         return;
355 
356     if (sym != NULL)  // sym can be NULL if we're pushing a new scope.
357     {
358         if (hash_insert(map->hash, sym, item) == -1)
359         {
360             Free(ctx, item);
361             return;
362         } // if
363     } // if
364 
365     item->symbol = sym;  // cached strings, don't copy.
366     item->index = index;
367     item->datatype = dt;
368     item->referenced = 0;
369     item->next = map->scope;
370     map->scope = item;
371 } // push_symbol
372 
push_usertype(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt)373 static void push_usertype(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
374 {
375     if (sym != NULL)
376     {
377         MOJOSHADER_astDataType *userdt;
378         userdt = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*userdt));
379         if (userdt != NULL)
380         {
381             // !!! FIXME: this is hacky.
382             if (!buffer_append(ctx->garbage, &userdt, sizeof (userdt)))
383             {
384                 Free(ctx, userdt);
385                 return;
386             } // if
387 
388             userdt->type = MOJOSHADER_AST_DATATYPE_USER;
389             userdt->user.details = dt;
390             userdt->user.name = sym;
391 
392             dt = userdt;
393         } // if
394     } // if
395 
396     push_symbol(ctx, &ctx->usertypes, sym, dt, 0, 1);
397 } // push_usertype
398 
push_variable(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt)399 static inline void push_variable(Context *ctx, const char *sym, const MOJOSHADER_astDataType *dt)
400 {
401     int idx = 0;
402     if (sym != NULL)
403     {
404         // leave space for individual member indexes. The IR will need this.
405         int additional = 0;
406         if (dt->type == MOJOSHADER_AST_DATATYPE_STRUCT)
407             additional = dt->structure.member_count;
408         if (ctx->is_func_scope)
409         {
410             idx = ++ctx->var_index;  // these are positive.
411             ctx->var_index += additional;
412         } // if
413         else
414         {
415             idx = --ctx->global_var_index;  // these are negative.
416             ctx->global_var_index -= additional;
417         } // else
418     } // if
419 
420     push_symbol(ctx, &ctx->variables, sym, dt, idx, 1);
421 } // push_variable
422 
push_function(Context * ctx,const char * sym,const MOJOSHADER_astDataType * dt,const int just_declare)423 static int push_function(Context *ctx, const char *sym,
424                           const MOJOSHADER_astDataType *dt,
425                           const int just_declare)
426 {
427     // we don't have any reason to support nested functions at the moment,
428     //  so this would be a bug.
429     assert(!ctx->is_func_scope);
430     assert(dt->type == MOJOSHADER_AST_DATATYPE_FUNCTION);
431 
432     // Functions are always global, so no need to search scopes.
433     //  Functions overload, though, so we have to continue iterating to
434     //  see if it matches anything.
435     const void *value = NULL;
436     void *iter = NULL;
437     while (hash_iter(ctx->variables.hash, sym, &value, &iter))
438     {
439         // !!! FIXME: this breaks if you predeclare a function.
440         // !!! FIXME:  (a declare AFTER defining works, though.)
441         // there's already something called this.
442         SymbolScope *item = (SymbolScope *) value;
443         if (datatypes_match(dt, item->datatype))
444         {
445             if (!just_declare)
446                 failf(ctx, "Function '%s' already defined.", sym);
447             return item->index;
448         } // if
449     } // while
450 
451     int idx = 0;
452     if ((sym != NULL) && (dt != NULL))
453     {
454         if (!dt->function.intrinsic)
455             idx = ++ctx->user_func_index;  // these are positive.
456         else
457             idx = --ctx->intrinsic_func_index;  // these are negative.
458     } // if
459 
460     // push_symbol() doesn't check dupes, because we just did.
461     push_symbol(ctx, &ctx->variables, sym, dt, idx, 0);
462 
463     return idx;
464 } // push_function
465 
push_scope(Context * ctx)466 static inline void push_scope(Context *ctx)
467 {
468     push_usertype(ctx, NULL, NULL);
469     push_variable(ctx, NULL, NULL);
470 } // push_scope
471 
pop_symbol(Context * ctx,SymbolMap * map)472 static void pop_symbol(Context *ctx, SymbolMap *map)
473 {
474     SymbolScope *item = map->scope;
475     if (!item)
476         return;
477     if (item->symbol)
478         hash_remove(map->hash, item->symbol);
479     map->scope = item->next;
480     Free(ctx, item);
481 } // pop_symbol
482 
pop_symbol_scope(Context * ctx,SymbolMap * map)483 static void pop_symbol_scope(Context *ctx, SymbolMap *map)
484 {
485     while ((map->scope) && (map->scope->symbol))
486         pop_symbol(ctx, map);
487 
488     assert(map->scope != NULL);
489     assert(map->scope->symbol == NULL);
490     pop_symbol(ctx, map);
491 } // pop_symbol_scope
492 
pop_scope(Context * ctx)493 static inline void pop_scope(Context *ctx)
494 {
495     pop_symbol_scope(ctx, &ctx->usertypes);
496     pop_symbol_scope(ctx, &ctx->variables);
497 } // push_scope
498 
find_symbol(Context * ctx,SymbolMap * map,const char * sym,int * _index)499 static const MOJOSHADER_astDataType *find_symbol(Context *ctx, SymbolMap *map, const char *sym, int *_index)
500 {
501     const void *_item = NULL;
502     hash_find(map->hash, sym, &_item);
503     SymbolScope *item = (SymbolScope *) _item;
504     if (item != NULL)
505     {
506         item->referenced++;
507         if (_index != NULL)
508             *_index = item->index;
509     } // if
510     return item ? item->datatype : NULL;
511 } // find_symbol
512 
find_usertype(Context * ctx,const char * sym)513 static inline const MOJOSHADER_astDataType *find_usertype(Context *ctx, const char *sym)
514 {
515     return find_symbol(ctx, &ctx->usertypes, sym, NULL);
516 } // find_usertype
517 
find_variable(Context * ctx,const char * sym,int * _index)518 static inline const MOJOSHADER_astDataType *find_variable(Context *ctx, const char *sym, int *_index)
519 {
520     return find_symbol(ctx, &ctx->variables, sym, _index);
521 } // find_variable
522 
destroy_symbolmap(Context * ctx,SymbolMap * map)523 static void destroy_symbolmap(Context *ctx, SymbolMap *map)
524 {
525     while (map->scope)
526         pop_symbol(ctx, map);
527     hash_destroy(map->hash);
528 } // destroy_symbolmap
529 
530 
new_datatype_vector(Context * ctx,const MOJOSHADER_astDataType * dt,const int columns)531 static const MOJOSHADER_astDataType *new_datatype_vector(Context *ctx,
532                                             const MOJOSHADER_astDataType *dt,
533                                             const int columns)
534 {
535     MOJOSHADER_astDataType *retval;
536     retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
537     if (retval == NULL)
538         return NULL;
539 
540     // !!! FIXME: this is hacky.
541     // !!! FIXME:  I'd like to cache these anyhow and reuse types.
542     if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
543     {
544         Free(ctx, retval);
545         return NULL;
546     } // if
547 
548     if ((columns < 1) || (columns > 4))
549         fail(ctx, "Vector must have between 1 and 4 elements");
550 
551     retval->type = MOJOSHADER_AST_DATATYPE_VECTOR;
552     retval->vector.base = dt;
553     retval->vector.elements = columns;
554     return retval;
555 } // new_datatype_vector
556 
new_datatype_matrix(Context * ctx,const MOJOSHADER_astDataType * dt,const int rows,const int columns)557 static const MOJOSHADER_astDataType *new_datatype_matrix(Context *ctx,
558                                             const MOJOSHADER_astDataType *dt,
559                                             const int rows, const int columns)
560 {
561     MOJOSHADER_astDataType *retval;
562     // !!! FIXME: allocate enough for a matrix, but we need to cleanup things that copy without checking for subsize.
563     retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
564     if (retval == NULL)
565         return NULL;
566 
567     // !!! FIXME: this is hacky.
568     // !!! FIXME:  I'd like to cache these anyhow and reuse types.
569     if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
570     {
571         Free(ctx, retval);
572         return NULL;
573     } // if
574 
575     if ((rows < 1) || (rows > 4))
576         fail(ctx, "Matrix must have between 1 and 4 rows");
577     if ((columns < 1) || (columns > 4))
578         fail(ctx, "Matrix must have between 1 and 4 columns");
579 
580     retval->type = MOJOSHADER_AST_DATATYPE_MATRIX;
581     retval->matrix.base = dt;
582     retval->matrix.rows = rows;
583     retval->matrix.columns = columns;
584     return retval;
585 } // new_datatype_matrix
586 
587 
588 // !!! FIXME: move this to mojoshader_ast.c
589 // !!! FIXME: new_* and delete_* should take an allocator, not a context.
590 
591 // These functions are mostly for construction and cleanup of nodes in the
592 //  parse tree. Mostly this is simple allocation and initialization, so we
593 //  can do as little in the lemon code as possible, and then sort it all out
594 //  afterwards.
595 
596 #define NEW_AST_NODE(retval, cls, typ) \
597     cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
598     do { \
599         if (retval == NULL) { return NULL; } \
600         retval->ast.type = typ; \
601         retval->ast.filename = ctx->sourcefile; \
602         retval->ast.line = ctx->sourceline; \
603     } while (0)
604 
605 #define DELETE_AST_NODE(cls) do { \
606     if (!cls) return; \
607 } while (0)
608 
609 
610 static void delete_compilation_unit(Context*, MOJOSHADER_astCompilationUnit*);
611 static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt);
612 
new_identifier_expr(Context * ctx,const char * string)613 static MOJOSHADER_astExpression *new_identifier_expr(Context *ctx,
614                                                      const char *string)
615 {
616     NEW_AST_NODE(retval, MOJOSHADER_astExpressionIdentifier,
617                  MOJOSHADER_AST_OP_IDENTIFIER);
618     retval->datatype = NULL;
619     retval->identifier = string;  // cached; don't copy string.
620     retval->index = 0;
621     return (MOJOSHADER_astExpression *) retval;
622 } // new_identifier_expr
623 
new_callfunc_expr(Context * ctx,const char * identifier,MOJOSHADER_astArguments * args)624 static MOJOSHADER_astExpression *new_callfunc_expr(Context *ctx,
625                                         const char *identifier,
626                                         MOJOSHADER_astArguments *args)
627 {
628     NEW_AST_NODE(retval, MOJOSHADER_astExpressionCallFunction,
629                  MOJOSHADER_AST_OP_CALLFUNC);
630     MOJOSHADER_astExpression *expr = new_identifier_expr(ctx, identifier);
631     retval->datatype = NULL;
632     retval->identifier = (MOJOSHADER_astExpressionIdentifier *) expr;
633     retval->args = args;
634     return (MOJOSHADER_astExpression *) retval;
635 } // new_callfunc_expr
636 
new_constructor_expr(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astArguments * args)637 static MOJOSHADER_astExpression *new_constructor_expr(Context *ctx,
638                                             const MOJOSHADER_astDataType *dt,
639                                             MOJOSHADER_astArguments *args)
640 {
641     NEW_AST_NODE(retval, MOJOSHADER_astExpressionConstructor,
642                  MOJOSHADER_AST_OP_CONSTRUCTOR);
643     retval->datatype = dt;
644     retval->args = args;
645     return (MOJOSHADER_astExpression *) retval;
646 } // new_constructor_expr
647 
new_cast_expr(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astExpression * operand)648 static MOJOSHADER_astExpression *new_cast_expr(Context *ctx,
649                                             const MOJOSHADER_astDataType *dt,
650                                             MOJOSHADER_astExpression *operand)
651 {
652     NEW_AST_NODE(retval, MOJOSHADER_astExpressionCast, MOJOSHADER_AST_OP_CAST);
653     retval->datatype = dt;
654     retval->operand = operand;
655     return (MOJOSHADER_astExpression *) retval;
656 } // new_cast_expr
657 
new_unary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * operand)658 static MOJOSHADER_astExpression *new_unary_expr(Context *ctx,
659                                             const MOJOSHADER_astNodeType op,
660                                             MOJOSHADER_astExpression *operand)
661 {
662     NEW_AST_NODE(retval, MOJOSHADER_astExpressionUnary, op);
663     assert(operator_is_unary(op));
664     retval->datatype = NULL;
665     retval->operand = operand;
666     return (MOJOSHADER_astExpression *) retval;
667 } // new_unary_expr
668 
new_binary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * left,MOJOSHADER_astExpression * right)669 static MOJOSHADER_astExpression *new_binary_expr(Context *ctx,
670                                             const MOJOSHADER_astNodeType op,
671                                             MOJOSHADER_astExpression *left,
672                                             MOJOSHADER_astExpression *right)
673 {
674     NEW_AST_NODE(retval, MOJOSHADER_astExpressionBinary, op);
675     assert(operator_is_binary(op));
676     retval->datatype = NULL;
677     retval->left = left;
678     retval->right = right;
679     return (MOJOSHADER_astExpression *) retval;
680 } // new_binary_expr
681 
new_ternary_expr(Context * ctx,const MOJOSHADER_astNodeType op,MOJOSHADER_astExpression * left,MOJOSHADER_astExpression * center,MOJOSHADER_astExpression * right)682 static MOJOSHADER_astExpression *new_ternary_expr(Context *ctx,
683                                             const MOJOSHADER_astNodeType op,
684                                             MOJOSHADER_astExpression *left,
685                                             MOJOSHADER_astExpression *center,
686                                             MOJOSHADER_astExpression *right)
687 {
688     NEW_AST_NODE(retval, MOJOSHADER_astExpressionTernary, op);
689     assert(operator_is_ternary(op));
690     assert(op == MOJOSHADER_AST_OP_CONDITIONAL);
691     retval->datatype = &ctx->dt_bool;
692     retval->left = left;
693     retval->center = center;
694     retval->right = right;
695     return (MOJOSHADER_astExpression *) retval;
696 } // new_ternary_expr
697 
new_deref_struct_expr(Context * ctx,MOJOSHADER_astExpression * identifier,const char * member)698 static MOJOSHADER_astExpression *new_deref_struct_expr(Context *ctx,
699                                         MOJOSHADER_astExpression *identifier,
700                                         const char *member)
701 {
702     NEW_AST_NODE(retval, MOJOSHADER_astExpressionDerefStruct,
703                  MOJOSHADER_AST_OP_DEREF_STRUCT);
704     retval->datatype = NULL;
705     retval->identifier = identifier;
706     retval->member = member;  // cached; don't copy string.
707     retval->isswizzle = 0;  // may change during semantic analysis.
708     retval->member_index = 0;  // set during semantic analysis.
709     return (MOJOSHADER_astExpression *) retval;
710 } // new_deref_struct_expr
711 
new_literal_int_expr(Context * ctx,const int value)712 static MOJOSHADER_astExpression *new_literal_int_expr(Context *ctx,
713                                                        const int value)
714 {
715     NEW_AST_NODE(retval, MOJOSHADER_astExpressionIntLiteral,
716                  MOJOSHADER_AST_OP_INT_LITERAL);
717     retval->datatype = &ctx->dt_int;
718     retval->value = value;
719     return (MOJOSHADER_astExpression *) retval;
720 } // new_literal_int_expr
721 
new_literal_float_expr(Context * ctx,const double dbl)722 static MOJOSHADER_astExpression *new_literal_float_expr(Context *ctx,
723                                                         const double dbl)
724 {
725     NEW_AST_NODE(retval, MOJOSHADER_astExpressionFloatLiteral,
726                  MOJOSHADER_AST_OP_FLOAT_LITERAL);
727     retval->datatype = &ctx->dt_float;
728     retval->value = dbl;
729     return (MOJOSHADER_astExpression *) retval;
730 } // new_literal_float_expr
731 
new_literal_string_expr(Context * ctx,const char * string)732 static MOJOSHADER_astExpression *new_literal_string_expr(Context *ctx,
733                                                          const char *string)
734 {
735     NEW_AST_NODE(retval, MOJOSHADER_astExpressionStringLiteral,
736                  MOJOSHADER_AST_OP_STRING_LITERAL);
737     retval->datatype = &ctx->dt_string;
738     retval->string = string;  // cached; don't copy string.
739     return (MOJOSHADER_astExpression *) retval;
740 } // new_literal_string_expr
741 
new_literal_boolean_expr(Context * ctx,const int value)742 static MOJOSHADER_astExpression *new_literal_boolean_expr(Context *ctx,
743                                                           const int value)
744 {
745     NEW_AST_NODE(retval, MOJOSHADER_astExpressionBooleanLiteral,
746                  MOJOSHADER_AST_OP_BOOLEAN_LITERAL);
747     retval->datatype = &ctx->dt_bool;
748     retval->value = value;
749     return (MOJOSHADER_astExpression *) retval;
750 } // new_literal_boolean_expr
751 
752 static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args);
753 
delete_expr(Context * ctx,MOJOSHADER_astExpression * _expr)754 static void delete_expr(Context *ctx, MOJOSHADER_astExpression *_expr)
755 {
756     MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
757 
758     DELETE_AST_NODE(expr);
759 
760     if (expr->ast.type == MOJOSHADER_AST_OP_CAST)
761         delete_expr(ctx, expr->cast.operand);
762 
763     else if (expr->ast.type == MOJOSHADER_AST_OP_CONSTRUCTOR)
764         delete_arguments(ctx, expr->constructor.args);
765 
766     else if (expr->ast.type == MOJOSHADER_AST_OP_DEREF_STRUCT)
767         delete_expr(ctx, expr->derefstruct.identifier);
768 
769     else if (operator_is_unary(expr->ast.type))
770         delete_expr(ctx, expr->unary.operand);
771 
772     else if (operator_is_binary(expr->ast.type))
773     {
774         delete_expr(ctx, expr->binary.left);
775         delete_expr(ctx, expr->binary.right);
776     } // else if
777 
778     else if (operator_is_ternary(expr->ast.type))
779     {
780         delete_expr(ctx, expr->ternary.left);
781         delete_expr(ctx, expr->ternary.center);
782         delete_expr(ctx, expr->ternary.right);
783     } // else if
784 
785     else if (expr->ast.type == MOJOSHADER_AST_OP_CALLFUNC)
786     {
787         delete_expr(ctx, (MOJOSHADER_astExpression*)expr->callfunc.identifier);
788         delete_arguments(ctx, expr->callfunc.args);
789     } // else if
790 
791     // rest of operators don't have extra data to free.
792 
793     Free(ctx, expr);
794 } // delete_expr
795 
new_argument(Context * ctx,MOJOSHADER_astExpression * arg)796 static MOJOSHADER_astArguments *new_argument(Context *ctx,
797                                              MOJOSHADER_astExpression *arg)
798 {
799     NEW_AST_NODE(retval, MOJOSHADER_astArguments, MOJOSHADER_AST_ARGUMENTS);
800     retval->argument = arg;
801     retval->next = NULL;
802     return retval;
803 } // new_argument
804 
delete_arguments(Context * ctx,MOJOSHADER_astArguments * args)805 static void delete_arguments(Context *ctx, MOJOSHADER_astArguments *args)
806 {
807     DELETE_AST_NODE(args);
808     delete_arguments(ctx, args->next);
809     delete_expr(ctx, args->argument);
810     Free(ctx, args);
811 } // delete_arguments
812 
new_function_param(Context * ctx,const MOJOSHADER_astInputModifier inputmod,const MOJOSHADER_astDataType * dt,const char * identifier,const char * semantic,const MOJOSHADER_astInterpolationModifier interpmod,MOJOSHADER_astExpression * initializer)813 static MOJOSHADER_astFunctionParameters *new_function_param(Context *ctx,
814                         const MOJOSHADER_astInputModifier inputmod,
815                         const MOJOSHADER_astDataType *dt,
816                         const char *identifier, const char *semantic,
817                         const MOJOSHADER_astInterpolationModifier interpmod,
818                         MOJOSHADER_astExpression *initializer)
819 {
820     NEW_AST_NODE(retval, MOJOSHADER_astFunctionParameters,
821                  MOJOSHADER_AST_FUNCTION_PARAMS);
822     retval->datatype = dt;
823     retval->input_modifier = inputmod;
824     retval->identifier = identifier;
825     retval->semantic = semantic;
826     retval->interpolation_modifier = interpmod;
827     retval->initializer = initializer;
828     retval->next = NULL;
829     return retval;
830 } // new_function_param
831 
delete_function_params(Context * ctx,MOJOSHADER_astFunctionParameters * params)832 static void delete_function_params(Context *ctx,
833                                    MOJOSHADER_astFunctionParameters *params)
834 {
835     DELETE_AST_NODE(params);
836     delete_function_params(ctx, params->next);
837     delete_expr(ctx, params->initializer);
838     Free(ctx, params);
839 } // delete_function_params
840 
new_function_signature(Context * ctx,const MOJOSHADER_astDataType * dt,const char * identifier,MOJOSHADER_astFunctionParameters * params)841 static MOJOSHADER_astFunctionSignature *new_function_signature(Context *ctx,
842                                     const MOJOSHADER_astDataType *dt,
843                                     const char *identifier,
844                                     MOJOSHADER_astFunctionParameters *params)
845 {
846     NEW_AST_NODE(retval, MOJOSHADER_astFunctionSignature,
847                  MOJOSHADER_AST_FUNCTION_SIGNATURE);
848     retval->datatype = dt;
849     retval->identifier = identifier;
850     retval->params = params;
851     retval->storage_class = MOJOSHADER_AST_FNSTORECLS_NONE;
852     retval->semantic = NULL;
853     return retval;
854 } // new_function_signature
855 
delete_function_signature(Context * ctx,MOJOSHADER_astFunctionSignature * sig)856 static void delete_function_signature(Context *ctx,
857                                       MOJOSHADER_astFunctionSignature *sig)
858 {
859     DELETE_AST_NODE(sig);
860     delete_function_params(ctx, sig->params);
861     Free(ctx, sig);
862 } // delete_function_signature
863 
new_function(Context * ctx,MOJOSHADER_astFunctionSignature * declaration,MOJOSHADER_astStatement * definition)864 static MOJOSHADER_astCompilationUnit *new_function(Context *ctx,
865                                 MOJOSHADER_astFunctionSignature *declaration,
866                                 MOJOSHADER_astStatement *definition)
867 {
868     NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitFunction,
869                  MOJOSHADER_AST_COMPUNIT_FUNCTION);
870     retval->next = NULL;
871     retval->declaration = declaration;
872     retval->definition = definition;
873     retval->index = 0;
874     return (MOJOSHADER_astCompilationUnit *) retval;
875 } // new_function
876 
delete_function(Context * ctx,MOJOSHADER_astCompilationUnitFunction * unitfn)877 static void delete_function(Context *ctx,
878                             MOJOSHADER_astCompilationUnitFunction *unitfn)
879 {
880     DELETE_AST_NODE(unitfn);
881     delete_compilation_unit(ctx, unitfn->next);
882     delete_function_signature(ctx, unitfn->declaration);
883     delete_statement(ctx, unitfn->definition);
884     Free(ctx, unitfn);
885 } // delete_function
886 
new_scalar_or_array(Context * ctx,const char * ident,const int isvec,MOJOSHADER_astExpression * dim)887 static MOJOSHADER_astScalarOrArray *new_scalar_or_array(Context *ctx,
888                                           const char *ident, const int isvec,
889                                           MOJOSHADER_astExpression *dim)
890 {
891     NEW_AST_NODE(retval, MOJOSHADER_astScalarOrArray,
892                  MOJOSHADER_AST_SCALAR_OR_ARRAY);
893     retval->identifier = ident;
894     retval->isarray = isvec;
895     retval->dimension = dim;
896     return retval;
897 } // new_scalar_or_array
898 
delete_scalar_or_array(Context * ctx,MOJOSHADER_astScalarOrArray * s)899 static void delete_scalar_or_array(Context *ctx,MOJOSHADER_astScalarOrArray *s)
900 {
901     DELETE_AST_NODE(s);
902     delete_expr(ctx, s->dimension);
903     Free(ctx, s);
904 } // delete_scalar_or_array
905 
new_typedef(Context * ctx,const int isconst,const MOJOSHADER_astDataType * dt,MOJOSHADER_astScalarOrArray * soa)906 static MOJOSHADER_astTypedef *new_typedef(Context *ctx, const int isconst,
907                                           const MOJOSHADER_astDataType *dt,
908                                           MOJOSHADER_astScalarOrArray *soa)
909 {
910     // we correct this datatype to the final version during semantic analysis.
911     NEW_AST_NODE(retval, MOJOSHADER_astTypedef, MOJOSHADER_AST_TYPEDEF);
912     retval->datatype = dt;
913     retval->isconst = isconst;
914     retval->details = soa;
915     return retval;
916 } // new_typedef
917 
delete_typedef(Context * ctx,MOJOSHADER_astTypedef * td)918 static void delete_typedef(Context *ctx, MOJOSHADER_astTypedef *td)
919 {
920     DELETE_AST_NODE(td);
921     delete_scalar_or_array(ctx, td->details);
922     Free(ctx, td);
923 } // delete_typedef
924 
new_pack_offset(Context * ctx,const char * a,const char * b)925 static MOJOSHADER_astPackOffset *new_pack_offset(Context *ctx,
926                                                  const char *a, const char *b)
927 {
928     NEW_AST_NODE(retval, MOJOSHADER_astPackOffset, MOJOSHADER_AST_PACK_OFFSET);
929     retval->ident1 = a;
930     retval->ident2 = b;
931     return retval;
932 } // new_pack_offset
933 
delete_pack_offset(Context * ctx,MOJOSHADER_astPackOffset * o)934 static void delete_pack_offset(Context *ctx, MOJOSHADER_astPackOffset *o)
935 {
936     DELETE_AST_NODE(o);
937     Free(ctx, o);
938 } // delete_pack_offset
939 
new_variable_lowlevel(Context * ctx,MOJOSHADER_astPackOffset * po,const char * reg)940 static MOJOSHADER_astVariableLowLevel *new_variable_lowlevel(Context *ctx,
941                                                MOJOSHADER_astPackOffset *po,
942                                                const char *reg)
943 {
944     NEW_AST_NODE(retval, MOJOSHADER_astVariableLowLevel,
945                  MOJOSHADER_AST_VARIABLE_LOWLEVEL);
946     retval->packoffset = po;
947     retval->register_name = reg;
948     return retval;
949 } // new_variable_lowlevel
950 
delete_variable_lowlevel(Context * ctx,MOJOSHADER_astVariableLowLevel * vll)951 static void delete_variable_lowlevel(Context *ctx,
952                                      MOJOSHADER_astVariableLowLevel *vll)
953 {
954     DELETE_AST_NODE(vll);
955     delete_pack_offset(ctx, vll->packoffset);
956     Free(ctx, vll);
957 } // delete_variable_lowlevel
958 
new_annotation(Context * ctx,const MOJOSHADER_astDataType * dt,MOJOSHADER_astExpression * initializer)959 static MOJOSHADER_astAnnotations *new_annotation(Context *ctx,
960                                         const MOJOSHADER_astDataType *dt,
961                                         MOJOSHADER_astExpression *initializer)
962 {
963     NEW_AST_NODE(retval, MOJOSHADER_astAnnotations, MOJOSHADER_AST_ANNOTATION);
964     retval->datatype = dt;
965     retval->initializer = initializer;
966     retval->next = NULL;
967     return retval;
968 } // new_annotation
969 
delete_annotation(Context * ctx,MOJOSHADER_astAnnotations * annos)970 static void delete_annotation(Context *ctx, MOJOSHADER_astAnnotations *annos)
971 {
972     DELETE_AST_NODE(annos);
973     delete_annotation(ctx, annos->next);
974     delete_expr(ctx, annos->initializer);
975     Free(ctx, annos);
976 } // delete_annotation
977 
new_variable_declaration(Context * ctx,MOJOSHADER_astScalarOrArray * soa,const char * semantic,MOJOSHADER_astAnnotations * annotations,MOJOSHADER_astExpression * init,MOJOSHADER_astVariableLowLevel * vll)978 static MOJOSHADER_astVariableDeclaration *new_variable_declaration(
979                             Context *ctx, MOJOSHADER_astScalarOrArray *soa,
980                             const char *semantic,
981                             MOJOSHADER_astAnnotations *annotations,
982                             MOJOSHADER_astExpression *init,
983                             MOJOSHADER_astVariableLowLevel *vll)
984 {
985     NEW_AST_NODE(retval, MOJOSHADER_astVariableDeclaration,
986                  MOJOSHADER_AST_VARIABLE_DECLARATION);
987     retval->datatype = NULL;
988     retval->attributes = 0;
989     retval->anonymous_datatype = NULL;
990     retval->details = soa;
991     retval->semantic = semantic;
992     retval->annotations = annotations;
993     retval->initializer = init;
994     retval->lowlevel = vll;
995     retval->next = NULL;
996     return retval;
997 } // new_variable_declaration
998 
delete_variable_declaration(Context * ctx,MOJOSHADER_astVariableDeclaration * dcl)999 static void delete_variable_declaration(Context *ctx,
1000                                         MOJOSHADER_astVariableDeclaration *dcl)
1001 {
1002     DELETE_AST_NODE(dcl);
1003     delete_variable_declaration(ctx, dcl->next);
1004     delete_scalar_or_array(ctx, dcl->details);
1005     delete_annotation(ctx, dcl->annotations);
1006     delete_expr(ctx, dcl->initializer);
1007     delete_variable_lowlevel(ctx, dcl->lowlevel);
1008     Free(ctx, dcl);
1009 } // delete_variable_declaration
1010 
new_global_variable(Context * ctx,MOJOSHADER_astVariableDeclaration * decl)1011 static MOJOSHADER_astCompilationUnit *new_global_variable(Context *ctx,
1012                                       MOJOSHADER_astVariableDeclaration *decl)
1013 {
1014     NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitVariable,
1015                  MOJOSHADER_AST_COMPUNIT_VARIABLE);
1016     retval->next = NULL;
1017     retval->declaration = decl;
1018     return (MOJOSHADER_astCompilationUnit *) retval;
1019 } // new_global_variable
1020 
delete_global_variable(Context * ctx,MOJOSHADER_astCompilationUnitVariable * var)1021 static void delete_global_variable(Context *ctx,
1022                                    MOJOSHADER_astCompilationUnitVariable *var)
1023 {
1024     DELETE_AST_NODE(var);
1025     delete_compilation_unit(ctx, var->next);
1026     delete_variable_declaration(ctx, var->declaration);
1027     Free(ctx, var);
1028 } // delete_global_variable
1029 
new_global_typedef(Context * ctx,MOJOSHADER_astTypedef * td)1030 static MOJOSHADER_astCompilationUnit *new_global_typedef(Context *ctx,
1031                                                      MOJOSHADER_astTypedef *td)
1032 {
1033     NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitTypedef,
1034                  MOJOSHADER_AST_COMPUNIT_TYPEDEF);
1035     retval->next = NULL;
1036     retval->type_info = td;
1037     return (MOJOSHADER_astCompilationUnit *) retval;
1038 } // new_global_typedef
1039 
delete_global_typedef(Context * ctx,MOJOSHADER_astCompilationUnitTypedef * unit)1040 static void delete_global_typedef(Context *ctx,
1041                                   MOJOSHADER_astCompilationUnitTypedef *unit)
1042 {
1043     DELETE_AST_NODE(unit);
1044     delete_compilation_unit(ctx, unit->next);
1045     delete_typedef(ctx, unit->type_info);
1046     Free(ctx, unit);
1047 } // delete_global_typedef
1048 
new_struct_member(Context * ctx,MOJOSHADER_astScalarOrArray * soa,const char * semantic)1049 static MOJOSHADER_astStructMembers *new_struct_member(Context *ctx,
1050                                             MOJOSHADER_astScalarOrArray *soa,
1051                                             const char *semantic)
1052 {
1053     NEW_AST_NODE(retval, MOJOSHADER_astStructMembers,
1054                  MOJOSHADER_AST_STRUCT_MEMBER);
1055     retval->datatype = NULL;
1056     retval->semantic = semantic;
1057     retval->details = soa;
1058     retval->interpolation_mod = MOJOSHADER_AST_INTERPMOD_NONE;
1059     retval->next = NULL;
1060     return retval;
1061 } // new_struct_member
1062 
delete_struct_member(Context * ctx,MOJOSHADER_astStructMembers * member)1063 static void delete_struct_member(Context *ctx,
1064                                  MOJOSHADER_astStructMembers *member)
1065 {
1066     DELETE_AST_NODE(member);
1067     delete_struct_member(ctx, member->next);
1068     delete_scalar_or_array(ctx, member->details);
1069     Free(ctx, member);
1070 } // delete_struct_member
1071 
new_struct_declaration(Context * ctx,const char * name,MOJOSHADER_astStructMembers * members)1072 static MOJOSHADER_astStructDeclaration *new_struct_declaration(Context *ctx,
1073                                         const char *name,
1074                                         MOJOSHADER_astStructMembers *members)
1075 {
1076     NEW_AST_NODE(retval, MOJOSHADER_astStructDeclaration,
1077                  MOJOSHADER_AST_STRUCT_DECLARATION);
1078     retval->datatype = NULL;
1079     retval->name = name;
1080     retval->members = members;
1081     return retval;
1082 } // new_struct_declaration
1083 
delete_struct_declaration(Context * ctx,MOJOSHADER_astStructDeclaration * decl)1084 static void delete_struct_declaration(Context *ctx,
1085                                       MOJOSHADER_astStructDeclaration *decl)
1086 {
1087     DELETE_AST_NODE(decl);
1088     delete_struct_member(ctx, decl->members);
1089     Free(ctx, decl);
1090 } // delete_struct_declaration
1091 
new_global_struct(Context * ctx,MOJOSHADER_astStructDeclaration * sd)1092 static MOJOSHADER_astCompilationUnit *new_global_struct(Context *ctx,
1093                                            MOJOSHADER_astStructDeclaration *sd)
1094 {
1095     NEW_AST_NODE(retval, MOJOSHADER_astCompilationUnitStruct,
1096                  MOJOSHADER_AST_COMPUNIT_STRUCT);
1097     retval->next = NULL;
1098     retval->struct_info = sd;
1099     return (MOJOSHADER_astCompilationUnit *) retval;
1100 } // new_global_struct
1101 
delete_global_struct(Context * ctx,MOJOSHADER_astCompilationUnitStruct * unit)1102 static void delete_global_struct(Context *ctx,
1103                                  MOJOSHADER_astCompilationUnitStruct *unit)
1104 {
1105     DELETE_AST_NODE(unit);
1106     delete_compilation_unit(ctx, unit->next);
1107     delete_struct_declaration(ctx, unit->struct_info);
1108     Free(ctx, unit);
1109 } // delete_global_struct
1110 
delete_compilation_unit(Context * ctx,MOJOSHADER_astCompilationUnit * unit)1111 static void delete_compilation_unit(Context *ctx,
1112                                     MOJOSHADER_astCompilationUnit *unit)
1113 {
1114     if (!unit) return;
1115 
1116     // it's important to not recurse too deeply here, since you may have
1117     //  thousands of items in this linked list (each line of a massive
1118     //  function, for example). To avoid this, we iterate the list here,
1119     //  deleting all children and making them think they have no reason
1120     //  to recurse in their own delete methods.
1121     // Please note that everyone should _try_ to delete their "next" member,
1122     //  just in case, but hopefully this cleaned it out.
1123 
1124     MOJOSHADER_astCompilationUnit *i = unit->next;
1125     unit->next = NULL;
1126     while (i)
1127     {
1128         MOJOSHADER_astCompilationUnit *next = i->next;
1129         i->next = NULL;
1130         delete_compilation_unit(ctx, i);
1131         i = next;
1132     } // while
1133 
1134     switch (unit->ast.type)
1135     {
1136         #define DELETE_UNIT(typ, cls, fn) \
1137             case MOJOSHADER_AST_COMPUNIT_##typ: delete_##fn(ctx, (cls *) unit); break;
1138         DELETE_UNIT(FUNCTION, MOJOSHADER_astCompilationUnitFunction, function);
1139         DELETE_UNIT(TYPEDEF, MOJOSHADER_astCompilationUnitTypedef, global_typedef);
1140         DELETE_UNIT(VARIABLE, MOJOSHADER_astCompilationUnitVariable, global_variable);
1141         DELETE_UNIT(STRUCT, MOJOSHADER_astCompilationUnitStruct, global_struct);
1142         #undef DELETE_UNIT
1143         default: assert(0 && "missing cleanup code"); break;
1144     } // switch
1145 
1146     // don't free (unit) here, the class-specific functions do it.
1147 } // delete_compilation_unit
1148 
new_typedef_statement(Context * ctx,MOJOSHADER_astTypedef * td)1149 static MOJOSHADER_astStatement *new_typedef_statement(Context *ctx,
1150                                                       MOJOSHADER_astTypedef *td)
1151 {
1152     NEW_AST_NODE(retval, MOJOSHADER_astTypedefStatement,
1153                  MOJOSHADER_AST_STATEMENT_TYPEDEF);
1154     retval->next = NULL;
1155     retval->type_info = td;
1156     return (MOJOSHADER_astStatement *) retval;
1157 } // new_typedef_statement
1158 
delete_typedef_statement(Context * ctx,MOJOSHADER_astTypedefStatement * stmt)1159 static void delete_typedef_statement(Context *ctx,
1160                                      MOJOSHADER_astTypedefStatement *stmt)
1161 {
1162     DELETE_AST_NODE(stmt);
1163     delete_statement(ctx, stmt->next);
1164     delete_typedef(ctx, stmt->type_info);
1165     Free(ctx, stmt);
1166 } // delete_typedef_statement
1167 
new_return_statement(Context * ctx,MOJOSHADER_astExpression * expr)1168 static MOJOSHADER_astStatement *new_return_statement(Context *ctx,
1169                                                 MOJOSHADER_astExpression *expr)
1170 {
1171     NEW_AST_NODE(retval, MOJOSHADER_astReturnStatement,
1172                  MOJOSHADER_AST_STATEMENT_RETURN);
1173     retval->next = NULL;
1174     retval->expr = expr;
1175     return (MOJOSHADER_astStatement *) retval;
1176 } // new_return_statement
1177 
delete_return_statement(Context * ctx,MOJOSHADER_astReturnStatement * stmt)1178 static void delete_return_statement(Context *ctx,
1179                                     MOJOSHADER_astReturnStatement *stmt)
1180 {
1181     DELETE_AST_NODE(stmt);
1182     delete_statement(ctx, stmt->next);
1183     delete_expr(ctx, stmt->expr);
1184     Free(ctx, stmt);
1185 } // delete_return_statement
1186 
new_block_statement(Context * ctx,MOJOSHADER_astStatement * stmts)1187 static MOJOSHADER_astStatement *new_block_statement(Context *ctx,
1188                                                MOJOSHADER_astStatement *stmts)
1189 {
1190     NEW_AST_NODE(retval, MOJOSHADER_astBlockStatement,
1191                  MOJOSHADER_AST_STATEMENT_BLOCK);
1192     retval->next = NULL;
1193     retval->statements = stmts;
1194     return (MOJOSHADER_astStatement *) retval;
1195 } // new_block_statement
1196 
delete_block_statement(Context * ctx,MOJOSHADER_astBlockStatement * stmt)1197 static void delete_block_statement(Context *ctx,
1198                                    MOJOSHADER_astBlockStatement *stmt)
1199 {
1200     DELETE_AST_NODE(stmt);
1201     delete_statement(ctx, stmt->statements);
1202     delete_statement(ctx, stmt->next);
1203     Free(ctx, stmt);
1204 } // delete_statement_block
1205 
new_for_statement(Context * ctx,MOJOSHADER_astVariableDeclaration * decl,MOJOSHADER_astExpression * initializer,MOJOSHADER_astExpression * looptest,MOJOSHADER_astExpression * counter,MOJOSHADER_astStatement * statement)1206 static MOJOSHADER_astStatement *new_for_statement(Context *ctx,
1207                                     MOJOSHADER_astVariableDeclaration *decl,
1208                                     MOJOSHADER_astExpression *initializer,
1209                                     MOJOSHADER_astExpression *looptest,
1210                                     MOJOSHADER_astExpression *counter,
1211                                     MOJOSHADER_astStatement *statement)
1212 {
1213     NEW_AST_NODE(retval, MOJOSHADER_astForStatement,
1214                  MOJOSHADER_AST_STATEMENT_FOR);
1215     retval->next = NULL;
1216     retval->unroll = -1;
1217     retval->var_decl = decl;
1218     retval->initializer = initializer;
1219     retval->looptest = looptest;
1220     retval->counter = counter;
1221     retval->statement = statement;
1222     return (MOJOSHADER_astStatement *) retval;
1223 } // new_for_statement
1224 
delete_for_statement(Context * ctx,MOJOSHADER_astForStatement * stmt)1225 static void delete_for_statement(Context *ctx,MOJOSHADER_astForStatement *stmt)
1226 {
1227     DELETE_AST_NODE(stmt);
1228     delete_statement(ctx, stmt->next);
1229     delete_variable_declaration(ctx, stmt->var_decl);
1230     delete_expr(ctx, stmt->initializer);
1231     delete_expr(ctx, stmt->looptest);
1232     delete_expr(ctx, stmt->counter);
1233     delete_statement(ctx, stmt->statement);
1234     Free(ctx, stmt);
1235 } // delete_for_statement
1236 
new_do_statement(Context * ctx,const int unroll,MOJOSHADER_astStatement * stmt,MOJOSHADER_astExpression * expr)1237 static MOJOSHADER_astStatement *new_do_statement(Context *ctx,
1238                                                 const int unroll,
1239                                                 MOJOSHADER_astStatement *stmt,
1240                                                 MOJOSHADER_astExpression *expr)
1241 {
1242     NEW_AST_NODE(retval,MOJOSHADER_astDoStatement,MOJOSHADER_AST_STATEMENT_DO);
1243     retval->next = NULL;
1244     retval->unroll = unroll;
1245     retval->expr = expr;
1246     retval->statement = stmt;
1247     return (MOJOSHADER_astStatement *) retval;
1248 } // new_do_statement
1249 
delete_do_statement(Context * ctx,MOJOSHADER_astDoStatement * stmt)1250 static void delete_do_statement(Context *ctx, MOJOSHADER_astDoStatement *stmt)
1251 {
1252     DELETE_AST_NODE(stmt);
1253     delete_statement(ctx, stmt->next);
1254     delete_statement(ctx, stmt->statement);
1255     delete_expr(ctx, stmt->expr);
1256     Free(ctx, stmt);
1257 } // delete_do_statement
1258 
new_while_statement(Context * ctx,const int unroll,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt)1259 static MOJOSHADER_astStatement *new_while_statement(Context *ctx,
1260                                                 const int unroll,
1261                                                 MOJOSHADER_astExpression *expr,
1262                                                 MOJOSHADER_astStatement *stmt)
1263 {
1264     NEW_AST_NODE(retval, MOJOSHADER_astWhileStatement,
1265                  MOJOSHADER_AST_STATEMENT_WHILE);
1266     retval->next = NULL;
1267     retval->unroll = unroll;
1268     retval->expr = expr;
1269     retval->statement = stmt;
1270     return (MOJOSHADER_astStatement *) retval;
1271 } // new_while_statement
1272 
delete_while_statement(Context * ctx,MOJOSHADER_astWhileStatement * stmt)1273 static void delete_while_statement(Context *ctx,
1274                                    MOJOSHADER_astWhileStatement *stmt)
1275 {
1276     DELETE_AST_NODE(stmt);
1277     delete_statement(ctx, stmt->next);
1278     delete_statement(ctx, stmt->statement);
1279     delete_expr(ctx, stmt->expr);
1280     Free(ctx, stmt);
1281 } // delete_while_statement
1282 
new_if_statement(Context * ctx,const int attr,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt,MOJOSHADER_astStatement * elsestmt)1283 static MOJOSHADER_astStatement *new_if_statement(Context *ctx,
1284                                             const int attr,
1285                                             MOJOSHADER_astExpression *expr,
1286                                             MOJOSHADER_astStatement *stmt,
1287                                             MOJOSHADER_astStatement *elsestmt)
1288 {
1289     NEW_AST_NODE(retval,MOJOSHADER_astIfStatement,MOJOSHADER_AST_STATEMENT_IF);
1290     retval->next = NULL;
1291     retval->attributes = attr;
1292     retval->expr = expr;
1293     retval->statement = stmt;
1294     retval->else_statement = elsestmt;
1295     return (MOJOSHADER_astStatement *) retval;
1296 } // new_if_statement
1297 
delete_if_statement(Context * ctx,MOJOSHADER_astIfStatement * stmt)1298 static void delete_if_statement(Context *ctx, MOJOSHADER_astIfStatement *stmt)
1299 {
1300     DELETE_AST_NODE(stmt);
1301     delete_statement(ctx, stmt->next);
1302     delete_expr(ctx, stmt->expr);
1303     delete_statement(ctx, stmt->statement);
1304     delete_statement(ctx, stmt->else_statement);
1305     Free(ctx, stmt);
1306 } // delete_if_statement
1307 
new_switch_case(Context * ctx,MOJOSHADER_astExpression * expr,MOJOSHADER_astStatement * stmt)1308 static MOJOSHADER_astSwitchCases *new_switch_case(Context *ctx,
1309                                                 MOJOSHADER_astExpression *expr,
1310                                                 MOJOSHADER_astStatement *stmt)
1311 {
1312     NEW_AST_NODE(retval, MOJOSHADER_astSwitchCases, MOJOSHADER_AST_SWITCH_CASE);
1313     retval->expr = expr;
1314     retval->statement = stmt;
1315     retval->next = NULL;
1316     return retval;
1317 } // new_switch_case
1318 
delete_switch_case(Context * ctx,MOJOSHADER_astSwitchCases * sc)1319 static void delete_switch_case(Context *ctx, MOJOSHADER_astSwitchCases *sc)
1320 {
1321     DELETE_AST_NODE(sc);
1322     delete_switch_case(ctx, sc->next);
1323     delete_expr(ctx, sc->expr);
1324     delete_statement(ctx, sc->statement);
1325     Free(ctx, sc);
1326 } // delete_switch_case
1327 
new_empty_statement(Context * ctx)1328 static MOJOSHADER_astStatement *new_empty_statement(Context *ctx)
1329 {
1330     NEW_AST_NODE(retval, MOJOSHADER_astEmptyStatement,
1331                  MOJOSHADER_AST_STATEMENT_EMPTY);
1332     retval->next = NULL;
1333     return (MOJOSHADER_astStatement *) retval;
1334 } // new_empty_statement
1335 
delete_empty_statement(Context * ctx,MOJOSHADER_astEmptyStatement * stmt)1336 static void delete_empty_statement(Context *ctx,
1337                                    MOJOSHADER_astEmptyStatement *stmt)
1338 {
1339     DELETE_AST_NODE(stmt);
1340     delete_statement(ctx, stmt->next);
1341     Free(ctx, stmt);
1342 } // delete_empty_statement
1343 
new_break_statement(Context * ctx)1344 static MOJOSHADER_astStatement *new_break_statement(Context *ctx)
1345 {
1346     NEW_AST_NODE(retval, MOJOSHADER_astBreakStatement,
1347                  MOJOSHADER_AST_STATEMENT_BREAK);
1348     retval->next = NULL;
1349     return (MOJOSHADER_astStatement *) retval;
1350 } // new_break_statement
1351 
delete_break_statement(Context * ctx,MOJOSHADER_astBreakStatement * stmt)1352 static void delete_break_statement(Context *ctx,
1353                                    MOJOSHADER_astBreakStatement *stmt)
1354 {
1355     DELETE_AST_NODE(stmt);
1356     delete_statement(ctx, stmt->next);
1357     Free(ctx, stmt);
1358 } // delete_break_statement
1359 
new_continue_statement(Context * ctx)1360 static MOJOSHADER_astStatement *new_continue_statement(Context *ctx)
1361 {
1362     NEW_AST_NODE(retval, MOJOSHADER_astContinueStatement,
1363                  MOJOSHADER_AST_STATEMENT_CONTINUE);
1364     retval->next = NULL;
1365     return (MOJOSHADER_astStatement *) retval;
1366 } // new_continue_statement
1367 
delete_continue_statement(Context * ctx,MOJOSHADER_astContinueStatement * stmt)1368 static void delete_continue_statement(Context *ctx,
1369                                       MOJOSHADER_astContinueStatement *stmt)
1370 {
1371     DELETE_AST_NODE(stmt);
1372     delete_statement(ctx, stmt->next);
1373     Free(ctx, stmt);
1374 } // delete_continue_statement
1375 
new_discard_statement(Context * ctx)1376 static MOJOSHADER_astStatement *new_discard_statement(Context *ctx)
1377 {
1378     NEW_AST_NODE(retval, MOJOSHADER_astDiscardStatement,
1379                  MOJOSHADER_AST_STATEMENT_DISCARD);
1380     retval->next = NULL;
1381     return (MOJOSHADER_astStatement *) retval;
1382 } // new_discard_statement
1383 
delete_discard_statement(Context * ctx,MOJOSHADER_astDiscardStatement * stmt)1384 static void delete_discard_statement(Context *ctx,
1385                                      MOJOSHADER_astDiscardStatement *stmt)
1386 {
1387     DELETE_AST_NODE(stmt);
1388     delete_statement(ctx, stmt->next);
1389     Free(ctx, stmt);
1390 } // delete_discard_statement
1391 
new_expr_statement(Context * ctx,MOJOSHADER_astExpression * expr)1392 static MOJOSHADER_astStatement *new_expr_statement(Context *ctx,
1393                                                 MOJOSHADER_astExpression *expr)
1394 {
1395     NEW_AST_NODE(retval, MOJOSHADER_astExpressionStatement,
1396                  MOJOSHADER_AST_STATEMENT_EXPRESSION);
1397     retval->next = NULL;
1398     retval->expr = expr;
1399     return (MOJOSHADER_astStatement *) retval;
1400 } // new_expr_statement
1401 
delete_expr_statement(Context * ctx,MOJOSHADER_astExpressionStatement * stmt)1402 static void delete_expr_statement(Context *ctx,
1403                                   MOJOSHADER_astExpressionStatement *stmt)
1404 {
1405     DELETE_AST_NODE(stmt);
1406     delete_statement(ctx, stmt->next);
1407     delete_expr(ctx, stmt->expr);
1408     Free(ctx, stmt);
1409 } // delete_expr_statement
1410 
new_switch_statement(Context * ctx,const int attr,MOJOSHADER_astExpression * expr,MOJOSHADER_astSwitchCases * cases)1411 static MOJOSHADER_astStatement *new_switch_statement(Context *ctx,
1412                                             const int attr,
1413                                             MOJOSHADER_astExpression *expr,
1414                                             MOJOSHADER_astSwitchCases *cases)
1415 {
1416     NEW_AST_NODE(retval, MOJOSHADER_astSwitchStatement,
1417                  MOJOSHADER_AST_STATEMENT_SWITCH);
1418     retval->next = NULL;
1419     retval->attributes = attr;
1420     retval->expr = expr;
1421     retval->cases = cases;
1422     return (MOJOSHADER_astStatement *) retval;
1423 } // new_switch_statement
1424 
delete_switch_statement(Context * ctx,MOJOSHADER_astSwitchStatement * stmt)1425 static void delete_switch_statement(Context *ctx,
1426                                     MOJOSHADER_astSwitchStatement *stmt)
1427 {
1428     DELETE_AST_NODE(stmt);
1429     delete_expr(ctx, stmt->expr);
1430     delete_switch_case(ctx, stmt->cases);
1431     Free(ctx, stmt);
1432 } // delete_switch_statement
1433 
new_struct_statement(Context * ctx,MOJOSHADER_astStructDeclaration * sd)1434 static MOJOSHADER_astStatement *new_struct_statement(Context *ctx,
1435                                         MOJOSHADER_astStructDeclaration *sd)
1436 {
1437     NEW_AST_NODE(retval, MOJOSHADER_astStructStatement,
1438                  MOJOSHADER_AST_STATEMENT_STRUCT);
1439     retval->next = NULL;
1440     retval->struct_info = sd;
1441     return (MOJOSHADER_astStatement *) retval;
1442 } // new_struct_statement
1443 
delete_struct_statement(Context * ctx,MOJOSHADER_astStructStatement * stmt)1444 static void delete_struct_statement(Context *ctx,
1445                                     MOJOSHADER_astStructStatement *stmt)
1446 {
1447     DELETE_AST_NODE(stmt);
1448     delete_statement(ctx, stmt->next);
1449     delete_struct_declaration(ctx, stmt->struct_info);
1450     Free(ctx, stmt);
1451 } // delete_struct_statement
1452 
new_vardecl_statement(Context * ctx,MOJOSHADER_astVariableDeclaration * vd)1453 static MOJOSHADER_astStatement *new_vardecl_statement(Context *ctx,
1454                                         MOJOSHADER_astVariableDeclaration *vd)
1455 {
1456     NEW_AST_NODE(retval, MOJOSHADER_astVarDeclStatement,
1457                  MOJOSHADER_AST_STATEMENT_VARDECL);
1458     retval->next = NULL;
1459     retval->declaration = vd;
1460     return (MOJOSHADER_astStatement *) retval;
1461 } // new_vardecl_statement
1462 
delete_vardecl_statement(Context * ctx,MOJOSHADER_astVarDeclStatement * stmt)1463 static void delete_vardecl_statement(Context *ctx,
1464                                      MOJOSHADER_astVarDeclStatement *stmt)
1465 {
1466     DELETE_AST_NODE(stmt);
1467     delete_statement(ctx, stmt->next);
1468     delete_variable_declaration(ctx, stmt->declaration);
1469     Free(ctx, stmt);
1470 } // delete_vardecl_statement
1471 
delete_statement(Context * ctx,MOJOSHADER_astStatement * stmt)1472 static void delete_statement(Context *ctx, MOJOSHADER_astStatement *stmt)
1473 {
1474     if (!stmt) return;
1475 
1476     // it's important to not recurse too deeply here, since you may have
1477     //  thousands of items in this linked list (each line of a massive
1478     //  function, for example). To avoid this, we iterate the list here,
1479     //  deleting all children and making them think they have no reason
1480     //  to recurse in their own delete methods.
1481     // Please note that everyone should _try_ to delete their "next" member,
1482     //  just in case, but hopefully this cleaned it out.
1483 
1484     MOJOSHADER_astStatement *i = stmt->next;
1485     stmt->next = NULL;
1486     while (i)
1487     {
1488         MOJOSHADER_astStatement *next = i->next;
1489         i->next = NULL;
1490         delete_statement(ctx, i);
1491         i = next;
1492     } // while
1493 
1494     switch (stmt->ast.type)
1495     {
1496         #define DELETE_STATEMENT(typ, cls, fn) \
1497             case MOJOSHADER_AST_STATEMENT_##typ: \
1498                 delete_##fn##_statement(ctx, (cls *) stmt); break;
1499         DELETE_STATEMENT(BLOCK, MOJOSHADER_astBlockStatement, block);
1500         DELETE_STATEMENT(EMPTY, MOJOSHADER_astEmptyStatement, empty);
1501         DELETE_STATEMENT(IF, MOJOSHADER_astIfStatement, if);
1502         DELETE_STATEMENT(SWITCH, MOJOSHADER_astSwitchStatement, switch);
1503         DELETE_STATEMENT(EXPRESSION, MOJOSHADER_astExpressionStatement, expr);
1504         DELETE_STATEMENT(FOR, MOJOSHADER_astForStatement, for);
1505         DELETE_STATEMENT(DO, MOJOSHADER_astDoStatement, do);
1506         DELETE_STATEMENT(WHILE, MOJOSHADER_astWhileStatement, while);
1507         DELETE_STATEMENT(RETURN, MOJOSHADER_astReturnStatement, return);
1508         DELETE_STATEMENT(BREAK, MOJOSHADER_astBreakStatement, break);
1509         DELETE_STATEMENT(CONTINUE, MOJOSHADER_astContinueStatement, continue);
1510         DELETE_STATEMENT(DISCARD, MOJOSHADER_astDiscardStatement, discard);
1511         DELETE_STATEMENT(TYPEDEF, MOJOSHADER_astTypedefStatement, typedef);
1512         DELETE_STATEMENT(STRUCT, MOJOSHADER_astStructStatement, struct);
1513         DELETE_STATEMENT(VARDECL, MOJOSHADER_astVarDeclStatement, vardecl);
1514         #undef DELETE_STATEMENT
1515         default: assert(0 && "missing cleanup code"); break;
1516     } // switch
1517     // don't free (stmt) here, the class-specific functions do it.
1518 } // delete_statement
1519 
1520 
get_usertype(const Context * ctx,const char * token)1521 static const MOJOSHADER_astDataType *get_usertype(const Context *ctx,
1522                                                   const char *token)
1523 {
1524     const void *value;  // search all scopes.
1525     if (!hash_find(ctx->usertypes.hash, token, &value))
1526         return NULL;
1527     return value ? ((SymbolScope *) value)->datatype : NULL;
1528 } // get_usertype
1529 
1530 
1531 // This is where the actual parsing happens. It's Lemon-generated!
1532 #define __MOJOSHADER_HLSL_COMPILER__ 1
1533 #include "mojoshader_parser_hlsl.h"
1534 
1535 
1536 #if 0
1537 static int expr_is_constant(MOJOSHADER_astExpression *expr)
1538 {
1539     const MOJOSHADER_astNodeType op = expr->ast.type;
1540     if (operator_is_unary(op))
1541         return expr_is_constant(expr->unary.operand);
1542     else if (operator_is_binary(op))
1543     {
1544         return ( expr_is_constant(expr->binary.left) &&
1545                  expr_is_constant(expr->binary.right) );
1546     } // else if
1547     else if (operator_is_ternary(op))
1548     {
1549         return ( expr_is_constant(expr->ternary.left) &&
1550                  expr_is_constant(expr->ternary.center) &&
1551                  expr_is_constant(expr->ternary.right) );
1552     } // else if
1553 
1554     return ( (op == MOJOSHADER_AST_OP_INT_LITERAL) ||
1555              (op == MOJOSHADER_AST_OP_FLOAT_LITERAL) ||
1556              (op == MOJOSHADER_AST_OP_STRING_LITERAL) ||
1557              (op == MOJOSHADER_AST_OP_BOOLEAN_LITERAL) );
1558 } // expr_is_constant
1559 #endif
1560 
1561 typedef struct AstCalcData
1562 {
1563     int isflt;
1564     union
1565     {
1566         double f;
1567         int64 i;
1568     } value;
1569 } AstCalcData;
1570 
1571 // returns 0 if this expression is non-constant, 1 if it is.
1572 //  calculation results land in (data).
calc_ast_const_expr(Context * ctx,void * _expr,AstCalcData * data)1573 static int calc_ast_const_expr(Context *ctx, void *_expr, AstCalcData *data)
1574 {
1575     const MOJOSHADER_astNode *expr = (MOJOSHADER_astNode *) _expr;
1576     const MOJOSHADER_astNodeType op = expr->ast.type;
1577 
1578     ctx->sourcefile = expr->ast.filename;
1579     ctx->sourceline = expr->ast.line;
1580 
1581     if (operator_is_unary(op))
1582     {
1583         if (!calc_ast_const_expr(ctx, expr->unary.operand, data))
1584             return 0;
1585 
1586         if (data->isflt)
1587         {
1588             switch (op)
1589             {
1590                 case MOJOSHADER_AST_OP_NEGATE:
1591                     data->value.f = -data->value.f;
1592                     return 1;
1593                 case MOJOSHADER_AST_OP_NOT:
1594                     data->value.f = !data->value.f;
1595                     return 1;
1596                 case MOJOSHADER_AST_OP_COMPLEMENT:
1597                     fail(ctx, "integer operation on floating point value");
1598                     return 0;
1599                 case MOJOSHADER_AST_OP_CAST:
1600                     // !!! FIXME: this should work, but it's complicated.
1601                     assert(0 && "write me");
1602                     return 0;
1603                 default: break;
1604             } // switch
1605         } // if
1606 
1607         else  // integer version
1608         {
1609             switch (op)
1610             {
1611                 case MOJOSHADER_AST_OP_NEGATE:
1612                     data->value.i = -data->value.i;
1613                     return 1;
1614                 case MOJOSHADER_AST_OP_NOT:
1615                     data->value.i = !data->value.i;
1616                     return 1;
1617                 case MOJOSHADER_AST_OP_COMPLEMENT:
1618                     data->value.i = ~data->value.i;
1619                     return 1;
1620                 case MOJOSHADER_AST_OP_CAST:
1621                     // !!! FIXME: this should work, but it's complicated.
1622                     assert(0 && "write me");
1623                     return 0;
1624                 default: break;
1625             } // switch
1626         } // else
1627         assert(0 && "unhandled operation?");
1628         return 0;
1629     } // if
1630 
1631     else if (operator_is_binary(op))
1632     {
1633         AstCalcData subdata2;
1634         if ( (!calc_ast_const_expr(ctx, expr->binary.left, data)) ||
1635              (!calc_ast_const_expr(ctx, expr->binary.right, &subdata2)) )
1636             return 0;
1637 
1638         // upgrade to float if either operand is float.
1639         if ((data->isflt) || (subdata2.isflt))
1640         {
1641             if (!data->isflt) data->value.f = (double) data->value.i;
1642             if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
1643             data->isflt = subdata2.isflt = 1;
1644         } // if
1645 
1646         switch (op)
1647         {
1648             // gcc doesn't handle commas here, either (fails to parse!).
1649             case MOJOSHADER_AST_OP_COMMA:
1650             case MOJOSHADER_AST_OP_ASSIGN:
1651             case MOJOSHADER_AST_OP_MULASSIGN:
1652             case MOJOSHADER_AST_OP_DIVASSIGN:
1653             case MOJOSHADER_AST_OP_MODASSIGN:
1654             case MOJOSHADER_AST_OP_ADDASSIGN:
1655             case MOJOSHADER_AST_OP_SUBASSIGN:
1656             case MOJOSHADER_AST_OP_LSHIFTASSIGN:
1657             case MOJOSHADER_AST_OP_RSHIFTASSIGN:
1658             case MOJOSHADER_AST_OP_ANDASSIGN:
1659             case MOJOSHADER_AST_OP_XORASSIGN:
1660             case MOJOSHADER_AST_OP_ORASSIGN:
1661                 return 0;  // assignment is non-constant.
1662             default: break;
1663         } // switch
1664 
1665         if (data->isflt)
1666         {
1667             switch (op)
1668             {
1669                 case MOJOSHADER_AST_OP_MULTIPLY:
1670                     data->value.f *= subdata2.value.f;
1671                     return 1;
1672                 case MOJOSHADER_AST_OP_DIVIDE:
1673                     data->value.f /= subdata2.value.f;
1674                     return 1;
1675                 case MOJOSHADER_AST_OP_ADD:
1676                     data->value.f += subdata2.value.f;
1677                     return 1;
1678                 case MOJOSHADER_AST_OP_SUBTRACT:
1679                     data->value.f -= subdata2.value.f;
1680                     return 1;
1681                 case MOJOSHADER_AST_OP_LESSTHAN:
1682                     data->isflt = 0;
1683                     data->value.i = data->value.f < subdata2.value.f;
1684                     return 1;
1685                 case MOJOSHADER_AST_OP_GREATERTHAN:
1686                     data->isflt = 0;
1687                     data->value.i = data->value.f > subdata2.value.f;
1688                     return 1;
1689                 case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
1690                     data->isflt = 0;
1691                     data->value.i = data->value.f <= subdata2.value.f;
1692                     return 1;
1693                 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
1694                     data->isflt = 0;
1695                     data->value.i = data->value.f >= subdata2.value.f;
1696                     return 1;
1697                 case MOJOSHADER_AST_OP_EQUAL:
1698                     data->isflt = 0;
1699                     data->value.i = data->value.f == subdata2.value.f;
1700                     return 1;
1701                 case MOJOSHADER_AST_OP_NOTEQUAL:
1702                     data->isflt = 0;
1703                     data->value.i = data->value.f != subdata2.value.f;
1704                     return 1;
1705                 case MOJOSHADER_AST_OP_LOGICALAND:
1706                     data->isflt = 0;
1707                     data->value.i = data->value.f && subdata2.value.f;
1708                     return 1;
1709                 case MOJOSHADER_AST_OP_LOGICALOR:
1710                     data->isflt = 0;
1711                     data->value.i = data->value.f || subdata2.value.f;
1712                     return 1;
1713 
1714                 case MOJOSHADER_AST_OP_LSHIFT:
1715                 case MOJOSHADER_AST_OP_RSHIFT:
1716                 case MOJOSHADER_AST_OP_MODULO:
1717                 case MOJOSHADER_AST_OP_BINARYAND:
1718                 case MOJOSHADER_AST_OP_BINARYXOR:
1719                 case MOJOSHADER_AST_OP_BINARYOR:
1720                     fail(ctx, "integer operation on floating point value");
1721                     return 0;
1722                 default: break;
1723             } // switch
1724         } // if
1725 
1726         else   // integer version.
1727         {
1728             switch (op)
1729             {
1730                 case MOJOSHADER_AST_OP_MULTIPLY:
1731                     data->value.i *= subdata2.value.i;
1732                     return 1;
1733                 case MOJOSHADER_AST_OP_DIVIDE:
1734                     data->value.i /= subdata2.value.i;
1735                     return 1;
1736                 case MOJOSHADER_AST_OP_ADD:
1737                     data->value.i += subdata2.value.i;
1738                     return 1;
1739                 case MOJOSHADER_AST_OP_SUBTRACT:
1740                     data->value.i -= subdata2.value.i;
1741                     return 1;
1742                 case MOJOSHADER_AST_OP_LESSTHAN:
1743                     data->value.i = data->value.i < subdata2.value.i;
1744                     return 1;
1745                 case MOJOSHADER_AST_OP_GREATERTHAN:
1746                     data->value.i = data->value.i > subdata2.value.i;
1747                     return 1;
1748                 case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
1749                     data->value.i = data->value.i <= subdata2.value.i;
1750                     return 1;
1751                 case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
1752                     data->value.i = data->value.i >= subdata2.value.i;
1753                     return 1;
1754                 case MOJOSHADER_AST_OP_EQUAL:
1755                     data->value.i = data->value.i == subdata2.value.i;
1756                     return 1;
1757                 case MOJOSHADER_AST_OP_NOTEQUAL:
1758                     data->value.i = data->value.i != subdata2.value.i;
1759                     return 1;
1760                 case MOJOSHADER_AST_OP_LOGICALAND:
1761                     data->value.i = data->value.i && subdata2.value.i;
1762                     return 1;
1763                 case MOJOSHADER_AST_OP_LOGICALOR:
1764                     data->value.i = data->value.i || subdata2.value.i;
1765                     return 1;
1766                 case MOJOSHADER_AST_OP_LSHIFT:
1767                     data->value.i = data->value.i << subdata2.value.i;
1768                     return 1;
1769                 case MOJOSHADER_AST_OP_RSHIFT:
1770                     data->value.i = data->value.i >> subdata2.value.i;
1771                     return 1;
1772                 case MOJOSHADER_AST_OP_MODULO:
1773                     data->value.i = data->value.i % subdata2.value.i;
1774                     return 1;
1775                 case MOJOSHADER_AST_OP_BINARYAND:
1776                     data->value.i = data->value.i & subdata2.value.i;
1777                     return 1;
1778                 case MOJOSHADER_AST_OP_BINARYXOR:
1779                     data->value.i = data->value.i ^ subdata2.value.i;
1780                     return 1;
1781                 case MOJOSHADER_AST_OP_BINARYOR:
1782                     data->value.i = data->value.i | subdata2.value.i;
1783                     return 1;
1784                 default: break;
1785             } // switch
1786         } // else
1787 
1788         assert(0 && "unhandled operation?");
1789         return 0;
1790     } // else if
1791 
1792     else if (operator_is_ternary(op))
1793     {
1794         AstCalcData subdata2;
1795         AstCalcData subdata3;
1796 
1797         assert(op == MOJOSHADER_AST_OP_CONDITIONAL);  // only one we have.
1798 
1799         if ( (!calc_ast_const_expr(ctx, expr->ternary.left, data)) ||
1800              (!calc_ast_const_expr(ctx, expr->ternary.center, &subdata2)) ||
1801              (!calc_ast_const_expr(ctx, expr->ternary.right, &subdata3)) )
1802             return 0;
1803 
1804         // first operand should be bool (for the one ternary operator we have).
1805         if (data->isflt)
1806         {
1807             data->isflt = 0;
1808             data->value.i = (int64) subdata3.value.f;
1809         } // if
1810 
1811         // upgrade to float if either operand is float.
1812         if ((subdata2.isflt) || (subdata3.isflt))
1813         {
1814             if (!subdata2.isflt) subdata2.value.f = (double) subdata2.value.i;
1815             if (!subdata3.isflt) subdata3.value.f = (double) subdata3.value.i;
1816             subdata2.isflt = subdata3.isflt = 1;
1817         } // if
1818 
1819         data->isflt = subdata2.isflt;
1820         if (data->isflt)
1821             data->value.f = data->value.i ? subdata2.value.f : subdata3.value.f;
1822         else
1823             data->value.i = data->value.i ? subdata2.value.i : subdata3.value.i;
1824         return 1;
1825     } // else if
1826 
1827     else  // not an operator? See if this is a literal value.
1828     {
1829         switch (op)
1830         {
1831             case MOJOSHADER_AST_OP_INT_LITERAL:
1832                 data->isflt = 0;
1833                 data->value.i = expr->intliteral.value;
1834                 return 1;
1835 
1836             case MOJOSHADER_AST_OP_FLOAT_LITERAL:
1837                 data->isflt = 1;
1838                 data->value.f = expr->floatliteral.value;
1839                 return 1;
1840 
1841             case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
1842                 data->isflt = 0;
1843                 data->value.i = expr->boolliteral.value ? 1 : 0;
1844                 return 1;
1845 
1846             default: break;
1847         } // switch
1848     } // switch
1849 
1850     return 0;  // not constant, or unhandled.
1851 } // calc_ast_const_expr
1852 
1853 
reduce_datatype(Context * ctx,const MOJOSHADER_astDataType * dt)1854 static const MOJOSHADER_astDataType *reduce_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
1855 {
1856     const MOJOSHADER_astDataType *retval = dt;
1857     while (retval && retval->type == MOJOSHADER_AST_DATATYPE_USER)
1858     {
1859         // !!! FIXME: Ugh, const removal.
1860         MOJOSHADER_astDataTypeUser *user = (MOJOSHADER_astDataTypeUser *) &retval->user;
1861         if (user->details->type == MOJOSHADER_AST_DATATYPE_NONE)
1862         {
1863             // Take this opportunity to fix up some usertype stubs that were
1864             //  left over from the parse phase. You HAVE to catch these in the
1865             //  right scope, so be aggressive about calling reduce_datatype()
1866             //  as soon as things come into view!
1867             user->details = get_usertype(ctx, user->name);
1868             assert(user->details != NULL);
1869         } // if
1870 
1871         retval = user->details;
1872     } // while
1873 
1874     return retval;
1875 } // reduce_datatype
1876 
1877 
sanitize_datatype(Context * ctx,const MOJOSHADER_astDataType * dt)1878 static inline const MOJOSHADER_astDataType *sanitize_datatype(Context *ctx, const MOJOSHADER_astDataType *dt)
1879 {
1880     reduce_datatype(ctx, dt);
1881     return dt;
1882 } // sanitize_datatype
1883 
1884 
build_function_datatype(Context * ctx,const MOJOSHADER_astDataType * rettype,const int paramcount,const MOJOSHADER_astDataType ** params,const int intrinsic)1885 static const MOJOSHADER_astDataType *build_function_datatype(Context *ctx,
1886                                         const MOJOSHADER_astDataType *rettype,
1887                                         const int paramcount,
1888                                         const MOJOSHADER_astDataType **params,
1889                                         const int intrinsic)
1890 {
1891     if ( ((paramcount > 0) && (params == NULL)) ||
1892          ((paramcount == 0) && (params != NULL)) )
1893         return NULL;
1894 
1895     // !!! FIXME: this is hacky.
1896     const MOJOSHADER_astDataType **dtparams;
1897     void *ptr = Malloc(ctx, sizeof (*params) * paramcount);
1898     if (ptr == NULL)
1899         return NULL;
1900     if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
1901     {
1902         Free(ctx, ptr);
1903         return NULL;
1904     } // if
1905     dtparams = (const MOJOSHADER_astDataType **) ptr;
1906     memcpy(dtparams, params, sizeof (*params) * paramcount);
1907 
1908     ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
1909     if (ptr == NULL)
1910         return NULL;
1911     if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
1912     {
1913         Free(ctx, ptr);
1914         return NULL;
1915     } // if
1916 
1917     MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
1918     dt->type = MOJOSHADER_AST_DATATYPE_FUNCTION;
1919     dt->function.retval = rettype;
1920     dt->function.params = dtparams;
1921     dt->function.num_params = paramcount;
1922     dt->function.intrinsic = intrinsic;
1923     return dt;
1924 } // build_function_datatype
1925 
1926 
build_datatype(Context * ctx,const int isconst,const MOJOSHADER_astDataType * dt,MOJOSHADER_astScalarOrArray * soa)1927 static const MOJOSHADER_astDataType *build_datatype(Context *ctx,
1928                                             const int isconst,
1929                                             const MOJOSHADER_astDataType *dt,
1930                                             MOJOSHADER_astScalarOrArray *soa)
1931 {
1932     MOJOSHADER_astDataType *retval = NULL;
1933 
1934     assert( (soa->isarray && soa->dimension) ||
1935             (!soa->isarray && !soa->dimension) );
1936 
1937     sanitize_datatype(ctx, dt);
1938 
1939     // see if we can just reuse the exist datatype.
1940     if (!soa->isarray)
1941     {
1942         const int c1 = (dt->type & MOJOSHADER_AST_DATATYPE_CONST) != 0;
1943         const int c2 = (isconst != 0);
1944         if (c1 == c2)
1945             return dt;  // reuse existing datatype!
1946     } // if
1947 
1948     retval = (MOJOSHADER_astDataType *) Malloc(ctx, sizeof (*retval));
1949     if (retval == NULL)
1950         return NULL;
1951 
1952     // !!! FIXME: this is hacky.
1953     if (!buffer_append(ctx->garbage, &retval, sizeof (retval)))
1954     {
1955         Free(ctx, retval);
1956         return NULL;
1957     } // if
1958 
1959     if (!soa->isarray)
1960     {
1961         assert(soa->dimension == NULL);
1962         memcpy(retval, dt, sizeof (MOJOSHADER_astDataType));
1963         if (isconst)
1964             retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type | MOJOSHADER_AST_DATATYPE_CONST);
1965         else
1966             retval->type = (MOJOSHADER_astDataTypeType)((unsigned)retval->type & ~MOJOSHADER_AST_DATATYPE_CONST);
1967         return retval;
1968     } // if
1969 
1970     retval->type = MOJOSHADER_AST_DATATYPE_ARRAY;
1971     retval->array.base = dt;
1972     if (soa->dimension == NULL)
1973     {
1974         retval->array.elements = -1;
1975         return retval;
1976     } // if
1977 
1978     // Run the expression to verify it's constant and produces a positive int.
1979     AstCalcData data;
1980     data.isflt = 0;
1981     data.value.i = 0;
1982     retval->array.elements = 16;  // sane default for failure.
1983     const int ok = calc_ast_const_expr(ctx, soa->dimension, &data);
1984 
1985     // reset error position.
1986     ctx->sourcefile = soa->ast.filename;
1987     ctx->sourceline = soa->ast.line;
1988 
1989     if (!ok)
1990         fail(ctx, "array dimensions not constant");
1991     else if (data.isflt)
1992         fail(ctx, "array dimensions not integer");
1993     else if (data.value.i < 0)
1994         fail(ctx, "array dimensions negative");
1995     else
1996         retval->array.elements = data.value.i;
1997 
1998     return retval;
1999 } // build_datatype
2000 
2001 
require_numeric_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2002 static void require_numeric_datatype(Context *ctx,
2003                                      const MOJOSHADER_astDataType *datatype)
2004 {
2005     datatype = reduce_datatype(ctx, datatype);
2006     if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2007         datatype = reduce_datatype(ctx, datatype->vector.base);
2008     else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2009         datatype = reduce_datatype(ctx, datatype->matrix.base);
2010 
2011     switch (datatype->type)
2012     {
2013         case MOJOSHADER_AST_DATATYPE_BOOL:
2014         case MOJOSHADER_AST_DATATYPE_INT:
2015         case MOJOSHADER_AST_DATATYPE_UINT:
2016         case MOJOSHADER_AST_DATATYPE_HALF:
2017         case MOJOSHADER_AST_DATATYPE_FLOAT:
2018         case MOJOSHADER_AST_DATATYPE_DOUBLE:
2019             return;
2020         default: break;
2021     } // switch
2022 
2023     fail(ctx, "Expected numeric type");  // !!! FIXME: fmt.
2024     // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
2025 } // require_numeric_datatype
2026 
require_integer_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2027 static void require_integer_datatype(Context *ctx,
2028                                      const MOJOSHADER_astDataType *datatype)
2029 {
2030     datatype = reduce_datatype(ctx, datatype);
2031     switch (datatype->type)
2032     {
2033         case MOJOSHADER_AST_DATATYPE_INT:
2034         case MOJOSHADER_AST_DATATYPE_UINT:
2035             return;
2036         default: break;
2037     } // switch
2038 
2039     fail(ctx, "Expected integer type");  // !!! FIXME: fmt.
2040     // !!! FIXME: replace AST node with an AST_OP_INT_LITERAL zero, keep going.
2041 } // require_integer_datatype
2042 
require_boolean_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2043 static void require_boolean_datatype(Context *ctx,
2044                                      const MOJOSHADER_astDataType *datatype)
2045 {
2046     datatype = reduce_datatype(ctx, datatype);
2047     switch (datatype->type)
2048     {
2049         case MOJOSHADER_AST_DATATYPE_BOOL:
2050         case MOJOSHADER_AST_DATATYPE_INT:
2051         case MOJOSHADER_AST_DATATYPE_UINT:
2052             return;
2053         default: break;
2054     } // switch
2055 
2056     fail(ctx, "Expected boolean type");  // !!! FIXME: fmt.
2057     // !!! FIXME: replace AST node with an AST_OP_BOOLEAN_LITERAL false, keep going.
2058 } // require_numeric_datatype
2059 
2060 
require_array_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2061 static void require_array_datatype(Context *ctx,
2062                                    const MOJOSHADER_astDataType *datatype)
2063 {
2064     datatype = reduce_datatype(ctx, datatype);
2065     if (datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY)
2066         return;
2067 
2068     fail(ctx, "expected array");
2069     // !!! FIXME: delete array dereference for further processing.
2070 } // require_array_datatype
2071 
2072 
require_struct_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2073 static void require_struct_datatype(Context *ctx,
2074                                     const MOJOSHADER_astDataType *datatype)
2075 {
2076     datatype = reduce_datatype(ctx, datatype);
2077     if (datatype->type == MOJOSHADER_AST_DATATYPE_STRUCT)
2078         return;
2079 
2080     fail(ctx, "expected struct");
2081     // !!! FIXME: delete struct dereference for further processing.
2082 } // require_struct_datatype
2083 
2084 
require_function_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2085 static int require_function_datatype(Context *ctx,
2086                                      const MOJOSHADER_astDataType *datatype)
2087 {
2088     datatype = reduce_datatype(ctx, datatype);
2089     if ((!datatype) || (datatype->type != MOJOSHADER_AST_DATATYPE_FUNCTION))
2090     {
2091         fail(ctx, "expected function");
2092         return 0;
2093     } // if
2094 
2095     return 1;
2096 } // require_function_datatype
2097 
2098 
2099 // Extract the individual element type from an array datatype.
array_element_datatype(Context * ctx,const MOJOSHADER_astDataType * datatype)2100 static const MOJOSHADER_astDataType *array_element_datatype(Context *ctx,
2101                                         const MOJOSHADER_astDataType *datatype)
2102 {
2103     datatype = reduce_datatype(ctx, datatype);
2104     assert(datatype->type == MOJOSHADER_AST_DATATYPE_ARRAY);
2105     return datatype->array.base;
2106 } // array_element_datatype
2107 
2108 
2109 // This tests two datatypes to see if they are compatible, and adds cast
2110 //  operator nodes to the AST if the program was relying on implicit
2111 //  casts between then. Will fail() if the datatypes can't be coerced
2112 //  with a cast at all. (left) can be NULL to say that its datatype is
2113 //  set in stone (an lvalue, for example). No other NULLs are allowed.
2114 // Returns final datatype used once implicit casting is complete.
2115 // The datatypes must be pointers from the string cache.
add_type_coercion(Context * ctx,MOJOSHADER_astExpression ** left,const MOJOSHADER_astDataType * _ldatatype,MOJOSHADER_astExpression ** right,const MOJOSHADER_astDataType * _rdatatype)2116 static const MOJOSHADER_astDataType *add_type_coercion(Context *ctx,
2117                                      MOJOSHADER_astExpression **left,
2118                                      const MOJOSHADER_astDataType *_ldatatype,
2119                                      MOJOSHADER_astExpression **right,
2120                                      const MOJOSHADER_astDataType *_rdatatype)
2121 {
2122     // !!! FIXME: this whole function is probably naive at best.
2123     const MOJOSHADER_astDataType *ldatatype = reduce_datatype(ctx, _ldatatype);
2124     const MOJOSHADER_astDataType *rdatatype = reduce_datatype(ctx, _rdatatype);
2125 
2126     if (ldatatype == rdatatype)
2127         return ldatatype;   // they already match, so we're done.
2128 
2129     struct {
2130         const MOJOSHADER_astDataTypeType type;
2131         const int bits;
2132         const int is_unsigned;
2133         const int floating;
2134     } typeinf[] = {
2135         { MOJOSHADER_AST_DATATYPE_BOOL,    1, 1, 0 },
2136         { MOJOSHADER_AST_DATATYPE_HALF,   16, 0, 1 },
2137         { MOJOSHADER_AST_DATATYPE_INT,    32, 0, 0 },
2138         { MOJOSHADER_AST_DATATYPE_UINT,   32, 1, 0 },
2139         { MOJOSHADER_AST_DATATYPE_FLOAT,  32, 0, 1 },
2140         { MOJOSHADER_AST_DATATYPE_DOUBLE, 64, 0, 1 },
2141     };
2142 
2143     int lvector = 0;
2144     int lmatrix = 0;
2145     int l = STATICARRAYLEN(typeinf);
2146     if (ldatatype != NULL)
2147     {
2148         MOJOSHADER_astDataTypeType type = ldatatype->type;
2149         if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
2150         {
2151             lvector = 1;
2152             type = ldatatype->vector.base->type;
2153         } // if
2154         else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
2155         {
2156             lmatrix = 1;
2157             type = ldatatype->matrix.base->type;
2158         } // if
2159 
2160         for (l = 0; l < STATICARRAYLEN(typeinf); l++)
2161         {
2162             if (typeinf[l].type == type)
2163                 break;
2164         } // for
2165     } // if
2166 
2167     int rvector = 0;
2168     int rmatrix = 0;
2169     int r = STATICARRAYLEN(typeinf);
2170     if (rdatatype != NULL)
2171     {
2172         MOJOSHADER_astDataTypeType type = rdatatype->type;
2173         if (type == MOJOSHADER_AST_DATATYPE_VECTOR)
2174         {
2175             rvector = 1;
2176             type = rdatatype->vector.base->type;
2177         } // if
2178         else if (type == MOJOSHADER_AST_DATATYPE_MATRIX)
2179         {
2180             rmatrix = 1;
2181             type = rdatatype->matrix.base->type;
2182         } // if
2183 
2184         for (r = 0; r < STATICARRAYLEN(typeinf); r++)
2185         {
2186             if (typeinf[r].type == type)
2187                 break;
2188         } // for
2189     } // if
2190 
2191     enum { CHOOSE_NEITHER, CHOOSE_LEFT, CHOOSE_RIGHT } choice = CHOOSE_NEITHER;
2192     if ((l < STATICARRAYLEN(typeinf)) && (r < STATICARRAYLEN(typeinf)))
2193     {
2194         if (left == NULL)
2195             choice = CHOOSE_LEFT;  // we need to force to the lvalue.
2196         else if (lmatrix && !rmatrix)
2197             choice = CHOOSE_LEFT;
2198         else if (!lmatrix && rmatrix)
2199             choice = CHOOSE_RIGHT;
2200         else if (lvector && !rvector)
2201             choice = CHOOSE_LEFT;
2202         else if (!lvector && rvector)
2203             choice = CHOOSE_RIGHT;
2204         else if (typeinf[l].bits > typeinf[r].bits)
2205             choice = CHOOSE_LEFT;
2206         else if (typeinf[l].bits < typeinf[r].bits)
2207             choice = CHOOSE_RIGHT;
2208         else if (typeinf[l].floating && !typeinf[r].floating)
2209             choice = CHOOSE_LEFT;
2210         else if (!typeinf[l].floating && typeinf[r].floating)
2211             choice = CHOOSE_RIGHT;
2212         else if (typeinf[l].is_unsigned && !typeinf[r].is_unsigned)
2213             choice = CHOOSE_LEFT;
2214         else if (!typeinf[l].is_unsigned && typeinf[r].is_unsigned)
2215             choice = CHOOSE_RIGHT;
2216     } // if
2217 
2218     if (choice == CHOOSE_LEFT)
2219     {
2220         *right = new_cast_expr(ctx, _ldatatype, *right);
2221         return _ldatatype;
2222     } // if
2223     else if (choice == CHOOSE_RIGHT)
2224     {
2225         *left = new_cast_expr(ctx, _rdatatype, *left);
2226         return _rdatatype;
2227     } // else if
2228 
2229     assert(choice == CHOOSE_NEITHER);
2230     fail(ctx, "incompatible data types");
2231     // Ditch original (*right), force a literal value that matches
2232     //  ldatatype, so further processing is normalized.
2233     // !!! FIXME: force (right) to match (left).
2234     delete_expr(ctx, *right);
2235     *right = new_cast_expr(ctx, _ldatatype, new_literal_int_expr(ctx, 0));
2236     return ldatatype;
2237 } // add_type_coercion
2238 
is_swizzle_str(const char * str,const int veclen)2239 static int is_swizzle_str(const char *str, const int veclen)
2240 {
2241     int i;
2242     int is_xyzw = 0;
2243     int is_rgba = 0;
2244 
2245     assert(*str != '\0');  // can this actually happen?
2246 
2247     for (i = 0; i < veclen; i++, str++)
2248     {
2249         const char ch = *str;
2250         if (ch == '\0')
2251             break;
2252         else if ((ch == 'x') || (ch == 'y') || (ch == 'z') || (ch == 'w'))
2253             is_xyzw = 1;
2254         else if ((ch == 'r') || (ch == 'g') || (ch == 'b') || (ch == 'a'))
2255             is_rgba = 1;
2256     } // for
2257 
2258     if (*str != '\0')  // must be end of string here.
2259         return 0;  // not a swizzle.
2260     return ((is_rgba + is_xyzw) == 1);  // can only be one or the other.
2261 } // is_swizzle_str
2262 
datatype_size(const MOJOSHADER_astDataType * dt)2263 static int datatype_size(const MOJOSHADER_astDataType *dt)
2264 {
2265     switch (dt->type)
2266     {
2267         case MOJOSHADER_AST_DATATYPE_BOOL: return 1;
2268         case MOJOSHADER_AST_DATATYPE_INT: return 4;
2269         case MOJOSHADER_AST_DATATYPE_UINT: return 4;
2270         case MOJOSHADER_AST_DATATYPE_FLOAT: return 4;
2271         case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 4;
2272         case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 4;
2273         case MOJOSHADER_AST_DATATYPE_HALF: return 2;
2274         case MOJOSHADER_AST_DATATYPE_DOUBLE: return 8;
2275             return 1;
2276         default:
2277             assert(0 && "Maybe should have used reduce_datatype()?");
2278             return 0;
2279     } // switch
2280 } // datatype_size
2281 
is_scalar_datatype(const MOJOSHADER_astDataType * dt)2282 static inline int is_scalar_datatype(const MOJOSHADER_astDataType *dt)
2283 {
2284     switch (dt->type)
2285     {
2286         case MOJOSHADER_AST_DATATYPE_BOOL:
2287         case MOJOSHADER_AST_DATATYPE_INT:
2288         case MOJOSHADER_AST_DATATYPE_UINT:
2289         case MOJOSHADER_AST_DATATYPE_FLOAT:
2290         case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
2291         case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
2292         case MOJOSHADER_AST_DATATYPE_HALF:
2293         case MOJOSHADER_AST_DATATYPE_DOUBLE:
2294             return 1;
2295         default:
2296             return 0;
2297     } // switch
2298 } // is_scalar_datatype
2299 
is_float_datatype(const MOJOSHADER_astDataType * dt)2300 static inline int is_float_datatype(const MOJOSHADER_astDataType *dt)
2301 {
2302     switch (dt->type)
2303     {
2304         case MOJOSHADER_AST_DATATYPE_FLOAT: return 1;
2305         case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM: return 1;
2306         case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM: return 1;
2307         default: return 0;
2308     } // switch
2309 } // is_float_datatype
2310 
datatype_elems(Context * ctx,const MOJOSHADER_astDataType * dt)2311 static int datatype_elems(Context *ctx, const MOJOSHADER_astDataType *dt)
2312 {
2313     dt = reduce_datatype(ctx, dt);
2314     switch (dt->type)
2315     {
2316         case MOJOSHADER_AST_DATATYPE_VECTOR:
2317             return dt->vector.elements;
2318         case MOJOSHADER_AST_DATATYPE_MATRIX:
2319             return dt->matrix.rows * dt->matrix.columns;
2320         default:
2321             return 1;
2322     } // switch
2323 } // datatype_elems
2324 
datatype_base(Context * ctx,const MOJOSHADER_astDataType * dt)2325 static const MOJOSHADER_astDataType *datatype_base(Context *ctx, const MOJOSHADER_astDataType *dt)
2326 {
2327     dt = reduce_datatype(ctx, dt);
2328     if (dt == NULL)
2329         return dt;
2330 
2331     switch (dt->type)
2332     {
2333         case MOJOSHADER_AST_DATATYPE_VECTOR:
2334             dt = dt->vector.base;
2335             break;
2336         case MOJOSHADER_AST_DATATYPE_MATRIX:
2337             dt = dt->matrix.base;
2338             break;
2339         case MOJOSHADER_AST_DATATYPE_BUFFER:
2340             dt = dt->buffer.base;
2341             break;
2342         case MOJOSHADER_AST_DATATYPE_ARRAY:
2343             dt = dt->array.base;
2344             break;
2345         default: break;
2346     } // switch
2347 
2348     return dt;
2349 } // datatype_base
2350 
2351 typedef enum
2352 {
2353     DT_MATCH_INCOMPATIBLE,         // flatly incompatible
2354     DT_MATCH_COMPATIBLE_DOWNCAST,  // would have to lose precision
2355     DT_MATCH_COMPATIBLE_UPCAST,    // would have to gain precision
2356     DT_MATCH_COMPATIBLE,           // can cast to without serious change.
2357     DT_MATCH_PERFECT               // identical datatype.
2358 } DatatypeMatch;
2359 
compatible_arg_datatype(Context * ctx,const MOJOSHADER_astDataType * arg,const MOJOSHADER_astDataType * param)2360 static DatatypeMatch compatible_arg_datatype(Context *ctx,
2361                                    const MOJOSHADER_astDataType *arg,
2362                                    const MOJOSHADER_astDataType *param)
2363 {
2364     // The matching rules for HLSL function overloading, as far as I can
2365     //  tell from experimenting with Microsoft's compiler, seem to be this:
2366     //
2367     // - All parameters of a function must match what the caller specified
2368     //   after possible type promotion via the following rules.
2369     // - If the number of arguments and the number of parameters don't match,
2370     //   that overload is immediately rejected.
2371     // - Each overloaded function is given a score that is the sum of the
2372     //   "worth" of each parameter vs the caller's arguments
2373     //   (see DatatypeMatch). The higher the score, the more favorable this
2374     //   function overload would be.
2375     // - If there is a tie for highest score between two or more function
2376     //   overloads, we declare that function call to be ambiguous and fail().
2377     // - Scalars can be promoted to vectors to make a parameter match.
2378     // - Scalars can promote to other scalars (short to int, etc).
2379     // - Datatypes can downcast, but should generate a warning.
2380     //   (calling void fn(float x); as fn((double)1.0) should warn).
2381     // - Vectors may NOT be extend (a float2 can't implicity extend to a
2382     //   float4).
2383     // - Vectors with the same elements can promote (a half2 can become
2384     //   a float2). Downcasting between vectors with the same number of
2385     //   elements is allowed.
2386     // - A perfect match of all params will be favored over any functions
2387     //   that only match if type promotion is applied (given a perfect match
2388     //   of all parameters, we'll stop looking for other matches).
2389 
2390     if (datatypes_match(arg, param))
2391         return DT_MATCH_PERFECT;  // that was easy.
2392 
2393     arg = reduce_datatype(ctx, arg);
2394     param = reduce_datatype(ctx, param);
2395 
2396     int do_base_test = 0;
2397 
2398     if (is_scalar_datatype(arg))
2399         do_base_test = 1; // we let these all go through for now.
2400 
2401     else if (arg->type == param->type)
2402     {
2403         if (arg->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2404             do_base_test = (arg->vector.elements == param->vector.elements);
2405         else if (arg->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2406         {
2407             do_base_test =
2408                 ((arg->matrix.rows == param->matrix.rows) &&
2409                  (arg->matrix.columns == param->matrix.columns));
2410         } // if
2411     } // if
2412 
2413     if (do_base_test)
2414     {
2415         arg = datatype_base(ctx, arg);
2416         param = datatype_base(ctx, param);
2417 
2418         const int argsize = datatype_size(arg);
2419         const int paramsize = datatype_size(param);
2420         const int argfloat = is_float_datatype(arg);
2421         const int paramfloat = is_float_datatype(param);
2422 
2423         if (argfloat && !paramfloat)
2424             return DT_MATCH_COMPATIBLE_DOWNCAST;  // always loss of precision.
2425         else if (argfloat && !paramfloat)
2426         {
2427             if (argsize < paramsize)
2428                 return DT_MATCH_COMPATIBLE_UPCAST;
2429             else
2430                 return DT_MATCH_COMPATIBLE_DOWNCAST;  // loss of precision.
2431         } // else if
2432         else if (argsize == paramsize)
2433             return DT_MATCH_COMPATIBLE;
2434         else if (argsize < paramsize)
2435             return DT_MATCH_COMPATIBLE_UPCAST;
2436         else /* if (argsize > paramsize) */
2437             return DT_MATCH_COMPATIBLE_DOWNCAST;
2438     } // if
2439 
2440     return DT_MATCH_INCOMPATIBLE;
2441 } // compatible_arg_datatype
2442 
2443 
2444 static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast);
2445 
2446 // !!! FIXME: this function sucks.
match_func_to_call(Context * ctx,MOJOSHADER_astExpressionCallFunction * ast)2447 static const MOJOSHADER_astDataType *match_func_to_call(Context *ctx,
2448                                     MOJOSHADER_astExpressionCallFunction *ast)
2449 {
2450     SymbolScope *best = NULL;  // best choice we find.
2451     int best_score = 0;
2452     MOJOSHADER_astExpressionIdentifier *ident = ast->identifier;
2453     const char *sym = ident->identifier;
2454     const void *value = NULL;
2455     void *iter = NULL;
2456 
2457     int argcount = 0;
2458     MOJOSHADER_astArguments *args = ast->args;
2459     while (args != NULL)
2460     {
2461         argcount++;
2462         type_check_ast(ctx, args->argument);
2463         args = args->next;
2464     } // while;
2465 
2466     // we do some tapdancing to handle function overloading here.
2467     int match = 0;
2468     while (hash_iter(ctx->variables.hash, sym, &value, &iter))
2469     {
2470         SymbolScope *item = (SymbolScope *) value;
2471         const MOJOSHADER_astDataType *dt = item->datatype;
2472         dt = reduce_datatype(ctx, dt);
2473         // there's a locally-scoped symbol with this name? It takes precedence.
2474         if (dt->type != MOJOSHADER_AST_DATATYPE_FUNCTION)
2475             return dt;
2476 
2477         const MOJOSHADER_astDataTypeFunction *dtfn = (MOJOSHADER_astDataTypeFunction *) dt;
2478         const int perfect = argcount * ((int) DT_MATCH_PERFECT);
2479         int score = 0;
2480 
2481         if (argcount == dtfn->num_params)  // !!! FIXME: default args.
2482         {
2483             args = ast->args;
2484             int i;
2485             for (i = 0; i < argcount; i++)
2486             {
2487                 assert(args != NULL);
2488                 dt = args->argument->datatype;
2489                 args = args->next;
2490                 const DatatypeMatch compatible = compatible_arg_datatype(ctx, dt, dtfn->params[i]);
2491                 if (compatible == DT_MATCH_INCOMPATIBLE)
2492                 {
2493                     args = NULL;
2494                     score = 0;
2495                     break;
2496                 } // if
2497 
2498                 score += (int) compatible;
2499             } // for
2500 
2501             if (args != NULL)
2502                 score = 0;  // too many arguments supplied. No match.
2503         } // else
2504 
2505         if (score == 0)  // incompatible.
2506             continue;
2507 
2508         else if (score == perfect)  // perfection! stop looking!
2509         {
2510             match = 1;  // ignore all other compatible matches.
2511             best = item;
2512             break;
2513         } // if
2514 
2515         else if (score >= best_score)  // compatible, but not perfect, match.
2516         {
2517             if (score == best_score)
2518             {
2519                 match++;
2520                 // !!! FIXME: list each possible function in a fail(),
2521                 // !!! FIXME:  but you can't actually fail() here, since
2522                 // !!! FIXME:  this may cease to be ambiguous if we get
2523                 // !!! FIXME:  a better match on a later overload.
2524             } // if
2525 
2526             else if (score > best_score)
2527             {
2528                 match = 1;  // reset the ambiguousness count.
2529                 best = item;
2530                 best_score = score;
2531             } // if
2532         } // else if
2533     } // while
2534 
2535     if (match > 1)
2536     {
2537         assert(best != NULL);
2538         failf(ctx, "Ambiguous function call to '%s'", sym);
2539     } // if
2540 
2541     if (best == NULL)
2542     {
2543         assert(match == 0);
2544         assert(best_score == 0);
2545         // !!! FIXME: ident->datatype = ?
2546         failf(ctx, "No matching function named '%s'", sym);
2547     } // if
2548     else
2549     {
2550         ident->datatype = reduce_datatype(ctx, best->datatype);
2551         ident->index = best->index;
2552     } // else
2553 
2554     return ident->datatype;
2555 } // match_func_to_call
2556 
2557 
vectype_from_base(Context * ctx,const MOJOSHADER_astDataType * base,const int len)2558 static const MOJOSHADER_astDataType *vectype_from_base(Context *ctx,
2559                                             const MOJOSHADER_astDataType *base,
2560                                             const int len)
2561 {
2562     assert(len > 0);
2563     assert(len <= 4);
2564 
2565     if (len == 1)  // return "float" and not "float1"
2566         return base;
2567 
2568     const char *typestr = NULL;
2569     switch (base->type)
2570     {
2571         case MOJOSHADER_AST_DATATYPE_BOOL: typestr = "bool"; break;
2572         case MOJOSHADER_AST_DATATYPE_INT: typestr = "int"; break;
2573         case MOJOSHADER_AST_DATATYPE_UINT: typestr = "uint"; break;
2574         case MOJOSHADER_AST_DATATYPE_HALF: typestr = "half"; break;
2575         case MOJOSHADER_AST_DATATYPE_FLOAT: typestr = "float"; break;
2576         case MOJOSHADER_AST_DATATYPE_DOUBLE: typestr = "double"; break;
2577         default: assert(0 && "This shouldn't happen"); break;
2578     } // switch
2579 
2580     char buf[32];
2581     snprintf(buf, sizeof (buf), "%s%d", typestr, len);
2582     const MOJOSHADER_astDataType *datatype = get_usertype(ctx, buf);
2583     assert(datatype != NULL);
2584     return datatype;
2585 } // vectype_from_base
2586 
2587 
2588 // Go through the AST and make sure all datatypes check out okay. For datatypes
2589 //  that are compatible but are relying on an implicit cast, we add explicit
2590 //  casts to the AST here, so further processing doesn't have to worry about
2591 //  type coercion.
2592 // For things that are incompatible, we generate errors and
2593 //  then replace them with reasonable defaults so further processing can
2594 //  continue (but code generation will be skipped due to errors).
2595 // This means further processing can assume the AST is sane and not have to
2596 //  spend effort verifying it again.
2597 // This stage will also set every AST node's datatype field, if it is
2598 //  meaningful to do so. This will allow conversion to IR to know what
2599 //  type/size a given node is.
type_check_ast(Context * ctx,void * _ast)2600 static const MOJOSHADER_astDataType *type_check_ast(Context *ctx, void *_ast)
2601 {
2602     MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
2603     const MOJOSHADER_astDataType *datatype = NULL;
2604     const MOJOSHADER_astDataType *datatype2 = NULL;
2605     const MOJOSHADER_astDataType *datatype3 = NULL;
2606 
2607     if ((!ast) || (ctx->out_of_memory))
2608         return NULL;
2609 
2610     // upkeep so we report correct error locations...
2611     ctx->sourcefile = ast->ast.filename;
2612     ctx->sourceline = ast->ast.line;
2613 
2614     switch (ast->ast.type)
2615     {
2616         case MOJOSHADER_AST_OP_POSTINCREMENT:
2617         case MOJOSHADER_AST_OP_POSTDECREMENT:
2618         case MOJOSHADER_AST_OP_PREINCREMENT:
2619         case MOJOSHADER_AST_OP_PREDECREMENT:
2620         case MOJOSHADER_AST_OP_COMPLEMENT:
2621         case MOJOSHADER_AST_OP_NEGATE:
2622             // !!! FIXME: must be lvalue.
2623             // !!! FIXME: bools must type-promote to ...int?
2624             // !!! FIXME: complement must not be float (...right?)
2625             datatype = type_check_ast(ctx, ast->unary.operand);
2626             require_numeric_datatype(ctx, datatype);
2627             ast->unary.datatype = datatype;
2628             return datatype;
2629 
2630         case MOJOSHADER_AST_OP_NOT:
2631             datatype = type_check_ast(ctx, ast->unary.operand);
2632             require_boolean_datatype(ctx, datatype);
2633             // !!! FIXME: coerce to bool here.
2634             ast->unary.datatype = &ctx->dt_bool;
2635             return datatype;
2636 
2637         case MOJOSHADER_AST_OP_DEREF_ARRAY:
2638             datatype = type_check_ast(ctx, ast->binary.left);
2639             datatype2 = type_check_ast(ctx, ast->binary.right);
2640             require_integer_datatype(ctx, datatype2);
2641             add_type_coercion(ctx, NULL, &ctx->dt_int, &ast->binary.right, datatype2);
2642 
2643             datatype = reduce_datatype(ctx, datatype);
2644             if (datatype->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2645             {
2646                 // !!! FIXME: if constant int, fail if not 0 >= value <= vecsize.
2647                 ast->binary.datatype = datatype->vector.base;
2648             } // if
2649             else if (datatype->type == MOJOSHADER_AST_DATATYPE_MATRIX)
2650             {
2651                 // !!! FIXME: if constant int, fail if not 0 >= value <= rowsize (colsize?).
2652                 ast->binary.datatype = vectype_from_base(ctx, datatype->matrix.base, datatype->matrix.columns);  // !!! FIXME: rows?
2653             }
2654             else
2655             {
2656                 require_array_datatype(ctx, datatype);
2657                 ast->binary.datatype = array_element_datatype(ctx, datatype);
2658             } // else
2659 
2660             return ast->binary.datatype;
2661 
2662         case MOJOSHADER_AST_OP_DEREF_STRUCT:
2663         {
2664             const char *member = ast->derefstruct.member;
2665             datatype = type_check_ast(ctx, ast->derefstruct.identifier);
2666             const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
2667 
2668             // Is this a swizzle and not a struct deref?
2669             if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2670             {
2671                 const int veclen = reduced->vector.elements;
2672                 ast->derefstruct.isswizzle = 1;
2673                 if (!is_swizzle_str(member, veclen))
2674                 {
2675                     fail(ctx, "invalid swizzle on vector");
2676                     // force this to be sane for further processing.
2677                     const char *sane_swiz = stringcache(ctx->strcache, "xyzw");
2678                     member = ast->derefstruct.member = sane_swiz;
2679                 } // if
2680 
2681                 const int swizlen = (int) strlen(member);
2682                 if (swizlen != veclen)
2683                     datatype = vectype_from_base(ctx, reduced->vector.base, swizlen);
2684 
2685                 ast->derefstruct.datatype = datatype;
2686                 return ast->derefstruct.datatype;
2687             } // if
2688 
2689             // maybe this is an actual struct?
2690             // !!! FIXME: replace with an int or something if not.
2691             require_struct_datatype(ctx, reduced);
2692 
2693             // map member to datatype
2694             assert(ast->derefstruct.datatype == NULL);
2695             const MOJOSHADER_astDataTypeStructMember *mbrs = reduced->structure.members;
2696             int i;
2697             for (i = 0; i < reduced->structure.member_count; i++)
2698             {
2699                 if (strcmp(mbrs[i].identifier, member) == 0)
2700                 {
2701                     ast->derefstruct.datatype = mbrs[i].datatype;
2702                     ast->derefstruct.member_index = i;
2703                     break;
2704                 } // if
2705             } // for
2706 
2707             if (ast->derefstruct.datatype == NULL)
2708             {
2709                 // !!! FIXME: replace with an int or something.
2710                 failf(ctx, "Struct has no member named '%s'", member);
2711             } // if
2712 
2713             return ast->derefstruct.datatype;
2714         } // case
2715 
2716         case MOJOSHADER_AST_OP_COMMA:
2717             // evaluate and throw away left, return right.
2718             type_check_ast(ctx, ast->binary.left);
2719             ast->binary.datatype = type_check_ast(ctx, ast->binary.right);
2720             return ast->binary.datatype;
2721 
2722         case MOJOSHADER_AST_OP_MULTIPLY:
2723         case MOJOSHADER_AST_OP_DIVIDE:
2724         case MOJOSHADER_AST_OP_ADD:
2725         case MOJOSHADER_AST_OP_SUBTRACT:
2726             datatype = type_check_ast(ctx, ast->binary.left);
2727             datatype2 = type_check_ast(ctx, ast->binary.right);
2728             require_numeric_datatype(ctx, datatype);
2729             require_numeric_datatype(ctx, datatype2);
2730             ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2731                                       datatype, &ast->binary.right, datatype2);
2732             return ast->binary.datatype;
2733 
2734         case MOJOSHADER_AST_OP_LSHIFT:
2735         case MOJOSHADER_AST_OP_RSHIFT:
2736         case MOJOSHADER_AST_OP_MODULO:
2737             datatype = type_check_ast(ctx, ast->binary.left);
2738             datatype2 = type_check_ast(ctx, ast->binary.right);
2739             require_integer_datatype(ctx, datatype);
2740             require_integer_datatype(ctx, datatype2);
2741             ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2742                                      datatype,  &ast->binary.right, datatype2);
2743             return ast->binary.datatype;
2744 
2745         case MOJOSHADER_AST_OP_LESSTHAN:
2746         case MOJOSHADER_AST_OP_GREATERTHAN:
2747         case MOJOSHADER_AST_OP_LESSTHANOREQUAL:
2748         case MOJOSHADER_AST_OP_GREATERTHANOREQUAL:
2749         case MOJOSHADER_AST_OP_NOTEQUAL:
2750         case MOJOSHADER_AST_OP_EQUAL:
2751             datatype = type_check_ast(ctx, ast->binary.left);
2752             datatype2 = type_check_ast(ctx, ast->binary.right);
2753             add_type_coercion(ctx, &ast->binary.left, datatype,
2754                               &ast->binary.right, datatype2);
2755             ast->binary.datatype = &ctx->dt_bool;
2756             return ast->binary.datatype;
2757 
2758         case MOJOSHADER_AST_OP_BINARYAND:
2759         case MOJOSHADER_AST_OP_BINARYXOR:
2760         case MOJOSHADER_AST_OP_BINARYOR:
2761             datatype = type_check_ast(ctx, ast->binary.left);
2762             datatype2 = type_check_ast(ctx, ast->binary.right);
2763             require_integer_datatype(ctx, datatype);
2764             require_integer_datatype(ctx, datatype2);
2765             ast->binary.datatype = add_type_coercion(ctx, &ast->binary.left,
2766                                       datatype, &ast->binary.right, datatype2);
2767             return ast->binary.datatype;
2768 
2769         case MOJOSHADER_AST_OP_LOGICALAND:
2770         case MOJOSHADER_AST_OP_LOGICALOR:
2771             datatype = type_check_ast(ctx, ast->binary.left);
2772             datatype2 = type_check_ast(ctx, ast->binary.right);
2773             require_boolean_datatype(ctx, datatype);
2774             require_boolean_datatype(ctx, datatype2);
2775             // !!! FIXME: coerce each to bool here, separately.
2776             add_type_coercion(ctx, &ast->binary.left, datatype,
2777                               &ast->binary.right, datatype2);
2778             ast->binary.datatype = &ctx->dt_bool;
2779 
2780         case MOJOSHADER_AST_OP_ASSIGN:
2781         case MOJOSHADER_AST_OP_MULASSIGN:
2782         case MOJOSHADER_AST_OP_DIVASSIGN:
2783         case MOJOSHADER_AST_OP_MODASSIGN:
2784         case MOJOSHADER_AST_OP_ADDASSIGN:
2785         case MOJOSHADER_AST_OP_SUBASSIGN:
2786         case MOJOSHADER_AST_OP_LSHIFTASSIGN:
2787         case MOJOSHADER_AST_OP_RSHIFTASSIGN:
2788         case MOJOSHADER_AST_OP_ANDASSIGN:
2789         case MOJOSHADER_AST_OP_XORASSIGN:
2790         case MOJOSHADER_AST_OP_ORASSIGN:
2791             // !!! FIXME: verify binary.left is an lvalue, or fail()!
2792             datatype = type_check_ast(ctx, ast->binary.left);
2793             datatype2 = type_check_ast(ctx, ast->binary.right);
2794             ast->binary.datatype = add_type_coercion(ctx, NULL, datatype,
2795                                                 &ast->binary.right, datatype2);
2796             return ast->binary.datatype;
2797 
2798         case MOJOSHADER_AST_OP_CONDITIONAL:
2799             datatype = type_check_ast(ctx, ast->ternary.left);
2800             datatype2 = type_check_ast(ctx, ast->ternary.center);
2801             datatype3 = type_check_ast(ctx, ast->ternary.right);
2802             require_numeric_datatype(ctx, datatype);
2803             ast->ternary.datatype = add_type_coercion(ctx, &ast->ternary.center,
2804                                     datatype2, &ast->ternary.right, datatype3);
2805             return ast->ternary.datatype;
2806 
2807         case MOJOSHADER_AST_OP_IDENTIFIER:
2808             datatype = find_variable(ctx, ast->identifier.identifier, &ast->identifier.index);
2809             if (datatype == NULL)
2810             {
2811                 fail(ctx, "Unknown identifier");
2812                 // !!! FIXME: replace with a sane default, move on.
2813                 datatype = &ctx->dt_int;
2814             } // if
2815             ast->identifier.datatype = datatype;
2816             return ast->identifier.datatype;
2817 
2818         case MOJOSHADER_AST_OP_INT_LITERAL:
2819         case MOJOSHADER_AST_OP_FLOAT_LITERAL:
2820         case MOJOSHADER_AST_OP_STRING_LITERAL:
2821         case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
2822             assert(ast->expression.datatype != NULL);
2823             return ast->expression.datatype;  // already set up during parsing.
2824 
2825         case MOJOSHADER_AST_ARGUMENTS:
2826             assert(0 && "Should be done by MOJOSHADER_AST_OP_CALLFUNC/CONSTRUCTOR");
2827             return NULL;
2828 
2829         case MOJOSHADER_AST_OP_CALLFUNC:
2830         {
2831             datatype = match_func_to_call(ctx, &ast->callfunc);
2832             const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, datatype);
2833             // !!! FIXME: replace AST node with an int if this isn't a func.
2834             if (!require_function_datatype(ctx, reduced))
2835             {
2836                 ast->callfunc.datatype = &ctx->dt_int;
2837                 return ast->callfunc.datatype;
2838             } // if
2839 
2840             MOJOSHADER_astArguments *arg = ast->callfunc.args;
2841             int i;
2842             for (i = 0; i < reduced->function.num_params; i++)
2843             {
2844                 if (arg == NULL)  // !!! FIXME: check for default parameters, fill them in.
2845                 {
2846                     fail(ctx, "Too few arguments");
2847                     // !!! FIXME: replace AST here.
2848                     break;
2849                 } // if
2850                 datatype2 = arg->argument->datatype;  // already type-checked.
2851                 add_type_coercion(ctx, NULL, reduced->function.params[i],
2852                                   &arg->argument, datatype2);
2853                 arg = arg->next;
2854             } // for
2855 
2856             assert(arg == NULL);  // shouldn't have chosen func if too many args.
2857 
2858             ast->callfunc.datatype = reduced->function.retval;
2859             return ast->callfunc.datatype;
2860         } // case
2861 
2862         case MOJOSHADER_AST_OP_CONSTRUCTOR:
2863         {
2864             const MOJOSHADER_astDataType *reduced = reduce_datatype(ctx, ast->constructor.datatype);
2865             const MOJOSHADER_astDataType *base_dt = reduced;
2866             int num_params = 1;
2867 
2868             assert(reduced != NULL);
2869             switch (reduced->type)
2870             {
2871                 case MOJOSHADER_AST_DATATYPE_VECTOR:
2872                     num_params = reduced->vector.elements;
2873                     base_dt = reduced->vector.base;
2874                     break;
2875                 case MOJOSHADER_AST_DATATYPE_MATRIX:
2876                     num_params = reduced->matrix.rows * reduced->matrix.columns;
2877                     base_dt = reduced->matrix.base;
2878                     break;
2879 
2880                 case MOJOSHADER_AST_DATATYPE_BOOL:
2881                 case MOJOSHADER_AST_DATATYPE_INT:
2882                 case MOJOSHADER_AST_DATATYPE_UINT:
2883                 case MOJOSHADER_AST_DATATYPE_FLOAT:
2884                 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
2885                 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
2886                 case MOJOSHADER_AST_DATATYPE_HALF:
2887                 case MOJOSHADER_AST_DATATYPE_DOUBLE:
2888                 case MOJOSHADER_AST_DATATYPE_STRING:
2889                     num_params = 1;
2890                     break;
2891 
2892                 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_STRUCT?
2893                 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_ARRAY?
2894                 // !!! FIXME: can you construct a MOJOSHADER_AST_DATATYPE_BUFFER?
2895 
2896                 default:
2897                     fail(ctx, "Invalid type for constructor");
2898                     delete_arguments(ctx, ast->constructor.args);
2899                     ast->constructor.args = new_argument(ctx, new_literal_int_expr(ctx, 0));
2900                     ast->constructor.datatype = &ctx->dt_int;
2901                     return ast->constructor.datatype;
2902             } // switch
2903 
2904             assert(num_params > 0);
2905 
2906             MOJOSHADER_astArguments *arg = ast->constructor.args;
2907             MOJOSHADER_astArguments *prev = NULL;
2908             int i;
2909             for (i = 0; i < num_params; i++)
2910             {
2911                 if (arg == NULL)  // !!! FIXME: check for default parameters.
2912                 {
2913                     fail(ctx, "Too few arguments");
2914                     // !!! FIXME: replace AST here.
2915                     break;
2916                 } // if
2917                 datatype2 = type_check_ast(ctx, arg->argument);
2918 
2919                 // "float4(float3(1,2,3),4)" is legal, so we need to see if
2920                 //  we're a vector, and jump that number of parameters instead
2921                 //  of doing type coercion.
2922                 reduced = reduce_datatype(ctx, datatype2);
2923                 if (reduced->type == MOJOSHADER_AST_DATATYPE_VECTOR)
2924                 {
2925                     // make sure things like float4(half3(1,2,3),1) convert that half3 to float3.
2926                     const int count = reduced->vector.elements;
2927                     datatype3 = vectype_from_base(ctx, base_dt, count);
2928                     add_type_coercion(ctx, NULL, datatype3, &arg->argument, datatype2);
2929                     i += count - 1;
2930                 } // else
2931                 else
2932                 {
2933                     add_type_coercion(ctx, NULL, base_dt, &arg->argument, datatype2);
2934                 } // else
2935                 prev = arg;
2936                 arg = arg->next;
2937             } // for
2938 
2939             if (arg != NULL)
2940             {
2941                 fail(ctx, "Too many arguments");
2942                 // Process extra arguments then chop them out.
2943                 MOJOSHADER_astArguments *argi;
2944                 for (argi = arg; argi != NULL; argi = argi->next)
2945                     type_check_ast(ctx, argi->argument);
2946                 if (prev != NULL)
2947                     prev->next = NULL;
2948                 delete_arguments(ctx, arg);
2949             } // if
2950 
2951             return ast->constructor.datatype;
2952         } // case
2953 
2954         case MOJOSHADER_AST_OP_CAST:
2955             datatype = sanitize_datatype(ctx, ast->cast.datatype);
2956             datatype2 = type_check_ast(ctx, ast->cast.operand);
2957             // you still need type coercion, since you could do a wrong cast,
2958             //  like "int x = (short) mychar;"
2959             add_type_coercion(ctx, NULL, datatype, &ast->cast.operand, datatype2);
2960             return datatype;
2961 
2962         case MOJOSHADER_AST_STATEMENT_BREAK:
2963             if ((ctx->loop_count == 0) && (ctx->switch_count == 0))
2964                 fail(ctx, "Break outside loop or switch");
2965             // !!! FIXME: warn if unreachable statements follow?
2966             type_check_ast(ctx, ast->stmt.next);
2967             return NULL;
2968 
2969         case MOJOSHADER_AST_STATEMENT_CONTINUE:
2970             if (ctx->loop_count == 0)
2971                 fail(ctx, "Continue outside loop");
2972             // !!! FIXME: warn if unreachable statements follow?
2973             type_check_ast(ctx, ast->stmt.next);
2974             return NULL;
2975 
2976         case MOJOSHADER_AST_STATEMENT_DISCARD:
2977             // !!! FIXME: warn if unreachable statements follow?
2978             type_check_ast(ctx, ast->stmt.next);
2979             return NULL;
2980 
2981         case MOJOSHADER_AST_STATEMENT_EMPTY:
2982             type_check_ast(ctx, ast->stmt.next);
2983             return NULL;
2984 
2985         case MOJOSHADER_AST_STATEMENT_EXPRESSION:
2986             // !!! FIXME: warn about expressions without a side-effect here?
2987             type_check_ast(ctx, ast->exprstmt.expr);  // !!! FIXME: This is named badly...
2988             type_check_ast(ctx, ast->exprstmt.next);
2989             return NULL;
2990 
2991         case MOJOSHADER_AST_STATEMENT_IF:
2992             push_scope(ctx);  // new scope for "if ((int x = blah()) != 0)"
2993             type_check_ast(ctx, ast->ifstmt.expr);
2994             type_check_ast(ctx, ast->ifstmt.statement);
2995             pop_scope(ctx);
2996             type_check_ast(ctx, ast->ifstmt.next);
2997             return NULL;
2998 
2999         case MOJOSHADER_AST_STATEMENT_TYPEDEF:
3000             type_check_ast(ctx, ast->typedefstmt.type_info);
3001             type_check_ast(ctx, ast->typedefstmt.next);
3002             return NULL;
3003 
3004         case MOJOSHADER_AST_STATEMENT_SWITCH:
3005         {
3006             ctx->switch_count++;
3007             MOJOSHADER_astSwitchCases *cases = ast->switchstmt.cases;
3008             // !!! FIXME: expr must be POD (no structs, arrays, etc!).
3009             datatype = type_check_ast(ctx, ast->switchstmt.expr);
3010             while (cases)
3011             {
3012                 // !!! FIXME: case must be POD (no structs, arrays, etc!).
3013                 datatype2 = type_check_ast(ctx, cases->expr);
3014                 add_type_coercion(ctx, NULL, datatype,
3015                                   &cases->expr, datatype2);
3016                 type_check_ast(ctx, cases->statement);
3017                 cases = cases->next;
3018             } // while
3019             ctx->switch_count--;
3020             type_check_ast(ctx, ast->switchstmt.next);
3021             return NULL;
3022         } // case
3023 
3024         case MOJOSHADER_AST_SWITCH_CASE:
3025             assert(0 && "Should be done by MOJOSHADER_AST_STATEMENT_SWITCH.");
3026             return NULL;
3027 
3028         case MOJOSHADER_AST_STATEMENT_STRUCT:
3029             type_check_ast(ctx, ast->structstmt.struct_info);
3030             type_check_ast(ctx, ast->structstmt.next);
3031             return NULL;
3032 
3033         case MOJOSHADER_AST_STATEMENT_VARDECL:
3034             type_check_ast(ctx, ast->vardeclstmt.declaration);
3035             type_check_ast(ctx, ast->vardeclstmt.next);
3036             return NULL;
3037 
3038         case MOJOSHADER_AST_STATEMENT_BLOCK:
3039             push_scope(ctx);  // new vars declared here live until '}'.
3040             type_check_ast(ctx, ast->blockstmt.statements);
3041             pop_scope(ctx);
3042             type_check_ast(ctx, ast->blockstmt.next);
3043             return NULL;
3044 
3045         case MOJOSHADER_AST_STATEMENT_FOR:
3046             ctx->loop_count++;
3047             push_scope(ctx);  // new scope for "for (int x = 0; ...)"
3048             type_check_ast(ctx, ast->forstmt.var_decl);
3049             type_check_ast(ctx, ast->forstmt.initializer);
3050             type_check_ast(ctx, ast->forstmt.looptest);
3051             type_check_ast(ctx, ast->forstmt.counter);
3052             type_check_ast(ctx, ast->forstmt.statement);
3053             pop_scope(ctx);
3054             ctx->loop_count--;
3055             type_check_ast(ctx, ast->forstmt.next);
3056             return NULL;
3057 
3058         case MOJOSHADER_AST_STATEMENT_DO:
3059             ctx->loop_count++;
3060             // !!! FIXME: should there be a push_scope() here?
3061             type_check_ast(ctx, ast->dostmt.statement);
3062             push_scope(ctx);  // new scope for "while ((int x = blah()) != 0)"
3063             type_check_ast(ctx, ast->dostmt.expr);
3064             pop_scope(ctx);
3065             ctx->loop_count--;
3066             type_check_ast(ctx, ast->dostmt.next);
3067             return NULL;
3068 
3069         case MOJOSHADER_AST_STATEMENT_WHILE:
3070             ctx->loop_count++;
3071             push_scope(ctx);  // new scope for "while ((int x = blah()) != 0)"
3072             type_check_ast(ctx, ast->whilestmt.expr);
3073             type_check_ast(ctx, ast->whilestmt.statement);
3074             pop_scope(ctx);
3075             ctx->loop_count--;
3076             type_check_ast(ctx, ast->whilestmt.next);
3077             return NULL;
3078 
3079         case MOJOSHADER_AST_STATEMENT_RETURN:
3080             // !!! FIXME: type coercion to outer function's return type.
3081             // !!! FIXME: warn if unreachable statements follow?
3082             type_check_ast(ctx, ast->returnstmt.expr);
3083             type_check_ast(ctx, ast->returnstmt.next);
3084             return NULL;
3085 
3086         case MOJOSHADER_AST_COMPUNIT_FUNCTION:
3087             assert(!ctx->is_func_scope);
3088 
3089             // We have to tapdance here to make sure the function is in
3090             //  the global scope, but it's parameters are pushed as variables
3091             //  in the function's scope.
3092             datatype = type_check_ast(ctx, ast->funcunit.declaration);
3093             ast->funcunit.index = push_function(ctx,
3094                                 ast->funcunit.declaration->identifier,
3095                                 datatype, ast->funcunit.definition == NULL);
3096 
3097             // not just a declaration, but a full function definition?
3098             if (ast->funcunit.definition != NULL)
3099             {
3100                 assert(ctx->loop_count == 0);
3101                 assert(ctx->switch_count == 0);
3102                 ctx->is_func_scope = 1;
3103                 ctx->var_index = 0;  // reset this every function.
3104                 push_scope(ctx);  // so function params are in function scope.
3105                 // repush the parameters before checking the actual function.
3106                 MOJOSHADER_astFunctionParameters *param;
3107                 for (param = ast->funcunit.declaration->params; param; param = param->next)
3108                     push_variable(ctx, param->identifier, param->datatype);
3109                 type_check_ast(ctx, ast->funcunit.definition);
3110                 pop_scope(ctx);
3111                 ctx->is_func_scope = 0;
3112                 assert(ctx->loop_count == 0);
3113                 assert(ctx->switch_count == 0);
3114             } // else
3115 
3116             type_check_ast(ctx, ast->funcunit.next);
3117             return NULL;
3118 
3119         case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
3120             type_check_ast(ctx, ast->typedefunit.type_info);
3121             type_check_ast(ctx, ast->typedefunit.next);
3122             return NULL;
3123 
3124         case MOJOSHADER_AST_COMPUNIT_STRUCT:
3125             type_check_ast(ctx, ast->structunit.struct_info);
3126             type_check_ast(ctx, ast->structunit.next);
3127             return NULL;
3128 
3129         case MOJOSHADER_AST_COMPUNIT_VARIABLE:
3130             type_check_ast(ctx, ast->varunit.declaration);
3131             type_check_ast(ctx, ast->varunit.next);
3132             return NULL;
3133 
3134         case MOJOSHADER_AST_SCALAR_OR_ARRAY:
3135             assert(0 && "Should be done by other AST nodes.");
3136             return NULL;
3137 
3138         case MOJOSHADER_AST_TYPEDEF:
3139         {
3140             MOJOSHADER_astScalarOrArray *soa = ast->typdef.details;
3141             datatype = get_usertype(ctx, soa->identifier);
3142             if (datatype != NULL)
3143             {
3144                 fail(ctx, "typedef already defined");
3145                 ast->typdef.datatype = datatype;
3146                 return datatype;
3147             } // if
3148 
3149             datatype = build_datatype(ctx, ast->typdef.isconst,
3150                                       ast->typdef.datatype, soa);
3151             if (datatype == NULL)
3152                 return NULL;  // out of memory?
3153 
3154             push_usertype(ctx, soa->identifier, datatype);
3155             ast->typdef.datatype = datatype;
3156             return ast->typdef.datatype;
3157         } // case
3158 
3159         case MOJOSHADER_AST_FUNCTION_PARAMS:
3160             assert(0 && "Should be done by MOJOSHADER_AST_FUNCTION_SIGNATURE");
3161 
3162         case MOJOSHADER_AST_FUNCTION_SIGNATURE:
3163         {
3164             MOJOSHADER_astFunctionParameters *param;
3165             const MOJOSHADER_astDataType *dtparams[64];
3166 
3167             int i = 0;
3168             for (param = ast->funcsig.params; param; param = param->next)
3169             {
3170                 assert(i <= STATICARRAYLEN(dtparams));  // laziness.
3171                 sanitize_datatype(ctx, param->datatype);
3172                 if (param->initializer != NULL)
3173                 {
3174                     datatype2 = type_check_ast(ctx, param->initializer);
3175                     add_type_coercion(ctx, NULL, param->datatype,
3176                                       &param->initializer, datatype2);
3177                 } // if
3178                 dtparams[i] = param->datatype;
3179                 i++;
3180             } // for
3181 
3182             ast->funcsig.datatype = build_function_datatype(ctx,
3183                                                         ast->funcsig.datatype,
3184                                                         i, dtparams, 0);
3185             return ast->funcsig.datatype;
3186         } // case
3187 
3188         case MOJOSHADER_AST_STRUCT_DECLARATION:
3189         {
3190             // !!! FIXME: We don't handle struct predeclaration at all right now
3191             // !!! FIXME:  (neither does the grammar)...not only does that mean
3192             // !!! FIXME:  you need to know the struct definition up front, but
3193             // !!! FIXME:  you can't do "struct XXX *next;" for a self-referencing
3194             // !!! FIXME:  linked list struct thing. This probably isn't a big
3195             // !!! FIXME:  deal, as there aren't (CURRENTLY!) pointers in HLSL,
3196             // !!! FIXME:  but you never know.
3197 
3198             const MOJOSHADER_astStructMembers *mbrs;
3199 
3200             // !!! FIXME: count this during parsing?
3201             int count = 0;
3202             mbrs = ast->structdecl.members;
3203             while (mbrs != NULL)
3204             {
3205                 count++;
3206                 mbrs = mbrs->next;
3207             } // while
3208 
3209             // !!! FIXME: this is hacky.
3210             MOJOSHADER_astDataTypeStructMember *dtmbrs;
3211             void *ptr = Malloc(ctx, sizeof (*dtmbrs) * count);
3212             if (ptr == NULL)
3213                 return NULL;
3214             if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
3215             {
3216                 Free(ctx, ptr);
3217                 return NULL;
3218             } // if
3219             dtmbrs = (MOJOSHADER_astDataTypeStructMember *) ptr;
3220 
3221             ptr = Malloc(ctx, sizeof (MOJOSHADER_astDataType));
3222             if (ptr == NULL)
3223                 return NULL;
3224             if (!buffer_append(ctx->garbage, &ptr, sizeof (ptr)))
3225             {
3226                 Free(ctx, ptr);
3227                 return NULL;
3228             } // if
3229             MOJOSHADER_astDataType *dt = (MOJOSHADER_astDataType *) ptr;
3230 
3231             mbrs = ast->structdecl.members;
3232             int i;
3233             for (i = 0; i < count; i++)
3234             {
3235                 // !!! FIXME: current grammar forbids const keyword on struct members!
3236                 dtmbrs[i].datatype = build_datatype(ctx, 0, mbrs->datatype, mbrs->details);
3237                 dtmbrs[i].identifier = mbrs->details->identifier;  // cached!
3238                 mbrs = mbrs->next;
3239             } // for
3240 
3241             dt->structure.type = MOJOSHADER_AST_DATATYPE_STRUCT;
3242             dt->structure.members = dtmbrs;
3243             dt->structure.member_count = count;
3244             ast->structdecl.datatype = dt;
3245 
3246             // !!! FIXME: this shouldn't push for anonymous structs: "struct { int x; } myvar;"
3247             // !!! FIXME:  but right now, the grammar is wrong and requires a name for the struct.
3248             push_usertype(ctx, ast->structdecl.name, ast->structdecl.datatype);
3249             return ast->structdecl.datatype;
3250         } // case
3251 
3252         case MOJOSHADER_AST_STRUCT_MEMBER:
3253             assert(0 && "Should be done by MOJOSHADER_AST_STRUCT_DECLARATION.");
3254             return NULL;
3255 
3256         case MOJOSHADER_AST_VARIABLE_DECLARATION:
3257         {
3258             MOJOSHADER_astVariableDeclaration *decl = &ast->vardecl;
3259 
3260             // this is true now, but we'll fill in ->datatype no matter what.
3261             assert((decl->datatype && !decl->anonymous_datatype) ||
3262                    (!decl->datatype && decl->anonymous_datatype));
3263 
3264             // An anonymous struct? That AST node does the heavy lifting.
3265             if (decl->anonymous_datatype != NULL)
3266                 datatype = type_check_ast(ctx, decl->anonymous_datatype);
3267             else
3268             {
3269                 datatype = build_datatype(ctx, (decl->attributes & MOJOSHADER_AST_VARATTR_CONST) != 0,
3270                                           decl->datatype, decl->details);
3271             } // else
3272 
3273             while (decl != NULL)
3274             {
3275                 decl->datatype = datatype;
3276                 push_variable(ctx, decl->details->identifier, datatype);
3277                 if (decl->initializer != NULL)
3278                 {
3279                     datatype2 = type_check_ast(ctx, decl->initializer);
3280                     add_type_coercion(ctx, NULL, datatype, &decl->initializer, datatype2);
3281                 } // if
3282 
3283                 type_check_ast(ctx, decl->annotations);
3284                 type_check_ast(ctx, decl->lowlevel);
3285                 decl = decl->next;
3286             } // while
3287 
3288             return datatype;
3289         } // case
3290 
3291         case MOJOSHADER_AST_ANNOTATION:
3292         {
3293             MOJOSHADER_astAnnotations *anno = &ast->annotations;
3294             while (anno)
3295             {
3296                 type_check_ast(ctx, anno->initializer);
3297                 anno = anno->next;
3298             } // while
3299             return NULL;
3300         } // case
3301 
3302         case MOJOSHADER_AST_PACK_OFFSET:
3303         case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
3304             return NULL;  // no-op (for now, at least).
3305 
3306         default:
3307             assert(0 && "unexpected type");
3308     } // switch
3309 
3310     return NULL;
3311 } // type_check_ast
3312 
3313 
semantic_analysis(Context * ctx)3314 static inline void semantic_analysis(Context *ctx)
3315 {
3316     type_check_ast(ctx, ctx->ast);
3317 } // semantic_analysis
3318 
3319 // !!! FIXME: isn't this a cut-and-paste of somewhere else?
strtoi64(const char * str,unsigned int len)3320 static inline int64 strtoi64(const char *str, unsigned int len)
3321 {
3322     int64 retval = 0;
3323     int64 mult = 1;
3324     int i = 0;
3325 
3326     while ((len) && (*str == ' '))
3327     {
3328         str++;
3329         len--;
3330     } // while
3331 
3332     if ((len) && (*str == '-'))
3333     {
3334         mult = -1;
3335         str++;
3336         len--;
3337     } // if
3338 
3339     while (i < len)
3340     {
3341         const char ch = str[i];
3342         if ((ch < '0') || (ch > '9'))
3343             break;
3344         i++;
3345     } // while
3346 
3347     while (--i >= 0)
3348     {
3349         const char ch = str[i];
3350         retval += ((int64) (ch - '0')) * mult;
3351         mult *= 10;
3352     } // while
3353 
3354     return retval;
3355 } // strtoi64
3356 
3357 // !!! FIXME: isn't this a cut-and-paste of somewhere else?
strtodouble(const char * _str,unsigned int len)3358 static inline double strtodouble(const char *_str, unsigned int len)
3359 {
3360     // !!! FIXME: laziness prevails.
3361     char *str = (char *) alloca(len+1);
3362     memcpy(str, _str, len);
3363     str[len] = '\0';
3364     return strtod(str, NULL);
3365 } // strtodouble
3366 
3367 #if 0
3368 // This does not check correctness (POSITIONT993842 passes, etc).
3369 static int is_semantic(const Context *ctx, const char *token,
3370                        const unsigned int tokenlen)
3371 {
3372     static const char *names[] = {
3373         "BINORMAL", "BLENDINDICES", "BLENDWEIGHT",
3374         "COLOR", "NORMAL", "POSITION", "POSITIONT", "PSIZE", "TANGENT",
3375         "TEXCOORD", "FOG", "TESSFACTOR", "TEXCOORD", "VFACE", "VPOS",
3376         "DEPTH", NULL
3377     };
3378 
3379     // !!! FIXME: DX10 has SV_* ("System Value Semantics").
3380     const char **i;
3381     for (i = names; *i; i++)
3382     {
3383         const char *name = *i;
3384         const size_t namelen = strlen(name);
3385         if (tokenlen < namelen)
3386             continue;
3387         else if (memcmp(token, name, namelen) != 0)
3388             continue;
3389 
3390         for (name += namelen; *name; name++)
3391         {
3392             if ((*name < '0') || (*name > '9'))
3393                 break;
3394         } // for
3395 
3396         if (*name == '\0')
3397             return 1;
3398     } // for
3399 
3400     return 0;
3401 } // is_semantic
3402 #endif
3403 
convert_to_lemon_token(Context * ctx,const char * token,unsigned int tokenlen,const Token tokenval)3404 static int convert_to_lemon_token(Context *ctx, const char *token,
3405                                   unsigned int tokenlen, const Token tokenval)
3406 {
3407     switch (tokenval)
3408     {
3409         case ((Token) ','): return TOKEN_HLSL_COMMA;
3410         case ((Token) '='): return TOKEN_HLSL_ASSIGN;
3411         case ((Token) TOKEN_ADDASSIGN): return TOKEN_HLSL_ADDASSIGN;
3412         case ((Token) TOKEN_SUBASSIGN): return TOKEN_HLSL_SUBASSIGN;
3413         case ((Token) TOKEN_MULTASSIGN): return TOKEN_HLSL_MULASSIGN;
3414         case ((Token) TOKEN_DIVASSIGN): return TOKEN_HLSL_DIVASSIGN;
3415         case ((Token) TOKEN_MODASSIGN): return TOKEN_HLSL_MODASSIGN;
3416         case ((Token) TOKEN_LSHIFTASSIGN): return TOKEN_HLSL_LSHIFTASSIGN;
3417         case ((Token) TOKEN_RSHIFTASSIGN): return TOKEN_HLSL_RSHIFTASSIGN;
3418         case ((Token) TOKEN_ANDASSIGN): return TOKEN_HLSL_ANDASSIGN;
3419         case ((Token) TOKEN_ORASSIGN): return TOKEN_HLSL_ORASSIGN;
3420         case ((Token) TOKEN_XORASSIGN): return TOKEN_HLSL_XORASSIGN;
3421         case ((Token) '?'): return TOKEN_HLSL_QUESTION;
3422         case ((Token) TOKEN_OROR): return TOKEN_HLSL_OROR;
3423         case ((Token) TOKEN_ANDAND): return TOKEN_HLSL_ANDAND;
3424         case ((Token) '|'): return TOKEN_HLSL_OR;
3425         case ((Token) '^'): return TOKEN_HLSL_XOR;
3426         case ((Token) '&'): return TOKEN_HLSL_AND;
3427         case ((Token) TOKEN_EQL): return TOKEN_HLSL_EQL;
3428         case ((Token) TOKEN_NEQ): return TOKEN_HLSL_NEQ;
3429         case ((Token) '<'): return TOKEN_HLSL_LT;
3430         case ((Token) TOKEN_LEQ): return TOKEN_HLSL_LEQ;
3431         case ((Token) '>'): return TOKEN_HLSL_GT;
3432         case ((Token) TOKEN_GEQ): return TOKEN_HLSL_GEQ;
3433         case ((Token) TOKEN_LSHIFT): return TOKEN_HLSL_LSHIFT;
3434         case ((Token) TOKEN_RSHIFT): return TOKEN_HLSL_RSHIFT;
3435         case ((Token) '+'): return TOKEN_HLSL_PLUS;
3436         case ((Token) '-'): return TOKEN_HLSL_MINUS;
3437         case ((Token) '*'): return TOKEN_HLSL_STAR;
3438         case ((Token) '/'): return TOKEN_HLSL_SLASH;
3439         case ((Token) '%'): return TOKEN_HLSL_PERCENT;
3440         case ((Token) '!'): return TOKEN_HLSL_EXCLAMATION;
3441         case ((Token) '~'): return TOKEN_HLSL_COMPLEMENT;
3442         case ((Token) TOKEN_DECREMENT): return TOKEN_HLSL_MINUSMINUS;
3443         case ((Token) TOKEN_INCREMENT): return TOKEN_HLSL_PLUSPLUS;
3444         case ((Token) '.'): return TOKEN_HLSL_DOT;
3445         case ((Token) '['): return TOKEN_HLSL_LBRACKET;
3446         case ((Token) ']'): return TOKEN_HLSL_RBRACKET;
3447         case ((Token) '('): return TOKEN_HLSL_LPAREN;
3448         case ((Token) ')'): return TOKEN_HLSL_RPAREN;
3449         case ((Token) TOKEN_INT_LITERAL): return TOKEN_HLSL_INT_CONSTANT;
3450         case ((Token) TOKEN_FLOAT_LITERAL): return TOKEN_HLSL_FLOAT_CONSTANT;
3451         case ((Token) TOKEN_STRING_LITERAL): return TOKEN_HLSL_STRING_LITERAL;
3452         case ((Token) ':'): return TOKEN_HLSL_COLON;
3453         case ((Token) ';'): return TOKEN_HLSL_SEMICOLON;
3454         case ((Token) '{'): return TOKEN_HLSL_LBRACE;
3455         case ((Token) '}'): return TOKEN_HLSL_RBRACE;
3456         //case ((Token) TOKEN_PP_PRAGMA): return TOKEN_HLSL_PRAGMA;
3457         //case ((Token) '\n'): return TOKEN_HLSL_NEWLINE;
3458 
3459         case ((Token) TOKEN_IDENTIFIER):
3460             #define tokencmp(t) ((tokenlen == strlen(t)) && (memcmp(token, t, tokenlen) == 0))
3461             //case ((Token) ''): return TOKEN_HLSL_TYPECAST
3462             //if (tokencmp("")) return TOKEN_HLSL_TYPE_NAME
3463             //if (tokencmp("...")) return TOKEN_HLSL_ELIPSIS
3464             if (tokencmp("else")) return TOKEN_HLSL_ELSE;
3465             if (tokencmp("inline")) return TOKEN_HLSL_INLINE;
3466             if (tokencmp("void")) return TOKEN_HLSL_VOID;
3467             if (tokencmp("in")) return TOKEN_HLSL_IN;
3468             if (tokencmp("inout")) return TOKEN_HLSL_INOUT;
3469             if (tokencmp("out")) return TOKEN_HLSL_OUT;
3470             if (tokencmp("uniform")) return TOKEN_HLSL_UNIFORM;
3471             if (tokencmp("linear")) return TOKEN_HLSL_LINEAR;
3472             if (tokencmp("centroid")) return TOKEN_HLSL_CENTROID;
3473             if (tokencmp("nointerpolation")) return TOKEN_HLSL_NOINTERPOLATION;
3474             if (tokencmp("noperspective")) return TOKEN_HLSL_NOPERSPECTIVE;
3475             if (tokencmp("sample")) return TOKEN_HLSL_SAMPLE;
3476             if (tokencmp("struct")) return TOKEN_HLSL_STRUCT;
3477             if (tokencmp("typedef")) return TOKEN_HLSL_TYPEDEF;
3478             if (tokencmp("const")) return TOKEN_HLSL_CONST;
3479             if (tokencmp("packoffset")) return TOKEN_HLSL_PACKOFFSET;
3480             if (tokencmp("register")) return TOKEN_HLSL_REGISTER;
3481             if (tokencmp("extern")) return TOKEN_HLSL_EXTERN;
3482             if (tokencmp("shared")) return TOKEN_HLSL_SHARED;
3483             if (tokencmp("static")) return TOKEN_HLSL_STATIC;
3484             if (tokencmp("volatile")) return TOKEN_HLSL_VOLATILE;
3485             if (tokencmp("row_major")) return TOKEN_HLSL_ROWMAJOR;
3486             if (tokencmp("column_major")) return TOKEN_HLSL_COLUMNMAJOR;
3487             if (tokencmp("bool")) return TOKEN_HLSL_BOOL;
3488             if (tokencmp("int")) return TOKEN_HLSL_INT;
3489             if (tokencmp("uint")) return TOKEN_HLSL_UINT;
3490             if (tokencmp("half")) return TOKEN_HLSL_HALF;
3491             if (tokencmp("float")) return TOKEN_HLSL_FLOAT;
3492             if (tokencmp("double")) return TOKEN_HLSL_DOUBLE;
3493             if (tokencmp("string")) return TOKEN_HLSL_STRING;
3494             if (tokencmp("snorm")) return TOKEN_HLSL_SNORM;
3495             if (tokencmp("unorm")) return TOKEN_HLSL_UNORM;
3496             if (tokencmp("buffer")) return TOKEN_HLSL_BUFFER;
3497             if (tokencmp("vector")) return TOKEN_HLSL_VECTOR;
3498             if (tokencmp("matrix")) return TOKEN_HLSL_MATRIX;
3499             if (tokencmp("break")) return TOKEN_HLSL_BREAK;
3500             if (tokencmp("continue")) return TOKEN_HLSL_CONTINUE;
3501             if (tokencmp("discard")) return TOKEN_HLSL_DISCARD;
3502             if (tokencmp("return")) return TOKEN_HLSL_RETURN;
3503             if (tokencmp("while")) return TOKEN_HLSL_WHILE;
3504             if (tokencmp("for")) return TOKEN_HLSL_FOR;
3505             if (tokencmp("unroll")) return TOKEN_HLSL_UNROLL;
3506             if (tokencmp("loop")) return TOKEN_HLSL_LOOP;
3507             if (tokencmp("do")) return TOKEN_HLSL_DO;
3508             if (tokencmp("if")) return TOKEN_HLSL_IF;
3509             if (tokencmp("branch")) return TOKEN_HLSL_BRANCH;
3510             if (tokencmp("flatten")) return TOKEN_HLSL_FLATTEN;
3511             if (tokencmp("switch")) return TOKEN_HLSL_SWITCH;
3512             if (tokencmp("forcecase")) return TOKEN_HLSL_FORCECASE;
3513             if (tokencmp("call")) return TOKEN_HLSL_CALL;
3514             if (tokencmp("case")) return TOKEN_HLSL_CASE;
3515             if (tokencmp("default")) return TOKEN_HLSL_DEFAULT;
3516             if (tokencmp("sampler")) return TOKEN_HLSL_SAMPLER;
3517             if (tokencmp("sampler1D")) return TOKEN_HLSL_SAMPLER1D;
3518             if (tokencmp("sampler2D")) return TOKEN_HLSL_SAMPLER2D;
3519             if (tokencmp("sampler3D")) return TOKEN_HLSL_SAMPLER3D;
3520             if (tokencmp("samplerCUBE")) return TOKEN_HLSL_SAMPLERCUBE;
3521             if (tokencmp("sampler_state")) return TOKEN_HLSL_SAMPLER_STATE;
3522             if (tokencmp("SamplerState")) return TOKEN_HLSL_SAMPLERSTATE;
3523             if (tokencmp("true")) return TOKEN_HLSL_TRUE;
3524             if (tokencmp("false")) return TOKEN_HLSL_FALSE;
3525             if (tokencmp("SamplerComparisonState")) return TOKEN_HLSL_SAMPLERCOMPARISONSTATE;
3526             if (tokencmp("isolate")) return TOKEN_HLSL_ISOLATE;
3527             if (tokencmp("maxInstructionCount")) return TOKEN_HLSL_MAXINSTRUCTIONCOUNT;
3528             if (tokencmp("noExpressionOptimizations")) return TOKEN_HLSL_NOEXPRESSIONOPTIMIZATIONS;
3529             if (tokencmp("unused")) return TOKEN_HLSL_UNUSED;
3530             if (tokencmp("xps")) return TOKEN_HLSL_XPS;
3531             #undef tokencmp
3532 
3533             // get a canonical copy of the string now, as we'll need it.
3534             token = stringcache_len(ctx->strcache, token, tokenlen);
3535             if (get_usertype(ctx, token) != NULL)
3536                 return TOKEN_HLSL_USERTYPE;
3537             return TOKEN_HLSL_IDENTIFIER;
3538 
3539         case TOKEN_EOI: return 0;
3540         default: assert(0 && "unexpected token from lexer\n"); return 0;
3541     } // switch
3542 
3543     return 0;
3544 } // convert_to_lemon_token
3545 
3546 
3547 static void delete_ir(Context *ctx, void *_ir);  // !!! FIXME: move this code around.
3548 
destroy_context(Context * ctx)3549 static void destroy_context(Context *ctx)
3550 {
3551     if (ctx != NULL)
3552     {
3553         MOJOSHADER_free f = ((ctx->free != NULL) ? ctx->free : MOJOSHADER_internal_free);
3554         void *d = ctx->malloc_data;
3555         size_t i = 0;
3556 
3557         // !!! FIXME: this is kinda hacky.
3558         const size_t count = buffer_size(ctx->garbage) / sizeof (void *);
3559         if (count > 0)
3560         {
3561             void **garbage = (void **) buffer_flatten(ctx->garbage);
3562             if (garbage != NULL)
3563             {
3564                 for (i = 0; i < count; i++)
3565                     f(garbage[i], d);
3566                 f(garbage, d);
3567             } // if
3568         } // if
3569         buffer_destroy(ctx->garbage);
3570 
3571         delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit*)ctx->ast);
3572         destroy_symbolmap(ctx, &ctx->usertypes);
3573         destroy_symbolmap(ctx, &ctx->variables);
3574         stringcache_destroy(ctx->strcache);
3575         errorlist_destroy(ctx->errors);
3576         errorlist_destroy(ctx->warnings);
3577 
3578         if (ctx->ir != NULL)
3579         {
3580             for (i = 0; i <= ctx->user_func_index; i++)
3581                 delete_ir(ctx, ctx->ir[i]);
3582             f(ctx->ir, d);
3583         } // if
3584 
3585         // !!! FIXME: more to clean up here, now.
3586 
3587         f(ctx, d);
3588     } // if
3589 } // destroy_context
3590 
build_context(MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)3591 static Context *build_context(MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
3592 {
3593     if (!m) m = MOJOSHADER_internal_malloc;
3594     if (!f) f = MOJOSHADER_internal_free;
3595 
3596     Context *ctx = (Context *) m(sizeof (Context), d);
3597     if (ctx == NULL)
3598         return NULL;
3599 
3600     memset(ctx, '\0', sizeof (Context));
3601     ctx->malloc = m;
3602     ctx->free = f;
3603     ctx->malloc_data = d;
3604     //ctx->parse_phase = MOJOSHADER_PARSEPHASE_NOTSTARTED;
3605     create_symbolmap(ctx, &ctx->usertypes); // !!! FIXME: check for failure.
3606     create_symbolmap(ctx, &ctx->variables); // !!! FIXME: check for failure.
3607     ctx->strcache = stringcache_create(MallocBridge, FreeBridge, ctx);  // !!! FIXME: check for failure.
3608     ctx->errors = errorlist_create(MallocBridge, FreeBridge, ctx);  // !!! FIXME: check for failure.
3609     ctx->warnings = errorlist_create(MallocBridge, FreeBridge, ctx);  // !!! FIXME: check for failure.
3610 
3611     // !!! FIXME: this feels hacky.
3612     ctx->garbage = buffer_create(256*sizeof(void*),MallocBridge,FreeBridge,ctx);  // !!! FIXME: check for failure.
3613 
3614     ctx->dt_none.type = MOJOSHADER_AST_DATATYPE_NONE;
3615     ctx->dt_bool.type = MOJOSHADER_AST_DATATYPE_BOOL;
3616     ctx->dt_int.type = MOJOSHADER_AST_DATATYPE_INT;
3617     ctx->dt_uint.type = MOJOSHADER_AST_DATATYPE_UINT;
3618     ctx->dt_float.type = MOJOSHADER_AST_DATATYPE_FLOAT;
3619     ctx->dt_float_snorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_SNORM;
3620     ctx->dt_float_unorm.type = MOJOSHADER_AST_DATATYPE_FLOAT_UNORM;
3621     ctx->dt_half.type = MOJOSHADER_AST_DATATYPE_HALF;
3622     ctx->dt_double.type = MOJOSHADER_AST_DATATYPE_DOUBLE;
3623     ctx->dt_string.type = MOJOSHADER_AST_DATATYPE_STRING;
3624     ctx->dt_sampler1d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_1D;
3625     ctx->dt_sampler2d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_2D;
3626     ctx->dt_sampler3d.type = MOJOSHADER_AST_DATATYPE_SAMPLER_3D;
3627     ctx->dt_samplercube.type = MOJOSHADER_AST_DATATYPE_SAMPLER_CUBE;
3628     ctx->dt_samplerstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_STATE;
3629     ctx->dt_samplercompstate.type = MOJOSHADER_AST_DATATYPE_SAMPLER_COMPARISON_STATE;
3630 
3631     #define INIT_DT_BUFFER(t) \
3632         ctx->dt_buf_##t.type = MOJOSHADER_AST_DATATYPE_BUFFER; \
3633         ctx->dt_buf_##t.buffer.base = &ctx->dt_##t;
3634     INIT_DT_BUFFER(bool);
3635     INIT_DT_BUFFER(int);
3636     INIT_DT_BUFFER(uint);
3637     INIT_DT_BUFFER(half);
3638     INIT_DT_BUFFER(float);
3639     INIT_DT_BUFFER(double);
3640     INIT_DT_BUFFER(float_snorm);
3641     INIT_DT_BUFFER(float_unorm);
3642     #undef INIT_DT_BUFFER
3643 
3644     return ctx;
3645 } // build_context
3646 
3647 
3648 // This macro salsa is kinda nasty, but it's the smallest, least error-prone
3649 //  way I can find to do this well in C.  :/
3650 
3651 #define ADD_INTRINSIC(fn, ret, params) do { \
3652     push_function(ctx, fn, \
3653         build_function_datatype(ctx, ret, STATICARRAYLEN(params), params, 1), \
3654         0); \
3655 } while (0)
3656 
3657 #define ADD_INTRINSIC_VECTOR(typestr, code) do { \
3658     const MOJOSHADER_astDataType *dt; \
3659     dt = get_usertype(ctx, typestr "1"); code; \
3660     dt = get_usertype(ctx, typestr "2"); code; \
3661     dt = get_usertype(ctx, typestr "3"); code; \
3662     dt = get_usertype(ctx, typestr "4"); code; \
3663 } while (0)
3664 
3665 #define ADD_INTRINSIC_VECTOR_FLOAT(code) { \
3666     ADD_INTRINSIC_VECTOR("float", code); \
3667     ADD_INTRINSIC_VECTOR("half", code); \
3668     ADD_INTRINSIC_VECTOR("double", code); \
3669 }
3670 #define ADD_INTRINSIC_VECTOR_INT(code) { \
3671     ADD_INTRINSIC_VECTOR("int", code); \
3672     ADD_INTRINSIC_VECTOR("uint", code); \
3673 }
3674 #define ADD_INTRINSIC_VECTOR_BOOL(code) { \
3675     ADD_INTRINSIC_VECTOR("bool", code); \
3676 }
3677 
3678 #define ADD_INTRINSIC_MATRIX(typestr, code) do { \
3679     const MOJOSHADER_astDataType *dt; \
3680     dt = get_usertype(ctx, typestr "1x1"); code; \
3681     dt = get_usertype(ctx, typestr "1x2"); code; \
3682     dt = get_usertype(ctx, typestr "1x3"); code; \
3683     dt = get_usertype(ctx, typestr "1x4"); code; \
3684     dt = get_usertype(ctx, typestr "2x1"); code; \
3685     dt = get_usertype(ctx, typestr "2x2"); code; \
3686     dt = get_usertype(ctx, typestr "2x3"); code; \
3687     dt = get_usertype(ctx, typestr "2x4"); code; \
3688     dt = get_usertype(ctx, typestr "3x1"); code; \
3689     dt = get_usertype(ctx, typestr "3x2"); code; \
3690     dt = get_usertype(ctx, typestr "3x3"); code; \
3691     dt = get_usertype(ctx, typestr "3x4"); code; \
3692     dt = get_usertype(ctx, typestr "4x1"); code; \
3693     dt = get_usertype(ctx, typestr "4x2"); code; \
3694     dt = get_usertype(ctx, typestr "4x3"); code; \
3695     dt = get_usertype(ctx, typestr "4x4"); code; \
3696 } while (0)
3697 
3698 #define ADD_INTRINSIC_MATRIX_FLOAT(code) { \
3699     ADD_INTRINSIC_MATRIX("float", code); \
3700     ADD_INTRINSIC_MATRIX("half", code); \
3701     ADD_INTRINSIC_MATRIX("double", code); \
3702 }
3703 #define ADD_INTRINSIC_MATRIX_INT(code) { \
3704     ADD_INTRINSIC_MATRIX("int", code); \
3705     ADD_INTRINSIC_MATRIX("uint", code); \
3706 }
3707 #define ADD_INTRINSIC_MATRIX_BOOL(code) { \
3708     ADD_INTRINSIC_MATRIX("bool", code); \
3709 }
3710 
3711 #define ADD_INTRINSIC_ANY(scalar, typestr, code) do { \
3712     { const MOJOSHADER_astDataType *dt = scalar; code; } \
3713     ADD_INTRINSIC_VECTOR(typestr, code); \
3714     ADD_INTRINSIC_MATRIX(typestr, code); \
3715 } while (0)
3716 
3717 #define ADD_INTRINSIC_ANY_FLOAT(code) do { \
3718     ADD_INTRINSIC_ANY(&ctx->dt_double, "double", code); \
3719     ADD_INTRINSIC_ANY(&ctx->dt_half, "half", code); \
3720     ADD_INTRINSIC_ANY(&ctx->dt_float, "float", code); \
3721 } while (0)
3722 #define ADD_INTRINSIC_ANY_INT(code) do { \
3723     ADD_INTRINSIC_ANY(&ctx->dt_uint, "uint", code); \
3724     ADD_INTRINSIC_ANY(&ctx->dt_int, "int", code); \
3725 } while (0)
3726 
3727 #define ADD_INTRINSIC_ANY_BOOL(code) ADD_INTRINSIC_ANY(&ctx->dt_bool, "bool", code)
3728 
add_intrinsic1(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1)3729 static void add_intrinsic1(Context *ctx, const char *fn,
3730                            const MOJOSHADER_astDataType *ret,
3731                            const MOJOSHADER_astDataType *dt1)
3732 {
3733     const MOJOSHADER_astDataType *params[] = { dt1 };
3734     ADD_INTRINSIC(fn, ret, params);
3735 } // add_intrinsic1
3736 
add_intrinsic2(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2)3737 static void add_intrinsic2(Context *ctx, const char *fn,
3738                            const MOJOSHADER_astDataType *ret,
3739                            const MOJOSHADER_astDataType *dt1,
3740                            const MOJOSHADER_astDataType *dt2)
3741 {
3742     const MOJOSHADER_astDataType *params[] = { dt1, dt2 };
3743     ADD_INTRINSIC(fn, ret, params);
3744 } // add_intrinsic2
3745 
add_intrinsic3(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2,const MOJOSHADER_astDataType * dt3)3746 static void add_intrinsic3(Context *ctx, const char *fn,
3747                            const MOJOSHADER_astDataType *ret,
3748                            const MOJOSHADER_astDataType *dt1,
3749                            const MOJOSHADER_astDataType *dt2,
3750                            const MOJOSHADER_astDataType *dt3)
3751 {
3752     const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3 };
3753     ADD_INTRINSIC(fn, ret, params);
3754 } // add_intrinsic3
3755 
add_intrinsic4(Context * ctx,const char * fn,const MOJOSHADER_astDataType * ret,const MOJOSHADER_astDataType * dt1,const MOJOSHADER_astDataType * dt2,const MOJOSHADER_astDataType * dt3,const MOJOSHADER_astDataType * dt4)3756 static void add_intrinsic4(Context *ctx, const char *fn,
3757                            const MOJOSHADER_astDataType *ret,
3758                            const MOJOSHADER_astDataType *dt1,
3759                            const MOJOSHADER_astDataType *dt2,
3760                            const MOJOSHADER_astDataType *dt3,
3761                            const MOJOSHADER_astDataType *dt4)
3762 {
3763     const MOJOSHADER_astDataType *params[] = { dt1, dt2, dt3, dt4 };
3764     ADD_INTRINSIC(fn, ret, params);
3765 } // add_intrinsic4
3766 
3767 // PLEASE NOTE that add_intrinsic*() is called AFTER the various
3768 //  ADD_INTRINSIC_* macros, even though these look like functions that
3769 //  should be called first. They might be called multiple times by the macro.
3770 //  The variable "dt" is defined by the macro for use by your code.
add_intrinsic_SAME1_ANYf(Context * ctx,const char * fn)3771 static void add_intrinsic_SAME1_ANYf(Context *ctx, const char *fn)
3772 {
3773     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3774 } // add_intrinsic_SAME1_ANYf
3775 
add_intrinsic_SAME1_ANYfi(Context * ctx,const char * fn)3776 static void add_intrinsic_SAME1_ANYfi(Context *ctx, const char *fn)
3777 {
3778     ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, dt, dt));
3779     add_intrinsic_SAME1_ANYf(ctx, fn);
3780 } // add_intrinsic_SAME1_ANYfi
3781 
add_intrinsic_BOOL_ANYf(Context * ctx,const char * fn)3782 static void add_intrinsic_BOOL_ANYf(Context *ctx, const char *fn)
3783 {
3784     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3785 } // add_intrinsic_BOOL_ANYf
3786 
add_intrinsic_BOOL_ANYfib(Context * ctx,const char * fn)3787 static void add_intrinsic_BOOL_ANYfib(Context *ctx, const char *fn)
3788 {
3789     ADD_INTRINSIC_ANY_BOOL(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3790     ADD_INTRINSIC_ANY_INT(add_intrinsic1(ctx, fn, &ctx->dt_bool, dt));
3791     add_intrinsic_BOOL_ANYf(ctx, fn);
3792 } // add_intrinsic_BOOL_ANYfib
3793 
add_intrinsic_SAME1_ANYf_SAME1(Context * ctx,const char * fn)3794 static void add_intrinsic_SAME1_ANYf_SAME1(Context *ctx, const char *fn)
3795 {
3796     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dt));
3797 } // add_intrinsic_SAME1_ANYf_SAME1
3798 
add_intrinsic_SAME1_ANYfi_SAME1(Context * ctx,const char * fn)3799 static void add_intrinsic_SAME1_ANYfi_SAME1(Context *ctx, const char *fn)
3800 {
3801     ADD_INTRINSIC_ANY_INT(add_intrinsic2(ctx, fn, dt, dt, dt));
3802     add_intrinsic_SAME1_ANYf_SAME1(ctx, fn);
3803 } // add_intrinsic_SAME1_ANYfi_SAME1
3804 
add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context * ctx,const char * fn)3805 static void add_intrinsic_SAME1_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
3806 {
3807     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3808 } // add_intrinsic_SAME1_ANYf_SAME1_SAME1
3809 
add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context * ctx,const char * fn)3810 static void add_intrinsic_SAME1_ANYfi_SAME1_SAME1(Context *ctx, const char *fn)
3811 {
3812     ADD_INTRINSIC_ANY_INT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3813     add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, fn);
3814 } // add_intrinsic_SAME1_ANYfi_SAME1_SAME1
3815 
add_intrinsic_SAME1_Mfib(Context * ctx,const char * fn)3816 static void add_intrinsic_SAME1_Mfib(Context *ctx, const char *fn)
3817 {
3818     ADD_INTRINSIC_MATRIX_BOOL(add_intrinsic1(ctx, fn, dt, dt));
3819     ADD_INTRINSIC_MATRIX_INT(add_intrinsic1(ctx, fn, dt, dt));
3820     ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3821 } // add_intrinsic_SAME1_Mfib
3822 
add_intrinsic_SAME1_Vf(Context * ctx,const char * fn)3823 static void add_intrinsic_SAME1_Vf(Context *ctx, const char *fn)
3824 {
3825     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt, dt));
3826 } // add_intrinsic_SAME1_Vf
3827 
add_intrinsic_SAME1_Vf_SAME1_SAME1(Context * ctx,const char * fn)3828 static void add_intrinsic_SAME1_Vf_SAME1_SAME1(Context *ctx, const char *fn)
3829 {
3830     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt));
3831 } // add_intrinsic_SAME1_Vf_SAME1_SAME1
3832 
add_intrinsic_SAME1_Vf_SAME1_f(Context * ctx,const char * fn)3833 static void add_intrinsic_SAME1_Vf_SAME1_f(Context *ctx, const char *fn)
3834 {
3835     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic3(ctx, fn, dt, dt, dt, dt->user.details->vector.base));
3836 } // add_intrinsic_SAME1_Vf_SAME1_f
3837 
add_intrinsic_VOID_ANYf(Context * ctx,const char * fn)3838 static void add_intrinsic_VOID_ANYf(Context *ctx, const char *fn)
3839 {
3840     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic1(ctx, fn, NULL, dt));
3841 } // add_intrinsic_VOID_ANYf
3842 
add_intrinsic_VOID_ANYf_SAME1_SAME1(Context * ctx,const char * fn)3843 static void add_intrinsic_VOID_ANYf_SAME1_SAME1(Context *ctx, const char *fn)
3844 {
3845     ADD_INTRINSIC_ANY_FLOAT(add_intrinsic3(ctx, fn, NULL, dt, dt, dt));
3846 } // add_intrinsic_VOID_ANYf_SAME1_SAME1
3847 
add_intrinsic_f_SQUAREMATRIXf(Context * ctx,const char * fn)3848 static void add_intrinsic_f_SQUAREMATRIXf(Context *ctx, const char *fn)
3849 {
3850     add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float1x1"));
3851     add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float2x2"));
3852     add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float3x3"));
3853     add_intrinsic1(ctx, fn, &ctx->dt_float, get_usertype(ctx, "float4x4"));
3854 } // add_intrinsic_f_SQUAREMATRIXf
3855 
add_intrinsic_f_Vf(Context * ctx,const char * fn)3856 static void add_intrinsic_f_Vf(Context *ctx, const char *fn)
3857 {
3858     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic1(ctx, fn, dt->user.details->vector.base, dt));
3859 } // add_intrinsic_f_Vf
3860 
add_intrinsic_fi_Vfi_SAME1(Context * ctx,const char * fn)3861 static void add_intrinsic_fi_Vfi_SAME1(Context *ctx, const char *fn)
3862 {
3863     ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3864     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3865 } // add_intrinsic_fi_Vfi_SAME1
3866 
add_intrinsic_f_Vf_SAME1(Context * ctx,const char * fn)3867 static void add_intrinsic_f_Vf_SAME1(Context *ctx, const char *fn)
3868 {
3869     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt->user.details->vector.base, dt, dt));
3870 } // add_intrinsic_f_Vf_SAME1
3871 
add_intrinsic_3f_3f_3f(Context * ctx,const char * fn)3872 static void add_intrinsic_3f_3f_3f(Context *ctx, const char *fn)
3873 {
3874     const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float3");
3875     add_intrinsic2(ctx, fn, dt, dt, dt);
3876 } // add_intrinsic_3f_3f_3f
3877 
add_intrinsic_4f_f_f_f(Context * ctx,const char * fn)3878 static void add_intrinsic_4f_f_f_f(Context *ctx, const char *fn)
3879 {
3880     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3881     const MOJOSHADER_astDataType *f = &ctx->dt_float;
3882     add_intrinsic3(ctx, fn, f4, f, f, f);
3883 } // add_intrinsic_4f_f_f_f
3884 
add_intrinsic_4f_s1_4f(Context * ctx,const char * fn)3885 static void add_intrinsic_4f_s1_4f(Context *ctx, const char *fn)
3886 {
3887     const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3888     add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, dt);
3889 } // add_intrinsic_4f_s1_4f
3890 
add_intrinsic_4f_s1_f(Context * ctx,const char * fn)3891 static void add_intrinsic_4f_s1_f(Context *ctx, const char *fn)
3892 {
3893     const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3894     add_intrinsic2(ctx, fn, dt, &ctx->dt_sampler1d, &ctx->dt_float);
3895 } // add_intrinsic_4f_s1_f
3896 
add_intrinsic_4f_s1_f_f_f(Context * ctx,const char * fn)3897 static void add_intrinsic_4f_s1_f_f_f(Context *ctx, const char *fn)
3898 {
3899     const MOJOSHADER_astDataType *dt = get_usertype(ctx, "float4");
3900     const MOJOSHADER_astDataType *f = &ctx->dt_float;
3901     add_intrinsic4(ctx, fn, dt, &ctx->dt_sampler1d, f, f, f);
3902 } // add_intrinsic_4f_s1_f_f_f
3903 
add_intrinsic_4f_s2_2f(Context * ctx,const char * fn)3904 static void add_intrinsic_4f_s2_2f(Context *ctx, const char *fn)
3905 {
3906     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3907     const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3908     add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f2);
3909 } // add_intrinsic_4f_s2_2f
3910 
add_intrinsic_4f_s2_2f_2f_2f(Context * ctx,const char * fn)3911 static void add_intrinsic_4f_s2_2f_2f_2f(Context *ctx, const char *fn)
3912 {
3913     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3914     const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3915     add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler2d, f2, f2, f2);
3916 } // add_intrinsic_4f_s2_2f_2f_2f
3917 
add_intrinsic_4f_s2_4f(Context * ctx,const char * fn)3918 static void add_intrinsic_4f_s2_4f(Context *ctx, const char *fn)
3919 {
3920     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3921     add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler2d, f4);
3922 } // add_intrinsic_4f_s2_4f
3923 
add_intrinsic_4f_s3_3f(Context * ctx,const char * fn)3924 static void add_intrinsic_4f_s3_3f(Context *ctx, const char *fn)
3925 {
3926     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3927     const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3928     add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f3);
3929 } // add_intrinsic_4f_s3_3f
3930 
add_intrinsic_4f_s3_3f_3f_3f(Context * ctx,const char * fn)3931 static void add_intrinsic_4f_s3_3f_3f_3f(Context *ctx, const char *fn)
3932 {
3933     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3934     const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3935     add_intrinsic4(ctx, fn, f4, &ctx->dt_sampler3d, f3, f3, f3);
3936 } // add_intrinsic_4f_s3_3f_3f_3f
3937 
add_intrinsic_4f_s3_4f(Context * ctx,const char * fn)3938 static void add_intrinsic_4f_s3_4f(Context *ctx, const char *fn)
3939 {
3940     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3941     add_intrinsic2(ctx, fn, f4, &ctx->dt_sampler3d, f4);
3942 } // add_intrinsic_4f_s3_4f
3943 
add_intrinsic_4f_sc_3f(Context * ctx,const char * fn)3944 static void add_intrinsic_4f_sc_3f(Context *ctx, const char *fn)
3945 {
3946     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3947     const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3948     add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f3);
3949 } // add_intrinsic_4f_sc_3f
3950 
add_intrinsic_4f_sc_3f_3f_3f(Context * ctx,const char * fn)3951 static void add_intrinsic_4f_sc_3f_3f_3f(Context *ctx, const char *fn)
3952 {
3953     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3954     const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3955     add_intrinsic4(ctx, fn, f4, &ctx->dt_samplercube, f3, f3, f3);
3956 } // add_intrinsic_4f_sc_3f_3f_3f
3957 
add_intrinsic_4f_sc_4f(Context * ctx,const char * fn)3958 static void add_intrinsic_4f_sc_4f(Context *ctx, const char *fn)
3959 {
3960     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3961     add_intrinsic2(ctx, fn, f4, &ctx->dt_samplercube, f4);
3962 } // add_intrinsic_4f_sc_4f
3963 
add_intrinsic_4i_4f(Context * ctx,const char * fn)3964 static void add_intrinsic_4i_4f(Context *ctx, const char *fn)
3965 {
3966     const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
3967     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3968     add_intrinsic1(ctx, fn, i4, f4);
3969 } // add_intrinsic_4i_4f
3970 
add_intrinsic_mul(Context * ctx,const char * fn)3971 static void add_intrinsic_mul(Context *ctx, const char *fn)
3972 {
3973     // mul() is nasty, since there's a bunch of overloads that aren't just
3974     //  related to vector size.
3975     // !!! FIXME: needs half, double, uint...
3976     const MOJOSHADER_astDataType *dtf = &ctx->dt_float;
3977     const MOJOSHADER_astDataType *dti = &ctx->dt_int;
3978     const MOJOSHADER_astDataType *f1 = get_usertype(ctx, "float1");
3979     const MOJOSHADER_astDataType *f2 = get_usertype(ctx, "float2");
3980     const MOJOSHADER_astDataType *f3 = get_usertype(ctx, "float3");
3981     const MOJOSHADER_astDataType *f4 = get_usertype(ctx, "float4");
3982     const MOJOSHADER_astDataType *i1 = get_usertype(ctx, "int1");
3983     const MOJOSHADER_astDataType *i2 = get_usertype(ctx, "int2");
3984     const MOJOSHADER_astDataType *i3 = get_usertype(ctx, "int3");
3985     const MOJOSHADER_astDataType *i4 = get_usertype(ctx, "int4");
3986     const MOJOSHADER_astDataType *f1x1 = get_usertype(ctx, "float1x1");
3987     const MOJOSHADER_astDataType *f1x2 = get_usertype(ctx, "float1x2");
3988     const MOJOSHADER_astDataType *f1x3 = get_usertype(ctx, "float1x3");
3989     const MOJOSHADER_astDataType *f1x4 = get_usertype(ctx, "float1x4");
3990     const MOJOSHADER_astDataType *f2x1 = get_usertype(ctx, "float2x1");
3991     const MOJOSHADER_astDataType *f2x2 = get_usertype(ctx, "float2x2");
3992     const MOJOSHADER_astDataType *f2x3 = get_usertype(ctx, "float2x3");
3993     const MOJOSHADER_astDataType *f2x4 = get_usertype(ctx, "float2x4");
3994     const MOJOSHADER_astDataType *f3x1 = get_usertype(ctx, "float3x1");
3995     const MOJOSHADER_astDataType *f3x2 = get_usertype(ctx, "float3x2");
3996     const MOJOSHADER_astDataType *f3x3 = get_usertype(ctx, "float3x3");
3997     const MOJOSHADER_astDataType *f3x4 = get_usertype(ctx, "float3x4");
3998     const MOJOSHADER_astDataType *f4x1 = get_usertype(ctx, "float4x1");
3999     const MOJOSHADER_astDataType *f4x2 = get_usertype(ctx, "float4x2");
4000     const MOJOSHADER_astDataType *f4x3 = get_usertype(ctx, "float4x3");
4001     const MOJOSHADER_astDataType *f4x4 = get_usertype(ctx, "float4x4");
4002     const MOJOSHADER_astDataType *i1x1 = get_usertype(ctx, "int1x1");
4003     const MOJOSHADER_astDataType *i1x2 = get_usertype(ctx, "int1x2");
4004     const MOJOSHADER_astDataType *i1x3 = get_usertype(ctx, "int1x3");
4005     const MOJOSHADER_astDataType *i1x4 = get_usertype(ctx, "int1x4");
4006     const MOJOSHADER_astDataType *i2x1 = get_usertype(ctx, "int2x1");
4007     const MOJOSHADER_astDataType *i2x2 = get_usertype(ctx, "int2x2");
4008     const MOJOSHADER_astDataType *i2x3 = get_usertype(ctx, "int2x3");
4009     const MOJOSHADER_astDataType *i2x4 = get_usertype(ctx, "int2x4");
4010     const MOJOSHADER_astDataType *i3x1 = get_usertype(ctx, "int3x1");
4011     const MOJOSHADER_astDataType *i3x2 = get_usertype(ctx, "int3x2");
4012     const MOJOSHADER_astDataType *i3x3 = get_usertype(ctx, "int3x3");
4013     const MOJOSHADER_astDataType *i3x4 = get_usertype(ctx, "int3x4");
4014     const MOJOSHADER_astDataType *i4x1 = get_usertype(ctx, "int4x1");
4015     const MOJOSHADER_astDataType *i4x2 = get_usertype(ctx, "int4x2");
4016     const MOJOSHADER_astDataType *i4x3 = get_usertype(ctx, "int4x3");
4017     const MOJOSHADER_astDataType *i4x4 = get_usertype(ctx, "int4x4");
4018 
4019     // scalar * scalar
4020     add_intrinsic2(ctx, fn, dti, dti, dti);
4021     add_intrinsic2(ctx, fn, dtf, dtf, dtf);
4022 
4023     // scalar * vector
4024     ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
4025     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
4026 
4027     // scalar * matrix
4028     ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dti, dt));
4029     ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dtf, dt));
4030 
4031     // vector * scalar
4032     ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
4033     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
4034 
4035     // vector * vector
4036     ADD_INTRINSIC_VECTOR_INT(add_intrinsic2(ctx, fn, dti, dt, dt));
4037     ADD_INTRINSIC_VECTOR_FLOAT(add_intrinsic2(ctx, fn, dtf, dt, dt));
4038 
4039     // vector * matrix
4040     add_intrinsic2(ctx, fn, i1, i1, i1x1);
4041     add_intrinsic2(ctx, fn, i2, i1, i1x2);
4042     add_intrinsic2(ctx, fn, i3, i1, i1x3);
4043     add_intrinsic2(ctx, fn, i4, i1, i1x4);
4044     add_intrinsic2(ctx, fn, i1, i2, i2x1);
4045     add_intrinsic2(ctx, fn, i2, i2, i2x2);
4046     add_intrinsic2(ctx, fn, i3, i2, i2x3);
4047     add_intrinsic2(ctx, fn, i4, i2, i2x4);
4048     add_intrinsic2(ctx, fn, i1, i3, i3x1);
4049     add_intrinsic2(ctx, fn, i2, i3, i3x2);
4050     add_intrinsic2(ctx, fn, i3, i3, i3x3);
4051     add_intrinsic2(ctx, fn, i4, i3, i3x4);
4052     add_intrinsic2(ctx, fn, i1, i4, i4x1);
4053     add_intrinsic2(ctx, fn, i2, i4, i4x2);
4054     add_intrinsic2(ctx, fn, i3, i4, i4x3);
4055     add_intrinsic2(ctx, fn, i4, i4, i4x4);
4056     add_intrinsic2(ctx, fn, f1, f1, f1x1);
4057     add_intrinsic2(ctx, fn, f2, f1, f1x2);
4058     add_intrinsic2(ctx, fn, f3, f1, f1x3);
4059     add_intrinsic2(ctx, fn, f4, f1, f1x4);
4060     add_intrinsic2(ctx, fn, f1, f2, f2x1);
4061     add_intrinsic2(ctx, fn, f2, f2, f2x2);
4062     add_intrinsic2(ctx, fn, f3, f2, f2x3);
4063     add_intrinsic2(ctx, fn, f4, f2, f2x4);
4064     add_intrinsic2(ctx, fn, f1, f3, f3x1);
4065     add_intrinsic2(ctx, fn, f2, f3, f3x2);
4066     add_intrinsic2(ctx, fn, f3, f3, f3x3);
4067     add_intrinsic2(ctx, fn, f4, f3, f3x4);
4068     add_intrinsic2(ctx, fn, f1, f4, f4x1);
4069     add_intrinsic2(ctx, fn, f2, f4, f4x2);
4070     add_intrinsic2(ctx, fn, f3, f4, f4x3);
4071     add_intrinsic2(ctx, fn, f4, f4, f4x4);
4072 
4073     // matrix * scalar
4074     ADD_INTRINSIC_MATRIX_INT(add_intrinsic2(ctx, fn, dt, dt, dti));
4075     ADD_INTRINSIC_MATRIX_FLOAT(add_intrinsic2(ctx, fn, dt, dt, dtf));
4076 
4077     // matrix * vector
4078     add_intrinsic2(ctx, fn, i1, i1x1, i1);
4079     add_intrinsic2(ctx, fn, i1, i1x2, i2);
4080     add_intrinsic2(ctx, fn, i1, i1x3, i3);
4081     add_intrinsic2(ctx, fn, i1, i1x4, i4);
4082     add_intrinsic2(ctx, fn, i2, i2x1, i1);
4083     add_intrinsic2(ctx, fn, i2, i2x2, i2);
4084     add_intrinsic2(ctx, fn, i2, i2x3, i3);
4085     add_intrinsic2(ctx, fn, i2, i2x4, i4);
4086     add_intrinsic2(ctx, fn, i3, i3x1, i1);
4087     add_intrinsic2(ctx, fn, i3, i3x2, i2);
4088     add_intrinsic2(ctx, fn, i3, i3x3, i3);
4089     add_intrinsic2(ctx, fn, i3, i3x4, i4);
4090     add_intrinsic2(ctx, fn, i4, i4x1, i1);
4091     add_intrinsic2(ctx, fn, i4, i4x2, i2);
4092     add_intrinsic2(ctx, fn, i4, i4x3, i3);
4093     add_intrinsic2(ctx, fn, i4, i4x4, i4);
4094     add_intrinsic2(ctx, fn, f1, f1x1, f1);
4095     add_intrinsic2(ctx, fn, f1, f1x2, f2);
4096     add_intrinsic2(ctx, fn, f1, f1x3, f3);
4097     add_intrinsic2(ctx, fn, f1, f1x4, f4);
4098     add_intrinsic2(ctx, fn, f2, f2x1, f1);
4099     add_intrinsic2(ctx, fn, f2, f2x2, f2);
4100     add_intrinsic2(ctx, fn, f2, f2x3, f3);
4101     add_intrinsic2(ctx, fn, f2, f2x4, f4);
4102     add_intrinsic2(ctx, fn, f3, f3x1, f1);
4103     add_intrinsic2(ctx, fn, f3, f3x2, f2);
4104     add_intrinsic2(ctx, fn, f3, f3x3, f3);
4105     add_intrinsic2(ctx, fn, f3, f3x4, f4);
4106     add_intrinsic2(ctx, fn, f4, f4x1, f1);
4107     add_intrinsic2(ctx, fn, f4, f4x2, f2);
4108     add_intrinsic2(ctx, fn, f4, f4x3, f3);
4109     add_intrinsic2(ctx, fn, f4, f4x4, f4);
4110 
4111     // matrix * matrix
4112     add_intrinsic2(ctx, fn, i1x1, i1x1, i1x1);
4113     add_intrinsic2(ctx, fn, i1x2, i1x1, i1x2);
4114     add_intrinsic2(ctx, fn, i1x3, i1x1, i1x3);
4115     add_intrinsic2(ctx, fn, i1x4, i1x1, i1x4);
4116     add_intrinsic2(ctx, fn, i1x1, i1x2, i2x1);
4117     add_intrinsic2(ctx, fn, i1x2, i1x2, i2x2);
4118     add_intrinsic2(ctx, fn, i1x3, i1x2, i2x3);
4119     add_intrinsic2(ctx, fn, i1x4, i1x2, i2x4);
4120     add_intrinsic2(ctx, fn, i1x1, i1x3, i3x1);
4121     add_intrinsic2(ctx, fn, i1x2, i1x3, i3x2);
4122     add_intrinsic2(ctx, fn, i1x3, i1x3, i3x3);
4123     add_intrinsic2(ctx, fn, i1x4, i1x3, i3x4);
4124     add_intrinsic2(ctx, fn, i1x1, i1x4, i4x1);
4125     add_intrinsic2(ctx, fn, i1x2, i1x4, i4x2);
4126     add_intrinsic2(ctx, fn, i1x3, i1x4, i4x3);
4127     add_intrinsic2(ctx, fn, i1x4, i1x4, i4x4);
4128     add_intrinsic2(ctx, fn, i2x1, i2x1, i1x1);
4129     add_intrinsic2(ctx, fn, i2x2, i2x1, i1x2);
4130     add_intrinsic2(ctx, fn, i2x3, i2x1, i1x3);
4131     add_intrinsic2(ctx, fn, i2x4, i2x1, i1x4);
4132     add_intrinsic2(ctx, fn, i2x1, i2x2, i2x1);
4133     add_intrinsic2(ctx, fn, i2x2, i2x2, i2x2);
4134     add_intrinsic2(ctx, fn, i2x3, i2x2, i2x3);
4135     add_intrinsic2(ctx, fn, i2x4, i2x2, i2x4);
4136     add_intrinsic2(ctx, fn, i2x1, i2x3, i3x1);
4137     add_intrinsic2(ctx, fn, i2x2, i2x3, i3x2);
4138     add_intrinsic2(ctx, fn, i2x3, i2x3, i3x3);
4139     add_intrinsic2(ctx, fn, i2x4, i2x3, i3x4);
4140     add_intrinsic2(ctx, fn, i2x1, i2x4, i4x1);
4141     add_intrinsic2(ctx, fn, i2x2, i2x4, i4x2);
4142     add_intrinsic2(ctx, fn, i2x3, i2x4, i4x3);
4143     add_intrinsic2(ctx, fn, i2x4, i2x4, i4x4);
4144     add_intrinsic2(ctx, fn, i3x1, i3x1, i1x1);
4145     add_intrinsic2(ctx, fn, i3x2, i3x1, i1x2);
4146     add_intrinsic2(ctx, fn, i3x3, i3x1, i1x3);
4147     add_intrinsic2(ctx, fn, i3x4, i3x1, i1x4);
4148     add_intrinsic2(ctx, fn, i3x1, i3x2, i2x1);
4149     add_intrinsic2(ctx, fn, i3x2, i3x2, i2x2);
4150     add_intrinsic2(ctx, fn, i3x3, i3x2, i2x3);
4151     add_intrinsic2(ctx, fn, i3x4, i3x2, i2x4);
4152     add_intrinsic2(ctx, fn, i3x1, i3x3, i3x1);
4153     add_intrinsic2(ctx, fn, i3x2, i3x3, i3x2);
4154     add_intrinsic2(ctx, fn, i3x3, i3x3, i3x3);
4155     add_intrinsic2(ctx, fn, i3x4, i3x3, i3x4);
4156     add_intrinsic2(ctx, fn, i3x1, i3x4, i4x1);
4157     add_intrinsic2(ctx, fn, i3x2, i3x4, i4x2);
4158     add_intrinsic2(ctx, fn, i3x3, i3x4, i4x3);
4159     add_intrinsic2(ctx, fn, i3x4, i3x4, i4x4);
4160     add_intrinsic2(ctx, fn, i4x1, i4x1, i1x1);
4161     add_intrinsic2(ctx, fn, i4x2, i4x1, i1x2);
4162     add_intrinsic2(ctx, fn, i4x3, i4x1, i1x3);
4163     add_intrinsic2(ctx, fn, i4x4, i4x1, i1x4);
4164     add_intrinsic2(ctx, fn, i4x1, i4x2, i2x1);
4165     add_intrinsic2(ctx, fn, i4x2, i4x2, i2x2);
4166     add_intrinsic2(ctx, fn, i4x3, i4x2, i2x3);
4167     add_intrinsic2(ctx, fn, i4x4, i4x2, i2x4);
4168     add_intrinsic2(ctx, fn, i4x1, i4x3, i3x1);
4169     add_intrinsic2(ctx, fn, i4x2, i4x3, i3x2);
4170     add_intrinsic2(ctx, fn, i4x3, i4x3, i3x3);
4171     add_intrinsic2(ctx, fn, i4x4, i4x3, i3x4);
4172     add_intrinsic2(ctx, fn, i4x1, i4x4, i4x1);
4173     add_intrinsic2(ctx, fn, i4x2, i4x4, i4x2);
4174     add_intrinsic2(ctx, fn, i4x3, i4x4, i4x3);
4175     add_intrinsic2(ctx, fn, i4x4, i4x4, i4x4);
4176     add_intrinsic2(ctx, fn, f1x1, f1x1, f1x1);
4177     add_intrinsic2(ctx, fn, f1x2, f1x1, f1x2);
4178     add_intrinsic2(ctx, fn, f1x3, f1x1, f1x3);
4179     add_intrinsic2(ctx, fn, f1x4, f1x1, f1x4);
4180     add_intrinsic2(ctx, fn, f1x1, f1x2, f2x1);
4181     add_intrinsic2(ctx, fn, f1x2, f1x2, f2x2);
4182     add_intrinsic2(ctx, fn, f1x3, f1x2, f2x3);
4183     add_intrinsic2(ctx, fn, f1x4, f1x2, f2x4);
4184     add_intrinsic2(ctx, fn, f1x1, f1x3, f3x1);
4185     add_intrinsic2(ctx, fn, f1x2, f1x3, f3x2);
4186     add_intrinsic2(ctx, fn, f1x3, f1x3, f3x3);
4187     add_intrinsic2(ctx, fn, f1x4, f1x3, f3x4);
4188     add_intrinsic2(ctx, fn, f1x1, f1x4, f4x1);
4189     add_intrinsic2(ctx, fn, f1x2, f1x4, f4x2);
4190     add_intrinsic2(ctx, fn, f1x3, f1x4, f4x3);
4191     add_intrinsic2(ctx, fn, f1x4, f1x4, f4x4);
4192     add_intrinsic2(ctx, fn, f2x1, f2x1, f1x1);
4193     add_intrinsic2(ctx, fn, f2x2, f2x1, f1x2);
4194     add_intrinsic2(ctx, fn, f2x3, f2x1, f1x3);
4195     add_intrinsic2(ctx, fn, f2x4, f2x1, f1x4);
4196     add_intrinsic2(ctx, fn, f2x1, f2x2, f2x1);
4197     add_intrinsic2(ctx, fn, f2x2, f2x2, f2x2);
4198     add_intrinsic2(ctx, fn, f2x3, f2x2, f2x3);
4199     add_intrinsic2(ctx, fn, f2x4, f2x2, f2x4);
4200     add_intrinsic2(ctx, fn, f2x1, f2x3, f3x1);
4201     add_intrinsic2(ctx, fn, f2x2, f2x3, f3x2);
4202     add_intrinsic2(ctx, fn, f2x3, f2x3, f3x3);
4203     add_intrinsic2(ctx, fn, f2x4, f2x3, f3x4);
4204     add_intrinsic2(ctx, fn, f2x1, f2x4, f4x1);
4205     add_intrinsic2(ctx, fn, f2x2, f2x4, f4x2);
4206     add_intrinsic2(ctx, fn, f2x3, f2x4, f4x3);
4207     add_intrinsic2(ctx, fn, f2x4, f2x4, f4x4);
4208     add_intrinsic2(ctx, fn, f3x1, f3x1, f1x1);
4209     add_intrinsic2(ctx, fn, f3x2, f3x1, f1x2);
4210     add_intrinsic2(ctx, fn, f3x3, f3x1, f1x3);
4211     add_intrinsic2(ctx, fn, f3x4, f3x1, f1x4);
4212     add_intrinsic2(ctx, fn, f3x1, f3x2, f2x1);
4213     add_intrinsic2(ctx, fn, f3x2, f3x2, f2x2);
4214     add_intrinsic2(ctx, fn, f3x3, f3x2, f2x3);
4215     add_intrinsic2(ctx, fn, f3x4, f3x2, f2x4);
4216     add_intrinsic2(ctx, fn, f3x1, f3x3, f3x1);
4217     add_intrinsic2(ctx, fn, f3x2, f3x3, f3x2);
4218     add_intrinsic2(ctx, fn, f3x3, f3x3, f3x3);
4219     add_intrinsic2(ctx, fn, f3x4, f3x3, f3x4);
4220     add_intrinsic2(ctx, fn, f3x1, f3x4, f4x1);
4221     add_intrinsic2(ctx, fn, f3x2, f3x4, f4x2);
4222     add_intrinsic2(ctx, fn, f3x3, f3x4, f4x3);
4223     add_intrinsic2(ctx, fn, f3x4, f3x4, f4x4);
4224     add_intrinsic2(ctx, fn, f4x1, f4x1, f1x1);
4225     add_intrinsic2(ctx, fn, f4x2, f4x1, f1x2);
4226     add_intrinsic2(ctx, fn, f4x3, f4x1, f1x3);
4227     add_intrinsic2(ctx, fn, f4x4, f4x1, f1x4);
4228     add_intrinsic2(ctx, fn, f4x1, f4x2, f2x1);
4229     add_intrinsic2(ctx, fn, f4x2, f4x2, f2x2);
4230     add_intrinsic2(ctx, fn, f4x3, f4x2, f2x3);
4231     add_intrinsic2(ctx, fn, f4x4, f4x2, f2x4);
4232     add_intrinsic2(ctx, fn, f4x1, f4x3, f3x1);
4233     add_intrinsic2(ctx, fn, f4x2, f4x3, f3x2);
4234     add_intrinsic2(ctx, fn, f4x3, f4x3, f3x3);
4235     add_intrinsic2(ctx, fn, f4x4, f4x3, f3x4);
4236     add_intrinsic2(ctx, fn, f4x1, f4x4, f4x1);
4237     add_intrinsic2(ctx, fn, f4x2, f4x4, f4x2);
4238     add_intrinsic2(ctx, fn, f4x3, f4x4, f4x3);
4239     add_intrinsic2(ctx, fn, f4x4, f4x4, f4x4);
4240 } // add_intrinsic_mul
4241 
init_builtins(Context * ctx)4242 static void init_builtins(Context *ctx)
4243 {
4244     // add in standard typedefs...
4245     const struct
4246     {
4247         const char *str;
4248         const MOJOSHADER_astDataType *datatype;
4249     } types[] = {
4250         { "bool", &ctx->dt_bool },
4251         { "int", &ctx->dt_int },
4252         { "uint", &ctx->dt_uint },
4253         { "half", &ctx->dt_half },
4254         { "float", &ctx->dt_float },
4255         { "double", &ctx->dt_double },
4256     };
4257 
4258     int i, j, k;
4259     for (i = 0; i < STATICARRAYLEN(types); i++)
4260     {
4261         char buf[32];
4262         int len;
4263         const MOJOSHADER_astDataType *dt;
4264 
4265         for (j = 1; j <= 4; j++)
4266         {
4267             // "float2"
4268             dt = new_datatype_vector(ctx, types[i].datatype, j);
4269             len = snprintf(buf, sizeof (buf), "%s%d", types[i].str, j);
4270             push_usertype(ctx, stringcache_len(ctx->strcache, buf, len), dt);
4271             for (k = 1; k <= 4; k++)
4272             {
4273                 // "float2x2"
4274                 dt = new_datatype_matrix(ctx, types[i].datatype, j, k);
4275                 len = snprintf(buf, sizeof (buf), "%s%dx%d", types[i].str,j,k);
4276                 push_usertype(ctx, stringcache_len(ctx->strcache,buf,len), dt);
4277             } // for
4278         } // for
4279     } // for
4280 
4281     // !!! FIXME: block these out by pixel/vertex/etc shader.
4282     // !!! FIXME: calculate actual shader model (or maybe just let bytecode verifier throw up?).
4283     const int shader_model = 3;
4284     if (shader_model >= 1)
4285     {
4286         add_intrinsic_SAME1_ANYfi(ctx, stringcache(ctx->strcache, "abs"));
4287         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "acos"));
4288         add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "all"));
4289         add_intrinsic_BOOL_ANYfib(ctx, stringcache(ctx->strcache, "any"));
4290         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "asin"));
4291         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "atan"));
4292         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "atan2"));
4293         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ceil"));
4294         add_intrinsic_SAME1_ANYfi_SAME1_SAME1(ctx, stringcache(ctx->strcache, "clamp"));
4295         add_intrinsic_VOID_ANYf(ctx, stringcache(ctx->strcache, "clip"));
4296         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cos"));
4297         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "cosh"));
4298         add_intrinsic_3f_3f_3f(ctx, stringcache(ctx->strcache, "cross"));
4299         add_intrinsic_4i_4f(ctx, stringcache(ctx->strcache, "D3DCOLORtoUBYTE4"));
4300         add_intrinsic_f_Vf_SAME1(ctx, stringcache(ctx->strcache, "distance"));
4301         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "degrees"));
4302         add_intrinsic_f_SQUAREMATRIXf(ctx, stringcache(ctx->strcache, "determinant"));
4303         add_intrinsic_fi_Vfi_SAME1(ctx, stringcache(ctx->strcache, "dot"));
4304         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp"));
4305         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "exp2"));
4306         add_intrinsic_SAME1_Vf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "faceforward"));
4307         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "floor"));
4308         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "fmod"));
4309         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "frac"));
4310         add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isfinite"));
4311         add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isinf"));
4312         add_intrinsic_BOOL_ANYf(ctx, stringcache(ctx->strcache, "isnan"));
4313         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "ldexp"));
4314         add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "length"));
4315         add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "lerp"));
4316         add_intrinsic_4f_f_f_f(ctx, stringcache(ctx->strcache, "lit"));
4317         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log"));
4318         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log10"));
4319         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "log2"));
4320         add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "max"));
4321         add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "min"));
4322         add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "modf"));  // !!! FIXME: out var?
4323         add_intrinsic_mul(ctx, stringcache(ctx->strcache, "mul"));
4324         add_intrinsic_f_Vf(ctx, stringcache(ctx->strcache, "noise"));
4325         add_intrinsic_SAME1_Vf(ctx, stringcache(ctx->strcache, "normalize"));
4326         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "pow"));
4327         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "radians"));
4328         add_intrinsic_SAME1_ANYfi_SAME1(ctx, stringcache(ctx->strcache, "reflect"));
4329         add_intrinsic_SAME1_Vf_SAME1_f(ctx, stringcache(ctx->strcache, "refract"));
4330         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "round"));
4331         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "rsqrt"));
4332         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "saturate"));
4333         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sign"));
4334         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sin"));
4335         add_intrinsic_VOID_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "sincos"));  // !!! FIXME: out var?
4336         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sinh"));
4337         add_intrinsic_SAME1_ANYf_SAME1_SAME1(ctx, stringcache(ctx->strcache, "smoothstep"));
4338         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "sqrt"));
4339         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "step"));
4340         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tan"));
4341         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "tanh"));
4342         add_intrinsic_4f_s1_f(ctx, stringcache(ctx->strcache, "tex1D"));
4343         add_intrinsic_4f_s2_2f(ctx, stringcache(ctx->strcache, "tex2D"));
4344         add_intrinsic_4f_s3_3f(ctx, stringcache(ctx->strcache, "tex3D"));
4345         add_intrinsic_4f_sc_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
4346         add_intrinsic_SAME1_Mfib(ctx, stringcache(ctx->strcache, "transpose"));
4347         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "trunc"));
4348     } // if
4349 
4350     if (shader_model >= 2)
4351     {
4352         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddx"));
4353         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "ddy"));
4354         add_intrinsic_SAME1_ANYf_SAME1(ctx, stringcache(ctx->strcache, "frexp"));
4355         add_intrinsic_SAME1_ANYf(ctx, stringcache(ctx->strcache, "fwidth"));
4356         add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1D"));
4357         add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dbias"));
4358         add_intrinsic_4f_s1_f_f_f(ctx, stringcache(ctx->strcache, "tex1Dgrad"));
4359         add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dproj"));
4360         add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2D"));
4361         add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dbias"));
4362         add_intrinsic_4f_s2_2f_2f_2f(ctx, stringcache(ctx->strcache, "tex2Dgrad"));
4363         add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dproj"));
4364         add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3D"));
4365         add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dbias"));
4366         add_intrinsic_4f_s3_3f_3f_3f(ctx, stringcache(ctx->strcache, "tex3Dgrad"));
4367         add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dproj"));
4368         add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBE"));
4369         add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEbias"));
4370         add_intrinsic_4f_sc_3f_3f_3f(ctx, stringcache(ctx->strcache, "texCUBEgrad"));
4371         add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBEproj"));
4372     } // if
4373 
4374     if (shader_model >= 3)
4375     {
4376         add_intrinsic_4f_s1_4f(ctx, stringcache(ctx->strcache, "tex1Dlod"));
4377         add_intrinsic_4f_s2_4f(ctx, stringcache(ctx->strcache, "tex2Dlod"));
4378         add_intrinsic_4f_s3_4f(ctx, stringcache(ctx->strcache, "tex3Dlod"));
4379         add_intrinsic_4f_sc_4f(ctx, stringcache(ctx->strcache, "texCUBElod"));
4380     } // if
4381 } // init_builtins
4382 
4383 
4384 // parse the source code into an AST.
parse_source(Context * ctx,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defines,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close)4385 static void parse_source(Context *ctx, const char *filename,
4386                          const char *source, unsigned int sourcelen,
4387                          const MOJOSHADER_preprocessorDefine *defines,
4388                          unsigned int define_count,
4389                          MOJOSHADER_includeOpen include_open,
4390                          MOJOSHADER_includeClose include_close)
4391 {
4392     TokenData data;
4393     unsigned int tokenlen;
4394     Token tokenval;
4395     const char *token;
4396     int lemon_token;
4397     const char *fname;
4398     Preprocessor *pp;
4399     void *parser;
4400 
4401     if (!include_open) include_open = MOJOSHADER_internal_include_open;
4402     if (!include_close) include_close = MOJOSHADER_internal_include_close;
4403 
4404     pp = preprocessor_start(filename, source, sourcelen, include_open,
4405                             include_close, defines, define_count, 0,
4406                             MallocBridge, FreeBridge, ctx);
4407     if (pp == NULL)
4408     {
4409         assert(ctx->out_of_memory);  // shouldn't fail for any other reason.
4410         return;
4411     } // if
4412 
4413     parser = ParseHLSLAlloc(ctx->malloc, ctx->malloc_data);
4414     if (parser == NULL)
4415     {
4416         assert(ctx->out_of_memory);  // shouldn't fail for any other reason.
4417         preprocessor_end(pp);
4418         return;
4419     } // if
4420 
4421     // !!! FIXME: check if (parser == NULL)...
4422 
4423     init_builtins(ctx);
4424 
4425     SymbolScope *start_scope = ctx->usertypes.scope;
4426 
4427     #if DEBUG_COMPILER_PARSER
4428     ParseHLSLTrace(stdout, "COMPILER: ");
4429     #endif
4430 
4431     // Run the preprocessor/lexer/parser...
4432     int is_pragma = 0;   // !!! FIXME: remove this later when we can parse #pragma.
4433     int skipping = 0; // !!! FIXME: remove this later when we can parse #pragma.
4434     do {
4435         token = preprocessor_nexttoken(pp, &tokenlen, &tokenval);
4436 
4437         if (ctx->out_of_memory)
4438             break;
4439 
4440         fname = preprocessor_sourcepos(pp, &ctx->sourceline);
4441         ctx->sourcefile = fname ? stringcache(ctx->strcache, fname) : 0;
4442 
4443         if ((tokenval == TOKEN_HASH) || (tokenval == TOKEN_HASHHASH))
4444             tokenval = TOKEN_BAD_CHARS;
4445 
4446         if (tokenval == TOKEN_BAD_CHARS)
4447         {
4448             fail(ctx, "Bad characters in source file");
4449             continue;
4450         } // else if
4451 
4452         else if (tokenval == TOKEN_PREPROCESSING_ERROR)
4453         {
4454             fail(ctx, token);  // this happens to be null-terminated.
4455             continue;
4456         } // else if
4457 
4458         else if (tokenval == TOKEN_PP_PRAGMA)
4459         {
4460             assert(!is_pragma);
4461             is_pragma = 1;
4462             skipping = 1;
4463             continue;
4464         }
4465 
4466         else if (tokenval == ((Token) '\n'))
4467         {
4468             assert(is_pragma);
4469             is_pragma = 0;
4470             skipping = 0;
4471             continue;
4472         }
4473 
4474         else if (skipping)
4475         {
4476             continue;
4477         }
4478 
4479         // !!! FIXME: this is a mess, decide who should be doing this stuff, and only do it once.
4480         lemon_token = convert_to_lemon_token(ctx, token, tokenlen, tokenval);
4481         switch (lemon_token)
4482         {
4483             case TOKEN_HLSL_INT_CONSTANT:
4484                 data.i64 = strtoi64(token, tokenlen);
4485                 break;
4486 
4487             case TOKEN_HLSL_FLOAT_CONSTANT:
4488                 data.dbl = strtodouble(token, tokenlen);
4489                 break;
4490 
4491             case TOKEN_HLSL_USERTYPE:
4492                 data.string = stringcache_len(ctx->strcache, token, tokenlen);
4493                 data.datatype = get_usertype(ctx, data.string);  // !!! FIXME: do we need this? It's kind of useless during parsing.
4494                 assert(data.datatype != NULL);
4495                 break;
4496 
4497             case TOKEN_HLSL_STRING_LITERAL:
4498             case TOKEN_HLSL_IDENTIFIER:
4499                 data.string = stringcache_len(ctx->strcache, token, tokenlen);
4500                 break;
4501 
4502             default:
4503                 data.i64 = 0;
4504                 break;
4505         } // switch
4506 
4507         ParseHLSL(parser, lemon_token, data, ctx);
4508 
4509         // this probably isn't perfect, but it's good enough for surviving
4510         //  the parse. We'll sort out correctness once we have a tree.
4511         if (lemon_token == TOKEN_HLSL_LBRACE)
4512             push_scope(ctx);
4513         else if (lemon_token == TOKEN_HLSL_RBRACE)
4514             pop_scope(ctx);
4515     } while (tokenval != TOKEN_EOI);
4516 
4517     // Clean out extra usertypes; they are dummies until semantic analysis.
4518     while (ctx->usertypes.scope != start_scope)
4519         pop_symbol(ctx, &ctx->usertypes);
4520 
4521     ParseHLSLFree(parser, ctx->free, ctx->malloc_data);
4522     preprocessor_end(pp);
4523 } // parse_source
4524 
4525 
4526 /* Intermediate representation... */
4527 
generate_ir_label(Context * ctx)4528 static inline int generate_ir_label(Context *ctx)
4529 {
4530     return ctx->ir_label_count++;
4531 } // generate_ir_label
4532 
generate_ir_temp(Context * ctx)4533 static inline int generate_ir_temp(Context *ctx)
4534 {
4535     return ctx->ir_temp_count++;
4536 } // generate_ir_temp
4537 
push_ir_loop(Context * ctx,const int isswitch)4538 static const LoopLabels *push_ir_loop(Context *ctx, const int isswitch)
4539 {
4540     // !!! FIXME: cache these allocations?
4541     LoopLabels *retval = (LoopLabels *)Malloc(ctx, sizeof (LoopLabels));
4542     if (retval)
4543     {
4544         retval->start = (isswitch) ? -1 : generate_ir_label(ctx);
4545         retval->end = generate_ir_label(ctx);
4546         retval->prev = ctx->ir_loop;
4547         ctx->ir_loop = retval;
4548     } // if
4549 
4550     return retval;
4551 } // push_ir_loop
4552 
pop_ir_loop(Context * ctx)4553 static void pop_ir_loop(Context *ctx)
4554 {
4555     assert(ctx->ir_loop != NULL);
4556     LoopLabels *labels = ctx->ir_loop;
4557     ctx->ir_loop = ctx->ir_loop->prev;
4558     Free(ctx, labels);
4559 } // pop_ir_loop
4560 
4561 
4562 #define NEW_IR_NODE(retval, cls, typ) \
4563     cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
4564     do { \
4565         if (retval == NULL) { return NULL; } \
4566         retval->ir.type = typ; \
4567         retval->ir.filename = ctx->sourcefile; \
4568         retval->ir.line = ctx->sourceline; \
4569     } while (0)
4570 
4571 #define NEW_IR_EXPR(retval, cls, typ, dt, numelems) \
4572     cls *retval = (cls *) Malloc(ctx, sizeof (cls)); \
4573     do { \
4574         if (retval == NULL) { return NULL; } \
4575         retval->info.ir.type = typ; \
4576         retval->info.ir.filename = ctx->sourcefile; \
4577         retval->info.ir.line = ctx->sourceline; \
4578         retval->info.type = dt; \
4579         retval->info.elements = numelems; \
4580     } while (0)
4581 
4582 // syntactic sugar.
4583 static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast);
build_ir_expr(Context * ctx,void * _ast)4584 static inline MOJOSHADER_irExpression *build_ir_expr(Context *ctx, void *_ast)
4585 {
4586     MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
4587     assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_EXPR));
4588     assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_EXPR));
4589     return (MOJOSHADER_irExpression *) retval;
4590 } // build_ir_expr
4591 
build_ir_stmt(Context * ctx,void * _ast)4592 static inline MOJOSHADER_irStatement *build_ir_stmt(Context *ctx, void *_ast)
4593 {
4594     MOJOSHADER_irNode *retval = build_ir(ctx, _ast);
4595     assert(!retval || (retval->ir.type > MOJOSHADER_IR_START_RANGE_STMT));
4596     assert(!retval || (retval->ir.type < MOJOSHADER_IR_END_RANGE_STMT));
4597     return (MOJOSHADER_irStatement *) retval;
4598 } // build_ir_stmt
4599 
4600 
new_ir_binop(Context * ctx,const MOJOSHADER_irBinOpType op,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right)4601 static MOJOSHADER_irExpression *new_ir_binop(Context *ctx,
4602                                        const MOJOSHADER_irBinOpType op,
4603                                        MOJOSHADER_irExpression *left,
4604                                        MOJOSHADER_irExpression *right)
4605 {
4606     if ((!left) || (!right)) return NULL;
4607     NEW_IR_EXPR(retval, MOJOSHADER_irBinOp, MOJOSHADER_IR_BINOP, left->info.type, left->info.elements);
4608     assert(left->info.type == right->info.type);
4609     assert(left->info.elements == right->info.elements);
4610     retval->op = op;
4611     retval->left = left;
4612     retval->right = right;
4613     return (MOJOSHADER_irExpression *) retval;
4614 } // new_ir_binop
4615 
new_ir_eseq(Context * ctx,MOJOSHADER_irStatement * stmt,MOJOSHADER_irExpression * expr)4616 static MOJOSHADER_irExpression *new_ir_eseq(Context *ctx,
4617                                       MOJOSHADER_irStatement *stmt,
4618                                       MOJOSHADER_irExpression *expr)
4619 {
4620     if (!expr) return NULL;
4621     NEW_IR_EXPR(retval, MOJOSHADER_irESeq, MOJOSHADER_IR_ESEQ, expr->info.type, expr->info.elements);
4622     retval->stmt = stmt;
4623     retval->expr = expr;
4624     return (MOJOSHADER_irExpression *) retval;
4625 } // new_ir_eseq
4626 
new_ir_temp(Context * ctx,const int index,const MOJOSHADER_astDataTypeType type,const int elements)4627 static MOJOSHADER_irExpression *new_ir_temp(Context *ctx, const int index,
4628                                             const MOJOSHADER_astDataTypeType type,
4629                                             const int elements)
4630 {
4631     NEW_IR_EXPR(retval, MOJOSHADER_irTemp, MOJOSHADER_IR_TEMP, type, elements);
4632     retval->index = index;
4633     return (MOJOSHADER_irExpression *) retval;
4634 } // new_ir_temp
4635 
4636 
4637 
4638 #define NEW_IR_BINOP(op,l,r) new_ir_binop(ctx, MOJOSHADER_IR_BINOP_##op, l, r)
4639 #define EASY_IR_BINOP(op) \
4640     NEW_IR_BINOP(op, build_ir_expr(ctx, ast->binary.left), \
4641                  build_ir_expr(ctx, ast->binary.right))
4642 
4643 // You have to fill in ->value yourself!
new_ir_constant(Context * ctx,const MOJOSHADER_astDataTypeType type,const int elements)4644 static MOJOSHADER_irExpression *new_ir_constant(Context *ctx,
4645                                                 const MOJOSHADER_astDataTypeType type,
4646                                                 const int elements)
4647 {
4648     NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, type, elements);
4649     return (MOJOSHADER_irExpression *) retval;
4650 } // new_ir_constant
4651 
new_ir_constint(Context * ctx,const int val)4652 static MOJOSHADER_irExpression *new_ir_constint(Context *ctx, const int val)
4653 {
4654     NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_INT, 1);
4655     retval->value.ival[0] = val;
4656     return (MOJOSHADER_irExpression *) retval;
4657 } // new_ir_constint
4658 
new_ir_constfloat(Context * ctx,const float val)4659 static MOJOSHADER_irExpression *new_ir_constfloat(Context *ctx, const float val)
4660 {
4661     NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_FLOAT, 1);
4662     retval->value.fval[0] = val;
4663     return (MOJOSHADER_irExpression *) retval;
4664 } // new_ir_constfloat
4665 
new_ir_constbool(Context * ctx,const int val)4666 static MOJOSHADER_irExpression *new_ir_constbool(Context *ctx, const int val)
4667 {
4668     // !!! FIXME: cache true and false in (ctx), ignore in delete_ir().
4669     NEW_IR_EXPR(retval, MOJOSHADER_irConstant, MOJOSHADER_IR_CONSTANT, MOJOSHADER_AST_DATATYPE_BOOL, 1);
4670     retval->value.ival[0] = val;
4671     return (MOJOSHADER_irExpression *) retval;
4672 } // new_ir_constbool
4673 
new_ir_convert(Context * ctx,MOJOSHADER_irExpression * expr,const MOJOSHADER_astDataTypeType type,const int elements)4674 static MOJOSHADER_irExpression *new_ir_convert(Context *ctx, MOJOSHADER_irExpression *expr,
4675                                                const MOJOSHADER_astDataTypeType type,
4676                                                const int elements)
4677 {
4678     NEW_IR_EXPR(retval, MOJOSHADER_irConvert, MOJOSHADER_IR_CONVERT, type, elements);
4679     retval->expr = expr;
4680     return (MOJOSHADER_irExpression *) retval;
4681 } // new_ir_convert
4682 
new_ir_construct(Context * ctx,MOJOSHADER_irExprList * args,const MOJOSHADER_astDataTypeType type,const int elements)4683 static MOJOSHADER_irExpression *new_ir_construct(Context *ctx, MOJOSHADER_irExprList *args,
4684                                                const MOJOSHADER_astDataTypeType type,
4685                                                const int elements)
4686 {
4687     NEW_IR_EXPR(retval, MOJOSHADER_irConstruct, MOJOSHADER_IR_CONSTRUCT, type, elements);
4688     retval->args = args;
4689     return (MOJOSHADER_irExpression *) retval;
4690 } // new_ir_construct
4691 
new_ir_call(Context * ctx,const int index,MOJOSHADER_irExprList * args,const MOJOSHADER_astDataTypeType type,const int elements)4692 static MOJOSHADER_irExpression *new_ir_call(Context *ctx, const int index,
4693                                             MOJOSHADER_irExprList *args,
4694                                             const MOJOSHADER_astDataTypeType type,
4695                                             const int elements)
4696 {
4697     NEW_IR_EXPR(retval, MOJOSHADER_irCall, MOJOSHADER_IR_CALL, type, elements);
4698     retval->args = args;
4699     retval->index = index;
4700     return (MOJOSHADER_irExpression *) retval;
4701 } // new_ir_call
4702 
new_ir_swizzle(Context * ctx,MOJOSHADER_irExpression * expr,const char * channels,const MOJOSHADER_astDataTypeType type,const int elements)4703 static MOJOSHADER_irExpression *new_ir_swizzle(Context *ctx,
4704                                                MOJOSHADER_irExpression *expr,
4705                                                const char *channels,
4706                                                const MOJOSHADER_astDataTypeType type,
4707                                                const int elements)
4708 {
4709     NEW_IR_EXPR(retval, MOJOSHADER_irSwizzle, MOJOSHADER_IR_SWIZZLE, type, elements);
4710     retval->expr = expr;
4711     memcpy(retval->channels, channels, sizeof (retval->channels));
4712     return (MOJOSHADER_irExpression *) retval;
4713 } // new_ir_swizzle
4714 
new_ir_memory(Context * ctx,const int index,const MOJOSHADER_astDataTypeType type,const int elements)4715 static MOJOSHADER_irExpression *new_ir_memory(Context *ctx, const int index,
4716                                               const MOJOSHADER_astDataTypeType type,
4717                                               const int elements)
4718 {
4719     NEW_IR_EXPR(retval, MOJOSHADER_irMemory, MOJOSHADER_IR_MEMORY, type, elements);
4720     retval->index = index;
4721     return (MOJOSHADER_irExpression *) retval;
4722 } // new_ir_memory
4723 
new_ir_array(Context * ctx,MOJOSHADER_irExpression * array,MOJOSHADER_irExpression * element,const MOJOSHADER_astDataTypeType type,const int elements)4724 static MOJOSHADER_irExpression *new_ir_array(Context *ctx,
4725                                              MOJOSHADER_irExpression *array,
4726                                              MOJOSHADER_irExpression *element,
4727                                              const MOJOSHADER_astDataTypeType type,
4728                                              const int elements)
4729 {
4730     NEW_IR_EXPR(retval, MOJOSHADER_irArray, MOJOSHADER_IR_ARRAY, type, elements);
4731     retval->array = array;
4732     retval->element = element;
4733     return (MOJOSHADER_irExpression *) retval;
4734 } // new_ir_array
4735 
new_ir_seq(Context * ctx,MOJOSHADER_irStatement * first,MOJOSHADER_irStatement * next)4736 static MOJOSHADER_irStatement *new_ir_seq(Context *ctx,
4737                                      MOJOSHADER_irStatement *first,
4738                                      MOJOSHADER_irStatement *next)
4739 {
4740     assert((first != NULL) || (next != NULL));
4741     if (first == NULL)  // don't generate a SEQ if unnecessary.
4742         return next;
4743     else if (next == NULL)
4744         return first;
4745 
4746     NEW_IR_NODE(retval, MOJOSHADER_irSeq, MOJOSHADER_IR_SEQ);
4747     retval->first = first;
4748     retval->next = next;
4749     return (MOJOSHADER_irStatement *) retval;
4750 } // new_ir_seq
4751 
new_ir_jump(Context * ctx,const int label)4752 static MOJOSHADER_irStatement *new_ir_jump(Context *ctx, const int label)
4753 {
4754     NEW_IR_NODE(retval, MOJOSHADER_irJump, MOJOSHADER_IR_JUMP);
4755     retval->label = label;
4756     return (MOJOSHADER_irStatement *) retval;
4757 } // new_ir_jump
4758 
new_ir_cjump(Context * ctx,const MOJOSHADER_irConditionType cond,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right,const int iftrue,const int iffalse)4759 static MOJOSHADER_irStatement *new_ir_cjump(Context *ctx,
4760                                        const MOJOSHADER_irConditionType cond,
4761                                        MOJOSHADER_irExpression *left,
4762                                        MOJOSHADER_irExpression *right,
4763                                        const int iftrue, const int iffalse)
4764 {
4765     NEW_IR_NODE(retval, MOJOSHADER_irCJump, MOJOSHADER_IR_CJUMP);
4766     retval->cond = cond;
4767     retval->left = left;
4768     retval->right = right;
4769     retval->iftrue = iftrue;
4770     retval->iffalse = iffalse;
4771     return (MOJOSHADER_irStatement *) retval;
4772 } // new_ir_cjump
4773 
new_ir_label(Context * ctx,const int index)4774 static MOJOSHADER_irStatement *new_ir_label(Context *ctx, const int index)
4775 {
4776     NEW_IR_NODE(retval, MOJOSHADER_irLabel, MOJOSHADER_IR_LABEL);
4777     retval->index = index;
4778     return (MOJOSHADER_irStatement *) retval;
4779 } // new_ir_label
4780 
new_ir_move(Context * ctx,MOJOSHADER_irExpression * dst,MOJOSHADER_irExpression * src,const int writemask)4781 static MOJOSHADER_irStatement *new_ir_move(Context *ctx,
4782                                       MOJOSHADER_irExpression *dst,
4783                                       MOJOSHADER_irExpression *src,
4784                                       const int writemask)
4785 {
4786     NEW_IR_NODE(retval, MOJOSHADER_irMove, MOJOSHADER_IR_MOVE);
4787     assert(dst && src && (dst->info.type == src->info.type));
4788     assert(dst && src && (dst->info.elements == src->info.elements));
4789     retval->dst = dst;
4790     retval->src = src;
4791     retval->writemask = writemask;
4792     return (MOJOSHADER_irStatement *) retval;
4793 } // new_ir_move
4794 
new_ir_expr_stmt(Context * ctx,MOJOSHADER_irExpression * expr)4795 static MOJOSHADER_irStatement *new_ir_expr_stmt(Context *ctx, MOJOSHADER_irExpression *expr)
4796 {
4797     NEW_IR_NODE(retval, MOJOSHADER_irExprStmt, MOJOSHADER_IR_EXPR_STMT);
4798     retval->expr = expr;
4799     return (MOJOSHADER_irStatement *) retval;
4800 } // new_ir_expr_stmt
4801 
new_ir_discard(Context * ctx)4802 static MOJOSHADER_irStatement *new_ir_discard(Context *ctx)
4803 {
4804     NEW_IR_NODE(retval, MOJOSHADER_irDiscard, MOJOSHADER_IR_DISCARD);
4805     return (MOJOSHADER_irStatement *) retval;
4806 } // new_ir_discard
4807 
new_ir_exprlist(Context * ctx,MOJOSHADER_irExpression * expr)4808 static MOJOSHADER_irExprList *new_ir_exprlist(Context *ctx, MOJOSHADER_irExpression *expr)
4809 {
4810     NEW_IR_NODE(retval, MOJOSHADER_irExprList, MOJOSHADER_IR_EXPRLIST);
4811     retval->expr = expr;
4812     retval->next = NULL;
4813     return (MOJOSHADER_irExprList *) retval;
4814 } // new_ir_exprlist
4815 
4816 
4817 // This handles most comparison operators (less-than, equals, etc...)
build_ir_compare(Context * ctx,const MOJOSHADER_irConditionType operation,MOJOSHADER_irExpression * left,MOJOSHADER_irExpression * right,MOJOSHADER_irExpression * tval,MOJOSHADER_irExpression * fval)4818 static MOJOSHADER_irExpression *build_ir_compare(Context *ctx,
4819                                     const MOJOSHADER_irConditionType operation,
4820                                     MOJOSHADER_irExpression *left,
4821                                     MOJOSHADER_irExpression *right,
4822                                     MOJOSHADER_irExpression *tval,
4823                                     MOJOSHADER_irExpression *fval)
4824 {
4825     /* The gist...
4826             cjump x < y, t, f  // '<' is whatever operation
4827         t:
4828             move tmp, tval
4829             jump join
4830         f:
4831             move tmp, fval
4832         join:
4833     */
4834 
4835     const int t = generate_ir_label(ctx);
4836     const int f = generate_ir_label(ctx);
4837     const int join = generate_ir_label(ctx);
4838     const int tmp = generate_ir_temp(ctx);
4839 
4840     assert(tval && fval && (tval->info.type == fval->info.type));
4841     assert(tval && fval && (tval->info.elements == fval->info.elements));
4842 
4843     const MOJOSHADER_astDataTypeType dt = tval->info.type;
4844     const int elements = tval->info.elements;
4845 
4846     return new_ir_eseq(ctx,
4847                 new_ir_seq(ctx, new_ir_cjump(ctx, operation, left, right, t, f),
4848                 new_ir_seq(ctx, new_ir_label(ctx, t),
4849                 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), tval, -1),
4850                 new_ir_seq(ctx, new_ir_jump(ctx, join),
4851                 new_ir_seq(ctx, new_ir_label(ctx, f),
4852                 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elements), fval, -1),
4853                                 new_ir_label(ctx, join))))))),
4854                     new_ir_temp(ctx, tmp, dt, elements));
4855 } // build_ir_compare
4856 
4857 #define EASY_IR_COMPARE(op) \
4858     build_ir_compare(ctx, MOJOSHADER_IR_COND_##op, \
4859                    build_ir_expr(ctx, ast->binary.left), \
4860                    build_ir_expr(ctx, ast->binary.right), \
4861                    new_ir_constbool(ctx, 1), \
4862                    new_ir_constbool(ctx, 0))
4863 
4864 
4865 // This handles && and || operators.
build_ir_logical_and_or(Context * ctx,const MOJOSHADER_astExpressionBinary * ast,const int left_testval)4866 static MOJOSHADER_irExpression *build_ir_logical_and_or(Context *ctx,
4867                                     const MOJOSHADER_astExpressionBinary *ast,
4868                                     const int left_testval)
4869 {
4870     /* The gist...
4871             cjump left == left_testval, maybe, f
4872         maybe:
4873             cjump right == true, t, f
4874         t:
4875             move tmp, 1
4876             jump join
4877         f:
4878             move tmp, 0
4879         join:
4880     */
4881 
4882     assert(ast->left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4883     assert(ast->right->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4884 
4885     const int t = generate_ir_label(ctx);
4886     const int f = generate_ir_label(ctx);
4887     const int maybe = generate_ir_label(ctx);
4888     const int join = generate_ir_label(ctx);
4889     const int tmp = generate_ir_temp(ctx);
4890 
4891     return new_ir_eseq(ctx,
4892                 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->left), new_ir_constbool(ctx, left_testval), maybe, f),
4893                 new_ir_seq(ctx, new_ir_label(ctx, maybe),
4894                 new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->right), new_ir_constbool(ctx, 1), t, f),
4895                 new_ir_seq(ctx, new_ir_label(ctx, t),
4896                 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 1), -1),
4897                 new_ir_seq(ctx, new_ir_jump(ctx, join),
4898                 new_ir_seq(ctx, new_ir_label(ctx, f),
4899                 new_ir_seq(ctx, new_ir_move(ctx, new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1), new_ir_constbool(ctx, 0), -1),
4900                                 new_ir_label(ctx, join))))))))),
4901                     new_ir_temp(ctx, tmp, MOJOSHADER_AST_DATATYPE_BOOL, 1));
4902 } // build_ir_logical_and_or
4903 
build_ir_logical_and(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)4904 static inline MOJOSHADER_irExpression *build_ir_logical_and(Context *ctx,
4905                                     const MOJOSHADER_astExpressionBinary *ast)
4906 {
4907     // this needs to not evaluate (right) if (left) is false!
4908     return build_ir_logical_and_or(ctx, ast, 1);
4909 } // build_ir_logical_and
4910 
build_ir_logical_or(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)4911 static inline MOJOSHADER_irExpression *build_ir_logical_or(Context *ctx,
4912                                     const MOJOSHADER_astExpressionBinary *ast)
4913 {
4914     // this needs to not evaluate (right) if (left) is true!
4915     return build_ir_logical_and_or(ctx, ast, 0);
4916 } // build_ir_logical_or
4917 
build_ir_no_op(Context * ctx)4918 static inline MOJOSHADER_irStatement *build_ir_no_op(Context *ctx)
4919 {
4920     return new_ir_label(ctx, generate_ir_label(ctx));
4921 } // build_ir_no_op
4922 
build_ir_ifstmt(Context * ctx,const MOJOSHADER_astIfStatement * ast)4923 static MOJOSHADER_irStatement *build_ir_ifstmt(Context *ctx,
4924                                           const MOJOSHADER_astIfStatement *ast)
4925 {
4926     assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4927 
4928     // !!! FIXME: ast->attributes?
4929 
4930     // IF statement without an ELSE.
4931     if (ast->else_statement == NULL)
4932     {
4933         /* The gist...
4934                 cjump expr, t, join
4935             t:
4936                 statement
4937             join:
4938         */
4939 
4940         const int t = generate_ir_label(ctx);
4941         const int join = generate_ir_label(ctx);
4942 
4943         return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
4944                new_ir_seq(ctx, new_ir_label(ctx, t),
4945                new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
4946                new_ir_seq(ctx, new_ir_label(ctx, join),
4947                                build_ir_stmt(ctx, ast->next)))));
4948     } // if
4949 
4950     // IF statement _with_ an ELSE.
4951     /* The gist...
4952             cjump expr, t, f
4953         t:
4954             statement
4955             jump join
4956         f:
4957             elsestatement
4958         join:
4959     */
4960 
4961     const int t = generate_ir_label(ctx);
4962     const int f = generate_ir_label(ctx);
4963     const int join = generate_ir_label(ctx);
4964 
4965     return new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, f),
4966            new_ir_seq(ctx, new_ir_label(ctx, t),
4967            new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
4968            new_ir_seq(ctx, new_ir_jump(ctx, join),
4969            new_ir_seq(ctx, new_ir_label(ctx, f),
4970            new_ir_seq(ctx, build_ir_stmt(ctx, ast->else_statement),
4971            new_ir_seq(ctx, new_ir_label(ctx, join),
4972                            build_ir_stmt(ctx, ast->next))))))));
4973 } // build_ir_ifstmt
4974 
4975 
build_ir_forstmt(Context * ctx,const MOJOSHADER_astForStatement * ast)4976 static MOJOSHADER_irStatement *build_ir_forstmt(Context *ctx,
4977                                        const MOJOSHADER_astForStatement *ast)
4978 {
4979     // !!! FIXME: ast->unroll
4980 
4981     assert(ast->looptest->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
4982 
4983     /* The gist...
4984             initializer  // (or var_decl->initializer!)
4985         test:
4986             cjump looptest == true, loop, join
4987         loop:
4988             statement
4989         increment:  // needs to be here; this is where "continue" jumps!
4990             counter
4991             jump test
4992         join:
4993     */
4994 
4995     const int test = generate_ir_label(ctx);
4996     const int loop = generate_ir_label(ctx);
4997 
4998     const LoopLabels *labels = push_ir_loop(ctx, 0);
4999     if (labels == NULL)
5000         return NULL;  // out of memory...
5001 
5002     const int increment = labels->start;
5003     const int join = labels->end;
5004 
5005     assert( (ast->var_decl && !ast->initializer) ||
5006             (!ast->var_decl && ast->initializer) );
5007 
5008     MOJOSHADER_irStatement *init = NULL;
5009     if (ast->var_decl != NULL)
5010     {
5011 //sdfsdf
5012         // !!! FIXME: map the initializer to the variable? Need fix to var_decl parsing.
5013 //        new_ir_move(ctx, FIXME MAP TO REGISTER ast->var_decl->index, build_ir_expr(ctx, ast->fsdf));
5014 //        FIXME
5015 //        init = build_ir_vardecl(ctx, ast->var_decl);
5016     } // if
5017     else
5018     {
5019 //        init = build_ir_expr(ctx, ast->initializer);
5020     } // else
5021 
5022     MOJOSHADER_irStatement *retval =
5023         new_ir_seq(ctx, init,
5024         new_ir_seq(ctx, new_ir_label(ctx, test),
5025         new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->looptest), new_ir_constbool(ctx, 1), loop, join),
5026         new_ir_seq(ctx, new_ir_label(ctx, loop),
5027         new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5028         new_ir_seq(ctx, new_ir_label(ctx, increment),
5029         new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->counter)),
5030         new_ir_seq(ctx, new_ir_jump(ctx, test),
5031                         new_ir_label(ctx, join)))))))));
5032 
5033     pop_ir_loop(ctx);
5034 
5035     return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5036 } // build_ir_forstmt
5037 
build_ir_whilestmt(Context * ctx,const MOJOSHADER_astWhileStatement * ast)5038 static MOJOSHADER_irStatement *build_ir_whilestmt(Context *ctx,
5039                                           const MOJOSHADER_astWhileStatement *ast)
5040 {
5041     // !!! FIXME: ast->unroll
5042 
5043     assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5044 
5045     /* The gist...
5046         loop:
5047             cjump expr == true, t, join
5048         t:
5049             statement
5050             jump loop
5051         join:
5052     */
5053 
5054     const LoopLabels *labels = push_ir_loop(ctx, 0);
5055     if (labels == NULL)
5056         return NULL;  // out of memory...
5057 
5058     const int loop = labels->start;
5059     const int t = generate_ir_label(ctx);
5060     const int join = labels->end;
5061 
5062     MOJOSHADER_irStatement *retval =
5063         new_ir_seq(ctx, new_ir_label(ctx, loop),
5064         new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), t, join),
5065         new_ir_seq(ctx, new_ir_label(ctx, t),
5066         new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5067         new_ir_seq(ctx, new_ir_jump(ctx, loop),
5068                         new_ir_label(ctx, join))))));
5069 
5070     pop_ir_loop(ctx);
5071 
5072     return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5073 } // build_ir_whilestmt
5074 
build_ir_dostmt(Context * ctx,const MOJOSHADER_astDoStatement * ast)5075 static MOJOSHADER_irStatement *build_ir_dostmt(Context *ctx,
5076                                           const MOJOSHADER_astDoStatement *ast)
5077 {
5078     // !!! FIXME: ast->unroll
5079 
5080     assert(ast->expr->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5081 
5082     /* The gist...
5083         loop:
5084             statement
5085             cjump expr == true, loop, join
5086         join:
5087     */
5088 
5089     const LoopLabels *labels = push_ir_loop(ctx, 0);
5090     if (labels == NULL)
5091         return NULL;  // out of memory...
5092 
5093     const int loop = labels->start;
5094     const int join = labels->end;
5095 
5096     MOJOSHADER_irStatement *retval =
5097         new_ir_seq(ctx, new_ir_label(ctx, loop),
5098         new_ir_seq(ctx, build_ir_stmt(ctx, ast->statement),
5099         new_ir_seq(ctx, new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, ast->expr), new_ir_constbool(ctx, 1), loop, join),
5100                         new_ir_label(ctx, join))));
5101 
5102     pop_ir_loop(ctx);
5103 
5104     return new_ir_seq(ctx, retval, build_ir_stmt(ctx, ast->next));
5105 } // build_ir_dostmt
5106 
build_ir_switch(Context * ctx,const MOJOSHADER_astSwitchStatement * ast)5107 static MOJOSHADER_irStatement *build_ir_switch(Context *ctx, const MOJOSHADER_astSwitchStatement *ast)
5108 {
5109     // Dithering down to a list of if-statements in all cases
5110     //  isn't ideal, but we can't do jumptables in D3D bytecode.
5111 
5112     // !!! FIXME: attributes?
5113 
5114     /* The gist...
5115             move tmp, expr
5116             cjump tmp == case1expr, case1, testcase2
5117         testcase2:  // etc
5118             cjump tmp == case2expr, case2, join
5119         case1:
5120             case1stmt  // might have a break in it somewhere.
5121         case2:
5122             case2stmt
5123         join:
5124     */
5125 
5126     const LoopLabels *labels = push_ir_loop(ctx, 1);
5127     if (labels == NULL)
5128         return NULL;  // out of memory...
5129 
5130     const int join = labels->end;
5131     const int elems = datatype_elems(ctx, ast->expr->datatype);
5132     const MOJOSHADER_astDataTypeType dt = datatype_base(ctx, ast->expr->datatype)->type;
5133 
5134     const MOJOSHADER_astSwitchCases *cases = ast->cases;
5135     const int tmp = generate_ir_temp(ctx);
5136     MOJOSHADER_irStatement *startseqs = new_ir_move(ctx, new_ir_temp(ctx, tmp, dt, elems), build_ir_expr(ctx, ast->expr), -1);
5137     MOJOSHADER_irStatement *testseqs = startseqs;
5138     MOJOSHADER_irStatement *startcaseseqs = NULL;
5139     MOJOSHADER_irStatement *caseseqs = NULL;
5140     while (cases)
5141     {
5142         const int t = generate_ir_label(ctx);
5143         const int f = (cases->next == NULL) ? join : generate_ir_label(ctx);
5144         MOJOSHADER_irStatement *cjump = new_ir_cjump(ctx, MOJOSHADER_IR_COND_EQL, build_ir_expr(ctx, cases->expr), new_ir_temp(ctx, tmp, dt, elems), t, f);
5145 
5146         if (cases->next == NULL)  // last one, do the join label.
5147         {
5148             testseqs = new_ir_seq(ctx, testseqs, cjump);
5149             caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
5150             caseseqs = new_ir_seq(ctx, caseseqs, new_ir_label(ctx, f));
5151         } // if
5152         else
5153         {
5154             testseqs = new_ir_seq(ctx, testseqs, new_ir_seq(ctx, cjump, new_ir_label(ctx, f)));
5155             caseseqs = new_ir_seq(ctx, caseseqs, new_ir_seq(ctx, new_ir_label(ctx, t), build_ir_stmt(ctx, cases->statement)));
5156         } // else
5157 
5158         if (startcaseseqs == NULL)
5159             startcaseseqs = caseseqs;
5160 
5161         cases = cases->next;
5162     } // while
5163 
5164     pop_ir_loop(ctx);
5165 
5166     return new_ir_seq(ctx, startseqs, new_ir_seq(ctx, startcaseseqs, build_ir_stmt(ctx, ast->next)));
5167 } // build_ir_switch
5168 
build_ir_increxpr(Context * ctx,const MOJOSHADER_astDataType * _dt,const int val)5169 static MOJOSHADER_irExpression *build_ir_increxpr(Context *ctx, const MOJOSHADER_astDataType *_dt,
5170                                                   const int val)
5171 {
5172     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, _dt);
5173     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5174     const int elems = datatype_elems(ctx, dt);
5175     MOJOSHADER_irConstant *retval = (MOJOSHADER_irConstant *) new_ir_constant(ctx, type, elems);
5176     int i;
5177 
5178     switch (type)
5179     {
5180         case MOJOSHADER_AST_DATATYPE_BOOL:
5181         case MOJOSHADER_AST_DATATYPE_INT:
5182         case MOJOSHADER_AST_DATATYPE_UINT:
5183             for (i = 0; i < elems; i++)
5184                 retval->value.ival[i] = (int) val;
5185             break;
5186 
5187         case MOJOSHADER_AST_DATATYPE_FLOAT:
5188         case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
5189         case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
5190         case MOJOSHADER_AST_DATATYPE_HALF:
5191         case MOJOSHADER_AST_DATATYPE_DOUBLE:
5192             for (i = 0; i < elems; i++)
5193                 retval->value.fval[i] = (float) val;
5194             break;
5195 
5196         default:
5197             assert(0 && "Semantic analysis should have caught this!");
5198     } // switch
5199 
5200     return (MOJOSHADER_irExpression *) retval;
5201 } // build_ir_increxpr
5202 
build_ir_preincdec(Context * ctx,MOJOSHADER_astExpressionUnary * ast,const MOJOSHADER_irBinOpType binop)5203 static MOJOSHADER_irExpression *build_ir_preincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
5204 {
5205     /* The gist...
5206         move expr, expr + 1
5207         return expr
5208     */
5209     // !!! FIXME: can you writemask an increment operator?
5210     MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
5211     return new_ir_eseq(ctx,
5212                 new_ir_move(ctx,
5213                     build_ir_expr(ctx, ast->operand),
5214                     new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1),
5215                 build_ir_expr(ctx, ast->operand));
5216 } // build_ir_preincdec
5217 
build_ir_postincdec(Context * ctx,MOJOSHADER_astExpressionUnary * ast,const MOJOSHADER_irBinOpType binop)5218 static MOJOSHADER_irExpression *build_ir_postincdec(Context *ctx, MOJOSHADER_astExpressionUnary *ast, const MOJOSHADER_irBinOpType binop)
5219 {
5220     /* The gist...
5221         move tmp, expr
5222         move expr, expr + 1
5223         return tmp
5224     */
5225 
5226     // !!! FIXME: can you writemask an increment operator?
5227     MOJOSHADER_irExpression *constant = build_ir_increxpr(ctx, ast->datatype, 1);
5228     const int tmp = generate_ir_temp(ctx);
5229     return new_ir_eseq(ctx,
5230                 new_ir_seq(ctx,
5231                     new_ir_move(ctx, new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements), build_ir_expr(ctx, ast->operand), -1),
5232                     new_ir_move(ctx, build_ir_expr(ctx, ast->operand),
5233                         new_ir_binop(ctx, binop, build_ir_expr(ctx, ast->operand), constant), -1)),
5234                 new_ir_temp(ctx, tmp, constant->info.type, constant->info.elements));
5235 } // build_ir_postincdec
5236 
build_ir_convert(Context * ctx,const MOJOSHADER_astExpressionCast * ast)5237 static MOJOSHADER_irExpression *build_ir_convert(Context *ctx, const MOJOSHADER_astExpressionCast *ast)
5238 {
5239     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5240     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5241     const int elems = datatype_elems(ctx, dt);
5242     return new_ir_convert(ctx, build_ir_expr(ctx, ast->operand), type, elems);
5243 } // build_ir_convert
5244 
build_ir_exprlist(Context * ctx,MOJOSHADER_astArguments * args)5245 static MOJOSHADER_irExprList *build_ir_exprlist(Context *ctx, MOJOSHADER_astArguments *args)
5246 {
5247     MOJOSHADER_irExprList *retval = NULL;
5248     MOJOSHADER_irExprList *prev = NULL;
5249 
5250     while (args != NULL)
5251     {
5252         assert((retval && prev) || ((!retval) && (!prev)));
5253 
5254         MOJOSHADER_irExprList *item = new_ir_exprlist(ctx, build_ir_expr(ctx, args->argument));
5255         if (prev == NULL)
5256             prev = retval = item;
5257         else
5258             prev->next = item;
5259 
5260         args = args->next;
5261     } // while
5262 
5263     return retval;
5264 } // build_ir_exprlist
5265 
build_ir_constructor(Context * ctx,const MOJOSHADER_astExpressionConstructor * ast)5266 static MOJOSHADER_irExpression *build_ir_constructor(Context *ctx, const MOJOSHADER_astExpressionConstructor *ast)
5267 {
5268     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5269     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5270     const int elems = datatype_elems(ctx, dt);
5271     assert(elems <= 16);  // just in case (matrix4x4 constructor is largest).
5272     return new_ir_construct(ctx, build_ir_exprlist(ctx, ast->args), type, elems);
5273 } // build_ir_constructor
5274 
build_ir_call(Context * ctx,const MOJOSHADER_astExpressionCallFunction * ast)5275 static MOJOSHADER_irExpression *build_ir_call(Context *ctx, const MOJOSHADER_astExpressionCallFunction *ast)
5276 {
5277     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5278     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5279     const int elems = datatype_elems(ctx, dt);
5280     return new_ir_call(ctx, ast->identifier->index, build_ir_exprlist(ctx, ast->args), type, elems);
5281 } // build_ir_call
5282 
swiz_to_channel(const char swiz)5283 static char swiz_to_channel(const char swiz)
5284 {
5285     if ((swiz == 'r') || (swiz == 'x')) return 0;
5286     if ((swiz == 'g') || (swiz == 'y')) return 1;
5287     if ((swiz == 'b') || (swiz == 'z')) return 2;
5288     if ((swiz == 'a') || (swiz == 'w')) return 3;
5289     assert(0 && "Should have been caught by semantic analysis.");
5290     return 0;
5291 } // swiz_to_channel
5292 
build_ir_swizzle(Context * ctx,const MOJOSHADER_astExpressionDerefStruct * ast)5293 static MOJOSHADER_irExpression *build_ir_swizzle(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
5294 {
5295     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5296     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5297     const int elems = datatype_elems(ctx, dt);
5298     char chans[4] = { 0, 0, 0, 0 };
5299     const char *swizstr = ast->member;
5300     int i;
5301 
5302     for (i = 0; swizstr[i]; i++)
5303         chans[i] = swiz_to_channel(swizstr[i]);
5304 
5305     return new_ir_swizzle(ctx, build_ir_expr(ctx, ast->identifier), chans, type, elems);
5306 } // build_ir_swizzle
5307 
build_ir_identifier(Context * ctx,const MOJOSHADER_astExpressionIdentifier * ast)5308 static MOJOSHADER_irExpression *build_ir_identifier(Context *ctx, const MOJOSHADER_astExpressionIdentifier *ast)
5309 {
5310     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5311     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5312     const int elems = datatype_elems(ctx, dt);
5313     return new_ir_memory(ctx, ast->index, type, elems);
5314 } // build_ir_identifier
5315 
build_ir_derefstruct(Context * ctx,const MOJOSHADER_astExpressionDerefStruct * ast)5316 static MOJOSHADER_irExpression *build_ir_derefstruct(Context *ctx, const MOJOSHADER_astExpressionDerefStruct *ast)
5317 {
5318     // There are only three possible IR nodes that contain a struct:
5319     //  an irTemp, an irMemory, or an irESeq that results in a temp or memory.
5320     //  As such, we figure out which it is, and offset appropriately for the
5321     //  member.
5322     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5323     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5324     const int elems = datatype_elems(ctx, dt);
5325     MOJOSHADER_irExpression *expr = build_ir_expr(ctx, ast->identifier);
5326     MOJOSHADER_irExpression *finalexpr = expr;
5327 
5328     if (expr == NULL)
5329         return NULL;
5330 
5331     assert(!ast->isswizzle);
5332 
5333     while (finalexpr->ir.type == MOJOSHADER_IR_ESEQ)
5334         finalexpr = finalexpr->eseq.expr;
5335 
5336     if (finalexpr->ir.type == MOJOSHADER_IR_TEMP)
5337         finalexpr->temp.index += ast->member_index;
5338     else if (finalexpr->ir.type == MOJOSHADER_IR_MEMORY)
5339         finalexpr->memory.index += ast->member_index;
5340     else
5341         assert(0 && "Unexpected condition");
5342 
5343     // Replace the struct type with the type of the member.
5344     expr->info.type = type;
5345     expr->info.elements = elems;
5346 
5347     return expr;
5348 } // build_ir_derefstruct
5349 
build_ir_derefarray(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)5350 static MOJOSHADER_irExpression *build_ir_derefarray(Context *ctx, const MOJOSHADER_astExpressionBinary *ast)
5351 {
5352     // In most compilers, arrays dither down to offsets into memory, but
5353     //  they're somewhat special in D3D, since they might have to deal with
5354     //  vectors, etc...so we keep them as first-class citizens of the IR,
5355     //  and let the optimizer/codegen sort it out.
5356     // !!! FIXME: this might be the wrong move. Maybe remove this IR node type?
5357     const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->datatype);
5358     const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5359     const int elems = datatype_elems(ctx, dt);
5360 
5361     // !!! FIXME: Array dereference of a vector can become a simple swizzle operation, if we have a constant index.
5362     // !!! FIXME: Matrix dereference of a vector can become a simple reference to a temp/memory, if we have a constant index.
5363     return new_ir_array(ctx, build_ir_expr(ctx, ast->left), build_ir_expr(ctx, ast->right), type, elems);
5364 } // build_ir_derefarray
5365 
build_ir_assign_binop(Context * ctx,const MOJOSHADER_irBinOpType op,const MOJOSHADER_astExpressionBinary * ast)5366 static MOJOSHADER_irExpression *build_ir_assign_binop(Context *ctx,
5367                                                 const MOJOSHADER_irBinOpType op,
5368                                                 const MOJOSHADER_astExpressionBinary *ast)
5369 {
5370     MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
5371     MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
5372     const MOJOSHADER_astDataTypeType type = lvalue->info.type;
5373     const int elems = lvalue->info.elements;
5374     const int tmp = generate_ir_temp(ctx);
5375 
5376     // Semantic analysis should have inserted casts if necessary.
5377     assert(type == rvalue->info.type);
5378     assert(elems == rvalue->info.elements);
5379 
5380     // The destination must eventually be lvalue, which means memory or temp.
5381     MOJOSHADER_irExpression *dst = lvalue;
5382     while (dst->ir.type == MOJOSHADER_IR_ESEQ)
5383         dst = dst->eseq.expr;
5384 
5385     if (dst->ir.type == MOJOSHADER_IR_TEMP)
5386         dst = new_ir_temp(ctx, dst->temp.index, dst->info.type, dst->info.elements);
5387     else if (dst->ir.type == MOJOSHADER_IR_MEMORY)
5388         dst = new_ir_memory(ctx, dst->memory.index, dst->info.type, dst->info.elements);
5389     else
5390         assert(0 && "Unexpected condition");
5391 
5392     // !!! FIXME: write masking!
5393     return new_ir_eseq(ctx,
5394                 new_ir_seq(ctx,
5395                     new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), new_ir_binop(ctx, op, lvalue, rvalue), -1),
5396                     new_ir_move(ctx, dst, new_ir_temp(ctx, tmp, type, elems), -1)),
5397                 new_ir_temp(ctx, tmp, type, elems));
5398 } // build_ir_assign_binop
5399 
build_ir_assign(Context * ctx,const MOJOSHADER_astExpressionBinary * ast)5400 static MOJOSHADER_irExpression *build_ir_assign(Context *ctx,
5401                                                 const MOJOSHADER_astExpressionBinary *ast)
5402 {
5403     MOJOSHADER_irExpression *lvalue = build_ir_expr(ctx, ast->left);
5404     MOJOSHADER_irExpression *rvalue = build_ir_expr(ctx, ast->right);
5405     const MOJOSHADER_astDataTypeType type = lvalue->info.type;
5406     const int elems = lvalue->info.elements;
5407     const int tmp = generate_ir_temp(ctx);
5408 
5409     // Semantic analysis should have inserted casts if necessary.
5410     assert(type == rvalue->info.type);
5411     assert(elems == rvalue->info.elements);
5412 
5413     // !!! FIXME: write masking!
5414     // !!! FIXME: whole array/struct assignments need to become a sequence of moves.
5415     return new_ir_eseq(ctx,
5416                 new_ir_seq(ctx,
5417                     new_ir_move(ctx, new_ir_temp(ctx, tmp, type, elems), rvalue, -1),
5418                     new_ir_move(ctx, lvalue, new_ir_temp(ctx, tmp, type, elems), -1)),
5419                 new_ir_temp(ctx, tmp, type, elems));
5420 } // build_ir_assign
5421 
5422 
5423 // The AST must be perfect and normalized and sane here. If there are any
5424 //  strange corner cases, you should strive to handle them in semantic
5425 //  analysis, so conversion to IR can proceed with a minimum of drama.
5426 static void *build_ir_internal(Context *ctx, void *_ast);
build_ir(Context * ctx,void * _ast)5427 static inline MOJOSHADER_irNode *build_ir(Context *ctx, void *_ast)
5428 {
5429     return (MOJOSHADER_irNode *) build_ir_internal(ctx, _ast);
5430 } // build_ir
5431 
build_ir_internal(Context * ctx,void * _ast)5432 static void *build_ir_internal(Context *ctx, void *_ast)
5433 {
5434     if ((_ast == NULL) || (ctx->out_of_memory))
5435         return NULL;
5436 
5437     MOJOSHADER_astNode *ast = (MOJOSHADER_astNode *) _ast;
5438 
5439     // upkeep so we report correct error locations...
5440     ctx->sourcefile = ast->ast.filename;
5441     ctx->sourceline = ast->ast.line;
5442 
5443     switch (ast->ast.type)
5444     {
5445         case MOJOSHADER_AST_OP_PREINCREMENT:  // !!! FIXME: sequence points?
5446             return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
5447 
5448         case MOJOSHADER_AST_OP_POSTINCREMENT: // !!! FIXME: sequence points?
5449             return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_ADD);
5450 
5451         case MOJOSHADER_AST_OP_PREDECREMENT:  // !!! FIXME: sequence points?
5452             return build_ir_preincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
5453 
5454         case MOJOSHADER_AST_OP_POSTDECREMENT: // !!! FIXME: sequence points?
5455             return build_ir_postincdec(ctx, &ast->unary, MOJOSHADER_IR_BINOP_SUBTRACT);
5456 
5457         case MOJOSHADER_AST_OP_COMPLEMENT:
5458             return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
5459                                 new_ir_constint(ctx, 0xFFFFFFFF));
5460 
5461         case MOJOSHADER_AST_OP_NEGATE:  // !!! FIXME: -0.0f != +0.0f
5462             return NEW_IR_BINOP(SUBTRACT, build_ir_increxpr(ctx, ast->unary.datatype, -1),
5463                                 build_ir_expr(ctx, ast->unary.operand));
5464 
5465         case MOJOSHADER_AST_OP_NOT:  // operand must be bool here!
5466             assert(ast->unary.operand->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5467             return NEW_IR_BINOP(XOR, build_ir_expr(ctx, ast->unary.operand),
5468                                 new_ir_constint(ctx, 1));
5469 
5470         case MOJOSHADER_AST_OP_DEREF_ARRAY:
5471             return build_ir_derefarray(ctx, &ast->binary);
5472 
5473         case MOJOSHADER_AST_OP_DEREF_STRUCT:
5474             if (ast->derefstruct.isswizzle)
5475                 return build_ir_swizzle(ctx, &ast->derefstruct);
5476             return build_ir_derefstruct(ctx, &ast->derefstruct);
5477 
5478         case MOJOSHADER_AST_OP_COMMA:
5479             // evaluate and throw away left, return right.
5480             return new_ir_eseq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->binary.left)),
5481                                build_ir_expr(ctx, ast->binary.right));
5482 
5483         case MOJOSHADER_AST_OP_LESSTHAN: return EASY_IR_COMPARE(LT);
5484         case MOJOSHADER_AST_OP_GREATERTHAN: return EASY_IR_COMPARE(GT);
5485         case MOJOSHADER_AST_OP_LESSTHANOREQUAL: return EASY_IR_COMPARE(LEQ);
5486         case MOJOSHADER_AST_OP_GREATERTHANOREQUAL: return EASY_IR_COMPARE(GEQ);
5487         case MOJOSHADER_AST_OP_NOTEQUAL: return EASY_IR_COMPARE(NEQ);
5488         case MOJOSHADER_AST_OP_EQUAL: return EASY_IR_COMPARE(EQL);
5489 
5490         case MOJOSHADER_AST_OP_MULTIPLY: return EASY_IR_BINOP(MULTIPLY);
5491         case MOJOSHADER_AST_OP_DIVIDE: return EASY_IR_BINOP(DIVIDE);
5492         case MOJOSHADER_AST_OP_MODULO: return EASY_IR_BINOP(MODULO);
5493         case MOJOSHADER_AST_OP_ADD: return EASY_IR_BINOP(ADD);
5494         case MOJOSHADER_AST_OP_SUBTRACT: return EASY_IR_BINOP(SUBTRACT);
5495         case MOJOSHADER_AST_OP_LSHIFT: return EASY_IR_BINOP(LSHIFT);
5496         case MOJOSHADER_AST_OP_RSHIFT: return EASY_IR_BINOP(RSHIFT);
5497         case MOJOSHADER_AST_OP_BINARYAND: return EASY_IR_BINOP(AND);
5498         case MOJOSHADER_AST_OP_BINARYXOR: return EASY_IR_BINOP(XOR);
5499         case MOJOSHADER_AST_OP_BINARYOR: return EASY_IR_BINOP(OR);
5500 
5501         case MOJOSHADER_AST_OP_LOGICALAND:
5502             return build_ir_logical_and(ctx, &ast->binary);
5503 
5504         case MOJOSHADER_AST_OP_LOGICALOR:
5505             return build_ir_logical_or(ctx, &ast->binary);
5506 
5507         case MOJOSHADER_AST_OP_ASSIGN:
5508             return build_ir_assign(ctx, &ast->binary);
5509 
5510         case MOJOSHADER_AST_OP_MULASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MULTIPLY, &ast->binary);
5511         case MOJOSHADER_AST_OP_DIVASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_DIVIDE, &ast->binary);
5512         case MOJOSHADER_AST_OP_MODASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_MODULO, &ast->binary);
5513         case MOJOSHADER_AST_OP_ADDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_ADD, &ast->binary);
5514         case MOJOSHADER_AST_OP_SUBASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_SUBTRACT, &ast->binary);
5515         case MOJOSHADER_AST_OP_LSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_LSHIFT, &ast->binary);
5516         case MOJOSHADER_AST_OP_RSHIFTASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_RSHIFT, &ast->binary);
5517         case MOJOSHADER_AST_OP_ANDASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_AND, &ast->binary);
5518         case MOJOSHADER_AST_OP_XORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_XOR, &ast->binary);
5519         case MOJOSHADER_AST_OP_ORASSIGN: return build_ir_assign_binop(ctx, MOJOSHADER_IR_BINOP_OR, &ast->binary);
5520 
5521         case MOJOSHADER_AST_OP_CONDITIONAL:
5522             assert(ast->binary.left->datatype->type == MOJOSHADER_AST_DATATYPE_BOOL);
5523             return build_ir_compare(ctx, MOJOSHADER_IR_COND_EQL,
5524                                   build_ir_expr(ctx, ast->ternary.left),
5525                                   new_ir_constbool(ctx, 1),
5526                                   build_ir_expr(ctx, ast->ternary.center),
5527                                   build_ir_expr(ctx, ast->ternary.right));
5528 
5529         case MOJOSHADER_AST_OP_IDENTIFIER:
5530             return build_ir_identifier(ctx, &ast->identifier);
5531 
5532         case MOJOSHADER_AST_OP_INT_LITERAL:
5533             return new_ir_constint(ctx, ast->intliteral.value);
5534 
5535         case MOJOSHADER_AST_OP_FLOAT_LITERAL:
5536             return new_ir_constfloat(ctx, ast->floatliteral.value);
5537 
5538         case MOJOSHADER_AST_OP_BOOLEAN_LITERAL:
5539             return new_ir_constbool(ctx, ast->boolliteral.value);
5540 
5541         case MOJOSHADER_AST_OP_CALLFUNC:
5542             return build_ir_call(ctx, &ast->callfunc);
5543 
5544         case MOJOSHADER_AST_OP_CONSTRUCTOR:
5545             return build_ir_constructor(ctx, &ast->constructor);
5546 
5547         case MOJOSHADER_AST_OP_CAST:
5548             return build_ir_convert(ctx, &ast->cast);
5549 
5550         case MOJOSHADER_AST_STATEMENT_BREAK:
5551         {
5552             const LoopLabels *labels = ctx->ir_loop;
5553             assert(labels != NULL);  // semantic analysis should catch this.
5554             return new_ir_jump(ctx, labels->end);
5555         } // case
5556 
5557         case MOJOSHADER_AST_STATEMENT_CONTINUE:
5558         {
5559             const LoopLabels *labels = ctx->ir_loop;
5560             assert(labels != NULL);  // semantic analysis should catch this.
5561             return new_ir_jump(ctx, labels->start);
5562         } // case
5563 
5564         case MOJOSHADER_AST_STATEMENT_DISCARD:
5565             return new_ir_seq(ctx, new_ir_discard(ctx), build_ir_stmt(ctx, ast->discardstmt.next));
5566 
5567         case MOJOSHADER_AST_STATEMENT_EMPTY:
5568             return build_ir(ctx, ast->stmt.next);  // skip it, do next thing.
5569 
5570         case MOJOSHADER_AST_STATEMENT_EXPRESSION:
5571             return new_ir_seq(ctx, new_ir_expr_stmt(ctx, build_ir_expr(ctx, ast->exprstmt.expr)), build_ir_stmt(ctx, ast->exprstmt.next));
5572 
5573         case MOJOSHADER_AST_STATEMENT_IF:
5574             return build_ir_ifstmt(ctx, &ast->ifstmt);
5575 
5576         case MOJOSHADER_AST_STATEMENT_TYPEDEF:  // ignore this, move on.
5577             return build_ir(ctx, ast->typedefstmt.next);
5578 
5579         case MOJOSHADER_AST_STATEMENT_SWITCH:
5580             return build_ir_switch(ctx, &ast->switchstmt);
5581 
5582         case MOJOSHADER_AST_STATEMENT_STRUCT:  // ignore this, move on.
5583             return build_ir(ctx, ast->structstmt.next);
5584 
5585         case MOJOSHADER_AST_STATEMENT_VARDECL: // ignore this, move on.
5586             return build_ir(ctx, ast->vardeclstmt.next);
5587 
5588         case MOJOSHADER_AST_STATEMENT_BLOCK:
5589             return new_ir_seq(ctx, build_ir_stmt(ctx, ast->blockstmt.statements), build_ir_stmt(ctx, ast->blockstmt.next));
5590 
5591         case MOJOSHADER_AST_STATEMENT_FOR:
5592             return build_ir_forstmt(ctx, &ast->forstmt);
5593 
5594         case MOJOSHADER_AST_STATEMENT_DO:
5595             return build_ir_dostmt(ctx, &ast->dostmt);
5596 
5597         case MOJOSHADER_AST_STATEMENT_WHILE:
5598             return build_ir_whilestmt(ctx, &ast->whilestmt);
5599 
5600         case MOJOSHADER_AST_STATEMENT_RETURN:
5601         {
5602             const int label = ctx->ir_end;
5603             assert(label >= 0);  // parser should have caught this!
5604             MOJOSHADER_irStatement *retval = NULL;
5605             if (ast->returnstmt.expr != NULL)
5606             {
5607                 // !!! FIXME: whole array/struct returns need to move more into the temp.
5608                 const MOJOSHADER_astDataType *dt = reduce_datatype(ctx, ast->returnstmt.expr->datatype);
5609                 const MOJOSHADER_astDataTypeType type = datatype_base(ctx, dt)->type;
5610                 const int elems = datatype_elems(ctx, dt);
5611                 assert(ctx->ir_ret >= 0);
5612                 retval = new_ir_move(ctx, new_ir_temp(ctx, ctx->ir_ret, type, elems), build_ir_expr(ctx, ast->returnstmt.expr), -1);
5613             } // if
5614             return new_ir_seq(ctx, retval, new_ir_jump(ctx, label));
5615         } // case
5616 
5617         case MOJOSHADER_AST_COMPUNIT_TYPEDEF:
5618         case MOJOSHADER_AST_COMPUNIT_STRUCT:
5619         case MOJOSHADER_AST_COMPUNIT_VARIABLE:
5620         case MOJOSHADER_AST_COMPUNIT_FUNCTION:
5621         case MOJOSHADER_AST_ARGUMENTS:
5622         case MOJOSHADER_AST_OP_STRING_LITERAL:
5623         case MOJOSHADER_AST_SWITCH_CASE:
5624         case MOJOSHADER_AST_SCALAR_OR_ARRAY:
5625         case MOJOSHADER_AST_TYPEDEF:
5626         case MOJOSHADER_AST_FUNCTION_PARAMS:
5627         case MOJOSHADER_AST_FUNCTION_SIGNATURE:
5628         case MOJOSHADER_AST_STRUCT_DECLARATION:
5629         case MOJOSHADER_AST_STRUCT_MEMBER:
5630         case MOJOSHADER_AST_VARIABLE_DECLARATION:
5631         case MOJOSHADER_AST_ANNOTATION:
5632         case MOJOSHADER_AST_PACK_OFFSET:
5633         case MOJOSHADER_AST_VARIABLE_LOWLEVEL:
5634             assert(0 && "Shouldn't hit this in build_ir.");
5635             return NULL;
5636 
5637         default:
5638             assert(0 && "unexpected type");
5639             return NULL;
5640     } // switch
5641 } // build_ir
5642 
print_ir(FILE * io,unsigned int depth,void * _ir)5643 static void print_ir(FILE *io, unsigned int depth, void *_ir)
5644 {
5645     MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
5646     if (ir == NULL)
5647         return;
5648 
5649     const char *fname = strrchr(ir->ir.filename, '/');
5650     if (fname != NULL)
5651         fname++;
5652     else
5653     {
5654         fname = strrchr(ir->ir.filename, '\\');
5655         if (fname != NULL)
5656             fname++;
5657         else
5658             fname = ir->ir.filename;
5659     } // else
5660 
5661     int i;
5662     for (i = 0; i < depth; i++)
5663         fprintf(io, "  ");
5664     depth++;
5665 
5666     fprintf(io, "[ %s:%d ", fname, ir->ir.line);
5667 
5668     switch (ir->ir.type)
5669     {
5670         case MOJOSHADER_IR_LABEL:
5671             fprintf(io, "LABEL %d ]\n", ir->stmt.label.index);
5672             break;
5673 
5674         case MOJOSHADER_IR_CONSTANT:
5675             fprintf(io, "CONSTANT ");
5676             switch (ir->expr.constant.info.type)
5677             {
5678                 case MOJOSHADER_AST_DATATYPE_BOOL:
5679                 case MOJOSHADER_AST_DATATYPE_INT:
5680                 case MOJOSHADER_AST_DATATYPE_UINT:
5681                     for (i = 0; i < ir->expr.constant.info.elements-1; i++)
5682                         fprintf(io, "%d, ", ir->expr.constant.value.ival[i]);
5683                     if (ir->expr.constant.info.elements > 0)
5684                         fprintf(io, "%d", ir->expr.constant.value.ival[i]);
5685                     break;
5686 
5687                 case MOJOSHADER_AST_DATATYPE_FLOAT:
5688                 case MOJOSHADER_AST_DATATYPE_FLOAT_SNORM:
5689                 case MOJOSHADER_AST_DATATYPE_FLOAT_UNORM:
5690                 case MOJOSHADER_AST_DATATYPE_HALF:
5691                 case MOJOSHADER_AST_DATATYPE_DOUBLE:
5692                     for (i = 0; i < ir->expr.constant.info.elements-1; i++)
5693                         fprintf(io, "%ff, ", ir->expr.constant.value.fval[i]);
5694                     if (ir->expr.constant.info.elements > 0)
5695                         fprintf(io, "%ff", ir->expr.constant.value.fval[i]);
5696                     break;
5697 
5698                 default: assert(0 && "shouldn't happen");
5699             } // switch
5700             fprintf(io, " ]\n");
5701             break;
5702 
5703         case MOJOSHADER_IR_TEMP:
5704             fprintf(io, "TEMP %d ]\n", ir->expr.temp.index);
5705             break;
5706 
5707         case MOJOSHADER_IR_DISCARD:
5708             fprintf(io, "DISCARD ]\n");
5709             break;
5710 
5711         case MOJOSHADER_IR_SWIZZLE:
5712             fprintf(io, "SWIZZLE");
5713             for (i = 0; i < ir->expr.swizzle.info.elements-1; i++)
5714                 fprintf(io, " %d", (int) ir->expr.swizzle.channels[i]);
5715             fprintf(io, " ]\n");
5716             print_ir(io, depth, ir->expr.swizzle.expr);
5717             break;
5718 
5719         case MOJOSHADER_IR_CONSTRUCT:
5720             fprintf(io, "CONSTRUCT ]\n");
5721             print_ir(io, depth, ir->expr.construct.args);
5722             break;
5723 
5724         case MOJOSHADER_IR_CONVERT:
5725             fprintf(io, "CONVERT ]\n");
5726             print_ir(io, depth, ir->expr.convert.expr);
5727             break;
5728 
5729         case MOJOSHADER_IR_BINOP:
5730             fprintf(io, "BINOP ");
5731             switch (ir->expr.binop.op)
5732             {
5733                 #define PRINT_IR_BINOP(x) \
5734                     case MOJOSHADER_IR_BINOP_##x: fprintf(io, #x); break;
5735                 PRINT_IR_BINOP(ADD)
5736                 PRINT_IR_BINOP(SUBTRACT)
5737                 PRINT_IR_BINOP(MULTIPLY)
5738                 PRINT_IR_BINOP(DIVIDE)
5739                 PRINT_IR_BINOP(MODULO)
5740                 PRINT_IR_BINOP(AND)
5741                 PRINT_IR_BINOP(OR)
5742                 PRINT_IR_BINOP(XOR)
5743                 PRINT_IR_BINOP(LSHIFT)
5744                 PRINT_IR_BINOP(RSHIFT)
5745                 PRINT_IR_BINOP(UNKNOWN)
5746                 #undef PRINT_IR_BINOP
5747                 default: assert(0 && "unexpected case"); break;
5748             } // switch
5749             fprintf(io, " ]\n");
5750             print_ir(io, depth, ir->expr.binop.left);
5751             print_ir(io, depth, ir->expr.binop.right);
5752             break;
5753 
5754         case MOJOSHADER_IR_MEMORY:
5755             fprintf(io, "MEMORY %d ]\n", ir->expr.memory.index);
5756             break;
5757 
5758         case MOJOSHADER_IR_CALL:
5759             fprintf(io, "CALL %d ]\n", ir->expr.call.index);
5760             print_ir(io, depth, ir->expr.call.args);
5761             break;
5762 
5763         case MOJOSHADER_IR_ESEQ:
5764             fprintf(io, "ESEQ ]\n");
5765             print_ir(io, depth, ir->expr.eseq.stmt);
5766             break;
5767 
5768         case MOJOSHADER_IR_ARRAY:
5769             fprintf(io, "ARRAY ]\n");
5770             print_ir(io, depth, ir->expr.array.array);
5771             print_ir(io, depth, ir->expr.array.element);
5772             break;
5773 
5774         case MOJOSHADER_IR_MOVE:
5775             fprintf(io, "MOVE ]\n");
5776             print_ir(io, depth, ir->stmt.move.dst);
5777             print_ir(io, depth, ir->stmt.move.src);
5778             break;
5779 
5780         case MOJOSHADER_IR_EXPR_STMT:
5781             fprintf(io, "EXPRSTMT ]\n");
5782             print_ir(io, depth, ir->stmt.expr.expr);
5783             break;
5784 
5785         case MOJOSHADER_IR_JUMP:
5786             fprintf(io, "JUMP %d ]\n", ir->stmt.jump.label);
5787             break;
5788 
5789         case MOJOSHADER_IR_CJUMP:
5790             fprintf(io, "CJUMP ");
5791             switch (ir->stmt.cjump.cond)
5792             {
5793                 #define PRINT_IR_COND(x) \
5794                     case MOJOSHADER_IR_COND_##x: fprintf(io, #x); break;
5795                 PRINT_IR_COND(EQL)
5796                 PRINT_IR_COND(NEQ)
5797                 PRINT_IR_COND(LT)
5798                 PRINT_IR_COND(GT)
5799                 PRINT_IR_COND(LEQ)
5800                 PRINT_IR_COND(GEQ)
5801                 PRINT_IR_COND(UNKNOWN)
5802                 #undef PRINT_IR_COND
5803                 default: assert(0 && "unexpected case"); break;
5804             } // switch
5805             fprintf(io, " %d %d ]\n", ir->stmt.cjump.iftrue, ir->stmt.cjump.iffalse);
5806             print_ir(io, depth, ir->stmt.cjump.left);
5807             print_ir(io, depth, ir->stmt.cjump.right);
5808             break;
5809 
5810         case MOJOSHADER_IR_SEQ:
5811             fprintf(io, "SEQ ]\n");
5812             print_ir(io, depth, ir->stmt.seq.first);
5813             print_ir(io, depth, ir->stmt.seq.next);  // !!! FIXME: don't recurse?
5814             break;
5815 
5816         case MOJOSHADER_IR_EXPRLIST:
5817             fprintf(io, "EXPRLIST ]\n");
5818             print_ir(io, depth, ir->misc.exprlist.expr);
5819             print_ir(io, depth, ir->misc.exprlist.next);  // !!! FIXME: don't recurse?
5820             break;
5821 
5822         default: assert(0 && "unexpected IR node"); break;
5823     } // switch
5824 } // print_ir
5825 
print_whole_ir(Context * ctx,FILE * io)5826 static void print_whole_ir(Context *ctx, FILE *io)
5827 {
5828     if (ctx->ir != NULL)
5829     {
5830         int i;
5831         for (i = 0; i <= ctx->user_func_index; i++)
5832         {
5833             printf("[FUNCTION %d ]\n", i);
5834             print_ir(io, 1, ctx->ir[i]);
5835         } // for
5836     } // if
5837 } // print_whole_ir
5838 
delete_ir(Context * ctx,void * _ir)5839 static void delete_ir(Context *ctx, void *_ir)
5840 {
5841     MOJOSHADER_irNode *ir = (MOJOSHADER_irNode *) _ir;
5842     if (ir == NULL)
5843         return;
5844 
5845     switch (ir->ir.type)
5846     {
5847         case MOJOSHADER_IR_JUMP:
5848         case MOJOSHADER_IR_LABEL:
5849         case MOJOSHADER_IR_CONSTANT:
5850         case MOJOSHADER_IR_TEMP:
5851         case MOJOSHADER_IR_DISCARD:
5852         case MOJOSHADER_IR_MEMORY:
5853             break;  // nothing extra to free here.
5854 
5855         case MOJOSHADER_IR_BINOP:
5856             delete_ir(ctx, ir->expr.binop.left);
5857             delete_ir(ctx, ir->expr.binop.right);
5858             break;
5859 
5860         case MOJOSHADER_IR_CALL:
5861             delete_ir(ctx, ir->expr.call.args);
5862             break;
5863 
5864         case MOJOSHADER_IR_ESEQ:
5865             delete_ir(ctx, ir->expr.eseq.stmt);
5866             delete_ir(ctx, ir->expr.eseq.expr);
5867             break;
5868 
5869         case MOJOSHADER_IR_ARRAY:
5870             delete_ir(ctx, ir->expr.array.array);
5871             delete_ir(ctx, ir->expr.array.element);
5872             break;
5873 
5874         case MOJOSHADER_IR_MOVE:
5875             delete_ir(ctx, ir->stmt.move.dst);
5876             delete_ir(ctx, ir->stmt.move.src);
5877             break;
5878 
5879         case MOJOSHADER_IR_EXPR_STMT:
5880             delete_ir(ctx, ir->stmt.expr.expr);
5881             break;
5882 
5883         case MOJOSHADER_IR_CJUMP:
5884             delete_ir(ctx, ir->stmt.cjump.left);
5885             delete_ir(ctx, ir->stmt.cjump.right);
5886             break;
5887 
5888         case MOJOSHADER_IR_SEQ:
5889             delete_ir(ctx, ir->stmt.seq.first);
5890             delete_ir(ctx, ir->stmt.seq.next);  // !!! FIXME: don't recurse?
5891             break;
5892 
5893         case MOJOSHADER_IR_EXPRLIST:
5894             delete_ir(ctx, ir->misc.exprlist.expr);
5895             delete_ir(ctx, ir->misc.exprlist.next);  // !!! FIXME: don't recurse?
5896             break;
5897 
5898         case MOJOSHADER_IR_SWIZZLE:
5899             delete_ir(ctx, ir->expr.swizzle.expr);
5900             break;
5901 
5902         case MOJOSHADER_IR_CONSTRUCT:
5903             delete_ir(ctx, ir->expr.construct.args);
5904             break;
5905 
5906         case MOJOSHADER_IR_CONVERT:
5907             delete_ir(ctx, ir->expr.convert.expr);
5908             break;
5909 
5910         default: assert(0 && "unexpected IR node"); break;
5911     } // switch
5912 
5913     Free(ctx, ir);
5914 } // delete_ir
5915 
intermediate_representation(Context * ctx)5916 static void intermediate_representation(Context *ctx)
5917 {
5918     const MOJOSHADER_astCompilationUnit *ast = NULL;
5919     const MOJOSHADER_astCompilationUnitFunction *astfn = NULL;
5920     const size_t arraylen = (ctx->user_func_index+1) * sizeof (MOJOSHADER_irStatement *);
5921 
5922     ctx->ir = (MOJOSHADER_irStatement **)Malloc(ctx, arraylen);
5923     if (ctx->ir == NULL)
5924         return;
5925     memset(ctx->ir, '\0', arraylen);
5926 
5927     ctx->ir_end = -1;
5928     ctx->ir_ret = -1;
5929 
5930     for (ast = &ctx->ast->compunit; ast != NULL; ast = ast->next)
5931     {
5932         assert(ast->ast.type > MOJOSHADER_AST_COMPUNIT_START_RANGE);
5933         assert(ast->ast.type < MOJOSHADER_AST_COMPUNIT_END_RANGE);
5934         if (ast->ast.type != MOJOSHADER_AST_COMPUNIT_FUNCTION)
5935             continue;  // only care about functions right now.
5936 
5937         astfn = (MOJOSHADER_astCompilationUnitFunction *) ast;
5938         if (astfn->definition == NULL)  // just a predeclare; skip.
5939             continue;
5940 
5941         assert(ctx->ir_loop == NULL);  // parser should have caught this!
5942         assert(ctx->ir_end < 0);  // parser should have caught this!
5943         assert(ctx->ir_ret < 0);  // parser should have caught this!
5944         const int start = generate_ir_label(ctx);  // !!! FIXME: store somewhere.
5945         const int end = generate_ir_label(ctx);
5946         ctx->ir_end = end;
5947 
5948         if (astfn->declaration->datatype != NULL)
5949             ctx->ir_ret = generate_ir_temp(ctx);
5950 
5951         MOJOSHADER_irStatement *funcseq = new_ir_seq(ctx, new_ir_label(ctx, start), build_ir_stmt(ctx, astfn->definition));
5952         funcseq = new_ir_seq(ctx, funcseq, new_ir_label(ctx, end));
5953         assert(ctx->ir_loop == NULL);  // parser should have caught this!
5954         ctx->ir_end = -1;
5955         ctx->ir_ret = -1;
5956 
5957         assert(astfn->index <= ctx->user_func_index);
5958         assert(ctx->ir[astfn->index] == NULL);
5959         ctx->ir[astfn->index] = funcseq;
5960     } // for
5961 
5962     print_whole_ir(ctx, stdout);
5963 
5964     // done with the AST, nuke it.
5965     // !!! FIXME: we're going to need CTAB data from this at some point.
5966     delete_compilation_unit(ctx, (MOJOSHADER_astCompilationUnit *) ctx->ast);
5967     ctx->ast = NULL;
5968 } // intermediate_representation
5969 
5970 
5971 
5972 static MOJOSHADER_astData MOJOSHADER_out_of_mem_ast_data = {
5973     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0
5974 };
5975 
5976 
5977 // !!! FIXME: cut and paste from assembler.
build_failed_ast(Context * ctx)5978 static const MOJOSHADER_astData *build_failed_ast(Context *ctx)
5979 {
5980     assert(isfail(ctx));
5981 
5982     if (ctx->out_of_memory)
5983         return &MOJOSHADER_out_of_mem_ast_data;
5984 
5985     MOJOSHADER_astData *retval = NULL;
5986     retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
5987     if (retval == NULL)
5988         return &MOJOSHADER_out_of_mem_ast_data;
5989 
5990     memset(retval, '\0', sizeof (MOJOSHADER_astData));
5991     retval->source_profile = ctx->source_profile;
5992     retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
5993     retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
5994     retval->malloc_data = ctx->malloc_data;
5995     retval->error_count = errorlist_count(ctx->errors);
5996     retval->errors = errorlist_flatten(ctx->errors);
5997 
5998     if (ctx->out_of_memory)
5999     {
6000         Free(ctx, retval);
6001         return &MOJOSHADER_out_of_mem_ast_data;
6002     } // if
6003 
6004     return retval;
6005 } // build_failed_ast
6006 
6007 
build_astdata(Context * ctx)6008 static const MOJOSHADER_astData *build_astdata(Context *ctx)
6009 {
6010     MOJOSHADER_astData *retval = NULL;
6011 
6012     if (ctx->out_of_memory)
6013         return &MOJOSHADER_out_of_mem_ast_data;
6014 
6015     retval = (MOJOSHADER_astData *) Malloc(ctx, sizeof (MOJOSHADER_astData));
6016     if (retval == NULL)
6017         return &MOJOSHADER_out_of_mem_ast_data;
6018 
6019     memset(retval, '\0', sizeof (MOJOSHADER_astData));
6020     retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6021     retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6022     retval->malloc_data = ctx->malloc_data;
6023 
6024     if (!isfail(ctx))
6025     {
6026         retval->source_profile = ctx->source_profile;
6027         retval->ast = ctx->ast;
6028     } // if
6029 
6030     retval->error_count = errorlist_count(ctx->errors);
6031     retval->errors = errorlist_flatten(ctx->errors);
6032     if (ctx->out_of_memory)
6033     {
6034         Free(ctx, retval);
6035         return &MOJOSHADER_out_of_mem_ast_data;
6036     } // if
6037 
6038     retval->opaque = ctx;
6039 
6040     return retval;
6041 } // build_astdata
6042 
6043 
choose_src_profile(Context * ctx,const char * srcprofile)6044 static void choose_src_profile(Context *ctx, const char *srcprofile)
6045 {
6046     ctx->source_profile = srcprofile;
6047 
6048     #define TEST_PROFILE(x) if (strcmp(srcprofile, x) == 0) { return; }
6049 
6050     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_1_1);
6051     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_2_0);
6052     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_VS_3_0);
6053     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_1);
6054     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_2);
6055     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_3);
6056     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_1_4);
6057     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_2_0);
6058     TEST_PROFILE(MOJOSHADER_SRC_PROFILE_HLSL_PS_3_0);
6059 
6060     #undef TEST_PROFILE
6061 
6062     fail(ctx, "Unknown profile");
6063 } // choose_src_profile
6064 
6065 
6066 static MOJOSHADER_compileData MOJOSHADER_out_of_mem_compile_data = {
6067     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
6068 };
6069 
6070 
6071 // !!! FIXME: cut and paste from assembler.
build_failed_compile(Context * ctx)6072 static const MOJOSHADER_compileData *build_failed_compile(Context *ctx)
6073 {
6074     assert(isfail(ctx));
6075 
6076     MOJOSHADER_compileData *retval = NULL;
6077     retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
6078     if (retval == NULL)
6079         return &MOJOSHADER_out_of_mem_compile_data;
6080 
6081     memset(retval, '\0', sizeof (MOJOSHADER_compileData));
6082     retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6083     retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6084     retval->malloc_data = ctx->malloc_data;
6085     retval->source_profile = ctx->source_profile;
6086     retval->error_count = errorlist_count(ctx->errors);
6087     retval->errors = errorlist_flatten(ctx->errors);
6088     retval->warning_count = errorlist_count(ctx->warnings);
6089     retval->warnings = errorlist_flatten(ctx->warnings);
6090 
6091     if (ctx->out_of_memory)  // in case something failed up there.
6092     {
6093         MOJOSHADER_freeCompileData(retval);
6094         return &MOJOSHADER_out_of_mem_compile_data;
6095     } // if
6096 
6097     return retval;
6098 } // build_failed_compile
6099 
6100 
build_compiledata(Context * ctx)6101 static const MOJOSHADER_compileData *build_compiledata(Context *ctx)
6102 {
6103     assert(!isfail(ctx));
6104 
6105     MOJOSHADER_compileData *retval = NULL;
6106 
6107     retval = (MOJOSHADER_compileData *) Malloc(ctx, sizeof (MOJOSHADER_compileData));
6108     if (retval == NULL)
6109         return &MOJOSHADER_out_of_mem_compile_data;
6110 
6111     memset(retval, '\0', sizeof (MOJOSHADER_compileData));
6112     retval->malloc = (ctx->malloc == MOJOSHADER_internal_malloc) ? NULL : ctx->malloc;
6113     retval->free = (ctx->free == MOJOSHADER_internal_free) ? NULL : ctx->free;
6114     retval->malloc_data = ctx->malloc_data;
6115     retval->source_profile = ctx->source_profile;
6116 
6117     if (!isfail(ctx))
6118     {
6119         // !!! FIXME: build output and output_len here.
6120     } // if
6121 
6122     if (!isfail(ctx))
6123     {
6124         // !!! FIXME: build symbols and symbol_count here.
6125     } // if
6126 
6127     retval->error_count = errorlist_count(ctx->errors);
6128     retval->errors = errorlist_flatten(ctx->errors);
6129     retval->warning_count = errorlist_count(ctx->warnings);
6130     retval->warnings = errorlist_flatten(ctx->warnings);
6131 
6132     if (ctx->out_of_memory)  // in case something failed up there.
6133     {
6134         MOJOSHADER_freeCompileData(retval);
6135         return &MOJOSHADER_out_of_mem_compile_data;
6136     } // if
6137 
6138     return retval;
6139 } // build_compiledata
6140 
6141 
6142 // API entry point...
6143 
6144 // !!! FIXME: move this (and a lot of other things) to mojoshader_ast.c.
MOJOSHADER_parseAst(const char * srcprofile,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defs,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close,MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)6145 const MOJOSHADER_astData *MOJOSHADER_parseAst(const char *srcprofile,
6146                                     const char *filename, const char *source,
6147                                     unsigned int sourcelen,
6148                                     const MOJOSHADER_preprocessorDefine *defs,
6149                                     unsigned int define_count,
6150                                     MOJOSHADER_includeOpen include_open,
6151                                     MOJOSHADER_includeClose include_close,
6152                                     MOJOSHADER_malloc m, MOJOSHADER_free f,
6153                                     void *d)
6154 {
6155     const MOJOSHADER_astData *retval = NULL;
6156     Context *ctx = NULL;
6157 
6158     if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
6159         return &MOJOSHADER_out_of_mem_ast_data;  // supply both or neither.
6160 
6161     ctx = build_context(m, f, d);
6162     if (ctx == NULL)
6163         return &MOJOSHADER_out_of_mem_ast_data;
6164 
6165     choose_src_profile(ctx, srcprofile);
6166 
6167     if (!isfail(ctx))
6168     {
6169         parse_source(ctx, filename, source, sourcelen, defs, define_count,
6170                      include_open, include_close);
6171     } // if
6172 
6173     if (!isfail(ctx))
6174         retval = build_astdata(ctx);  // ctx isn't destroyed yet!
6175     else
6176     {
6177         retval = (MOJOSHADER_astData *) build_failed_ast(ctx);
6178         destroy_context(ctx);
6179     } // else
6180 
6181     return retval;
6182 } // MOJOSHADER_parseAst
6183 
6184 
MOJOSHADER_freeAstData(const MOJOSHADER_astData * _data)6185 void MOJOSHADER_freeAstData(const MOJOSHADER_astData *_data)
6186 {
6187     MOJOSHADER_astData *data = (MOJOSHADER_astData *) _data;
6188     if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_ast_data))
6189         return;  // no-op.
6190 
6191     // !!! FIXME: this needs to live for deleting the stringcache and the ast.
6192     Context *ctx = (Context *) data->opaque;
6193     MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
6194     void *d = data->malloc_data;
6195     int i;
6196 
6197     // we don't f(data->source_profile), because that's internal static data.
6198 
6199     for (i = 0; i < data->error_count; i++)
6200     {
6201         f((void *) data->errors[i].error, d);
6202         f((void *) data->errors[i].filename, d);
6203     } // for
6204     f((void *) data->errors, d);
6205 
6206     // don't delete data->ast (it'll delete with the context).
6207     f(data, d);
6208 
6209     destroy_context(ctx);  // finally safe to destroy this.
6210 } // MOJOSHADER_freeAstData
6211 
6212 
MOJOSHADER_compile(const char * srcprofile,const char * filename,const char * source,unsigned int sourcelen,const MOJOSHADER_preprocessorDefine * defs,unsigned int define_count,MOJOSHADER_includeOpen include_open,MOJOSHADER_includeClose include_close,MOJOSHADER_malloc m,MOJOSHADER_free f,void * d)6213 const MOJOSHADER_compileData *MOJOSHADER_compile(const char *srcprofile,
6214                                     const char *filename, const char *source,
6215                                     unsigned int sourcelen,
6216                                     const MOJOSHADER_preprocessorDefine *defs,
6217                                     unsigned int define_count,
6218                                     MOJOSHADER_includeOpen include_open,
6219                                     MOJOSHADER_includeClose include_close,
6220                                     MOJOSHADER_malloc m, MOJOSHADER_free f,
6221                                     void *d)
6222 {
6223     // !!! FIXME: cut and paste from MOJOSHADER_parseAst().
6224     MOJOSHADER_compileData *retval = NULL;
6225     Context *ctx = NULL;
6226 
6227     if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
6228         return &MOJOSHADER_out_of_mem_compile_data;  // supply both or neither.
6229 
6230     ctx = build_context(m, f, d);
6231     if (ctx == NULL)
6232         return &MOJOSHADER_out_of_mem_compile_data;
6233 
6234     choose_src_profile(ctx, srcprofile);
6235 
6236     if (!isfail(ctx))
6237     {
6238         parse_source(ctx, filename, source, sourcelen, defs, define_count,
6239                      include_open, include_close);
6240     } // if
6241 
6242     if (!isfail(ctx))
6243         semantic_analysis(ctx);
6244 
6245     if (!isfail(ctx))
6246         intermediate_representation(ctx);
6247 
6248     if (isfail(ctx))
6249         retval = (MOJOSHADER_compileData *) build_failed_compile(ctx);
6250     else
6251         retval = (MOJOSHADER_compileData *) build_compiledata(ctx);
6252 
6253     destroy_context(ctx);
6254     return retval;
6255 } // MOJOSHADER_compile
6256 
6257 
MOJOSHADER_freeCompileData(const MOJOSHADER_compileData * _data)6258 void MOJOSHADER_freeCompileData(const MOJOSHADER_compileData *_data)
6259 {
6260     MOJOSHADER_compileData *data = (MOJOSHADER_compileData *) _data;
6261     if ((data == NULL) || (data == &MOJOSHADER_out_of_mem_compile_data))
6262         return;  // no-op.
6263 
6264     MOJOSHADER_free f = (data->free == NULL) ? MOJOSHADER_internal_free : data->free;
6265     void *d = data->malloc_data;
6266     int i;
6267 
6268     // we don't f(data->source_profile), because that's internal static data.
6269 
6270     for (i = 0; i < data->error_count; i++)
6271     {
6272         f((void *) data->errors[i].error, d);
6273         f((void *) data->errors[i].filename, d);
6274     } // for
6275     f((void *) data->errors, d);
6276 
6277     for (i = 0; i < data->warning_count; i++)
6278     {
6279         f((void *) data->warnings[i].error, d);
6280         f((void *) data->warnings[i].filename, d);
6281     } // for
6282     f((void *) data->warnings, d);
6283 
6284     for (i = 0; i < data->symbol_count; i++)
6285     {
6286         f((void *) data->symbols[i].name, d);
6287         // !!! FIXME: this is missing stuff (including freeing substructs).
6288     } // for
6289     f((void *) data->symbols, d);
6290 
6291     f((void *) data->output, d);
6292     f(data, d);
6293 } // MOJOSHADER_freeCompileData
6294 
6295 // end of mojoshader_compiler.c ...
6296 
6297