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