| // 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. | 
 |  | 
 | // intrinsic-gen parses the <tint>/src/tint/intrinsics.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/intrinsic-gen/gen" | 
 | 	"dawn.googlesource.com/dawn/tools/src/cmd/intrinsic-gen/parser" | 
 | 	"dawn.googlesource.com/dawn/tools/src/cmd/intrinsic-gen/resolver" | 
 | 	"dawn.googlesource.com/dawn/tools/src/fileutils" | 
 | 	"dawn.googlesource.com/dawn/tools/src/glob" | 
 | ) | 
 |  | 
 | const defProjectRelPath = "src/tint/intrinsics.def" | 
 |  | 
 | func main() { | 
 | 	if err := run(); err != nil { | 
 | 		fmt.Println(err) | 
 | 		os.Exit(1) | 
 | 	} | 
 | } | 
 |  | 
 | func showUsage() { | 
 | 	fmt.Println(` | 
 | intrinsic-gen generates the intrinsic table for the Tint compiler | 
 |  | 
 | intrinsic-gen parses the <tint>/src/tint/intrinsics.def file, then scans the project | 
 | directory for '<file>.tmpl' files, to produce '<file>' source code files. | 
 |  | 
 | usage: | 
 |   intrinsic-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/intrinsic-gen | 
 | // using the template: | 
 | //   %v | 
 | // and the intrinsic defintion file: | 
 | //   %v | 
 | // | 
 | // Do not modify this file directly | 
 | //////////////////////////////////////////////////////////////////////////////// | 
 |  | 
 | ` |