luci: Index | Files

package interpreter

import ""

Package interpreter contains Starlark interpreter.

It supports loading Starlark programs that consist of many files that reference each other, thus allowing decomposing code into small logical chunks and enabling code reuse.

Modules and packages

Two main new concepts are modules and packages. A package is a collection of Starlark files living under the same root. A module is just one such Starlark file.

Modules within a single package can load each other (via 'load' statement) using their root-relative paths that start with "//". Modules are executed exactly once when they are loaded for the first time. All subsequent load("//module/path", ...) calls just reuse the cached dict of the executed module.

Packages also have identifiers, though they are local to the interpreter (e.g. not defined anywhere in the package itself). For that reason they are called "package aliases".

Modules from one package may load modules from another package by using the following syntax:

load("@<package alias>//<path within the package>", ...)

Presently the mapping between a package alias (e.g. 'stdlib') and package's source code (a collection of *.star files under a single root) is static and supplied by Go code that uses the interpreter. This may change in the future to allow loading packages dynamically, e.g. over the network.

Special packages

There are two special package aliases recognized natively by the interpreter: '__main__' and 'stdlib'.

'__main__' is a conventional name of the package with top level user-supplied code. When printing module paths in stack traces and error message, "@__main__//<path>" are shown as simply "//<path>" to avoid confusing users who don't know what "@<alias>//" might mean. There's no other special handling.

Module '@stdlib//' (if present) is loaded before any other code. All its exported symbols that do not start with '_' are made available in the global namespace of all other modules (except ones loaded by '@stdlib//' itself). This allows to implement in Starlark built-in global functions exposed by the interpreter.

Built-in symbols

Embedders of the interpreter can also supply arbitrary "predeclared" symbols they want to be available in the global scope of all loaded modules.


Package Files

interpreter.go loaders.go


const (
    // MainPkg is an alias of the package with user-supplied code.
    MainPkg = "__main__"
    // StdlibPkg is an alias of the package with the standard library.
    StdlibPkg = "stdlib"


var (
    // ErrNoModule is returned by loaders when they can't find a source code of
    // the requested module. It is also returned by LoadModule when it can't find
    // a module within an existing package.
    ErrNoModule = errors.New("no such module")

    // ErrNoPackage is returned by LoadModule when it can't find a package.
    ErrNoPackage = errors.New("no such package")

func Context Uses

func Context(th *starlark.Thread) context.Context

Context returns a context of the thread created through Interpreter.

Panics if the Starlark thread wasn't created through Interpreter.Thread().

type Interpreter Uses

type Interpreter struct {
    // Predeclared is a dict with predeclared symbols that are available globally.
    // They are available when loading stdlib and when executing user modules. Can
    // be used to extend the interpreter with native Go functions.
    Predeclared starlark.StringDict

    // Packages is a mapping from a package alias to a loader with package code.
    // Users of Interpreter are expected to supply a loader for at least __main__
    // package.
    Packages map[string]Loader

    // Logger is called by Starlark's print(...) function.
    // The callback takes the position in the starlark source code where
    // print(...) was called and the message it received.
    // The default implementation just prints the message to stderr.
    Logger func(file string, line int, message string)

    // ThreadModifier is called whenever interpreter makes a new starlark.Thread.
    // It can inject additional state into thread locals. Useful when hooking up
    // a thread to starlarktest's reporter in unit tests.
    ThreadModifier func(th *starlark.Thread)
    // contains filtered or unexported fields

Interpreter knows how to load starlark modules that can load other starlark modules.

func (*Interpreter) Init Uses

func (intr *Interpreter) Init(ctx context.Context) error

Init initializes the interpreter and loads '@stdlib//'.

Registers most basic built-in symbols first (like 'struct' and 'fail'), then whatever was passed via Predeclared. Then loads '@stdlib//', which may define more symbols or override already defined ones. Whatever symbols not starting with '_' end up in the global dict of '@stdlib//' module will become available as global symbols in all modules.

The context ends up available to builtins through Context(...).

func (*Interpreter) LoadModule Uses

func (intr *Interpreter) LoadModule(ctx context.Context, pkg, path string) (starlark.StringDict, error)

LoadModule finds and executes a starlark module, returning its dict.

'pkg' is a package alias, it will be used to lookup the package loader in intr.Packages. 'path' is a module path (without leading '//') within the package.

The context ends up available to builtins through Context(...).

Caches the result of the execution. Modules are always loaded only once.

func (*Interpreter) Thread Uses

func (intr *Interpreter) Thread(ctx context.Context) *starlark.Thread

Thread creates a new Starlark thread associated with the given context.

Thread() can be used, for example, to invoke callbacks registered by the loaded Starlark code.

The context ends up available to builtins through Context(...).

The returned thread has no implementation of load(...). Use LoadModule to load top-level Starlark code instead. Note that load(...) statements are forbidden inside Starlark functions anyway.

type Loader Uses

type Loader func(path string) (dict starlark.StringDict, src string, err error)

Loader knows how to load modules of some concrete package.

It takes a module path relative to the package and returns either modules's dict (e.g. for go native modules) or module's source code, to be interpreted.

Returns ErrNoModule if there's no such module in the package.

The source code is returned as 'string' to guarantee immutability and allowing efficient use of string Go constants.

func FileSystemLoader Uses

func FileSystemLoader(root string) Loader

FileSystemLoader returns a loader that loads files from the file system.

func MemoryLoader Uses

func MemoryLoader(files map[string]string) Loader

MemoryLoader returns a loader that loads files from the given map.

Useful together with 'assets' package to embed Starlark code into the interpreter binary.

func ProtoLoader Uses

func ProtoLoader(modules map[string]string) Loader

ProtoLoader returns a loader that is capable of loading protobuf modules.

Takes a mapping from a starlark module name to a corresponding *.proto file, as registered in the process's protobuf registry (look for proto.RegisterFile(...) calls in *.pb.go).

For example, passing {"service/api.proto": ""} and using the resulting loader as @proto package, would allow to load API protos via load("@proto//service/api.proto", ...).

This decouples observable Starlark proto module layout from a layout of Go packages in the interpreter.

If a requested module is not found in 'modules', returns ErrNoModule. Thus 'modules' also acts as a whitelist of what proto packages can be accessed from Starlark.

On success the returned dict has a single struct named after the proto package. It has all message constructors defined inside. See 'starlarkproto' package for more info.

Package interpreter imports 10 packages (graph) and is imported by 2 packages. Updated 2018-12-14. Refresh now. Tools for package owners.