| // 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 parser_test |
| |
| import ( |
| "testing" |
| |
| "dawn.googlesource.com/dawn/tools/src/fileutils" |
| "dawn.googlesource.com/dawn/tools/src/tint/intrinsic/ast" |
| "dawn.googlesource.com/dawn/tools/src/tint/intrinsic/parser" |
| "github.com/google/go-cmp/cmp" |
| ) |
| |
| var ignoreSource = cmp.FilterPath(func(p cmp.Path) bool { |
| return p.Last().String() == ".Source" |
| }, cmp.Ignore()) |
| |
| func TestParser(t *testing.T) { |
| type test struct { |
| location string |
| src string |
| expect ast.AST |
| } |
| |
| for _, test := range []test{ |
| { |
| fileutils.ThisLine(), |
| "enum E {}", |
| ast.AST{ |
| Enums: []ast.EnumDecl{{Name: "E"}}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "enum E { A @attr B C }", |
| ast.AST{ |
| Enums: []ast.EnumDecl{{ |
| Name: "E", |
| Entries: []ast.EnumEntry{ |
| {Name: "A"}, |
| { |
| Attributes: ast.Attributes{{ |
| Name: "attr", |
| Values: nil, |
| }}, |
| Name: "B", |
| }, |
| {Name: "C"}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "type T", |
| ast.AST{ |
| Types: []ast.TypeDecl{{Name: "T"}}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "type T<A, B, C>", |
| ast.AST{ |
| Types: []ast.TypeDecl{{ |
| Name: "T", |
| TemplateParams: ast.TemplateParams{ |
| {Name: "A"}, |
| {Name: "B"}, |
| {Name: "C"}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr type T", |
| ast.AST{ |
| Types: []ast.TypeDecl{{ |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: nil}, |
| }, |
| Name: "T", |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr_a @attr_b type T", |
| ast.AST{ |
| Types: []ast.TypeDecl{{ |
| Attributes: ast.Attributes{ |
| {Name: "attr_a", Values: nil}, |
| {Name: "attr_b", Values: nil}, |
| }, |
| Name: "T", |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| `@attr("a", "b") type T`, ast.AST{ |
| Types: []ast.TypeDecl{{ |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: []any{"a", "b"}}, |
| }, |
| Name: "T", |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| `@attr(1, "x", 2.0) type T`, ast.AST{ |
| Types: []ast.TypeDecl{{ |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: []any{1, "x", 2.0}}, |
| }, |
| Name: "T", |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "match M : A", |
| ast.AST{ |
| Matchers: []ast.MatcherDecl{{ |
| Name: "M", |
| Options: ast.MatcherOptions{ |
| Types: ast.TemplatedNames{ |
| {Name: "A"}, |
| }, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "match M : A | B", |
| ast.AST{ |
| Matchers: []ast.MatcherDecl{{ |
| Name: "M", |
| Options: ast.MatcherOptions{ |
| Types: ast.TemplatedNames{ |
| {Name: "A"}, |
| {Name: "B"}, |
| }, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "match M : A.B", |
| ast.AST{ |
| Matchers: []ast.MatcherDecl{{ |
| Name: "M", |
| Options: ast.MatcherOptions{ |
| Enums: ast.MemberNames{ |
| {Owner: "A", Member: "B"}, |
| }, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.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"}, |
| }, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F()", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr fn F()", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: nil}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F(a)", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F(a: T)", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "T"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F(a, b)", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| {Type: ast.TemplatedName{Name: "b"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F<A : B<C> >()", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| { |
| Name: "A", Type: ast.TemplatedName{ |
| Name: "B", |
| TemplateArgs: ast.TemplatedNames{ |
| {Name: "C"}, |
| }, |
| }, |
| }, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F<T>(a: X, b: Y<T>)", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| {Name: "T"}, |
| }, |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "X"}}, |
| {Name: "b", Type: ast.TemplatedName{ |
| Name: "Y", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F() -> X", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{Name: "X"}, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "fn F() -> X<T>", |
| ast.AST{ |
| Builtins: []ast.IntrinsicDecl{{ |
| Kind: ast.Builtin, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{ |
| Name: "X", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F()", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr op F()", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: nil}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F(a)", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F(@blah a)", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| { |
| Attributes: ast.Attributes{{Name: "blah", Values: nil}}, |
| Type: ast.TemplatedName{Name: "a"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F(a: T)", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "T"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F(a, b)", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| {Type: ast.TemplatedName{Name: "b"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F<A : B<C> >()", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| { |
| Name: "A", Type: ast.TemplatedName{ |
| Name: "B", |
| TemplateArgs: ast.TemplatedNames{ |
| {Name: "C"}, |
| }, |
| }, |
| }, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F<T>(a: X, b: Y<T>)", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| {Name: "T"}, |
| }, |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "X"}}, |
| {Name: "b", Type: ast.TemplatedName{ |
| Name: "Y", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F() -> X", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{Name: "X"}, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "op F() -> X<T>", |
| ast.AST{ |
| Operators: []ast.IntrinsicDecl{{ |
| Kind: ast.Operator, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{ |
| Name: "X", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F()", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr init F()", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: nil}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F(a)", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F(a: T)", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "T"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F(a, b)", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| {Type: ast.TemplatedName{Name: "b"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F<A : B<C> >()", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| { |
| Name: "A", Type: ast.TemplatedName{ |
| Name: "B", |
| TemplateArgs: ast.TemplatedNames{ |
| {Name: "C"}, |
| }, |
| }, |
| }, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F<T>(a: X, b: Y<T>)", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| {Name: "T"}, |
| }, |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "X"}}, |
| {Name: "b", Type: ast.TemplatedName{ |
| Name: "Y", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F() -> X", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{Name: "X"}, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "init F() -> X<T>", |
| ast.AST{ |
| Initializers: []ast.IntrinsicDecl{{ |
| Kind: ast.Initializer, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{ |
| Name: "X", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F()", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "@attr conv F()", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| Attributes: ast.Attributes{ |
| {Name: "attr", Values: nil}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F(a)", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F(a: T)", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "T"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F(a, b)", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| Parameters: ast.Parameters{ |
| {Type: ast.TemplatedName{Name: "a"}}, |
| {Type: ast.TemplatedName{Name: "b"}}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F<A : B<C> >()", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| { |
| Name: "A", Type: ast.TemplatedName{ |
| Name: "B", |
| TemplateArgs: ast.TemplatedNames{ |
| {Name: "C"}, |
| }, |
| }, |
| }, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F<T>(a: X, b: Y<T>)", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| TemplateParams: ast.TemplateParams{ |
| {Name: "T"}, |
| }, |
| Parameters: ast.Parameters{ |
| {Name: "a", Type: ast.TemplatedName{Name: "X"}}, |
| {Name: "b", Type: ast.TemplatedName{ |
| Name: "Y", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }}, |
| }, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F() -> X", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{Name: "X"}, |
| Parameters: ast.Parameters{}, |
| }}, |
| }, |
| }, { /////////////////////////////////////////////////////////////////// |
| fileutils.ThisLine(), |
| "conv F() -> X<T>", |
| ast.AST{ |
| Converters: []ast.IntrinsicDecl{{ |
| Kind: ast.Converter, |
| Name: "F", |
| ReturnType: &ast.TemplatedName{ |
| Name: "X", |
| TemplateArgs: []ast.TemplatedName{{Name: "T"}}, |
| }, |
| Parameters: ast.Parameters{}, |
| }}, |
| }}, |
| } { |
| got, err := parser.Parse(test.src, "file.txt") |
| if err != nil { |
| t.Errorf("\n%v\nWhile parsing:\n%s\nParse() returned error: %v", |
| test.location, test.src, err) |
| continue |
| } |
| |
| if diff := cmp.Diff(got, &test.expect, ignoreSource); diff != "" { |
| t.Errorf("\n%v\nWhile parsing:\n%s\n\n%s", |
| test.location, test.src, diff) |
| } |
| } |
| } |
| |
| func TestErrors(t *testing.T) { |
| type test struct { |
| src string |
| expect string |
| } |
| |
| for _, test := range []test{ |
| { |
| "£", |
| "test.txt:1:1: unexpected '£'", |
| }, |
| { |
| "123", |
| "test.txt:1:1 unexpected token 'integer'", |
| }, |
| { |
| "@123", |
| "test.txt:1:2 expected 'ident' for attribute name, got 'integer'", |
| }, |
| } { |
| got, err := parser.Parse(test.src, "test.txt") |
| gotErr := "" |
| if err != nil { |
| gotErr = err.Error() |
| } |
| if test.expect != gotErr { |
| t.Errorf(`Parse() returned error "%+v", expected error "%+v"`, gotErr, test.expect) |
| } |
| if got != nil { |
| t.Errorf("Lex() returned non-nil for error") |
| } |
| } |
| } |