mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-11 02:56:33 +00:00
277 lines
8 KiB
Go
277 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
|
||
|
}
|