package eval
import (
)
var (
ErrArgs = errors.New("args error")
ErrNoOptAccepted = errors.New("function does not accept any options")
)
type goFn struct {
name string
impl interface{}
frame bool
rawOptions bool
options reflect.Type
inputs bool
normalArgs []reflect.Type
variadicArg reflect.Type
}
type optionsPtr interface {
SetDefaultOptions()
}
type Inputs func(func(interface{}))
var (
frameType = reflect.TypeOf((*Frame)(nil))
rawOptionsType = reflect.TypeOf(RawOptions(nil))
optionsPtrType = reflect.TypeOf((*optionsPtr)(nil)).Elem()
inputsType = reflect.TypeOf(Inputs(nil))
)
func ( string, interface{}) Callable {
:= reflect.TypeOf()
:= &goFn{name: , impl: }
:= 0
if < .NumIn() && .In() == frameType {
.frame = true
++
}
if < .NumIn() && .In() == rawOptionsType {
.rawOptions = true
++
}
if < .NumIn() && reflect.PtrTo(.In()).Implements(optionsPtrType) {
if .rawOptions {
panic("Function declares both RawOptions and Options parameters")
}
.options = .In()
++
}
for ; < .NumIn(); ++ {
:= .In()
if == .NumIn()-1 {
if .IsVariadic() {
.variadicArg = .Elem()
break
} else if == inputsType {
.inputs = true
break
}
}
.normalArgs = append(.normalArgs, )
}
return
}
func (*goFn) () string {
return "fn"
}
func ( *goFn) ( interface{}) bool {
return ==
}
func ( *goFn) () uint32 {
return hash.Pointer(unsafe.Pointer())
}
func ( *goFn) (int) string {
return "<builtin " + .name + ">"
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
var errNoOptions = errors.New("function does not accept any options")
func ( *goFn) ( *Frame, []interface{}, map[string]interface{}) error {
if .variadicArg != nil {
if len() < len(.normalArgs) {
return errs.ArityMismatch{
What: "arguments here",
ValidLow: len(.normalArgs), ValidHigh: -1, Actual: len()}
}
} else if .inputs {
if len() != len(.normalArgs) && len() != len(.normalArgs)+1 {
return errs.ArityMismatch{
What: "arguments here",
ValidLow: len(.normalArgs), ValidHigh: len(.normalArgs) + 1, Actual: len()}
}
} else if len() != len(.normalArgs) {
return errs.ArityMismatch{
What: "arguments here",
ValidLow: len(.normalArgs), ValidHigh: len(.normalArgs), Actual: len()}
}
if !.rawOptions && .options == nil && len() > 0 {
return ErrNoOptAccepted
}
var []reflect.Value
if .frame {
= append(, reflect.ValueOf())
}
if .rawOptions {
= append(, reflect.ValueOf())
}
if .options != nil {
:= reflect.New(.options)
:= .Interface()
.(optionsPtr).SetDefaultOptions()
:= scanOptions(, )
if != nil {
return
}
= append(, .Elem())
}
for , := range {
var reflect.Type
if < len(.normalArgs) {
= .normalArgs[]
} else if .variadicArg != nil {
= .variadicArg
} else if .inputs {
break
} else {
panic("impossible")
}
:= reflect.New()
:= vals.ScanToGo(, .Interface())
if != nil {
return fmt.Errorf("wrong type of argument %d: %v", , )
}
= append(, .Elem())
}
if .inputs {
var Inputs
if len() == len(.normalArgs) {
= .IterateInputs
} else {
:= [len()-1]
if !vals.CanIterate() {
return fmt.Errorf("%s cannot be iterated", vals.Kind())
}
= func( func(interface{})) {
_ = vals.Iterate(, func( interface{}) bool {
()
return true
})
}
}
= append(, reflect.ValueOf())
}
:= reflect.ValueOf(.impl).Call()
if len() > 0 && [len()-1].Type() == errorType {
:= [len()-1].Interface()
if != nil {
return .(error)
}
= [:len()-1]
}
for , := range {
.OutputChan() <- vals.FromGo(.Interface())
}
return nil
}