174 lines
5.0 KiB
Go
174 lines
5.0 KiB
Go
// 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.
|
|
|
|
// builtin-gen parses the <tint>/src/tint/builtins.def file, then scans the
|
|
// project directory for '<file>.tmpl' files, to produce '<file>' source code
|
|
// files.
|
|
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"dawn.googlesource.com/dawn/tools/src/cmd/builtin-gen/gen"
|
|
"dawn.googlesource.com/dawn/tools/src/cmd/builtin-gen/parser"
|
|
"dawn.googlesource.com/dawn/tools/src/cmd/builtin-gen/resolver"
|
|
"dawn.googlesource.com/dawn/tools/src/fileutils"
|
|
"dawn.googlesource.com/dawn/tools/src/glob"
|
|
)
|
|
|
|
const defProjectRelPath = "src/tint/builtins.def"
|
|
|
|
func main() {
|
|
if err := run(); err != nil {
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func showUsage() {
|
|
fmt.Println(`
|
|
builtin-gen generates the builtin table for the Tint compiler
|
|
|
|
builtin-gen parses the <tint>/src/tint/builtins.def file, then scans the project
|
|
directory for '<file>.tmpl' files, to produce '<file>' source code files.
|
|
|
|
usage:
|
|
builtin-gen
|
|
|
|
optional flags:`)
|
|
flag.PrintDefaults()
|
|
fmt.Println(``)
|
|
os.Exit(1)
|
|
}
|
|
|
|
func run() error {
|
|
// Load the builtins definition file
|
|
projectRoot := fileutils.ProjectRoot()
|
|
defPath := filepath.Join(projectRoot, defProjectRelPath)
|
|
|
|
defSource, err := ioutil.ReadFile(defPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Parse the definition file to produce an AST
|
|
ast, err := parser.Parse(string(defSource), defProjectRelPath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Resolve the AST to produce the semantic info
|
|
sem, err := resolver.Resolve(ast)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Recursively find all the template files in the <tint>/src directory
|
|
files, err := glob.Scan(projectRoot, glob.MustParseConfig(`{
|
|
"paths": [{"include": [
|
|
"src/tint/**.tmpl",
|
|
"test/tint/**.tmpl"
|
|
]}]
|
|
}`))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// For each template file...
|
|
for _, relTmplPath := range files {
|
|
// Make tmplPath absolute
|
|
tmplPath := filepath.Join(projectRoot, relTmplPath)
|
|
|
|
// Read the template file
|
|
tmpl, err := ioutil.ReadFile(tmplPath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open '%v': %w", tmplPath, err)
|
|
}
|
|
|
|
// Create or update the file at relpath if the file content has changed
|
|
// relpath is a path relative to the template
|
|
writeFile := func(relpath, body string) error {
|
|
// Write the common file header
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(header, filepath.ToSlash(relTmplPath), filepath.ToSlash(defProjectRelPath)))
|
|
sb.WriteString(body)
|
|
content := sb.String()
|
|
abspath := filepath.Join(filepath.Dir(tmplPath), relpath)
|
|
return writeFileIfChanged(abspath, content)
|
|
}
|
|
|
|
// Write the content generated using the template and semantic info
|
|
sb := strings.Builder{}
|
|
if err := gen.Generate(sem, string(tmpl), &sb, writeFile); err != nil {
|
|
return fmt.Errorf("while processing '%v': %w", tmplPath, err)
|
|
}
|
|
|
|
if body := sb.String(); body != "" {
|
|
_, tmplFileName := filepath.Split(tmplPath)
|
|
outFileName := strings.TrimSuffix(tmplFileName, ".tmpl")
|
|
if err := writeFile(outFileName, body); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// writes content to path if the file has changed
|
|
func writeFileIfChanged(path, content string) error {
|
|
existing, err := ioutil.ReadFile(path)
|
|
if err == nil && string(existing) == content {
|
|
return nil // Not changed
|
|
}
|
|
if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
|
|
return fmt.Errorf("failed to create directory for '%v': %w", path, err)
|
|
}
|
|
if err := ioutil.WriteFile(path, []byte(content), 0666); err != nil {
|
|
return fmt.Errorf("failed to write file '%v': %w", path, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
const header = `// 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.
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// File generated by tools/builtin-gen
|
|
// using the template:
|
|
// %v
|
|
// and the builtin defintion file:
|
|
// %v
|
|
//
|
|
// Do not modify this file directly
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
`
|