• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env vpython3
2#
3# [VPYTHON:BEGIN]
4# wheel: <
5#   name: "infra/python/wheels/perfect-hash-py2_py3"
6#   version: "version:0.2.1"
7# >
8# [VPYTHON:END]
9#
10# Copyright 2018 The ANGLE Project Authors. All rights reserved.
11# Use of this source code is governed by a BSD-style license that can be
12# found in the LICENSE file.
13#
14# gen_builtin_symbols.py:
15#  Code generation for the built-in symbol tables.
16import sys
17
18# Conditional import enables getting inputs/outputs with python3 instead of vpython3
19if len(sys.argv) < 2:
20    from perfect_hash import generate_hash, Hash2
21
22from collections import OrderedDict
23import argparse
24import copy
25import hashlib
26import json
27import re
28import os
29import random
30
31template_immutablestring_cpp = """// GENERATED FILE - DO NOT EDIT.
32// Generated by {script_name} using data from {variable_data_source_name} and
33// {function_data_source_name}.
34//
35// Copyright 2020 The ANGLE Project Authors. All rights reserved.
36// Use of this source code is governed by a BSD-style license that can be
37// found in the LICENSE file.
38//
39// ImmutableString_{source_label}autogen.cpp: Wrapper for static or pool allocated char arrays, that are guaranteed to be
40// valid and unchanged for the duration of the compilation.
41// Implements mangledNameHash using perfect hash function from gen_builtin_symbols.py
42
43#include "compiler/translator/ImmutableString.h"
44
45std::ostream &operator<<(std::ostream &os, const sh::ImmutableString &str)
46{{
47    return os.write(str.data(), str.length());
48}}
49
50#if defined(_MSC_VER)
51#    pragma warning(disable : 4309)  // truncation of constant value
52#endif
53
54
55namespace
56{{
57
58constexpr int mangledkT1[] = {{{mangled_S1}}};
59constexpr int mangledkT2[] = {{{mangled_S2}}};
60constexpr int mangledkG[] = {{{mangled_G}}};
61
62int MangledHashG(const char *key, const int *T)
63{{
64    int sum = 0;
65
66    for (int i = 0; key[i] != '\\0'; i++)
67    {{
68        sum += T[i] * key[i];
69        sum %= {mangled_NG};
70    }}
71    return mangledkG[sum];
72}}
73
74int MangledPerfectHash(const char *key)
75{{
76    if (strlen(key) > {mangled_NS})
77        return 0;
78
79    return (MangledHashG(key, mangledkT1) + MangledHashG(key, mangledkT2)) % {mangled_NG};
80}}
81
82constexpr int unmangledkT1[] = {{{unmangled_S1}}};
83constexpr int unmangledkT2[] = {{{unmangled_S2}}};
84constexpr int unmangledkG[] = {{{unmangled_G}}};
85
86int UnmangledHashG(const char *key, const int *T)
87{{
88    int sum = 0;
89
90    for (int i = 0; key[i] != '\\0'; i++)
91    {{
92        sum += T[i] * key[i];
93        sum %= {unmangled_NG};
94    }}
95    return unmangledkG[sum];
96}}
97
98int UnmangledPerfectHash(const char *key)
99{{
100    if (strlen(key) > {unmangled_NS})
101        return 0;
102
103    return (UnmangledHashG(key, unmangledkT1) + UnmangledHashG(key, unmangledkT2)) % {unmangled_NG};
104}}
105
106}}
107
108namespace sh
109{{
110
111template <>
112const size_t ImmutableString::FowlerNollVoHash<4>::kFnvPrime = 16777619u;
113
114template <>
115const size_t ImmutableString::FowlerNollVoHash<4>::kFnvOffsetBasis = 0x811c9dc5u;
116
117template <>
118const size_t ImmutableString::FowlerNollVoHash<8>::kFnvPrime =
119    static_cast<size_t>(1099511628211ull);
120
121template <>
122const size_t ImmutableString::FowlerNollVoHash<8>::kFnvOffsetBasis =
123    static_cast<size_t>(0xcbf29ce484222325ull);
124
125uint32_t ImmutableString::mangledNameHash() const
126{{
127    return MangledPerfectHash(data());
128}}
129
130uint32_t ImmutableString::unmangledNameHash() const
131{{
132    return UnmangledPerfectHash(data());
133}}
134
135}}  // namespace sh
136"""
137
138template_immutablestringtest_cpp = """// GENERATED FILE - DO NOT EDIT.
139// Generated by {script_name} using data from {function_data_source_name}.
140//
141// Copyright 2020 The ANGLE Project Authors. All rights reserved.
142// Use of this source code is governed by a BSD-style license that can be
143// found in the LICENSE file.
144//
145// ImmutableString_test_{source_label}autogen.cpp:
146//   Tests for matching script-generated hashes with runtime computed hashes.
147
148#include "compiler/translator/ImmutableString.h"
149#include "gtest/gtest.h"
150
151namespace sh
152{{
153
154TEST(ImmutableStringTest, ScriptGeneratedHashesMatch)
155{{
156{script_generated_hash_tests}
157{unmangled_script_generated_hash_tests}
158}}
159
160}}  // namespace sh
161"""
162
163# The header file has a "get" function for each variable. They are used in traversers.
164# It also declares id values of built-ins with human readable names, so they can be used to identify built-ins.
165template_builtin_header = """// GENERATED FILE - DO NOT EDIT.
166// Generated by {script_name} using data from {variable_data_source_name} and
167// {function_data_source_name}.
168//
169// Copyright 2020 The ANGLE Project Authors. All rights reserved.
170// Use of this source code is governed by a BSD-style license that can be
171// found in the LICENSE file.
172//
173// BuiltIn_{header_label}autogen.h:
174//   Compile-time initialized built-ins.
175
176#ifndef COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
177#define COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
178
179#include "compiler/translator/SymbolUniqueId.h"
180
181namespace sh
182{{
183
184class TVariable;
185
186class BuiltInId
187{{
188public:
189
190{builtin_id_declarations}
191
192}};  // class BuiltInId
193
194namespace BuiltInVariable
195{{
196
197{get_variable_declarations}
198
199}}  // namespace BuiltInVariable
200
201}}  // namespace sh
202
203#endif  // COMPILER_TRANSLATOR_TREEUTIL_BUILTIN_AUTOGEN_H_
204"""
205
206template_symboltable_header = """// GENERATED FILE - DO NOT EDIT.
207// Generated by {script_name} using data from {variable_data_source_name} and
208// {function_data_source_name}.
209//
210// Copyright 2020 The ANGLE Project Authors. All rights reserved.
211// Use of this source code is governed by a BSD-style license that can be
212// found in the LICENSE file.
213//
214// SymbolTable_autogen.h:
215//   Autogenerated member variables of TSymbolTable.
216
217#ifndef COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
218#define COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
219
220namespace sh
221{{
222
223class TSymbolTableBase
224{{
225  public:
226    TSymbolTableBase() = default;
227{declare_member_variables}
228}};
229
230}}  // namespace sh
231
232#endif  // COMPILER_TRANSLATOR_SYMBOLTABLE_AUTOGEN_H_
233"""
234
235# By having the variables defined in a cpp file we ensure that there's just one instance of each of the declared variables.
236template_symboltable_cpp = """// GENERATED FILE - DO NOT EDIT.
237// Generated by {script_name} using data from {variable_data_source_name} and
238// {function_data_source_name}.
239//
240// Copyright 2020 The ANGLE Project Authors. All rights reserved.
241// Use of this source code is governed by a BSD-style license that can be
242// found in the LICENSE file.
243//
244// SymbolTable_{source_label}autogen.cpp:
245//   Compile-time initialized built-ins.
246
247#include "compiler/translator/SymbolTable.h"
248
249#include "angle_gl.h"
250#include "compiler/translator/tree_util/BuiltIn.h"
251#include "compiler/translator/ImmutableString.h"
252#include "compiler/translator/StaticType.h"
253#include "compiler/translator/Symbol.h"
254#include "compiler/translator/SymbolTable.h"
255
256namespace sh
257{{
258using Resources = ShBuiltInResources;
259using TableBase = TSymbolTableBase;
260
261const int TSymbolTable::kLastBuiltInId = {last_builtin_id};
262
263namespace BuiltInName
264{{
265
266constexpr const ImmutableString _empty("");
267{name_declarations}
268
269}}  // namespace BuiltInName
270
271// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend
272// this from TVariable. Now symbol constructors taking an id have to be public even though they're
273// not supposed to be accessible from outside of here. http://anglebug.com/2390
274namespace BuiltInVariable
275{{
276
277{type_array_sizes_declarations}
278
279{variable_declarations}
280
281{get_variable_definitions}
282
283}}  // namespace BuiltInVariable
284
285namespace BuiltInParameters
286{{
287
288{parameter_declarations}
289
290}}  // namespace BuiltInParameters
291
292// TODO(oetuaho): Would be nice to make this a class instead of a namespace so that we could friend
293// this from TFunction. Now symbol constructors taking an id have to be public even though they're
294// not supposed to be accessible from outside of here. http://anglebug.com/2390
295namespace Func
296{{
297
298{function_declarations}
299
300}}  // namespace Func
301
302namespace BuiltInArray
303{{
304using namespace Func;
305using Rule = SymbolRule;
306
307// Rules used to initialize the mangled name array.
308constexpr SymbolRule kRules[] = {{
309{mangled_rules}
310}};
311
312// Flat array of all mangled names.
313constexpr const char *kMangledNames[] = {{
314{mangled_names_array}
315}};
316
317// Flat array of offsets from a symbol into the rules table.
318constexpr uint16_t kMangledOffsets[] = {{
319{mangled_offsets_array}
320}};
321
322using Ext = TExtension;
323
324// Flat array of all unmangled name identifiers.
325constexpr UnmangledEntry unmangled[] = {{
326{unmangled_array}
327}};
328
329}}
330
331void TSymbolTable::initializeBuiltInVariables(sh::GLenum shaderType,
332                                              ShShaderSpec spec,
333                                              const ShBuiltInResources &resources)
334{{
335    const TSourceLoc zeroSourceLoc = {{0, 0, 0, 0}};
336{init_member_variables}
337}}
338
339namespace
340{{
341uint16_t GetNextRuleIndex(uint32_t nameHash)
342{{
343    if (nameHash == {num_mangled_names} - 1)
344        return ArraySize(BuiltInArray::kRules);
345    return BuiltInArray::kMangledOffsets[nameHash + 1];
346}}
347}}  // namespace
348
349const TSymbol *TSymbolTable::findBuiltIn(const ImmutableString &name,
350                                         int shaderVersion) const
351{{
352    if (name.length() > {max_mangled_name_length})
353        return nullptr;
354
355    uint32_t nameHash = name.mangledNameHash();
356    if (nameHash >= {num_mangled_names})
357        return nullptr;
358
359    const char *actualName = BuiltInArray::kMangledNames[nameHash];
360    if (name != actualName)
361        return nullptr;
362
363    uint16_t startIndex = BuiltInArray::kMangledOffsets[nameHash];
364    uint16_t nextIndex = GetNextRuleIndex(nameHash);
365
366    return FindMangledBuiltIn(mShaderSpec, shaderVersion, mShaderType, mResources, *this, BuiltInArray::kRules, startIndex, nextIndex);
367}}
368
369bool TSymbolTable::isUnmangledBuiltInName(const ImmutableString &name,
370                                          int shaderVersion,
371                                          const TExtensionBehavior &extensions) const
372{{
373    if (name.length() > {max_unmangled_name_length})
374        return false;
375
376    uint32_t nameHash = name.unmangledNameHash();
377    if (nameHash >= {num_unmangled_names})
378        return false;
379
380    return BuiltInArray::unmangled[nameHash].matches(name, mShaderSpec, shaderVersion, mShaderType, extensions);
381}}
382
383}}  // namespace sh
384"""
385
386template_operator_header = """// GENERATED FILE - DO NOT EDIT.
387// Generated by {script_name} using data from {function_data_source_name}.
388//
389// Copyright 2021 The ANGLE Project Authors. All rights reserved.
390// Use of this source code is governed by a BSD-style license that can be
391// found in the LICENSE file.
392//
393// Operator_autogen.h:
394//   Operators used by the high-level (parse tree) representation.
395
396#ifndef COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_
397#define COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_
398
399#include <stdint.h>
400
401namespace sh
402{{
403
404enum TOperator : uint16_t
405{{
406    EOpNull,  // if in a node, should only mean a node is still being built
407
408    // Call a function defined in the AST. This might be a user-defined function or a function
409    // inserted by an AST transformation.
410    EOpCallFunctionInAST,
411
412    // Call an internal helper function with a raw implementation - the implementation can't be
413    // subject to AST transformations. Raw functions have a few constraints to keep them compatible
414    // with AST traversers:
415    // * They should not return arrays.
416    // * They should not have out parameters.
417    //
418    // DEPRECATED; DO NOT USE.  TODO: remove this.  http://anglebug.com/6059
419    //
420    EOpCallInternalRawFunction,
421
422    //
423    // Branch (TIntermBranch)
424    //
425
426    EOpKill,  // Fragment only
427    EOpReturn,
428    EOpBreak,
429    EOpContinue,
430
431    //
432    // Constructor (TIntermAggregate)
433    //
434
435    EOpConstruct,
436
437    //
438    // Unary operators with special GLSL syntax (TIntermUnary).
439    //
440
441    EOpNegative,
442    EOpPositive,
443    EOpLogicalNot,
444    EOpBitwiseNot,
445
446    EOpPostIncrement,
447    EOpPostDecrement,
448    EOpPreIncrement,
449    EOpPreDecrement,
450
451    EOpArrayLength,
452
453    //
454    // Binary operators with special GLSL syntax (TIntermBinary).
455    //
456
457    EOpAdd,
458    EOpSub,
459    EOpMul,
460    EOpDiv,
461    EOpIMod,
462
463    EOpEqual,
464    EOpNotEqual,
465    EOpLessThan,
466    EOpGreaterThan,
467    EOpLessThanEqual,
468    EOpGreaterThanEqual,
469
470    EOpComma,
471
472    EOpVectorTimesScalar,
473    EOpVectorTimesMatrix,
474    EOpMatrixTimesVector,
475    EOpMatrixTimesScalar,
476    EOpMatrixTimesMatrix,
477
478    EOpLogicalOr,
479    EOpLogicalXor,
480    EOpLogicalAnd,
481
482    EOpBitShiftLeft,
483    EOpBitShiftRight,
484
485    EOpBitwiseAnd,
486    EOpBitwiseXor,
487    EOpBitwiseOr,
488
489    EOpIndexDirect,
490    EOpIndexIndirect,
491    EOpIndexDirectStruct,
492    EOpIndexDirectInterfaceBlock,
493
494    //
495    // Moves (TIntermBinary)
496    //
497
498    EOpAssign,
499    EOpInitialize,
500    EOpAddAssign,
501    EOpSubAssign,
502
503    EOpMulAssign,
504    EOpVectorTimesMatrixAssign,
505    EOpVectorTimesScalarAssign,
506    EOpMatrixTimesScalarAssign,
507    EOpMatrixTimesMatrixAssign,
508
509    EOpDivAssign,
510    EOpIModAssign,
511    EOpBitShiftLeftAssign,
512    EOpBitShiftRightAssign,
513    EOpBitwiseAndAssign,
514    EOpBitwiseXorAssign,
515    EOpBitwiseOrAssign,
516
517    // Not an op, but a marker for the start of built-in ops.
518    EOpLastNonBuiltIn = EOpBitwiseOrAssign,
519
520    //
521    // Built-in functions mapped to operators (either unary (TIntermUnary) or with multiple
522    // parameters (TIntermAggregate))
523    //
524    {operator_enum_declarations}
525}};
526
527// Returns the string corresponding to the operator in GLSL.  For built-in functions use the
528// function name directly.
529const char *GetOperatorString(TOperator op);
530
531// Say whether or not a binary or unary operation changes the value of a variable.
532bool IsAssignment(TOperator op);
533
534namespace BuiltInGroup
535{{
536static inline bool IsBuiltIn(TOperator op)
537{{
538    return op > EOpLastNonBuiltIn;
539}}
540{is_in_group_definitions}
541}}  // namespace BuiltInGroup
542
543}}  // namespace sh
544
545#endif  // COMPILER_TRANSLATOR_OPERATOR_AUTOGEN_H_
546
547"""
548
549template_rule = """Rule::Get<{spec}, {version}, {shaders}, {extension}>({symbol_or_var})"""
550
551basic_types_enumeration = [
552    'Void',
553    'Float',
554    'Double',
555    'Int',
556    'UInt',
557    'Bool',
558    'AtomicCounter',
559    'YuvCscStandardEXT',
560    'Sampler2D',
561    'Sampler3D',
562    'SamplerCube',
563    'Sampler2DArray',
564    'SamplerExternalOES',
565    'SamplerExternal2DY2YEXT',
566    'Sampler2DRect',
567    'Sampler2DMS',
568    'Sampler2DMSArray',
569    'ISampler2D',
570    'ISampler3D',
571    'ISamplerCube',
572    'ISampler2DArray',
573    'ISampler2DMS',
574    'ISampler2DMSArray',
575    'USampler2D',
576    'USampler3D',
577    'USamplerCube',
578    'USampler2DArray',
579    'USampler2DMS',
580    'USampler2DMSArray',
581    'Sampler2DShadow',
582    'SamplerCubeShadow',
583    'Sampler2DArrayShadow',
584    'Sampler1D',
585    'Sampler1DArray',
586    'Sampler1DArrayShadow',
587    'SamplerBuffer',
588    'SamplerCubeArray',
589    'SamplerCubeArrayShadow',
590    'Sampler1DShadow',
591    'Sampler2DRectShadow',
592    'ISampler1D',
593    'ISampler1DArray',
594    'ISampler2DRect',
595    'ISamplerBuffer',
596    'ISamplerCubeArray',
597    'USampler1D',
598    'USampler1DArray',
599    'USampler2DRect',
600    'USamplerBuffer',
601    'USamplerCubeArray',
602    'SamplerVideoWEBGL',
603    'Image2D',
604    'Image3D',
605    'Image2DArray',
606    'ImageCube',
607    'Image1D',
608    'Image1DArray',
609    'Image2DMS',
610    'Image2DMSArray',
611    'ImageCubeArray',
612    'ImageRect',
613    'ImageBuffer',
614    'IImage2D',
615    'IImage3D',
616    'IImage2DArray',
617    'IImageCube',
618    'IImage1D',
619    'IImage1DArray',
620    'IImage2DMS',
621    'IImage2DMSArray',
622    'IImageCubeArray',
623    'IImageRect',
624    'IImageBuffer',
625    'UImage2D',
626    'UImage3D',
627    'UImage2DArray',
628    'UImageCube',
629    'UImage1D',
630    'UImage1DArray',
631    'UImage2DMS',
632    'UImage2DMSArray',
633    'UImageCubeArray',
634    'UImageRect',
635    'UImageBuffer',
636    'PixelLocalANGLE',
637    'IPixelLocalANGLE',
638    'UPixelLocalANGLE',
639    'SubpassInput',
640    'ISubpassInput',
641    'USubpassInput',
642    'SubpassInputMS',
643    'ISubpassInputMS',
644    'USubpassInputMS',
645]
646
647id_counter = 0
648
649
650def set_working_dir():
651    script_dir = os.path.dirname(os.path.abspath(__file__))
652    os.chdir(script_dir)
653
654
655def get_basic_mangled_name(basic):
656    index = basic_types_enumeration.index(basic)
657    if index < 26:
658        return '0' + chr(ord('A') + index)
659    if index < 52:
660        return '0' + chr(ord('a') + index - 26)
661    if index < 78:
662        return '1' + chr(ord('A') + index - 52)
663    return '1' + chr(ord('a') + index - 78)
664
665
666essl_levels = [
667    'ESSL3_2_BUILTINS', 'ESSL3_1_BUILTINS', 'ESSL3_BUILTINS', 'ESSL1_BUILTINS', 'COMMON_BUILTINS',
668    'ESSL_INTERNAL_BACKEND_BUILTINS'
669]
670
671glsl_levels = [
672    'GLSL4_6_BUILTINS', 'GLSL4_5_BUILTINS', 'GLSL4_4_BUILTINS', 'GLSL4_3_BUILTINS',
673    'GLSL4_2_BUILTINS', 'GLSL4_1_BUILTINS', 'GLSL4_BUILTINS', 'GLSL3_3_BUILTINS',
674    'GLSL1_5_BUILTINS', 'GLSL1_4_BUILTINS', 'GLSL1_3_BUILTINS', 'GLSL1_2_BUILTINS',
675    'COMMON_BUILTINS'
676]
677
678
679def generate_suffix_from_level(level):
680    assert (level[:4] == 'GLSL' or level[:4] == 'ESSL')
681    assert (level[-9:] == '_BUILTINS')
682
683    # Turn XYSLN_M_BUILTINS to XYN_M
684    return level[:2] + level[4:-9]
685
686
687def get_essl_shader_version_for_level(level):
688    if level == None:
689        return '-1'
690    elif level == 'ESSL_INTERNAL_BACKEND_BUILTINS':
691        return 'kESSLInternalBackendBuiltIns'
692    elif level == 'ESSL3_2_BUILTINS':
693        return '320'
694    elif level == 'ESSL3_1_BUILTINS':
695        return '310'
696    elif level == 'ESSL3_BUILTINS':
697        return '300'
698    elif level == 'ESSL1_BUILTINS':
699        return '100'
700    elif level == 'COMMON_BUILTINS':
701        return '0'
702    else:
703        raise Exception('Unsupported symbol table level')
704
705
706def get_glsl_shader_version_for_level(level):
707    if level == None:
708        return '-1'
709    elif level == 'GLSL1_2_BUILTINS':
710        return '120'
711    elif level == 'GLSL1_3_BUILTINS':
712        return '130'
713    elif level == 'GLSL1_4_BUILTINS':
714        return '140'
715    elif level == 'GLSL1_5_BUILTINS':
716        return '150'
717    elif level == 'GLSL3_3_BUILTINS':
718        return '330'
719    elif level == 'GLSL4_BUILTINS':
720        return '400'
721    elif level == 'GLSL4_1_BUILTINS':
722        return '410'
723    elif level == 'GLSL4_2_BUILTINS':
724        return '420'
725    elif level == 'GLSL4_3_BUILTINS':
726        return '430'
727    elif level == 'GLSL4_4_BUILTINS':
728        return '440'
729    elif level == 'GLSL4_5_BUILTINS':
730        return '450'
731    elif level == 'GLSL4_6_BUILTINS':
732        return '460'
733    elif level == 'COMMON_BUILTINS':
734        return '0'
735    else:
736        raise Exception('Unsupported symbol table level')
737
738
739def get_shader_version_for_level(spec, level):
740    if spec == "ESSL":
741        return get_essl_shader_version_for_level(level)
742    else:
743        return get_glsl_shader_version_for_level(level)
744
745
746def get_extension_list(extensions):
747    extension_list = [ext.strip() for ext in extensions.split(',')]
748    extension_string = ', '.join(['TExtension::' + ext for ext in extension_list])
749    return 'std::array<TExtension, ' + str(len(extension_list)) + 'u>{{' + extension_string + '}}'
750
751
752class GroupedList:
753    """"Class for storing a list of objects grouped by symbol table level and condition."""
754
755    def __init__(self, hashfn, num_names):
756        self.objs = OrderedDict()
757        self.max_name_length = 0
758        self.hashfn = hashfn
759        self.num_names = num_names
760        self.rule_offset = 0
761
762    def add_entry(self, essl_level, glsl_level, shader_type, name, symbol, essl_extension,
763                  glsl_extension, script_generated_hash_tests):
764        if essl_level and essl_level not in essl_levels:
765            raise Exception('Unexpected essl level: ' + str(essl_level))
766        if glsl_level and glsl_level not in glsl_levels:
767            raise Exception('Unexpected glsl level: ' + str(glsl_level))
768        if len(name) > self.max_name_length:
769            self.max_name_length = len(name)
770
771        name_hash = mangledNameHash(name, self.hashfn, script_generated_hash_tests, False)
772        if name_hash not in self.objs:
773            self.objs[name_hash] = OrderedDict()
774
775        self.objs[name_hash]['name'] = name
776
777        if essl_extension == 'UNDEFINED' and glsl_extension == 'UNDEFINED':
778            if 'symbol' in self.objs[name_hash] and self.objs[name_hash]['symbol'] != symbol:
779                # Adding a variable that is part of two ESSL extensions that have become core
780                if 'symbol2' not in self.objs[name_hash]:
781                    if essl_level:
782                        self.objs[name_hash]['essl_level2'] = essl_level
783                    if glsl_level:
784                        self.objs[name_hash]['glsl_level2'] = glsl_level
785                    self.objs[name_hash]['symbol2'] = symbol
786                    self.objs[name_hash]['shader_type2'] = shader_type
787                elif 'symbol3' not in self.objs[name_hash]:
788                    if essl_level:
789                        self.objs[name_hash]['essl_level3'] = essl_level
790                    if glsl_level:
791                        self.objs[name_hash]['glsl_level3'] = glsl_level
792                    self.objs[name_hash]['symbol3'] = symbol
793                    self.objs[name_hash]['shader_type3'] = shader_type
794                elif 'symbol4' not in self.objs[name_hash]:
795                    if essl_level:
796                        self.objs[name_hash]['essl_level4'] = essl_level
797                    if glsl_level:
798                        self.objs[name_hash]['glsl_level4'] = glsl_level
799                    self.objs[name_hash]['symbol4'] = symbol
800                    self.objs[name_hash]['shader_type4'] = shader_type
801                else:
802                    assert (False)
803            else:
804                if essl_level:
805                    self.objs[name_hash]['essl_level'] = essl_level
806                if glsl_level:
807                    self.objs[name_hash]['glsl_level'] = glsl_level
808                self.objs[name_hash]['symbol'] = symbol
809                self.objs[name_hash]['shader_type'] = shader_type
810
811        if essl_extension != 'UNDEFINED':
812            if ('essl_ext_symbol' in self.objs[name_hash] and
813                    self.objs[name_hash]['essl_ext_symbol'] != symbol):
814                # Adding a variable that is part of two ESSL extensions
815                if 'essl_ext_symbol2' not in self.objs[name_hash]:
816                    self.objs[name_hash]['essl_extension2'] = essl_extension
817                    self.objs[name_hash]['essl_ext_level2'] = essl_level
818                    self.objs[name_hash]['essl_ext_symbol2'] = symbol
819                    self.objs[name_hash]['essl_ext_shader_type2'] = shader_type
820                elif 'essl_ext_symbol3' not in self.objs[name_hash]:
821                    self.objs[name_hash]['essl_extension3'] = essl_extension
822                    self.objs[name_hash]['essl_ext_level3'] = essl_level
823                    self.objs[name_hash]['essl_ext_symbol3'] = symbol
824                    self.objs[name_hash]['essl_ext_shader_type3'] = shader_type
825                elif 'essl_ext_symbol4' not in self.objs[name_hash]:
826                    self.objs[name_hash]['essl_extension4'] = essl_extension
827                    self.objs[name_hash]['essl_ext_level4'] = essl_level
828                    self.objs[name_hash]['essl_ext_symbol4'] = symbol
829                    self.objs[name_hash]['essl_ext_shader_type4'] = shader_type
830                else:
831                    assert (False)
832            else:
833                self.objs[name_hash]['essl_extension'] = essl_extension
834                self.objs[name_hash]['essl_ext_level'] = essl_level
835                self.objs[name_hash]['essl_ext_symbol'] = symbol
836                self.objs[name_hash]['essl_ext_shader_type'] = shader_type
837
838        if glsl_extension != 'UNDEFINED':
839            self.objs[name_hash]['glsl_extension'] = glsl_extension
840            self.objs[name_hash]['glsl_ext_level'] = glsl_level
841            self.objs[name_hash]['glsl_ext_symbol'] = symbol
842            self.objs[name_hash]['glsl_ext_shader_type'] = shader_type
843
844    def get_max_name_length(self):
845        return self.max_name_length
846
847    def format_rule(self, rule):
848        return template_rule.format(**rule)
849
850    def format_rules(self, rules):
851        return ", ".join([self.format_rule(rule) for rule in rules])
852
853    def get_rules(self):
854        return self.rules
855
856    def get_names(self):
857        return self.names
858
859    def get_offsets(self):
860        return self.offsets
861
862    def update_arrays(self, essl_only):
863
864        def add_rule(rules, spec, level, shaders, extension, symbol):
865            var = ("&TableBase::%s" % symbol) if symbol.startswith("m_gl") else None
866
867            extension_list = []
868            specField = "Spec::%s" % ("ESSL" if spec == "ESSL" else "GLSL")
869            versionField = get_shader_version_for_level(spec, level)
870            shadersField = "Shader::%s" % ("ALL" if shaders == "NONE" else shaders)
871            symbolOrVarField = symbol.replace("Func::", "") if var is None else var
872            if extension != None:
873                extension_list = [ext.strip() for ext in extension.split(',')]
874                for ext in extension_list:
875                    rules.append({
876                        "spec": specField,
877                        "version": versionField,
878                        "shaders": shadersField,
879                        "extension": "0" if ext == None else "EXT_INDEX(%s)" % ext,
880                        "symbol_or_var": symbolOrVarField
881                    })
882            else:
883                rules.append({
884                    "spec": specField,
885                    "version": versionField,
886                    "shaders": shadersField,
887                    "extension": "0",
888                    "symbol_or_var": symbolOrVarField
889                })
890
891        self.names = []
892        self.offsets = []
893        self.rules = []
894        for hash_val in range(0, self.num_names):
895            if hash_val in self.objs:
896                data = self.objs[hash_val]
897
898                rules = []
899
900                if "symbol" in data and "essl_level" in data:
901                    add_rule(rules, "ESSL", data['essl_level'], data['shader_type'], None,
902                             data["symbol"])
903
904                if "symbol" in data and "glsl_level" in data and not essl_only:
905                    add_rule(rules, "GLSL", data['glsl_level'], data['shader_type'], None,
906                             data["symbol"])
907
908                if "symbol2" in data and "essl_level2" in data:
909                    add_rule(rules, "ESSL", data['essl_level2'], data['shader_type2'], None,
910                             data["symbol2"])
911
912                if "symbol2" in data and "glsl_level2" in data and not essl_only:
913                    add_rule(rules, "GLSL", data['glsl_level2'], data['shader_type2'], None,
914                             data["symbol2"])
915
916                if "symbol3" in data and "essl_level3" in data:
917                    add_rule(rules, "ESSL", data['essl_level3'], data['shader_type3'], None,
918                             data["symbol3"])
919
920                if "symbol3" in data and "glsl_level3" in data and not essl_only:
921                    add_rule(rules, "GLSL", data['glsl_level3'], data['shader_type3'], None,
922                             data["symbol3"])
923
924                if "symbol4" in data and "essl_level4" in data:
925                    add_rule(rules, "ESSL", data['essl_level4'], data['shader_type4'], None,
926                             data["symbol4"])
927
928                if "symbol4" in data and "glsl_level4" in data and not essl_only:
929                    add_rule(rules, "GLSL", data['glsl_level4'], data['shader_type4'], None,
930                             data["symbol4"])
931
932                if "essl_ext_symbol" in data:
933                    add_rule(rules, "ESSL", data["essl_ext_level"], data["essl_ext_shader_type"],
934                             data["essl_extension"], data["essl_ext_symbol"])
935
936                if "glsl_ext_symbol" in data and not essl_only:
937                    add_rule(rules, "GLSL", data["glsl_ext_level"], data["glsl_ext_shader_type"],
938                             data["glsl_extension"], data["glsl_ext_symbol"])
939
940                if "essl_ext_symbol2" in data:
941                    add_rule(rules, "ESSL", data["essl_ext_level2"], data["essl_ext_shader_type2"],
942                             data["essl_extension2"], data["essl_ext_symbol2"])
943
944                if "essl_ext_symbol3" in data:
945                    add_rule(rules, "ESSL", data["essl_ext_level3"], data["essl_ext_shader_type3"],
946                             data["essl_extension3"], data["essl_ext_symbol3"])
947
948                if "essl_ext_symbol4" in data:
949                    add_rule(rules, "ESSL", data["essl_ext_level4"], data["essl_ext_shader_type4"],
950                             data["essl_extension4"], data["essl_ext_symbol4"])
951
952                name = data['name']
953                name_underscore = name.replace("(", "_")
954
955                self.names.append('"%s"' % name)
956                self.offsets.append("%d, // %s" % (self.rule_offset, name_underscore))
957                self.rules.append("%s" % self.format_rules(rules))
958
959                self.rule_offset += len(rules)
960
961            else:
962                self.names.append('""')
963                self.offsets.append('%d, // Empty' % self.rule_offset)
964
965
966class UnmangledGroupedList:
967    """"Class for storing a list of unmangled objects grouped by symbol table level and condition."""
968
969    def __init__(self, hashfn, num_names):
970        self.objs = OrderedDict()
971        self.max_name_length = 0
972        self.hashfn = hashfn
973        self.num_names = num_names
974
975    def add_entry(self, essl_level, glsl_level, shader_type, name, essl_ext, glsl_ext,
976                  essl_extension, glsl_extension, unmangled_script_generated_hash_tests):
977        if essl_level and essl_level not in essl_levels:
978            raise Exception('Unexpected essl level: ' + str(essl_level))
979        if glsl_level and glsl_level not in glsl_levels:
980            raise Exception('Unexpected glsl level: ' + str(glsl_level))
981        if len(name) > self.max_name_length:
982            self.max_name_length = len(name)
983
984        name_hash = mangledNameHash(name, self.hashfn, unmangled_script_generated_hash_tests, True)
985        self.objs[name_hash] = OrderedDict()
986        self.objs[name_hash]['name'] = name
987        self.objs[name_hash]['essl_level'] = essl_level
988        self.objs[name_hash]['glsl_level'] = glsl_level
989        self.objs[name_hash]['shader_type'] = shader_type
990        self.objs[name_hash]['essl_ext'] = essl_ext
991        self.objs[name_hash]['glsl_ext'] = glsl_ext
992        self.objs[name_hash]['essl_extension'] = essl_extension
993        self.objs[name_hash]['glsl_extension'] = glsl_extension
994
995    def has_key(self, essl_level, glsl_level, shader_type, name):
996        name_hash = mangledNameHash(name, self.hashfn, None, True, False)
997        if name_hash not in self.objs:
998            return False
999        entry = self.objs[name_hash]
1000        if entry['essl_level'] != essl_level:
1001            return False
1002        if entry['glsl_level'] != glsl_level:
1003            return False
1004        if entry['shader_type'] != shader_type:
1005            return False
1006        return True
1007
1008    def get(self, essl_level, glsl_level, shader_type, name):
1009        if self.has_key(essl_level, glsl_level, shader_type, name):
1010            name_hash = mangledNameHash(name, self.hashfn, None, True, False)
1011            return self.objs[name_hash]
1012        return None
1013
1014    def get_max_name_length(self):
1015        return self.max_name_length
1016
1017    def get_array(self):
1018        code = []
1019        for hash_val in range(0, self.num_names):
1020            obj = self.objs[hash_val]
1021            essl_level = obj['essl_level']
1022            glsl_level = obj['glsl_level']
1023            shader_type = 'Shader::' + obj['shader_type'] if obj[
1024                'shader_type'] != 'NONE' else 'Shader::ALL'
1025            data = []
1026            data.append('"{name}"'.format(name=obj['name']))
1027            essl_extensions = [ext.strip() for ext in obj['essl_extension'].split(',')]
1028            template_extensions = 'std::array<TExtension, {count}>{{{{{extensions}}}}}'
1029            data.append(
1030                template_extensions.format(
1031                    count=len(essl_extensions),
1032                    extensions=','.join(['Ext::' + ext for ext in essl_extensions])))
1033            data.append("Ext::" + obj['glsl_extension'])
1034            data.append(get_essl_shader_version_for_level(essl_level))
1035            data.append(get_glsl_shader_version_for_level(glsl_level))
1036            data.append(shader_type)
1037
1038            code.append('{%s}' % ', '.join(data))
1039        return code
1040
1041
1042class TType:
1043
1044    def __init__(self, glsl_header_type):
1045        if isinstance(glsl_header_type, str):
1046            self.data = self.parse_type(glsl_header_type)
1047        else:
1048            self.data = glsl_header_type
1049        self.normalize()
1050
1051    def normalize(self):
1052        # Note that this will set primarySize and secondarySize also on genTypes. In that case they
1053        # are overridden when the specific types are generated.
1054        if 'primarySize' not in self.data:
1055            if ('secondarySize' in self.data):
1056                raise Exception(
1057                    'Unexpected secondarySize on type that does not have primarySize set')
1058            self.data['primarySize'] = 1
1059        if 'secondarySize' not in self.data:
1060            self.data['secondarySize'] = 1
1061        if 'precision' not in self.data:
1062            self.data['precision'] = 'Undefined'
1063        if 'qualifier' not in self.data:
1064            self.data['qualifier'] = 'Global'
1065
1066    def has_array_size(self):
1067        return 'arraySize' in self.data
1068
1069    def get_statictype_string(self):
1070        template_type = 'StaticType::Get<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}>()'
1071        if self.has_array_size():
1072            template_type = 'StaticType::GetArray<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}, kArraySize{arraySize}, 1>()'
1073        return template_type.format(**self.data)
1074
1075    def get_dynamic_type_string(self):
1076        template_type = 'new TType(Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}'
1077        if self.has_array_size():
1078            template_type += ', TVector<unsigned int>{{{arraySize}}}'
1079        template_type += ')'
1080        return template_type.format(**self.data)
1081
1082    def get_mangled_name(self):
1083        mangled_name = ''
1084
1085        size_key = (self.data['secondarySize'] - 1) * 4 + self.data['primarySize'] - 1
1086        if size_key < 10:
1087            mangled_name += chr(ord('0') + size_key)
1088        else:
1089            mangled_name += chr(ord('A') + size_key - 10)
1090        mangled_name += get_basic_mangled_name(self.data['basic'])
1091        if self.has_array_size():
1092            mangled_name += 'x' + str(self.data['arraySize'])
1093        return mangled_name
1094
1095    def get_human_readable_name(self):
1096        name = self.data['basic']
1097        if self.has_array_size():
1098            name = str(self.data['arraySize']) + 'x' + name
1099        name += str(self.data['primarySize'])
1100        if self.data['secondarySize'] > 1:
1101            name += 'x' + str(self.data['secondarySize'])
1102        return name
1103
1104    def is_vector(self):
1105        return self.data['primarySize'] > 1 and self.data['secondarySize'] == 1
1106
1107    def is_matrix(self):
1108        return self.data['secondarySize'] > 1
1109
1110    def get_object_size(self):
1111        return self.data['primarySize'] * self.data['secondarySize']
1112
1113    def specific_sampler_or_image_or_subpass_type(self, basic_type_prefix):
1114        if 'genType' in self.data and self.data['genType'] == 'sampler_or_image_or_subpass':
1115            type = {}
1116            if 'basic' not in self.data:
1117                type['basic'] = {'': 'Float', 'I': 'Int', 'U': 'UInt'}[basic_type_prefix]
1118                type['primarySize'] = self.data['primarySize']
1119            else:
1120                type['basic'] = basic_type_prefix + self.data['basic']
1121                type['primarySize'] = 1
1122            type['precision'] = 'Undefined'
1123            return TType(type)
1124        return self
1125
1126    def specific_type(self, vec_size):
1127        type = {}
1128        if 'genType' in self.data:
1129            type['basic'] = self.data['basic']
1130            type['precision'] = self.data['precision']
1131            type['qualifier'] = self.data['qualifier']
1132            type['primarySize'] = vec_size
1133            type['secondarySize'] = 1
1134            return TType(type)
1135        return self
1136
1137    def parse_type(self, glsl_header_type):
1138        # TODO(http://anglebug.com/3833): handle readonly, writeonly qualifiers
1139        if glsl_header_type.startswith('readonly writeonly '):
1140            type_obj = self.parse_type(glsl_header_type[19:])
1141            type_obj['qualifier'] = 'Readonly Writeonly'
1142            return type_obj
1143        if glsl_header_type.startswith('readonly '):
1144            type_obj = self.parse_type(glsl_header_type[9:])
1145            type_obj['qualifier'] = 'Readonly'
1146            return type_obj
1147        if glsl_header_type.startswith('writeonly '):
1148            type_obj = self.parse_type(glsl_header_type[10:])
1149            type_obj['qualifier'] = 'Writeonly'
1150            return type_obj
1151        if glsl_header_type.startswith('out '):
1152            type_obj = self.parse_type(glsl_header_type[4:])
1153            type_obj['qualifier'] = 'ParamOut'
1154            return type_obj
1155        if glsl_header_type.startswith('inout '):
1156            type_obj = self.parse_type(glsl_header_type[6:])
1157            type_obj['qualifier'] = 'ParamInOut'
1158            return type_obj
1159
1160        basic_type_map = {
1161            'float': 'Float',
1162            'int': 'Int',
1163            'uint': 'UInt',
1164            'double': 'Double',
1165            'bool': 'Bool',
1166            'void': 'Void',
1167            'atomic_uint': 'AtomicCounter',
1168            'yuvCscStandardEXT': 'YuvCscStandardEXT'
1169        }
1170
1171        if glsl_header_type in basic_type_map:
1172            return {'basic': basic_type_map[glsl_header_type]}
1173
1174        type_obj = {}
1175
1176        basic_type_prefix_map = {
1177            '': 'Float',
1178            'i': 'Int',
1179            'u': 'UInt',
1180            'd': 'Double',
1181            'b': 'Bool',
1182            'v': 'Void'
1183        }
1184
1185        vec_re = re.compile(r'^([iudb]?)vec([234]?)((\[[234]\])?)$')
1186        vec_match = vec_re.match(glsl_header_type)
1187        if vec_match:
1188            type_obj['basic'] = basic_type_prefix_map[vec_match.group(1)]
1189            if vec_match.group(2) == '':
1190                # Type like "ivec" that represents either ivec2, ivec3 or ivec4
1191                type_obj['genType'] = 'vec'
1192            else:
1193                # vec with specific size
1194                if vec_match.group(3) != '':
1195                    # vec array
1196                    type_obj['primarySize'] = int(vec_match.group(2))
1197                    type_obj['arraySize'] = int(vec_match.group(3)[1])
1198                else:
1199                    type_obj['primarySize'] = int(vec_match.group(2))
1200            return type_obj
1201
1202        mat_re = re.compile(r'^mat([234])(x([234]))?$')
1203        mat_match = mat_re.match(glsl_header_type)
1204        if mat_match:
1205            type_obj['basic'] = 'Float'
1206            if len(glsl_header_type) == 4:
1207                mat_size = int(mat_match.group(1))
1208                type_obj['primarySize'] = mat_size
1209                type_obj['secondarySize'] = mat_size
1210            else:
1211                type_obj['primarySize'] = int(mat_match.group(1))
1212                type_obj['secondarySize'] = int(mat_match.group(3))
1213            return type_obj
1214
1215        gen_re = re.compile(r'^gen([IUDB]?)Type$')
1216        gen_match = gen_re.match(glsl_header_type)
1217        if gen_match:
1218            type_obj['basic'] = basic_type_prefix_map[gen_match.group(1).lower()]
1219            type_obj['genType'] = 'yes'
1220            return type_obj
1221
1222        if glsl_header_type.startswith('sampler'):
1223            type_obj['basic'] = glsl_header_type[0].upper() + glsl_header_type[1:]
1224            return type_obj
1225
1226        if glsl_header_type.startswith('gsampler') or \
1227           glsl_header_type.startswith('gimage') or \
1228           glsl_header_type.startswith('gpixelLocal') or \
1229           glsl_header_type.startswith('gsubpassInput'):
1230            type_obj['basic'] = glsl_header_type[1].upper() + glsl_header_type[2:]
1231            type_obj['genType'] = 'sampler_or_image_or_subpass'
1232            return type_obj
1233
1234        if glsl_header_type == 'gvec4':
1235            return {'primarySize': 4, 'genType': 'sampler_or_image_or_subpass'}
1236        if glsl_header_type == 'gvec3':
1237            return {'primarySize': 3, 'genType': 'sampler_or_image_or_subpass'}
1238
1239        if glsl_header_type == 'IMAGE_PARAMS':
1240            return {'genType': 'image_params'}
1241
1242        raise Exception('Unrecognized type: ' + str(glsl_header_type))
1243
1244
1245class SymbolsData:
1246
1247    def __init__(self):
1248
1249        # Declarations of symbol unique ids
1250        self.builtin_id_declarations = []
1251
1252        # Declarations of name string variables
1253        self.name_declarations = set()
1254
1255        # Code for testing that script-generated hashes match with runtime computed hashes.
1256        self.script_generated_hash_tests = OrderedDict()
1257        self.unmangled_script_generated_hash_tests = OrderedDict()
1258
1259
1260class VariablesData:
1261
1262    def __init__(self):
1263
1264        # Code for defining TVariables stored as members of TSymbolTable.
1265        self.declare_member_variables = []
1266        self.init_member_variables = []
1267
1268        # Declarations of static array sizes if any builtin TVariable is array.
1269        self.type_array_sizes_declarations = set()
1270
1271        # Declarations of builtin TVariables
1272        self.variable_declarations = []
1273
1274        # Functions for querying the pointer to a specific TVariable.
1275        self.get_variable_declarations = []
1276        self.get_variable_definitions = []
1277
1278
1279class FunctionsData:
1280
1281    def __init__(self):
1282
1283        # Declarations of builtin TFunctions
1284        self.function_declarations = []
1285
1286        # TOperator enum values (and grouping comments) for built-in functions.
1287        self.operator_list = dict()
1288        self.operator_enum_declarations = []
1289
1290        # Functions for testing whether a builtin belongs in group.
1291        self.is_in_group_definitions = []
1292
1293        # Declarations of parameter arrays for builtin TFunctions. Map from C++ variable name to the
1294        # full declaration.
1295        self.parameter_declarations = {}
1296
1297        self.defined_function_variants = set()
1298        self.defined_parameter_names = set()
1299
1300    def find_op(self, search_index, direction, limit_for_assertion):
1301
1302        while True:
1303            # Make sure the group is not empty.  An "opSuffix" must be used to distinguish between
1304            # built-ins with the same name, but in different groups.
1305            assert (search_index != limit_for_assertion)
1306
1307            line = self.operator_enum_declarations[search_index].lstrip()
1308            if line.startswith('EOp'):
1309                return line[:line.index(',')]
1310            search_index += direction
1311
1312
1313class HashFunction:
1314
1315    def __init__(self, f1, f2, G):
1316        self.f1 = f1
1317        self.f2 = f2
1318        self.G = G
1319
1320    def hash(self, key):
1321        return (self.G[self.f1(key)] + self.G[self.f2(key)]) % len(self.G)
1322
1323
1324def get_parsed_functions(functions_txt_filename, essl_only):
1325
1326    def parse_function_parameters(parameters):
1327        if parameters == '':
1328            return []
1329        parametersOut = []
1330        parameters = parameters.split(', ')
1331        for parameter in parameters:
1332            parametersOut.append(TType(parameter.strip()))
1333        return parametersOut
1334
1335    lines = []
1336    with open(functions_txt_filename) as f:
1337        lines = f.readlines()
1338    lines = [
1339        line.strip() for line in lines if line.strip() != '' and not line.strip().startswith('//')
1340    ]
1341
1342    fun_re = re.compile(r'^(\w+) (\w+)\((.*)\);$')
1343
1344    parsed_functions = OrderedDict()
1345    group_stack = []
1346    default_metadata = {}
1347
1348    for line in lines:
1349        if line.startswith('GROUP BEGIN '):
1350            group_rest = line[12:].strip()
1351            group_parts = group_rest.split(' ', 1)
1352            current_group = {'functions': [], 'name': group_parts[0], 'subgroups': {}}
1353            if len(group_parts) > 1:
1354                group_metadata = json.loads(group_parts[1])
1355                current_group.update(group_metadata)
1356            group_stack.append(current_group)
1357        elif line.startswith('GROUP END '):
1358            group_end_name = line[10:].strip()
1359            current_group = group_stack[-1]
1360            if current_group['name'] != group_end_name:
1361                raise Exception('GROUP END: Unexpected function group name "' + group_end_name +
1362                                '" was expecting "' + current_group['name'] + '"')
1363            group_stack.pop()
1364            is_top_level_group = (len(group_stack) == 0)
1365            if is_top_level_group:
1366                if current_group['name'] in parsed_functions:
1367                    raise Exception('GROUP END: Duplicate group name "%s"' % current_group['name'])
1368                parsed_functions[current_group['name']] = current_group
1369                default_metadata = {}
1370            else:
1371                super_group = group_stack[-1]
1372                super_group['subgroups'][current_group['name']] = current_group
1373        elif line.startswith('DEFAULT METADATA'):
1374            line_rest = line[16:].strip()
1375            default_metadata = json.loads(line_rest)
1376        else:
1377            fun_match = fun_re.match(line)
1378            if fun_match:
1379                return_type = fun_match.group(1)
1380                name = fun_match.group(2)
1381                parameters = fun_match.group(3)
1382                function_props = {
1383                    'name': name,
1384                    'returnType': TType(return_type),
1385                    'parameters': parse_function_parameters(parameters)
1386                }
1387                function_props.update(default_metadata)
1388                if essl_only:
1389                    # Skip GLSL-only functions
1390                    if 'essl_level' in function_props:
1391                        group_stack[-1]['functions'].append(function_props)
1392                else:
1393                    group_stack[-1]['functions'].append(function_props)
1394            else:
1395                raise Exception('Unexpected function input line: ' + line)
1396
1397    return parsed_functions
1398
1399
1400def mangledNameHash(str, hashfn, script_generated_hash_tests, unmangled, save_test=True):
1401    hash = hashfn.hash(str)
1402    if save_test:
1403        confidence_check = ''
1404        if unmangled:
1405            confidence_check = '    ASSERT_EQ(0x{hash}u, ImmutableString("{str}").unmangledNameHash());'.format(
1406                hash=('%08x' % hash), str=str)
1407        else:
1408            confidence_check = '    ASSERT_EQ(0x{hash}u, ImmutableString("{str}").mangledNameHash());'.format(
1409                hash=('%08x' % hash), str=str)
1410        script_generated_hash_tests.update({confidence_check: None})
1411    return hash
1412
1413
1414def get_function_names(group, mangled_names, unmangled_names):
1415    if 'functions' in group:
1416        for function_props in group['functions']:
1417            function_name = function_props['name']
1418            unmangled_names.append(function_name)
1419            function_variants = gen_function_variants(function_props)
1420            for function_props in function_variants:
1421                parameters = get_parameters(function_props)
1422                mangled_names.append(get_function_mangled_name(function_name, parameters))
1423    if 'subgroups' in group:
1424        for subgroup_name, subgroup in group['subgroups'].items():
1425            get_function_names(subgroup, mangled_names, unmangled_names)
1426
1427
1428def get_variable_names(group, mangled_names):
1429    if 'variables' in group:
1430        for variable_name, props in group['variables'].items():
1431            mangled_names.append(variable_name)
1432    if 'subgroups' in group:
1433        for subgroup_name, subgroup in group['subgroups'].items():
1434            get_variable_names(subgroup, mangled_names)
1435
1436
1437def get_suffix(props):
1438    if 'suffix' in props:
1439        return props['suffix']
1440    return ''
1441
1442
1443def get_essl_extension(props):
1444    if 'essl_extension' in props:
1445        return props['essl_extension']
1446    return 'UNDEFINED'
1447
1448
1449def get_glsl_extension(props):
1450    if 'glsl_extension' in props:
1451        return props['glsl_extension']
1452    return 'UNDEFINED'
1453
1454
1455def get_op(name, function_props, group_op_suffix):
1456    return 'EOp' + name[0].upper() + name[1:] + group_op_suffix + function_props.get(
1457        'opSuffix', '')
1458
1459
1460def get_known_to_not_have_side_effects(function_props):
1461    if 'hasSideEffects' in function_props:
1462        return 'false'
1463    else:
1464        for param in get_parameters(function_props):
1465            if 'qualifier' in param.data and (param.data['qualifier'] == 'ParamOut' or
1466                                              param.data['qualifier'] == 'ParamInOut'):
1467                return 'false'
1468        return 'true'
1469
1470
1471def get_parameters(function_props):
1472    if 'parameters' in function_props:
1473        return function_props['parameters']
1474    return []
1475
1476
1477def get_function_mangled_name(function_name, parameters):
1478    mangled_name = function_name + '('
1479    for param in parameters:
1480        mangled_name += param.get_mangled_name()
1481    return mangled_name
1482
1483
1484def get_function_human_readable_name(function_name, parameters):
1485    name = function_name
1486    for param in parameters:
1487        name += '_' + param.get_human_readable_name()
1488    return name
1489
1490
1491def get_unique_identifier_name(function_name, parameters):
1492    unique_name = function_name + '_'
1493    for param in parameters:
1494        unique_name += param.get_mangled_name()
1495    return unique_name
1496
1497
1498def get_variable_name_to_store_parameter(param):
1499    unique_name = 'pt'
1500    if 'qualifier' in param.data:
1501        if param.data['qualifier'] == 'ParamOut':
1502            unique_name += '_o_'
1503        if param.data['qualifier'] == 'ParamInOut':
1504            unique_name += '_io_'
1505    unique_name += param.get_mangled_name()
1506    return unique_name
1507
1508
1509def get_variable_name_to_store_parameters(parameters):
1510    if len(parameters) == 0:
1511        return 'empty'
1512    unique_name = 'p'
1513    for param in parameters:
1514        if 'qualifier' in param.data:
1515            if param.data['qualifier'] == 'ParamOut':
1516                unique_name += '_o_'
1517            if param.data['qualifier'] == 'ParamInOut':
1518                unique_name += '_io_'
1519        unique_name += param.get_mangled_name()
1520    return unique_name
1521
1522
1523def define_constexpr_type_array_sizes(template_args, type_array_sizes_declarations):
1524    template_array_sizes_declaration = 'constexpr const unsigned int kArraySize{arraySize}[1] = {{{arraySize}}};'
1525    type_array_sizes_declarations.add(template_array_sizes_declaration.format(**template_args))
1526
1527
1528def define_constexpr_variable(template_args, variable_declarations):
1529    template_args['extension'] = get_extension_list(template_args['extension'])
1530    template_variable_declaration = 'constexpr const TVariable k{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});'
1531
1532    variable_declarations.append(template_variable_declaration.format(**template_args))
1533
1534
1535def gen_function_variants(function_props):
1536    function_variants = []
1537    parameters = get_parameters(function_props)
1538    function_is_gen_type = False
1539    gen_type = set()
1540    image_params_index = 0
1541    for param in parameters + [function_props['returnType']]:
1542        if 'genType' in param.data:
1543            if param.data['genType'] not in [
1544                    'sampler_or_image_or_subpass', 'vec', 'yes', 'image_params'
1545            ]:
1546                raise Exception(
1547                    'Unexpected value of genType "' + str(param.data['genType']) +
1548                    '" should be "sampler_or_image_or_subpass", "vec", "yes", or "image_params"')
1549            gen_type.add(param.data['genType'])
1550            if param.data['genType'] == 'image_params':
1551                image_params_index = parameters.index(param)
1552
1553    if len(gen_type) == 0:
1554        function_variants.append(function_props)
1555        return function_variants
1556
1557    # If we have image_params then we're generating variants for 33 separate functions,
1558    # each for a different type of image variable
1559    if 'image_params' in gen_type:
1560        variants = [['gimage2D', 'ivec2'], ['gimage3D', 'ivec3'], ['gimageCube', 'ivec3'],
1561                    ['gimageBuffer', 'int'], ['gimage2DArray', 'ivec3'],
1562                    ['gimageCubeArray', 'ivec3'], ['gimage1D', 'int'], ['gimage1DArray', 'ivec2'],
1563                    ['gimageRect', 'ivec2'], ['gimage2DMS', 'ivec2', 'int'],
1564                    ['gimage2DMSArray', 'ivec3', 'int']]
1565        for variant in variants:
1566            image_variant_parameters = []
1567            for param in parameters:
1568                if parameters.index(param) == image_params_index:
1569                    for variant_param in variant:
1570                        image_variant_parameters.append(TType(variant_param))
1571                else:
1572                    image_variant_parameters.append(param)
1573            types = ['', 'I', 'U']
1574            for type in types:
1575                variant_props = function_props.copy()
1576                variant_parameters = []
1577                for param in image_variant_parameters:
1578                    variant_parameters.append(
1579                        param.specific_sampler_or_image_or_subpass_type(type))
1580                variant_props['parameters'] = variant_parameters
1581                variant_props['returnType'] = function_props[
1582                    'returnType'].specific_sampler_or_image_or_subpass_type(type)
1583                function_variants.append(variant_props)
1584        return function_variants
1585
1586    # If we have a gsampler_or_image_or_subpass then we're generating variants for float, int and uint
1587    # samplers.
1588    if 'sampler_or_image_or_subpass' in gen_type:
1589        types = ['', 'I', 'U']
1590        for type in types:
1591            variant_props = function_props.copy()
1592            variant_parameters = []
1593            for param in parameters:
1594                variant_parameters.append(param.specific_sampler_or_image_or_subpass_type(type))
1595            variant_props['parameters'] = variant_parameters
1596            variant_props['returnType'] = function_props[
1597                'returnType'].specific_sampler_or_image_or_subpass_type(type)
1598            function_variants.append(variant_props)
1599        return function_variants
1600
1601    # If we have a normal gentype then we're generating variants for different sizes of vectors.
1602    sizes = range(1, 5)
1603    if 'vec' in gen_type:
1604        sizes = range(2, 5)
1605    for size in sizes:
1606        variant_props = function_props.copy()
1607        variant_parameters = []
1608        for param in parameters:
1609            variant_parameters.append(param.specific_type(size))
1610        variant_props['parameters'] = variant_parameters
1611        variant_props['returnType'] = function_props['returnType'].specific_type(size)
1612        function_variants.append(variant_props)
1613    return function_variants
1614
1615
1616def process_single_function(shader_type, group_name, function_props, symbols, variables, functions,
1617                            group_op_suffix, unmangled_function_if_statements, mangled_builtins):
1618    global id_counter
1619
1620    function_name = function_props['name']
1621    essl_level = function_props['essl_level'] if 'essl_level' in function_props else None
1622    glsl_level = function_props['glsl_level'] if 'glsl_level' in function_props else None
1623    essl_extension = get_essl_extension(function_props)
1624    glsl_extension = get_glsl_extension(function_props)
1625    extension = essl_extension if essl_extension != 'UNDEFINED' else glsl_extension
1626    op = get_op(function_name, function_props, group_op_suffix)
1627    template_args = {
1628        'name': function_name,
1629        'name_with_suffix': function_name + get_suffix(function_props),
1630        'essl_level': essl_level,
1631        'glsl_level': glsl_level,
1632        'essl_extension': essl_extension,
1633        'glsl_extension': glsl_extension,
1634        # This assumes that functions cannot be part of an ESSL and GLSL extension
1635        # Will need to update after adding GLSL extension functions if this is not the case
1636        'extension': essl_extension if essl_extension != 'UNDEFINED' else glsl_extension,
1637        'op': op,
1638        'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props)
1639    }
1640
1641    function_variants = gen_function_variants(function_props)
1642
1643    template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");'
1644    name_declaration = template_name_declaration.format(**template_args)
1645    if not name_declaration in symbols.name_declarations:
1646        symbols.name_declarations.add(name_declaration)
1647
1648    essl_ext = '{essl_extension}'.format(**template_args)
1649    glsl_ext = '{glsl_extension}'.format(**template_args)
1650    unmangled_builtin_no_shader_type = unmangled_function_if_statements.get(
1651        essl_level, glsl_level, 'NONE', function_name)
1652    if unmangled_builtin_no_shader_type != None and unmangled_builtin_no_shader_type[
1653            'essl_extension'] == 'UNDEFINED' and unmangled_builtin_no_shader_type[
1654                'glsl_extension'] == 'UNDEFINED':
1655        # We already have this unmangled name without a shader type nor extension on the same level.
1656        # No need to add a duplicate with a type.
1657        pass
1658    elif (not unmangled_function_if_statements.has_key(
1659            essl_level, glsl_level, shader_type, function_name)) or (
1660                unmangled_builtin_no_shader_type and
1661                ((essl_extension == 'UNDEFINED' and
1662                  unmangled_builtin_no_shader_type['essl_extension'] != 'UNDEFINED') or
1663                 (glsl_extension == 'UNDEFINED' and
1664                  unmangled_builtin_no_shader_type['glsl_extension'] != 'UNDEFINED'))):
1665        unmangled_function_if_statements.add_entry(essl_level, glsl_level, shader_type,
1666                                                   function_name, essl_ext, glsl_ext,
1667                                                   essl_extension, glsl_extension,
1668                                                   symbols.unmangled_script_generated_hash_tests)
1669
1670    extension_string = get_extension_list(template_args['extension'])
1671
1672    if op not in functions.operator_list:
1673        functions.operator_list[op] = group_name
1674        is_unary = group_name.startswith('Math') and len(get_parameters(function_variants[0])) == 1
1675        assert (not is_unary or
1676                all([len(get_parameters(props)) == 1 for props in function_variants]))
1677
1678        template_operator_enum = '    {op},{is_unary_comment}'
1679        template_args['is_unary_comment'] = '  // Unary' if is_unary else ''
1680
1681        functions.operator_enum_declarations.append(template_operator_enum.format(**template_args))
1682    else:
1683        # Ensure that built-ins in different groups don't generate the same op.  The Is<Group> query
1684        # functions rely on this.
1685        previous_group_name = functions.operator_list[op]
1686        if group_name != previous_group_name:
1687            print('Op ' + op + ' found in group ' + group_name + ' but was previously in group ' +
1688                  previous_group_name)
1689        assert (group_name == previous_group_name)
1690
1691    for function_props in function_variants:
1692        template_args['id'] = id_counter
1693
1694        parameters = get_parameters(function_props)
1695
1696        template_args['unique_name'] = get_unique_identifier_name(
1697            template_args['name_with_suffix'], parameters)
1698        template_args['param_count'] = len(parameters)
1699        template_args['return_type'] = function_props['returnType'].get_statictype_string()
1700        template_args['mangled_name'] = get_function_mangled_name(function_name, parameters)
1701        template_args['human_readable_name'] = get_function_human_readable_name(
1702            template_args['name_with_suffix'], parameters)
1703        template_args['mangled_name_length'] = len(template_args['mangled_name'])
1704
1705        symbol = '&Func::{unique_name}'.format(**template_args)
1706        mangled_builtins.add_entry(essl_level, glsl_level, shader_type,
1707                                   template_args['mangled_name'], symbol,
1708                                   template_args['essl_extension'],
1709                                   template_args['glsl_extension'],
1710                                   symbols.script_generated_hash_tests)
1711
1712        if template_args['unique_name'] in functions.defined_function_variants:
1713            continue
1714        functions.defined_function_variants.add(template_args['unique_name'])
1715
1716        template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});'
1717        symbols.builtin_id_declarations.append(
1718            template_builtin_id_declaration.format(**template_args))
1719
1720        parameters_list = []
1721        for param in parameters:
1722            unique_param_name = get_variable_name_to_store_parameter(param)
1723            param_template_args = {
1724                'name': '_empty',
1725                'name_with_suffix': unique_param_name,
1726                'type': param.get_statictype_string(),
1727                'extension': 'UNDEFINED'
1728            }
1729            if unique_param_name not in functions.defined_parameter_names:
1730                id_counter += 1
1731                param_template_args['id'] = id_counter
1732                template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1733                symbols.builtin_id_declarations.append(
1734                    template_builtin_id_declaration.format(**param_template_args))
1735                define_constexpr_variable(param_template_args, variables.variable_declarations)
1736                functions.defined_parameter_names.add(unique_param_name)
1737                if param.has_array_size():
1738                    array_size_template_args = {'arraySize': param.data['arraySize']}
1739                    define_constexpr_type_array_sizes(array_size_template_args,
1740                                                      variables.type_array_sizes_declarations)
1741            parameters_list.append(
1742                '&BuiltInVariable::k{name_with_suffix}'.format(**param_template_args))
1743
1744        template_args['parameters_var_name'] = get_variable_name_to_store_parameters(parameters)
1745        if len(parameters) > 0:
1746            template_args['parameters_list'] = ', '.join(parameters_list)
1747            template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};'
1748            functions.parameter_declarations[
1749                template_args['parameters_var_name']] = template_parameter_list_declaration.format(
1750                    **template_args)
1751        else:
1752            template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;'
1753            functions.parameter_declarations[
1754                template_args['parameters_var_name']] = template_parameter_list_declaration.format(
1755                    **template_args)
1756
1757        template_args['extension'] = extension_string
1758        template_function_declaration = 'constexpr const TFunction {unique_name}(BuiltInId::{human_readable_name}, BuiltInName::{name_with_suffix}, {extension}, BuiltInParameters::{parameters_var_name}, {param_count}, {return_type}, {op}, {known_to_not_have_side_effects});'
1759        functions.function_declarations.append(
1760            template_function_declaration.format(**template_args))
1761
1762        id_counter += 1
1763
1764
1765def process_single_function_group(shader_type, group_name, group, symbols, variables, functions,
1766                                  group_op_suffix, unmangled_function_if_statements,
1767                                  mangled_builtins):
1768
1769    if 'functions' not in group:
1770        return
1771
1772    for function_props in group['functions']:
1773        process_single_function(shader_type, group_name, function_props, symbols, variables,
1774                                functions, group_op_suffix, unmangled_function_if_statements,
1775                                mangled_builtins)
1776
1777        if 'essl_extension_becomes_core_in' in function_props:
1778            assert ('essl_extension' in function_props)
1779
1780            core_props = copy.deepcopy(function_props)
1781
1782            # Adjust the props by updating the level, removing extension and adding suffix
1783            core_level = function_props['essl_extension_becomes_core_in']
1784            core_props['essl_level'] = core_level
1785            del core_props['essl_extension']
1786            suffix = core_props['suffix'] if 'suffix' in core_props else ''
1787            suffix += generate_suffix_from_level(core_level)
1788            core_props['suffix'] = suffix
1789
1790            process_single_function(shader_type, group_name, core_props, symbols, variables,
1791                                    functions, group_op_suffix, unmangled_function_if_statements,
1792                                    mangled_builtins)
1793
1794
1795def process_function_group(group_name, group, symbols, variables, functions,
1796                           parent_group_op_suffix, unmangled_function_if_statements,
1797                           mangled_builtins):
1798
1799    functions.operator_enum_declarations.append('')
1800    functions.operator_enum_declarations.append('    // Group ' + group_name)
1801    first_op_index = len(functions.operator_enum_declarations)
1802
1803    shader_type = 'NONE'
1804    if 'shader_type' in group:
1805        shader_type = group['shader_type']
1806
1807    group_op_suffix = parent_group_op_suffix + group.get('opSuffix', '')
1808    process_single_function_group(shader_type, group_name, group, symbols, variables, functions,
1809                                  group_op_suffix, unmangled_function_if_statements,
1810                                  mangled_builtins)
1811
1812    if 'subgroups' in group:
1813        for subgroup_name, subgroup in group['subgroups'].items():
1814            process_function_group(group_name + subgroup_name, subgroup, symbols, variables,
1815                                   functions, group_op_suffix, unmangled_function_if_statements,
1816                                   mangled_builtins)
1817
1818    if 'queryFunction' in group:
1819        last_op_index = len(functions.operator_enum_declarations) - 1
1820
1821        first_op = functions.find_op(first_op_index, +1, last_op_index + 1)
1822        last_op = functions.find_op(last_op_index, -1, first_op_index - 1)
1823
1824        template_args = {'first_op': first_op, 'last_op': last_op, 'group_name': group_name}
1825        template_is_in_group_definition = """static inline bool Is{group_name}(TOperator op)
1826{{
1827    return op >= {first_op} && op <= {last_op};
1828}}"""
1829        functions.is_in_group_definitions.append(
1830            template_is_in_group_definition.format(**template_args))
1831
1832
1833def prune_parameters_arrays(parameter_declarations, function_declarations):
1834    # We can share parameters arrays between functions in case one array is a subarray of another.
1835    parameter_variable_name_replacements = {}
1836    used_param_variable_names = set()
1837    for param_variable_name, param_declaration in sorted(
1838            parameter_declarations.items(), key=lambda item: -len(item[0])):
1839        replaced = False
1840        for used in sorted(used_param_variable_names):
1841            if used.startswith(param_variable_name):
1842                parameter_variable_name_replacements[param_variable_name] = used
1843                replaced = True
1844                break
1845        if not replaced:
1846            used_param_variable_names.add(param_variable_name)
1847
1848    for i in range(len(function_declarations)):
1849        for replaced, replacement in parameter_variable_name_replacements.items():
1850            function_declarations[i] = function_declarations[i].replace(
1851                'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',')
1852
1853    return [
1854        value for key, value in parameter_declarations.items() if key in used_param_variable_names
1855    ]
1856
1857
1858def process_single_variable(shader_type, variable_name, props, symbols, variables,
1859                            mangled_builtins):
1860    global id_counter
1861
1862    essl_level = props['essl_level'] if 'essl_level' in props else None
1863    glsl_level = props['glsl_level'] if 'glsl_level' in props else None
1864    template_args = {
1865        'id':
1866            id_counter,
1867        'name':
1868            variable_name,
1869        'name_with_suffix':
1870            variable_name + get_suffix(props),
1871        'essl_level':
1872            essl_level,
1873        'glsl_level':
1874            glsl_level,
1875        'essl_extension':
1876            get_essl_extension(props),
1877        'glsl_extension':
1878            get_glsl_extension(props),
1879        # This assumes that variables cannot be part of an ESSL and GLSL extension
1880        # Will need to update after adding GLSL extension variables if this is not the case
1881        'extension':
1882            get_essl_extension(props)
1883            if get_essl_extension(props) != 'UNDEFINED' else get_glsl_extension(props),
1884        'class':
1885            'TVariable'
1886    }
1887
1888    template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1889    symbols.builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args))
1890
1891    template_name_declaration = 'constexpr const ImmutableString {name}("{name}");'
1892    symbols.name_declarations.add(template_name_declaration.format(**template_args))
1893
1894    is_member = True
1895    template_init_variable = ''
1896
1897    extension_string = get_extension_list(template_args['extension'])
1898
1899    if 'type' in props:
1900        if props['type']['basic'] != 'Bool' and 'precision' not in props['type']:
1901            raise Exception('Missing precision for variable ' + variable_name)
1902        template_args['type'] = TType(props['type']).get_statictype_string()
1903
1904    if 'fields' in props:
1905        # Handle struct and interface block definitions.
1906        template_args['class'] = props['class']
1907        template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args)
1908        variables.init_member_variables.append(
1909            '    TFieldList *{fields} = new TFieldList();'.format(**template_args))
1910        for field_name, field_type in props['fields'].items():
1911            template_args['field_name'] = field_name
1912            template_args['field_type'] = TType(field_type).get_dynamic_type_string()
1913            template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");'
1914            symbols.name_declarations.add(template_name_declaration.format(**template_args))
1915            template_add_field = '    {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));'
1916            variables.init_member_variables.append(template_add_field.format(**template_args))
1917        template_args['extension'] = extension_string
1918        template_init_temp_variable = '    {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, {extension}, {fields});'
1919        variables.init_member_variables.append(template_init_temp_variable.format(**template_args))
1920        if 'private' in props and props['private']:
1921            is_member = False
1922        else:
1923            template_init_variable = '    m_{name_with_suffix} = {name_with_suffix};'
1924
1925    elif 'initDynamicType' in props:
1926        # Handle variables whose type can't be expressed as TStaticType
1927        # (type is a struct or has variable array size for example).
1928        template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args)
1929        template_args['type'] = template_args['type_name']
1930        template_args['ext_or_core_suffix'] = ''
1931        if 'essl_extension_becomes_core_in' in props and 'essl_extension' not in props:
1932            template_args['ext_or_core_suffix'] = generate_suffix_from_level(props['essl_level'])
1933        template_args['initDynamicType'] = props['initDynamicType'].format(**template_args)
1934        template_args['extension'] = extension_string
1935        template_init_variable = """    {initDynamicType}
1936{type_name}->realize();
1937m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});"""
1938
1939    elif 'value' in props:
1940        # Handle variables with constant value, such as gl_MaxDrawBuffers.
1941        if props['value'] != 'resources':
1942            raise Exception('Unrecognized value source in variable properties: ' +
1943                            str(props['value']))
1944        resources_key = variable_name[3:]
1945        if 'valueKey' in props:
1946            resources_key = props['valueKey']
1947        template_args['value'] = 'resources.' + resources_key
1948        template_args['object_size'] = TType(props['type']).get_object_size()
1949        template_args['extension'] = extension_string
1950        template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});
1951{{
1952    TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1953    unionArray[0].setIConst({value});
1954    static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1955}}"""
1956        if template_args['object_size'] > 1:
1957            template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});
1958{{
1959    TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1960    for (size_t index = 0u; index < {object_size}; ++index)
1961    {{
1962        unionArray[index].setIConst({value}[index]);
1963    }}
1964    static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1965}}"""
1966
1967    else:
1968        # Handle variables that can be stored as constexpr TVariable like
1969        # gl_Position, gl_FragColor etc.
1970        define_constexpr_variable(template_args, variables.variable_declarations)
1971        is_member = False
1972
1973        template_get_variable_declaration = 'const TVariable *{name_with_suffix}();'
1974        variables.get_variable_declarations.append(
1975            template_get_variable_declaration.format(**template_args))
1976
1977        template_get_variable_definition = """const TVariable *{name_with_suffix}()
1978{{
1979return &k{name_with_suffix};
1980}}
1981"""
1982        variables.get_variable_definitions.append(
1983            template_get_variable_definition.format(**template_args))
1984
1985        if essl_level != 'GLSL_BUILTINS':
1986            obj = '&BuiltInVariable::k{name_with_suffix}'.format(**template_args)
1987            # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
1988            mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type,
1989                                       template_args['name'], obj, template_args['essl_extension'],
1990                                       template_args['glsl_extension'],
1991                                       symbols.script_generated_hash_tests)
1992
1993    if is_member:
1994        variables.init_member_variables.append(template_init_variable.format(**template_args))
1995
1996        template_declare_member_variable = 'TSymbol *m_{name_with_suffix} = nullptr;'
1997        variables.declare_member_variables.append(
1998            template_declare_member_variable.format(**template_args))
1999
2000        obj = 'm_{name_with_suffix}'.format(**template_args)
2001
2002        # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
2003        mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type,
2004                                   template_args['name'], obj, template_args['essl_extension'],
2005                                   template_args['glsl_extension'],
2006                                   symbols.script_generated_hash_tests)
2007
2008    id_counter += 1
2009
2010
2011def process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins):
2012    global id_counter
2013    if 'variables' not in group:
2014        return
2015    for variable_name, props in group['variables'].items():
2016        process_single_variable(shader_type, variable_name, props, symbols, variables,
2017                                mangled_builtins)
2018
2019        if 'essl_extension_becomes_core_in' in props:
2020            assert ('essl_extension' in props)
2021
2022            core_props = copy.deepcopy(props)
2023
2024            # Adjust the props by updating the level, removing extension and adding suffix
2025            core_level = props['essl_extension_becomes_core_in']
2026            core_props['essl_level'] = core_level
2027            del core_props['essl_extension']
2028            suffix = core_props['suffix'] if 'suffix' in core_props else ''
2029            suffix += generate_suffix_from_level(core_level)
2030            core_props['suffix'] = suffix
2031            process_single_variable(shader_type, variable_name, core_props, symbols, variables,
2032                                    mangled_builtins)
2033
2034
2035def process_variable_group(shader_type, group_name, group, symbols, variables, mangled_builtins):
2036    global id_counter
2037
2038    if 'shader_type' in group:
2039        shader_type = group['shader_type']
2040
2041    process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins)
2042
2043    if 'subgroups' in group:
2044        for subgroup_name, subgroup in group['subgroups'].items():
2045            process_variable_group(shader_type, subgroup_name, subgroup, symbols, variables,
2046                                   mangled_builtins)
2047
2048
2049def generate_files(essl_only, args, functions_txt_filename, variables_json_filename,
2050                   immutablestring_cpp_filename, immutablestringtest_cpp_filename,
2051                   builtin_header_filename, symboltable_cpp_filename, operator_header_filename,
2052                   symboltable_header_filename):
2053
2054    symbols = SymbolsData()
2055    variables = VariablesData()
2056    functions = FunctionsData()
2057
2058    parsed_functions = get_parsed_functions(functions_txt_filename, essl_only)
2059
2060    if args.dump_intermediate_json:
2061        with open('builtin_functions_ESSL.json' if essl_only else 'builtin_functions.json',
2062                  'w') as outfile:
2063
2064            def serialize_obj(obj):
2065                if isinstance(obj, TType):
2066                    return obj.data
2067                else:
2068                    raise "Cannot serialize to JSON: " + str(obj)
2069
2070            json.dump(
2071                parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj)
2072
2073    parsed_variables = None
2074    with open(variables_json_filename) as f:
2075        # TODO(http://anglebug.com/3835): skip loading GLSL-only vars when they are added if essl_only
2076        parsed_variables = json.load(f, object_pairs_hook=OrderedDict)
2077
2078    # This script uses a perfect hash function to avoid dealing with collisions
2079    mangled_names = []
2080    unmangled_names = []
2081    for group_name, group in parsed_functions.items():
2082        get_function_names(group, mangled_names, unmangled_names)
2083    for group_name, group in parsed_variables.items():
2084        get_variable_names(group, mangled_names)
2085
2086    # Hashing mangled names
2087    mangled_names = list(dict.fromkeys(mangled_names))
2088    num_mangled_names = len(mangled_names)
2089    mangled_names_dict = dict(zip(mangled_names, range(0, len(mangled_names))))
2090    # Generate the perfect hash function
2091    f1, f2, mangled_G = generate_hash(mangled_names_dict, Hash2)
2092    mangled_hashfn = HashFunction(f1, f2, mangled_G)
2093    mangled_S1 = f1.salt
2094    mangled_S2 = f2.salt
2095    # Array for querying mangled builtins
2096    mangled_builtins = GroupedList(mangled_hashfn, num_mangled_names)
2097
2098    # Hashing unmangled names
2099    unmangled_names = list(dict.fromkeys(unmangled_names))
2100    num_unmangled_names = len(unmangled_names)
2101    unmangled_names_dict = dict(zip(unmangled_names, range(0, len(unmangled_names))))
2102    # Generate the perfect hash function
2103    f1, f2, unmangled_G = generate_hash(unmangled_names_dict, Hash2)
2104    unmangled_hashfn = HashFunction(f1, f2, unmangled_G)
2105    unmangled_S1 = f1.salt
2106    unmangled_S2 = f2.salt
2107    # Array for querying unmangled builtins
2108    unmangled_function_if_statements = UnmangledGroupedList(unmangled_hashfn, num_unmangled_names)
2109
2110    for group_name, group in parsed_functions.items():
2111        process_function_group(group_name, group, symbols, variables, functions, '',
2112                               unmangled_function_if_statements, mangled_builtins)
2113
2114    functions.parameter_declarations = prune_parameters_arrays(functions.parameter_declarations,
2115                                                               functions.function_declarations)
2116
2117    for group_name, group in parsed_variables.items():
2118        process_variable_group('NONE', group_name, group, symbols, variables, mangled_builtins)
2119
2120    mangled_builtins.update_arrays(essl_only)
2121
2122    output_strings = {
2123        'script_name':
2124            os.path.basename(__file__),
2125        'builtin_id_declarations':
2126            '\n'.join(symbols.builtin_id_declarations),
2127        'last_builtin_id':
2128            id_counter - 1,
2129        'name_declarations':
2130            '\n'.join(sorted(list(symbols.name_declarations))),
2131        'function_data_source_name':
2132            functions_txt_filename,
2133        'function_declarations':
2134            '\n'.join(functions.function_declarations),
2135        'parameter_declarations':
2136            '\n'.join(sorted(functions.parameter_declarations)),
2137        'operator_enum_declarations':
2138            '\n'.join(functions.operator_enum_declarations),
2139        'is_in_group_definitions':
2140            '\n'.join(functions.is_in_group_definitions),
2141        'variable_data_source_name':
2142            variables_json_filename,
2143        'type_array_sizes_declarations':
2144            '\n'.join(sorted(variables.type_array_sizes_declarations)),
2145        'variable_declarations':
2146            '\n'.join(sorted(variables.variable_declarations)),
2147        'get_variable_declarations':
2148            '\n'.join(sorted(variables.get_variable_declarations)),
2149        'get_variable_definitions':
2150            '\n'.join(sorted(variables.get_variable_definitions)),
2151        'declare_member_variables':
2152            '\n'.join(variables.declare_member_variables),
2153        'init_member_variables':
2154            '\n'.join(variables.init_member_variables),
2155        'mangled_names_array':
2156            ',\n'.join(mangled_builtins.get_names()),
2157        'mangled_offsets_array':
2158            '\n'.join(mangled_builtins.get_offsets()),
2159        'mangled_rules':
2160            ',\n'.join(mangled_builtins.get_rules()),
2161        'unmangled_array':
2162            ', '.join(unmangled_function_if_statements.get_array()),
2163        'max_unmangled_name_length':
2164            unmangled_function_if_statements.get_max_name_length(),
2165        'max_mangled_name_length':
2166            mangled_builtins.get_max_name_length(),
2167        'num_unmangled_names':
2168            num_unmangled_names,
2169        'num_mangled_names':
2170            num_mangled_names,
2171        'script_generated_hash_tests':
2172            '\n'.join(symbols.script_generated_hash_tests.keys()),
2173        'unmangled_script_generated_hash_tests':
2174            '\n'.join(symbols.unmangled_script_generated_hash_tests.keys()),
2175        'mangled_S1':
2176            str(mangled_S1).replace('[', ' ').replace(']', ' '),
2177        'mangled_S2':
2178            str(mangled_S2).replace('[', ' ').replace(']', ' '),
2179        'mangled_G':
2180            str(mangled_G).replace('[', ' ').replace(']', ' '),
2181        'mangled_NG':
2182            len(mangled_G),
2183        'mangled_NS':
2184            len(mangled_S1),
2185        'unmangled_S1':
2186            str(unmangled_S1).replace('[', ' ').replace(']', ' '),
2187        'unmangled_S2':
2188            str(unmangled_S2).replace('[', ' ').replace(']', ' '),
2189        'unmangled_G':
2190            str(unmangled_G).replace('[', ' ').replace(']', ' '),
2191        'unmangled_NG':
2192            len(unmangled_G),
2193        'unmangled_NS':
2194            len(unmangled_S1),
2195        'header_label':
2196            'ESSL_' if essl_only else 'complete_',
2197        'source_label':
2198            'ESSL_' if essl_only else ''
2199    }
2200
2201    with open(immutablestring_cpp_filename, 'wt') as outfile_cpp:
2202        output_cpp = template_immutablestring_cpp.format(**output_strings)
2203        outfile_cpp.write(output_cpp)
2204
2205    with open(immutablestringtest_cpp_filename, 'wt') as outfile_cpp:
2206        output_cpp = template_immutablestringtest_cpp.format(**output_strings)
2207        outfile_cpp.write(output_cpp)
2208
2209    with open(builtin_header_filename, 'wt') as outfile_header:
2210        output_header = template_builtin_header.format(**output_strings)
2211        outfile_header.write(output_header)
2212
2213    with open(symboltable_cpp_filename, 'wt') as outfile_cpp:
2214        output_cpp = template_symboltable_cpp.format(**output_strings)
2215        outfile_cpp.write(output_cpp)
2216
2217    if not essl_only:
2218        with open(operator_header_filename, 'wt') as outfile_header:
2219            output_header = template_operator_header.format(**output_strings)
2220            outfile_header.write(output_header)
2221
2222        with open(symboltable_header_filename, 'wt') as outfile_h:
2223            output_h = template_symboltable_header.format(**output_strings)
2224            outfile_h.write(output_h)
2225
2226
2227def main():
2228    random.seed(0)
2229    set_working_dir()
2230
2231    parser = argparse.ArgumentParser()
2232    parser.add_argument(
2233        '--dump-intermediate-json',
2234        help='Dump parsed function data as a JSON file builtin_functions.json',
2235        action="store_true")
2236    parser.add_argument('auto_script_command', nargs='?', default='')
2237    args = parser.parse_args()
2238
2239    test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp'
2240    essl_test_filename = '../../tests/compiler_tests/ImmutableString_test_ESSL_autogen.cpp'
2241    variables_json_filename = 'builtin_variables.json'
2242    functions_txt_filename = 'builtin_function_declarations.txt'
2243
2244    # auto_script parameters.
2245    if args.auto_script_command != '':
2246        inputs = [
2247            functions_txt_filename,
2248            variables_json_filename,
2249        ]
2250        outputs = [
2251            'ImmutableString_autogen.cpp',
2252            'Operator_autogen.h',
2253            'SymbolTable_autogen.cpp',
2254            'SymbolTable_autogen.h',
2255            'tree_util/BuiltIn_complete_autogen.h',
2256            test_filename,
2257            'ImmutableString_ESSL_autogen.cpp',
2258            'SymbolTable_ESSL_autogen.cpp',
2259            'tree_util/BuiltIn_ESSL_autogen.h',
2260            essl_test_filename,
2261        ]
2262
2263        if args.auto_script_command == 'inputs':
2264            print(','.join(inputs))
2265        elif args.auto_script_command == 'outputs':
2266            print(','.join(outputs))
2267        else:
2268            print('Invalid script parameters')
2269            return 1
2270        return 0
2271
2272    # Generate files based on GLSL + ESSL symbols
2273    generate_files(False, args, functions_txt_filename, variables_json_filename,
2274                   'ImmutableString_autogen.cpp', test_filename,
2275                   'tree_util/BuiltIn_complete_autogen.h', 'SymbolTable_autogen.cpp',
2276                   'Operator_autogen.h', 'SymbolTable_autogen.h')
2277
2278    # Generate files based on only ESSL symbols
2279    # Symbol table with GLSL + ESSL symbols is too large for Android
2280    generate_files(True, args, functions_txt_filename, variables_json_filename,
2281                   'ImmutableString_ESSL_autogen.cpp', essl_test_filename,
2282                   'tree_util/BuiltIn_ESSL_autogen.h', 'SymbolTable_ESSL_autogen.cpp',
2283                   'Operator_autogen.h', 'SymbolTable_autogen.h')
2284
2285    return 0
2286
2287
2288if __name__ == '__main__':
2289    sys.exit(main())
2290