-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ruleguard: embed dsl/fluent dependency
When importing "github.com/quasilyte/go-ruleguard/dsl/fluent", use the embedded version so the binary does not depend on that package during the run-time. A simple `dslgen/dslgen.go` program writes all DSL sources as byte slices and puts them in dslgen package. When we need to create *types.Package out of them, we use generated byte slices as a parser and typechecker input. It's amusing that rules parser now has 3 different "importers". Fixes #23 Signed-off-by: Iskander Sharipov <[email protected]>
- Loading branch information
Showing
4 changed files
with
99 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package dslgen | ||
|
||
var Fluent = []byte("package fluent\n\n// Matcher is a main API group-level entry point.\n// It's used to define and configure the group rules.\n// It also represents a map of all rule-local variables.\ntype Matcher map[string]Var\n\n// Import loads given package path into a rule group imports table.\n//\n// That table is used during the rules compilation.\n//\n// The table has the following effect on the rules:\n//\t* For type expressions, it's used to resolve the\n//\t full package paths of qualified types, like `foo.Bar`.\n//\t If Import(`a/b/foo`) is called, `foo.Bar` will match\n//\t `a/b/foo.Bar` type during the pattern execution.\nfunc (m Matcher) Import(pkgPath string) {}\n\n// Match specifies a set of patterns that match a rule being defined.\n// Pattern matching succeeds if at least 1 pattern matches.\n//\n// If none of the given patterns matched, rule execution stops.\nfunc (m Matcher) Match(pattern string, alternatives ...string) Matcher {\n\treturn m\n}\n\n// Where applies additional constraint to a match.\n// If a given cond is not satisfied, a match is rejected and\n// rule execution stops.\nfunc (m Matcher) Where(cond bool) Matcher {\n\treturn m\n}\n\n// Report prints a message if associated rule match is successful.\n//\n// A message is a string that can contain interpolated expressions.\n// For every matched variable it's possible to interpolate\n// their printed representation into the message text with $<name>.\n// An entire match can be addressed with $$.\nfunc (m Matcher) Report(message string) Matcher {\n\treturn m\n}\n\n// Suggest assigns a quickfix suggestion for the matched code.\nfunc (m Matcher) Suggest(suggestion string) Matcher {\n\treturn m\n}\n\n// At binds the reported node to a named submatch.\n// If no explicit location is given, the outermost node ($$) is used.\nfunc (m Matcher) At(v Var) Matcher {\n\treturn m\n}\n\n// Var is a pattern variable that describes a named submatch.\ntype Var struct {\n\t// Pure reports whether expr matched by var is side-effect-free.\n\tPure bool\n\n\t// Const reports whether expr matched by var is a constant value.\n\tConst bool\n\n\t// Addressable reports whether the corresponding expression is addressable.\n\t// See https://golang.org/ref/spec#Address_operators.\n\tAddressable bool\n\n\t// Type is a type of a matched expr.\n\tType ExprType\n}\n\n// ExprType describes a type of a matcher expr.\ntype ExprType struct {\n\t// Size represents expression type size in bytes.\n\tSize int\n}\n\n// AssignableTo reports whether a type is assign-compatible with a given type.\n// See https://golang.org/pkg/go/types/#AssignableTo.\nfunc (ExprType) AssignableTo(typ string) bool { return boolResult }\n\n// ConvertibleTo reports whether a type is conversible to a given type.\n// See https://golang.org/pkg/go/types/#ConvertibleTo.\nfunc (ExprType) ConvertibleTo(typ string) bool { return boolResult }\n\n// Implements reports whether a type implements a given interface.\n// See https://golang.org/pkg/go/types/#Implements.\nfunc (ExprType) Implements(typ string) bool { return boolResult }\n\n// Is reports whether a type is identical to a given type.\nfunc (ExprType) Is(typ string) bool { return boolResult }\n\n\n\nvar boolResult bool\n\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,53 @@ | ||
// +build generate | ||
|
||
package main | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
) | ||
|
||
func main() { | ||
// See #23. | ||
|
||
data, err := dirToBytes("../dsl/fluent") | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
f, err := os.Create("./dsl_sources.go") | ||
if err != nil { | ||
panic(err) | ||
} | ||
defer f.Close() | ||
|
||
fmt.Fprintf(f, `package dslgen | ||
var Fluent = []byte(%q) | ||
`, string(data)) | ||
} | ||
|
||
func dirToBytes(dir string) ([]byte, error) { | ||
files, err := ioutil.ReadDir(dir) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var buf bytes.Buffer | ||
for i, f := range files { | ||
data, err := ioutil.ReadFile(filepath.Join(dir, f.Name())) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if i != 0 { | ||
newline := bytes.IndexByte(data, '\n') | ||
data = data[newline:] | ||
} | ||
buf.Write(data) | ||
buf.WriteByte('\n') | ||
} | ||
return buf.Bytes(), nil | ||
} |
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,40 @@ | ||
package ruleguard | ||
|
||
import ( | ||
"go/ast" | ||
"go/importer" | ||
"go/parser" | ||
"go/token" | ||
"go/types" | ||
|
||
"github.com/quasilyte/go-ruleguard/dslgen" | ||
) | ||
|
||
type dslImporter struct { | ||
fallback types.Importer | ||
} | ||
|
||
func newDSLImporter() *dslImporter { | ||
return &dslImporter{fallback: importer.Default()} | ||
} | ||
|
||
func (i *dslImporter) Import(path string) (*types.Package, error) { | ||
switch path { | ||
case "github.com/quasilyte/go-ruleguard/dsl/fluent": | ||
return i.importDSL(path, dslgen.Fluent) | ||
|
||
default: | ||
return i.fallback.Import(path) | ||
} | ||
} | ||
|
||
func (i *dslImporter) importDSL(path string, src []byte) (*types.Package, error) { | ||
fset := token.NewFileSet() | ||
f, err := parser.ParseFile(fset, "dsl.go", src, 0) | ||
if err != nil { | ||
return nil, err | ||
} | ||
var typecheker types.Config | ||
var info types.Info | ||
return typecheker.Check(path, fset, []*ast.File{f}, &info) | ||
} |
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