diff options
Diffstat (limited to 'vm0/func.go')
| -rw-r--r-- | vm0/func.go | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/vm0/func.go b/vm0/func.go new file mode 100644 index 0000000..6c95383 --- /dev/null +++ b/vm0/func.go @@ -0,0 +1,73 @@ +package vm0 + +import ( + "reflect" + "strings" + + "github.com/gnolang/parscan/parser" +) + +var types = map[string]reflect.Type{ + "int": reflect.TypeOf(0), + "string": reflect.TypeOf(""), +} + +func (i *Interp) callFunc(n *parser.Node) { + fp := i.fp + l := len(i.stack) + nargs := i.stack[l-1].(int) + args := make([]reflect.Value, nargs) + for j := range args { + args[nargs-j-1] = reflect.ValueOf(i.stack[l-2-j]) + } + f := reflect.ValueOf(i.stack[l-2-nargs]) + out := f.Call(args) + i.fp = fp + i.stack = i.stack[:l-2-nargs] + for _, v := range out { + i.push(v.Interface()) + } +} + +func (i *Interp) declareFunc(r *parser.Node, scope string) { + fname := r.Child[0].Content() + + // Add symbols for input and output function arguments. + inArgs := r.Child[1].Child + fscope := strings.TrimPrefix(scope+"/"+fname+"/", "/") + in := make([]reflect.Type, len(inArgs)) + for j, c := range inArgs { + i.sym[fscope+c.Content()] = j + in[j] = types[c.Child[0].Content()] + } + var out []reflect.Type + if len(r.Child) > 3 { // function has return values + if i.IsBlock(r.Child[2]) { + outArgs := r.Child[2].Child + out = make([]reflect.Type, len(outArgs)) + for j, c := range outArgs { + out[j] = types[c.Content()] + } + } else { + out = []reflect.Type{types[r.Child[2].Content()]} + } + } + funT := reflect.FuncOf(in, out, false) + + // Generate a wrapper function which will run function body AST. + f := reflect.MakeFunc(funT, func(args []reflect.Value) (res []reflect.Value) { + i.fp = len(i.stack) // fp will be restored by caller (callFunc). + for _, arg := range args { + i.push(arg.Interface()) + } + i.Run(r.Child[len(r.Child)-1], fscope) + b := len(i.stack) - len(out) + for j := range out { + res = append(res, reflect.ValueOf(i.stack[b+j])) + } + return res + }) + + // Add a symbol for newly created func. + i.sym[scope+fname] = i.push(f.Interface()) - i.fp +} |
