1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "BsASTFX.h" |
4 | #include "BsMMAlloc.h" |
5 | #include <assert.h> |
6 | |
7 | OptionInfo OPTION_LOOKUP[] = |
8 | { |
9 | { OT_None, ODT_Int }, |
10 | { OT_Options, ODT_Complex }, |
11 | { OT_Separable, ODT_Bool }, |
12 | { OT_Priority, ODT_Int }, |
13 | { OT_Sort, ODT_Int }, |
14 | { OT_Transparent, ODT_Bool }, |
15 | { OT_Shader, ODT_Complex }, |
16 | { OT_SubShader, ODT_Complex }, |
17 | { OT_Mixin, ODT_String }, |
18 | { OT_Raster, ODT_Complex }, |
19 | { OT_Depth, ODT_Complex }, |
20 | { OT_Stencil, ODT_Complex }, |
21 | { OT_Blend, ODT_Complex }, |
22 | { OT_FeatureSet, ODT_String }, |
23 | { OT_Pass, ODT_Complex }, |
24 | { OT_FillMode, ODT_Int }, |
25 | { OT_CullMode, ODT_Int }, |
26 | { OT_DepthBias, ODT_Float }, |
27 | { OT_SDepthBias, ODT_Float }, |
28 | { OT_DepthClip, ODT_Bool }, |
29 | { OT_Scissor, ODT_Bool }, |
30 | { OT_Multisample, ODT_Bool }, |
31 | { OT_AALine, ODT_Bool }, |
32 | { OT_DepthRead, ODT_Bool }, |
33 | { OT_DepthWrite, ODT_Bool }, |
34 | { OT_CompareFunc, ODT_Int }, |
35 | { OT_StencilReadMask, ODT_Int }, |
36 | { OT_StencilWriteMask, ODT_Int }, |
37 | { OT_StencilOpFront, ODT_Complex }, |
38 | { OT_StencilOpBack, ODT_Complex }, |
39 | { OT_PassOp, ODT_Int }, |
40 | { OT_Fail, ODT_Int }, |
41 | { OT_ZFail, ODT_Int }, |
42 | { OT_AlphaToCoverage, ODT_Bool }, |
43 | { OT_IndependantBlend, ODT_Bool }, |
44 | { OT_Target, ODT_Complex }, |
45 | { OT_Index, ODT_Int }, |
46 | { OT_Enabled, ODT_Bool }, |
47 | { OT_Color, ODT_Complex }, |
48 | { OT_Alpha, ODT_Complex }, |
49 | { OT_WriteMask, ODT_Int }, |
50 | { OT_Source, ODT_Int }, |
51 | { OT_Dest, ODT_Int }, |
52 | { OT_Op, ODT_Int }, |
53 | { OT_Identifier, ODT_String }, |
54 | { OT_Code, ODT_Complex }, |
55 | { OT_StencilRef, ODT_Int }, |
56 | { OT_Tags, ODT_Complex }, |
57 | { OT_TagValue, ODT_String }, |
58 | { OT_Variations, ODT_Complex }, |
59 | { OT_Variation, ODT_Complex }, |
60 | { OT_VariationValue, ODT_Int }, |
61 | { OT_Forward, ODT_Bool }, |
62 | { OT_Attributes, ODT_Complex }, |
63 | { OT_AttrName, ODT_String }, |
64 | { OT_VariationOption, ODT_Complex }, |
65 | { OT_AttrShow, ODT_Int }, |
66 | }; |
67 | |
68 | NodeOptions* nodeOptionsCreate(void* context) |
69 | { |
70 | static const int BUFFER_SIZE = 5; |
71 | |
72 | NodeOptions* options = (NodeOptions*)mmalloc(context, sizeof(NodeOptions)); |
73 | options->count = 0; |
74 | options->bufferSize = BUFFER_SIZE; |
75 | |
76 | options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize); |
77 | memset(options->entries, 0, sizeof(NodeOption) * options->bufferSize); |
78 | |
79 | return options; |
80 | } |
81 | |
82 | void nodeOptionDelete(NodeOption* option) |
83 | { |
84 | if (OPTION_LOOKUP[(int)option->type].dataType == ODT_Complex) |
85 | { |
86 | nodeDelete(option->value.nodePtr); |
87 | option->value.nodePtr = 0; |
88 | } |
89 | else if (OPTION_LOOKUP[(int)option->type].dataType == ODT_String) |
90 | { |
91 | mmfree((void*)option->value.strValue); |
92 | option->value.strValue = 0; |
93 | } |
94 | } |
95 | |
96 | void nodeOptionsDelete(NodeOptions* options) |
97 | { |
98 | int i = 0; |
99 | |
100 | for (i = 0; i < options->count; i++) |
101 | nodeOptionDelete(&options->entries[i]); |
102 | |
103 | mmfree(options->entries); |
104 | mmfree(options); |
105 | } |
106 | |
107 | void nodeOptionsResize(void* context, NodeOptions* options, int size) |
108 | { |
109 | NodeOption* originalEntries = options->entries; |
110 | int originalSize = options->bufferSize; |
111 | int elementsToCopy = originalSize; |
112 | int sizeToCopy = 0; |
113 | |
114 | options->bufferSize = size; |
115 | if (options->count > options->bufferSize) |
116 | options->count = options->bufferSize; |
117 | |
118 | if (elementsToCopy > size) |
119 | elementsToCopy = size; |
120 | |
121 | sizeToCopy = elementsToCopy * sizeof(NodeOption); |
122 | |
123 | options->entries = (NodeOption*)mmalloc(context, sizeof(NodeOption) * options->bufferSize); |
124 | |
125 | memcpy(options->entries, originalEntries, sizeToCopy); |
126 | memset(options->entries + elementsToCopy, 0, sizeof(NodeOption) * options->bufferSize - sizeToCopy); |
127 | |
128 | mmfree(originalEntries); |
129 | } |
130 | |
131 | void nodeOptionsGrowIfNeeded(void* context, NodeOptions* options) |
132 | { |
133 | static const int BUFFER_GROW = 10; |
134 | |
135 | if (options->count == options->bufferSize) |
136 | nodeOptionsResize(context, options, options->bufferSize + BUFFER_GROW); |
137 | } |
138 | |
139 | void nodeOptionsAdd(void* context, NodeOptions* options, const NodeOption* option) |
140 | { |
141 | nodeOptionsGrowIfNeeded(context, options); |
142 | |
143 | options->entries[options->count] = *option; |
144 | options->count++; |
145 | } |
146 | |
147 | ASTFXNode* nodeCreate(void* context, NodeType type) |
148 | { |
149 | ASTFXNode* node = (ASTFXNode*)mmalloc(context, sizeof(ASTFXNode)); |
150 | node->options = nodeOptionsCreate(context); |
151 | node->type = type; |
152 | |
153 | return node; |
154 | } |
155 | |
156 | void nodeDelete(ASTFXNode* node) |
157 | { |
158 | nodeOptionsDelete(node->options); |
159 | |
160 | mmfree(node); |
161 | } |
162 | |
163 | void nodePush(ParseState* parseState, ASTFXNode* node) |
164 | { |
165 | NodeLink* linkNode = (NodeLink*)mmalloc(parseState->memContext, sizeof(NodeLink)); |
166 | linkNode->next = parseState->nodeStack; |
167 | linkNode->node = node; |
168 | |
169 | parseState->nodeStack = linkNode; |
170 | parseState->topNode = node; |
171 | } |
172 | |
173 | void nodePop(ParseState* parseState) |
174 | { |
175 | if (!parseState->nodeStack) |
176 | return; |
177 | |
178 | NodeLink* toRemove = parseState->nodeStack; |
179 | parseState->nodeStack = toRemove->next; |
180 | |
181 | if (parseState->nodeStack) |
182 | parseState->topNode = parseState->nodeStack->node; |
183 | else |
184 | parseState->topNode = 0; |
185 | |
186 | mmfree(toRemove); |
187 | } |
188 | |
189 | void beginCodeBlock(ParseState* parseState, RawCodeType type) |
190 | { |
191 | RawCode* rawCodeBlock = (RawCode*)mmalloc(parseState->memContext, sizeof(RawCode)); |
192 | rawCodeBlock->index = parseState->numRawCodeBlocks[type]; |
193 | rawCodeBlock->size = 0; |
194 | rawCodeBlock->capacity = 4096; |
195 | rawCodeBlock->code = mmalloc(parseState->memContext, rawCodeBlock->capacity); |
196 | rawCodeBlock->next = parseState->rawCodeBlock[type]; |
197 | |
198 | parseState->numRawCodeBlocks[type]++; |
199 | parseState->rawCodeBlock[type] = rawCodeBlock; |
200 | |
201 | // Insert defines for code-blocks as we don't perform pre-processing within code blocks but we still want outer defines |
202 | // to be recognized by them (Performing pre-processing for code blocks is problematic because it would require parsing |
203 | // of all the language syntax in order to properly handle macro replacement). |
204 | for (int i = 0; i < parseState->numDefines; i++) |
205 | { |
206 | const char* define = "#define " ; |
207 | |
208 | appendCodeBlock(parseState, type, define, (int)strlen(define)); |
209 | appendCodeBlock(parseState, type, parseState->defines[i].name, (int)strlen(parseState->defines[i].name)); |
210 | |
211 | if (parseState->defines[i].expr != 0) |
212 | { |
213 | appendCodeBlock(parseState, type, " " , 1); |
214 | appendCodeBlock(parseState, type, parseState->defines[i].expr, (int)strlen(parseState->defines[i].expr)); |
215 | } |
216 | |
217 | appendCodeBlock(parseState, type, "\n" , 1); |
218 | } |
219 | } |
220 | |
221 | void appendCodeBlock(ParseState* parseState, RawCodeType type, const char* value, int size) |
222 | { |
223 | RawCode* rawCode = parseState->rawCodeBlock[type]; |
224 | |
225 | if ((rawCode->size + size) > rawCode->capacity) |
226 | { |
227 | int newCapacity = rawCode->capacity; |
228 | do |
229 | { |
230 | newCapacity *= 2; |
231 | } while ((rawCode->size + size) > newCapacity); |
232 | |
233 | char* newBuffer = mmalloc(parseState->memContext, newCapacity); |
234 | memcpy(newBuffer, rawCode->code, rawCode->size); |
235 | mmfree(rawCode->code); |
236 | |
237 | rawCode->code = newBuffer; |
238 | rawCode->capacity = newCapacity; |
239 | } |
240 | |
241 | memcpy(&rawCode->code[rawCode->size], value, size); |
242 | rawCode->size += size; |
243 | } |
244 | |
245 | int getCodeBlockIndex(ParseState* parseState, RawCodeType type) |
246 | { |
247 | return parseState->rawCodeBlock[type]->index; |
248 | } |
249 | |
250 | char* getCurrentFilename(ParseState* parseState) |
251 | { |
252 | if (!parseState->includeStack) |
253 | return NULL; |
254 | |
255 | return parseState->includeStack->data->filename; |
256 | } |
257 | |
258 | void addDefine(ParseState* parseState, const char* value) |
259 | { |
260 | int defineIdx = parseState->numDefines; |
261 | parseState->numDefines++; |
262 | |
263 | if(parseState->numDefines > parseState->defineCapacity) |
264 | { |
265 | int newCapacity = parseState->defineCapacity * 2; |
266 | DefineEntry* newDefines = mmalloc(parseState->memContext, newCapacity * sizeof(DefineEntry)); |
267 | |
268 | memcpy(newDefines, parseState->defines, parseState->defineCapacity * sizeof(DefineEntry)); |
269 | |
270 | mmfree(parseState->defines); |
271 | parseState->defines = newDefines; |
272 | parseState->defineCapacity = newCapacity; |
273 | } |
274 | |
275 | parseState->defines[defineIdx].name = mmalloc_strdup(parseState->memContext, value); |
276 | parseState->defines[defineIdx].expr = 0; |
277 | } |
278 | |
279 | void addDefineExpr(ParseState* parseState, const char* value) |
280 | { |
281 | int defineIdx = parseState->numDefines - 1; |
282 | if(defineIdx < 0) |
283 | { |
284 | assert(0); |
285 | return; |
286 | } |
287 | |
288 | parseState->defines[defineIdx].expr = mmalloc_strdup(parseState->memContext, value); |
289 | } |
290 | |
291 | int hasDefine(ParseState* parseState, const char* value) |
292 | { |
293 | for (int i = 0; i < parseState->numDefines; i++) |
294 | { |
295 | if (strcmp(parseState->defines[i].name, value) == 0) |
296 | return 1; |
297 | } |
298 | |
299 | return 0; |
300 | } |
301 | |
302 | int isDefineEnabled(ParseState* parseState, const char* value) |
303 | { |
304 | for (int i = 0; i < parseState->numDefines; i++) |
305 | { |
306 | if (strcmp(parseState->defines[i].name, value) == 0) |
307 | { |
308 | if(parseState->defines[i].expr == 0) |
309 | return 0; |
310 | |
311 | int val = atoi(parseState->defines[i].expr); |
312 | return val != 0; |
313 | } |
314 | } |
315 | |
316 | return 0; |
317 | } |
318 | |
319 | void removeDefine(ParseState* parseState, const char* value) |
320 | { |
321 | for (int i = 0; i < parseState->numDefines; i++) |
322 | { |
323 | if (strcmp(parseState->defines[i].name, value) == 0) |
324 | { |
325 | int remaining = parseState->numDefines - (i + 1); |
326 | |
327 | if(remaining > 0) |
328 | memcpy(&parseState->defines[i], &parseState->defines[i + 1], remaining * sizeof(DefineEntry)); |
329 | |
330 | parseState->numDefines--; |
331 | } |
332 | } |
333 | } |
334 | |
335 | int pushConditionalDef(ParseState* parseState, int state) |
336 | { |
337 | ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData)); |
338 | conditional->enabled = state && (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled); |
339 | conditional->selfEnabled = state; |
340 | conditional->name = NULL; |
341 | conditional->op = CO_None; |
342 | conditional->value = NULL; |
343 | conditional->next = parseState->conditionalStack; |
344 | |
345 | parseState->conditionalStack = conditional; |
346 | |
347 | return conditional->enabled; |
348 | } |
349 | |
350 | void pushConditional(ParseState* parseState, const char* name) |
351 | { |
352 | ConditionalData* conditional = mmalloc(parseState->memContext, sizeof(ConditionalData)); |
353 | conditional->enabled = (parseState->conditionalStack == 0 || parseState->conditionalStack->enabled); |
354 | conditional->selfEnabled = 0; |
355 | conditional->op = CO_None; |
356 | conditional->value = NULL; |
357 | conditional->name = NULL; |
358 | conditional->next = parseState->conditionalStack; |
359 | |
360 | if(name) |
361 | conditional->name = mmalloc_strdup(parseState->memContext, name); |
362 | |
363 | parseState->conditionalStack = conditional; |
364 | } |
365 | |
366 | void setConditional(ParseState* parseState, const char* name) |
367 | { |
368 | assert(parseState->conditionalStack > 0); |
369 | |
370 | ConditionalData* conditional = parseState->conditionalStack; |
371 | ConditionalData* parent = conditional->next; |
372 | |
373 | conditional->name = mmalloc_strdup(parseState->memContext, name); |
374 | conditional->enabled = (parent == 0 || parent->enabled); |
375 | conditional->selfEnabled = 0; |
376 | } |
377 | |
378 | void setConditionalOp(ParseState* parseState, ConditionalOp op) |
379 | { |
380 | assert(parseState->conditionalStack > 0); |
381 | |
382 | ConditionalData* conditional = parseState->conditionalStack; |
383 | conditional->op = op; |
384 | } |
385 | |
386 | void setConditionalVal(ParseState* parseState, const char* value) |
387 | { |
388 | assert(parseState->conditionalStack > 0); |
389 | |
390 | ConditionalData* conditional = parseState->conditionalStack; |
391 | conditional->value = mmalloc_strdup(parseState->memContext, value); |
392 | } |
393 | |
394 | int evalConditional(ParseState* parseState) |
395 | { |
396 | assert(parseState->conditionalStack > 0); |
397 | |
398 | ConditionalData* conditional = parseState->conditionalStack; |
399 | if(!conditional->name) |
400 | { |
401 | conditional->enabled = 0; |
402 | return 0; |
403 | } |
404 | |
405 | int myVal = 1; |
406 | if(conditional->value) |
407 | myVal = atoi(conditional->value); |
408 | |
409 | for (int i = 0; i < parseState->numDefines; i++) |
410 | { |
411 | if (strcmp(parseState->defines[i].name, conditional->name) == 0) |
412 | { |
413 | int val = 0; |
414 | if(parseState->defines[i].expr) |
415 | val = atoi(parseState->defines[i].expr); |
416 | |
417 | switch(conditional->op) |
418 | { |
419 | default: |
420 | case CO_None: conditional->selfEnabled = val != 0; break; |
421 | case CO_Equals: conditional->selfEnabled = myVal == val; break; |
422 | case CO_NotEquals: conditional->selfEnabled = myVal != val; break; |
423 | case CO_Lesser: conditional->selfEnabled = val < myVal; break; |
424 | case CO_Greater: conditional->selfEnabled = val > myVal; break; |
425 | case CO_LesserEqual: conditional->selfEnabled = val <= myVal; break; |
426 | case CO_GreaterEqual: conditional->selfEnabled = val >= myVal; break; |
427 | } |
428 | } |
429 | } |
430 | |
431 | conditional->enabled &= conditional->selfEnabled; |
432 | return conditional->enabled; |
433 | } |
434 | |
435 | int setConditionalState(ParseState* parseState, int state) |
436 | { |
437 | if (parseState->conditionalStack == 0) |
438 | return 1; |
439 | |
440 | ConditionalData* conditional = parseState->conditionalStack; |
441 | ConditionalData* parent = conditional->next; |
442 | |
443 | conditional->enabled = state && (parent == 0 || parent->enabled); |
444 | conditional->selfEnabled = state; |
445 | |
446 | return conditional->enabled; |
447 | } |
448 | |
449 | int switchConditional(ParseState* parseState) |
450 | { |
451 | if (parseState->conditionalStack == 0) |
452 | return 1; |
453 | |
454 | ConditionalData* conditional = parseState->conditionalStack; |
455 | return setConditionalState(parseState, !conditional->selfEnabled); |
456 | } |
457 | |
458 | int popConditional(ParseState* parseState) |
459 | { |
460 | if (parseState->conditionalStack == 0) |
461 | return 1; |
462 | |
463 | ConditionalData* conditional = parseState->conditionalStack; |
464 | parseState->conditionalStack = conditional->next; |
465 | |
466 | if(conditional->value) |
467 | mmfree(conditional->value); |
468 | |
469 | if(conditional->name) |
470 | mmfree(conditional->name); |
471 | |
472 | mmfree(conditional); |
473 | |
474 | return parseState->conditionalStack == 0 || parseState->conditionalStack->enabled; |
475 | } |
476 | |
477 | ParseState* parseStateCreate() |
478 | { |
479 | ParseState* parseState = (ParseState*)malloc(sizeof(ParseState)); |
480 | parseState->memContext = mmalloc_new_context(); |
481 | parseState->rootNode = nodeCreate(parseState->memContext, NT_Root); |
482 | parseState->topNode = 0; |
483 | parseState->nodeStack = 0; |
484 | parseState->includeStack = 0; |
485 | parseState->includes = 0; |
486 | parseState->rawCodeBlock[0] = 0; |
487 | parseState->rawCodeBlock[1] = 0; |
488 | parseState->numRawCodeBlocks[0] = 0; |
489 | parseState->numRawCodeBlocks[1] = 0; |
490 | parseState->numOpenBrackets = 0; |
491 | |
492 | parseState->hasError = 0; |
493 | parseState->errorLine = 0; |
494 | parseState->errorColumn = 0; |
495 | parseState->errorMessage = 0; |
496 | parseState->errorFile = 0; |
497 | |
498 | parseState->conditionalStack = 0; |
499 | parseState->defineCapacity = 10; |
500 | parseState->numDefines = 0; |
501 | parseState->defines = mmalloc(parseState->memContext, parseState->defineCapacity * sizeof(DefineEntry)); |
502 | |
503 | nodePush(parseState, parseState->rootNode); |
504 | |
505 | return parseState; |
506 | } |
507 | |
508 | void parseStateDelete(ParseState* parseState) |
509 | { |
510 | while (parseState->nodeStack != 0) |
511 | nodePop(parseState); |
512 | |
513 | nodeDelete(parseState->rootNode); |
514 | mmalloc_free_context(parseState->memContext); |
515 | |
516 | free(parseState); |
517 | } |