| // Copyright 2021 The Tint 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. |
| |
| package sem |
| |
| import ( |
| "fmt" |
| "sort" |
| |
| "dawn.googlesource.com/dawn/tools/src/cmd/intrinsic-gen/ast" |
| ) |
| |
| // Sem is the root of the semantic tree |
| type Sem struct { |
| Enums []*Enum |
| Types []*Type |
| TypeMatchers []*TypeMatcher |
| EnumMatchers []*EnumMatcher |
| Builtins []*Intrinsic |
| UnaryOperators []*Intrinsic |
| BinaryOperators []*Intrinsic |
| ConstructorsAndConverters []*Intrinsic |
| // Maximum number of template types used across all builtins |
| MaxTemplateTypes int |
| // Maximum number of template numbers used across all builtins |
| MaxTemplateNumbers int |
| // The alphabetically sorted list of unique parameter names |
| UniqueParameterNames []string |
| } |
| |
| // New returns a new Sem |
| func New() *Sem { |
| return &Sem{ |
| Enums: []*Enum{}, |
| Types: []*Type{}, |
| TypeMatchers: []*TypeMatcher{}, |
| EnumMatchers: []*EnumMatcher{}, |
| Builtins: []*Intrinsic{}, |
| UnaryOperators: []*Intrinsic{}, |
| BinaryOperators: []*Intrinsic{}, |
| } |
| } |
| |
| // Enum describes an enumerator |
| type Enum struct { |
| Decl ast.EnumDecl |
| Name string |
| Entries []*EnumEntry |
| } |
| |
| // FindEntry returns the enum entry with the given name |
| func (e *Enum) FindEntry(name string) *EnumEntry { |
| for _, entry := range e.Entries { |
| if entry.Name == name { |
| return entry |
| } |
| } |
| return nil |
| } |
| |
| // EnumEntry is an entry in an enumerator |
| type EnumEntry struct { |
| Enum *Enum |
| Name string |
| IsInternal bool // True if this entry is not part of the WGSL grammar |
| } |
| |
| // Format implements the fmt.Formatter interface |
| func (e EnumEntry) Format(w fmt.State, verb rune) { |
| if e.IsInternal { |
| fmt.Fprint(w, "[[internal]] ") |
| } |
| fmt.Fprint(w, e.Name) |
| } |
| |
| // Type declares a type |
| type Type struct { |
| TemplateParams []TemplateParam |
| Decl ast.TypeDecl |
| Name string |
| DisplayName string |
| Precedence int |
| } |
| |
| // TypeMatcher declares a type matcher |
| type TypeMatcher struct { |
| TemplateParams []TemplateParam |
| Decl ast.MatcherDecl |
| Name string |
| Types []*Type |
| } |
| |
| func (t TypeMatcher) PrecedenceSortedTypes() []*Type { |
| out := make([]*Type, len(t.Types)) |
| copy(out, t.Types) |
| sort.Slice(out, func(i, j int) bool { return out[i].Precedence > out[j].Precedence }) |
| return out |
| } |
| |
| // EnumMatcher declares a enum matcher |
| type EnumMatcher struct { |
| TemplateParams []TemplateParam |
| Decl ast.MatcherDecl |
| Name string |
| Enum *Enum |
| Options []*EnumEntry |
| } |
| |
| // TemplateEnumParam is a template enum parameter |
| type TemplateEnumParam struct { |
| Name string |
| Enum *Enum |
| Matcher *EnumMatcher // Optional |
| } |
| |
| // TemplateTypeParam is a template type parameter |
| type TemplateTypeParam struct { |
| Name string |
| Type ResolvableType |
| } |
| |
| // TemplateNumberParam is a template type parameter |
| type TemplateNumberParam struct { |
| Name string |
| } |
| |
| // Intrinsic describes the overloads of a builtin or operator |
| type Intrinsic struct { |
| Name string |
| Overloads []*Overload |
| } |
| |
| // Overload describes a single overload of a builtin or operator |
| type Overload struct { |
| Decl ast.IntrinsicDecl |
| Intrinsic *Intrinsic |
| TemplateParams []TemplateParam |
| TemplateTypes []*TemplateTypeParam |
| TemplateNumbers []TemplateParam |
| ReturnType *FullyQualifiedName |
| Parameters []Parameter |
| CanBeUsedInStage StageUses |
| IsDeprecated bool // True if this overload is deprecated |
| ConstEvalFunction string // Name of the function used to evaluate the intrinsic at shader creation time |
| } |
| |
| // StageUses describes the stages an overload can be used in |
| type StageUses struct { |
| Vertex bool |
| Fragment bool |
| Compute bool |
| } |
| |
| // List returns the stage uses as a string list |
| func (u StageUses) List() []string { |
| out := []string{} |
| if u.Vertex { |
| out = append(out, "vertex") |
| } |
| if u.Fragment { |
| out = append(out, "fragment") |
| } |
| if u.Compute { |
| out = append(out, "compute") |
| } |
| return out |
| } |
| |
| // Format implements the fmt.Formatter interface |
| func (o Overload) Format(w fmt.State, verb rune) { |
| switch o.Decl.Kind { |
| case ast.Builtin: |
| fmt.Fprintf(w, "fn ") |
| case ast.Operator: |
| fmt.Fprintf(w, "op ") |
| } |
| fmt.Fprintf(w, "%v", o.Intrinsic.Name) |
| if len(o.TemplateParams) > 0 { |
| fmt.Fprintf(w, "<") |
| for i, t := range o.TemplateParams { |
| if i > 0 { |
| fmt.Fprint(w, ", ") |
| } |
| fmt.Fprintf(w, "%v", t) |
| } |
| fmt.Fprintf(w, ">") |
| } |
| fmt.Fprint(w, "(") |
| for i, p := range o.Parameters { |
| if i > 0 { |
| fmt.Fprint(w, ", ") |
| } |
| fmt.Fprintf(w, "%v", p) |
| } |
| fmt.Fprint(w, ")") |
| if o.ReturnType != nil { |
| fmt.Fprintf(w, " -> %v", o.ReturnType) |
| } |
| } |
| |
| // Parameter describes a single parameter of a function overload |
| type Parameter struct { |
| Name string |
| Type FullyQualifiedName |
| IsConst bool // Did this parameter have a @const attribute? |
| } |
| |
| // Format implements the fmt.Formatter interface |
| func (p Parameter) Format(w fmt.State, verb rune) { |
| if p.IsConst { |
| fmt.Fprint(w, "@const ") |
| } |
| if p.Name != "" { |
| fmt.Fprintf(w, "%v: ", p.Name) |
| } |
| fmt.Fprintf(w, "%v", p.Type) |
| } |
| |
| // FullyQualifiedName is the usage of a Type, TypeMatcher or TemplateTypeParam |
| type FullyQualifiedName struct { |
| Target Named |
| TemplateArguments []interface{} |
| } |
| |
| // Format implements the fmt.Formatter interface |
| func (f FullyQualifiedName) Format(w fmt.State, verb rune) { |
| fmt.Fprint(w, f.Target.GetName()) |
| if len(f.TemplateArguments) > 0 { |
| fmt.Fprintf(w, "<") |
| for i, t := range f.TemplateArguments { |
| if i > 0 { |
| fmt.Fprint(w, ", ") |
| } |
| fmt.Fprintf(w, "%v", t) |
| } |
| fmt.Fprintf(w, ">") |
| } |
| } |
| |
| // TemplateParam is a TemplateEnumParam, TemplateTypeParam or TemplateNumberParam |
| type TemplateParam interface { |
| Named |
| isTemplateParam() |
| } |
| |
| func (*TemplateEnumParam) isTemplateParam() {} |
| func (*TemplateTypeParam) isTemplateParam() {} |
| func (*TemplateNumberParam) isTemplateParam() {} |
| |
| // ResolvableType is a Type, TypeMatcher or TemplateTypeParam |
| type ResolvableType interface { |
| Named |
| isResolvableType() |
| } |
| |
| func (*Type) isResolvableType() {} |
| func (*TypeMatcher) isResolvableType() {} |
| func (*TemplateTypeParam) isResolvableType() {} |
| |
| // Named is something that can be looked up by name |
| type Named interface { |
| isNamed() |
| GetName() string |
| } |
| |
| func (*Enum) isNamed() {} |
| func (*EnumEntry) isNamed() {} |
| func (*Type) isNamed() {} |
| func (*TypeMatcher) isNamed() {} |
| func (*EnumMatcher) isNamed() {} |
| func (*TemplateTypeParam) isNamed() {} |
| func (*TemplateEnumParam) isNamed() {} |
| func (*TemplateNumberParam) isNamed() {} |
| |
| // GetName returns the name of the Enum |
| func (e *Enum) GetName() string { return e.Name } |
| |
| // GetName returns the name of the EnumEntry |
| func (e *EnumEntry) GetName() string { return e.Name } |
| |
| // GetName returns the name of the Type |
| func (t *Type) GetName() string { return t.Name } |
| |
| // GetName returns the name of the TypeMatcher |
| func (t *TypeMatcher) GetName() string { return t.Name } |
| |
| // GetName returns the name of the EnumMatcher |
| func (e *EnumMatcher) GetName() string { return e.Name } |
| |
| // GetName returns the name of the TemplateTypeParam |
| func (t *TemplateTypeParam) GetName() string { return t.Name } |
| |
| // GetName returns the name of the TemplateEnumParam |
| func (t *TemplateEnumParam) GetName() string { return t.Name } |
| |
| // GetName returns the name of the TemplateNumberParam |
| func (t *TemplateNumberParam) GetName() string { return t.Name } |