Starlark in Go: the Starlark configuration language, implemented in Go

Starlark in Go

Travis CI GoDoc

This is the home of the Starlark in Go project. Starlark in Go is an interpreter for Starlark, implemented in Go. Starlark was formerly known as Skylark. The new import path for Go packages is "go.starlark.net/starlark".

Starlark is a dialect of Python intended for use as a configuration language. Like Python, it is an untyped dynamic language with high-level data types, first-class functions with lexical scope, and garbage collection. Unlike CPython, independent Starlark threads execute in parallel, so Starlark workloads scale well on parallel machines. Starlark is a small and simple language with a familiar and highly readable syntax. You can use it as an expressive notation for structured data, defining functions to eliminate repetition, or you can use it to add scripting capabilities to an existing application.

A Starlark interpreter is typically embedded within a larger application, and the application may define additional domain-specific functions and data types beyond those provided by the core language. For example, Starlark was originally developed for the Bazel build tool. Bazel uses Starlark as the notation both for its BUILD files (like Makefiles, these declare the executables, libraries, and tests in a directory) and for its macro language, through which Bazel is extended with custom logic to support new languages and compilers.

Documentation

Getting started

Build the code:

# check out the code and dependencies,
# and install interpreter in $GOPATH/bin
$ go get -u go.starlark.net/cmd/starlark

Run the interpreter:

$ cat coins.star
coins = {
  'dime': 10,
  'nickel': 5,
  'penny': 1,
  'quarter': 25,
}
print('By name:\t' + ', '.join(sorted(coins.keys())))
print('By value:\t' + ', '.join(sorted(coins.keys(), key=coins.get)))

$ starlark coins.star
By name:	dime, nickel, penny, quarter
By value:	penny, nickel, dime, quarter

Interact with the read-eval-print loop (REPL):

