From 8717f1ef4b794b7bc9063d22882edf851e922eb0 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 19 Mar 2019 12:25:04 +0100 Subject: [PATCH] fix: correct append with variadic parameters and spread array (#124) * fix: correct append with variadic parameters and spread array * feat: add print builtin --- _test/print0.go | 8 ++++++ interp/cfg.go | 8 ++++++ interp/interp.go | 1 + interp/interp_eval_test.go | 9 ++++++ interp/interp_test.go | 19 ++++++++++++ interp/run.go | 59 ++++++++++++++++++++++++++++++++++---- 6 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 _test/print0.go diff --git a/_test/print0.go b/_test/print0.go new file mode 100644 index 00000000..43cdcf19 --- /dev/null +++ b/_test/print0.go @@ -0,0 +1,8 @@ +package main + +func main() { + print("hello") +} + +// Output: +// hello diff --git a/interp/cfg.go b/interp/cfg.go index 02502556..bf5e972b 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -94,6 +94,8 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { v.findex = vindex } } + n.findex = -1 + n.val = nil scope = scope.pushBloc() case CaseClause: @@ -532,6 +534,9 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { if n.typ = scope.getType(n.child[1].ident); n.typ == nil { n.typ, err = nodeType(interp, scope, n.child[1]) } + if c2 := n.child[2]; len(n.child) == 3 && c2.typ.cat == ArrayT && c2.typ.val.id() == n.typ.val.id() { + n.gen = appendSlice + } case "cap", "copy", "len": n.typ = scope.getType("int") case "make": @@ -548,6 +553,9 @@ func (interp *Interpreter) Cfg(root *Node) ([]*Node, error) { } if n.typ != nil { n.findex = scope.add(n.typ) + } else { + n.findex = -1 + n.val = nil } case n.child[0].isType(scope): // Type conversion expression diff --git a/interp/interp.go b/interp/interp.go index 4527e301..a991252a 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -160,6 +160,7 @@ func initUniverse() *Scope { "make": &Symbol{kind: Bltn, builtin: _make}, "new": &Symbol{kind: Bltn, builtin: _new}, "panic": &Symbol{kind: Bltn, builtin: _panic}, + "print": &Symbol{kind: Bltn, builtin: _print}, "println": &Symbol{kind: Bltn, builtin: _println}, "recover": &Symbol{kind: Bltn, builtin: _recover}, // TODO: complex, copy, delete, imag, new, print, real diff --git a/interp/interp_eval_test.go b/interp/interp_eval_test.go index 6de7523c..24c672ef 100644 --- a/interp/interp_eval_test.go +++ b/interp/interp_eval_test.go @@ -55,6 +55,15 @@ func TestEvalAssign(t *testing.T) { }) } +func TestEvalBuiltin(t *testing.T) { + i := interp.New(interp.Opt{}) + runTests(t, i, []testCase{ + {src: `a := []int{}; a = append(a, 1); a`, res: "[1]"}, + {src: `a := []int{1}; a = append(a, 2, 3); a`, res: "[1 2 3]"}, + {src: `a := []int{1}; b := []int{2, 3}; a = append(a, b...); a`, res: "[1 2 3]"}, + }) +} + func TestEvalDecl(t *testing.T) { i := interp.New(interp.Opt{}) runTests(t, i, []testCase{ diff --git a/interp/interp_test.go b/interp/interp_test.go index aee33cf9..aa875415 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -4710,6 +4710,25 @@ func main() { // true } +func Example_print0() { + src := ` +package main + +func main() { + print("hello") +} +` + i := interp.New(interp.Opt{Entry: "main"}) + i.Use(stdlib.Value) + _, err := i.Eval(src) + if err != nil { + panic(err) + } + + // Output: + // hello +} + func Example_ptr0() { src := ` package main diff --git a/interp/run.go b/interp/run.go index fffc79f9..346cf3bf 100644 --- a/interp/run.go +++ b/interp/run.go @@ -320,6 +320,25 @@ func deref(n *Node) { } } +func _print(n *Node) { + child := n.child[1:] + next := getExec(n.tnext) + values := make([]func(*Frame) reflect.Value, len(child)) + for i, c := range child { + values[i] = genValue(c) + } + + n.exec = func(f *Frame) Builtin { + for i, value := range values { + if i > 0 { + fmt.Printf(" ") + } + fmt.Printf("%v", value(f)) + } + return next + } +} + func _println(n *Node) { child := n.child[1:] next := getExec(n.tnext) @@ -1276,19 +1295,49 @@ func _case(n *Node) { } } -// TODO: handle variable number of arguments to append -func _append(n *Node) { +func appendSlice(n *Node) { i := n.findex - value0 := genValue(n.child[1]) - value1 := genValue(n.child[2]) + value := genValue(n.child[1]) next := getExec(n.tnext) + value0 := genValue(n.child[2]) n.exec = func(f *Frame) Builtin { - f.data[i] = reflect.Append(value0(f), value1(f)) + f.data[i] = reflect.AppendSlice(value(f), value0(f)) return next } } +func _append(n *Node) { + i := n.findex + value := genValue(n.child[1]) + next := getExec(n.tnext) + + if len(n.child) > 3 { + args := n.child[2:] + l := len(args) + values := make([]func(*Frame) reflect.Value, l) + for i, arg := range args { + values[i] = genValue(arg) + } + + n.exec = func(f *Frame) Builtin { + sl := make([]reflect.Value, l) + for i, v := range values { + sl[i] = v(f) + } + f.data[i] = reflect.Append(value(f), sl...) + return next + } + } else { + value0 := genValue(n.child[2]) + + n.exec = func(f *Frame) Builtin { + f.data[i] = reflect.Append(value(f), value0(f)) + return next + } + } +} + func _cap(n *Node) { i := n.findex value := genValue(n.child[1])