-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
exec: initial commit of execgen tool
Execgen will be our tool for generating templated code necessary for columnarized execution. So far it only generates the EncDatumRowsToColVec function, which is used by the columnarizer to convert a RowSource into a columnarized Operator. Release note: None
- Loading branch information
1 parent
2998190
commit c106c32
Showing
9 changed files
with
459 additions
and
117 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
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 @@ | ||
*.og.go |
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,160 @@ | ||
// Copyright 2018 The Cockroach 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 main | ||
|
||
import ( | ||
"bytes" | ||
"flag" | ||
"fmt" | ||
"go/format" | ||
"io" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
var ( | ||
errInvalidArgCount = errors.New("invalid number of arguments") | ||
) | ||
|
||
func main() { | ||
gen := execgen{stdErr: os.Stderr} | ||
if !gen.run(os.Args[1:]...) { | ||
os.Exit(2) | ||
} | ||
} | ||
|
||
type execgen struct { | ||
// useGoFmt runs the go fmt tool on code generated by execgen, if this setting | ||
// is true. | ||
useGoFmt bool | ||
|
||
// stdErr is the writer to which all standard error output will be redirected. | ||
stdErr io.Writer | ||
|
||
// cmdLine stores the set of flags used to invoke the Execgen tool. | ||
cmdLine *flag.FlagSet | ||
} | ||
|
||
type generator func(io.Writer) error | ||
|
||
var generators = make(map[string]generator) | ||
|
||
func registerGenerator(g generator, filename string) { | ||
if _, ok := generators[filename]; ok { | ||
panic(fmt.Sprintf("%s generator already registered", filename)) | ||
} | ||
generators[filename] = g | ||
} | ||
|
||
func (g *execgen) run(args ...string) bool { | ||
// Parse command line. | ||
g.cmdLine = flag.NewFlagSet("execgen", flag.ContinueOnError) | ||
g.cmdLine.SetOutput(g.stdErr) | ||
g.cmdLine.Usage = g.usage | ||
g.cmdLine.BoolVar(&g.useGoFmt, "useGoFmt", true, "run go fmt on generated code") | ||
err := g.cmdLine.Parse(args) | ||
if err != nil { | ||
return false | ||
} | ||
|
||
// Get remaining args after any flags have been parsed. | ||
args = g.cmdLine.Args() | ||
if len(args) < 1 { | ||
g.cmdLine.Usage() | ||
g.reportError(errInvalidArgCount) | ||
return false | ||
} | ||
|
||
for _, out := range args { | ||
_, file := filepath.Split(out) | ||
gen := generators[file] | ||
if gen == nil { | ||
g.reportError(errors.Errorf("unrecognized filename: %s", file)) | ||
return false | ||
} | ||
if err := g.generate(gen, out); err != nil { | ||
g.reportError(err) | ||
return false | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
func (g *execgen) generate(genFunc generator, out string) error { | ||
var buf bytes.Buffer | ||
buf.WriteString("// Code generated by execgen; DO NOT EDIT.\n") | ||
|
||
err := genFunc(&buf) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
var b []byte | ||
if g.useGoFmt { | ||
|
||
b, err = format.Source(buf.Bytes()) | ||
if err != nil { | ||
// Write out incorrect source for easier debugging. | ||
b = buf.Bytes() | ||
err = errors.Wrap(err, "Code formatting failed with Go parse error") | ||
} | ||
} else { | ||
b = buf.Bytes() | ||
} | ||
|
||
if err != nil { | ||
// Ignore any write error if another error already occurred. | ||
_ = g.writeOutputFile(b, out) | ||
return err | ||
} | ||
return g.writeOutputFile(b, out) | ||
} | ||
|
||
func (g *execgen) writeOutputFile(b []byte, out string) error { | ||
file, err := os.Create(out) | ||
if err != nil { | ||
return err | ||
} | ||
defer file.Close() | ||
|
||
_, err = file.Write(b) | ||
return err | ||
} | ||
|
||
// usage is a replacement usage function for the flags package. | ||
func (g *execgen) usage() { | ||
fmt.Fprintf(g.stdErr, "Execgen is a tool for generating templated code related to ") | ||
fmt.Fprintf(g.stdErr, "columnarized execution.\n\n") | ||
|
||
fmt.Fprintf(g.stdErr, "Usage:\n") | ||
fmt.Fprintf(g.stdErr, "\texecgen [path]...\n\n") | ||
|
||
fmt.Fprintf(g.stdErr, "Supported filenames are:\n") | ||
for filename := range generators { | ||
fmt.Fprintf(g.stdErr, "\t%s\n", filename) | ||
} | ||
fmt.Fprintf(g.stdErr, "\n") | ||
|
||
fmt.Fprintf(g.stdErr, "Flags:\n") | ||
g.cmdLine.PrintDefaults() | ||
fmt.Fprintf(g.stdErr, "\n") | ||
} | ||
|
||
func (g *execgen) reportError(err error) { | ||
fmt.Fprintf(g.stdErr, "ERROR: %v\n", err) | ||
} |
Oops, something went wrong.