From 897cdeeb61f93040e5b6859a1a592d3dbef4285a Mon Sep 17 00:00:00 2001 From: Ben Clayton Date: Tue, 28 Sep 2021 10:01:02 +0000 Subject: [PATCH] dawn_node: Add template files Templates used to generate the NodeJS interop classes for the WebGPU IDL. Also includes a stub `Browser.idl` file that provides stub definitions for browser IDL declarations referenced by the WebGPU IDL. Bug: dawn:1123 Change-Id: I4067cb186f63436a502c3516a879ed1c5cd30731 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64902 Commit-Queue: Ben Clayton Reviewed-by: Austin Eng --- src/dawn_node/interop/Browser.idl | 84 ++++++ src/dawn_node/interop/WebGPU.cpp.tmpl | 341 ++++++++++++++++++++++++ src/dawn_node/interop/WebGPU.h.tmpl | 263 ++++++++++++++++++ src/dawn_node/interop/WebGPUCommon.tmpl | 126 +++++++++ 4 files changed, 814 insertions(+) create mode 100644 src/dawn_node/interop/Browser.idl create mode 100644 src/dawn_node/interop/WebGPU.cpp.tmpl create mode 100644 src/dawn_node/interop/WebGPU.h.tmpl create mode 100644 src/dawn_node/interop/WebGPUCommon.tmpl diff --git a/src/dawn_node/interop/Browser.idl b/src/dawn_node/interop/Browser.idl new file mode 100644 index 0000000000..8208058f82 --- /dev/null +++ b/src/dawn_node/interop/Browser.idl @@ -0,0 +1,84 @@ +// Copyright 2021 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. + +// An IDL file that provides stub definitions for dictionaries and interfaces +// used by the webgpu.idl file + +dictionary EventInit { + boolean bubbles = false; + boolean cancelable = false; + boolean composed = false; +}; + +interface Navigator { + readonly attribute DOMString vendorSub; + readonly attribute DOMString productSub; + readonly attribute DOMString vendor; +}; + +interface Event { + readonly attribute boolean bubbles; + readonly attribute boolean cancelable; + attribute boolean returnValue; +}; + +interface WorkerNavigator{}; + +interface EventListener { + undefined handleEvent(Event event); +}; + +interface EventTarget { + undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options); + undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options); + boolean dispatchEvent(Event event); +}; + +dictionary EventListenerOptions { boolean capture = false; }; + +dictionary AddEventListenerOptions : EventListenerOptions { + boolean passive = false; + boolean once = false; +}; + +interface HTMLVideoElement { + attribute unsigned long width; + attribute unsigned long height; + readonly attribute unsigned long videoWidth; + readonly attribute unsigned long videoHeight; + attribute DOMString poster; +}; + +typedef(Int8Array or Int16Array or Int32Array or Uint8Array or Uint16Array or + Uint32Array or Float32Array or Float64Array or + DataView) ArrayBufferView; + +typedef(ArrayBufferView or ArrayBuffer) BufferSource; + +interface ImageBitmap { + readonly attribute unsigned long width; + readonly attribute unsigned long height; +}; + +interface HTMLCanvasElement { + attribute unsigned long width; + attribute unsigned long height; +}; + +interface OffscreenCanvas { + attribute unsigned long width; + attribute unsigned long height; +}; + +interface EventHandler{}; diff --git a/src/dawn_node/interop/WebGPU.cpp.tmpl b/src/dawn_node/interop/WebGPU.cpp.tmpl new file mode 100644 index 0000000000..d52a991b05 --- /dev/null +++ b/src/dawn_node/interop/WebGPU.cpp.tmpl @@ -0,0 +1,341 @@ +{{/* + Copyright 2021 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. +*/}} + +{{- /* +-------------------------------------------------------------------------------- +Template file for use with src/dawn_node/tools/cmd/idlgen/main.go to generate +the WebGPU.cpp source file. + +See: +* https://github.com/ben-clayton/webidlparser/blob/main/ast/ast.go for the AST + types used by this template +* src/dawn_node/tools/cmd/idlgen/main.go for additional structures and functions + used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Include "WebGPUCommon.tmpl" -}} + +#include "src/dawn_node/interop/WebGPU.h" + +#include + +#include "src/dawn_node/utils/Debug.h" + +namespace wgpu { +namespace interop { + +namespace { + +{{template "Wrappers" $}} + +} // namespace + +{{ range $ := .Declarations}} +{{- if IsDictionary $}}{{template "Dictionary" $}} +{{- else if IsInterface $}}{{template "Interface" $}} +{{- else if IsEnum $}}{{template "Enum" $}} +{{- end}} +{{- end}} + + +void Initialize(Napi::Env env) { + auto* wrapper = Wrappers::Init(env); + auto global = env.Global(); +{{ range $ := .Declarations}} +{{- if IsInterfaceOrNamespace $}} + global.Set(Napi::String::New(env, "{{$.Name}}"), wrapper->{{$.Name}}_ctor.Value()); +{{- end}} +{{- end}} +} + +} // namespace interop +} // namespace wgpu + + +{{- /* +-------------------------------------------------------------------------------- +-- Wrappers emits the C++ 'Wrappers' class, which holds all the interface and +-- namespace interop wrapper classes. +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Wrappers"}} +// Wrappers holds all the Napi class constructors, and Napi::ObjectWrap type +// declarations, for each of the WebIDL interface and namespace types. +class Wrappers { + Wrappers(Napi::Env env) { +{{- range $ := .Declarations}} +{{- if IsInterfaceOrNamespace $}} + {{$.Name}}_ctor = Napi::Persistent(W{{$.Name}}::Class(env)); +{{- end}} +{{- end}} + } + + static Wrappers* instance; + +public: +{{- range $ := .Declarations}} +{{- if IsInterfaceOrNamespace $}}{{template "Wrapper" $}} +{{- end}} +{{- end}} + + // Allocates and constructs the Wrappers instance + static Wrappers* Init(Napi::Env env) { + instance = new Wrappers(env); + return instance; + } + + // Destructs and frees the Wrappers instance + static void Term(Napi::Env env) { + delete instance; + instance = nullptr; + } + + static Wrappers* For(Napi::Env env) { + // Currently Napi only actually supports a single Env, so there's no point + // maintaining a map of Env to Wrapper. Note: This might not always be true. + return instance; + } + +{{ range $ := .Declarations}} +{{- if IsInterfaceOrNamespace $}} + Napi::FunctionReference {{$.Name}}_ctor; +{{- end}} +{{- end}} +}; + +Wrappers* Wrappers::instance = nullptr; +{{- end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Wrapper emits the C++ wrapper class for the given ast.Interface or +-- ast.Namespace. +-- This wrapper class inherits from Napi::ObjectWrap, which binds the lifetime +-- of the JavaScript object to the lifetime of the wrapper class instance. +-- If the wrapper is for an interface, the wrapper object holds a unique_ptr to +-- the interface implementation, and delegates all exposed method calls on to +-- the implementation. +-- See: https://github.com/nodejs/node-addon-api/blob/main/doc/object_wrap.md +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Wrapper"}} + struct W{{$.Name}} : public Napi::ObjectWrap { +{{- if IsInterface $}} + std::unique_ptr<{{$.Name}}> impl; +{{- end}} + static Napi::Function Class(Napi::Env env) { + return DefineClass(env, "{{$.Name}}", { +{{- range $m := MethodsOf $}} + InstanceMethod("{{$m.Name}}", &W{{$.Name}}::{{$m.Name}}), +{{- end}} +{{- range $a := AttributesOf $}} + InstanceAccessor("{{$a.Name}}", &W{{$.Name}}::get{{Title $a.Name}}, +{{- if $a.Readonly}} nullptr{{else}} &W{{$.Name}}::set{{Title $a.Name}}{{end -}} + ), +{{- end}} +{{- range $c := ConstantsOf $}} + StaticValue("{{$c.Name}}", ToJS(env, {{$.Name}}::{{$c.Name}})), +{{- end}} + }); + } + + W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {} +{{- range $m := MethodsOf $}} + Napi::Value {{$m.Name}}(const Napi::CallbackInfo& info) { +{{- range $overload_idx, $o := $m.Overloads}} + { // Overload {{$overload_idx}} + std::tuple< +{{- range $i, $p := $o.Parameters}} +{{- if $i}}, {{end}} +{{- if $p.Optional}}std::optional<{{template "Type" $p.Type}}> +{{- else }}{{template "Type" $p.Type}} +{{- end}} +{{- end}}> args; + if (FromJS(info, args)) { + {{/* indent */}}INTEROP_LOG( +{{- range $i, $p := $o.Parameters}} +{{- if $i}}, ", {{$p.Name}}: "{{else}}"{{$p.Name}}: "{{end}}, std::get<{{$i}}>(args) +{{- end}}); + {{/* indent */}} +{{- if not (IsUndefinedType $o.Type) }}auto result = {{end -}} + impl->{{$o.Name}}(info.Env(){{range $i, $_ := $o.Parameters}}, std::get<{{$i}}>(args){{end}}); + {{/* indent */ -}} +{{- if IsUndefinedType $o.Type}}return info.Env().Null(); +{{- else }}return ToJS(info.Env(), result); +{{- end }} + } + } +{{- end}} + Napi::Error::New(info.Env(), "invalid arguments to {{$m.Name}}").ThrowAsJavaScriptException(); + return {}; + } +{{- end}} + +{{- range $a := AttributesOf $}} + Napi::Value get{{Title $a.Name}}(const Napi::CallbackInfo& info) { + return ToJS(info.Env(), impl->get{{Title $a.Name}}(info.Env())); + } +{{- if not $a.Readonly}} + void set{{Title $a.Name}}(const Napi::CallbackInfo& info, const Napi::Value& value) { + {{template "Type" $a.Type}} v{}; + if (FromJS(info.Env(), value, v)) { + impl->set{{Title $a.Name}}(info.Env(), std::move(v)); + } else { + Napi::Error::New(info.Env(), "invalid value to {{$a.Name}}").ThrowAsJavaScriptException(); + } + } +{{- end }} +{{- end}} + }; +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Dictionary emits the C++ method implementations and associated functions of +-- the interop type that defines the given ast.Dictionary +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Dictionary"}} +bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { + auto object = value.ToObject(); + return true{{template "DictionaryMembersFromJS" $}}; +} + +Napi::Value Converter<{{$.Name}}>::ToJS(Napi::Env env, {{$.Name}} value) { + auto object = Napi::Object::New(env); +{{- template "DictionaryMembersToJS" $}} + return object; +} + +std::ostream& operator<<(std::ostream& o, const {{$.Name}}& dict) { + o << "{{$.Name}} {"; +{{- range $i, $m := $.Members}} + o << {{if $i}}", "{{else}}" "{{end}} << "{{$m.Name}}: "; + utils::Write(o, dict.{{$m.Name}}); +{{- end }} + o << "}" << std::endl; + return o; +} +{{ end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- DictionaryMembersFromJS emits the C++ logic to convert each of the +-- dictionary ast.Member fields from JavaScript to C++. Each call to FromJS() is +-- prefixed with '&&' so that the combined expression is true iff all members +-- are converted succesfully +-------------------------------------------------------------------------------- +*/ -}} +{{- define "DictionaryMembersFromJS"}} +{{- if $.Inherits}}{{template "DictionaryMembersFromJS" (Lookup $.Inherits)}}{{end}} +{{- range $i, $m := $.Members}} && + {{/* indent */}} +{{- if $m.Init }}interop::FromJSOptional(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}) +{{- else }}interop::FromJS(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}) +{{- end }} +{{- end}} +{{- end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- DictionaryMembersToJS emits the C++ logic to convert each of the +-- dictionary ast.Member fields to JavaScript from C++. Each call to ToJS() is +-- emitted as a separate statement +-------------------------------------------------------------------------------- +*/ -}} +{{- define "DictionaryMembersToJS"}} +{{- if $.Inherits}}{{template "DictionaryMembersToJS" (Lookup $.Inherits)}}{{end}} +{{- range $m := $.Members}} + object.Set(Napi::String::New(env, "{{$m.Name}}"), interop::ToJS(env, value.{{$m.Name}})); +{{- end}} +{{- end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Interface emits the C++ method implementations that define the given +-- ast.Interface. +-- Note: Most of the actual binding logic lives in the interface wrapper class. +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Interface"}} +{{$.Name}}::{{$.Name}}() = default; + +{{$.Name}}* {{$.Name}}::Unwrap(Napi::Object object) { + auto* wrappers = Wrappers::For(object.Env()); + if (!object.InstanceOf(wrappers->{{$.Name}}_ctor.Value())) { + return nullptr; + } + return Wrappers::W{{$.Name}}::Unwrap(object)->impl.get(); +} + +Interface<{{$.Name}}> {{$.Name}}::Bind(Napi::Env env, std::unique_ptr<{{$.Name}}>&& impl) { + auto* wrappers = Wrappers::For(env); + auto object = wrappers->{{$.Name}}_ctor.New({}); + auto* wrapper = Wrappers::W{{$.Name}}::Unwrap(object); + wrapper->impl = std::move(impl); + return Interface<{{$.Name}}>(object); +} + +{{$.Name}}::~{{$.Name}}() = default; +{{ end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Enum emits the C++ associated functions of the interop type that defines the +-- given ast.Enum +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Enum"}} +bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { + std::string str = value.ToString(); +{{- range $e := $.Values}} + if (str == {{$e.Value}}) { + out = {{$.Name}}::{{EnumEntryName $e.Value}}; + return true; + } +{{- end}} + return false; +} +Napi::Value Converter<{{$.Name}}>::ToJS(Napi::Env env, {{$.Name}} value) { + switch (value) { +{{- range $e := $.Values}} + case {{$.Name}}::{{EnumEntryName $e.Value}}: + return Napi::String::New(env, {{$e.Value}}); + break; +{{- end}} + } + return env.Undefined(); +} + +std::ostream& operator<<(std::ostream& o, {{$.Name}} value) { + switch (value) { +{{- range $e := $.Values}} + case {{$.Name}}::{{EnumEntryName $e.Value}}: + return o << {{$e.Value}}; +{{- end}} + } + return o << "undefined<{{$.Name}}>"; +} + +{{end}} diff --git a/src/dawn_node/interop/WebGPU.h.tmpl b/src/dawn_node/interop/WebGPU.h.tmpl new file mode 100644 index 0000000000..7c791c6c77 --- /dev/null +++ b/src/dawn_node/interop/WebGPU.h.tmpl @@ -0,0 +1,263 @@ +{{/* + Copyright 2021 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. +*/}} + +{{- /* +-------------------------------------------------------------------------------- +Template file for use with src/dawn_node/tools/cmd/idlgen/main.go to generate +the WebGPU.h header file. + +See: +* https://github.com/ben-clayton/webidlparser/blob/main/ast/ast.go for the AST + types used by this template +* src/dawn_node/tools/cmd/idlgen/main.go for additional structures and functions + used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + +{{- Include "WebGPUCommon.tmpl" -}} + +#ifndef DAWN_NODE_GEN_INTEROP_WEBGPU_H_ +#define DAWN_NODE_GEN_INTEROP_WEBGPU_H_ + +#include "src/dawn_node/interop/Core.h" + +namespace wgpu { +namespace interop { + +// Initialize() registers the WebGPU types with the Napi environment. +void Initialize(Napi::Env env); + +{{ range $ := .Declarations}} +{{- if IsDictionary $}}{{template "Dictionary" $}} +{{- else if IsNamespace $}}{{template "Namespace" $}} +{{- else if IsInterface $}}{{template "Interface" $}} +{{- else if IsEnum $}}{{template "Enum" $}} +{{- else if IsTypedef $}}{{template "Typedef" $}} +{{- end}} +{{- end}} + +} // namespace interop +} // namespace wgpu + +#endif // DAWN_NODE_GEN_INTEROP_WEBGPU_H_ + + +{{- /* +-------------------------------------------------------------------------------- +-- Dictionary emits the C++ header declaration that defines the interop type for +-- the given ast.Dictionary +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Dictionary"}} +// dictionary {{$.Name}} +class {{$.Name}} {{- if $.Inherits }} : public {{$.Inherits}}{{end}} { +public: +{{ range $m := $.Members}} +{{- if IsConstructor $m}} {{$.Name}}(); +{{ else if IsMember $m}} {{template "DictionaryMember" $m}} +{{ end}} +{{- end -}} +}; + +template<> +class Converter<{{$.Name}}> { +public: + static bool FromJS(Napi::Env, Napi::Value, {{$.Name}}&); + static Napi::Value ToJS(Napi::Env, {{$.Name}}); +}; + +std::ostream& operator<<(std::ostream& o, const {{$.Name}}& desc); +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Namespace emits the C++ header declaration that defines the interop type for +-- the given ast.Namespace +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Namespace"}} +// namespace {{$.Name}} +class {{$.Name}} { +public: + virtual ~{{$.Name}}(); + {{$.Name}}(); +{{- range $c := ConstantsOf $}} +{{- template "Constant" $c}} +{{- end}} +}; +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Interface emits the C++ header declaration that defines the interop type for +-- the given ast.Interface +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Interface"}} +// interface {{$.Name}} +class {{$.Name}} {{- if $.Inherits }} : public {{$.Inherits}}{{end}} { +public: + static Interface<{{$.Name}}> Bind(Napi::Env, std::unique_ptr<{{$.Name}}>&&); + static {{$.Name}}* Unwrap(Napi::Object); + + template + static inline Interface<{{$.Name}}> Create(Napi::Env env, ARGS&& ... args) { + return Bind(env, std::make_unique(std::forward(args)...)); + } + + virtual ~{{$.Name}}(); + {{$.Name}}(); +{{- range $m := MethodsOf $}} +{{- template "InterfaceMethod" $m}} +{{- end}} +{{- range $a := AttributesOf $}} +{{- template "InterfaceAttribute" $a}} +{{- end}} +{{- range $c := ConstantsOf $}} +{{- template "Constant" $c}} +{{- end}} +}; +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Typedef emits the C++ header declaration that defines the interop type for +-- the given ast.Interface +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Typedef"}} +using {{$.Name}} = {{template "Type" $.Type}}; +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Enum emits the C++ header declaration that defines the interop type for +-- the given ast.Enum +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Enum"}} +enum class {{$.Name}} { +{{- range $ := $.Values}} + {{EnumEntryName $.Value}}, +{{- end}} +}; + +template<> +class Converter<{{$.Name}}> { +public: + static bool FromJS(Napi::Env, Napi::Value, {{$.Name}}&); + static Napi::Value ToJS(Napi::Env, {{$.Name}}); +}; + +std::ostream& operator<<(std::ostream& o, {{$.Name}}); +{{end}} + + +{{- /* +-------------------------------------------------------------------------------- +-- DictionaryMember emits the C++ declaration for a single dictionary ast.Member +-------------------------------------------------------------------------------- +*/ -}} +{{- define "DictionaryMember"}} +{{- if $.Attribute}}{{template "AttributeType" $}} {{$.Name}} +{{- if $.Init}} = {{Eval "Literal" "Value" $.Init "Type" $.Type}}{{end}}; +{{- else }}{{template "Type" $.Type}} {{$.Name}}({{template "Parameters" $.Parameters}}); +{{- end }} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- InterfaceMethod emits the C++ declaration for a single interface ast.Member +-- method +-------------------------------------------------------------------------------- +*/ -}} +{{- define "InterfaceMethod"}} +{{- range $o := $.Overloads}} + virtual {{template "Type" $o.Type}} {{$.Name}}(Napi::Env{{template "ParametersWithLeadingComma" $o.Parameters}}) = 0; +{{- end }} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- InterfaceAttribute emits the C++ declaration for a single interface +-- ast.Member attribute +-------------------------------------------------------------------------------- +*/ -}} +{{- define "InterfaceAttribute"}} + virtual {{template "Type" $.Type}} get{{Title $.Name}}(Napi::Env) = 0; +{{- if not $.Readonly}} + virtual void set{{Title $.Name}}(Napi::Env, {{template "Type" $.Type}} value) = 0; +{{- end }} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- Constant emits the C++ declaration for a single ast.Member constant +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Constant"}} + static constexpr {{template "Type" $.Type}} {{$.Name}} = {{Eval "Literal" "Value" $.Init "Type" $.Type}}; +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- Parameters emits the C++ comma separated list of parameter declarations for +-- the given []ast.Parameter +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Parameters"}} +{{- range $i, $param := $ }} +{{- if $i }}, {{end}} +{{- template "Parameter" $param}} +{{- end }} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- ParametersWithLeadingComma emits the C++ comma separated list of parameter +-- declarations for the given []ast.Parameter, starting with a leading comma +-- for the first parameter +-------------------------------------------------------------------------------- +*/ -}} +{{- define "ParametersWithLeadingComma"}} +{{- range $i, $param := $ }}, {{/* */}} +{{- template "Parameter" $param}} +{{- end }} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- Parameter emits the C++ parameter type and name for the given ast.Parameter +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Parameter" -}} +{{- if $.Optional -}} +std::optional<{{template "Type" $.Type}}> {{$.Name}} +{{- else}} +{{- template "Type" $.Type}} {{$.Name}} +{{- end}} +{{- end}} diff --git a/src/dawn_node/interop/WebGPUCommon.tmpl b/src/dawn_node/interop/WebGPUCommon.tmpl new file mode 100644 index 0000000000..8630773563 --- /dev/null +++ b/src/dawn_node/interop/WebGPUCommon.tmpl @@ -0,0 +1,126 @@ +{{/* + Copyright 2021 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. +*/}} + +{{- /* +-------------------------------------------------------------------------------- +Template file for use with src/dawn_node/tools/cmd/idlgen/main.go. +This file provides common template definitions and is included by WebGPU.h.tmpl +and WebGPU.cpp.tmpl. + +See: +* https://github.com/ben-clayton/webidlparser/blob/main/ast/ast.go for the AST + types used by this template +* src/dawn_node/tools/cmd/idlgen/main.go for additional structures and functions + used by this template +* https://golang.org/pkg/text/template/ for documentation on the template syntax +-------------------------------------------------------------------------------- +*/ -}} + + +{{- /* +-------------------------------------------------------------------------------- +-- Type generates the C++ type for the given ast.Type +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Type" -}} +{{- if IsUndefinedType $}}void +{{- else if IsTypeName $}} +{{- if eq $.Name "boolean" }}bool +{{- else if eq $.Name "long" }}int32_t +{{- else if eq $.Name "unsigned long" }}uint32_t +{{- else if eq $.Name "long long" }}int64_t +{{- else if eq $.Name "unsigned long long" }}uint64_t +{{- else if eq $.Name "object" }}Object +{{- else if eq $.Name "DOMString" }}std::string +{{- else if eq $.Name "USVString" }}std::string +{{- else if eq $.Name "ArrayBuffer" }}ArrayBuffer +{{- else if IsInterface (Lookup $.Name) }}Interface<{{$.Name}}> +{{- else }}{{$.Name}} +{{- end }} +{{- else if IsParametrizedType $}}{{$.Name}}<{{template "TypeList" $.Elems}}> +{{- else if IsNullableType $}}std::optional<{{template "Type" $.Type}}> +{{- else if IsUnionType $}}std::variant<{{template "VariantTypeList" $.Types}}> +{{- else if IsSequenceType $}}std::vector<{{template "Type" $.Elem}}> +{{- else if IsRecordType $}}std::unordered_map<{{template "Type" $.Key}}, {{template "Type" $.Elem}}> +{{- else }} /* Unhandled Type {{printf "%T" $}} */ +{{- end -}} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- AttributeType generates the C++ type for the given ast.Member +-------------------------------------------------------------------------------- +*/ -}} +{{- define "AttributeType" -}} +{{- if $.Required }}{{template "Type" $.Type}} +{{- else if $.Init }}{{template "Type" $.Type}} +{{- else }}std::optional<{{template "Type" $.Type}}> +{{- end}} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- Literal generates a C++ literal value using the following arguments: +-- Value - the ast.Literal +-- Type - the ast.Type of the literal +-------------------------------------------------------------------------------- +*/ -}} +{{- define "Literal" -}} +{{- if IsDefaultDictionaryLiteral $.Value}}{{template "Type" $.Type}}{} +{{- else if IsTypeName $.Type }} +{{- $ty := Lookup $.Type.Name}} +{{- if IsEnum $ty }}{{$.Type.Name}}::{{EnumEntryName $.Value.Value}} +{{- else if IsBasicLiteral $.Value }}{{$.Value.Value}} +{{- else }}/* Unhandled Type {{printf "ty: %v $.Type.Name: %T $.Value: %T" $ty $.Type.Name $.Value}} */ +{{- end }} +{{- else if IsSequenceType $.Type }}{{template "Type" $.Type}}{} {{- /* TODO: Assumes the initialiser is empty */}} +{{- else if IsBasicLiteral $.Value }}{{$.Value.Value}} +{{- else }} /* Unhandled Type {{printf "%T %T" $.Type $.Value}} */ +{{- end}} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- TypeList generates a C++ comma separated list of types from the given +-- []ast.Type +-------------------------------------------------------------------------------- +*/ -}} +{{- define "TypeList" -}} +{{- range $i, $ty := $}} +{{- if $i }}, {{end}} +{{- template "Type" $ty}} +{{- end}} +{{- end }} + + +{{- /* +-------------------------------------------------------------------------------- +-- VariantTypeList generates a C++ comma separated list of types from the given +-- []ast.Type, skipping any 'undefined' types +-------------------------------------------------------------------------------- +*/ -}} +{{- define "VariantTypeList" -}} +{{- range $i, $ty := $}} +{{- if not (IsUndefinedType $ty)}} +{{- if $i }}, {{end}} +{{- template "Type" $ty}} +{{- end}} +{{- end}} +{{- end }} +