Generators for Emscripten

api_struct_info.json:
//* This generator is used to produce part of Emscripten's struct_info.json,
//* which is a list of struct fields that it uses to generate field offset
//* information for its own code generators.
//* https://github.com/emscripten-core/emscripten/blob/master/src/struct_info.json

library_webgpu_enum_tables.js:
//* This generator is used to produce the number-to-string mappings for
//* Emscripten's library_webgpu.js.
//* https://github.com/emscripten-core/emscripten/blob/master/src/library_webgpu.js

Change-Id: I4704509737cde4685a093eb484dd977e5a106d19
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/15240
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/dawn.json b/dawn.json
index fccab43..b849ff8 100644
--- a/dawn.json
+++ b/dawn.json
@@ -27,6 +27,7 @@
     },
     "adapter type": {
         "category": "enum",
+        "javascript": false,
         "values": [
             {"value": 0, "name": "discrete GPU"},
             {"value": 1, "name": "integrated GPU"},
@@ -44,6 +45,7 @@
     },
     "backend type": {
         "category": "enum",
+        "javascript": false,
         "values": [
             {"value": 0, "name": "null"},
             {"value": 1, "name": "D3D11"},
@@ -1314,6 +1316,7 @@
     "surface descriptor from metal layer": {
         "category": "structure",
         "chained": true,
+        "javascript": false,
         "members": [
             {"name": "layer", "type": "void", "annotation": "*"}
         ]
@@ -1321,6 +1324,7 @@
     "surface descriptor from windows HWND": {
         "category": "structure",
         "chained": true,
+        "javascript": false,
         "members": [
             {"name": "hinstance", "type": "void", "annotation": "*"},
             {"name": "hwnd", "type": "void", "annotation": "*"}
@@ -1329,6 +1333,7 @@
     "surface descriptor from xlib": {
         "category": "structure",
         "chained": true,
+        "javascript": false,
         "members": [
             {"name": "display", "type": "void", "annotation": "*"},
             {"name": "window", "type": "uint32_t"}
@@ -1365,6 +1370,7 @@
     },
     "s type": {
         "category": "enum",
+        "javascript": false,
         "values": [
             {"value": 0, "name": "invalid"},
             {"value": 1, "name": "surface descriptor from metal layer"},
@@ -1439,7 +1445,7 @@
     "texture format": {
         "category": "enum",
         "values": [
-            {"value": 0, "name": "undefined", "valid": false},
+            {"value": 0, "name": "undefined", "valid": false, "jsrepr": "undefined"},
             {"value": 1, "name": "R8 unorm"},
             {"value": 2, "name": "R8 snorm"},
             {"value": 3, "name": "R8 uint"},
@@ -1535,7 +1541,7 @@
     "texture view dimension": {
         "category": "enum",
         "values": [
-            {"value": 0, "name": "undefined", "valid": false},
+            {"value": 0, "name": "undefined", "valid": false, "jsrepr": "undefined"},
             {"value": 1, "name": "1D"},
             {"value": 2, "name": "2D"},
             {"value": 3, "name": "2D array"},
diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py
index 83cdd2f..6ff4280 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -51,6 +51,14 @@
     def snake_case(self):
         return '_'.join(self.chunks)
 
+    def js_enum_case(self):
+        result = self.chunks[0].lower()
+        for chunk in self.chunks[1:]:
+            if not result[-1].isdigit():
+                result += '-'
+            result += chunk.lower()
+        return result
+
 def concat_names(*names):
     return ' '.join([name.canonical_case() for name in names])
 
@@ -60,12 +68,26 @@
         self.dict_name = name
         self.name = Name(name, native=native)
         self.category = json_data['category']
+        self.javascript = self.json_data.get('javascript', True)
 
-EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid'])
+EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'jsrepr'])
 class EnumType(Type):
     def __init__(self, name, json_data):
         Type.__init__(self, name, json_data)
-        self.values = [EnumValue(Name(m['name']), m['value'], m.get('valid', True)) for m in self.json_data['values']]
+
+        self.values = []
+        self.contiguousFromZero = True
+        lastValue = -1
+        for m in self.json_data['values']:
+            value = m['value']
+            if value != lastValue + 1:
+                self.contiguousFromZero = False
+            lastValue = value
+            self.values.append(EnumValue(
+                Name(m['name']),
+                value,
+                m.get('valid', True),
+                m.get('jsrepr', None)))
 
         # Assert that all values are unique in enums
         all_values = set()
@@ -377,6 +399,10 @@
     else:
         return name.CamelCase()
 
+def as_jsEnumValue(value):
+    if value.jsrepr: return value.jsrepr
+    return "'" + value.name.js_enum_case() + "'"
+
 def convert_cType_to_cppType(typ, annotation, arg, indent=0):
     if typ.category == 'native':
         return arg
@@ -522,6 +548,7 @@
             'as_cType': as_cType,
             'as_cTypeDawn': as_cTypeDawn,
             'as_cppType': as_cppType,
+            'as_jsEnumValue': as_jsEnumValue,
             'convert_cType_to_cppType': convert_cType_to_cppType,
             'as_varName': as_varName,
             'decorate': decorate,
@@ -544,6 +571,10 @@
         if 'dawncpp' in targets:
             renders.append(FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp', [base_params, api_params]))
 
+        if 'emscripten_bits' in targets:
+            renders.append(FileRender('webgpu_struct_info.json', 'src/dawn/webgpu_struct_info.json', [base_params, api_params]))
+            renders.append(FileRender('library_webgpu_enum_tables.js', 'src/dawn/library_webgpu_enum_tables.js', [base_params, api_params]))
+
         if 'mock_webgpu' in targets:
             mock_params = [
                 base_params,
diff --git a/generator/templates/library_webgpu_enum_tables.js b/generator/templates/library_webgpu_enum_tables.js
new file mode 100644
index 0000000..44048ad
--- /dev/null
+++ b/generator/templates/library_webgpu_enum_tables.js
@@ -0,0 +1,35 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+//*
+//*
+//* This generator is used to produce the number-to-string mappings for
+//* Emscripten's library_webgpu.js.
+//* https://github.com/emscripten-core/emscripten/blob/master/src/library_webgpu.js
+//*
+    {% for type in by_category["enum"] if type.javascript %}
+        {{type.name.CamelCase()}}: {% if type.contiguousFromZero -%}
+            [
+                {% for value in type.values %}
+                  {{as_jsEnumValue(value)}},
+                {% endfor %}
+            ]
+        {%- else -%}
+            {
+                {% for value in type.values %}
+                  {{value.value}}: {{as_jsEnumValue(value)}},
+                {% endfor %}
+            }
+        {%- endif -%}
+        ,
+    {% endfor %}
diff --git a/generator/templates/webgpu_struct_info.json b/generator/templates/webgpu_struct_info.json
new file mode 100644
index 0000000..5120ba8
--- /dev/null
+++ b/generator/templates/webgpu_struct_info.json
@@ -0,0 +1,51 @@
+//* Copyright 2020 The Dawn Authors
+//*
+//* Licensed under the Apache License, Version 2.0 (the "License");
+//* you may not use this file except in compliance with the License.
+//* You may obtain a copy of the License at
+//*
+//*     http://www.apache.org/licenses/LICENSE-2.0
+//*
+//* Unless required by applicable law or agreed to in writing, software
+//* distributed under the License is distributed on an "AS IS" BASIS,
+//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//* See the License for the specific language governing permissions and
+//* limitations under the License.
+//*
+//*
+//* This generator is used to produce part of Emscripten's struct_info.json,
+//* which is a list of struct fields that it uses to generate field offset
+//* information for its own code generators.
+//* https://github.com/emscripten-core/emscripten/blob/master/src/struct_info.json
+//*
+    {
+        "file": "webgpu/webgpu.h",
+        "defines": [],
+        "structs": {
+            "WGPUChainedStruct": [
+                "nextInChain",
+                "sType"
+            ],
+            {% for type in by_category["structure"] if type.javascript %}
+                "{{as_cType(type.name)}}": [
+                    {% if type.chained %}
+                        "nextInChain",
+                        "sType"
+                    {%- elif type.extensible %}
+                        "nextInChain"
+                    {%- endif %}
+                    {% for member in type.members -%}
+                        {%- if (type.chained or type.extensible) or not loop.first -%}
+                            ,
+                        {% endif %}
+                        "{{as_varName(member.name)}}"
+                    {%- endfor %}
+
+                ]
+                {%- if not loop.last -%}
+                    ,
+                {% endif %}
+            {% endfor %}
+
+        }
+    }
diff --git a/src/dawn/BUILD.gn b/src/dawn/BUILD.gn
index dd6e890..fdfa5e9 100644
--- a/src/dawn/BUILD.gn
+++ b/src/dawn/BUILD.gn
@@ -37,6 +37,14 @@
   ]
 }
 
+dawn_json_generator("emscripten_bits_gen") {
+  target = "emscripten_bits"
+  outputs = [
+    "src/dawn/webgpu_struct_info.json",
+    "src/dawn/library_webgpu_enum_tables.js",
+  ]
+}
+
 source_set("dawn_headers") {
   all_dependent_configs = [ "${dawn_root}/src/common:dawn_public_include_dirs" ]
   public_deps = [