-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
attr: generate code from textflag.h (#176)
- Loading branch information
1 parent
e5c9b4e
commit c5faaae
Showing
4 changed files
with
297 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
// +build ignore | ||
|
||
package main | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"go/format" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
var ( | ||
TextFlagPath = "src/runtime/textflag.h" | ||
TextFlagName = filepath.Base(TextFlagPath) | ||
) | ||
|
||
var ( | ||
download = flag.Bool("download", false, "download new version of "+TextFlagName) | ||
version = flag.String("version", runtime.Version(), "go version to download file from") | ||
textflag = flag.String("textflag", TextFlagName, "path to "+TextFlagName) | ||
output = flag.String("output", "", "path to output file") | ||
) | ||
|
||
func main() { | ||
if err := mainerr(); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func mainerr() error { | ||
flag.Parse() | ||
|
||
// Download new version, if requested. | ||
if *download { | ||
if err := DownloadGoSourceFile(*textflag, *version, TextFlagPath); err != nil { | ||
return err | ||
} | ||
log.Printf("downloaded %q from version %s to %q", TextFlagPath, *version, *textflag) | ||
} | ||
|
||
// Parse text flags header. | ||
fs, err := ParseFile(*textflag) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Determine output. | ||
w := os.Stdout | ||
if *output != "" { | ||
f, err := os.Create(*output) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
w = f | ||
} | ||
|
||
// Generate code and format it. | ||
buf := bytes.NewBuffer(nil) | ||
PrintFlagAttributes(buf, fs) | ||
|
||
src, err := format.Source(buf.Bytes()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Write output. | ||
_, err = w.Write(src) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// DownloadGoSourceFile downloads a Go source file from a specific version. | ||
func DownloadGoSourceFile(outpath, v, srcpath string) (err error) { | ||
// Download from github. | ||
url := "https://github.com/golang/go/raw/" + v + "/" + srcpath | ||
res, err := http.Get(url) | ||
if err != nil { | ||
return err | ||
} | ||
defer func() { | ||
if errc := res.Body.Close(); errc != nil && err == nil { | ||
err = errc | ||
} | ||
}() | ||
|
||
// Write to file. | ||
buf := bytes.NewBuffer(nil) | ||
fmt.Fprintf(buf, "// Code generated by downloading from %s. DO NOT EDIT.\n\n", url) | ||
|
||
if _, err := io.Copy(buf, res.Body); err != nil { | ||
return err | ||
} | ||
|
||
if err := ioutil.WriteFile(outpath, buf.Bytes(), 0644); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
type Flag struct { | ||
Doc []string | ||
Name string | ||
Value int | ||
} | ||
|
||
// Parse text flags header format. | ||
func Parse(r io.Reader) ([]Flag, error) { | ||
var fs []Flag | ||
var doc []string | ||
|
||
s := bufio.NewScanner(r) | ||
for s.Scan() { | ||
line := s.Text() | ||
switch { | ||
case strings.Contains(line, "TODO"): | ||
// skip | ||
|
||
case strings.HasPrefix(line, "// "): | ||
doc = append(doc, strings.TrimPrefix(line, "// ")) | ||
|
||
case strings.HasPrefix(line, "#define"): | ||
fields := strings.Fields(line) | ||
if len(fields) != 3 || fields[0] != "#define" { | ||
return nil, fmt.Errorf("unexpected line format %q", line) | ||
} | ||
v, err := strconv.Atoi(fields[2]) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
fs = append(fs, Flag{ | ||
Doc: doc, | ||
Name: fields[1], | ||
Value: v, | ||
}) | ||
doc = nil | ||
|
||
case line == "" || line == "//": | ||
doc = nil | ||
|
||
default: | ||
return nil, errors.New("unexpected format") | ||
} | ||
} | ||
|
||
if err := s.Err(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return fs, nil | ||
} | ||
|
||
// ParseFile parses text flags header file. | ||
func ParseFile(filename string) ([]Flag, error) { | ||
b, err := ioutil.ReadFile(filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return Parse(bytes.NewReader(b)) | ||
} | ||
|
||
func PrintFlagAttributes(w io.Writer, fs []Flag) { | ||
_, self, _, _ := runtime.Caller(0) | ||
fmt.Fprintf(w, "// Code generated by %s. DO NOT EDIT.\n\n", filepath.Base(self)) | ||
fmt.Fprintf(w, "package attr\n") | ||
|
||
// Attribute constants. | ||
fmt.Fprintf(w, "\n// Attribute values defined in %s.\n", TextFlagName) | ||
fmt.Fprintf(w, "const (\n") | ||
for _, f := range fs { | ||
for _, line := range f.Doc { | ||
fmt.Fprintf(w, "\t// %s\n", line) | ||
} | ||
fmt.Fprintf(w, "\t%s Attribute = %d\n\n", f.Name, f.Value) | ||
} | ||
fmt.Fprintf(w, ")\n") | ||
|
||
// String map. | ||
fmt.Fprintf(w, "\nvar attrname = map[Attribute]string{\n") | ||
for _, f := range fs { | ||
fmt.Fprintf(w, "\t%s: %q,\n", f.Name, f.Name) | ||
} | ||
fmt.Fprintf(w, "}\n") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Code generated by downloading from https://github.com/golang/go/raw/go1.16.2/src/runtime/textflag.h. DO NOT EDIT. | ||
|
||
// Copyright 2013 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
// This file defines flags attached to various functions | ||
// and data objects. The compilers, assemblers, and linker must | ||
// all agree on these values. | ||
// | ||
// Keep in sync with src/cmd/internal/obj/textflag.go. | ||
|
||
// Don't profile the marked routine. This flag is deprecated. | ||
#define NOPROF 1 | ||
// It is ok for the linker to get multiple of these symbols. It will | ||
// pick one of the duplicates to use. | ||
#define DUPOK 2 | ||
// Don't insert stack check preamble. | ||
#define NOSPLIT 4 | ||
// Put this data in a read-only section. | ||
#define RODATA 8 | ||
// This data contains no pointers. | ||
#define NOPTR 16 | ||
// This is a wrapper function and should not count as disabling 'recover'. | ||
#define WRAPPER 32 | ||
// This function uses its incoming context register. | ||
#define NEEDCTXT 64 | ||
// Allocate a word of thread local storage and store the offset from the | ||
// thread local base to the thread local storage in this variable. | ||
#define TLSBSS 256 | ||
// Do not insert instructions to allocate a stack frame for this function. | ||
// Only valid on functions that declare a frame size of 0. | ||
// TODO(mwhudson): only implemented for ppc64x at present. | ||
#define NOFRAME 512 | ||
// Function can call reflect.Type.Method or reflect.Type.MethodByName. | ||
#define REFLECTMETHOD 1024 | ||
// Function is the top of the call stack. Call stack unwinders should stop | ||
// at this function. | ||
#define TOPFRAME 2048 |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.