1#!/usr/bin/env vpython
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 datetime import date
19from perfect_hash import generate_hash, Hash2
20import argparse
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 {copyright_year} 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 {copyright_year} 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 {copyright_year} 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 {copyright_year} 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 {copyright_year} 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_parsecontext_header = """// GENERATED FILE - DO NOT EDIT.
388// Generated by {script_name} using data from {variable_data_source_name} and
389// {function_data_source_name}.
390//
391// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
392// Use of this source code is governed by a BSD-style license that can be
393// found in the LICENSE file.
394//
395// ParseContext_{header_label}autogen.h:
396//   Helpers for built-in related checks.
397
398#ifndef COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
399#define COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
400
401namespace sh
402{{
403
404namespace BuiltInGroup
405{{
406
407{is_in_group_definitions}
408
409}}  // namespace BuiltInGroup
410
411}}  // namespace sh
412
413#endif  // COMPILER_TRANSLATOR_PARSECONTEXT_AUTOGEN_H_
414
415"""
416
417template_rule = """Rule::Get<{spec}, {version}, {shaders}, {extension}>({symbol_or_var})"""
418
419basic_types_enumeration = [
420    'Void',
421    'Float',
422    'Double',
423    'Int',
424    'UInt',
425    'Bool',
426    'AtomicCounter',
427    'YuvCscStandardEXT',
428    'Sampler2D',
429    'Sampler3D',
430    'SamplerCube',
431    'Sampler2DArray',
432    'SamplerExternalOES',
433    'SamplerExternal2DY2YEXT',
434    'Sampler2DRect',
435    'Sampler2DMS',
436    'Sampler2DMSArray',
437    'ISampler2D',
438    'ISampler3D',
439    'ISamplerCube',
440    'ISampler2DArray',
441    'ISampler2DMS',
442    'ISampler2DMSArray',
443    'USampler2D',
444    'USampler3D',
445    'USamplerCube',
446    'USampler2DArray',
447    'USampler2DMS',
448    'USampler2DMSArray',
449    'Sampler2DShadow',
450    'SamplerCubeShadow',
451    'Sampler2DArrayShadow',
452    'Sampler1D',
453    'Sampler1DArray',
454    'Sampler1DArrayShadow',
455    'SamplerBuffer',
456    'SamplerCubeArray',
457    'SamplerCubeArrayShadow',
458    'Sampler1DShadow',
459    'Sampler2DRectShadow',
460    'ISampler1D',
461    'ISampler1DArray',
462    'ISampler2DRect',
463    'ISamplerBuffer',
464    'ISamplerCubeArray',
465    'USampler1D',
466    'USampler1DArray',
467    'USampler2DRect',
468    'USamplerBuffer',
469    'USamplerCubeArray',
470    'SamplerVideoWEBGL',
471    'Image2D',
472    'IImage2D',
473    'UImage2D',
474    'Image3D',
475    'IImage3D',
476    'UImage3D',
477    'Image2DArray',
478    'IImage2DArray',
479    'UImage2DArray',
480    'ImageCube',
481    'IImageCube',
482    'UImageCube',
483    'Image1D',
484    'IImage1D',
485    'UImage1D',
486    'Image1DArray',
487    'IImage1DArray',
488    'UImage1DArray',
489    'Image2DMS',
490    'IImage2DMS',
491    'UImage2DMS',
492    'Image2DMSArray',
493    'IImage2DMSArray',
494    'UImage2DMSArray',
495    'Image2DRect',
496    'IImage2DRect',
497    'UImage2DRect',
498    'ImageCubeArray',
499    'IImageCubeArray',
500    'UImageCubeArray',
501    'ImageRect',
502    'IImageRect',
503    'UImageRect',
504    'ImageBuffer',
505    'IImageBuffer',
506    'UImageBuffer',
507    'SubpassInput',
508    'ISubpassInput',
509    'USubpassInput',
510    'SubpassInputMS',
511    'ISubpassInputMS',
512    'USubpassInputMS',
513]
514
515id_counter = 0
516
517
518def set_working_dir():
519    script_dir = os.path.dirname(os.path.abspath(__file__))
520    os.chdir(script_dir)
521
522
523def get_basic_mangled_name(basic):
524    index = basic_types_enumeration.index(basic)
525    if index < 26:
526        return '0' + chr(ord('A') + index)
527    if index < 52:
528        return '0' + chr(ord('a') + index - 26)
529    if index < 78:
530        return '1' + chr(ord('A') + index - 52)
531    return '1' + chr(ord('a') + index - 78)
532
533
534essl_levels = [
535    'ESSL3_2_BUILTINS', 'ESSL3_1_BUILTINS', 'ESSL3_BUILTINS', 'ESSL1_BUILTINS', 'COMMON_BUILTINS'
536]
537
538glsl_levels = [
539    'GLSL4_6_BUILTINS', 'GLSL4_5_BUILTINS', 'GLSL4_4_BUILTINS', 'GLSL4_3_BUILTINS',
540    'GLSL4_2_BUILTINS', 'GLSL4_1_BUILTINS', 'GLSL4_BUILTINS', 'GLSL3_3_BUILTINS',
541    'GLSL1_5_BUILTINS', 'GLSL1_4_BUILTINS', 'GLSL1_3_BUILTINS', 'GLSL1_2_BUILTINS',
542    'COMMON_BUILTINS'
543]
544
545
546def get_essl_shader_version_for_level(level):
547    if level == None:
548        return '-1'
549    elif level == 'ESSL3_2_BUILTINS':
550        return '320'
551    elif level == 'ESSL3_1_BUILTINS':
552        return '310'
553    elif level == 'ESSL3_BUILTINS':
554        return '300'
555    elif level == 'ESSL1_BUILTINS':
556        return '100'
557    elif level == 'COMMON_BUILTINS':
558        return '0'
559    else:
560        raise Exception('Unsupported symbol table level')
561
562
563def get_glsl_shader_version_for_level(level):
564    if level == None:
565        return '-1'
566    elif level == 'GLSL1_2_BUILTINS':
567        return '120'
568    elif level == 'GLSL1_3_BUILTINS':
569        return '130'
570    elif level == 'GLSL1_4_BUILTINS':
571        return '140'
572    elif level == 'GLSL1_5_BUILTINS':
573        return '150'
574    elif level == 'GLSL3_3_BUILTINS':
575        return '330'
576    elif level == 'GLSL4_BUILTINS':
577        return '400'
578    elif level == 'GLSL4_1_BUILTINS':
579        return '410'
580    elif level == 'GLSL4_2_BUILTINS':
581        return '420'
582    elif level == 'GLSL4_3_BUILTINS':
583        return '430'
584    elif level == 'GLSL4_4_BUILTINS':
585        return '440'
586    elif level == 'GLSL4_5_BUILTINS':
587        return '450'
588    elif level == 'GLSL4_6_BUILTINS':
589        return '460'
590    elif level == 'COMMON_BUILTINS':
591        return '0'
592    else:
593        raise Exception('Unsupported symbol table level')
594
595
596def get_shader_version_for_level(spec, level):
597    if spec == "ESSL":
598        return get_essl_shader_version_for_level(level)
599    else:
600        return get_glsl_shader_version_for_level(level)
601
602
603class GroupedList:
604    """"Class for storing a list of objects grouped by symbol table level and condition."""
605
606    def __init__(self, hashfn, num_names):
607        self.objs = OrderedDict()
608        self.max_name_length = 0
609        self.hashfn = hashfn
610        self.num_names = num_names
611        self.rule_offset = 0
612
613    def add_entry(self, essl_level, glsl_level, shader_type, name, symbol, essl_extension,
614                  glsl_extension, script_generated_hash_tests):
615        if essl_level and essl_level not in essl_levels:
616            raise Exception('Unexpected essl level: ' + str(essl_level))
617        if glsl_level and glsl_level not in glsl_levels:
618            raise Exception('Unexpected glsl level: ' + str(glsl_level))
619        if len(name) > self.max_name_length:
620            self.max_name_length = len(name)
621
622        name_hash = mangledNameHash(name, self.hashfn, script_generated_hash_tests, False)
623        if name_hash not in self.objs:
624            self.objs[name_hash] = OrderedDict()
625
626        self.objs[name_hash]['name'] = name
627
628        if essl_extension == 'UNDEFINED' and glsl_extension == 'UNDEFINED':
629            if essl_level:
630                self.objs[name_hash]['essl_level'] = essl_level
631            if glsl_level:
632                self.objs[name_hash]['glsl_level'] = glsl_level
633            self.objs[name_hash]['symbol'] = symbol
634            self.objs[name_hash]['shader_type'] = shader_type
635
636        if essl_extension != 'UNDEFINED':
637            if ('essl_ext_symbol' in self.objs[name_hash] and
638                    self.objs[name_hash]['essl_ext_symbol'] != symbol):
639                # Adding a variable that is part of two ESSL extensions
640                if essl_extension != 'UNDEFINED':
641                    self.objs[name_hash]['essl_extension2'] = essl_extension
642                    self.objs[name_hash]['essl_ext_level2'] = essl_level
643                    self.objs[name_hash]['essl_ext_symbol2'] = symbol
644                    self.objs[name_hash]['essl_ext_shader_type2'] = shader_type
645            else:
646                self.objs[name_hash]['essl_extension'] = essl_extension
647                self.objs[name_hash]['essl_ext_level'] = essl_level
648                self.objs[name_hash]['essl_ext_symbol'] = symbol
649                self.objs[name_hash]['essl_ext_shader_type'] = shader_type
650
651        if glsl_extension != 'UNDEFINED':
652            self.objs[name_hash]['glsl_extension'] = glsl_extension
653            self.objs[name_hash]['glsl_ext_level'] = glsl_level
654            self.objs[name_hash]['glsl_ext_symbol'] = symbol
655            self.objs[name_hash]['glsl_ext_shader_type'] = shader_type
656
657    def get_max_name_length(self):
658        return self.max_name_length
659
660    def format_rule(self, rule):
661        return template_rule.format(**rule)
662
663    def format_rules(self, rules):
664        return ", ".join([self.format_rule(rule) for rule in rules])
665
666    def get_rules(self):
667        return self.rules
668
669    def get_names(self):
670        return self.names
671
672    def get_offsets(self):
673        return self.offsets
674
675    def update_arrays(self):
676
677        def add_rule(rules, spec, level, shaders, extension, symbol):
678            var = ("&TableBase::%s" % symbol) if symbol.startswith("m_gl") else None
679
680            rules.append({
681                "spec": "Spec::%s" % ("ESSL" if spec == "ESSL" else "GLSL"),
682                "version": get_shader_version_for_level(spec, level),
683                "shaders": "Shader::%s" % ("ALL" if shaders == "NONE" else shaders),
684                "extension": "0" if extension == None else "EXT_INDEX(%s)" % extension,
685                "symbol_or_var": symbol.replace("Func::", "") if var is None else var
686            })
687
688        self.names = []
689        self.offsets = []
690        self.rules = []
691        for hash_val in range(0, self.num_names):
692            if hash_val in self.objs:
693                data = self.objs[hash_val]
694
695                rules = []
696
697                if "symbol" in data and "essl_level" in data:
698                    add_rule(rules, "ESSL", data['essl_level'], data['shader_type'], None,
699                             data["symbol"])
700
701                if "symbol" in data and "glsl_level" in data:
702                    add_rule(rules, "GLSL", data['glsl_level'], data['shader_type'], None,
703                             data["symbol"])
704
705                if "essl_ext_symbol" in data:
706                    add_rule(rules, "ESSL", data["essl_ext_level"], data["essl_ext_shader_type"],
707                             data["essl_extension"], data["essl_ext_symbol"])
708
709                if "glsl_ext_symbol" in data:
710                    add_rule(rules, "GLSL", data["glsl_ext_level"], data["glsl_ext_shader_type"],
711                             data["glsl_extension"], data["glsl_ext_symbol"])
712
713                if "essl_ext_symbol2" in data:
714                    add_rule(rules, "ESSL", data["essl_ext_level2"], data["essl_ext_shader_type2"],
715                             data["essl_extension2"], data["essl_ext_symbol2"])
716
717                name = data['name']
718                name_underscore = name.replace("(", "_")
719
720                self.names.append('"%s"' % name)
721                self.offsets.append("%d, // %s" % (self.rule_offset, name_underscore))
722                self.rules.append("%s" % self.format_rules(rules))
723
724                self.rule_offset += len(rules)
725
726            else:
727                self.names.append('""')
728                self.offsets.append('%d, // Empty' % self.rule_offset)
729
730
731class UnmangledGroupedList:
732    """"Class for storing a list of unmangled objects grouped by symbol table level and condition."""
733
734    def __init__(self, hashfn, num_names):
735        self.objs = OrderedDict()
736        self.max_name_length = 0
737        self.hashfn = hashfn
738        self.num_names = num_names
739
740    def add_entry(self, essl_level, glsl_level, shader_type, name, essl_ext, glsl_ext,
741                  essl_extension, glsl_extension, unmangled_script_generated_hash_tests):
742        if essl_level and essl_level not in essl_levels:
743            raise Exception('Unexpected essl level: ' + str(essl_level))
744        if glsl_level and glsl_level not in glsl_levels:
745            raise Exception('Unexpected glsl level: ' + str(glsl_level))
746        if len(name) > self.max_name_length:
747            self.max_name_length = len(name)
748
749        name_hash = mangledNameHash(name, self.hashfn, unmangled_script_generated_hash_tests, True)
750        self.objs[name_hash] = OrderedDict()
751        self.objs[name_hash]['name'] = name
752        self.objs[name_hash]['essl_level'] = essl_level
753        self.objs[name_hash]['glsl_level'] = glsl_level
754        self.objs[name_hash]['shader_type'] = shader_type
755        self.objs[name_hash]['essl_ext'] = essl_ext
756        self.objs[name_hash]['glsl_ext'] = glsl_ext
757        self.objs[name_hash]['essl_extension'] = essl_extension
758        self.objs[name_hash]['glsl_extension'] = glsl_extension
759
760    def has_key(self, essl_level, glsl_level, shader_type, name):
761        name_hash = mangledNameHash(name, self.hashfn, None, True, False)
762        if name_hash not in self.objs:
763            return False
764        entry = self.objs[name_hash]
765        if entry['essl_level'] != essl_level:
766            return False
767        if entry['glsl_level'] != glsl_level:
768            return False
769        if entry['shader_type'] != shader_type:
770            return False
771        return True
772
773    def get(self, essl_level, glsl_level, shader_type, name):
774        if self.has_key(essl_level, glsl_level, shader_type, name):
775            name_hash = mangledNameHash(name, self.hashfn, None, True, False)
776            return self.objs[name_hash]
777        return None
778
779    def get_max_name_length(self):
780        return self.max_name_length
781
782    def get_array(self):
783        code = []
784        for hash_val in range(0, self.num_names):
785            obj = self.objs[hash_val]
786            essl_level = obj['essl_level']
787            glsl_level = obj['glsl_level']
788            shader_type = 'Shader::' + obj['shader_type'] if obj[
789                'shader_type'] != 'NONE' else 'Shader::ALL'
790            data = []
791            data.append('"{name}"'.format(name=obj['name']))
792            data.append("Ext::" + obj['essl_extension'])
793            data.append("Ext::" + obj['glsl_extension'])
794            data.append(get_essl_shader_version_for_level(essl_level))
795            data.append(get_glsl_shader_version_for_level(glsl_level))
796            data.append(shader_type)
797
798            code.append('{%s}' % ', '.join(data))
799        return code
800
801
802class TType:
803
804    def __init__(self, glsl_header_type):
805        if isinstance(glsl_header_type, basestring):
806            self.data = self.parse_type(glsl_header_type)
807        else:
808            self.data = glsl_header_type
809        self.normalize()
810
811    def normalize(self):
812        # Note that this will set primarySize and secondarySize also on genTypes. In that case they
813        # are overridden when the specific types are generated.
814        if 'primarySize' not in self.data:
815            if ('secondarySize' in self.data):
816                raise Exception(
817                    'Unexpected secondarySize on type that does not have primarySize set')
818            self.data['primarySize'] = 1
819        if 'secondarySize' not in self.data:
820            self.data['secondarySize'] = 1
821        if 'precision' not in self.data:
822            self.data['precision'] = 'Undefined'
823        if 'qualifier' not in self.data:
824            self.data['qualifier'] = 'Global'
825
826    def has_array_size(self):
827        return 'arraySize' in self.data
828
829    def get_statictype_string(self):
830        template_type = 'StaticType::Get<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}>()'
831        if self.has_array_size():
832            template_type = 'StaticType::GetArray<Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}, kArraySize{arraySize}, 1>()'
833        return template_type.format(**self.data)
834
835    def get_dynamic_type_string(self):
836        template_type = 'new TType(Ebt{basic}, Ebp{precision}, Evq{qualifier}, {primarySize}, {secondarySize}'
837        if self.has_array_size():
838            template_type += ', TVector<unsigned int>{{{arraySize}}}'
839        template_type += ')'
840        return template_type.format(**self.data)
841
842    def get_mangled_name(self):
843        mangled_name = ''
844
845        size_key = (self.data['secondarySize'] - 1) * 4 + self.data['primarySize'] - 1
846        if size_key < 10:
847            mangled_name += chr(ord('0') + size_key)
848        else:
849            mangled_name += chr(ord('A') + size_key - 10)
850        mangled_name += get_basic_mangled_name(self.data['basic'])
851        if self.has_array_size():
852            mangled_name += 'x' + str(self.data['arraySize'])
853        return mangled_name
854
855    def get_human_readable_name(self):
856        name = self.data['basic']
857        if self.has_array_size():
858            name = str(self.data['arraySize']) + 'x' + name
859        name += str(self.data['primarySize'])
860        if self.data['secondarySize'] > 1:
861            name += 'x' + str(self.data['secondarySize'])
862        return name
863
864    def is_vector(self):
865        return self.data['primarySize'] > 1 and self.data['secondarySize'] == 1
866
867    def is_matrix(self):
868        return self.data['secondarySize'] > 1
869
870    def get_object_size(self):
871        return self.data['primarySize'] * self.data['secondarySize']
872
873    def specific_sampler_or_image_or_subpass_type(self, basic_type_prefix):
874        if 'genType' in self.data and self.data['genType'] == 'sampler_or_image_or_subpass':
875            type = {}
876            if 'basic' not in self.data:
877                type['basic'] = {'': 'Float', 'I': 'Int', 'U': 'UInt'}[basic_type_prefix]
878                type['primarySize'] = self.data['primarySize']
879            else:
880                type['basic'] = basic_type_prefix + self.data['basic']
881                type['primarySize'] = 1
882            type['precision'] = 'Undefined'
883            return TType(type)
884        return self
885
886    def specific_type(self, vec_size):
887        type = {}
888        if 'genType' in self.data:
889            type['basic'] = self.data['basic']
890            type['precision'] = self.data['precision']
891            type['qualifier'] = self.data['qualifier']
892            type['primarySize'] = vec_size
893            type['secondarySize'] = 1
894            return TType(type)
895        return self
896
897    def parse_type(self, glsl_header_type):
898        # TODO(http://anglebug.com/3833): handle readonly, writeonly qualifiers
899        if glsl_header_type.startswith('readonly writeonly '):
900            type_obj = self.parse_type(glsl_header_type[19:])
901            type_obj['qualifier'] = 'Readonly Writeonly'
902            return type_obj
903        if glsl_header_type.startswith('readonly '):
904            type_obj = self.parse_type(glsl_header_type[9:])
905            type_obj['qualifier'] = 'Readonly'
906            return type_obj
907        if glsl_header_type.startswith('writeonly '):
908            type_obj = self.parse_type(glsl_header_type[10:])
909            type_obj['qualifier'] = 'Writeonly'
910            return type_obj
911        if glsl_header_type.startswith('out '):
912            type_obj = self.parse_type(glsl_header_type[4:])
913            type_obj['qualifier'] = 'Out'
914            return type_obj
915        if glsl_header_type.startswith('inout '):
916            type_obj = self.parse_type(glsl_header_type[6:])
917            type_obj['qualifier'] = 'InOut'
918            return type_obj
919
920        basic_type_map = {
921            'float': 'Float',
922            'int': 'Int',
923            'uint': 'UInt',
924            'double': 'Double',
925            'bool': 'Bool',
926            'void': 'Void',
927            'atomic_uint': 'AtomicCounter',
928            'yuvCscStandardEXT': 'YuvCscStandardEXT'
929        }
930
931        if glsl_header_type in basic_type_map:
932            return {'basic': basic_type_map[glsl_header_type]}
933
934        type_obj = {}
935
936        basic_type_prefix_map = {
937            '': 'Float',
938            'i': 'Int',
939            'u': 'UInt',
940            'd': 'Double',
941            'b': 'Bool',
942            'v': 'Void'
943        }
944
945        vec_re = re.compile(r'^([iudb]?)vec([234]?)((\[[234]\])?)$')
946        vec_match = vec_re.match(glsl_header_type)
947        if vec_match:
948            type_obj['basic'] = basic_type_prefix_map[vec_match.group(1)]
949            if vec_match.group(2) == '':
950                # Type like "ivec" that represents either ivec2, ivec3 or ivec4
951                type_obj['genType'] = 'vec'
952            else:
953                # vec with specific size
954                if vec_match.group(3) != '':
955                    # vec array
956                    type_obj['primarySize'] = int(vec_match.group(2))
957                    type_obj['arraySize'] = int(vec_match.group(3)[1])
958                else:
959                    type_obj['primarySize'] = int(vec_match.group(2))
960            return type_obj
961
962        mat_re = re.compile(r'^mat([234])(x([234]))?$')
963        mat_match = mat_re.match(glsl_header_type)
964        if mat_match:
965            type_obj['basic'] = 'Float'
966            if len(glsl_header_type) == 4:
967                mat_size = int(mat_match.group(1))
968                type_obj['primarySize'] = mat_size
969                type_obj['secondarySize'] = mat_size
970            else:
971                type_obj['primarySize'] = int(mat_match.group(1))
972                type_obj['secondarySize'] = int(mat_match.group(3))
973            return type_obj
974
975        gen_re = re.compile(r'^gen([IUDB]?)Type$')
976        gen_match = gen_re.match(glsl_header_type)
977        if gen_match:
978            type_obj['basic'] = basic_type_prefix_map[gen_match.group(1).lower()]
979            type_obj['genType'] = 'yes'
980            return type_obj
981
982        if glsl_header_type.startswith('sampler'):
983            type_obj['basic'] = glsl_header_type[0].upper() + glsl_header_type[1:]
984            return type_obj
985
986        if glsl_header_type.startswith('gsampler') or glsl_header_type.startswith(
987                'gimage') or glsl_header_type.startswith('gsubpassInput'):
988            type_obj['basic'] = glsl_header_type[1].upper() + glsl_header_type[2:]
989            type_obj['genType'] = 'sampler_or_image_or_subpass'
990            return type_obj
991
992        if glsl_header_type == 'gvec4':
993            return {'primarySize': 4, 'genType': 'sampler_or_image_or_subpass'}
994        if glsl_header_type == 'gvec3':
995            return {'primarySize': 3, 'genType': 'sampler_or_image_or_subpass'}
996
997        if glsl_header_type == 'IMAGE_PARAMS':
998            return {'genType': 'image_params'}
999
1000        raise Exception('Unrecognized type: ' + str(glsl_header_type))
1001
1002
1003class HashFunction:
1004
1005    def __init__(self, f1, f2, G):
1006        self.f1 = f1
1007        self.f2 = f2
1008        self.G = G
1009
1010    def hash(self, key):
1011        return (self.G[self.f1(key)] + self.G[self.f2(key)]) % len(self.G)
1012
1013
1014def get_parsed_functions(functions_txt_filename, essl_only):
1015
1016    def parse_function_parameters(parameters):
1017        if parameters == '':
1018            return []
1019        parametersOut = []
1020        parameters = parameters.split(', ')
1021        for parameter in parameters:
1022            parametersOut.append(TType(parameter.strip()))
1023        return parametersOut
1024
1025    lines = []
1026    with open(functions_txt_filename) as f:
1027        lines = f.readlines()
1028    lines = [
1029        line.strip() for line in lines if line.strip() != '' and not line.strip().startswith('//')
1030    ]
1031
1032    fun_re = re.compile(r'^(\w+) (\w+)\((.*)\);$')
1033
1034    parsed_functions = OrderedDict()
1035    group_stack = []
1036    default_metadata = {}
1037
1038    for line in lines:
1039        fun_match = fun_re.match(line)
1040        if line.startswith('GROUP BEGIN '):
1041            group_rest = line[12:].strip()
1042            group_parts = group_rest.split(' ', 1)
1043            current_group = {'functions': [], 'name': group_parts[0], 'subgroups': {}}
1044            if len(group_parts) > 1:
1045                group_metadata = json.loads(group_parts[1])
1046                current_group.update(group_metadata)
1047            group_stack.append(current_group)
1048        elif line.startswith('GROUP END '):
1049            group_end_name = line[10:].strip()
1050            current_group = group_stack[-1]
1051            if current_group['name'] != group_end_name:
1052                raise Exception('GROUP END: Unexpected function group name "' + group_end_name +
1053                                '" was expecting "' + current_group['name'] + '"')
1054            group_stack.pop()
1055            is_top_level_group = (len(group_stack) == 0)
1056            if is_top_level_group:
1057                parsed_functions[current_group['name']] = current_group
1058                default_metadata = {}
1059            else:
1060                super_group = group_stack[-1]
1061                super_group['subgroups'][current_group['name']] = current_group
1062        elif line.startswith('DEFAULT METADATA'):
1063            line_rest = line[16:].strip()
1064            default_metadata = json.loads(line_rest)
1065        elif fun_match:
1066            return_type = fun_match.group(1)
1067            name = fun_match.group(2)
1068            parameters = fun_match.group(3)
1069            function_props = {
1070                'name': name,
1071                'returnType': TType(return_type),
1072                'parameters': parse_function_parameters(parameters)
1073            }
1074            function_props.update(default_metadata)
1075            if essl_only:
1076                # Skip GLSL-only functions
1077                if 'essl_level' in function_props:
1078                    group_stack[-1]['functions'].append(function_props)
1079            else:
1080                group_stack[-1]['functions'].append(function_props)
1081        else:
1082            raise Exception('Unexpected function input line: ' + line)
1083
1084    return parsed_functions
1085
1086
1087def mangledNameHash(str, hashfn, script_generated_hash_tests, unmangled, save_test=True):
1088    hash = hashfn.hash(str)
1089    if save_test:
1090        sanity_check = ''
1091        if unmangled:
1092            sanity_check = '    ASSERT_EQ(0x{hash}u, ImmutableString("{str}").unmangledNameHash());'.format(
1093                hash=('%08x' % hash), str=str)
1094        else:
1095            sanity_check = '    ASSERT_EQ(0x{hash}u, ImmutableString("{str}").mangledNameHash());'.format(
1096                hash=('%08x' % hash), str=str)
1097        script_generated_hash_tests.update({sanity_check: None})
1098    return hash
1099
1100
1101def get_function_names(group, mangled_names, unmangled_names):
1102    if 'functions' in group:
1103        for function_props in group['functions']:
1104            function_name = function_props['name']
1105            unmangled_names.append(function_name)
1106            function_variants = gen_function_variants(function_props)
1107            for function_props in function_variants:
1108                parameters = get_parameters(function_props)
1109                mangled_names.append(get_function_mangled_name(function_name, parameters))
1110    if 'subgroups' in group:
1111        for subgroup_name, subgroup in group['subgroups'].iteritems():
1112            get_function_names(subgroup, mangled_names, unmangled_names)
1113
1114
1115def get_variable_names(group, mangled_names):
1116    if 'variables' in group:
1117        for variable_name, props in group['variables'].iteritems():
1118            mangled_names.append(variable_name)
1119    if 'subgroups' in group:
1120        for subgroup_name, subgroup in group['subgroups'].iteritems():
1121            get_variable_names(subgroup, mangled_names)
1122
1123
1124def get_suffix(props):
1125    if 'suffix' in props:
1126        return props['suffix']
1127    return ''
1128
1129
1130def get_essl_extension(props):
1131    if 'essl_extension' in props:
1132        return props['essl_extension']
1133    return 'UNDEFINED'
1134
1135
1136def get_glsl_extension(props):
1137    if 'glsl_extension' in props:
1138        return props['glsl_extension']
1139    return 'UNDEFINED'
1140
1141
1142def get_op(name, function_props):
1143    if 'op' not in function_props:
1144        raise Exception('function op not defined')
1145    if function_props['op'] == 'auto':
1146        return name[0].upper() + name[1:]
1147    return function_props['op']
1148
1149
1150def get_known_to_not_have_side_effects(function_props):
1151    if 'op' in function_props and function_props['op'] != 'CallBuiltInFunction':
1152        if 'hasSideEffects' in function_props:
1153            return 'false'
1154        else:
1155            for param in get_parameters(function_props):
1156                if 'qualifier' in param.data and (param.data['qualifier'] == 'Out' or
1157                                                  param.data['qualifier'] == 'InOut'):
1158                    return 'false'
1159            return 'true'
1160    return 'false'
1161
1162
1163def get_parameters(function_props):
1164    if 'parameters' in function_props:
1165        return function_props['parameters']
1166    return []
1167
1168
1169def get_function_mangled_name(function_name, parameters):
1170    mangled_name = function_name + '('
1171    for param in parameters:
1172        mangled_name += param.get_mangled_name()
1173    return mangled_name
1174
1175
1176def get_function_human_readable_name(function_name, parameters):
1177    name = function_name
1178    for param in parameters:
1179        name += '_' + param.get_human_readable_name()
1180    return name
1181
1182
1183def get_unique_identifier_name(function_name, parameters):
1184    unique_name = function_name + '_'
1185    for param in parameters:
1186        unique_name += param.get_mangled_name()
1187    return unique_name
1188
1189
1190def get_variable_name_to_store_parameter(param):
1191    unique_name = 'pt'
1192    if 'qualifier' in param.data:
1193        if param.data['qualifier'] == 'Out':
1194            unique_name += '_o_'
1195        if param.data['qualifier'] == 'InOut':
1196            unique_name += '_io_'
1197    unique_name += param.get_mangled_name()
1198    return unique_name
1199
1200
1201def get_variable_name_to_store_parameters(parameters):
1202    if len(parameters) == 0:
1203        return 'empty'
1204    unique_name = 'p'
1205    for param in parameters:
1206        if 'qualifier' in param.data:
1207            if param.data['qualifier'] == 'Out':
1208                unique_name += '_o_'
1209            if param.data['qualifier'] == 'InOut':
1210                unique_name += '_io_'
1211        unique_name += param.get_mangled_name()
1212    return unique_name
1213
1214
1215def define_constexpr_type_array_sizes(template_args, type_array_sizes_declarations):
1216    template_array_sizes_declaration = 'constexpr const unsigned int kArraySize{arraySize}[1] = {{{arraySize}}};'
1217    type_array_sizes_declarations.add(template_array_sizes_declaration.format(**template_args))
1218
1219
1220def define_constexpr_variable(template_args, variable_declarations):
1221    template_variable_declaration = 'constexpr const TVariable k{name_with_suffix}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});'
1222    variable_declarations.append(template_variable_declaration.format(**template_args))
1223
1224
1225def gen_function_variants(function_props):
1226    function_variants = []
1227    parameters = get_parameters(function_props)
1228    function_is_gen_type = False
1229    gen_type = set()
1230    image_params_index = 0
1231    for param in parameters + [function_props['returnType']]:
1232        if 'genType' in param.data:
1233            if param.data['genType'] not in [
1234                    'sampler_or_image_or_subpass', 'vec', 'yes', 'image_params'
1235            ]:
1236                raise Exception(
1237                    'Unexpected value of genType "' + str(param.data['genType']) +
1238                    '" should be "sampler_or_image_or_subpass", "vec", "yes", or "image_params"')
1239            gen_type.add(param.data['genType'])
1240            if param.data['genType'] == 'image_params':
1241                image_params_index = parameters.index(param)
1242
1243    if len(gen_type) == 0:
1244        function_variants.append(function_props)
1245        return function_variants
1246
1247    # If we have image_params then we're generating variants for 33 separate functions,
1248    # each for a different type of image variable
1249    if 'image_params' in gen_type:
1250        variants = [['gimage2D', 'ivec2'], ['gimage3D', 'ivec3'], ['gimageCube', 'ivec3'],
1251                    ['gimageBuffer', 'int'], ['gimage2DArray', 'ivec3'],
1252                    ['gimageCubeArray', 'ivec3'], ['gimage1D', 'int'], ['gimage1DArray', 'ivec2'],
1253                    ['gimage2DRect', 'ivec2'], ['gimage2DMS', 'ivec2', 'int'],
1254                    ['gimage2DMSArray', 'ivec3', 'int']]
1255        for variant in variants:
1256            image_variant_parameters = []
1257            for param in parameters:
1258                if parameters.index(param) == image_params_index:
1259                    for variant_param in variant:
1260                        image_variant_parameters.append(TType(variant_param))
1261                else:
1262                    image_variant_parameters.append(param)
1263            types = ['', 'I', 'U']
1264            for type in types:
1265                variant_props = function_props.copy()
1266                variant_parameters = []
1267                for param in image_variant_parameters:
1268                    variant_parameters.append(
1269                        param.specific_sampler_or_image_or_subpass_type(type))
1270                variant_props['parameters'] = variant_parameters
1271                variant_props['returnType'] = function_props[
1272                    'returnType'].specific_sampler_or_image_or_subpass_type(type)
1273                function_variants.append(variant_props)
1274        return function_variants
1275
1276    # If we have a gsampler_or_image_or_subpass then we're generating variants for float, int and uint
1277    # samplers.
1278    if 'sampler_or_image_or_subpass' in gen_type:
1279        types = ['', 'I', 'U']
1280        for type in types:
1281            variant_props = function_props.copy()
1282            variant_parameters = []
1283            for param in parameters:
1284                variant_parameters.append(param.specific_sampler_or_image_or_subpass_type(type))
1285            variant_props['parameters'] = variant_parameters
1286            variant_props['returnType'] = function_props[
1287                'returnType'].specific_sampler_or_image_or_subpass_type(type)
1288            function_variants.append(variant_props)
1289        return function_variants
1290
1291    # If we have a normal gentype then we're generating variants for different sizes of vectors.
1292    sizes = range(1, 5)
1293    if 'vec' in gen_type:
1294        sizes = range(2, 5)
1295    for size in sizes:
1296        variant_props = function_props.copy()
1297        variant_parameters = []
1298        for param in parameters:
1299            variant_parameters.append(param.specific_type(size))
1300        variant_props['parameters'] = variant_parameters
1301        variant_props['returnType'] = function_props['returnType'].specific_type(size)
1302        function_variants.append(variant_props)
1303    return function_variants
1304
1305
1306def process_single_function_group(
1307        shader_type, group_name, group, parameter_declarations, name_declarations,
1308        unmangled_function_if_statements, defined_function_variants, builtin_id_declarations,
1309        builtin_id_definitions, defined_parameter_names, type_array_sizes_declarations,
1310        variable_declarations, function_declarations, script_generated_hash_tests,
1311        unmangled_script_generated_hash_tests, mangled_builtins):
1312    global id_counter
1313
1314    if 'functions' not in group:
1315        return
1316
1317    for function_props in group['functions']:
1318        function_name = function_props['name']
1319        essl_level = function_props['essl_level'] if 'essl_level' in function_props else None
1320        glsl_level = function_props['glsl_level'] if 'glsl_level' in function_props else None
1321        essl_extension = get_essl_extension(function_props)
1322        glsl_extension = get_glsl_extension(function_props)
1323        extension = essl_extension if essl_extension != 'UNDEFINED' else glsl_extension
1324        template_args = {
1325            'name': function_name,
1326            'name_with_suffix': function_name + get_suffix(function_props),
1327            'essl_level': essl_level,
1328            'glsl_level': glsl_level,
1329            'essl_extension': essl_extension,
1330            'glsl_extension': glsl_extension,
1331            # This assumes that functions cannot be part of an ESSL and GLSL extension
1332            # Will need to update after adding GLSL extension functions if this is not the case
1333            'extension': essl_extension if essl_extension != 'UNDEFINED' else glsl_extension,
1334            'op': get_op(function_name, function_props),
1335            'known_to_not_have_side_effects': get_known_to_not_have_side_effects(function_props)
1336        }
1337
1338        function_variants = gen_function_variants(function_props)
1339
1340        template_name_declaration = 'constexpr const ImmutableString {name_with_suffix}("{name}");'
1341        name_declaration = template_name_declaration.format(**template_args)
1342        if not name_declaration in name_declarations:
1343            name_declarations.add(name_declaration)
1344
1345        essl_ext = '{essl_extension}'.format(**template_args)
1346        glsl_ext = '{glsl_extension}'.format(**template_args)
1347        unmangled_builtin_no_shader_type = unmangled_function_if_statements.get(
1348            essl_level, glsl_level, 'NONE', function_name)
1349        if unmangled_builtin_no_shader_type != None and unmangled_builtin_no_shader_type[
1350                'essl_extension'] == 'UNDEFINED' and unmangled_builtin_no_shader_type[
1351                    'glsl_extension'] == 'UNDEFINED':
1352            # We already have this unmangled name without a shader type nor extension on the same level.
1353            # No need to add a duplicate with a type.
1354            pass
1355        elif (not unmangled_function_if_statements.has_key(
1356                essl_level, glsl_level, shader_type, function_name)) or (
1357                    unmangled_builtin_no_shader_type and
1358                    ((essl_extension == 'UNDEFINED' and
1359                      unmangled_builtin_no_shader_type['essl_extension'] != 'UNDEFINED') or
1360                     (glsl_extension == 'UNDEFINED' and
1361                      unmangled_builtin_no_shader_type['glsl_extension'] != 'UNDEFINED'))):
1362            unmangled_function_if_statements.add_entry(
1363                essl_level, glsl_level, shader_type, function_name, essl_ext, glsl_ext,
1364                essl_extension, glsl_extension, unmangled_script_generated_hash_tests)
1365
1366        for function_props in function_variants:
1367            template_args['id'] = id_counter
1368
1369            parameters = get_parameters(function_props)
1370
1371            template_args['unique_name'] = get_unique_identifier_name(
1372                template_args['name_with_suffix'], parameters)
1373            template_args['param_count'] = len(parameters)
1374            template_args['return_type'] = function_props['returnType'].get_statictype_string()
1375            template_args['mangled_name'] = get_function_mangled_name(function_name, parameters)
1376            template_args['human_readable_name'] = get_function_human_readable_name(
1377                template_args['name_with_suffix'], parameters)
1378            template_args['mangled_name_length'] = len(template_args['mangled_name'])
1379
1380            symbol = '&Func::{unique_name}'.format(**template_args)
1381            mangled_builtins.add_entry(
1382                essl_level, glsl_level, shader_type, template_args['mangled_name'], symbol,
1383                template_args['essl_extension'], template_args['glsl_extension'],
1384                script_generated_hash_tests)
1385
1386            if template_args['unique_name'] in defined_function_variants:
1387                continue
1388            defined_function_variants.add(template_args['unique_name'])
1389
1390            template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {human_readable_name} = TSymbolUniqueId({id});'
1391            builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args))
1392            template_builtin_id_definition = 'constexpr const TSymbolUniqueId BuiltInId::{human_readable_name};'
1393            builtin_id_definitions.append(template_builtin_id_definition.format(**template_args))
1394
1395            parameters_list = []
1396            for param in parameters:
1397                unique_param_name = get_variable_name_to_store_parameter(param)
1398                param_template_args = {
1399                    'name': '_empty',
1400                    'name_with_suffix': unique_param_name,
1401                    'type': param.get_statictype_string(),
1402                    'extension': 'UNDEFINED'
1403                }
1404                if unique_param_name not in defined_parameter_names:
1405                    id_counter += 1
1406                    param_template_args['id'] = id_counter
1407                    template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1408                    builtin_id_declarations.append(
1409                        template_builtin_id_declaration.format(**param_template_args))
1410                    define_constexpr_variable(param_template_args, variable_declarations)
1411                    defined_parameter_names.add(unique_param_name)
1412                    if param.has_array_size():
1413                        array_size_template_args = {'arraySize': param.data['arraySize']}
1414                        define_constexpr_type_array_sizes(array_size_template_args,
1415                                                          type_array_sizes_declarations)
1416                parameters_list.append(
1417                    '&BuiltInVariable::k{name_with_suffix}'.format(**param_template_args))
1418
1419            template_args['parameters_var_name'] = get_variable_name_to_store_parameters(
1420                parameters)
1421            if len(parameters) > 0:
1422                template_args['parameters_list'] = ', '.join(parameters_list)
1423                template_parameter_list_declaration = 'constexpr const TVariable *{parameters_var_name}[{param_count}] = {{ {parameters_list} }};'
1424                parameter_declarations[template_args[
1425                    'parameters_var_name']] = template_parameter_list_declaration.format(
1426                        **template_args)
1427            else:
1428                template_parameter_list_declaration = 'constexpr const TVariable **{parameters_var_name} = nullptr;'
1429                parameter_declarations[template_args[
1430                    'parameters_var_name']] = template_parameter_list_declaration.format(
1431                        **template_args)
1432
1433            template_function_declaration = 'constexpr const TFunction {unique_name}(BuiltInId::{human_readable_name}, BuiltInName::{name_with_suffix}, TExtension::{extension}, BuiltInParameters::{parameters_var_name}, {param_count}, {return_type}, EOp{op}, {known_to_not_have_side_effects});'
1434            function_declarations.append(template_function_declaration.format(**template_args))
1435
1436            id_counter += 1
1437
1438
1439def process_function_group(
1440        group_name, group, parameter_declarations, name_declarations,
1441        unmangled_function_if_statements, defined_function_variants, builtin_id_declarations,
1442        builtin_id_definitions, defined_parameter_names, type_array_sizes_declarations,
1443        variable_declarations, function_declarations, script_generated_hash_tests,
1444        unmangled_script_generated_hash_tests, mangled_builtins, is_in_group_definitions):
1445    global id_counter
1446    first_id = id_counter
1447
1448    shader_type = 'NONE'
1449    if 'shader_type' in group:
1450        shader_type = group['shader_type']
1451
1452    process_single_function_group(
1453        shader_type, group_name, group, parameter_declarations, name_declarations,
1454        unmangled_function_if_statements, defined_function_variants, builtin_id_declarations,
1455        builtin_id_definitions, defined_parameter_names, type_array_sizes_declarations,
1456        variable_declarations, function_declarations, script_generated_hash_tests,
1457        unmangled_script_generated_hash_tests, mangled_builtins)
1458
1459    if 'subgroups' in group:
1460        for subgroup_name, subgroup in group['subgroups'].iteritems():
1461            process_function_group(
1462                group_name + subgroup_name, subgroup, parameter_declarations, name_declarations,
1463                unmangled_function_if_statements, defined_function_variants,
1464                builtin_id_declarations, builtin_id_definitions, defined_parameter_names,
1465                type_array_sizes_declarations, variable_declarations, function_declarations,
1466                script_generated_hash_tests, unmangled_script_generated_hash_tests,
1467                mangled_builtins, is_in_group_definitions)
1468
1469    if 'queryFunction' in group:
1470        template_args = {'first_id': first_id, 'last_id': id_counter - 1, 'group_name': group_name}
1471        template_is_in_group_definition = """bool is{group_name}(const TFunction *func)
1472{{
1473    int id = func->uniqueId().get();
1474    return id >= {first_id} && id <= {last_id};
1475}}"""
1476        is_in_group_definitions.append(template_is_in_group_definition.format(**template_args))
1477
1478
1479def prune_parameters_arrays(parameter_declarations, function_declarations):
1480    # We can share parameters arrays between functions in case one array is a subarray of another.
1481    parameter_variable_name_replacements = {}
1482    used_param_variable_names = set()
1483    for param_variable_name, param_declaration in sorted(
1484            parameter_declarations.iteritems(), key=lambda item: -len(item[0])):
1485        replaced = False
1486        for used in used_param_variable_names:
1487            if used.startswith(param_variable_name):
1488                parameter_variable_name_replacements[param_variable_name] = used
1489                replaced = True
1490                break
1491        if not replaced:
1492            used_param_variable_names.add(param_variable_name)
1493
1494    for i in xrange(len(function_declarations)):
1495        for replaced, replacement in parameter_variable_name_replacements.iteritems():
1496            function_declarations[i] = function_declarations[i].replace(
1497                'BuiltInParameters::' + replaced + ',', 'BuiltInParameters::' + replacement + ',')
1498
1499    return [
1500        value for key, value in parameter_declarations.iteritems()
1501        if key in used_param_variable_names
1502    ]
1503
1504
1505def process_single_variable_group(shader_type, group_name, group, builtin_id_declarations,
1506                                  builtin_id_definitions, name_declarations, init_member_variables,
1507                                  get_variable_declarations, mangled_builtins,
1508                                  declare_member_variables, variable_declarations,
1509                                  get_variable_definitions, script_generated_hash_tests):
1510    global id_counter
1511    if 'variables' not in group:
1512        return
1513    for variable_name, props in group['variables'].iteritems():
1514        essl_level = props['essl_level'] if 'essl_level' in props else None
1515        glsl_level = props['glsl_level'] if 'glsl_level' in props else None
1516        template_args = {
1517            'id':
1518                id_counter,
1519            'name':
1520                variable_name,
1521            'name_with_suffix':
1522                variable_name + get_suffix(props),
1523            'essl_level':
1524                essl_level,
1525            'glsl_level':
1526                glsl_level,
1527            'essl_extension':
1528                get_essl_extension(props),
1529            'glsl_extension':
1530                get_glsl_extension(props),
1531            # This assumes that variables cannot be part of an ESSL and GLSL extension
1532            # Will need to update after adding GLSL extension variables if this is not the case
1533            'extension':
1534                get_essl_extension(props)
1535                if get_essl_extension(props) != 'UNDEFINED' else get_glsl_extension(props),
1536            'class':
1537                'TVariable'
1538        }
1539
1540        template_builtin_id_declaration = '    static constexpr const TSymbolUniqueId {name_with_suffix} = TSymbolUniqueId({id});'
1541        builtin_id_declarations.append(template_builtin_id_declaration.format(**template_args))
1542        template_builtin_id_definition = 'constexpr const TSymbolUniqueId BuiltInId::{name_with_suffix};'
1543        builtin_id_definitions.append(template_builtin_id_definition.format(**template_args))
1544
1545        template_name_declaration = 'constexpr const ImmutableString {name}("{name}");'
1546        name_declarations.add(template_name_declaration.format(**template_args))
1547
1548        is_member = True
1549        template_init_variable = ''
1550
1551        if 'type' in props:
1552            if props['type']['basic'] != 'Bool' and 'precision' not in props['type']:
1553                raise Exception('Missing precision for variable ' + variable_name)
1554            template_args['type'] = TType(props['type']).get_statictype_string()
1555
1556        if 'fields' in props:
1557            # Handle struct and interface block definitions.
1558            template_args['class'] = props['class']
1559            template_args['fields'] = 'fields_{name_with_suffix}'.format(**template_args)
1560            init_member_variables.append(
1561                '    TFieldList *{fields} = new TFieldList();'.format(**template_args))
1562            for field_name, field_type in props['fields'].iteritems():
1563                template_args['field_name'] = field_name
1564                template_args['field_type'] = TType(field_type).get_dynamic_type_string()
1565                template_name_declaration = 'constexpr const ImmutableString {field_name}("{field_name}");'
1566                name_declarations.add(template_name_declaration.format(**template_args))
1567                template_add_field = '    {fields}->push_back(new TField({field_type}, BuiltInName::{field_name}, zeroSourceLoc, SymbolType::BuiltIn));'
1568                init_member_variables.append(template_add_field.format(**template_args))
1569            template_init_temp_variable = '    {class} *{name_with_suffix} = new {class}(BuiltInId::{name_with_suffix}, BuiltInName::{name}, TExtension::{extension}, {fields});'
1570            init_member_variables.append(template_init_temp_variable.format(**template_args))
1571            if 'private' in props and props['private']:
1572                is_member = False
1573            else:
1574                template_init_variable = '    m_{name_with_suffix} = {name_with_suffix};'
1575
1576        elif 'initDynamicType' in props:
1577            # Handle variables whose type can't be expressed as TStaticType
1578            # (type is a struct or has variable array size for example).
1579            template_args['type_name'] = 'type_{name_with_suffix}'.format(**template_args)
1580            template_args['type'] = template_args['type_name']
1581            template_args['initDynamicType'] = props['initDynamicType'].format(**template_args)
1582            template_init_variable = """    {initDynamicType}
1583    {type_name}->realize();
1584    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});"""
1585
1586        elif 'value' in props:
1587            # Handle variables with constant value, such as gl_MaxDrawBuffers.
1588            if props['value'] != 'resources':
1589                raise Exception('Unrecognized value source in variable properties: ' +
1590                                str(props['value']))
1591            resources_key = variable_name[3:]
1592            if 'valueKey' in props:
1593                resources_key = props['valueKey']
1594            template_args['value'] = 'resources.' + resources_key
1595            template_args['object_size'] = TType(props['type']).get_object_size()
1596            template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});
1597    {{
1598        TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1599        unionArray[0].setIConst({value});
1600        static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1601    }}"""
1602            if template_args['object_size'] > 1:
1603                template_init_variable = """    m_{name_with_suffix} = new TVariable(BuiltInId::{name_with_suffix}, BuiltInName::{name}, SymbolType::BuiltIn, TExtension::{extension}, {type});
1604    {{
1605        TConstantUnion *unionArray = new TConstantUnion[{object_size}];
1606        for (size_t index = 0u; index < {object_size}; ++index)
1607        {{
1608            unionArray[index].setIConst({value}[index]);
1609        }}
1610        static_cast<TVariable *>(m_{name_with_suffix})->shareConstPointer(unionArray);
1611    }}"""
1612
1613        else:
1614            # Handle variables that can be stored as constexpr TVariable like
1615            # gl_Position, gl_FragColor etc.
1616            define_constexpr_variable(template_args, variable_declarations)
1617            is_member = False
1618
1619            template_get_variable_declaration = 'const TVariable *{name_with_suffix}();'
1620            get_variable_declarations.append(
1621                template_get_variable_declaration.format(**template_args))
1622
1623            template_get_variable_definition = """const TVariable *{name_with_suffix}()
1624{{
1625    return &k{name_with_suffix};
1626}}
1627"""
1628            get_variable_definitions.append(
1629                template_get_variable_definition.format(**template_args))
1630
1631            if essl_level != 'GLSL_BUILTINS':
1632                obj = '&BuiltInVariable::k{name_with_suffix}'.format(**template_args)
1633                # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
1634                mangled_builtins.add_entry(
1635                    essl_level, 'COMMON_BUILTINS', shader_type, template_args['name'], obj,
1636                    template_args['essl_extension'], template_args['glsl_extension'],
1637                    script_generated_hash_tests)
1638
1639        if is_member:
1640            init_member_variables.append(template_init_variable.format(**template_args))
1641
1642            template_declare_member_variable = 'TSymbol *m_{name_with_suffix} = nullptr;'
1643            declare_member_variables.append(
1644                template_declare_member_variable.format(**template_args))
1645
1646            obj = 'm_{name_with_suffix}'.format(**template_args)
1647
1648            # TODO(http://anglebug.com/3835): Add GLSL level once GLSL built-in vars are added
1649            mangled_builtins.add_entry(essl_level, 'COMMON_BUILTINS', shader_type,
1650                                       template_args['name'], obj, template_args['essl_extension'],
1651                                       template_args['glsl_extension'],
1652                                       script_generated_hash_tests)
1653
1654        id_counter += 1
1655
1656
1657def process_variable_group(shader_type, group_name, group, builtin_id_declarations,
1658                           builtin_id_definitions, name_declarations, init_member_variables,
1659                           get_variable_declarations, mangled_builtins, declare_member_variables,
1660                           variable_declarations, get_variable_definitions,
1661                           script_generated_hash_tests):
1662    global id_counter
1663
1664    if 'shader_type' in group:
1665        shader_type = group['shader_type']
1666
1667    process_single_variable_group(shader_type, group_name, group, builtin_id_declarations,
1668                                  builtin_id_definitions, name_declarations, init_member_variables,
1669                                  get_variable_declarations, mangled_builtins,
1670                                  declare_member_variables, variable_declarations,
1671                                  get_variable_definitions, script_generated_hash_tests)
1672
1673    if 'subgroups' in group:
1674        for subgroup_name, subgroup in group['subgroups'].iteritems():
1675            process_variable_group(
1676                shader_type, subgroup_name, subgroup, builtin_id_declarations,
1677                builtin_id_definitions, name_declarations, init_member_variables,
1678                get_variable_declarations, mangled_builtins, declare_member_variables,
1679                variable_declarations, get_variable_definitions, script_generated_hash_tests)
1680
1681
1682def generate_files(essl_only, args, functions_txt_filename, variables_json_filename,
1683                   immutablestring_cpp_filename, immutablestringtest_cpp_filename,
1684                   builtin_header_filename, symboltable_cpp_filename, parsecontext_header_filename,
1685                   symboltable_header_filename):
1686    # Declarations of symbol unique ids
1687    builtin_id_declarations = []
1688
1689    # Definitions of symbol unique ids needed for those ids used outside of constexpr expressions.
1690    builtin_id_definitions = []
1691
1692    # Declarations of name string variables
1693    name_declarations = set()
1694
1695    # Declarations of static array sizes if any builtin TVariable is array.
1696    type_array_sizes_declarations = set()
1697
1698    # Declarations of builtin TVariables
1699    variable_declarations = []
1700
1701    # Declarations of builtin TFunctions
1702    function_declarations = []
1703
1704    # Functions for querying the pointer to a specific TVariable.
1705    get_variable_declarations = []
1706    get_variable_definitions = []
1707
1708    # Code for defining TVariables stored as members of TSymbolTable.
1709    declare_member_variables = []
1710    init_member_variables = []
1711
1712    # Code for testing that script-generated hashes match with runtime computed hashes.
1713    script_generated_hash_tests = OrderedDict()
1714    unmangled_script_generated_hash_tests = OrderedDict()
1715
1716    # Functions for testing whether a builtin belongs in group.
1717    is_in_group_definitions = []
1718
1719    # Declarations of parameter arrays for builtin TFunctions. Map from C++ variable name to the full
1720    # declaration.
1721    parameter_declarations = {}
1722
1723    defined_function_variants = set()
1724    defined_parameter_names = set()
1725
1726    parsed_functions = get_parsed_functions(functions_txt_filename, essl_only)
1727
1728    if args.dump_intermediate_json:
1729        with open('builtin_functions_ESSL.json' if essl_only else 'builtin_functions.json',
1730                  'w') as outfile:
1731
1732            def serialize_obj(obj):
1733                if isinstance(obj, TType):
1734                    return obj.data
1735                else:
1736                    raise "Cannot serialize to JSON: " + str(obj)
1737
1738            json.dump(
1739                parsed_functions, outfile, indent=4, separators=(',', ': '), default=serialize_obj)
1740
1741    parsed_variables = None
1742    with open(variables_json_filename) as f:
1743        # TODO(http://anglebug.com/3835): skip loading GLSL-only vars when they are added if essl_only
1744        parsed_variables = json.load(f, object_pairs_hook=OrderedDict)
1745
1746    # This script uses a perfect hash function to avoid dealing with collisions
1747    mangled_names = []
1748    unmangled_names = []
1749    for group_name, group in parsed_functions.iteritems():
1750        get_function_names(group, mangled_names, unmangled_names)
1751    for group_name, group in parsed_variables.iteritems():
1752        get_variable_names(group, mangled_names)
1753
1754    # Hashing mangled names
1755    mangled_names = list(dict.fromkeys(mangled_names))
1756    num_mangled_names = len(mangled_names)
1757    mangled_names_dict = dict(zip(mangled_names, range(0, len(mangled_names))))
1758    # Generate the perfect hash function
1759    f1, f2, mangled_G = generate_hash(mangled_names_dict, Hash2)
1760    mangled_hashfn = HashFunction(f1, f2, mangled_G)
1761    mangled_S1 = f1.salt
1762    mangled_S2 = f2.salt
1763    # Array for querying mangled builtins
1764    mangled_builtins = GroupedList(mangled_hashfn, num_mangled_names)
1765
1766    # Hashing unmangled names
1767    unmangled_names = list(dict.fromkeys(unmangled_names))
1768    num_unmangled_names = len(unmangled_names)
1769    unmangled_names_dict = dict(zip(unmangled_names, range(0, len(unmangled_names))))
1770    # Generate the perfect hash function
1771    f1, f2, unmangled_G = generate_hash(unmangled_names_dict, Hash2)
1772    unmangled_hashfn = HashFunction(f1, f2, unmangled_G)
1773    unmangled_S1 = f1.salt
1774    unmangled_S2 = f2.salt
1775    # Array for querying unmangled builtins
1776    unmangled_function_if_statements = UnmangledGroupedList(unmangled_hashfn, num_unmangled_names)
1777
1778    for group_name, group in parsed_functions.iteritems():
1779        process_function_group(
1780            group_name, group, parameter_declarations, name_declarations,
1781            unmangled_function_if_statements, defined_function_variants, builtin_id_declarations,
1782            builtin_id_definitions, defined_parameter_names, type_array_sizes_declarations,
1783            variable_declarations, function_declarations, script_generated_hash_tests,
1784            unmangled_script_generated_hash_tests, mangled_builtins, is_in_group_definitions)
1785
1786    parameter_declarations = prune_parameters_arrays(parameter_declarations, function_declarations)
1787
1788    for group_name, group in parsed_variables.iteritems():
1789        process_variable_group('NONE', group_name, group, builtin_id_declarations,
1790                               builtin_id_definitions, name_declarations, init_member_variables,
1791                               get_variable_declarations, mangled_builtins,
1792                               declare_member_variables, variable_declarations,
1793                               get_variable_definitions, script_generated_hash_tests)
1794
1795    mangled_builtins.update_arrays()
1796
1797    output_strings = {
1798        'script_name':
1799            os.path.basename(__file__),
1800        'copyright_year':
1801            date.today().year,
1802        'builtin_id_declarations':
1803            '\n'.join(builtin_id_declarations),
1804        'builtin_id_definitions':
1805            '\n'.join(builtin_id_definitions),
1806        'last_builtin_id':
1807            id_counter - 1,
1808        'name_declarations':
1809            '\n'.join(sorted(list(name_declarations))),
1810        'function_data_source_name':
1811            functions_txt_filename,
1812        'function_declarations':
1813            '\n'.join(function_declarations),
1814        'parameter_declarations':
1815            '\n'.join(sorted(parameter_declarations)),
1816        'is_in_group_definitions':
1817            '\n'.join(is_in_group_definitions),
1818        'variable_data_source_name':
1819            variables_json_filename,
1820        'type_array_sizes_declarations':
1821            '\n'.join(sorted(type_array_sizes_declarations)),
1822        'variable_declarations':
1823            '\n'.join(sorted(variable_declarations)),
1824        'get_variable_declarations':
1825            '\n'.join(sorted(get_variable_declarations)),
1826        'get_variable_definitions':
1827            '\n'.join(sorted(get_variable_definitions)),
1828        'declare_member_variables':
1829            '\n'.join(declare_member_variables),
1830        'init_member_variables':
1831            '\n'.join(init_member_variables),
1832        'mangled_names_array':
1833            ',\n'.join(mangled_builtins.get_names()),
1834        'mangled_offsets_array':
1835            '\n'.join(mangled_builtins.get_offsets()),
1836        'mangled_rules':
1837            ',\n'.join(mangled_builtins.get_rules()),
1838        'unmangled_array':
1839            ', '.join(unmangled_function_if_statements.get_array()),
1840        'max_unmangled_name_length':
1841            unmangled_function_if_statements.get_max_name_length(),
1842        'max_mangled_name_length':
1843            mangled_builtins.get_max_name_length(),
1844        'num_unmangled_names':
1845            num_unmangled_names,
1846        'num_mangled_names':
1847            num_mangled_names,
1848        'script_generated_hash_tests':
1849            '\n'.join(script_generated_hash_tests.iterkeys()),
1850        'unmangled_script_generated_hash_tests':
1851            '\n'.join(unmangled_script_generated_hash_tests.iterkeys()),
1852        'mangled_S1':
1853            str(mangled_S1).replace('[', ' ').replace(']', ' '),
1854        'mangled_S2':
1855            str(mangled_S2).replace('[', ' ').replace(']', ' '),
1856        'mangled_G':
1857            str(mangled_G).replace('[', ' ').replace(']', ' '),
1858        'mangled_NG':
1859            len(mangled_G),
1860        'mangled_NS':
1861            len(mangled_S1),
1862        'unmangled_S1':
1863            str(unmangled_S1).replace('[', ' ').replace(']', ' '),
1864        'unmangled_S2':
1865            str(unmangled_S2).replace('[', ' ').replace(']', ' '),
1866        'unmangled_G':
1867            str(unmangled_G).replace('[', ' ').replace(']', ' '),
1868        'unmangled_NG':
1869            len(unmangled_G),
1870        'unmangled_NS':
1871            len(unmangled_S1),
1872        'header_label':
1873            'ESSL_' if essl_only else 'complete_',
1874        'source_label':
1875            'ESSL_' if essl_only else ''
1876    }
1877
1878    with open(immutablestring_cpp_filename, 'wt') as outfile_cpp:
1879        output_cpp = template_immutablestring_cpp.format(**output_strings)
1880        outfile_cpp.write(output_cpp)
1881
1882    with open(immutablestringtest_cpp_filename, 'wt') as outfile_cpp:
1883        output_cpp = template_immutablestringtest_cpp.format(**output_strings)
1884        outfile_cpp.write(output_cpp)
1885
1886    with open(builtin_header_filename, 'wt') as outfile_header:
1887        output_header = template_builtin_header.format(**output_strings)
1888        outfile_header.write(output_header)
1889
1890    with open(symboltable_cpp_filename, 'wt') as outfile_cpp:
1891        output_cpp = template_symboltable_cpp.format(**output_strings)
1892        outfile_cpp.write(output_cpp)
1893
1894    with open(parsecontext_header_filename, 'wt') as outfile_header:
1895        output_header = template_parsecontext_header.format(**output_strings)
1896        outfile_header.write(output_header)
1897
1898    if not essl_only:
1899        with open(symboltable_header_filename, 'wt') as outfile_h:
1900            output_h = template_symboltable_header.format(**output_strings)
1901            outfile_h.write(output_h)
1902
1903
1904def main():
1905    random.seed(0)
1906    set_working_dir()
1907
1908    parser = argparse.ArgumentParser()
1909    parser.add_argument(
1910        '--dump-intermediate-json',
1911        help='Dump parsed function data as a JSON file builtin_functions.json',
1912        action="store_true")
1913    parser.add_argument('auto_script_command', nargs='?', default='')
1914    args = parser.parse_args()
1915
1916    test_filename = '../../tests/compiler_tests/ImmutableString_test_autogen.cpp'
1917    essl_test_filename = '../../tests/compiler_tests/ImmutableString_test_ESSL_autogen.cpp'
1918    variables_json_filename = 'builtin_variables.json'
1919    functions_txt_filename = 'builtin_function_declarations.txt'
1920
1921    # auto_script parameters.
1922    if args.auto_script_command != '':
1923        inputs = [
1924            functions_txt_filename,
1925            variables_json_filename,
1926        ]
1927        outputs = [
1928            'ImmutableString_autogen.cpp',
1929            'ParseContext_complete_autogen.h',
1930            'SymbolTable_autogen.cpp',
1931            'SymbolTable_autogen.h',
1932            'tree_util/BuiltIn_complete_autogen.h',
1933            test_filename,
1934            'ImmutableString_ESSL_autogen.cpp',
1935            'ParseContext_ESSL_autogen.h',
1936            'SymbolTable_ESSL_autogen.cpp',
1937            'tree_util/BuiltIn_ESSL_autogen.h',
1938            essl_test_filename,
1939        ]
1940
1941        if args.auto_script_command == 'inputs':
1942            print ','.join(inputs)
1943        elif args.auto_script_command == 'outputs':
1944            print ','.join(outputs)
1945        else:
1946            print('Invalid script parameters')
1947            return 1
1948        return 0
1949
1950    # Generate files based on GLSL + ESSL symbols
1951    generate_files(False, args, functions_txt_filename, variables_json_filename,
1952                   'ImmutableString_autogen.cpp', test_filename,
1953                   'tree_util/BuiltIn_complete_autogen.h', 'SymbolTable_autogen.cpp',
1954                   'ParseContext_complete_autogen.h', 'SymbolTable_autogen.h')
1955
1956    # Generate files based on only ESSL symbols
1957    # Symbol table with GLSL + ESSL symbols is too large for Android
1958    generate_files(True, args, functions_txt_filename, variables_json_filename,
1959                   'ImmutableString_ESSL_autogen.cpp', essl_test_filename,
1960                   'tree_util/BuiltIn_ESSL_autogen.h', 'SymbolTable_ESSL_autogen.cpp',
1961                   'ParseContext_ESSL_autogen.h', 'SymbolTable_autogen.h')
1962
1963    return 0
1964
1965
1966if __name__ == '__main__':
1967    sys.exit(main())
1968