diff --git a/gen/cheader.tmpl b/gen/cheader.tmpl index ce00424..b11fa6e 100644 --- a/gen/cheader.tmpl +++ b/gen/cheader.tmpl @@ -198,7 +198,7 @@ struct {{CType .Base ""}}CallbackInfo; {{- range $entryIndex, $_ := .Entries}} {{- if .}} {{- MCommentEnumValue .Doc 0 $enum $entryIndex }} -_wgpu_EXTEND_ENUM({{CType $enum.Base ""}}, {{CEnumName $enum.Base .Base}}, {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}); +_wgpu_EXTEND_ENUM({{CType $enum.Base ""}}, {{CEnumValueName $enum.Base .Base}}, {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}); {{- end}} {{- end}} {{- else}} @@ -206,7 +206,7 @@ typedef enum {{CType .Base ""}} { {{- range $entryIndex, $_ := .Entries}} {{- if .}} {{- MCommentEnumValue .Doc 4 $enum $entryIndex }} - {{CEnumName $enum.Base .Base}} = {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}, + {{CEnumValueName $enum.Base .Base}} = {{EnumValue32 $enum $entryIndex | printf "0x%.8X"}}, {{- end}} {{- end}} {{CType $enum.Base ""}}_Force32 = 0x7FFFFFFF @@ -230,7 +230,7 @@ typedef WGPUFlags {{CType .Base ""}}; {{- end}} {{- range $entryIndex, $_ := .Entries}} {{- MCommentBitflagValue .Doc 0 $bitflag $entryIndex }} -static const {{CType $bitflag.Base ""}} {{CEnumName $bitflag.Base .Base}} = {{BitflagValue $bitflag $entryIndex}}; +static const {{CType $bitflag.Base ""}} {{CEnumValueName $bitflag.Base .Base}} = {{BitflagValue $bitflag $entryIndex}}; {{- end}} {{- end}} diff --git a/gen/gen.go b/gen/gen.go index 569b5ac..fc7d9f0 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -12,8 +12,8 @@ import ( ) type Generator struct { - ExtPrefix string - HeaderName string + UseExtPrefix bool + HeaderName string *Yml } @@ -194,7 +194,7 @@ func (g *Generator) Gen(dst io.Writer) error { "CamelCase": CamelCase, "ConstantCaseName": g.ConstantCaseName, "PascalCaseName": g.PascalCaseName, - "CEnumName": g.CEnumName, + "CEnumValueName": g.CEnumValueName, "CMethodName": g.CMethodName, "CType": g.CType, "CValue": g.CValue, @@ -243,43 +243,43 @@ func (g *Generator) FindBaseType(typ string) Base { case "constant": idx := slices.IndexFunc(g.Constants, func(c Constant) bool { return c.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Constants[idx].Base case "typedef": idx := slices.IndexFunc(g.Typedefs, func(t Typedef) bool { return t.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Typedefs[idx].Base case "enum": idx := slices.IndexFunc(g.Enums, func(e Enum) bool { return e.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Enums[idx].Base case "bitflag": idx := slices.IndexFunc(g.Bitflags, func(b Bitflag) bool { return b.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Bitflags[idx].Base case "struct": idx := slices.IndexFunc(g.Structs, func(s Struct) bool { return s.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Structs[idx].Base case "callback": idx := slices.IndexFunc(g.Callbacks, func(c Callback) bool { return c.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Callbacks[idx].Base case "object": idx := slices.IndexFunc(g.Objects, func(o Object) bool { return o.Name == name }) if idx == -1 { - return Base{Name: name, Namespace: g.PrefixForNamespace("")} + return Base{Name: name, Namespace: "webgpu"} } return g.Objects[idx].Base default: @@ -287,48 +287,66 @@ func (g *Generator) FindBaseType(typ string) Base { } } -func (g *Generator) ConstantCaseName(b Base) string { - if b.Extended { - return ConstantCase(b.Name) - } - - prefix := g.PrefixForNamespace(b.Namespace) - switch prefix { - case "": - return ConstantCase(b.Name) - default: - return ConstantCase(prefix + "_" + b.Name) +// Top-level items: constants, typedefs, and types (objects/enums/bitflags/structs/callbacks) +func (g *Generator) ResolveNamespaceForTopLevelItem(b Base) string { + if b.Namespace != "" { + return b.Namespace + } else if b.Extended { + // If we're extending an enum, assume it's in the core namespace if not otherwise specified + return "webgpu" + } else { + return g.Name } } -func (g *Generator) PascalCaseName(b Base) string { - if b.Extended { - return PascalCase(b.Name) +// Items nested inside other items: methods, enum values, and bitflag values +func (g *Generator) ResolveNamespaceForNestedItem(topLevelItem Base, nestedItem Base) string { + if nestedItem.Namespace != "" { + return nestedItem.Namespace + } else if topLevelItem.Namespace != "" { + return topLevelItem.Namespace + } else { + return g.Name } +} - prefix := g.PrefixForNamespace(b.Namespace) +func (g *Generator) CanonicalCaseName(prefix string, b Base) string { switch prefix { case "": - return PascalCase(b.Name) + return b.Name default: - return PascalCase(prefix + "_" + b.Name) + return prefix + "_" + b.Name } } -func (g *Generator) CEnumName(typ Base, entry Base) string { - if !typ.Extended { - return g.CType(typ, "") + "_" + PascalCase(entry.Name) +func (g *Generator) ConstantCaseName(b Base) string { + prefix := g.GetNamespacePrefix(g.ResolveNamespaceForTopLevelItem(b)) + return ConstantCase(g.CanonicalCaseName(prefix, b)) +} + +func (g *Generator) PascalCaseName(b Base) string { + prefix := g.GetNamespacePrefix(g.ResolveNamespaceForTopLevelItem(b)) + return PascalCase(g.CanonicalCaseName(prefix, b)) +} + +func (g *Generator) GetNamespacePrefixForNestedItem(topLevelItem Base, nestedItem Base) string { + outerNamespace := g.ResolveNamespaceForTopLevelItem(topLevelItem) + innerNamespace := g.ResolveNamespaceForNestedItem(topLevelItem, nestedItem) + if outerNamespace == innerNamespace { + return "" } else { - return g.CType(typ, "") + "_" + g.PascalCaseName(entry) + return g.GetNamespacePrefix(innerNamespace) } } +func (g *Generator) CEnumValueName(typ Base, entry Base) string { + entryPrefix := g.GetNamespacePrefixForNestedItem(typ, entry) + return g.CType(typ, "") + "_" + PascalCase(g.CanonicalCaseName(entryPrefix, entry)) +} + func (g *Generator) CMethodName(o Object, m Function) string { - if !o.Extended { - return g.PascalCaseName(o.Base) + PascalCase(m.Name) - } else { - return PascalCase(o.Name) + g.PascalCaseName(m.Base) - } + entryPrefix := g.GetNamespacePrefixForNestedItem(o.Base, m.Base) + return g.PascalCaseName(o.Base) + PascalCase(g.CanonicalCaseName(entryPrefix, m.Base)) } func (g *Generator) CValue(s string) (string, error) { @@ -488,34 +506,38 @@ func (g *Generator) CallbackArgs(f Callback) string { return sb.String() } -func (g *Generator) EnumValue16(e Enum, entryIndex int) (uint16, error) { +func (g *Generator) EnumValue32(e Enum, entryIndex int) (uint32, error) { entry := e.Entries[entryIndex] - if entry.Value == "" { - return uint16(entryIndex), nil - } else { - var num string - var base int - if strings.HasPrefix(entry.Value, "0x") { - base = 16 - num = strings.TrimPrefix(entry.Value, "0x") - } else { - base = 10 - num = entry.Value + + var enum_prefix uint16 + if entry.Namespace != "" { + if g.EnumPrefix != 0 { + return 0, fmt.Errorf("EnumValue32: entry %s with overridden namespace %s can only be used in core webgpu.h (with global enum_prefix 0)", entry.Name, entry.Namespace) } - value, err := strconv.ParseUint(num, base, 16) - if err != nil { - return 0, err + if entry.Value == nil { + return 0, fmt.Errorf("EnumValue32: entry %s with overridden namespace %s must have an explicit value", entry.Name, entry.Namespace) } - return uint16(value), nil + switch entry.Namespace { + case "compatibility_mode": + enum_prefix = 0x2000 + default: + return 0, fmt.Errorf("EnumValue32: unknown namespace %s", entry.Namespace) + } + } else { + enum_prefix = g.EnumPrefix } -} -func (g *Generator) EnumValue32(e Enum, entryIndex int) (uint32, error) { - value16, err := g.EnumValue16(e, entryIndex) - if err != nil { - return 0, err + var value16 uint16 + if entry.Value == nil { + value16 = uint16(entryIndex) + if int(value16) != entryIndex { + return 0, fmt.Errorf("EnumValue32: entry %s default value (entry index %d) is too large", entry.Name, entryIndex) + } + } else { + value16 = *entry.Value } - return uint32(g.EnumPrefix)<<16 | uint32(value16), nil + + return uint32(enum_prefix)<<16 | uint32(value16), nil } func bitflagEntryValue(entry BitflagEntry, entryIndex int) (uint64, error) { @@ -587,14 +609,20 @@ func (g *Generator) BitflagValue(b Bitflag, entryIndex int, isDocString bool) (s } } -func (g *Generator) PrefixForNamespace(namespace string) string { +func (g *Generator) GetNamespacePrefix(namespace string) string { switch namespace { case "": - return g.ExtPrefix + panic("Missing namespace") case "webgpu": return "" + case "compatibility_mode": + return "" default: - return namespace + if g.UseExtPrefix { + return namespace + } else { + return "" + } } } diff --git a/gen/main.go b/gen/main.go index d4e3f67..08495e2 100644 --- a/gen/main.go +++ b/gen/main.go @@ -76,14 +76,10 @@ func main() { SortAndTransform(&yml) - prefix := "" - if yml.Name != "webgpu" && extPrefix { - prefix = yml.Name - } g := &Generator{ - Yml: &yml, - HeaderName: outHeaderFileNameSplit[0], - ExtPrefix: prefix, + Yml: &yml, + HeaderName: outHeaderFileNameSplit[0], + UseExtPrefix: extPrefix, } if err := g.Gen(dst); err != nil { panic(err) diff --git a/gen/yml.go b/gen/yml.go index 74b27e8..1a895a0 100644 --- a/gen/yml.go +++ b/gen/yml.go @@ -46,7 +46,7 @@ type Enum struct { } type EnumEntry struct { Base `yaml:",inline"` - Value string `yaml:"value"` + Value *uint16 `yaml:"value"` } type Bitflag struct { diff --git a/schema.json b/schema.json index 76ddfbe..28f59f9 100644 --- a/schema.json +++ b/schema.json @@ -104,9 +104,8 @@ "description": "Callback name" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this callback is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this callback is defined" }, "doc": { "type": "string" @@ -198,9 +197,8 @@ "description": "Name of the function" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this function is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this function is defined" }, "doc": { "type": "string" @@ -265,7 +263,7 @@ "description": "The name/namespace of the specification" }, "enum_prefix": { - "type": "number", + "type": "integer", "minimum": 0, "maximum": 32767, "description": "The dedicated enum prefix for the implementation specific header to avoid collisions" @@ -284,9 +282,8 @@ "$ref": "#/definitions/Name" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this typedef is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this typedef is defined" }, "doc": { "type": "string" @@ -313,9 +310,8 @@ "description": "Name of the constant variable/define" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this constant is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this constant is defined" }, "value": { "$ref": "#/definitions/Value64", @@ -343,9 +339,8 @@ "description": "Name of the enum" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this enum is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this enum is defined" }, "doc": { "type": "string" @@ -371,16 +366,15 @@ "description": "Name of the enum entry" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this enum entry is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this enum entry is defined, applying both its name prefix and its enum block" }, "doc": { "type": "string" }, "value": { "$ref": "#/definitions/Value16", - "description": "Optional property, a 16-bit unsigned integer" + "description": "If specified, overrides the default value for the enum entry (which is its index in the list)" } }, "required": [ @@ -409,9 +403,8 @@ "description": "Name of the bitflag" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this bitflag is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this bitflag is defined" }, "doc": { "type": "string" @@ -431,9 +424,8 @@ "description": "Name of the bitflag entry" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this bitmask entry is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this bitmask entry is defined" }, "doc": { "type": "string" @@ -474,9 +466,8 @@ "description": "Name of the structure" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this struct is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this struct is defined" }, "doc": { "type": "string" @@ -540,9 +531,8 @@ "description": "Name of the object" }, "namespace": { - "type": "string", - "description": "Optional property, specifying the namespace where this object is defined", - "pattern": "^[a-z]+$" + "$ref": "#/definitions/Name", + "description": "Optional property, specifying the namespace where this object is defined" }, "doc": { "type": "string" diff --git a/tests/extensions/extension.json b/tests/extensions/extension.json index 2e3771c..eba047f 100644 --- a/tests/extensions/extension.json +++ b/tests/extensions/extension.json @@ -84,6 +84,12 @@ "name": "new_constant2", "namespace": "webgpu", "value": "uint64_max" + }, + { + "doc": "The 'compatibility_mode' namespace also has no prefix.\n(This test is not really related to extensions, it's just easiest to test here.)\n", + "name": "new_constant3", + "namespace": "compatibility_mode", + "value": "uint64_max" } ], "copyright": "Copyright 2025 WebGPU-Native developers\n\nSPDX-License-Identifier: BSD-3-Clause\n", diff --git a/tests/extensions/extension.yml b/tests/extensions/extension.yml index 18820a0..623101e 100644 --- a/tests/extensions/extension.yml +++ b/tests/extensions/extension.yml @@ -16,6 +16,12 @@ constants: value: uint64_max doc: | New constant can be declared in the 'webgpu' namespace explicitly. + - name: new_constant3 + namespace: compatibility_mode + value: uint64_max + doc: | + The 'compatibility_mode' namespace also has no prefix. + (This test is not really related to extensions, it's just easiest to test here.) typedefs: - name: new_typedef1 type: uint32 diff --git a/tests/extensions/webgpu_extension.h b/tests/extensions/webgpu_extension.h index c68ef34..f873f46 100644 --- a/tests/extensions/webgpu_extension.h +++ b/tests/extensions/webgpu_extension.h @@ -54,6 +54,11 @@ * New constant can be declared in the 'webgpu' namespace explicitly. */ #define WGPU_NEW_CONSTANT2 (UINT64_MAX) +/** + * The 'compatibility_mode' namespace also has no prefix. + * (This test is not really related to extensions, it's just easiest to test here.) + */ +#define WGPU_NEW_CONSTANT3 (UINT64_MAX) /** @} */