diff options
author | Alessandro Arzilli <alessandro.arzilli@gmail.com> | 2018-12-05 15:04:35 +0100 |
---|---|---|
committer | alandonovan <adonovan@google.com> | 2018-12-05 09:04:35 -0500 |
commit | 3b628ff4e934b8e3a290c981c3d2fea5a8e18c5d (patch) | |
tree | d0c18e952e7d852c931bb774e56ae9225b21204c | |
parent | 5c7d5aa7ed56b35691775864b8a5e97329a916e5 (diff) | |
download | starlark-go-3b628ff4e934b8e3a290c981c3d2fea5a8e18c5d.tar.gz |
Support doc strings (#37)
If the first statement of the body of a function is a string its value
will be returned when calling the Doc() method of starlark.(*Function).
Implements #35
-rw-r--r-- | internal/compile/compile.go | 20 | ||||
-rw-r--r-- | internal/compile/serial.go | 3 | ||||
-rw-r--r-- | starlark/eval_test.go | 12 | ||||
-rw-r--r-- | starlark/value.go | 1 |
4 files changed, 36 insertions, 0 deletions
diff --git a/internal/compile/compile.go b/internal/compile/compile.go index c30807b..4adff67 100644 --- a/internal/compile/compile.go +++ b/internal/compile/compile.go @@ -300,6 +300,7 @@ type Funcode struct { Prog *Program Pos syntax.Position // position of def or lambda token Name string // name of this function + Doc string // docstring of this function Code []byte // the byte code pclinetab []uint16 // mapping from pc to linenum Locals []Ident // for error messages and tracing @@ -439,6 +440,7 @@ func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.St Prog: pcomp.prog, Pos: pos, Name: name, + Doc: docStringFromBody(stmts), Locals: idents(locals), Freevars: idents(freevars), }, @@ -596,6 +598,24 @@ func (pcomp *pcomp) function(name string, pos syntax.Position, stmts []syntax.St return fn } +func docStringFromBody(body []syntax.Stmt) string { + if len(body) == 0 { + return "" + } + expr, ok := body[0].(*syntax.ExprStmt) + if !ok { + return "" + } + lit, ok := expr.X.(*syntax.Literal) + if !ok { + return "" + } + if lit.Token != syntax.STRING { + return "" + } + return lit.Value.(string) +} + func (insn *insn) stackeffect() int { se := int(stackEffect[insn.op]) if se == variableStackEffect { diff --git a/internal/compile/serial.go b/internal/compile/serial.go index 3a3fe60..f6cf807 100644 --- a/internal/compile/serial.go +++ b/internal/compile/serial.go @@ -175,6 +175,7 @@ func (e *encoder) idents(ids []Ident) { func (e *encoder) function(fn *Funcode) { e.ident(Ident{fn.Name, fn.Pos}) + e.string(fn.Doc) e.bytes(fn.Code) e.int(len(fn.pclinetab)) for _, x := range fn.pclinetab { @@ -339,6 +340,7 @@ func (d *decoder) bool() bool { return d.int() != 0 } func (d *decoder) function() *Funcode { id := d.ident() + doc := d.string() code := d.bytes() pclinetab := make([]uint16, d.int()) for i := range pclinetab { @@ -354,6 +356,7 @@ func (d *decoder) function() *Funcode { // Prog is filled in later. Pos: id.Pos, Name: id.Name, + Doc: doc, Code: code, pclinetab: pclinetab, Locals: locals, diff --git a/starlark/eval_test.go b/starlark/eval_test.go index cfbb92d..2d8519c 100644 --- a/starlark/eval_test.go +++ b/starlark/eval_test.go @@ -461,3 +461,15 @@ func TestUnpackUserDefined(t *testing.T) { t.Errorf("unpack args error = %q, want %q", err, want) } } + +func TestDocstring(t *testing.T) { + globals, _ := starlark.ExecFile(&starlark.Thread{}, "doc.star", ` +def somefunc(): + "somefunc doc" + return 0 +`, nil) + + if globals["somefunc"].(*starlark.Function).Doc() != "somefunc doc" { + t.Fatal("docstring not found") + } +} diff --git a/starlark/value.go b/starlark/value.go index 9653e73..002651a 100644 --- a/starlark/value.go +++ b/starlark/value.go @@ -527,6 +527,7 @@ type Function struct { } func (fn *Function) Name() string { return fn.funcode.Name } // "lambda" for anonymous functions +func (fn *Function) Doc() string { return fn.funcode.Doc } func (fn *Function) Hash() (uint32, error) { return hashString(fn.funcode.Name), nil } func (fn *Function) Freeze() { fn.defaults.Freeze(); fn.freevars.Freeze() } func (fn *Function) String() string { return toString(fn) } |