blob: 3d229c0ac3faa3e79f4410dcd810a3d99e844aaf [file] [log] [blame]
// 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/tint/tools/src/cmd/builtin-gen/ast"
"dawn.googlesource.com/tint/tools/src/cmd/builtin-gen/parser"
)
func TestParser(t *testing.T) {
type test struct {
src string
expect ast.AST
}
for _, test := range []test{
{"enum E {}", ast.AST{
Enums: []ast.EnumDecl{{Name: "E"}},
}},
{"enum E { A [[deco]] B C }", ast.AST{
Enums: []ast.EnumDecl{{
Name: "E",
Entries: []ast.EnumEntry{
{Name: "A"},
{
Decorations: ast.Decorations{{Name: "deco"}},
Name: "B",
},
{Name: "C"},
},
}},
}},
{"type T", ast.AST{
Types: []ast.TypeDecl{{Name: "T"}},
}},
{"type T<A, B, C>", ast.AST{
Types: []ast.TypeDecl{{
Name: "T",
TemplateParams: ast.TemplateParams{
{Name: "A"},
{Name: "B"},
{Name: "C"},
},
}},
}},
{"[[deco]] type T", ast.AST{
Types: []ast.TypeDecl{{
Decorations: ast.Decorations{
{Name: "deco"},
},
Name: "T",
}},
}},
{`[[deco("a", "b")]] type T`, ast.AST{
Types: []ast.TypeDecl{{
Decorations: ast.Decorations{
{Name: "deco", Values: []string{"a", "b"}},
},
Name: "T",
}},
}},
{"match M : A", ast.AST{
Matchers: []ast.MatcherDecl{{
Name: "M",
Options: ast.MatcherOptions{
ast.TemplatedName{Name: "A"},
},
}},
}},
{"match M : A | B", ast.AST{
Matchers: []ast.MatcherDecl{{
Name: "M",
Options: ast.MatcherOptions{
ast.TemplatedName{Name: "A"},
ast.TemplatedName{Name: "B"},
},
}},
}},
{"fn F()", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
}},
}},
{"[[deco]] fn F()", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
Decorations: ast.Decorations{
{Name: "deco"},
},
}},
}},
{"fn F(a)", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
Parameters: ast.Parameters{
{Type: ast.TemplatedName{Name: "a"}},
},
}},
}},
{"fn F(a: T)", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
Parameters: ast.Parameters{
{Name: "a", Type: ast.TemplatedName{Name: "T"}},
},
}},
}},
{"fn F(a, b)", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
Parameters: ast.Parameters{
{Type: ast.TemplatedName{Name: "a"}},
{Type: ast.TemplatedName{Name: "b"}},
},
}},
}},
{"fn F<A : B<C>>()", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
TemplateParams: ast.TemplateParams{
{
Name: "A", Type: ast.TemplatedName{
Name: "B",
TemplateArgs: ast.TemplatedNames{
{Name: "C"},
},
},
},
},
}},
}},
{"fn F<T>(a: X, b: Y<T>)", ast.AST{
Functions: []ast.FunctionDecl{{
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"}},
}},
},
}},
}},
{"fn F() -> X", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
ReturnType: &ast.TemplatedName{Name: "X"},
}},
}},
{"fn F() -> X<T>", ast.AST{
Functions: []ast.FunctionDecl{{
Name: "F",
ReturnType: &ast.TemplatedName{
Name: "X",
TemplateArgs: []ast.TemplatedName{{Name: "T"}},
},
}},
}},
} {
got, err := parser.Parse(test.src, "file.txt")
if err != nil {
t.Errorf("While parsing:\n%s\nParse() returned error: %v", test.src, err)
continue
}
gotStr, expectStr := got.String(), test.expect.String()
if gotStr != expectStr {
t.Errorf("While parsing:\n%s\nGot:\n%s\nExpected:\n%s", test.src, gotStr, expectStr)
}
}
}
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:3 expected 'ident' for decoration name, got 'integer'"},
{"[[abc", "expected ']]' for decoration list, but reached end of file"},
} {
got, err := parser.Parse(test.src, "test.txt")
if gotErr := err.Error(); 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")
}
}
}