tint/intrinsics.def: Change language for enums
Previously enum members were added to the global namespace, so that overload template parameters could be constrained to a single enum-entry without the need to declare a matcher. While this was a minor convenience feature, it means that you cannot declare an enum with members that share the same name as a type. This will be very common for extensions, like 'f16' where 'f16' is the name of an extension and a type name. Change scoping so that enum members need to be fully qualified. Also change the intrinsic syntax so that enums always need to use a matcher for enums. Change-Id: Ided91130e9df537d38dc8ecb41325c0992dea14b Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/97146 Reviewed-by: Dan Sinclair <dsinclair@chromium.org> Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
parent
1260a53018
commit
c768e640f4
|
@ -153,17 +153,38 @@ match iu32: i32 | u32
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// https://gpuweb.github.io/gpuweb/wgsl/#texel-formats
|
// https://gpuweb.github.io/gpuweb/wgsl/#texel-formats
|
||||||
match f32_texel_format:
|
match f32_texel_format
|
||||||
rgba8unorm | rgba8snorm | rgba16float | r32float | rg32float | rgba32float
|
: texel_format.rgba8unorm
|
||||||
match i32_texel_format:
|
| texel_format.rgba8snorm
|
||||||
rgba8sint | rgba16sint | r32sint | rg32sint | rgba32sint
|
| texel_format.rgba16float
|
||||||
match u32_texel_format:
|
| texel_format.r32float
|
||||||
rgba8uint | rgba16uint | r32uint | rg32uint | rgba32uint
|
| texel_format.rg32float
|
||||||
|
| texel_format.rgba32float
|
||||||
|
match i32_texel_format
|
||||||
|
: texel_format.rgba8sint
|
||||||
|
| texel_format.rgba16sint
|
||||||
|
| texel_format.r32sint
|
||||||
|
| texel_format.rg32sint
|
||||||
|
| texel_format.rgba32sint
|
||||||
|
match u32_texel_format
|
||||||
|
: texel_format.rgba8uint
|
||||||
|
| texel_format.rgba16uint
|
||||||
|
| texel_format.r32uint
|
||||||
|
| texel_format.rg32uint
|
||||||
|
| texel_format.rgba32uint
|
||||||
|
|
||||||
match write_only: write
|
match write: access.write
|
||||||
|
match read_write: access.read_write
|
||||||
|
|
||||||
match function_private_workgroup: function | private | workgroup
|
match function_private_workgroup
|
||||||
match workgroup_or_storage: workgroup | storage
|
: storage_class.function
|
||||||
|
| storage_class.private
|
||||||
|
| storage_class.workgroup
|
||||||
|
match workgroup_or_storage
|
||||||
|
: storage_class.workgroup
|
||||||
|
| storage_class.storage
|
||||||
|
match storage
|
||||||
|
: storage_class.storage
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Builtin Functions //
|
// Builtin Functions //
|
||||||
|
@ -502,10 +523,10 @@ fn textureDimensions(texture: texture_depth_cube, level: i32) -> vec2<i32>
|
||||||
fn textureDimensions(texture: texture_depth_cube_array) -> vec2<i32>
|
fn textureDimensions(texture: texture_depth_cube_array) -> vec2<i32>
|
||||||
fn textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32>
|
fn textureDimensions(texture: texture_depth_cube_array, level: i32) -> vec2<i32>
|
||||||
fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32>
|
fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<i32>
|
||||||
fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_1d<F, A>) -> i32
|
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_1d<F, A>) -> i32
|
||||||
fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_2d<F, A>) -> vec2<i32>
|
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d<F, A>) -> vec2<i32>
|
||||||
fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_2d_array<F, A>) -> vec2<i32>
|
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> vec2<i32>
|
||||||
fn textureDimensions<F: texel_format, A: write_only>(texture: texture_storage_3d<F, A>) -> vec3<i32>
|
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_3d<F, A>) -> vec3<i32>
|
||||||
fn textureDimensions(texture: texture_external) -> vec2<i32>
|
fn textureDimensions(texture: texture_external) -> vec2<i32>
|
||||||
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
|
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
|
||||||
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
|
fn textureGather<T: fiu32>(@const component: i32, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
|
||||||
|
@ -529,7 +550,7 @@ fn textureNumLayers<T: fiu32>(texture: texture_2d_array<T>) -> i32
|
||||||
fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> i32
|
fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> i32
|
||||||
fn textureNumLayers(texture: texture_depth_2d_array) -> i32
|
fn textureNumLayers(texture: texture_depth_2d_array) -> i32
|
||||||
fn textureNumLayers(texture: texture_depth_cube_array) -> i32
|
fn textureNumLayers(texture: texture_depth_cube_array) -> i32
|
||||||
fn textureNumLayers<F: texel_format, A: write_only>(texture: texture_storage_2d_array<F, A>) -> i32
|
fn textureNumLayers<F: texel_format, A: write>(texture: texture_storage_2d_array<F, A>) -> i32
|
||||||
fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> i32
|
fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> i32
|
||||||
fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> i32
|
fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> i32
|
||||||
fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> i32
|
fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> i32
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -195,12 +195,21 @@ func (p Parameter) Format(w fmt.State, verb rune) {
|
||||||
p.Type.Format(w, verb)
|
p.Type.Format(w, verb)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MatcherOptions is a list of TemplatedName
|
// MatcherOptions is a list of TemplatedNames or MemberNames
|
||||||
type MatcherOptions TemplatedNames
|
type MatcherOptions struct {
|
||||||
|
Types TemplatedNames
|
||||||
|
Enums MemberNames
|
||||||
|
}
|
||||||
|
|
||||||
// Format implements the fmt.Formatter interface
|
// Format implements the fmt.Formatter interface
|
||||||
func (o MatcherOptions) Format(w fmt.State, verb rune) {
|
func (o MatcherOptions) Format(w fmt.State, verb rune) {
|
||||||
for i, mo := range o {
|
for i, mo := range o.Types {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Fprintf(w, " | ")
|
||||||
|
}
|
||||||
|
mo.Format(w, verb)
|
||||||
|
}
|
||||||
|
for i, mo := range o.Enums {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
fmt.Fprintf(w, " | ")
|
fmt.Fprintf(w, " | ")
|
||||||
}
|
}
|
||||||
|
@ -242,6 +251,33 @@ func (t TemplatedName) Format(w fmt.State, verb rune) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MemberNames is a list of MemberName
|
||||||
|
// Example:
|
||||||
|
// a.b, c.d
|
||||||
|
type MemberNames []MemberName
|
||||||
|
|
||||||
|
// Format implements the fmt.Formatter interface
|
||||||
|
func (l MemberNames) Format(w fmt.State, verb rune) {
|
||||||
|
for i, n := range l {
|
||||||
|
if i > 0 {
|
||||||
|
fmt.Fprintf(w, ", ")
|
||||||
|
}
|
||||||
|
n.Format(w, verb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemberName is two identifiers separated by a dot (Owner.Member)
|
||||||
|
type MemberName struct {
|
||||||
|
Source tok.Source
|
||||||
|
Owner string
|
||||||
|
Member string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format implements the fmt.Formatter interface
|
||||||
|
func (t MemberName) Format(w fmt.State, verb rune) {
|
||||||
|
fmt.Fprintf(w, "%v.%v", t.Owner, t.Member)
|
||||||
|
}
|
||||||
|
|
||||||
// TypeDecl describes a type declaration
|
// TypeDecl describes a type declaration
|
||||||
type TypeDecl struct {
|
type TypeDecl struct {
|
||||||
Source tok.Source
|
Source tok.Source
|
||||||
|
|
|
@ -91,6 +91,7 @@ func (l *lexer) lex() error {
|
||||||
l.skip(l.count(toFirst('\n')))
|
l.skip(l.count(toFirst('\n')))
|
||||||
l.next() // Consume newline
|
l.next() // Consume newline
|
||||||
case l.match("/", tok.Divide):
|
case l.match("/", tok.Divide):
|
||||||
|
case l.match(".", tok.Dot):
|
||||||
case l.match("->", tok.Arrow):
|
case l.match("->", tok.Arrow):
|
||||||
case l.match("-", tok.Minus):
|
case l.match("-", tok.Minus):
|
||||||
case l.match("fn", tok.Function):
|
case l.match("fn", tok.Function):
|
||||||
|
|
|
@ -109,10 +109,19 @@ func (p *parser) matcherDecl() ast.MatcherDecl {
|
||||||
name := p.expect(tok.Identifier, "matcher name")
|
name := p.expect(tok.Identifier, "matcher name")
|
||||||
m := ast.MatcherDecl{Source: name.Source, Name: string(name.Runes)}
|
m := ast.MatcherDecl{Source: name.Source, Name: string(name.Runes)}
|
||||||
p.expect(tok.Colon, "matcher declaration")
|
p.expect(tok.Colon, "matcher declaration")
|
||||||
for p.err == nil {
|
if p.peekIs(1, tok.Dot) { // enum list
|
||||||
m.Options = append(m.Options, p.templatedName())
|
for p.err == nil {
|
||||||
if p.match(tok.Or) == nil {
|
m.Options.Enums = append(m.Options.Enums, p.memberName())
|
||||||
break
|
if p.match(tok.Or) == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // type list
|
||||||
|
for p.err == nil {
|
||||||
|
m.Options.Types = append(m.Options.Types, p.templatedName())
|
||||||
|
if p.match(tok.Or) == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
@ -277,6 +286,17 @@ func (p *parser) string() string {
|
||||||
return string(s.Runes)
|
return string(s.Runes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *parser) memberName() ast.MemberName {
|
||||||
|
owner := p.expect(tok.Identifier, "member name")
|
||||||
|
p.expect(tok.Dot, "member name")
|
||||||
|
member := p.expect(tok.Identifier, "member name")
|
||||||
|
return ast.MemberName{
|
||||||
|
Source: member.Source,
|
||||||
|
Owner: string(owner.Runes),
|
||||||
|
Member: string(member.Runes),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *parser) templatedName() ast.TemplatedName {
|
func (p *parser) templatedName() ast.TemplatedName {
|
||||||
name := p.expect(tok.Identifier, "type name")
|
name := p.expect(tok.Identifier, "type name")
|
||||||
m := ast.TemplatedName{Source: name.Source, Name: string(name.Runes)}
|
m := ast.TemplatedName{Source: name.Source, Name: string(name.Runes)}
|
||||||
|
|
|
@ -129,7 +129,9 @@ func TestParser(t *testing.T) {
|
||||||
Matchers: []ast.MatcherDecl{{
|
Matchers: []ast.MatcherDecl{{
|
||||||
Name: "M",
|
Name: "M",
|
||||||
Options: ast.MatcherOptions{
|
Options: ast.MatcherOptions{
|
||||||
ast.TemplatedName{Name: "A"},
|
Types: ast.TemplatedNames{
|
||||||
|
{Name: "A"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
@ -140,8 +142,37 @@ func TestParser(t *testing.T) {
|
||||||
Matchers: []ast.MatcherDecl{{
|
Matchers: []ast.MatcherDecl{{
|
||||||
Name: "M",
|
Name: "M",
|
||||||
Options: ast.MatcherOptions{
|
Options: ast.MatcherOptions{
|
||||||
ast.TemplatedName{Name: "A"},
|
Types: ast.TemplatedNames{
|
||||||
ast.TemplatedName{Name: "B"},
|
{Name: "A"},
|
||||||
|
{Name: "B"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"match M : A.B",
|
||||||
|
ast.AST{
|
||||||
|
Matchers: []ast.MatcherDecl{{
|
||||||
|
Name: "M",
|
||||||
|
Options: ast.MatcherOptions{
|
||||||
|
Enums: ast.MemberNames{
|
||||||
|
{Owner: "A", Member: "B"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
}, { ///////////////////////////////////////////////////////////////////
|
||||||
|
utils.ThisLine(),
|
||||||
|
"match M : A.B | B.C",
|
||||||
|
ast.AST{
|
||||||
|
Matchers: []ast.MatcherDecl{{
|
||||||
|
Name: "M",
|
||||||
|
Options: ast.MatcherOptions{
|
||||||
|
Enums: ast.MemberNames{
|
||||||
|
{Owner: "A", Member: "B"},
|
||||||
|
{Owner: "B", Member: "C"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"dawn.googlesource.com/dawn/tools/src/container"
|
||||||
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/ast"
|
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/ast"
|
||||||
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/sem"
|
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/sem"
|
||||||
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/tok"
|
"dawn.googlesource.com/dawn/tools/src/tint/intrinsic/tok"
|
||||||
|
@ -125,6 +126,7 @@ func (r *resolver) enum(e ast.EnumDecl) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register each of the enum entries
|
// Register each of the enum entries
|
||||||
|
names := container.NewSet[string]()
|
||||||
for _, ast := range e.Entries {
|
for _, ast := range e.Entries {
|
||||||
entry := &sem.EnumEntry{
|
entry := &sem.EnumEntry{
|
||||||
Name: ast.Name,
|
Name: ast.Name,
|
||||||
|
@ -139,10 +141,11 @@ func (r *resolver) enum(e ast.EnumDecl) error {
|
||||||
if len(ast.Attributes) != 0 {
|
if len(ast.Attributes) != 0 {
|
||||||
return fmt.Errorf("%v unknown attribute", ast.Attributes[0].Source)
|
return fmt.Errorf("%v unknown attribute", ast.Attributes[0].Source)
|
||||||
}
|
}
|
||||||
if err := r.globals.declare(entry, e.Source); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.Entries = append(s.Entries, entry)
|
s.Entries = append(s.Entries, entry)
|
||||||
|
if names.Contains(ast.Name) {
|
||||||
|
return fmt.Errorf("%v duplicate enum entry '%v'", ast.Source, ast.Name)
|
||||||
|
}
|
||||||
|
names.Add(ast.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -203,16 +206,13 @@ func (r *resolver) ty(a ast.TypeDecl) error {
|
||||||
// The resulting matcher is appended to either Sem.TypeMatchers or
|
// The resulting matcher is appended to either Sem.TypeMatchers or
|
||||||
// Sem.EnumMatchers, and is registered with the global scope.
|
// Sem.EnumMatchers, and is registered with the global scope.
|
||||||
func (r *resolver) matcher(a ast.MatcherDecl) error {
|
func (r *resolver) matcher(a ast.MatcherDecl) error {
|
||||||
// Determine whether this is a type matcher or enum matcher by resolving the
|
isTypeMatcher := len(a.Options.Types) != 0
|
||||||
// first option
|
isEnumMatcher := len(a.Options.Enums) != 0
|
||||||
firstOption, err := r.lookupNamed(&r.globals, a.Options[0])
|
if isTypeMatcher && isEnumMatcher {
|
||||||
if err != nil {
|
return fmt.Errorf("%v matchers cannot mix enums and types", a.Source)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve to a sem.TypeMatcher or a sem.EnumMatcher
|
if isTypeMatcher {
|
||||||
switch firstOption := firstOption.(type) {
|
|
||||||
case *sem.Type:
|
|
||||||
options := map[sem.Named]tok.Source{}
|
options := map[sem.Named]tok.Source{}
|
||||||
m := &sem.TypeMatcher{
|
m := &sem.TypeMatcher{
|
||||||
Decl: a,
|
Decl: a,
|
||||||
|
@ -226,7 +226,7 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve each of the types in the options list
|
// Resolve each of the types in the options list
|
||||||
for _, ast := range m.Decl.Options {
|
for _, ast := range m.Decl.Options.Types {
|
||||||
ty, err := r.lookupType(&r.globals, ast)
|
ty, err := r.lookupType(&r.globals, ast)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -239,9 +239,25 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
}
|
||||||
|
if isEnumMatcher {
|
||||||
|
owners := container.NewSet[string]()
|
||||||
|
for _, enum := range a.Options.Enums {
|
||||||
|
owners.Add(enum.Owner)
|
||||||
|
}
|
||||||
|
if len(owners) > 1 {
|
||||||
|
return fmt.Errorf("%v cannot mix enums (%v) in type matcher", a.Source, owners)
|
||||||
|
}
|
||||||
|
enumName := owners.One()
|
||||||
|
lookup := r.globals.lookup(enumName)
|
||||||
|
if lookup == nil {
|
||||||
|
return fmt.Errorf("%v cannot resolve enum '%v'", a.Source, enumName)
|
||||||
|
}
|
||||||
|
enum, _ := lookup.object.(*sem.Enum)
|
||||||
|
if enum == nil {
|
||||||
|
return fmt.Errorf("%v cannot resolve enum '%v'", a.Source, enumName)
|
||||||
|
}
|
||||||
|
|
||||||
case *sem.EnumEntry:
|
|
||||||
enum := firstOption.Enum
|
|
||||||
m := &sem.EnumMatcher{
|
m := &sem.EnumMatcher{
|
||||||
Decl: a,
|
Decl: a,
|
||||||
Name: a.Name,
|
Name: a.Name,
|
||||||
|
@ -255,17 +271,18 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve each of the enums in the options list
|
// Resolve each of the enums in the options list
|
||||||
for _, ast := range m.Decl.Options {
|
for _, ast := range m.Decl.Options.Enums {
|
||||||
entry := enum.FindEntry(ast.Name)
|
entry := enum.FindEntry(ast.Member)
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
return fmt.Errorf("%v enum '%v' does not contain '%v'", ast.Source, enum.Name, ast.Name)
|
return fmt.Errorf("%v enum '%v' does not contain '%v'", ast.Source, enum.Name, ast.Member)
|
||||||
}
|
}
|
||||||
m.Options = append(m.Options, entry)
|
m.Options = append(m.Options, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("'%v' cannot be used for matcher", a.Name)
|
|
||||||
|
return fmt.Errorf("%v matcher cannot be empty", a.Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
// intrinsic() resolves a intrinsic overload declaration.
|
// intrinsic() resolves a intrinsic overload declaration.
|
||||||
|
@ -419,33 +436,6 @@ func (r *resolver) fullyQualifiedName(s *scope, arg ast.TemplatedName) (sem.Full
|
||||||
return sem.FullyQualifiedName{}, err
|
return sem.FullyQualifiedName{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry, ok := target.(*sem.EnumEntry); ok {
|
|
||||||
// The target resolved to an enum entry.
|
|
||||||
// Automagically transform this into a synthetic matcher with a single
|
|
||||||
// option. i.e.
|
|
||||||
// This:
|
|
||||||
// enum E{ a b c }
|
|
||||||
// fn F(b)
|
|
||||||
// Becomes:
|
|
||||||
// enum E{ a b c }
|
|
||||||
// matcher b
|
|
||||||
// fn F(b)
|
|
||||||
// We don't really care right now that we have a symbol collision
|
|
||||||
// between E.b and b, as the generators return different names for
|
|
||||||
// these.
|
|
||||||
matcher, ok := r.enumEntryMatchers[entry]
|
|
||||||
if !ok {
|
|
||||||
matcher = &sem.EnumMatcher{
|
|
||||||
Name: entry.Name,
|
|
||||||
Enum: entry.Enum,
|
|
||||||
Options: []*sem.EnumEntry{entry},
|
|
||||||
}
|
|
||||||
r.enumEntryMatchers[entry] = matcher
|
|
||||||
r.s.EnumMatchers = append(r.s.EnumMatchers, matcher)
|
|
||||||
}
|
|
||||||
target = matcher
|
|
||||||
}
|
|
||||||
|
|
||||||
fqn := sem.FullyQualifiedName{
|
fqn := sem.FullyQualifiedName{
|
||||||
Target: target,
|
Target: target,
|
||||||
TemplateArguments: make([]interface{}, len(arg.TemplateArgs)),
|
TemplateArguments: make([]interface{}, len(arg.TemplateArgs)),
|
||||||
|
|
|
@ -54,7 +54,7 @@ match y: x`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e {a b c}
|
enum e {a b c}
|
||||||
match y: c | a | b`,
|
match y: e.c | e.a | e.b`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
`fn f()`,
|
`fn f()`,
|
||||||
|
@ -94,26 +94,35 @@ fn f(P<m>)`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a }
|
enum e { a }
|
||||||
fn f(a)`,
|
match m: e.a
|
||||||
|
fn f(m)`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a b }
|
enum e { a b }
|
||||||
type T<E: e>
|
type T<E: e>
|
||||||
match m: a
|
match m: e.a
|
||||||
fn f<E: m>(T<E>)`,
|
fn f<E: m>(T<E>)`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a b }
|
enum e { a b }
|
||||||
type T<E: e>
|
type T<E: e>
|
||||||
match m: a
|
match m: e.a
|
||||||
fn f(T<m>)`,
|
fn f(T<m>)`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a }
|
enum e { a }
|
||||||
type T<E: e>
|
type T<E: e>
|
||||||
|
match m : e.a
|
||||||
|
fn f(T<m>)`,
|
||||||
|
success,
|
||||||
|
}, {
|
||||||
|
`
|
||||||
|
enum e { a }
|
||||||
|
type T<E: e>
|
||||||
|
match a : e.a
|
||||||
fn f(T<a>)`,
|
fn f(T<a>)`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
|
@ -132,7 +141,7 @@ fn f<E: e>()`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a b }
|
enum e { a b }
|
||||||
match m: a | b
|
match m: e.a | e.b
|
||||||
fn f<E: m>()`,
|
fn f<E: m>()`,
|
||||||
success,
|
success,
|
||||||
}, {
|
}, {
|
||||||
|
@ -178,8 +187,7 @@ conv f32(T<f32>)`,
|
||||||
}, {
|
}, {
|
||||||
`enum E {A A}`,
|
`enum E {A A}`,
|
||||||
`
|
`
|
||||||
file.txt:1:6 'A' already declared
|
file.txt:1:11 duplicate enum entry 'A'
|
||||||
First declared here: file.txt:1:6
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -230,14 +238,6 @@ file.txt:2:14 cannot resolve 'b'
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type a
|
type a
|
||||||
enum e { b }
|
|
||||||
match x: a | b`,
|
|
||||||
`
|
|
||||||
file.txt:3:14 'b' resolves to enum entry 'e.b' but type is expected
|
|
||||||
`,
|
|
||||||
}, {
|
|
||||||
`
|
|
||||||
type a
|
|
||||||
type b
|
type b
|
||||||
match x: a | b | a`,
|
match x: a | b | a`,
|
||||||
`
|
`
|
||||||
|
@ -247,15 +247,15 @@ First declared here: file.txt:3:10
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a c }
|
enum e { a c }
|
||||||
match x: a | b | c`,
|
match x: e.a | e.b | e.c`,
|
||||||
`
|
`
|
||||||
file.txt:2:14 enum 'e' does not contain 'b'
|
file.txt:2:18 enum 'e' does not contain 'b'
|
||||||
`,
|
`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
enum e { a }
|
enum e { a }
|
||||||
match x: a
|
match x: e.a
|
||||||
match x: a`,
|
match x: e.a`,
|
||||||
`
|
`
|
||||||
file.txt:3:7 'x' already declared
|
file.txt:3:7 'x' already declared
|
||||||
First declared here: file.txt:2:7
|
First declared here: file.txt:2:7
|
||||||
|
@ -266,7 +266,7 @@ type t
|
||||||
match x: t
|
match x: t
|
||||||
match y: x`,
|
match y: x`,
|
||||||
`
|
`
|
||||||
'y' cannot be used for matcher
|
file.txt:3:10 'x' resolves to type matcher 'x' but type is expected
|
||||||
`,
|
`,
|
||||||
}, {
|
}, {
|
||||||
`fn f(u)`,
|
`fn f(u)`,
|
||||||
|
@ -300,12 +300,6 @@ fn f(A<B>)`,
|
||||||
`file.txt:3:8 cannot use type 'B' as template number`,
|
`file.txt:3:8 cannot use type 'B' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type A<N>
|
|
||||||
enum E { b }
|
|
||||||
fn f(A<b>)`,
|
|
||||||
`file.txt:3:8 cannot use enum entry 'E.b' as template type`,
|
|
||||||
}, {
|
|
||||||
`
|
|
||||||
type T
|
type T
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
match m: T
|
match m: T
|
||||||
|
@ -321,14 +315,14 @@ fn f(P<E>)`,
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
fn f(P<m>)`,
|
fn f(P<m>)`,
|
||||||
`file.txt:4:8 cannot use enum matcher 'm' as template number`,
|
`file.txt:4:8 cannot use enum matcher 'm' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
fn f<M: m>(P<M>)`,
|
fn f<M: m>(P<M>)`,
|
||||||
`file.txt:4:14 cannot use template enum 'E' as template number`,
|
`file.txt:4:14 cannot use template enum 'E' as template number`,
|
||||||
}, {
|
}, {
|
||||||
|
@ -366,8 +360,9 @@ op << (A<B>)`,
|
||||||
`
|
`
|
||||||
type A<N>
|
type A<N>
|
||||||
enum E { b }
|
enum E { b }
|
||||||
op << (A<b>)`,
|
match M: E.b
|
||||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
op << (A<M>)`,
|
||||||
|
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type T
|
type T
|
||||||
|
@ -385,14 +380,14 @@ op << (P<E>)`,
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
op << (P<m>)`,
|
op << (P<m>)`,
|
||||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
op << <M: m>(P<M>)`,
|
op << <M: m>(P<M>)`,
|
||||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
}, {
|
}, {
|
||||||
|
@ -421,8 +416,9 @@ ctor F(A<B>)`,
|
||||||
`
|
`
|
||||||
type A<N>
|
type A<N>
|
||||||
enum E { b }
|
enum E { b }
|
||||||
ctor F(A<b>)`,
|
match M: E.b
|
||||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
ctor F(A<M>)`,
|
||||||
|
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type T
|
type T
|
||||||
|
@ -440,14 +436,14 @@ ctor F(P<E>)`,
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
ctor F(P<m>)`,
|
ctor F(P<m>)`,
|
||||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
ctor F<M: m>(P<M>)`,
|
ctor F<M: m>(P<M>)`,
|
||||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
}, {
|
}, {
|
||||||
|
@ -485,8 +481,9 @@ conv F(A<B>)`,
|
||||||
`
|
`
|
||||||
type A<N>
|
type A<N>
|
||||||
enum E { b }
|
enum E { b }
|
||||||
conv F(A<b>)`,
|
match M: E.b
|
||||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
conv F(A<M>)`,
|
||||||
|
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type T
|
type T
|
||||||
|
@ -504,32 +501,22 @@ conv F(P<E>)`,
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
conv F(P<m>)`,
|
conv F(P<m>)`,
|
||||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||||
}, {
|
}, {
|
||||||
`
|
`
|
||||||
type P<N: num>
|
type P<N: num>
|
||||||
enum E { a b }
|
enum E { a b }
|
||||||
match m: a | b
|
match m: E.a | E.b
|
||||||
conv F<M: m>(P<M>)`,
|
conv F<M: m>(P<M>)`,
|
||||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||||
}, {
|
|
||||||
`
|
|
||||||
enum E { a }
|
|
||||||
type T<X: a>`,
|
|
||||||
`file.txt:2:8 invalid template parameter type 'a'`,
|
|
||||||
}, {
|
|
||||||
`
|
|
||||||
enum E { a }
|
|
||||||
fn f<M: a>()`,
|
|
||||||
`file.txt:2:6 invalid template parameter type 'a'`,
|
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
|
||||||
ast, err := parser.Parse(strings.TrimSpace(string(test.src)), "file.txt")
|
ast, err := parser.Parse(strings.TrimSpace(string(test.src)), "file.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected parser error: %v", err)
|
t.Errorf("While parsing:\n%s\nUnexpected parser error: %v", test.src, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ const (
|
||||||
Comma Kind = ","
|
Comma Kind = ","
|
||||||
Complement Kind = "~"
|
Complement Kind = "~"
|
||||||
Divide Kind = "/"
|
Divide Kind = "/"
|
||||||
|
Dot Kind = "."
|
||||||
Equal Kind = "=="
|
Equal Kind = "=="
|
||||||
Ge Kind = ">="
|
Ge Kind = ">="
|
||||||
Gt Kind = ">"
|
Gt Kind = ">"
|
||||||
|
|
Loading…
Reference in New Issue