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
|
||||
match f32_texel_format:
|
||||
rgba8unorm | rgba8snorm | rgba16float | r32float | rg32float | rgba32float
|
||||
match i32_texel_format:
|
||||
rgba8sint | rgba16sint | r32sint | rg32sint | rgba32sint
|
||||
match u32_texel_format:
|
||||
rgba8uint | rgba16uint | r32uint | rg32uint | rgba32uint
|
||||
match f32_texel_format
|
||||
: texel_format.rgba8unorm
|
||||
| texel_format.rgba8snorm
|
||||
| texel_format.rgba16float
|
||||
| texel_format.r32float
|
||||
| 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 workgroup_or_storage: workgroup | storage
|
||||
match function_private_workgroup
|
||||
: 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 //
|
||||
|
@ -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, level: i32) -> 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_only>(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_only>(texture: texture_storage_3d<F, A>) -> vec3<i32>
|
||||
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_1d<F, A>) -> i32
|
||||
fn textureDimensions<F: texel_format, A: write>(texture: texture_storage_2d<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>(texture: texture_storage_3d<F, A>) -> vec3<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>, @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(texture: texture_depth_2d_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_2d<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)
|
||||
}
|
||||
|
||||
// MatcherOptions is a list of TemplatedName
|
||||
type MatcherOptions TemplatedNames
|
||||
// MatcherOptions is a list of TemplatedNames or MemberNames
|
||||
type MatcherOptions struct {
|
||||
Types TemplatedNames
|
||||
Enums MemberNames
|
||||
}
|
||||
|
||||
// Format implements the fmt.Formatter interface
|
||||
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 {
|
||||
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
|
||||
type TypeDecl struct {
|
||||
Source tok.Source
|
||||
|
|
|
@ -91,6 +91,7 @@ func (l *lexer) lex() error {
|
|||
l.skip(l.count(toFirst('\n')))
|
||||
l.next() // Consume newline
|
||||
case l.match("/", tok.Divide):
|
||||
case l.match(".", tok.Dot):
|
||||
case l.match("->", tok.Arrow):
|
||||
case l.match("-", tok.Minus):
|
||||
case l.match("fn", tok.Function):
|
||||
|
|
|
@ -109,12 +109,21 @@ func (p *parser) matcherDecl() ast.MatcherDecl {
|
|||
name := p.expect(tok.Identifier, "matcher name")
|
||||
m := ast.MatcherDecl{Source: name.Source, Name: string(name.Runes)}
|
||||
p.expect(tok.Colon, "matcher declaration")
|
||||
if p.peekIs(1, tok.Dot) { // enum list
|
||||
for p.err == nil {
|
||||
m.Options = append(m.Options, p.templatedName())
|
||||
m.Options.Enums = append(m.Options.Enums, p.memberName())
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -277,6 +286,17 @@ func (p *parser) string() string {
|
|||
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 {
|
||||
name := p.expect(tok.Identifier, "type name")
|
||||
m := ast.TemplatedName{Source: name.Source, Name: string(name.Runes)}
|
||||
|
|
|
@ -129,7 +129,9 @@ func TestParser(t *testing.T) {
|
|||
Matchers: []ast.MatcherDecl{{
|
||||
Name: "M",
|
||||
Options: ast.MatcherOptions{
|
||||
ast.TemplatedName{Name: "A"},
|
||||
Types: ast.TemplatedNames{
|
||||
{Name: "A"},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
|
@ -140,8 +142,37 @@ func TestParser(t *testing.T) {
|
|||
Matchers: []ast.MatcherDecl{{
|
||||
Name: "M",
|
||||
Options: ast.MatcherOptions{
|
||||
ast.TemplatedName{Name: "A"},
|
||||
ast.TemplatedName{Name: "B"},
|
||||
Types: ast.TemplatedNames{
|
||||
{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"
|
||||
"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/sem"
|
||||
"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
|
||||
names := container.NewSet[string]()
|
||||
for _, ast := range e.Entries {
|
||||
entry := &sem.EnumEntry{
|
||||
Name: ast.Name,
|
||||
|
@ -139,10 +141,11 @@ func (r *resolver) enum(e ast.EnumDecl) error {
|
|||
if len(ast.Attributes) != 0 {
|
||||
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)
|
||||
if names.Contains(ast.Name) {
|
||||
return fmt.Errorf("%v duplicate enum entry '%v'", ast.Source, ast.Name)
|
||||
}
|
||||
names.Add(ast.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -203,16 +206,13 @@ func (r *resolver) ty(a ast.TypeDecl) error {
|
|||
// The resulting matcher is appended to either Sem.TypeMatchers or
|
||||
// Sem.EnumMatchers, and is registered with the global scope.
|
||||
func (r *resolver) matcher(a ast.MatcherDecl) error {
|
||||
// Determine whether this is a type matcher or enum matcher by resolving the
|
||||
// first option
|
||||
firstOption, err := r.lookupNamed(&r.globals, a.Options[0])
|
||||
if err != nil {
|
||||
return err
|
||||
isTypeMatcher := len(a.Options.Types) != 0
|
||||
isEnumMatcher := len(a.Options.Enums) != 0
|
||||
if isTypeMatcher && isEnumMatcher {
|
||||
return fmt.Errorf("%v matchers cannot mix enums and types", a.Source)
|
||||
}
|
||||
|
||||
// Resolve to a sem.TypeMatcher or a sem.EnumMatcher
|
||||
switch firstOption := firstOption.(type) {
|
||||
case *sem.Type:
|
||||
if isTypeMatcher {
|
||||
options := map[sem.Named]tok.Source{}
|
||||
m := &sem.TypeMatcher{
|
||||
Decl: a,
|
||||
|
@ -226,7 +226,7 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -239,9 +239,25 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
|||
}
|
||||
|
||||
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{
|
||||
Decl: a,
|
||||
Name: a.Name,
|
||||
|
@ -255,17 +271,18 @@ func (r *resolver) matcher(a ast.MatcherDecl) error {
|
|||
}
|
||||
|
||||
// Resolve each of the enums in the options list
|
||||
for _, ast := range m.Decl.Options {
|
||||
entry := enum.FindEntry(ast.Name)
|
||||
for _, ast := range m.Decl.Options.Enums {
|
||||
entry := enum.FindEntry(ast.Member)
|
||||
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)
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -419,33 +436,6 @@ func (r *resolver) fullyQualifiedName(s *scope, arg ast.TemplatedName) (sem.Full
|
|||
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{
|
||||
Target: target,
|
||||
TemplateArguments: make([]interface{}, len(arg.TemplateArgs)),
|
||||
|
|
|
@ -54,7 +54,7 @@ match y: x`,
|
|||
}, {
|
||||
`
|
||||
enum e {a b c}
|
||||
match y: c | a | b`,
|
||||
match y: e.c | e.a | e.b`,
|
||||
success,
|
||||
}, {
|
||||
`fn f()`,
|
||||
|
@ -94,26 +94,35 @@ fn f(P<m>)`,
|
|||
}, {
|
||||
`
|
||||
enum e { a }
|
||||
fn f(a)`,
|
||||
match m: e.a
|
||||
fn f(m)`,
|
||||
success,
|
||||
}, {
|
||||
`
|
||||
enum e { a b }
|
||||
type T<E: e>
|
||||
match m: a
|
||||
match m: e.a
|
||||
fn f<E: m>(T<E>)`,
|
||||
success,
|
||||
}, {
|
||||
`
|
||||
enum e { a b }
|
||||
type T<E: e>
|
||||
match m: a
|
||||
match m: e.a
|
||||
fn f(T<m>)`,
|
||||
success,
|
||||
}, {
|
||||
`
|
||||
enum e { a }
|
||||
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>)`,
|
||||
success,
|
||||
}, {
|
||||
|
@ -132,7 +141,7 @@ fn f<E: e>()`,
|
|||
}, {
|
||||
`
|
||||
enum e { a b }
|
||||
match m: a | b
|
||||
match m: e.a | e.b
|
||||
fn f<E: m>()`,
|
||||
success,
|
||||
}, {
|
||||
|
@ -178,8 +187,7 @@ conv f32(T<f32>)`,
|
|||
}, {
|
||||
`enum E {A A}`,
|
||||
`
|
||||
file.txt:1:6 'A' already declared
|
||||
First declared here: file.txt:1:6
|
||||
file.txt:1:11 duplicate enum entry 'A'
|
||||
`,
|
||||
},
|
||||
{
|
||||
|
@ -230,14 +238,6 @@ file.txt:2:14 cannot resolve 'b'
|
|||
}, {
|
||||
`
|
||||
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
|
||||
match x: a | b | a`,
|
||||
`
|
||||
|
@ -247,15 +247,15 @@ First declared here: file.txt:3:10
|
|||
}, {
|
||||
`
|
||||
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 }
|
||||
match x: a
|
||||
match x: a`,
|
||||
match x: e.a
|
||||
match x: e.a`,
|
||||
`
|
||||
file.txt:3:7 'x' already declared
|
||||
First declared here: file.txt:2:7
|
||||
|
@ -266,7 +266,7 @@ type t
|
|||
match x: t
|
||||
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)`,
|
||||
|
@ -300,12 +300,6 @@ fn f(A<B>)`,
|
|||
`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 P<N: num>
|
||||
match m: T
|
||||
|
@ -321,14 +315,14 @@ fn f(P<E>)`,
|
|||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
fn f(P<m>)`,
|
||||
`file.txt:4:8 cannot use enum matcher 'm' as template number`,
|
||||
}, {
|
||||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
fn f<M: m>(P<M>)`,
|
||||
`file.txt:4:14 cannot use template enum 'E' as template number`,
|
||||
}, {
|
||||
|
@ -366,8 +360,9 @@ op << (A<B>)`,
|
|||
`
|
||||
type A<N>
|
||||
enum E { b }
|
||||
op << (A<b>)`,
|
||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
||||
match M: E.b
|
||||
op << (A<M>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||
}, {
|
||||
`
|
||||
type T
|
||||
|
@ -385,14 +380,14 @@ op << (P<E>)`,
|
|||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
op << (P<m>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||
}, {
|
||||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
op << <M: m>(P<M>)`,
|
||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||
}, {
|
||||
|
@ -421,8 +416,9 @@ ctor F(A<B>)`,
|
|||
`
|
||||
type A<N>
|
||||
enum E { b }
|
||||
ctor F(A<b>)`,
|
||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
||||
match M: E.b
|
||||
ctor F(A<M>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||
}, {
|
||||
`
|
||||
type T
|
||||
|
@ -440,14 +436,14 @@ ctor F(P<E>)`,
|
|||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
ctor F(P<m>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||
}, {
|
||||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
ctor F<M: m>(P<M>)`,
|
||||
`file.txt:4:16 cannot use template enum 'E' as template number`,
|
||||
}, {
|
||||
|
@ -485,8 +481,9 @@ conv F(A<B>)`,
|
|||
`
|
||||
type A<N>
|
||||
enum E { b }
|
||||
conv F(A<b>)`,
|
||||
`file.txt:3:10 cannot use enum entry 'E.b' as template type`,
|
||||
match M: E.b
|
||||
conv F(A<M>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'M' as template type`,
|
||||
}, {
|
||||
`
|
||||
type T
|
||||
|
@ -504,32 +501,22 @@ conv F(P<E>)`,
|
|||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
conv F(P<m>)`,
|
||||
`file.txt:4:10 cannot use enum matcher 'm' as template number`,
|
||||
}, {
|
||||
`
|
||||
type P<N: num>
|
||||
enum E { a b }
|
||||
match m: a | b
|
||||
match m: E.a | E.b
|
||||
conv F<M: m>(P<M>)`,
|
||||
`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")
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected parser error: %v", err)
|
||||
t.Errorf("While parsing:\n%s\nUnexpected parser error: %v", test.src, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ const (
|
|||
Comma Kind = ","
|
||||
Complement Kind = "~"
|
||||
Divide Kind = "/"
|
||||
Dot Kind = "."
|
||||
Equal Kind = "=="
|
||||
Ge Kind = ">="
|
||||
Gt Kind = ">"
|
||||
|
|
Loading…
Reference in New Issue