woodpecker/vendor/github.com/quasilyte/go-ruleguard/ruleguard/libdsl.go
Lukas c28f7cb29f
Add golangci-lint (#502)
Initial part of #435
2021-11-14 21:01:54 +01:00

276 lines
8 KiB
Go

package ruleguard
import (
"go/types"
"github.com/quasilyte/go-ruleguard/internal/xtypes"
"github.com/quasilyte/go-ruleguard/ruleguard/quasigo"
)
// This file implements `dsl/*` packages as native functions in quasigo.
//
// Every function and method defined in any `dsl/*` package should have
// associated Go function that implements it.
//
// In quasigo, it's impossible to have a pointer to an interface and
// non-pointer struct type. All interface type methods have FQN without `*` prefix
// while all struct type methods always begin with `*`.
//
// Fields are readonly.
// Field access is compiled into a method call that have a name identical to the field.
// For example, `foo.Bar` field access will be compiled as `foo.Bar()`.
// This may change in the future; benchmarks are needed to figure out
// what is more efficient: reflect-based field access or a function call.
//
// To keep this code organized, every type and package functions are represented
// as structs with methods. Then we bind a method value to quasigo symbol.
// The naming scheme is `dsl{$name}Package` for packages and `dsl{$pkg}{$name}` for types.
func initEnv(state *engineState, env *quasigo.Env) {
nativeTypes := map[string]quasigoNative{
`*github.com/quasilyte/go-ruleguard/dsl.VarFilterContext`: dslVarFilterContext{state: state},
`github.com/quasilyte/go-ruleguard/dsl/types.Type`: dslTypesType{},
`*github.com/quasilyte/go-ruleguard/dsl/types.Interface`: dslTypesInterface{},
`*github.com/quasilyte/go-ruleguard/dsl/types.Pointer`: dslTypesPointer{},
`*github.com/quasilyte/go-ruleguard/dsl/types.Array`: dslTypesArray{},
`*github.com/quasilyte/go-ruleguard/dsl/types.Slice`: dslTypesSlice{},
}
for qualifier, typ := range nativeTypes {
for methodName, fn := range typ.funcs() {
env.AddNativeMethod(qualifier, methodName, fn)
}
}
nativePackages := map[string]quasigoNative{
`github.com/quasilyte/go-ruleguard/dsl/types`: dslTypesPackage{},
}
for qualifier, pkg := range nativePackages {
for funcName, fn := range pkg.funcs() {
env.AddNativeMethod(qualifier, funcName, fn)
}
}
}
type quasigoNative interface {
funcs() map[string]func(*quasigo.ValueStack)
}
type dslTypesType struct{}
func (native dslTypesType) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Underlying": native.Underlying,
"String": native.String,
}
}
func (dslTypesType) Underlying(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(types.Type).Underlying())
}
func (dslTypesType) String(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(types.Type).String())
}
type dslTypesInterface struct{}
func (native dslTypesInterface) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Underlying": native.Underlying,
"String": native.String,
}
}
func (dslTypesInterface) Underlying(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Interface).Underlying())
}
func (dslTypesInterface) String(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Interface).String())
}
type dslTypesSlice struct{}
func (native dslTypesSlice) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Underlying": native.Underlying,
"String": native.String,
"Elem": native.Elem,
}
}
func (dslTypesSlice) Underlying(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Slice).Underlying())
}
func (dslTypesSlice) String(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Slice).String())
}
func (dslTypesSlice) Elem(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Slice).Elem())
}
type dslTypesArray struct{}
func (native dslTypesArray) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Underlying": native.Underlying,
"String": native.String,
"Elem": native.Elem,
"Len": native.Len,
}
}
func (dslTypesArray) Underlying(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Array).Underlying())
}
func (dslTypesArray) String(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Array).String())
}
func (dslTypesArray) Elem(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Array).Elem())
}
func (dslTypesArray) Len(stack *quasigo.ValueStack) {
stack.PushInt(int(stack.Pop().(*types.Array).Len()))
}
type dslTypesPointer struct{}
func (native dslTypesPointer) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Underlying": native.Underlying,
"String": native.String,
"Elem": native.Elem,
}
}
func (dslTypesPointer) Underlying(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Pointer).Underlying())
}
func (dslTypesPointer) String(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Pointer).String())
}
func (dslTypesPointer) Elem(stack *quasigo.ValueStack) {
stack.Push(stack.Pop().(*types.Pointer).Elem())
}
type dslTypesPackage struct{}
func (native dslTypesPackage) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Implements": native.Implements,
"Identical": native.Identical,
"NewArray": native.NewArray,
"NewSlice": native.NewSlice,
"NewPointer": native.NewPointer,
"AsArray": native.AsArray,
"AsSlice": native.AsSlice,
"AsPointer": native.AsPointer,
"AsInterface": native.AsInterface,
}
}
func (dslTypesPackage) Implements(stack *quasigo.ValueStack) {
iface := stack.Pop().(*types.Interface)
typ := stack.Pop().(types.Type)
stack.Push(xtypes.Implements(typ, iface))
}
func (dslTypesPackage) Identical(stack *quasigo.ValueStack) {
y := stack.Pop().(types.Type)
x := stack.Pop().(types.Type)
stack.Push(xtypes.Identical(x, y))
}
func (dslTypesPackage) NewArray(stack *quasigo.ValueStack) {
length := stack.PopInt()
typ := stack.Pop().(types.Type)
stack.Push(types.NewArray(typ, int64(length)))
}
func (dslTypesPackage) NewSlice(stack *quasigo.ValueStack) {
typ := stack.Pop().(types.Type)
stack.Push(types.NewSlice(typ))
}
func (dslTypesPackage) NewPointer(stack *quasigo.ValueStack) {
typ := stack.Pop().(types.Type)
stack.Push(types.NewPointer(typ))
}
func (dslTypesPackage) AsArray(stack *quasigo.ValueStack) {
typ, _ := stack.Pop().(types.Type).(*types.Array)
stack.Push(typ)
}
func (dslTypesPackage) AsSlice(stack *quasigo.ValueStack) {
typ, _ := stack.Pop().(types.Type).(*types.Slice)
stack.Push(typ)
}
func (dslTypesPackage) AsPointer(stack *quasigo.ValueStack) {
typ, _ := stack.Pop().(types.Type).(*types.Pointer)
stack.Push(typ)
}
func (dslTypesPackage) AsInterface(stack *quasigo.ValueStack) {
typ, _ := stack.Pop().(types.Type).(*types.Interface)
stack.Push(typ)
}
type dslVarFilterContext struct {
state *engineState
}
func (native dslVarFilterContext) funcs() map[string]func(*quasigo.ValueStack) {
return map[string]func(*quasigo.ValueStack){
"Type": native.Type,
"SizeOf": native.SizeOf,
"GetType": native.GetType,
"GetInterface": native.GetInterface,
}
}
func (dslVarFilterContext) Type(stack *quasigo.ValueStack) {
params := stack.Pop().(*filterParams)
typ := params.typeofNode(params.subExpr(params.varname))
stack.Push(typ)
}
func (native dslVarFilterContext) SizeOf(stack *quasigo.ValueStack) {
typ := stack.Pop().(types.Type)
params := stack.Pop().(*filterParams)
stack.PushInt(int(params.ctx.Sizes.Sizeof(typ)))
}
func (native dslVarFilterContext) GetType(stack *quasigo.ValueStack) {
fqn := stack.Pop().(string)
params := stack.Pop().(*filterParams)
typ, err := native.state.FindType(params.importer, params.ctx.Pkg, fqn)
if err != nil {
panic(err)
}
stack.Push(typ)
}
func (native dslVarFilterContext) GetInterface(stack *quasigo.ValueStack) {
fqn := stack.Pop().(string)
params := stack.Pop().(*filterParams)
typ, err := native.state.FindType(params.importer, params.ctx.Pkg, fqn)
if err != nil {
panic(err)
}
if ifaceType, ok := typ.Underlying().(*types.Interface); ok {
stack.Push(ifaceType)
return
}
stack.Push((*types.Interface)(nil)) // Not found or not an interface
}