• 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        has_side_effects = function_props['hasSideEffects']
1463        if isinstance(has_side_effects, str):
1464            assert has_side_effects in ['true',
1465                                        'false'], 'Bad side effects value: ' + has_side_effects
1466            has_side_effects = has_side_effects == 'true'
1467        assert isinstance(has_side_effects, bool)
1468        return 'false' if has_side_effects else 'true'
1469    else:
1470        for param in get_parameters(function_props):
1471            if 'qualifier' in param.data and (param.data['qualifier'] == 'ParamOut' or
1472                                              param.data['qualifier'] == 'ParamInOut'):
1473                return 'false'
1474        return 'true'
1475
1476
1477def get_parameters(function_props):
1478    if 'parameters' in function_props:
1479        return function_props['parameters']
1480    return []
1481
1482
1483def get_function_mangled_name(function_name, parameters):
1484    mangled_name = function_name + '('
1485    for param in parameters:
1486        mangled_name += param.get_mangled_name()
1487    return mangled_name
1488
1489
1490def get_function_human_readable_name(function_name, parameters):
1491    name = function_name
1492    for param in parameters:
1493        name += '_' + param.get_human_readable_name()
1494    return name
1495
1496
1497def get_unique_identifier_name(function_name, parameters):
1498    unique_name = function_name + '_'
1499    for param in parameters:
1500        unique_name += param.get_mangled_name()
1501    return unique_name
1502
1503
1504def get_variable_name_to_store_parameter(param):
1505    unique_name = 'pt'
1506    if 'qualifier' in param.data:
1507        if param.data['qualifier'] == 'ParamOut':
1508            unique_name += '_o_'
1509        if param.data['qualifier'] == 'ParamInOut':
1510            unique_name += '_io_'
1511    unique_name += param.get_mangled_name()
1512    return unique_name
1513
1514
1515def get_variable_name_to_store_parameters(parameters):
1516    if len(parameters) == 0:
1517        return 'empty'
1518    unique_name = 'p'
1519    for param in parameters:
1520        if 'qualifier' in param.data:
1521            if param.data['qualifier'] == 'ParamOut':
1522                unique_name += '_o_'
1523            if param.data['qualifier'] == 'ParamInOut':
1524                unique_name += '_io_'
1525        unique_name += param.get_mangled_name()
1526    return unique_name
1527
1528
1529def define_constexpr_type_array_sizes(template_args, type_array_sizes_declarations):
1530    template_array_sizes_declaration = 'constexpr const unsigned int kArraySize{arraySize}[1] = {{{arraySize}}};'
1531    type_array_sizes_declarations.add(template_array_sizes_declaration.format(**template_args))
1532
1533
1534def define_constexpr_variable(template_args, variable_declarations):
1535    template_args['extension'] = get_extension_list(template_args['extension'])
1536    template_variable_declaration = 'constexpr const TVariable k{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});'
1537
1538    variable_declarations.append(template_variable_declaration.format(**template_args))
1539
1540
1541def gen_function_variants(function_props):
1542    function_variants = []
1543    parameters = get_parameters(function_props)
1544    function_is_gen_type = False
1545    gen_type = set()
1546    image_params_index = 0
1547    for param in parameters + [function_props['returnType']]:
1548        if 'genType' in param.data:
1549            if param.data['genType'] not in [
1550                    'sampler_or_image_or_subpass', 'vec', 'yes', 'image_params'
1551            ]:
1552                raise Exception(
1553                    'Unexpected value of genType "' + str(param.data['genType']) +
1554                    '" should be "sampler_or_image_or_subpass", "vec", "yes", or "image_params"')
1555            gen_type.add(param.data['genType'])
1556            if param.data['genType'] == 'image_params':
1557                image_params_index = parameters.index(param)
1558
1559    if len(gen_type) == 0:
1560        function_variants.append(function_props)
1561        return function_variants
1562
1563    # If we have image_params then we're generating variants for 33 separate functions,
1564    # each for a different type of image variable
1565    if 'image_params' in gen_type:
1566        variants = [['gimage2D', 'ivec2'], ['gimage3D', 'ivec3'], ['gimageCube', 'ivec3'],
1567                    ['gimageBuffer', 'int'], ['gimage2DArray', 'ivec3'],
1568                    ['gimageCubeArray', 'ivec3'], ['gimage1D', 'int'], ['gimage1DArray', 'ivec2'],
1569                    ['gimageRect', 'ivec2'], ['gimage2DMS', 'ivec2', 'int'],
1570                    ['gimage2DMSArray', 'ivec3', 'int']]
1571        for variant in variants:
1572            image_variant_parameters = []
1573            for param in parameters:
1574                if parameters.index(param) == image_params_index:
1575                    for variant_param in variant:
1576                        image_variant_parameters.append(TType(variant_param))
1577                else:
1578                    image_variant_parameters.append(param)
1579            types = ['', 'I', 'U']
1580            for type in types:
1581                variant_props = function_props.copy()
1582                variant_parameters = []
1583                for param in image_variant_parameters:
1584                    variant_parameters.append(
1585                        param.specific_sampler_or_image_or_subpass_type(type))
1586                variant_props['parameters'] = variant_parameters
1587                variant_props['returnType'] = function_props[
1588                    'returnType'].specific_sampler_or_image_or_subpass_type(type)
1589                function_variants.append(variant_props)
1590        return function_variants
1591
1592    # If we have a gsampler_or_image_or_subpass then we're generating variants for float, int and uint
1593    # samplers.
1594    if 'sampler_or_image_or_subpass' in gen_type:
1595        types = ['', 'I', 'U']
1596        for type in types:
1597            variant_props = function_props.copy()
1598            variant_parameters = []
1599            for param in parameters:
1600                variant_parameters.append(param.specific_sampler_or_image_or_subpass_type(type))
1601            variant_props['parameters'] = variant_parameters
1602            variant_props['returnType'] = function_props[
1603                'returnType'].specific_sampler_or_image_or_subpass_type(type)
1604            function_variants.append(variant_props)
1605        return function_variants
1606
1607    # If we have a normal gentype then we're generating variants for different sizes of vectors.
1608    sizes = range(1, 5)
1609    if 'vec' in gen_type:
1610        sizes = range(2, 5)
1611    for size in sizes:
1612        variant_props = function_props.copy()
1613        variant_parameters = []
1614        for param in parameters:
1615            variant_parameters.append(param.specific_type(size))
1616        variant_props['parameters'] = variant_parameters
1617        variant_props['returnType'] = function_props['returnType'].specific_type(size)
1618        function_variants.append(variant_props)
1619    return function_variants
1620
1621
1622def process_single_function(shader_type, group_name, function_props, symbols, variables, functions,
1623                            group_op_suffix, unmangled_function_if_statements, mangled_builtins):
1624    global id_counter
1625
1626    function_name = function_props['name']
1627    essl_level = function_props['essl_level'] if 'essl_level' in function_props else None
1628    glsl_level = function_props['glsl_level'] if 'glsl_level' in function_props else None
1629    essl_extension = get_essl_extension(function_props)
1630    glsl_extension = get_glsl_extension(function_props)
1631    extension = essl_extension if essl_extension != 'UNDEFINED' else glsl_extension
1632    op = get_op(function_name, function_props, group_op_suffix)
1633    template_args = {
1634        'name': function_name,
1635        'name_with_suffix': function_name + get_suffix(function_props),
1636        'essl_level': essl_level,
1637        'glsl_level': glsl_level,
1638        'essl_extension': essl_extension,
1639        'glsl_extension': glsl_extension,
1640        # This assumes that functions cannot be part of an ESSL and GLSL extension
1641        # Will need to update after adding GLSL extension functions if this is not the case
1642        'extension': essl_extension if essl_extension != 'UNDEFINED' else glsl_extension,
1643        'op': op,
1644        'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props)
1645    }
1646
1647    function_variants = gen_function_variants(function_props)
1648
1649    template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");'
1650    name_declaration = template_name_declaration.format(**template_args)
1651    if not name_declaration in symbols.name_declarations:
1652        symbols.name_declarations.add(name_declaration)
1653
1654    essl_ext = '{essl_extension}'.format(**template_args)
1655    glsl_ext = '{glsl_extension}'.format(**template_args)
1656    unmangled_builtin_no_shader_type = unmangled_function_if_statements.get(
1657        essl_level, glsl_level, 'NONE', function_name)
1658    if unmangled_builtin_no_shader_type != None and unmangled_builtin_no_shader_type[
1659            'essl_extension'] == 'UNDEFINED' and unmangled_builtin_no_shader_type[
1660                'glsl_extension'] == 'UNDEFINED':
1661        # We already have this unmangled name without a shader type nor extension on the same level.
1662        # No need to add a duplicate with a type.
1663        pass
1664    elif (not unmangled_function_if_statements.has_key(
1665            essl_level, glsl_level, shader_type, function_name)) or (
1666                unmangled_builtin_no_shader_type and
1667                ((essl_extension == 'UNDEFINED' and
1668                  unmangled_builtin_no_shader_type['essl_extension'] != 'UNDEFINED') or
1669                 (glsl_extension == 'UNDEFINED' and
1670                  unmangled_builtin_no_shader_type['glsl_extension'] != 'UNDEFINED'))):
1671        unmangled_function_if_statements.add_entry(essl_level, glsl_level, shader_type,
1672                                                   function_name, essl_ext, glsl_ext,
1673                                                   essl_extension, glsl_extension,
1674                                                   symbols.unmangled_script_generated_hash_tests)
1675
1676    extension_string = get_extension_list(template_args['extension'])
1677
1678    if op not in functions.operator_list:
1679        functions.operator_list[op] = group_name
1680        is_unary = group_name.startswith('Math') and len(get_parameters(function_variants[0])) == 1
1681        assert (not is_unary or
1682                all([len(get_parameters(props)) == 1 for props in function_variants]))
1683
1684        template_operator_enum = '    {op},{is_unary_comment}'
1685        template_args['is_unary_comment'] = '  // Unary' if is_unary else ''
1686
1687        functions.operator_enum_declarations.append(template_operator_enum.format(**template_args))
1688    else:
1689        # Ensure that built-ins in different groups don't generate the same op.  The Is<Group> query
1690        # functions rely on this.
1691        previous_group_name = functions.operator_list[op]
1692        if group_name != previous_group_name:
1693            print('Op ' + op + ' found in group ' + group_name + ' but was previously in group ' +
1694                  previous_group_name)
1695        assert (group_name == previous_group_name)
1696
1697    for function_props in function_variants:
1698        template_args['id'] = id_counter
1699
1700        parameters = get_parameters(function_props)
1701
1702        template_args['unique_name'] = get_unique_identifier_name(
1703            template_args['name_with_suffix'], parameters)
1704        template_args['param_count'] = len(parameters)
1705        template_args['return_type'] = function_props['returnType'].get_statictype_string()
1706        template_args['mangled_name'] = get_function_mangled_name(function_name, parameters)
1707        template_args['human_readable_name'] = get_function_human_readable_name(
1708            template_args['name_with_suffix'], parameters)
1709        template_args['mangled_name_length'] = len(template_args['mangled_name'])
1710
1711        symbol = '&Func::{unique_name}'.format(**template_args)
1712        mangled_builtins.add_entry(essl_level, glsl_level, shader_type,
1713                                   template_args['mangled_name'], symbol,
1714                                   template_args['essl_extension'],
1715                                   template_args['glsl_extension'],
1716                                   symbols.script_generated_hash_tests)
1717
1718        if template_args['unique_name'] in functions.defined_function_variants:
1719            continue
1720        functions.defined_function_variants.add(template_args['unique_name'])
1721
1722        template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});'
1723        symbols.builtin_id_declarations.append(
1724            template_builtin_id_declaration.format(**template_args))
1725
1726        parameters_list = []
1727        for param in parameters:
1728            unique_param_name = get_variable_name_to_store_parameter(param)
1729            param_template_args = {
1730                'name': '_empty',
1731                'name_with_suffix': unique_param_name,
1732                'type': param.get_statictype_string(),
1733                'extension': 'UNDEFINED'
1734            }
1735            if unique_param_name not in functions.defined_parameter_names:
1736                id_counter += 1
1737                param_template_args['id'] = id_counter
1738                template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1739                symbols.builtin_id_declarations.append(
1740                    template_builtin_id_declaration.format(**param_template_args))
1741                define_constexpr_variable(param_template_args, variables.variable_declarations)
1742                functions.defined_parameter_names.add(unique_param_name)
1743                if param.has_array_size():
1744                    array_size_template_args = {'arraySize': param.data['arraySize']}
1745                    define_constexpr_type_array_sizes(array_size_template_args,
1746                                                      variables.type_array_sizes_declarations)
1747            parameters_list.append(
1748                '&BuiltInVariable::k{name_with_suffix}'.format(**param_template_args))
1749
1750        template_args['parameters_var_name'] = get_variable_name_to_store_parameters(parameters)
1751        if len(parameters) > 0:
1752            template_args['parameters_list'] = ', '.join(parameters_list)
1753            template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};'
1754            functions.parameter_declarations[
1755                template_args['parameters_var_name']] = template_parameter_list_declaration.format(
1756                    **template_args)
1757        else:
1758            template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;'
1759            functions.parameter_declarations[
1760                template_args['parameters_var_name']] = template_parameter_list_declaration.format(
1761                    **template_args)
1762
1763        template_args['extension'] = extension_string
1764        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});'
1765        functions.function_declarations.append(
1766            template_function_declaration.format(**template_args))
1767
1768        id_counter += 1
1769
1770
1771def process_single_function_group(shader_type, group_name, group, symbols, variables, functions,
1772                                  group_op_suffix, unmangled_function_if_statements,
1773                                  mangled_builtins):
1774
1775    if 'functions' not in group:
1776        return
1777
1778    for function_props in group['functions']:
1779        process_single_function(shader_type, group_name, function_props, symbols, variables,
1780                                functions, group_op_suffix, unmangled_function_if_statements,
1781                                mangled_builtins)
1782
1783        if 'essl_extension_becomes_core_in' in function_props:
1784            assert ('essl_extension' in function_props)
1785
1786            core_props = copy.deepcopy(function_props)
1787
1788            # Adjust the props by updating the level, removing extension and adding suffix
1789            core_level = function_props['essl_extension_becomes_core_in']
1790            core_props['essl_level'] = core_level
1791            del core_props['essl_extension']
1792            suffix = core_props['suffix'] if 'suffix' in core_props else ''
1793            suffix += generate_suffix_from_level(core_level)
1794            core_props['suffix'] = suffix
1795
1796            process_single_function(shader_type, group_name, core_props, symbols, variables,
1797                                    functions, group_op_suffix, unmangled_function_if_statements,
1798                                    mangled_builtins)
1799
1800
1801def process_function_group(group_name, group, symbols, variables, functions,
1802                           parent_group_op_suffix, unmangled_function_if_statements,
1803                           mangled_builtins):
1804
1805    functions.operator_enum_declarations.append('')
1806    functions.operator_enum_declarations.append('    // Group ' + group_name)
1807    first_op_index = len(functions.operator_enum_declarations)
1808
1809    shader_type = 'NONE'
1810    if 'shader_type' in group:
1811        shader_type = group['shader_type']
1812
1813    group_op_suffix = parent_group_op_suffix + group.get('opSuffix', '')
1814    process_single_function_group(shader_type, group_name, group, symbols, variables, functions,
1815                                  group_op_suffix, unmangled_function_if_statements,
1816                                  mangled_builtins)
1817
1818    if 'subgroups' in group:
1819        for subgroup_name, subgroup in group['subgroups'].items():
1820            process_function_group(group_name + subgroup_name, subgroup, symbols, variables,
1821                                   functions, group_op_suffix, unmangled_function_if_statements,
1822                                   mangled_builtins)
1823
1824    if 'queryFunction' in group:
1825        last_op_index = len(functions.operator_enum_declarations) - 1
1826
1827        first_op = functions.find_op(first_op_index, +1, last_op_index + 1)
1828        last_op = functions.find_op(last_op_index, -1, first_op_index - 1)
1829
1830        template_args = {'first_op': first_op, 'last_op': last_op, 'group_name': group_name}
1831        template_is_in_group_definition = """static inline bool Is{group_name}(TOperator op)
1832{{
1833    return op >= {first_op} && op <= {last_op};
1834}}"""
1835        functions.is_in_group_definitions.append(
1836            template_is_in_group_definition.format(**template_args))
1837
1838
1839def prune_parameters_arrays(parameter_declarations, function_declarations):
1840    # We can share parameters arrays between functions in case one array is a subarray of another.
1841    parameter_variable_name_replacements = {}
1842    used_param_variable_names = set()
1843    for param_variable_name, param_declaration in sorted(
1844            parameter_declarations.items(), key=lambda item: -len(item[0])):
1845        replaced = False
1846        for used in sorted(used_param_variable_names):
1847            if used.startswith(param_variable_name):
1848                parameter_variable_name_replacements[param_variable_name] = used
1849                replaced = True
1850                break
1851        if not replaced:
1852            used_param_variable_names.add(param_variable_name)
1853
1854    for i in range(len(function_declarations)):
1855        for replaced, replacement in parameter_variable_name_replacements.items():
1856            function_declarations[i] = function_declarations[i].replace(
1857                'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',')
1858
1859    return [
1860        value for key, value in parameter_declarations.items() if key in used_param_variable_names
1861    ]
1862
1863
1864def process_single_variable(shader_type, variable_name, props, symbols, variables,
1865                            mangled_builtins):
1866    global id_counter
1867
1868    essl_level = props['essl_level'] if 'essl_level' in props else None
1869    glsl_level = props['glsl_level'] if 'glsl_level' in props else None
1870    template_args = {
1871        'id':
1872            id_counter,
1873        'name':
1874            variable_name,
1875        'name_with_suffix':
1876            variable_name + get_suffix(props),
1877        'essl_level':
1878            essl_level,
1879        'glsl_level':
1880            glsl_level,
1881        'essl_extension':
1882            get_essl_extension(props),
1883        'glsl_extension':
1884            get_glsl_extension(props),
1885        # This assumes that variables cannot be part of an ESSL and GLSL extension
1886        # Will need to update after adding GLSL extension variables if this is not the case
1887        'extension':
1888            get_essl_extension(props)
1889            if get_essl_extension(props) != 'UNDEFINED' else get_glsl_extension(props),
1890        'class':
1891            'TVariable'
1892    }
1893
1894    template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1895    symbols.builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args))
1896
1897    template_name_declaration = 'constexpr const ImmutableString {name}("{name}");'
1898    symbols.name_declarations.add(template_name_declaration.format(**template_args))
1899
1900    is_member = True
1901    template_init_variable = ''
1902
1903    extension_string = get_extension_list(template_args['extension'])
1904
1905    if 'type' in props:
1906        if props['type']['basic'] != 'Bool' and 'precision' not in props['type']:
1907            raise Exception('Missing precision for variable ' + variable_name)
1908        template_args['type'] = TType(props['type']).get_statictype_string()
1909
1910    if 'fields' in props:
1911        # Handle struct and interface block definitions.
1912        template_args['class'] = props['class']
1913        template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args)
1914        variables.init_member_variables.append(
1915            '    TFieldList *{fields} = new TFieldList();'.format(**template_args))
1916        for field_name, field_type in props['fields'].items():
1917            template_args['field_name'] = field_name
1918            template_args['field_type'] = TType(field_type).get_dynamic_type_string()
1919            template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");'
1920            symbols.name_declarations.add(template_name_declaration.format(**template_args))
1921            template_add_field = '    {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));'
1922            variables.init_member_variables.append(template_add_field.format(**template_args))
1923        template_args['extension'] = extension_string
1924        template_init_temp_variable = '    {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, {extension}, {fields});'
1925        variables.init_member_variables.append(template_init_temp_variable.format(**template_args))
1926        if 'private' in props and props['private']:
1927            is_member = False
1928        else:
1929            template_init_variable = '    m_{name_with_suffix} = {name_with_suffix};'
1930
1931    elif 'initDynamicType' in props:
1932        # Handle variables whose type can't be expressed as TStaticType
1933        # (type is a struct or has variable array size for example).
1934        template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args)
1935        template_args['type'] = template_args['type_name']
1936        template_args['ext_or_core_suffix'] = ''
1937        if 'essl_extension_becomes_core_in' in props and 'essl_extension' not in props:
1938            template_args['ext_or_core_suffix'] = generate_suffix_from_level(props['essl_level'])
1939        template_args['initDynamicType'] = props['initDynamicType'].format(**template_args)
1940        template_args['extension'] = extension_string
1941        template_init_variable = """    {initDynamicType}
1942{type_name}->realize();
1943m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});"""
1944
1945    elif 'value' in props:
1946        # Handle variables with constant value, such as gl_MaxDrawBuffers.
1947        if props['value'] != 'resources':
1948            raise Exception('Unrecognized value source in variable properties: ' +
1949                            str(props['value']))
1950        resources_key = variable_name[3:]
1951        if 'valueKey' in props:
1952            resources_key = props['valueKey']
1953        template_args['value'] = 'resources.' + resources_key
1954        template_args['object_size'] = TType(props['type']).get_object_size()
1955        template_args['extension'] = extension_string
1956        template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});
1957{{
1958    TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1959    unionArray[0].setIConst({value});
1960    static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1961}}"""
1962        if template_args['object_size'] > 1:
1963            template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, {extension}, {type});
1964{{
1965    TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1966    for (size_t index = 0u; index < {object_size}; ++index)
1967    {{
1968        unionArray[index].setIConst({value}[index]);
1969    }}
1970    static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1971}}"""
1972
1973    else:
1974        # Handle variables that can be stored as constexpr TVariable like
1975        # gl_Position, gl_FragColor etc.
1976        define_constexpr_variable(template_args, variables.variable_declarations)
1977        is_member = False
1978
1979        template_get_variable_declaration = 'const TVariable *{name_with_suffix}();'
1980        variables.get_variable_declarations.append(
1981            template_get_variable_declaration.format(**template_args))
1982
1983        template_get_variable_definition = """const TVariable *{name_with_suffix}()
1984{{
1985return &k{name_with_suffix};
1986}}
1987"""
1988        variables.get_variable_definitions.append(
1989            template_get_variable_definition.format(**template_args))
1990
1991        if essl_level != 'GLSL_BUILTINS':
1992            obj = '&BuiltInVariable::k{name_with_suffix}'.format(**template_args)
1993            # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
1994            mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type,
1995                                       template_args['name'], obj, template_args['essl_extension'],
1996                                       template_args['glsl_extension'],
1997                                       symbols.script_generated_hash_tests)
1998
1999    if is_member:
2000        variables.init_member_variables.append(template_init_variable.format(**template_args))
2001
2002        template_declare_member_variable = 'TSymbol *m_{name_with_suffix} = nullptr;'
2003        variables.declare_member_variables.append(
2004            template_declare_member_variable.format(**template_args))
2005
2006        obj = 'm_{name_with_suffix}'.format(**template_args)
2007
2008        # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
2009        mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type,
2010                                   template_args['name'], obj, template_args['essl_extension'],
2011                                   template_args['glsl_extension'],
2012                                   symbols.script_generated_hash_tests)
2013
2014    id_counter += 1
2015
2016
2017def process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins):
2018    global id_counter
2019    if 'variables' not in group:
2020        return
2021    for variable_name, props in group['variables'].items():
2022        process_single_variable(shader_type, variable_name, props, symbols, variables,
2023                                mangled_builtins)
2024
2025        if 'essl_extension_becomes_core_in' in props:
2026            assert ('essl_extension' in props)
2027
2028            core_props = copy.deepcopy(props)
2029
2030            # Adjust the props by updating the level, removing extension and adding suffix
2031            core_level = props['essl_extension_becomes_core_in']
2032            core_props['essl_level'] = core_level
2033            del core_props['essl_extension']
2034            suffix = core_props['suffix'] if 'suffix' in core_props else ''
2035            suffix += generate_suffix_from_level(core_level)
2036            core_props['suffix'] = suffix
2037            process_single_variable(shader_type, variable_name, core_props, symbols, variables,
2038                                    mangled_builtins)
2039
2040
2041def process_variable_group(shader_type, group_name, group, symbols, variables, mangled_builtins):
2042    global id_counter
2043
2044    if 'shader_type' in group:
2045        shader_type = group['shader_type']
2046
2047    process_single_variable_group(shader_type, group, symbols, variables, mangled_builtins)
2048
2049    if 'subgroups' in group:
2050        for subgroup_name, subgroup in group['subgroups'].items():
2051            process_variable_group(shader_type, subgroup_name, subgroup, symbols, variables,
2052                                   mangled_builtins)
2053
2054
2055def generate_files(essl_only, args, functions_txt_filename, variables_json_filename,
2056                   immutablestring_cpp_filename, immutablestringtest_cpp_filename,
2057                   builtin_header_filename, symboltable_cpp_filename, operator_header_filename,
2058                   symboltable_header_filename):
2059
2060    symbols = SymbolsData()
2061    variables = VariablesData()
2062    functions = FunctionsData()
2063
2064    parsed_functions = get_parsed_functions(functions_txt_filename, essl_only)
2065
2066    if args.dump_intermediate_json:
2067        with open('builtin_functions_ESSL.json' if essl_only else 'builtin_functions.json',
2068                  'w') as outfile:
2069
2070            def serialize_obj(obj):
2071                if isinstance(obj, TType):
2072                    return obj.data
2073                else:
2074                    raise "Cannot serialize to JSON: " + str(obj)
2075
2076            json.dump(
2077                parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj)
2078
2079    parsed_variables = None
2080    with open(variables_json_filename) as f:
2081        # TODO(http://anglebug.com/3835): skip loading GLSL-only vars when they are added if essl_only
2082        parsed_variables = json.load(f, object_pairs_hook=OrderedDict)
2083
2084    # This script uses a perfect hash function to avoid dealing with collisions
2085    mangled_names = []
2086    unmangled_names = []
2087    for group_name, group in parsed_functions.items():
2088        get_function_names(group, mangled_names, unmangled_names)
2089    for group_name, group in parsed_variables.items():
2090        get_variable_names(group, mangled_names)
2091
2092    # Hashing mangled names
2093    mangled_names = list(dict.fromkeys(mangled_names))
2094    num_mangled_names = len(mangled_names)
2095    mangled_names_dict = dict(zip(mangled_names, range(0, len(mangled_names))))
2096    # Generate the perfect hash function
2097    f1, f2, mangled_G = generate_hash(mangled_names_dict, Hash2)
2098    mangled_hashfn = HashFunction(f1, f2, mangled_G)
2099    mangled_S1 = f1.salt
2100    mangled_S2 = f2.salt
2101    # Array for querying mangled builtins
2102    mangled_builtins = GroupedList(mangled_hashfn, num_mangled_names)
2103
2104    # Hashing unmangled names
2105    unmangled_names = list(dict.fromkeys(unmangled_names))
2106    num_unmangled_names = len(unmangled_names)
2107    unmangled_names_dict = dict(zip(unmangled_names, range(0, len(unmangled_names))))
2108    # Generate the perfect hash function
2109    f1, f2, unmangled_G = generate_hash(unmangled_names_dict, Hash2)
2110    unmangled_hashfn = HashFunction(f1, f2, unmangled_G)
2111    unmangled_S1 = f1.salt
2112    unmangled_S2 = f2.salt
2113    # Array for querying unmangled builtins
2114    unmangled_function_if_statements = UnmangledGroupedList(unmangled_hashfn, num_unmangled_names)
2115
2116    for group_name, group in parsed_functions.items():
2117        process_function_group(group_name, group, symbols, variables, functions, '',
2118                               unmangled_function_if_statements, mangled_builtins)
2119
2120    functions.parameter_declarations = prune_parameters_arrays(functions.parameter_declarations,
2121                                                               functions.function_declarations)
2122
2123    for group_name, group in parsed_variables.items():
2124        process_variable_group('NONE', group_name, group, symbols, variables, mangled_builtins)
2125
2126    mangled_builtins.update_arrays(essl_only)
2127
2128    output_strings = {
2129        'script_name':
2130            os.path.basename(__file__),
2131        'builtin_id_declarations':
2132            '\n'.join(symbols.builtin_id_declarations),
2133        'last_builtin_id':
2134            id_counter - 1,
2135        'name_declarations':
2136            '\n'.join(sorted(list(symbols.name_declarations))),
2137        'function_data_source_name':
2138            functions_txt_filename,
2139        'function_declarations':
2140            '\n'.join(functions.function_declarations),
2141        'parameter_declarations':
2142            '\n'.join(sorted(functions.parameter_declarations)),
2143        'operator_enum_declarations':
2144            '\n'.join(functions.operator_enum_declarations),
2145        'is_in_group_definitions':
2146            '\n'.join(functions.is_in_group_definitions),
2147        'variable_data_source_name':
2148            variables_json_filename,
2149        'type_array_sizes_declarations':
2150            '\n'.join(sorted(variables.type_array_sizes_declarations)),
2151        'variable_declarations':
2152            '\n'.join(sorted(variables.variable_declarations)),
2153        'get_variable_declarations':
2154            '\n'.join(sorted(variables.get_variable_declarations)),
2155        'get_variable_definitions':
2156            '\n'.join(sorted(variables.get_variable_definitions)),
2157        'declare_member_variables':
2158            '\n'.join(variables.declare_member_variables),
2159        'init_member_variables':
2160            '\n'.join(variables.init_member_variables),
2161        'mangled_names_array':
2162            ',\n'.join(mangled_builtins.get_names()),
2163        'mangled_offsets_array':
2164            '\n'.join(mangled_builtins.get_offsets()),
2165        'mangled_rules':
2166            ',\n'.join(mangled_builtins.get_rules()),
2167        'unmangled_array':
2168            ', '.join(unmangled_function_if_statements.get_array()),
2169        'max_unmangled_name_length':
2170            unmangled_function_if_statements.get_max_name_length(),
2171        'max_mangled_name_length':
2172            mangled_builtins.get_max_name_length(),
2173        'num_unmangled_names':
2174            num_unmangled_names,
2175        'num_mangled_names':
2176            num_mangled_names,
2177        'script_generated_hash_tests':
2178            '\n'.join(symbols.script_generated_hash_tests.keys()),
2179        'unmangled_script_generated_hash_tests':
2180            '\n'.join(symbols.unmangled_script_generated_hash_tests.keys()),
2181        'mangled_S1':
2182            str(mangled_S1).replace('[', ' ').replace(']', ' '),
2183        'mangled_S2':
2184            str(mangled_S2).replace('[', ' ').replace(']', ' '),
2185        'mangled_G':
2186            str(mangled_G).replace('[', ' ').replace(']', ' '),
2187        'mangled_NG':
2188            len(mangled_G),
2189        'mangled_NS':
2190            len(mangled_S1),
2191        'unmangled_S1':
2192            str(unmangled_S1).replace('[', ' ').replace(']', ' '),
2193        'unmangled_S2':
2194            str(unmangled_S2).replace('[', ' ').replace(']', ' '),
2195        'unmangled_G':
2196            str(unmangled_G).replace('[', ' ').replace(']', ' '),
2197        'unmangled_NG':
2198            len(unmangled_G),
2199        'unmangled_NS':
2200            len(unmangled_S1),
2201        'header_label':
2202            'ESSL_' if essl_only else 'complete_',
2203        'source_label':
2204            'ESSL_' if essl_only else ''
2205    }
2206
2207    with open(immutablestring_cpp_filename, 'wt') as outfile_cpp:
2208        output_cpp = template_immutablestring_cpp.format(**output_strings)
2209        outfile_cpp.write(output_cpp)
2210
2211    with open(immutablestringtest_cpp_filename, 'wt') as outfile_cpp:
2212        output_cpp = template_immutablestringtest_cpp.format(**output_strings)
2213        outfile_cpp.write(output_cpp)
2214
2215    with open(builtin_header_filename, 'wt') as outfile_header:
2216        output_header = template_builtin_header.format(**output_strings)
2217        outfile_header.write(output_header)
2218
2219    with open(symboltable_cpp_filename, 'wt') as outfile_cpp:
2220        output_cpp = template_symboltable_cpp.format(**output_strings)
2221        outfile_cpp.write(output_cpp)
2222
2223    if not essl_only:
2224        with open(operator_header_filename, 'wt') as outfile_header:
2225            output_header = template_operator_header.format(**output_strings)
2226            outfile_header.write(output_header)
2227
2228        with open(symboltable_header_filename, 'wt') as outfile_h:
2229            output_h = template_symboltable_header.format(**output_strings)
2230            outfile_h.write(output_h)
2231
2232
2233def main():
2234    random.seed(0)
2235    set_working_dir()
2236
2237    parser = argparse.ArgumentParser()
2238    parser.add_argument(
2239        '--dump-intermediate-json',
2240        help='Dump parsed function data as a JSON file builtin_functions.json',
2241        action="store_true")
2242    parser.add_argument('auto_script_command', nargs='?', default='')
2243    args = parser.parse_args()
2244
2245    test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp'
2246    essl_test_filename = '../../tests/compiler_tests/ImmutableString_test_ESSL_autogen.cpp'
2247    variables_json_filename = 'builtin_variables.json'
2248    functions_txt_filename = 'builtin_function_declarations.txt'
2249
2250    # auto_script parameters.
2251    if args.auto_script_command != '':
2252        inputs = [
2253            functions_txt_filename,
2254            variables_json_filename,
2255        ]
2256        outputs = [
2257            'ImmutableString_autogen.cpp',
2258            'Operator_autogen.h',
2259            'SymbolTable_autogen.cpp',
2260            'SymbolTable_autogen.h',
2261            'tree_util/BuiltIn_complete_autogen.h',
2262            test_filename,
2263            'ImmutableString_ESSL_autogen.cpp',
2264            'SymbolTable_ESSL_autogen.cpp',
2265            'tree_util/BuiltIn_ESSL_autogen.h',
2266            essl_test_filename,
2267        ]
2268
2269        if args.auto_script_command == 'inputs':
2270            print(','.join(inputs))
2271        elif args.auto_script_command == 'outputs':
2272            print(','.join(outputs))
2273        else:
2274            print('Invalid script parameters')
2275            return 1
2276        return 0
2277
2278    # Generate files based on GLSL + ESSL symbols
2279    generate_files(False, args, functions_txt_filename, variables_json_filename,
2280                   'ImmutableString_autogen.cpp', test_filename,
2281                   'tree_util/BuiltIn_complete_autogen.h', 'SymbolTable_autogen.cpp',
2282                   'Operator_autogen.h', 'SymbolTable_autogen.h')
2283
2284    # Generate files based on only ESSL symbols
2285    # Symbol table with GLSL + ESSL symbols is too large for Android
2286    generate_files(True, args, functions_txt_filename, variables_json_filename,
2287                   'ImmutableString_ESSL_autogen.cpp', essl_test_filename,
2288                   'tree_util/BuiltIn_ESSL_autogen.h', 'SymbolTable_ESSL_autogen.cpp',
2289                   'Operator_autogen.h', 'SymbolTable_autogen.h')
2290
2291    return 0
2292
2293
2294if __name__ == '__main__':
2295    sys.exit(main())
2296