Coverage Report

Created: 2026-02-26 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreScriptCompiler.cpp
Line
Count
Source
1
/*
2
-----------------------------------------------------------------------------
3
This source file is part of OGRE
4
    (Object-oriented Graphics Rendering Engine)
5
For the latest info, see http://www.ogre3d.org/
6
7
Copyright (c) 2000-2014 Torus Knot Software Ltd
8
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
15
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
18
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
THE SOFTWARE.
26
-----------------------------------------------------------------------------
27
*/
28
29
#include "OgreStableHeaders.h"
30
#include "OgreScriptParser.h"
31
#include "OgreBuiltinScriptTranslators.h"
32
#include "OgreComponents.h"
33
34
#define DEBUG_AST 0
35
36
namespace Ogre
37
{
38
    // AbstractNode
39
    AbstractNode::AbstractNode(AbstractNode *ptr)
40
0
        :line(0), type(ANT_UNKNOWN), parent(ptr)
41
0
    {}
42
43
    // AtomAbstractNode
44
    AtomAbstractNode::AtomAbstractNode(AbstractNode *ptr)
45
0
        :AbstractNode(ptr), id(0)
46
0
    {
47
0
        type = ANT_ATOM;
48
0
    }
49
50
    AbstractNode *AtomAbstractNode::clone() const
51
0
    {
52
0
        AtomAbstractNode *node = OGRE_NEW AtomAbstractNode(parent);
53
0
        node->file = file;
54
0
        node->line = line;
55
0
        node->id = id;
56
0
        node->type = type;
57
0
        node->value = value;
58
0
        return node;
59
0
    }
60
61
    // ObjectAbstractNode
62
    ObjectAbstractNode::ObjectAbstractNode(AbstractNode *ptr)
63
0
        :AbstractNode(ptr), id(0), abstract(false)
64
0
    {
65
0
        type = ANT_OBJECT;
66
0
    }
67
68
    AbstractNode *ObjectAbstractNode::clone() const
69
0
    {
70
0
        ObjectAbstractNode *node = OGRE_NEW ObjectAbstractNode(parent);
71
0
        node->file = file;
72
0
        node->line = line;
73
0
        node->type = type;
74
0
        node->name = name;
75
0
        node->cls = cls;
76
0
        node->id = id;
77
0
        node->abstract = abstract;
78
0
        for(const auto & i : children)
79
0
        {
80
0
            AbstractNodePtr newNode = AbstractNodePtr(i->clone());
81
0
            newNode->parent = node;
82
0
            node->children.push_back(newNode);
83
0
        }
84
0
        for(const auto & value : values)
85
0
        {
86
0
            AbstractNodePtr newNode = AbstractNodePtr(value->clone());
87
0
            newNode->parent = node;
88
0
            node->values.push_back(newNode);
89
0
        }
90
0
        node->mEnv = mEnv;
91
0
        return node;
92
0
    }
93
94
    void ObjectAbstractNode::addVariable(const Ogre::String &inName)
95
0
    {
96
0
        mEnv.insert(std::make_pair(inName, ""));
97
0
    }
98
99
    void ObjectAbstractNode::setVariable(const Ogre::String &inName, const Ogre::String &value)
100
0
    {
101
0
        mEnv[inName] = value;
102
0
    }
103
104
    std::pair<bool,String> ObjectAbstractNode::getVariable(const String &inName) const
105
0
    {
106
0
        std::map<String,String>::const_iterator i = mEnv.find(inName);
107
0
        if(i != mEnv.end())
108
0
            return std::make_pair(true, i->second);
109
110
0
        ObjectAbstractNode *parentNode = (ObjectAbstractNode*)this->parent;
111
0
        while(parentNode)
112
0
        {
113
0
            i = parentNode->mEnv.find(inName);
114
0
            if(i != parentNode->mEnv.end())
115
0
                return std::make_pair(true, i->second);
116
0
            parentNode = (ObjectAbstractNode*)parentNode->parent;
117
0
        }
118
0
        return std::make_pair(false, "");
119
0
    }
120
121
    const std::map<String,String> &ObjectAbstractNode::getVariables() const
122
0
    {
123
0
        return mEnv;
124
0
    }
125
126
    // PropertyAbstractNode
127
    PropertyAbstractNode::PropertyAbstractNode(AbstractNode *ptr)
128
0
        :AbstractNode(ptr), id(0)
129
0
    {
130
0
        type = ANT_PROPERTY;
131
0
    }
132
133
    AbstractNode *PropertyAbstractNode::clone() const
134
0
    {
135
0
        PropertyAbstractNode *node = OGRE_NEW PropertyAbstractNode(parent);
136
0
        node->file = file;
137
0
        node->line = line;
138
0
        node->type = type;
139
0
        node->name = name;
140
0
        node->id = id;
141
0
        for(const auto & value : values)
142
0
        {
143
0
            AbstractNodePtr newNode = AbstractNodePtr(value->clone());
144
0
            newNode->parent = node;
145
0
            node->values.push_back(newNode);
146
0
        }
147
0
        return node;
148
0
    }
149
150
    // ImportAbstractNode
151
    ImportAbstractNode::ImportAbstractNode()
152
0
        :AbstractNode(0)
153
0
    {
154
0
        type = ANT_IMPORT;
155
0
    }
156
157
    AbstractNode *ImportAbstractNode::clone() const
158
0
    {
159
0
        ImportAbstractNode *node = OGRE_NEW ImportAbstractNode();
160
0
        node->file = file;
161
0
        node->line = line;
162
0
        node->type = type;
163
0
        node->target = target;
164
0
        node->source = source;
165
0
        return node;
166
0
    }
167
168
    // VariableAccessAbstractNode
169
    VariableAccessAbstractNode::VariableAccessAbstractNode(AbstractNode *ptr)
170
0
        :AbstractNode(ptr)
171
0
    {
172
0
        type = ANT_VARIABLE_ACCESS;
173
0
    }
174
175
    AbstractNode *VariableAccessAbstractNode::clone() const
176
0
    {
177
0
        VariableAccessAbstractNode *node = OGRE_NEW VariableAccessAbstractNode(parent);
178
0
        node->file = file;
179
0
        node->line = line;
180
0
        node->type = type;
181
0
        node->name = name;
182
0
        return node;
183
0
    }
184
185
    // ScriptCompilerListener
186
    ScriptCompilerListener::ScriptCompilerListener()
187
0
    {
188
0
    }
189
190
    ConcreteNodeListPtr ScriptCompilerListener::importFile(ScriptCompiler *compiler, const String &name)
191
0
    {
192
0
        return ConcreteNodeListPtr();
193
0
    }
194
195
    void ScriptCompilerListener::preConversion(ScriptCompiler *compiler, ConcreteNodeListPtr nodes)
196
0
    {
197
198
0
    }
199
200
    bool ScriptCompilerListener::postConversion(ScriptCompiler *compiler, const AbstractNodeListPtr &nodes)
201
0
    {
202
0
        return true;
203
0
    }
204
205
    void ScriptCompilerListener::handleError(ScriptCompiler *compiler, uint32 code, const String &file, int line, const String &msg)
206
0
    {
207
0
        StringStream ss;
208
0
        ss << "ScriptCompiler - " << ScriptCompiler::formatErrorCode(code) << " in " << file << "(" << line << ")";
209
0
        if(!msg.empty())
210
0
            ss << ": " << msg;
211
212
0
        if(code == ScriptCompiler::CE_DEPRECATEDSYMBOL)
213
0
            LogManager::getSingleton().logWarning(ss.str());
214
0
        else
215
0
            LogManager::getSingleton().logError(ss.str());
216
0
    }
217
218
    bool ScriptCompilerListener::handleEvent(ScriptCompiler *compiler, ScriptCompilerEvent *evt, void *retval)
219
0
    {
220
0
        return false;
221
0
    }
222
223
    // ScriptCompiler
224
    String ScriptCompiler::formatErrorCode(uint32 code)
225
0
    {
226
0
        switch(code)
227
0
        {
228
0
        case CE_STRINGEXPECTED:
229
0
            return "string expected";
230
0
        case CE_NUMBEREXPECTED:
231
0
            return "number expected";
232
0
        case CE_FEWERPARAMETERSEXPECTED:
233
0
            return "fewer parameters expected";
234
0
        case CE_VARIABLEEXPECTED:
235
0
            return "variable expected";
236
0
        case CE_UNDEFINEDVARIABLE:
237
0
            return "undefined variable";
238
0
        case CE_OBJECTNAMEEXPECTED:
239
0
            return "object name expected";
240
0
        case CE_OBJECTALLOCATIONERROR:
241
0
            return "no object created";
242
0
        case CE_OBJECTBASENOTFOUND:
243
0
            return "base object not found";
244
0
        case CE_INVALIDPARAMETERS:
245
0
            return "invalid parameters";
246
0
        case CE_DUPLICATEOVERRIDE:
247
0
            return "duplicate object override";
248
0
        case CE_REFERENCETOANONEXISTINGOBJECT:
249
0
            return "reference to a non existing object";
250
0
        case CE_UNEXPECTEDTOKEN:
251
0
            return "unexpected token";
252
0
        case CE_DEPRECATEDSYMBOL:
253
0
            return "deprecated symbol";
254
0
        default:
255
0
            return "unknown error";
256
0
        }
257
0
    }
258
259
    ScriptCompiler::ScriptCompiler()
260
1
        :mListener(0)
261
1
    {
262
1
        initWordMap();
263
1
    }
264
265
    bool ScriptCompiler::compile(const String &str, const String &source, const String &group)
266
0
    {
267
0
        ConcreteNodeListPtr nodes = ScriptParser::parse(ScriptLexer::tokenize(str, source), source);
268
0
        return compile(nodes, group);
269
0
    }
270
271
#if DEBUG_AST
272
    static void logAST(int tabs, const AbstractNodePtr &node)
273
    {
274
        String msg = "";
275
        for(int i = 0; i < tabs; ++i)
276
            msg += "\t";
277
278
        switch(node->type)
279
        {
280
        case ANT_ATOM:
281
            {
282
                AtomAbstractNode *atom = static_cast<AtomAbstractNode*>(node.get());
283
                msg = msg + atom->value;
284
            }
285
            break;
286
        case ANT_PROPERTY:
287
            {
288
                PropertyAbstractNode *prop = static_cast<PropertyAbstractNode*>(node.get());
289
                msg = msg + prop->name + " =";
290
                for(const auto& v : prop->values)
291
                {
292
                    if(v->type == ANT_ATOM)
293
                        msg = msg + " " + static_cast<AtomAbstractNode*>(v.get())->value;
294
                }
295
            }
296
            break;
297
        case ANT_OBJECT:
298
            {
299
                ObjectAbstractNode *obj = static_cast<ObjectAbstractNode*>(node.get());
300
                msg = msg + node->file + " - " + StringConverter::toString(node->line) + " - " + obj->cls + " \"" + obj->name + "\" =";
301
                for(const auto& v : obj->values)
302
                {
303
                    if(v->type == ANT_ATOM)
304
                        msg = msg + " " + static_cast<AtomAbstractNode*>(v.get())->value;
305
                }
306
            }
307
            break;
308
        default:
309
            msg = msg + "Unacceptable node type: " + StringConverter::toString(node->type);
310
        }
311
312
        LogManager::getSingleton().logMessage(msg);
313
314
        if(node->type == ANT_OBJECT)
315
        {
316
            ObjectAbstractNode *obj = static_cast<ObjectAbstractNode*>(node.get());
317
            for(const auto& c : obj->children)
318
            {
319
                logAST(tabs + 1, c);
320
            }
321
        }
322
    }
323
#endif
324
325
    bool ScriptCompiler::compile(const ConcreteNodeListPtr &nodes, const String &group)
326
0
    {
327
0
        if(nodes && !nodes->empty())
328
0
        {
329
0
            mSourceFile = nodes->front()->file;
330
0
        }
331
332
        // Set up the compilation context
333
0
        mGroup = group;
334
335
        // Clear the past errors
336
0
        mErrors.clear();
337
338
        // Clear the environment
339
0
        mEnv.clear();
340
341
0
        if(mListener)
342
0
            mListener->preConversion(this, nodes);
343
344
        // Convert our nodes to an AST
345
0
        AbstractNodeListPtr ast = convertToAST(*nodes);
346
        // Processes the imports for this script
347
0
        processImports(*ast);
348
        // Process object inheritance
349
0
        processObjects(*ast, *ast);
350
        // Process variable expansion
351
0
        processVariables(*ast);
352
353
        // Allows early bail-out through the listener
354
0
        if(mListener && !mListener->postConversion(this, ast))
355
0
            return mErrors.empty();
356
357
        // Translate the nodes
358
0
        for(auto & i : *ast)
359
0
        {
360
#if DEBUG_AST
361
            logAST(0, i);
362
#endif
363
0
            if(i->type == ANT_OBJECT && static_cast<ObjectAbstractNode*>(i.get())->abstract)
364
0
                continue;
365
            //LogManager::getSingleton().logMessage(static_cast<ObjectAbstractNode*>((*i).get())->name);
366
0
            ScriptTranslator *translator = ScriptCompilerManager::getSingleton().getTranslator(i);
367
0
            if(translator)
368
0
                translator->translate(this, i);
369
0
        }
370
371
0
        mImports.clear();
372
0
        mImportRequests.clear();
373
0
        mImportTable.clear();
374
0
        mSourceFile.clear();
375
376
0
        return mErrors.empty();
377
0
    }
378
379
    void ScriptCompiler::addError(uint32 code, const Ogre::String &file, int line, const String &msg)
380
0
    {
381
0
        if(mListener)
382
0
        {
383
0
            mListener->handleError(this, code, file, line, msg);
384
0
        }
385
0
        else
386
0
        {
387
0
            static ScriptCompilerListener defaultListener;
388
0
            defaultListener.handleError(this, code, file, line, msg);
389
0
        }
390
391
0
        mErrors.push_back({file, msg, line, code});
392
0
    }
393
394
    void ScriptCompiler::addError(const AbstractNode& node, const String& msg, uint32 code)
395
0
    {
396
0
        addError(code, mSourceFile, node.line, msg);
397
0
    }
398
399
    void ScriptCompiler::setListener(ScriptCompilerListener *listener)
400
0
    {
401
0
        mListener = listener;
402
0
    }
403
404
    ScriptCompilerListener *ScriptCompiler::getListener()
405
0
    {
406
0
        return mListener;
407
0
    }
408
409
    const String &ScriptCompiler::getResourceGroup() const
410
0
    {
411
0
        return mGroup;
412
0
    }
413
414
    bool ScriptCompiler::_fireEvent(ScriptCompilerEvent *evt, void *retval)
415
0
    {
416
0
        if(mListener)
417
0
            return mListener->handleEvent(this, evt, retval);
418
0
        return false;
419
0
    }
420
421
    AbstractNodeListPtr ScriptCompiler::convertToAST(const ConcreteNodeList &nodes)
422
0
    {
423
0
        AbstractTreeBuilder builder(this);
424
0
        AbstractTreeBuilder::visit(&builder, nodes);
425
0
        return builder.getResult();
426
0
    }
427
428
    void ScriptCompiler::processImports(AbstractNodeList &nodes)
429
0
    {
430
        // We only need to iterate over the top-level of nodes
431
0
        AbstractNodeList::iterator i = nodes.begin();
432
0
        while(i != nodes.end())
433
0
        {
434
            // We move to the next node here and save the current one.
435
            // If any replacement happens, then we are still assured that
436
            // i points to the node *after* the replaced nodes, no matter
437
            // how many insertions and deletions may happen
438
0
            AbstractNodeList::iterator cur = i++;
439
0
            if((*cur)->type == ANT_IMPORT)
440
0
            {
441
0
                ImportAbstractNode *import = (ImportAbstractNode*)(*cur).get();
442
                // Only process if the file's contents haven't been loaded
443
0
                if(mImports.find(import->source) == mImports.end())
444
0
                {
445
                    // Load the script
446
0
                    AbstractNodeListPtr importedNodes = loadImportPath(import->source);
447
0
                    if(importedNodes && !importedNodes->empty())
448
0
                    {
449
0
                        processImports(*importedNodes);
450
0
                        processObjects(*importedNodes, *importedNodes);
451
0
                    }
452
0
                    else
453
0
                    {
454
0
                        addError(CE_REFERENCETOANONEXISTINGOBJECT, import->file, import->line, import->source);
455
0
                    }
456
457
0
                    if(importedNodes && !importedNodes->empty())
458
0
                        mImports.insert(std::make_pair(import->source, importedNodes));
459
0
                }
460
461
0
                ImportRequestMap::iterator iter = mImportRequests.lower_bound(import->source),
462
0
                                           end = mImportRequests.upper_bound(import->source);
463
                // Handle the target request now
464
                // If it is a '*' import we remove all previous requests and just use the '*'
465
                // Otherwise, ensure '*' isn't already registered and register our request
466
0
                if(import->target == "*")
467
0
                {
468
0
                    mImportRequests.erase(iter, end);
469
0
                    mImportRequests.insert(std::make_pair(import->source, "*"));
470
0
                }
471
0
                else
472
0
                {
473
0
                    if(iter == end || iter->second != "*")
474
0
                    {
475
0
                        mImportRequests.insert(std::make_pair(import->source, import->target));
476
0
                    }
477
0
                }
478
479
0
                nodes.erase(cur);
480
0
            }
481
0
        }
482
483
        // All import nodes are removed
484
        // We have cached the code blocks from all the imported scripts
485
        // We can process all import requests now
486
0
        for(auto & import : mImports)
487
0
        {
488
0
            ImportRequestMap::iterator j = mImportRequests.lower_bound(import.first),
489
0
                end = mImportRequests.upper_bound(import.first);
490
0
            if(j != end)
491
0
            {
492
0
                if(j->second == "*")
493
0
                {
494
                    // Insert the entire AST into the import table
495
0
                    mImportTable.insert(mImportTable.begin(), import.second->begin(), import.second->end());
496
0
                    continue; // Skip ahead to the next file
497
0
                }
498
0
                else
499
0
                {
500
0
                    for(; j != end; ++j)
501
0
                    {
502
                        // Locate this target and insert it into the import table
503
0
                        AbstractNodeList newNodes = locateTarget(*import.second, j->second);
504
0
                        if(!newNodes.empty())
505
0
                            mImportTable.insert(mImportTable.begin(), newNodes.begin(), newNodes.end());
506
0
                        else
507
                            // -1 for line as we lost that info here
508
0
                            addError(CE_REFERENCETOANONEXISTINGOBJECT, nodes.front()->file, -1, j->second);
509
0
                    }
510
0
                }
511
0
            }
512
0
        }
513
0
    }
514
515
    AbstractNodeListPtr ScriptCompiler::loadImportPath(const Ogre::String &name)
516
0
    {
517
0
        AbstractNodeListPtr retval;
518
0
        ConcreteNodeListPtr nodes;
519
520
0
        if(mListener)
521
0
            nodes = mListener->importFile(this, name);
522
523
0
        if(!nodes && ResourceGroupManager::getSingletonPtr())
524
0
        {
525
0
            auto stream = ResourceGroupManager::getSingleton().openResource(name, mGroup, NULL, false);
526
527
0
            if (!stream)
528
0
                return retval;
529
530
0
            nodes = ScriptParser::parse(ScriptLexer::tokenize(stream->getAsString(), name), name);
531
0
        }
532
533
0
        if(nodes)
534
0
            retval = convertToAST(*nodes);
535
536
0
        return retval;
537
0
    }
538
539
    AbstractNodeList ScriptCompiler::locateTarget(const AbstractNodeList& nodes, const Ogre::String &target)
540
0
    {
541
0
        SharedPtr<AbstractNode> iter = nullptr;
542
543
        // Search for a top-level object node
544
0
        for(auto i : nodes)
545
0
        {
546
0
            if(i->type == ANT_OBJECT)
547
0
            {
548
0
                ObjectAbstractNode *impl = (ObjectAbstractNode*)i.get();
549
0
                if(impl->name == target)
550
0
                    iter = i;
551
0
            }
552
0
        }
553
554
0
        AbstractNodeList newNodes;
555
0
        if(iter)
556
0
        {
557
0
            newNodes.push_back(iter);
558
0
        }
559
0
        return newNodes;
560
0
    }
561
562
    void ScriptCompiler::processObjects(AbstractNodeList& nodes, const AbstractNodeList &top)
563
0
    {
564
0
        for(auto& node : nodes)
565
0
        {
566
0
            if(node->type == ANT_OBJECT)
567
0
            {
568
0
                ObjectAbstractNode *obj = (ObjectAbstractNode*)node.get();
569
570
0
#ifdef OGRE_BUILD_COMPONENT_OVERLAY
571
0
                bool isOverlayElement = obj->cls == "overlay_element";
572
0
#endif
573
                // Overlay base classes in order.
574
0
                for (String& base : obj->bases)
575
0
                {
576
                    // Check the top level first, then check the import table
577
0
                    AbstractNodeList newNodes = locateTarget(top, base);
578
0
                    if(newNodes.empty())
579
0
                        newNodes = locateTarget(mImportTable, base);
580
581
0
                    if (newNodes.empty())
582
0
                        addError(CE_OBJECTBASENOTFOUND, obj->file, obj->line, base);
583
584
0
                    for(const auto& n : newNodes)
585
0
                    {
586
0
                        if(n->type != ANT_OBJECT) continue;
587
588
0
                        auto src = static_cast<const ObjectAbstractNode&>(*n);
589
590
0
#ifdef OGRE_BUILD_COMPONENT_OVERLAY
591
                        // uses custom inheritance for renaming children
592
0
                        if(isOverlayElement)
593
0
                        {
594
0
                            if(src.abstract)
595
0
                                base = ""; // hide from custom inheritance
596
0
                            else
597
0
                                continue;
598
0
                        }
599
0
#endif
600
0
                        overlayObject(src, *obj);
601
0
                    }
602
0
                }
603
604
                // Recurse into children
605
0
                processObjects(obj->children, top);
606
607
                // Overrides now exist in obj's overrides list. These are non-object nodes which must now
608
                // Be placed in the children section of the object node such that overriding from parents
609
                // into children works properly.
610
0
                obj->children.insert(obj->children.begin(), obj->overrides.begin(), obj->overrides.end());
611
0
            }
612
0
        }
613
0
    }
614
615
    void ScriptCompiler::overlayObject(const ObjectAbstractNode &src, ObjectAbstractNode& dest)
616
0
    {
617
        // Overlay the environment of one on top the other first
618
0
        for(const auto & i : src.getVariables())
619
0
        {
620
0
            std::pair<bool,String> var = dest.getVariable(i.first);
621
0
            if(!var.first)
622
0
                dest.setVariable(i.first, i.second);
623
0
        }
624
625
        // Create a vector storing each pairing of override between source and destination
626
0
        typedef SharedPtr<ObjectAbstractNode> ObjectAbstractNodePtr;
627
0
        std::vector<std::pair<ObjectAbstractNodePtr,AbstractNodeList::iterator> > overrides;
628
        // A list of indices for each destination node tracks the minimum
629
        // source node they can index-match against
630
0
        std::map<ObjectAbstractNode*,size_t> indices;
631
        // A map storing which nodes have overridden from the destination node
632
0
        std::map<ObjectAbstractNode*,bool> overridden;
633
634
        // Fill the vector with objects from the source node (base)
635
        // And insert non-objects into the overrides list of the destination
636
0
        AbstractNodeList::iterator insertPos = dest.children.begin();
637
0
        for(const auto & i : src.children)
638
0
        {
639
0
            if(i->type == ANT_OBJECT)
640
0
            {
641
0
                overrides.push_back(std::make_pair(static_pointer_cast<ObjectAbstractNode>(i), dest.children.end()));
642
0
            }
643
0
            else
644
0
            {
645
0
                AbstractNodePtr newNode(i->clone());
646
0
                newNode->parent = &dest;
647
0
                dest.overrides.push_back(newNode);
648
0
            }
649
0
        }
650
651
        // Track the running maximum override index in the name-matching phase
652
0
        size_t maxOverrideIndex = 0;
653
654
        // Loop through destination children searching for name-matching overrides
655
0
        for(AbstractNodeList::iterator i = dest.children.begin(); i != dest.children.end(); )
656
0
        {
657
0
            if((*i)->type == ANT_OBJECT)
658
0
            {
659
                // Start tracking the override index position for this object
660
0
                size_t overrideIndex = 0;
661
662
0
                ObjectAbstractNode *node = static_cast<ObjectAbstractNode*>((*i).get());
663
0
                indices[node] = maxOverrideIndex;
664
0
                overridden[node] = false;
665
666
                // special treatment for materials with * in their name
667
0
                bool nodeHasWildcard=node->name.find('*') != String::npos;
668
669
                // Find the matching name node
670
0
                for(size_t j = 0; j < overrides.size(); ++j)
671
0
                {
672
0
                    ObjectAbstractNode *temp = overrides[j].first.get();
673
                    // Consider a match a node that has a wildcard and matches an input name
674
0
                    bool wildcardMatch = nodeHasWildcard &&
675
0
                        (StringUtil::match(temp->name,node->name,true) ||
676
0
                            (node->name.size() == 1 && temp->name.empty()));
677
0
                    if(temp->cls == node->cls && !node->name.empty() && (temp->name == node->name || wildcardMatch))
678
0
                    {
679
                        // Pair these two together unless it's already paired
680
0
                        if(overrides[j].second == dest.children.end())
681
0
                        {
682
0
                            AbstractNodeList::iterator currentIterator = i;
683
0
                            ObjectAbstractNode *currentNode = node;
684
0
                            if (wildcardMatch)
685
0
                            {
686
                                //If wildcard is matched, make a copy of current material and put it before the iterator, matching its name to the parent. Use same reinterpret cast as above when node is set
687
0
                                AbstractNodePtr newNode((*i)->clone());
688
0
                                currentIterator = dest.children.insert(currentIterator, newNode);
689
0
                                currentNode = static_cast<ObjectAbstractNode*>((*currentIterator).get());
690
0
                                currentNode->name = temp->name;//make the regex match its matcher
691
0
                            }
692
0
                            overrides[j] = std::make_pair(overrides[j].first, currentIterator);
693
                            // Store the max override index for this matched pair
694
0
                            overrideIndex = j;
695
0
                            overrideIndex = maxOverrideIndex = std::max(overrideIndex, maxOverrideIndex);
696
0
                            indices[currentNode] = overrideIndex;
697
0
                            overridden[currentNode] = true;
698
0
                        }
699
0
                        else
700
0
                        {
701
0
                            addError(CE_DUPLICATEOVERRIDE, node->file, node->line);
702
0
                        }
703
704
0
                        if(!wildcardMatch)
705
0
                            break;
706
0
                    }
707
0
                }
708
709
0
                if (nodeHasWildcard)
710
0
                {
711
                    //if the node has a wildcard it will be deleted since it was duplicated for every match
712
0
                    AbstractNodeList::iterator deletable=i++;
713
0
                    dest.children.erase(deletable);
714
0
                }
715
0
                else
716
0
                {
717
0
                    ++i; //Behavior in absence of regex, just increment iterator
718
0
                }
719
0
            }
720
0
            else
721
0
            {
722
0
                ++i; //Behavior in absence of replaceable object, just increment iterator to find another
723
0
            }
724
0
        }
725
726
        // Now make matches based on index
727
        // Loop through destination children searching for index-matching overrides
728
0
        for(AbstractNodeList::iterator i = dest.children.begin(); i != dest.children.end(); ++i)
729
0
        {
730
0
            if((*i)->type == ANT_OBJECT)
731
0
            {
732
0
                ObjectAbstractNode *node = static_cast<ObjectAbstractNode*>((*i).get());
733
0
                if(!overridden[node])
734
0
                {
735
                    // Retrieve the minimum override index from the map
736
0
                    size_t overrideIndex = indices[node];
737
738
0
                    if(overrideIndex < overrides.size())
739
0
                    {
740
                        // Search for minimum matching override
741
0
                        for(size_t j = overrideIndex; j < overrides.size(); ++j)
742
0
                        {
743
0
                            ObjectAbstractNode *temp = overrides[j].first.get();
744
0
                            if(temp->name.empty() && node->name.empty() && temp->cls == node->cls && overrides[j].second == dest.children.end())
745
0
                            {
746
0
                                overrides[j] = std::make_pair(overrides[j].first, i);
747
0
                                break;
748
0
                            }
749
0
                        }
750
0
                    }
751
0
                }
752
0
            }
753
0
        }
754
755
        // Loop through overrides, either inserting source nodes or overriding
756
0
        insertPos = dest.children.begin();
757
0
        for(auto & override : overrides)
758
0
        {
759
0
            if(override.second != dest.children.end())
760
0
            {
761
                // Override the destination with the source (base) object
762
0
                overlayObject(*override.first,
763
0
                    static_cast<ObjectAbstractNode&>(**override.second));
764
0
                insertPos = override.second;
765
0
                insertPos++;
766
0
            }
767
0
            else
768
0
            {
769
                // No override was possible, so insert this node at the insert position
770
                // into the destination (child) object
771
0
                AbstractNodePtr newNode(override.first->clone());
772
0
                newNode->parent = &dest;
773
0
                if(insertPos != dest.children.end())
774
0
                {
775
0
                    dest.children.insert(insertPos, newNode);
776
0
                }
777
0
                else
778
0
                {
779
0
                    dest.children.push_back(newNode);
780
0
                }
781
0
            }
782
0
        }
783
0
    }
784
785
    bool ScriptCompiler::isNameExcluded(const ObjectAbstractNode& node, AbstractNode* parent)
786
0
    {
787
        // Run past the listener
788
0
        bool excludeName = false;
789
0
        ProcessNameExclusionScriptCompilerEvent evt(node.cls, parent);
790
0
        if(_fireEvent(&evt, (void*)&excludeName))
791
0
            return excludeName;
792
793
        // Process the built-in name exclusions
794
0
        if(node.id == ID_EMITTER || node.id == ID_AFFECTOR)
795
0
        {
796
            // emitters or affectors inside a particle_system are excluded
797
0
            while(parent && parent->type == ANT_OBJECT)
798
0
            {
799
0
                ObjectAbstractNode *obj = static_cast<ObjectAbstractNode*>(parent);
800
0
                if(obj->id == ID_PARTICLE_SYSTEM)
801
0
                    return true;
802
0
                parent = obj->parent;
803
0
            }
804
0
        }
805
0
        else if(node.id == ID_PASS)
806
0
        {
807
            // passes inside compositors are excluded
808
0
            while(parent && parent->type == ANT_OBJECT)
809
0
            {
810
0
                ObjectAbstractNode *obj = static_cast<ObjectAbstractNode*>(parent);
811
0
                if(obj->id == ID_TARGET || obj->id == ID_TARGET_OUTPUT)
812
0
                    return true;
813
0
                parent = obj->parent;
814
0
            }
815
0
        }
816
0
        else if(node.id == ID_TEXTURE_SOURCE)
817
0
        {
818
            // Parent must be texture_unit
819
0
            while(parent && parent->type == ANT_OBJECT)
820
0
            {
821
0
                ObjectAbstractNode *obj = static_cast<ObjectAbstractNode*>(parent);
822
0
                if(obj->id == ID_TEXTURE_UNIT)
823
0
                    return true;
824
0
                parent = obj->parent;
825
0
            }
826
0
        }
827
828
0
        return false;
829
0
    }
830
831
    void ScriptCompiler::processVariables(AbstractNodeList& nodes)
832
0
    {
833
0
        AbstractNodeList::iterator i = nodes.begin();
834
0
        while(i != nodes.end())
835
0
        {
836
0
            AbstractNodeList::iterator cur = i;
837
0
            ++i;
838
839
0
            if((*cur)->type == ANT_OBJECT)
840
0
            {
841
                // Only process if this object is not abstract
842
0
                ObjectAbstractNode *obj = (ObjectAbstractNode*)(*cur).get();
843
0
                if(!obj->abstract)
844
0
                {
845
0
                    processVariables(obj->children);
846
0
                    processVariables(obj->values);
847
0
                }
848
0
            }
849
0
            else if((*cur)->type == ANT_PROPERTY)
850
0
            {
851
0
                PropertyAbstractNode *prop = (PropertyAbstractNode*)(*cur).get();
852
0
                processVariables(prop->values);
853
0
            }
854
0
            else if((*cur)->type == ANT_VARIABLE_ACCESS)
855
0
            {
856
0
                VariableAccessAbstractNode *var = (VariableAccessAbstractNode*)(*cur).get();
857
858
                // Look up the enclosing scope
859
0
                ObjectAbstractNode *scope = 0;
860
0
                AbstractNode *temp = var->parent;
861
0
                while(temp)
862
0
                {
863
0
                    if(temp->type == ANT_OBJECT)
864
0
                    {
865
0
                        scope = (ObjectAbstractNode*)temp;
866
0
                        break;
867
0
                    }
868
0
                    temp = temp->parent;
869
0
                }
870
871
                // Look up the variable in the environment
872
0
                std::pair<bool,String> varAccess;
873
0
                if(scope)
874
0
                    varAccess = scope->getVariable(var->name);
875
0
                if(!scope || !varAccess.first)
876
0
                {
877
0
                    std::map<String,String>::iterator k = mEnv.find(var->name);
878
0
                    varAccess.first = k != mEnv.end();
879
0
                    if(varAccess.first)
880
0
                        varAccess.second = k->second;
881
0
                }
882
883
0
                if(varAccess.first)
884
0
                {
885
                    // Found the variable, so process it and insert it into the tree
886
0
                    ConcreteNodeListPtr cst = ScriptParser::parseChunk(ScriptLexer::tokenize(varAccess.second, var->file), var->file);
887
0
                    AbstractNodeListPtr ast = convertToAST(*cst);
888
889
                    // Set up ownership for these nodes
890
0
                    for(auto & j : *ast)
891
0
                        j->parent = var->parent;
892
893
                    // Recursively handle variable accesses within the variable expansion
894
0
                    processVariables(*ast);
895
896
                    // Insert the nodes in place of the variable
897
0
                    nodes.insert(cur, ast->begin(), ast->end());
898
0
                }
899
0
                else
900
0
                {
901
                    // Error
902
0
                    addError(CE_UNDEFINEDVARIABLE, var->file, var->line, var->name);
903
0
                }
904
905
                // Remove the variable node
906
0
                nodes.erase(cur);
907
0
            }
908
0
        }
909
0
    }
910
911
    void ScriptCompiler::initWordMap()
912
1
    {
913
1
        mIds["on"] = ID_ON;
914
1
        mIds["off"] = ID_OFF;
915
1
        mIds["true"] = ID_TRUE;
916
1
        mIds["false"] = ID_FALSE;
917
1
        mIds["yes"] = ID_YES;
918
1
        mIds["no"] = ID_NO;
919
920
        // Material ids
921
1
        mIds["material"] = ID_MATERIAL;
922
1
        mIds["vertex_program"] = ID_VERTEX_PROGRAM;
923
1
        mIds["geometry_program"] = ID_GEOMETRY_PROGRAM;
924
1
        mIds["fragment_program"] = ID_FRAGMENT_PROGRAM;
925
1
        mIds["tessellation_hull_program"] = ID_TESSELLATION_HULL_PROGRAM;
926
1
        mIds["tessellation_domain_program"] = ID_TESSELLATION_DOMAIN_PROGRAM;
927
1
        mIds["compute_program"] = ID_COMPUTE_PROGRAM;
928
1
        mIds["mesh_program"] = ID_MESH_PROGRAM;
929
1
        mIds["task_program"] = ID_TASK_PROGRAM;
930
1
        mIds["technique"] = ID_TECHNIQUE;
931
1
        mIds["pass"] = ID_PASS;
932
1
        mIds["texture_unit"] = ID_TEXTURE_UNIT;
933
1
        mIds["vertex_program_ref"] = ID_VERTEX_PROGRAM_REF;
934
1
        mIds["geometry_program_ref"] = ID_GEOMETRY_PROGRAM_REF;
935
1
        mIds["fragment_program_ref"] = ID_FRAGMENT_PROGRAM_REF;
936
1
        mIds["tessellation_hull_program_ref"] = ID_TESSELLATION_HULL_PROGRAM_REF;
937
1
        mIds["tessellation_domain_program_ref"] = ID_TESSELLATION_DOMAIN_PROGRAM_REF;
938
1
        mIds["compute_program_ref"] = ID_COMPUTE_PROGRAM_REF;
939
1
        mIds["mesh_program_ref"] = ID_MESH_PROGRAM_REF;
940
1
        mIds["task_program_ref"] = ID_TASK_PROGRAM_REF;
941
1
        mIds["shadow_caster_vertex_program_ref"] = ID_SHADOW_CASTER_VERTEX_PROGRAM_REF;
942
1
        mIds["shadow_caster_fragment_program_ref"] = ID_SHADOW_CASTER_FRAGMENT_PROGRAM_REF;
943
1
        mIds["shadow_receiver_vertex_program_ref"] = ID_SHADOW_RECEIVER_VERTEX_PROGRAM_REF;
944
1
        mIds["shadow_receiver_fragment_program_ref"] = ID_SHADOW_RECEIVER_FRAGMENT_PROGRAM_REF;
945
946
1
        mIds["lod_values"] = ID_LOD_VALUES;
947
1
        mIds["lod_strategy"] = ID_LOD_STRATEGY;
948
1
        mIds["lod_distances"] = ID_LOD_DISTANCES;
949
1
        mIds["receive_shadows"] = ID_RECEIVE_SHADOWS;
950
1
        mIds["transparency_casts_shadows"] = ID_TRANSPARENCY_CASTS_SHADOWS;
951
1
        mIds["set_texture_alias"] = ID_SET_TEXTURE_ALIAS;
952
953
1
        mIds["source"] = ID_SOURCE;
954
1
        mIds["syntax"] = ID_SYNTAX;
955
1
        mIds["default_params"] = ID_DEFAULT_PARAMS;
956
1
        mIds["param_indexed"] = ID_PARAM_INDEXED;
957
1
        mIds["param_named"] = ID_PARAM_NAMED;
958
1
        mIds["param_indexed_auto"] = ID_PARAM_INDEXED_AUTO;
959
1
        mIds["param_named_auto"] = ID_PARAM_NAMED_AUTO;
960
961
1
        mIds["scheme"] = ID_SCHEME;
962
1
        mIds["lod_index"] = ID_LOD_INDEX;
963
1
        mIds["shadow_caster_material"] = ID_SHADOW_CASTER_MATERIAL;
964
1
        mIds["shadow_receiver_material"] = ID_SHADOW_RECEIVER_MATERIAL;
965
1
        mIds["gpu_vendor_rule"] = ID_GPU_VENDOR_RULE;
966
1
        mIds["gpu_device_rule"] = ID_GPU_DEVICE_RULE;
967
1
        mIds["include"] = ID_INCLUDE;
968
1
        mIds["exclude"] = ID_EXCLUDE;
969
970
1
        mIds["ambient"] = ID_AMBIENT;
971
1
        mIds["diffuse"] = ID_DIFFUSE;
972
1
        mIds["specular"] = ID_SPECULAR;
973
1
        mIds["emissive"] = ID_EMISSIVE;
974
1
        mIds["vertexcolour"] = ID_VERTEXCOLOUR;
975
1
        mIds["scene_blend"] = ID_SCENE_BLEND;
976
1
        mIds["colour_blend"] = ID_COLOUR_BLEND;
977
1
        mIds["one"] = ID_ONE;
978
1
        mIds["zero"] = ID_ZERO;
979
1
        mIds["dest_colour"] = ID_DEST_COLOUR;
980
1
        mIds["src_colour"] = ID_SRC_COLOUR;
981
1
        mIds["one_minus_src_colour"] = ID_ONE_MINUS_SRC_COLOUR;
982
1
        mIds["one_minus_dest_colour"] = ID_ONE_MINUS_DEST_COLOUR;
983
1
        mIds["dest_alpha"] = ID_DEST_ALPHA;
984
1
        mIds["src_alpha"] = ID_SRC_ALPHA;
985
1
        mIds["one_minus_dest_alpha"] = ID_ONE_MINUS_DEST_ALPHA;
986
1
        mIds["one_minus_src_alpha"] = ID_ONE_MINUS_SRC_ALPHA;
987
1
        mIds["separate_scene_blend"] = ID_SEPARATE_SCENE_BLEND;
988
1
        mIds["scene_blend_op"] = ID_SCENE_BLEND_OP;
989
1
        mIds["reverse_subtract"] = ID_REVERSE_SUBTRACT;
990
1
        mIds["min"] = ID_MIN;
991
1
        mIds["max"] = ID_MAX;
992
1
        mIds["separate_scene_blend_op"] = ID_SEPARATE_SCENE_BLEND_OP;
993
1
        mIds["depth_check"] = ID_DEPTH_CHECK;
994
1
        mIds["depth_write"] = ID_DEPTH_WRITE;
995
1
        mIds["depth_func"] = ID_DEPTH_FUNC;
996
1
        mIds["depth_bias"] = ID_DEPTH_BIAS;
997
1
        mIds["iteration_depth_bias"] = ID_ITERATION_DEPTH_BIAS;
998
1
        mIds["always_fail"] = ID_ALWAYS_FAIL;
999
1
        mIds["always_pass"] = ID_ALWAYS_PASS;
1000
1
        mIds["less_equal"] = ID_LESS_EQUAL;
1001
1
        mIds["less"] = ID_LESS;
1002
1
        mIds["equal"] = ID_EQUAL;
1003
1
        mIds["not_equal"] = ID_NOT_EQUAL;
1004
1
        mIds["greater_equal"] = ID_GREATER_EQUAL;
1005
1
        mIds["greater"] = ID_GREATER;
1006
1
        mIds["alpha_rejection"] = ID_ALPHA_REJECTION;
1007
1
        mIds["alpha_to_coverage"] = ID_ALPHA_TO_COVERAGE;
1008
1
        mIds["light_scissor"] = ID_LIGHT_SCISSOR;
1009
1
        mIds["light_clip_planes"] = ID_LIGHT_CLIP_PLANES;
1010
1
        mIds["transparent_sorting"] = ID_TRANSPARENT_SORTING;
1011
1
        mIds["illumination_stage"] = ID_ILLUMINATION_STAGE;
1012
1
        mIds["decal"] = ID_DECAL;
1013
1
        mIds["cull_hardware"] = ID_CULL_HARDWARE;
1014
1
        mIds["clockwise"] = ID_CLOCKWISE;
1015
1
        mIds["anticlockwise"] = ID_ANTICLOCKWISE;
1016
1
        mIds["cull_software"] = ID_CULL_SOFTWARE;
1017
1
        mIds["back"] = ID_BACK;
1018
1
        mIds["front"] = ID_FRONT;
1019
1
        mIds["lighting"] = ID_LIGHTING;
1020
1
        mIds["shading"] = ID_SHADING;
1021
1
        mIds["flat"] = ID_FLAT;
1022
1
        mIds["gouraud"] = ID_GOURAUD;
1023
1
        mIds["phong"] = ID_PHONG;
1024
1
        mIds["polygon_mode"] = ID_POLYGON_MODE;
1025
1
        mIds["solid"] = ID_SOLID;
1026
1
        mIds["wireframe"] = ID_WIREFRAME;
1027
1
        mIds["points"] = ID_POINTS;
1028
1
        mIds["polygon_mode_overrideable"] = ID_POLYGON_MODE_OVERRIDEABLE;
1029
1
        mIds["fog_override"] = ID_FOG_OVERRIDE;
1030
1
        mIds["none"] = ID_NONE;
1031
1
        mIds["linear"] = ID_LINEAR;
1032
1
        mIds["exp"] = ID_EXP;
1033
1
        mIds["exp2"] = ID_EXP2;
1034
1
        mIds["colour_write"] = ID_COLOUR_WRITE;
1035
1
        mIds["max_lights"] = ID_MAX_LIGHTS;
1036
1
        mIds["start_light"] = ID_START_LIGHT;
1037
1
        mIds["iteration"] = ID_ITERATION;
1038
1
        mIds["once"] = ID_ONCE;
1039
1
        mIds["once_per_light"] = ID_ONCE_PER_LIGHT;
1040
1
        mIds["per_n_lights"] = ID_PER_N_LIGHTS;
1041
1
        mIds["per_light"] = ID_PER_LIGHT;
1042
1
        mIds["point"] = ID_POINT;
1043
1
        mIds["spot"] = ID_SPOT;
1044
1
        mIds["directional"] = ID_DIRECTIONAL;
1045
1
        mIds["light_mask"] = ID_LIGHT_MASK;
1046
1
        mIds["point_size"] = ID_POINT_SIZE;
1047
1
        mIds["point_sprites"] = ID_POINT_SPRITES;
1048
1
        mIds["point_size_min"] = ID_POINT_SIZE_MIN;
1049
1
        mIds["point_size_max"] = ID_POINT_SIZE_MAX;
1050
1
        mIds["point_size_attenuation"] = ID_POINT_SIZE_ATTENUATION;
1051
1052
1
        mIds["texture_alias"] = ID_TEXTURE_ALIAS;
1053
1
        mIds["texture"] = ID_TEXTURE;
1054
1
        mIds["1d"] = ID_1D;
1055
1
        mIds["2d"] = ID_2D;
1056
1
        mIds["3d"] = ID_3D;
1057
1
        mIds["cubic"] = ID_CUBIC;
1058
1
        mIds["unlimited"] = ID_UNLIMITED;
1059
1
        mIds["2darray"] = ID_2DARRAY; // deprecated and undocumented
1060
1
        mIds["2d_array"] = ID_2DARRAY;
1061
1
        mIds["2d_ms"] = ID_2DMS;
1062
1
        mIds["alpha"] = ID_ALPHA;
1063
1
        mIds["gamma"] = ID_GAMMA;
1064
1
        mIds["anim_texture"] = ID_ANIM_TEXTURE;
1065
1
        mIds["cubic_texture"] = ID_CUBIC_TEXTURE;
1066
1
        mIds["separateUV"] = ID_SEPARATE_UV;
1067
1
        mIds["combinedUVW"] = ID_COMBINED_UVW;
1068
1
        mIds["tex_coord_set"] = ID_TEX_COORD_SET;
1069
1
        mIds["tex_address_mode"] = ID_TEX_ADDRESS_MODE;
1070
1
        mIds["wrap"] = ID_WRAP;
1071
1
        mIds["clamp"] = ID_CLAMP;
1072
1
        mIds["mirror"] = ID_MIRROR;
1073
1
        mIds["border"] = ID_BORDER;
1074
1
        mIds["tex_border_colour"] = ID_TEX_BORDER_COLOUR;
1075
1
        mIds["filtering"] = ID_FILTERING;
1076
1
        mIds["bilinear"] = ID_BILINEAR;
1077
1
        mIds["trilinear"] = ID_TRILINEAR;
1078
1
        mIds["anisotropic"] = ID_ANISOTROPIC;
1079
1
        mIds["compare_test"] = ID_CMPTEST;
1080
1
        mIds["compare_func"] = ID_CMPFUNC;
1081
1
        mIds["max_anisotropy"] = ID_MAX_ANISOTROPY;
1082
1
        mIds["mipmap_bias"] = ID_MIPMAP_BIAS;
1083
1
        mIds["colour_op"] = ID_COLOUR_OP;
1084
1
        mIds["replace"] = ID_REPLACE;
1085
1
        mIds["add"] = ID_ADD;
1086
1
        mIds["modulate"] = ID_MODULATE;
1087
1
        mIds["alpha_blend"] = ID_ALPHA_BLEND;
1088
1
        mIds["colour_op_ex"] = ID_COLOUR_OP_EX;
1089
1
        mIds["source1"] = ID_SOURCE1;
1090
1
        mIds["source2"] = ID_SOURCE2;
1091
1
        mIds["modulate"] = ID_MODULATE;
1092
1
        mIds["modulate_x2"] = ID_MODULATE_X2;
1093
1
        mIds["modulate_x4"] = ID_MODULATE_X4;
1094
1
        mIds["add"] = ID_ADD;
1095
1
        mIds["add_signed"] = ID_ADD_SIGNED;
1096
1
        mIds["add_smooth"] = ID_ADD_SMOOTH;
1097
1
        mIds["subtract"] = ID_SUBTRACT;
1098
1
        mIds["blend_diffuse_alpha"] = ID_BLEND_DIFFUSE_ALPHA;
1099
1
        mIds["blend_texture_alpha"] = ID_BLEND_TEXTURE_ALPHA;
1100
1
        mIds["blend_current_alpha"] = ID_BLEND_CURRENT_ALPHA;
1101
1
        mIds["blend_manual"] = ID_BLEND_MANUAL;
1102
1
        mIds["dotproduct"] = ID_DOT_PRODUCT;
1103
1
        mIds["blend_diffuse_colour"] = ID_BLEND_DIFFUSE_COLOUR;
1104
1
        mIds["src_current"] = ID_SRC_CURRENT;
1105
1
        mIds["src_texture"] = ID_SRC_TEXTURE;
1106
1
        mIds["src_diffuse"] = ID_SRC_DIFFUSE;
1107
1
        mIds["src_specular"] = ID_SRC_SPECULAR;
1108
1
        mIds["src_manual"] = ID_SRC_MANUAL;
1109
1
        mIds["colour_op_multipass_fallback"] = ID_COLOUR_OP_MULTIPASS_FALLBACK;
1110
1
        mIds["alpha_op_ex"] = ID_ALPHA_OP_EX;
1111
1
        mIds["env_map"] = ID_ENV_MAP;
1112
1
        mIds["spherical"] = ID_SPHERICAL;
1113
1
        mIds["planar"] = ID_PLANAR;
1114
1
        mIds["cubic_reflection"] = ID_CUBIC_REFLECTION;
1115
1
        mIds["cubic_normal"] = ID_CUBIC_NORMAL;
1116
1
        mIds["scroll"] = ID_SCROLL;
1117
1
        mIds["scroll_anim"] = ID_SCROLL_ANIM;
1118
1
        mIds["rotate"] = ID_ROTATE;
1119
1
        mIds["rotate_anim"] = ID_ROTATE_ANIM;
1120
1
        mIds["scale"] = ID_SCALE;
1121
1
        mIds["wave_xform"] = ID_WAVE_XFORM;
1122
1
        mIds["scroll_x"] = ID_SCROLL_X;
1123
1
        mIds["scroll_y"] = ID_SCROLL_Y;
1124
1
        mIds["scale_x"] = ID_SCALE_X;
1125
1
        mIds["scale_y"] = ID_SCALE_Y;
1126
1
        mIds["sine"] = ID_SINE;
1127
1
        mIds["triangle"] = ID_TRIANGLE;
1128
1
        mIds["sawtooth"] = ID_SAWTOOTH;
1129
1
        mIds["square"] = ID_SQUARE;
1130
1
        mIds["inverse_sawtooth"] = ID_INVERSE_SAWTOOTH;
1131
1
        mIds["transform"] = ID_TRANSFORM;
1132
1
        mIds["geometry"] = ID_GEOMETRY;
1133
1
        mIds["tessellation_hull"] = ID_TESSELLATION_HULL;
1134
1
        mIds["tessellation_domain"] = ID_TESSELLATION_DOMAIN;
1135
1
        mIds["compute"] = ID_COMPUTE;
1136
1
        mIds["content_type"] = ID_CONTENT_TYPE;
1137
1
        mIds["named"] = ID_NAMED;
1138
1
        mIds["shadow"] = ID_SHADOW;
1139
1
        mIds["texture_source"] = ID_TEXTURE_SOURCE;
1140
1
        mIds["shared_params"] = ID_SHARED_PARAMS;
1141
1
        mIds["shared_param_named"] = ID_SHARED_PARAM_NAMED;
1142
1
        mIds["shared_params_ref"] = ID_SHARED_PARAMS_REF;
1143
1
        mIds["use_linear_colours"] = ID_USE_LINEAR_COLOURS;
1144
1145
        // Particle system
1146
1
        mIds["particle_system"] = ID_PARTICLE_SYSTEM;
1147
1
        mIds["emitter"] = ID_EMITTER;
1148
1
        mIds["affector"] = ID_AFFECTOR;
1149
1150
        // Compositor
1151
1
        mIds["compositor"] = ID_COMPOSITOR;
1152
1
        mIds["target"] = ID_TARGET;
1153
1
        mIds["target_output"] = ID_TARGET_OUTPUT;
1154
1155
1
        mIds["input"] = ID_INPUT;
1156
        //mIds["none"] = ID_NONE; - already registered
1157
1
        mIds["previous"] = ID_PREVIOUS;
1158
1
        mIds["target_width"] = ID_TARGET_WIDTH;
1159
1
        mIds["target_height"] = ID_TARGET_HEIGHT;
1160
1
        mIds["target_width_scaled"] = ID_TARGET_WIDTH_SCALED;
1161
1
        mIds["target_height_scaled"] = ID_TARGET_HEIGHT_SCALED;
1162
1
        mIds["pooled"] = ID_POOLED;
1163
        //mIds["gamma"] = ID_GAMMA; - already registered
1164
1
        mIds["no_fsaa"] = ID_NO_FSAA;
1165
1
        mIds["fsaa"] = ID_FSAA;
1166
1
        mIds["depth_pool"] = ID_DEPTH_POOL;
1167
1168
1
        mIds["texture_ref"] = ID_TEXTURE_REF;
1169
1
        mIds["local_scope"] = ID_SCOPE_LOCAL;
1170
1
        mIds["chain_scope"] = ID_SCOPE_CHAIN;
1171
1
        mIds["global_scope"] = ID_SCOPE_GLOBAL;
1172
1
        mIds["compositor_logic"] = ID_COMPOSITOR_LOGIC;
1173
1174
1
        mIds["only_initial"] = ID_ONLY_INITIAL;
1175
1
        mIds["visibility_mask"] = ID_VISIBILITY_MASK;
1176
1
        mIds["lod_bias"] = ID_LOD_BIAS;
1177
1
        mIds["material_scheme"] = ID_MATERIAL_SCHEME;
1178
1
        mIds["shadows"] = ID_SHADOWS_ENABLED;
1179
1180
1
        mIds["clear"] = ID_CLEAR;
1181
1
        mIds["stencil"] = ID_STENCIL;
1182
1
        mIds["render_scene"] = ID_RENDER_SCENE;
1183
1
        mIds["render_quad"] = ID_RENDER_QUAD;
1184
1
        mIds["identifier"] = ID_IDENTIFIER;
1185
1
        mIds["first_render_queue"] = ID_FIRST_RENDER_QUEUE;
1186
1
        mIds["last_render_queue"] = ID_LAST_RENDER_QUEUE;
1187
1
        mIds["quad_normals"] = ID_QUAD_NORMALS;
1188
1
        mIds["camera_far_corners_view_space"] = ID_CAMERA_FAR_CORNERS_VIEW_SPACE;
1189
1
        mIds["camera_far_corners_world_space"] = ID_CAMERA_FAR_CORNERS_WORLD_SPACE;
1190
1191
1
        mIds["buffers"] = ID_BUFFERS;
1192
1
        mIds["colour"] = ID_COLOUR;
1193
1
        mIds["depth"] = ID_DEPTH;
1194
1
        mIds["colour_value"] = ID_COLOUR_VALUE;
1195
1
        mIds["depth_value"] = ID_DEPTH_VALUE;
1196
1
        mIds["stencil_value"] = ID_STENCIL_VALUE;
1197
1198
1
        mIds["check"] = ID_CHECK;
1199
1
        mIds["comp_func"] = ID_COMP_FUNC;
1200
1
        mIds["ref_value"] = ID_REF_VALUE;
1201
1
        mIds["mask"] = ID_MASK;
1202
1
        mIds["fail_op"] = ID_FAIL_OP;
1203
1
        mIds["keep"] = ID_KEEP;
1204
1
        mIds["increment"] = ID_INCREMENT;
1205
1
        mIds["decrement"] = ID_DECREMENT;
1206
1
        mIds["increment_wrap"] = ID_INCREMENT_WRAP;
1207
1
        mIds["decrement_wrap"] = ID_DECREMENT_WRAP;
1208
1
        mIds["invert"] = ID_INVERT;
1209
1
        mIds["depth_fail_op"] = ID_DEPTH_FAIL_OP;
1210
1
        mIds["pass_op"] = ID_PASS_OP;
1211
1
        mIds["two_sided"] = ID_TWO_SIDED;
1212
1213
1
        mIds["line_width"] = ID_LINE_WIDTH;
1214
1
        mIds["sampler"] = ID_SAMPLER;
1215
1
        mIds["sampler_ref"] = ID_SAMPLER_REF;
1216
1
        mIds["thread_groups"] = ID_THREAD_GROUPS;
1217
1
        mIds["render_custom"] = ID_RENDER_CUSTOM;
1218
1
        mIds["auto"] = ID_AUTO;
1219
1
        mIds["camera"] = ID_CAMERA;
1220
1
        mIds["align_to_face"] = ID_ALIGN_TO_FACE;
1221
1
        mIds["unordered_access_mip"] = ID_UNORDERED_ACCESS_MIP;
1222
1223
1
    mLargestRegisteredWordId = ID_END_BUILTIN_IDS;
1224
1
  }
1225
1226
  uint32 ScriptCompiler::registerCustomWordId(const String &word)
1227
0
  {
1228
    // if the word is already registered, just return the right id
1229
0
    IdMap::iterator iter = mIds.find(word);
1230
0
    if(iter != mIds.end())
1231
0
      return iter->second;
1232
1233
    // As there are no other function changing mIds than registerCustomWordId and initWordMap,
1234
    // we know that mLargestRegisteredWordId is the largest word id and therefore mLargestRegisteredWordId+1
1235
    // wasn't used yet.
1236
0
    mLargestRegisteredWordId++;
1237
0
    mIds[word] = mLargestRegisteredWordId;
1238
0
    return mLargestRegisteredWordId;
1239
0
    }
1240
1241
    // AbstractTreeeBuilder
1242
    ScriptCompiler::AbstractTreeBuilder::AbstractTreeBuilder(ScriptCompiler *compiler)
1243
0
        :mNodes(std::make_shared<AbstractNodeList>()), mCurrent(0), mCompiler(compiler)
1244
0
    {
1245
0
    }
1246
1247
    const AbstractNodeListPtr &ScriptCompiler::AbstractTreeBuilder::getResult() const
1248
0
    {
1249
0
        return mNodes;
1250
0
    }
1251
1252
    void ScriptCompiler::AbstractTreeBuilder::visit(ConcreteNode *node)
1253
0
    {
1254
0
        AbstractNodePtr asn;
1255
1256
        // Import = "import" >> 2 children, mCurrent == null
1257
0
        if(node->type == CNT_IMPORT && mCurrent == 0)
1258
0
        {
1259
0
            if(node->children.size() > 2)
1260
0
            {
1261
0
                mCompiler->addError(CE_FEWERPARAMETERSEXPECTED, node->file, node->line);
1262
0
                return;
1263
0
            }
1264
0
            if(node->children.size() < 2)
1265
0
            {
1266
0
                mCompiler->addError(CE_STRINGEXPECTED, node->file, node->line);
1267
0
                return;
1268
0
            }
1269
1270
0
            ImportAbstractNode *impl = OGRE_NEW ImportAbstractNode();
1271
0
            impl->line = node->line;
1272
0
            impl->file = node->file;
1273
1274
0
            ConcreteNodeList::iterator iter = node->children.begin();
1275
0
            impl->target = (*iter)->token;
1276
1277
0
            iter++;
1278
0
            impl->source = (*iter)->token;
1279
1280
0
            asn = AbstractNodePtr(impl);
1281
0
        }
1282
        // variable set = "set" >> 2 children, children[0] == variable
1283
0
        else if(node->type == CNT_VARIABLE_ASSIGN)
1284
0
        {
1285
0
            if(node->children.size() > 2)
1286
0
            {
1287
0
                mCompiler->addError(CE_FEWERPARAMETERSEXPECTED, node->file, node->line);
1288
0
                return;
1289
0
            }
1290
0
            if(node->children.size() < 2)
1291
0
            {
1292
0
                mCompiler->addError(CE_STRINGEXPECTED, node->file, node->line);
1293
0
                return;
1294
0
            }
1295
0
            if(node->children.front()->type != CNT_VARIABLE)
1296
0
            {
1297
0
                mCompiler->addError(CE_VARIABLEEXPECTED, node->children.front()->file, node->children.front()->line);
1298
0
                return;
1299
0
            }
1300
1301
0
            ConcreteNodeList::iterator i = node->children.begin();
1302
0
            String name = (*i)->token;
1303
1304
0
            ++i;
1305
0
            String value = (*i)->token;
1306
1307
0
            if(mCurrent && mCurrent->type == ANT_OBJECT)
1308
0
            {
1309
0
                ObjectAbstractNode *ptr = (ObjectAbstractNode*)mCurrent;
1310
0
                ptr->setVariable(name, value);
1311
0
            }
1312
0
            else
1313
0
            {
1314
0
                mCompiler->mEnv.insert(std::make_pair(name, value));
1315
0
            }
1316
0
        }
1317
        // variable = $*, no children
1318
0
        else if(node->type == CNT_VARIABLE)
1319
0
        {
1320
0
            if(!node->children.empty())
1321
0
            {
1322
0
                mCompiler->addError(CE_FEWERPARAMETERSEXPECTED, node->file, node->line);
1323
0
                return;
1324
0
            }
1325
1326
0
            VariableAccessAbstractNode *impl = OGRE_NEW VariableAccessAbstractNode(mCurrent);
1327
0
            impl->line = node->line;
1328
0
            impl->file = node->file;
1329
0
            impl->name = node->token;
1330
1331
0
            asn = AbstractNodePtr(impl);
1332
0
        }
1333
        // Handle properties and objects here
1334
0
        else if(!node->children.empty())
1335
0
        {
1336
            // Grab the last two nodes
1337
0
            ConcreteNodePtr temp1, temp2;
1338
0
            ConcreteNodeList::reverse_iterator riter = node->children.rbegin();
1339
0
            if(riter != node->children.rend())
1340
0
            {
1341
0
                temp1 = *riter;
1342
0
                riter++;
1343
0
            }
1344
0
            if(riter != node->children.rend())
1345
0
                temp2 = *riter;
1346
1347
            // object = last 2 children == { and }
1348
0
            if(temp1 && temp2 &&
1349
0
                temp1->type == CNT_RBRACE && temp2->type == CNT_LBRACE)
1350
0
            {
1351
0
                if(node->children.size() < 2)
1352
0
                {
1353
0
                    mCompiler->addError(CE_STRINGEXPECTED, node->file, node->line);
1354
0
                    return;
1355
0
                }
1356
1357
0
                ObjectAbstractNode *impl = OGRE_NEW ObjectAbstractNode(mCurrent);
1358
0
                impl->line = node->line;
1359
0
                impl->file = node->file;
1360
0
                impl->abstract = false;
1361
1362
                // Create a temporary detail list
1363
0
                std::list<ConcreteNode*> temp;
1364
0
                if(node->token == "abstract")
1365
0
                {
1366
0
                    impl->abstract = true;
1367
0
                    for(const auto& c : node->children)
1368
0
                        temp.push_back(c.get());
1369
0
                }
1370
0
                else
1371
0
                {
1372
0
                    temp.push_back(node);
1373
0
                    for(const auto& c : node->children)
1374
0
                        temp.push_back(c.get());
1375
0
                }
1376
1377
                // Get the type of object
1378
0
                std::list<ConcreteNode*>::const_iterator iter = temp.begin();
1379
0
                impl->cls = (*iter)->token;
1380
0
                ++iter;
1381
1382
                // try to map the cls to an id
1383
0
                ScriptCompiler::IdMap::const_iterator iter2 = mCompiler->mIds.find(impl->cls);
1384
0
                if(iter2 != mCompiler->mIds.end())
1385
0
                {
1386
0
                    impl->id = iter2->second;
1387
0
                }
1388
0
                else
1389
0
                {
1390
0
                    mCompiler->addError(CE_UNEXPECTEDTOKEN, impl->file, impl->line,
1391
0
                                        "'" + impl->cls + "'. If this is a legacy script you must prepend the type (e.g. font, overlay).");
1392
0
                }
1393
1394
                // Get the name
1395
                // Unless the type is in the exclusion list
1396
0
                if(iter != temp.end() && ((*iter)->type == CNT_WORD || (*iter)->type == CNT_QUOTE || (*iter)->type == CNT_VARIABLE) &&
1397
0
                    !mCompiler->isNameExcluded(*impl, mCurrent))
1398
0
                {
1399
0
                    impl->name = (*iter)->token;
1400
0
                    ++iter;
1401
0
                }
1402
1403
                // Everything up until the colon is a "value" of this object
1404
0
                while(iter != temp.end() && (*iter)->type != CNT_COLON && (*iter)->type != CNT_LBRACE)
1405
0
                {
1406
0
                    if((*iter)->type == CNT_VARIABLE)
1407
0
                    {
1408
0
                        VariableAccessAbstractNode *var = OGRE_NEW VariableAccessAbstractNode(impl);
1409
0
                        var->file = (*iter)->file;
1410
0
                        var->line = (*iter)->line;
1411
0
                        var->type = ANT_VARIABLE_ACCESS;
1412
0
                        var->name = (*iter)->token;
1413
0
                        impl->values.push_back(AbstractNodePtr(var));
1414
0
                    }
1415
0
                    else
1416
0
                    {
1417
0
                        AtomAbstractNode *atom = OGRE_NEW AtomAbstractNode(impl);
1418
0
                        atom->file = (*iter)->file;
1419
0
                        atom->line = (*iter)->line;
1420
0
                        atom->type = ANT_ATOM;
1421
0
                        atom->value = (*iter)->token;
1422
1423
0
                        auto idpos = mCompiler->mIds.find(atom->value);
1424
0
                        if(idpos != mCompiler->mIds.end())
1425
0
                            atom->id = idpos->second;
1426
1427
0
                        impl->values.push_back(AbstractNodePtr(atom));
1428
0
                    }
1429
0
                    ++iter;
1430
0
                }
1431
1432
                // Find the bases
1433
0
                if(iter != temp.end() && (*iter)->type == CNT_COLON)
1434
0
                {
1435
                    // Children of the ':' are bases
1436
0
                    for(auto & j : (*iter)->children)
1437
0
                        impl->bases.push_back(j->token);
1438
0
                    ++iter;
1439
0
                }
1440
1441
0
                asn = AbstractNodePtr(impl);
1442
0
                mCurrent = impl;
1443
1444
                // Visit the children of the {
1445
0
                AbstractTreeBuilder::visit(this, temp2->children);
1446
1447
                // Go back up the stack
1448
0
                mCurrent = impl->parent;
1449
0
            }
1450
            // Otherwise, it is a property
1451
0
            else
1452
0
            {
1453
0
                PropertyAbstractNode *impl = OGRE_NEW PropertyAbstractNode(mCurrent);
1454
0
                impl->line = node->line;
1455
0
                impl->file = node->file;
1456
0
                impl->name = node->token;
1457
1458
0
                ScriptCompiler::IdMap::const_iterator iter2 = mCompiler->mIds.find(impl->name);
1459
0
                if(iter2 != mCompiler->mIds.end())
1460
0
                    impl->id = iter2->second;
1461
1462
0
                asn = AbstractNodePtr(impl);
1463
0
                mCurrent = impl;
1464
1465
                // Visit the children of the {
1466
0
                AbstractTreeBuilder::visit(this, node->children);
1467
1468
                // Go back up the stack
1469
0
                mCurrent = impl->parent;
1470
0
            }
1471
0
        }
1472
        // Otherwise, it is a standard atom
1473
0
        else
1474
0
        {
1475
0
            AtomAbstractNode *impl = OGRE_NEW AtomAbstractNode(mCurrent);
1476
0
            impl->line = node->line;
1477
0
            impl->file = node->file;
1478
0
            impl->value = node->token;
1479
1480
0
            ScriptCompiler::IdMap::const_iterator iter2 = mCompiler->mIds.find(impl->value);
1481
0
            if(iter2 != mCompiler->mIds.end())
1482
0
                impl->id = iter2->second;
1483
1484
0
            asn = AbstractNodePtr(impl);
1485
1486
0
            if(mCurrent && mCurrent->type != ANT_PROPERTY)
1487
0
            {
1488
                // stray atom outside of a property is likely a property without a value
1489
0
                mCompiler->addError(*impl, "missing property value");
1490
0
            }
1491
0
        }
1492
1493
        // Here, we must insert the node into the tree
1494
0
        if(asn)
1495
0
        {
1496
0
            if(mCurrent)
1497
0
            {
1498
0
                if(mCurrent->type == ANT_PROPERTY)
1499
0
                {
1500
0
                    PropertyAbstractNode *impl = static_cast<PropertyAbstractNode*>(mCurrent);
1501
0
                    impl->values.push_back(asn);
1502
0
                }
1503
0
                else
1504
0
                {
1505
0
                    ObjectAbstractNode *impl = static_cast<ObjectAbstractNode*>(mCurrent);
1506
0
                    impl->children.push_back(asn);
1507
0
                }
1508
0
            }
1509
0
            else
1510
0
            {
1511
0
                mNodes->push_back(asn);
1512
0
            }
1513
0
        }
1514
0
    }
1515
1516
    void ScriptCompiler::AbstractTreeBuilder::visit(AbstractTreeBuilder *visitor, const ConcreteNodeList &nodes)
1517
0
    {
1518
0
        for(const auto & node : nodes)
1519
0
            visitor->visit(node.get());
1520
0
    }
1521
1522
1523
    // ScriptCompilerManager
1524
    template<> ScriptCompilerManager *Singleton<ScriptCompilerManager>::msSingleton = 0;
1525
1526
    ScriptCompilerManager* ScriptCompilerManager::getSingletonPtr(void)
1527
0
    {
1528
0
        return msSingleton;
1529
0
    }
1530
    //-----------------------------------------------------------------------
1531
    ScriptCompilerManager& ScriptCompilerManager::getSingleton(void)
1532
0
    {
1533
0
        assert( msSingleton );  return ( *msSingleton );
1534
0
    }
1535
    //-----------------------------------------------------------------------
1536
    ScriptCompilerManager::ScriptCompilerManager()
1537
1
    {
1538
1
            OGRE_LOCK_AUTO_MUTEX;
1539
1
        mScriptPatterns.push_back("*.program");
1540
1
        mScriptPatterns.push_back("*.material");
1541
1
        mScriptPatterns.push_back("*.particle");
1542
1
        mScriptPatterns.push_back("*.compositor");
1543
1
        mScriptPatterns.push_back("*.os");
1544
1
        ResourceGroupManager::getSingleton()._registerScriptLoader(this);
1545
1546
1
        mBuiltinTranslatorManager = OGRE_NEW BuiltinScriptTranslatorManager();
1547
1
        mManagers.push_back(mBuiltinTranslatorManager);
1548
1
    }
1549
    //-----------------------------------------------------------------------
1550
    ScriptCompilerManager::~ScriptCompilerManager()
1551
1
    {
1552
1
        OGRE_DELETE mBuiltinTranslatorManager;
1553
1
    }
1554
    //-----------------------------------------------------------------------
1555
    void ScriptCompilerManager::setListener(ScriptCompilerListener *listener)
1556
0
    {
1557
0
            OGRE_LOCK_AUTO_MUTEX;
1558
0
        mScriptCompiler.setListener(listener);
1559
0
    }
1560
    //-----------------------------------------------------------------------
1561
    ScriptCompilerListener *ScriptCompilerManager::getListener()
1562
0
    {
1563
0
        return mScriptCompiler.getListener();
1564
0
    }
1565
    //-----------------------------------------------------------------------
1566
    void ScriptCompilerManager::addTranslatorManager(Ogre::ScriptTranslatorManager *man)
1567
0
    {
1568
0
            OGRE_LOCK_AUTO_MUTEX;
1569
0
        mManagers.push_back(man);
1570
0
    }
1571
    //-----------------------------------------------------------------------
1572
    void ScriptCompilerManager::removeTranslatorManager(Ogre::ScriptTranslatorManager *man)
1573
0
    {
1574
0
            OGRE_LOCK_AUTO_MUTEX;
1575
1576
0
        for(std::vector<ScriptTranslatorManager*>::iterator i = mManagers.begin(); i != mManagers.end(); ++i)
1577
0
        {
1578
0
            if(*i == man)
1579
0
            {
1580
0
                mManagers.erase(i);
1581
0
                break;
1582
0
            }
1583
0
        }
1584
0
    }
1585
    //-------------------------------------------------------------------------
1586
    void ScriptCompilerManager::clearTranslatorManagers()
1587
0
    {
1588
0
        mManagers.clear();
1589
0
    }
1590
    //-----------------------------------------------------------------------
1591
    ScriptTranslator *ScriptCompilerManager::getTranslator(const AbstractNodePtr &node)
1592
0
    {
1593
0
        ScriptTranslator *translator = 0;
1594
0
        {
1595
0
                    OGRE_LOCK_AUTO_MUTEX;
1596
1597
            // Start looking from the back
1598
0
            for(std::vector<ScriptTranslatorManager*>::reverse_iterator i = mManagers.rbegin(); i != mManagers.rend(); ++i)
1599
0
            {
1600
0
                translator = (*i)->getTranslator(node);
1601
0
                if(translator != 0)
1602
0
                    break;
1603
0
            }
1604
0
        }
1605
0
        return translator;
1606
0
  }
1607
  //-----------------------------------------------------------------------
1608
  uint32 ScriptCompilerManager::registerCustomWordId(const String &word)
1609
0
  {
1610
0
    return mScriptCompiler.registerCustomWordId(word);
1611
0
    }
1612
    //-----------------------------------------------------------------------
1613
    void ScriptCompilerManager::addScriptPattern(const String &pattern)
1614
0
    {
1615
0
        mScriptPatterns.push_back(pattern);
1616
0
    }
1617
    //-----------------------------------------------------------------------
1618
    const StringVector& ScriptCompilerManager::getScriptPatterns(void) const
1619
0
    {
1620
0
        return mScriptPatterns;
1621
0
    }
1622
    //-----------------------------------------------------------------------
1623
    Real ScriptCompilerManager::getLoadingOrder(void) const
1624
1
    {
1625
        /// Load relatively early, before most script loaders run
1626
1
        return 90.0f;
1627
1
    }
1628
    //-----------------------------------------------------------------------
1629
    void ScriptCompilerManager::parseScript(DataStreamPtr& stream, const String& groupName)
1630
0
    {
1631
0
        ConcreteNodeListPtr nodes =
1632
0
            ScriptParser::parse(ScriptLexer::tokenize(stream->getAsString(), stream->getName()), stream->getName());
1633
0
        {
1634
            // compile is not reentrant
1635
0
            OGRE_LOCK_AUTO_MUTEX;
1636
0
            mScriptCompiler.compile(nodes, groupName);
1637
0
        }
1638
0
    }
1639
1640
    //-------------------------------------------------------------------------
1641
    String ProcessResourceNameScriptCompilerEvent::eventType = "processResourceName";
1642
    //-------------------------------------------------------------------------
1643
    String ProcessNameExclusionScriptCompilerEvent::eventType = "processNameExclusion";
1644
    //----------------------------------------------------------------------------
1645
    String CreateMaterialScriptCompilerEvent::eventType = "createMaterial";
1646
    //----------------------------------------------------------------------------
1647
    String CreateGpuProgramScriptCompilerEvent::eventType = "createGpuProgram";
1648
    //-------------------------------------------------------------------------
1649
    String CreateGpuSharedParametersScriptCompilerEvent::eventType = "createGpuSharedParameters";
1650
    //-------------------------------------------------------------------------
1651
    String CreateParticleSystemScriptCompilerEvent::eventType = "createParticleSystem";
1652
    //-------------------------------------------------------------------------
1653
    String CreateCompositorScriptCompilerEvent::eventType = "createCompositor";
1654
}
1655
1656