$ starlark
>>> def fibonacci(n):
...    res = list(range(n))
...    for i in res[2:]:
...        res[i] = res[i-2] + res[i-1]
...    return res
...
>>> fibonacci(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>>

When you have finished, type Ctrl-D to close the REPL's input stream.

Embed the interpreter in your Go program:

import "go.starlark.net/starlark"

// Execute Starlark program in a file.
thread := &starlark.Thread{Name: "my thread"}
globals, err := starlark.ExecFile(thread, "fibonacci.star", nil, nil)
if err != nil { ... }

// Retrieve a module global.
fibonacci := globals["fibonacci"]

// Call Starlark function from Go.
v, err := starlark.Call(thread, fibonacci, starlark.Tuple{starlark.MakeInt(10)}, nil)
if err != nil { ... }
fmt.Printf("fibonacci(10) = %v\n", v) // fibonacci(10) = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

See starlark/example_test.go for more examples.

Contributing

We welcome submissions but please let us know what you're working on if you want to change or add to the Starlark repository.

Before undertaking to write something new for the Starlark project, please file an issue or claim an existing issue. All significant changes to the language or to the interpreter's Go API must be discussed before they can be accepted. This gives all participants a chance to validate the design and to avoid duplication of effort.

Despite some differences, the Go implementation of Starlark strives to match the behavior of the Java implementation used by Bazel and maintained by the Bazel team. For that reason, proposals to change the language itself should generally be directed to the Starlark site, not to the maintainers of this project. Only once there is consensus that a language change is desirable may its Go implementation proceed.

We use GitHub pull requests for contributions.

Please complete Google's contributor license agreement (CLA) before sending your first change to the project. If you are the copyright holder, you will need to agree to the individual contributor license agreement, which can be completed online. If your organization is the copyright holder, the organization will need to agree to the corporate contributor license agreement. If the copyright holder for your contribution has already completed the agreement in connection with another Google open source project, it does not need to be completed again.

Stability

We reserve the right to make breaking language and API changes at this stage in the project, although we will endeavor to keep them to a minimum. Once the Bazel team has finalized the version 1 language specification, we will be more rigorous with interface stability.

Credits

Starlark was designed and implemented in Java by Ulf Adams, Lukács Berki, Jon Brandvein, John Field, Laurent Le Brun, Dmitry Lomov, Damien Martin-Guillerez, Vladimir Moskva, and Florian Weikert, standing on the shoulders of the Python community. The Go implementation was written by Alan Donovan and Jay Conrod; its scanner was derived from one written by Russ Cox.

Legal

Starlark in Go is Copyright (c) 2018 The Bazel Authors. All rights reserved.

It is provided under a 3-clause BSD license: LICENSE.

Starlark in Go is not an official Google product.

Owner
Google
Google ❤️ Open Source
Google
Comments
  • time: add time module

    time: add time module

    Signed-off-by: b5 [email protected]

    A few notes:

    • I've added this to lib/time based on @alandonovan's feedback from #326
    • we're waiting on a chat with @srebhan about the naming of the constructors vs. parsing functions before this is final
    • We use a tool to extract documentation from this package in doc.go into other formats. I can remove this to conform to other packages, but if this info can stay & be maintained, I'd be deeply appreciated. Keeping documentation to the code itself has made our lives much easier.
    • If we merge this I'll take this back to our contributors on the starlib project & chat about relying on this package upstream. @alandonovan in the past you'd mentioned interest in other packages from the project, now might be the time to go shopping 😉
  • feat: introduce regexp package

    feat: introduce regexp package

    @essobedo is going to be heading up turning this code into a package that closes #241. We're using the re package from starlib as a starting point, but it needs a lot of work before it's ready for initial review.

    @essobedo I think at a minimum we should:

    • [x] switch the defined here to match the API defined in #241
    • [x] remove regexp/doc.go (I've kept it only so you have context)
    • [x] document regexp/regexp.go
    • [x] completely re-write the test suite to test the new API
    • [x] add a test that confirms failure when attempting to compile a regular expression that that uses byte-ordered features: \C
  •  Specify starting line and column for expression parser ParseExpr

    Specify starting line and column for expression parser ParseExpr

    One of the file formats in the application that I am developing uses Starlark for writing expressions. The Starlark expressions are surrounded by source code written in another language.

    I want to specify a starting line number and column number when parsing expressions so that errors point back to the original source code.

    Here's a suggested function for the syntax package.

    // ParseExpr parses a Starlark expression in src. A comma-separated
    // list of expressions is parsed as a tuple. Positions in the resulting 
    // expression are based on pos.
    func ParseExprPosition(pos Position, src []byte, mode Mode) (expr Expr, err error)
    

    The proposed function does not have the usual filename, src pattern as in other functions in the syntax package because it's designed to work on a snippet from a larger file.

    My feature request is for a way to specify the starting line and column number for the scanner, not for the specific function shown above.

    My fallback plan is to rewrite positions in syntax.Error and starlark.EvalError using a source map that I maintain on the side. I can do that, but it seems that other users of Starlark expressions will have a similar requirement.

  • Proposal: add Context field to starlark.Thread

    Proposal: add Context field to starlark.Thread

    The repl program uses a "context" local variable suggesting that long-running operations should check this context and terminate early when the context expires. This solution will probably take care of 99% of use cases but won't stop the interpreter if the long-running operation is implemented in starlark itself.

    I propose that a Context field is added to starlark.Thread and that the interpreter loop checks it every N-th instruction and returns an appropriate error when starlark.Thread.Context expires.

  • a math library

    a math library

    Starlark seem mighty terrific. I just have a minor query about doing some math.

    In starlark-go, how would one raise n to the m-th power?

    In Go, I would call math.Pow(n, m). In Python, math.pow(n, m).

    Another way of asking: is there a way to get at the math library from Go perhaps?

  • Time and duration module

    Time and duration module

    This PR adds time and duration support to starlark and solves issue #19. The API is inspired by the discussion in above issue as well as the linked first implementation for skylark. However, we diverged on some points from the proposal (as well as from the python datetime API) to provide a more clean and consistent interface.

  • resolve: allow use of predeclared name prior to a global def (if AllowGlobalReassign)

    resolve: allow use of predeclared name prior to a global def (if AllowGlobalReassign)

    This change causes the AllowGlobalReassign flag (used for legacy Bazel semantics) to also allow use of predeclared names prior to a global binding of the same name, as in:

    print(len); len=1; print(len)

    This effectively reverses github.com/google/skylark/pull/123 behind an option.

    See github.com/google/skylark/issues/116 for discussion.

  • Requests a 'large

    Requests a 'large" amount of virtual memory addresses, which may fail on some operating systems.

    I am trying to use a piece of software that relies on starlark-go on a system that rigourously enforces ulimits (in particular on virtual memory). Which means that I have to patch out the the line 62 in int_posix64.go, which tries to allocate 4Gb of memory, which the machine does not possess.

    var smallints = reserveAddresses(1 << 32)
    
    func reserveAddresses(len int) uintptr {
    	b, err := unix.Mmap(-1, 0, len, unix.PROT_READ, unix.MAP_PRIVATE|unix.MAP_ANON)
    	if err != nil {
    		log.Fatalf("mmap: %v", err)
    	}
    	return uintptr(unsafe.Pointer(&b[0]))
    }
    

    Please, consider implementing proper memory management, instead of "just allocating 4Gb of RAM".

  • missing

    missing "keyword repeated" check for dict construction

    $ starlark -c "dict(S=5, S=5)"
    $ python -c "dict(S=5, S=5)"
      File "<string>", line 1
    SyntaxError: keyword argument repeated
    

    Found by go-fuzz.

  • Fatalf on darwin arm64 iOS

    Fatalf on darwin arm64 iOS

    root cause:

    https://github.com/google/starlark-go/blob/50ca820fafb940caeda09b96864b9215f8b84c04/starlark/int_posix64.go#L55-L57

    when targeting on darwin/arm64, it case mmap: cannot allocate memory

  • Is there any way to stop a running script with a timeout?

    Is there any way to stop a running script with a timeout?

    In my use case, I receive a function from the user. And I passthrough params and execute it. But I need a way to stop the function running with a timeout (e.g. 2000ms).

    can starlark-go provide a function like CallContext?

    thread := &starlark.Thread{
        Name:  "example",
    }
    
    globals, _ := starlark.ExecFile(thread, "test.star", f, nil)
    
    mainFn := globals["main"]
    dict := starlark.StringDict{
        "param": starlark.String("test"),
    }
    
    m := starlarkstruct.FromStringDict(starlarkstruct.Default, dict)
    arg := starlark.Tuple{m}
    
    ctx, cancel := context.WithTimeout(context.background(), time.Second)
    defer cancel()
    starlark.CallContext(ctx, thread, mainFn, arg, nil)
    
  • Walk syntax.DictEntry instead of ignoring it

    Walk syntax.DictEntry instead of ignoring it

    *syntax.DictExpr has a field List []Expr which is supposed to only contain *syntax.DictEntrys:

    https://github.com/google/starlark-go/blob/d7da88764354917a82dfa84a8ae1cb04f107ab78/syntax/syntax.go#L377

    However, when we are walking *syntax.DictExpr node in syntax.Walk function, we are ignoring *syntax.DictEntrys, directly unwrapping it, and then continuing the walk recursions. This means the caller will not be able to "see" a *syntax.DictEntry node when calling the walk function.

    This PR fixes this by directly walking on each element of the List field, which in turn will be automatically handled by the *syntax.DictEntry case in Walk.

  • FR: add Clone methods for mutable aggregate types

    FR: add Clone methods for mutable aggregate types

    For *List, *Dict, and *Set, it'd be nice to have convenience methods to shallow-copy them, so an application doesn't have to use an explicit loop or call the Slice method.

  • Made JSON encoder a public function

    Made JSON encoder a public function

    This one is pretty simple. I found myself starting to write a bunch of code to encode a Starlark value as JSON, when I realized that oh hey, there's a JSON encoder already in the project. It's just hidden.

  • Proposal: Add Function Type Annotation Syntax

    Proposal: Add Function Type Annotation Syntax

    I'd like to re-visit the proposal for python-like function type annotations in starlark, at least in the starlark-go implementation. This has been discussed before in:

    • https://groups.google.com/g/bazel-dev/c/Pk9VrPCqby0/m/zoOL1IkxEAAJ?pli=1
    • https://github.com/bazelbuild/starlark/issues/106
    • https://github.com/bazelbuild/buildtools/issues/900

    An example of what this looks like in practice:

    def func_one(a, b: str, c: list[int]) -> bool:
    	pass
    

    This proposal is only for function definition type hints. Other kinds (such as assignment annotations) could be discussed, but I believe function annotations provide the most value with least effort, and can be done without changing any runtime semantics. Function type annotation syntax has already been implemented in buildifier (https://github.com/bazelbuild/buildtools/pull/946) and starlark-rust (https://github.com/facebookexperimental/starlark-rust/blob/main/docs/types.md).

    The proposed syntax follows a subset of python type annotations, as well as the same syntax already supported by buildifier and starlark-rust. Type annotations are Test syntax elements, and are parsed as expressions.

    -DefStmt = 'def' identifier '(' [Parameters [',']] ')' ':' Suite .
    +DefStmt = 'def' identifier '(' [Parameters [',']] ')' ['->' Test] ':' Suite .
    
     Parameters = Parameter {',' Parameter}.
    
    -Parameter = identifier | identifier '=' Test | '*' | '*' identifier | '**' identifier .
    +Parameter = identifier [':' Test] | identifier [':' Test] '=' Test | '*' | '*' identifier [':' Test] | '**' identifier [':' Test] .
    

    Requirements

    • Support function definition type annotations in-line with existing starlark implementations and python syntax.
    • Does not change the compiled result of a program.
    • Maintain backwards compatibility with existing starlark code using the starlark-go interpeter and compiler.
    • Maintain backwards compatability with existing code using starlark-go to parse and compile starlark code.

    Why Now?

    • Other starlark implementations already have function type annotations, with the same syntax, and share the same syntax as python.
    • Python type hints (certainly function definition hints) have had quite a bit of time to mature.
    • I believe starlark is a great language for defining simple logic and configuration, but lack of tooling and IDE assistance around typing hampers useability, safety, and simplicity. Even in the context of bazel -- I know my experience would be greatly improved with IDE assisted type support and documentation.

    Choices

    Syntatic Element of a Type Annotation

    Test / Expr. This is the same element chosen by starlark-rust and buildifier, and is the closest analogue to python type hints which allows arbitrary expressions.

    Ident with TypeHint Field instead of TypedIdent

    The buildifier implementation parses a TypedIdent with an ident and type hint:

    type TypedIdent struct {
    	Comments
    	Ident   *Ident
    	Type    Expr
    }
    

    Whereas the proposed implementation for starlark-go reuses type Ident struct with a TypeHint Expr field:

    type Ident struct {
    	commentsRef
    	NamePos  Position
    	Name     string
    	TypeHint Expr // TypeHint can be nil
    
    	Binding interface{} // a *resolver.Binding, set by resolver
    }
    

    There are two reasons for this:

    • Maintain backwards compatibility with programs using the parser: parameters with type hints will still produce the same output type, and Go programs make heavy use of type switches for consuming the tree.
    • In writing code that consumes the type hints, I found the TypeHint field approach easier to use, as it requires fewer type switches and idents can be treated the same. Generally types are either extracted or an Any type is returned if TypeHint is nil.

    syntax.Walk Support

    This PR intentionally excludes syntax.Walk support for type hints, as it would change the behaviour for programs using starlark-go to parse starlark.

    On-the-fence Choices

    Syntax Feature Flag

    Whether or not to lock the syntax behind a flag. Unlike other features behind flags, this does not change the output of programs and does not have backwards compatibility implications.

    • This could potentially only be an issue if syntax.Walk is altered to recurse under type hints, as it would change the expected behaviour of programs calling it.
    • By keeping this on by default, it increases the likelihood programs will take advantage of type hints as it will at least always be valid in starlark-go.

    Resolving Type Annotation Identifiers

    The PR adds a ResolveTypeHintIdents flag in the resolve package, which defaults to false. When it is false, type hints cannot cause resolution/compilation failures.

    When it is true, type annotation identifiers are resolved and given binding information. If a type annotation refers to an unknown identifier, it could cause resolution to fail. Additionally, if a type hint in a nested function definition referred to an identifier from its parent scopes, it could cause local variables to be promoted to Cell. Because this can slightly change program behaviour, and cause compilation failures it is enabled behind a flag.

    I consider this fairly desirable because:

    • It follows python's behaviour with respect to resolving type annotation identifiers, and producing errors on resolution failure.
    • Tooling that consumes type hints will likely want to make sure type annotations refer to valid identifiers.
    • Tooling that consumes type hints might want scope/binding information for type identifiers. By re-using the existing resolve code this is readily available (otherwise the resolve logic would have to be heavily duplicated).

    Skip Type Hints for Assignment Syntax

    These are supported by starlark-rust, but not buildifier. Python PEP-526 formalizes this for python, however the only applicable syntax for starlark would be variable assignment and definition:

    x  # Binding failure
    x: int  # Works in python, binding failure in starlark
    y: str = "asdf" # Would work in starlark, but we could infer type anyways.
    

    Python changed its behaviour slightly to allow binding unknown variables if given a typehint. This would be a runtime behaviour change in starlark. The currently supported behaviour would require assignment anyways, where we can often infer the type anyways.

    While assignment annotations could provide some value, it's a lot less clear cut to me than function definition annotations. I'd like to table discussion of assignment type hints for a different proposal.

  • Mutable package-level vars are a poor choice for configuration

    Mutable package-level vars are a poor choice for configuration

    Hello there! I have a project where I get this library as a transitive dependency. It's used for "stuff X". I also want to use this library for "stuff Y", unrelated to "stuff X", in the same codebase/binary. I'd like to configure the library and modules differently for different use cases. But in a few places the library uses package-level variables for "global" configuration and I cannot do what I want.

    Examples:

    • https://github.com/google/starlark-go/blob/acb66ad56dd25d86c91a1efc3869d4a0ec0fcbdb/lib/time/time.go#L74
    • https://github.com/google/starlark-go/blob/acb66ad56dd25d86c91a1efc3869d4a0ec0fcbdb/starlark/library.go#L34
    • https://github.com/google/starlark-go/blob/acb66ad56dd25d86c91a1efc3869d4a0ec0fcbdb/resolve/resolve.go#L100-L111
    • Maybe a few more places I didn't find now.

    In addition to the above, global mutable variables are sometimes abused by third-party libraries. They assume they are the center of the world and mutate such variables in other packages in their init(). No mutable globals -> no such problems.

    p.s. thank you for the library! It's great!

Related tags
A fast script language for Go
A fast script language for Go

The Tengo Language Tengo is a small, dynamic, fast, secure script language for Go. Tengo is fast and secure because it's compiled/executed as bytecode

Dec 30, 2022
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io
Simple, fast, safe, compiled language for developing maintainable software. Compiles itself in <1s with zero library dependencies. https://vlang.io

The V Programming Language vlang.io | Docs | Changelog | Speed | Contributing & compiler design Key Features of V Simplicity: the language can be lear

Jan 4, 2023
Compiler for a small language into x86-64 Assembly

Compiler This project is a small compiler, that compiles my own little language into X86-64 Assembly. It then uses yasm and ld to assemble and link in

Dec 13, 2022
Elvish = Expressive Programming Language + Versatile Interactive Shell

Elvish: Expressive Programming Language + Versatile Interactive Shell Elvish is an expressive programming language and a versatile interactive shell,

Dec 25, 2022
A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022
DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot
DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot

DanaConfig is a static configuration extractor implemented in Golang for the main component of DanaBot (targeting Microsoft Windows). By de

Mar 7, 2022
Flux is a tool for keeping Kubernetes clusters in sync with sources of configuration, and automating updates to configuration when there is new code to deploy.
Flux is a tool for keeping Kubernetes clusters in sync with sources of configuration, and automating updates to configuration when there is new code to deploy.

Flux is a tool for keeping Kubernetes clusters in sync with sources of configuration (like Git repositories), and automating updates to configuration when there is new code to deploy.

Jan 8, 2023
Utility CLI to convert Spring Boot Yaml configuration into external configuration

boot-config-export Utility CLI to convert Spring Boot Yaml configuration into external configuration (as environment variables). The variables are tra

Nov 17, 2021
Traefik config validator: a CLI tool to (syntactically) validate your Traefik configuration filesTraefik config validator: a CLI tool to (syntactically) validate your Traefik configuration files
Traefik config validator: a CLI tool to (syntactically) validate your Traefik configuration filesTraefik config validator: a CLI tool to (syntactically) validate your Traefik configuration files

Traefik Config Validator Note This is currently pre-release software. traefik-config-validator is a CLI tool to (syntactically) validate your Traefik

Dec 16, 2021
BGP implemented in the Go Programming Language

GoBGP: BGP implementation in Go GoBGP is an open source BGP implementation designed from scratch for modern environment and implemented in a modern pr

Dec 31, 2022
Firebase Cloud Messaging for application servers implemented using the Go programming language.

Firebase Cloud Notifications Client Firebase Cloud Messaging for application servers implemented using the Go programming language. It's designed for

Dec 17, 2022
Google Cloud Messaging for application servers implemented using the Go programming language.

gcm The Android SDK provides a nice convenience library (com.google.android.gcm.server) that greatly simplifies the interaction between Java-based app

Sep 27, 2022
Cryptocurrency implemented using the Go programming language

Nomadcoin Making a Cryptocurrency using the Go programming language. Features Mining Transactions Database Backend Wallets REST API HTML Explorer P2P

Dec 7, 2022
Go specs implemented as a scripting language in Rust.

Goscript A script language like Python or Lua written in Rust, with exactly the same syntax as Go's. The Goal Runs most pure Go code, probably add som

Jan 8, 2023
Based on user32.dll, go language is implemented to call function MessageBoxW of Windows platform
Based on user32.dll, go language is implemented to call function MessageBoxW of Windows platform

go-mbw 一个通过user32.dll调用 Windows 平台的MessageBoxW函数的 Go 语言库 A Go lib for call windows platform function MessageBoxW from user32.dll. 安装(Install) go get g

Oct 27, 2022
Simple HCL (HashiCorp Configuration Language) parser for your vars.

HCL to Markdown About To write a good documentation for terraform module, quite often we just need to print all our input variables as a fancy table.

Dec 14, 2021
HCL is the HashiCorp configuration language.

HCL HCL is a toolkit for creating structured configuration languages that are both human- and machine-friendly, for use with command-line tools. Altho

Jan 9, 2023
The new home of the CUE language! Validate and define text-based and dynamic configuration

The CUE Data Constraint Language Configure, Unify, Execute CUE is an open source data constraint language which aims to simplify tasks involving defin

Dec 31, 2022
Graph-based Declarative Configuration Language
Graph-based Declarative Configuration Language

Virgo Configuration Language Most configuration problems reduce to graphs, e.g. Dockerfiles and Makefiles But there are no graph-based configuration l

Nov 26, 2022
Generate code for any language, with any language.

gocog - generate code for any language, with any language gocog v1.0 build 20130206 Binaries for popular OSes are available on the Downloads page of t

Aug 5, 2022