starlarkgen

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2020 License: MIT Imports: 10 Imported by: 0

README

Go Documentation PkgGoDev

starlarkgen

Package starlarkgen provides Starlark code generation methods from go.starlark.net syntax tree primitives

Docs and examples

Check out the docs at the usual place: on godoc.org or pkg.go.dev

Simple usage example

Add a prefix new_ prefix for all the methods and calls by parsing the source, walking the AST tree and rebuilding the source back.

f, err := syntax.Parse("testdata/import.star", nil, 0)
if err != nil {
    log.Fatal(err)
}

// rename all the functions and function calls
syntax.Walk(f, func(n syntax.Node) bool {
    switch t := n.(type) {
    case *syntax.DefStmt:
        t.Name.Name = "new_" + t.Name.Name
    case *syntax.CallExpr:
        if ident, ok := t.Fn.(*syntax.Ident); ok {
            ident.Name = "new_" + ident.Name
        }
    }
    return true
})

// Build the Starlark source back from the AST tree
//
// Note that node positions will be ignored
var sb strings.Builder
sep := ""
for _, s := range f.Stmts {
    sb.WriteString(sep)
    st, err := StarlarkStmt(s)
    if err != nil {
        log.Fatal(err)
    }
    sb.WriteString(st)
    sep = "\n"
}

fmt.Println(sb.String())

See the full example code

Also see the examples in the docs

Documentation

Overview

Package starlarkgen provides Starlark code generation methods from go.starlark.net (https://go.starlark.net) syntax tree primitives

Example
// Parse source file
f, err := syntax.Parse("testdata/import.star", nil, 0)
if err != nil {
	log.Fatal(err)
}

// rename all the functions and function calls
syntax.Walk(f, func(n syntax.Node) bool {
	switch t := n.(type) {
	case *syntax.DefStmt:
		t.Name.Name = "new_" + t.Name.Name
	case *syntax.CallExpr:
		if ident, ok := t.Fn.(*syntax.Ident); ok {
			ident.Name = "new_" + ident.Name
		}
	}
	return true
})

// Build the Starlark source back from the AST tree
//
// Note that node positions will be ignored
var sb strings.Builder
sep := ""
for _, s := range f.Stmts {
	sb.WriteString(sep)
	st, err := StarlarkStmt(s)
	if err != nil {
		log.Fatal(err)
	}
	sb.WriteString(st)
	sep = "\n"
}

fmt.Println(sb.String())
Output:

"""test import file"""

def new_foo(n):
    pass

def new_bar(x):
    new_foo(x * 2)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func StarlarkExpr

func StarlarkExpr(input syntax.Expr, options ...Option) (string, error)

StarlarkExpr produces Starlark source code for a single expression using the options supplied. In case of an error the string output is always empty.

func StarlarkStmt

func StarlarkStmt(input syntax.Stmt, options ...Option) (string, error)

StarlarkStmt produces Starlark source code for a single statement using the options supplied. In case of an error the string output is always empty.

Example
stm := &syntax.DefStmt{
	Name: &syntax.Ident{Name: "foo"},
	Params: []syntax.Expr{
		&syntax.Ident{Name: "bar"},
		&syntax.BinaryExpr{X: &syntax.Ident{Name: "foo"}, Op: syntax.EQ, Y: &syntax.Literal{Value: 2}},
	},
	Body: []syntax.Stmt{
		&syntax.ReturnStmt{Result: &syntax.BinaryExpr{X: &syntax.Ident{Name: "bar"}, Op: syntax.MINUS, Y: &syntax.Literal{Value: 2}}},
	},
}

st, err := StarlarkStmt(stm)
if err != nil {
	log.Fatal(err)
}
fmt.Println(st)
Output:

def foo(bar, foo=2):
    return bar - 2

func WriteExpr

func WriteExpr(output io.StringWriter, input syntax.Expr, options ...Option) error

WriteExpr writes the Starlark expression to the provided writer using the options supplied. In case of an error incomplete results might be written to the output, use StarlarkStmt to avoid handling partial input.

func WriteStmt

func WriteStmt(output io.StringWriter, input syntax.Stmt, options ...Option) error

WriteStmt writes the Starlark statement to the provided writer using the options supplied. In case of an error incomplete results might be written to the output, use StarlarkStmt to avoid handling partial input.

Types

type CallOption

type CallOption renderOption

CallOption controls how the function calls are rendered. See examples for details on each specific option.

const (
	// CallOptionSingleLine is the default, render as single line.
	CallOptionSingleLine CallOption = iota
	// CallOptionSingleLineComma will render call as single line, with comma after last argument.
	CallOptionSingleLineComma
	// CallOptionSingleLineCommaTwoAndMore will render call as single line, with comma after last argument, if there are two or more arguments.
	CallOptionSingleLineCommaTwoAndMore

	// CallOptionMultilineMultiple will render single argument calls as single line,
	// and two and more arguments as multiline.
	CallOptionMultilineMultiple
	// CallOptionMultilineMultipleComma will render single argument calls as single line,
	// and two and more arguments as multiline, with comma after last argument.
	CallOptionMultilineMultipleComma
	// CallOptionMultilineMultipleCommaTwoAndMore will render single argument calls as single line,
	// and two and more arguments as multiline, with comma after last argument if two or more argument are present.
	CallOptionMultilineMultipleCommaTwoAndMore

	// CallOptionMultiline will render call as multiline.
	CallOptionMultiline
	// CallOptionMultilineComma will render call as multiline, with comma after last argument.
	CallOptionMultilineComma
	// CallOptionMultilineCommaTwoAndMore will render call as multiline, with comma after last argument, if there are two or more argument.
	CallOptionMultilineCommaTwoAndMore
)

type DictOption

type DictOption renderOption

DictOption controls how the dict literals are rendered. See examples for details on each specific option.

const (
	// DictOptionSingleLine is the default, render as single line.
	DictOptionSingleLine DictOption = iota
	// DictOptionSingleLineComma will render dict as single line, with comma after last item.
	DictOptionSingleLineComma
	// DictOptionSingleLineCommaTwoAndMore will render dict as single line, with comma after last item, if there are two or more items.
	DictOptionSingleLineCommaTwoAndMore

	// DictOptionMultilineMultiple will render single element dictionaries as single line,
	// and two and more elements as multiline.
	DictOptionMultilineMultiple
	// DictOptionMultilineMultipleComma will render single element dictionaries as single line,
	// and two and more elements as multiline, with comma after last item.
	DictOptionMultilineMultipleComma
	// DictOptionMultilineMultipleCommaTwoAndMore will render single element dictionaries as single line,
	// and two and more elements as multiline, with comma after last item if two or more elements are present.
	DictOptionMultilineMultipleCommaTwoAndMore

	// DictOptionMultiline will render dict as multiline.
	DictOptionMultiline
	// DictOptionMultilineComma will render dict as multiline, with comma after last item.
	DictOptionMultilineComma
	// DictOptionMultilineCommaTwoAndMore will render dict as multiline, with comma after last item, if there are two or more items.
	DictOptionMultilineCommaTwoAndMore
)

type ListOption

type ListOption renderOption

ListOption controls how the list literals are rendered. See examples for details on each specific option.

const (
	// ListOptionSingleLine is the default, render as single line.
	ListOptionSingleLine ListOption = iota
	// ListOptionSingleLineComma will render list as single line, with comma after last item.
	ListOptionSingleLineComma
	// ListOptionSingleLineCommaTwoAndMore will render list as single line, with comma after last item, if there are two or more items.
	ListOptionSingleLineCommaTwoAndMore

	// ListOptionMultilineMultiple will render single element lists as single line,
	// and two and more elements as multiline.
	ListOptionMultilineMultiple
	// ListOptionMultilineMultipleComma will render single element lists as single line,
	// and two and more elements as multiline, with comma after last item.
	ListOptionMultilineMultipleComma
	// ListOptionMultilineMultipleCommaTwoAndMore will render single element lists as single line,
	// and two and more elements as multiline, with comma after last item if two or more elements are present.
	ListOptionMultilineMultipleCommaTwoAndMore

	// ListOptionMultiline will render list as multiline.
	ListOptionMultiline
	// ListOptionMultilineComma will render list as multiline, with comma after last item.
	ListOptionMultilineComma
	// ListOptionMultilineCommaTwoAndMore will render list as multiline, with comma after last item, if there are two or more items.
	ListOptionMultilineCommaTwoAndMore
)

type Option

type Option func(*outputOpts) (*outputOpts, error)

Option represents Starlark code rendering option.

func WithCallOption

func WithCallOption(value CallOption) Option

WithCallOption sets the option to render function calls.

Example
matrix := map[CallOption]string{
	CallOptionMultiline:                        "CallOptionMultiline",
	CallOptionMultilineComma:                   "CallOptionMultilineComma",
	CallOptionMultilineCommaTwoAndMore:         "CallOptionMultilineCommaTwoAndMore",
	CallOptionMultilineMultiple:                "CallOptionMultilineMultiple",
	CallOptionMultilineMultipleComma:           "CallOptionMultilineMultipleComma",
	CallOptionMultilineMultipleCommaTwoAndMore: "CallOptionMultilineMultipleCommaTwoAndMore",
	CallOptionSingleLine:                       "CallOptionSingleLine",
	CallOptionSingleLineComma:                  "CallOptionSingleLineComma",
	CallOptionSingleLineCommaTwoAndMore:        "CallOptionSingleLineCommaTwoAndMore",
}
for i := 0; i < len(matrix); i++ {
	opt, name := CallOption(i), matrix[CallOption(i)]
	call := &syntax.CallExpr{
		Fn: &syntax.Ident{Name: "some_func"},
		Args: []syntax.Expr{
			&syntax.Ident{Name: "foo"},
			&syntax.Ident{Name: "bar"},
		},
	}
	fmt.Println(name)
	for {
		exp, err := StarlarkExpr(call, WithCallOption(opt))

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println(exp)

		if len(call.Args) == 0 {
			break
		}
		call.Args = call.Args[:len(call.Args)-1]
	}
}
Output:

CallOptionSingleLine
some_func(foo, bar)
some_func(foo)
some_func()
CallOptionSingleLineComma
some_func(foo, bar,)
some_func(foo,)
some_func()
CallOptionSingleLineCommaTwoAndMore
some_func(foo, bar,)
some_func(foo)
some_func()
CallOptionMultilineMultiple
some_func(
    foo,
    bar
)
some_func(foo)
some_func()
CallOptionMultilineMultipleComma
some_func(
    foo,
    bar,
)
some_func(foo,)
some_func()
CallOptionMultilineMultipleCommaTwoAndMore
some_func(
    foo,
    bar,
)
some_func(foo)
some_func()
CallOptionMultiline
some_func(
    foo,
    bar
)
some_func(
    foo
)
some_func()
CallOptionMultilineComma
some_func(
    foo,
    bar,
)
some_func(
    foo,
)
some_func()
CallOptionMultilineCommaTwoAndMore
some_func(
    foo,
    bar,
)
some_func(
    foo
)
some_func()

func WithDepth

func WithDepth(depth int) Option

WithDepth sets the initial indentation depth.

Example
st, err := StarlarkStmt(&syntax.BranchStmt{Token: syntax.PASS}, WithDepth(10))
if err != nil {
	log.Fatal(err)
}

fmt.Println(len(st) - len(strings.TrimLeft(st, " "))) // 10 * 4
Output:

40

func WithDictOption

func WithDictOption(value DictOption) Option

WithDictOption sets the option to render dictionary literals.

Example
matrix := map[DictOption]string{
	DictOptionMultiline:                        "DictOptionMultiline",
	DictOptionMultilineComma:                   "DictOptionMultilineComma",
	DictOptionMultilineCommaTwoAndMore:         "DictOptionMultilineCommaTwoAndMore",
	DictOptionMultilineMultiple:                "DictOptionMultilineMultiple",
	DictOptionMultilineMultipleComma:           "DictOptionMultilineMultipleComma",
	DictOptionMultilineMultipleCommaTwoAndMore: "DictOptionMultilineMultipleCommaTwoAndMore",
	DictOptionSingleLine:                       "DictOptionSingleLine",
	DictOptionSingleLineComma:                  "DictOptionSingleLineComma",
	DictOptionSingleLineCommaTwoAndMore:        "DictOptionSingleLineCommaTwoAndMore",
}
for i := 0; i < len(matrix); i++ {
	opt, name := DictOption(i), matrix[DictOption(i)]
	dict := &syntax.DictExpr{
		List: []syntax.Expr{
			&syntax.DictEntry{Key: &syntax.Ident{Name: "foo"}, Value: &syntax.Literal{Value: 1}},
			&syntax.DictEntry{Key: &syntax.Ident{Name: "bar"}, Value: &syntax.Literal{Value: 2}},
		},
	}
	fmt.Println(name)
	for {
		exp, err := StarlarkExpr(dict, WithDictOption(opt))

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println(exp)

		if len(dict.List) == 0 {
			break
		}
		dict.List = dict.List[:len(dict.List)-1]
	}
}
Output:

DictOptionSingleLine
{foo: 1, bar: 2}
{foo: 1}
{}
DictOptionSingleLineComma
{foo: 1, bar: 2,}
{foo: 1,}
{}
DictOptionSingleLineCommaTwoAndMore
{foo: 1, bar: 2,}
{foo: 1}
{}
DictOptionMultilineMultiple
{
    foo: 1,
    bar: 2
}
{foo: 1}
{}
DictOptionMultilineMultipleComma
{
    foo: 1,
    bar: 2,
}
{foo: 1,}
{}
DictOptionMultilineMultipleCommaTwoAndMore
{
    foo: 1,
    bar: 2,
}
{foo: 1}
{}
DictOptionMultiline
{
    foo: 1,
    bar: 2
}
{
    foo: 1
}
{}
DictOptionMultilineComma
{
    foo: 1,
    bar: 2,
}
{
    foo: 1,
}
{}
DictOptionMultilineCommaTwoAndMore
{
    foo: 1,
    bar: 2,
}
{
    foo: 1
}
{}

func WithIndent

func WithIndent(indent string) Option

WithIndent replaces the default indentation sequence.

Example
st, err := StarlarkStmt(&syntax.IfStmt{
	Cond: &syntax.BinaryExpr{Op: syntax.LT, X: &syntax.Ident{Name: "foo"}, Y: &syntax.Ident{Name: "bar"}},
	True: []syntax.Stmt{&syntax.BranchStmt{Token: syntax.PASS}},
}, WithIndent("____"))
if err != nil {
	log.Fatal(err)
}

fmt.Println(st)
Output:

if foo < bar:
____pass

func WithListOption

func WithListOption(value ListOption) Option

WithListOption sets the option to render list literals.

Example
matrix := map[ListOption]string{
	ListOptionMultiline:                        "ListOptionMultiline",
	ListOptionMultilineComma:                   "ListOptionMultilineComma",
	ListOptionMultilineCommaTwoAndMore:         "ListOptionMultilineCommaTwoAndMore",
	ListOptionMultilineMultiple:                "ListOptionMultilineMultiple",
	ListOptionMultilineMultipleComma:           "ListOptionMultilineMultipleComma",
	ListOptionMultilineMultipleCommaTwoAndMore: "ListOptionMultilineMultipleCommaTwoAndMore",
	ListOptionSingleLine:                       "ListOptionSingleLine",
	ListOptionSingleLineComma:                  "ListOptionSingleLineComma",
	ListOptionSingleLineCommaTwoAndMore:        "ListOptionSingleLineCommaTwoAndMore",
}
for i := 0; i < len(matrix); i++ {
	opt, name := ListOption(i), matrix[ListOption(i)]
	list := &syntax.ListExpr{
		List: []syntax.Expr{
			&syntax.Ident{Name: "foo"},
			&syntax.Ident{Name: "bar"},
		},
	}
	fmt.Println(name)
	for {
		exp, err := StarlarkExpr(list, WithListOption(opt))

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println(exp)

		if len(list.List) == 0 {
			break
		}
		list.List = list.List[:len(list.List)-1]
	}
}
Output:

ListOptionSingleLine
[foo, bar]
[foo]
[]
ListOptionSingleLineComma
[foo, bar,]
[foo,]
[]
ListOptionSingleLineCommaTwoAndMore
[foo, bar,]
[foo]
[]
ListOptionMultilineMultiple
[
    foo,
    bar
]
[foo]
[]
ListOptionMultilineMultipleComma
[
    foo,
    bar,
]
[foo,]
[]
ListOptionMultilineMultipleCommaTwoAndMore
[
    foo,
    bar,
]
[foo]
[]
ListOptionMultiline
[
    foo,
    bar
]
[
    foo
]
[]
ListOptionMultilineComma
[
    foo,
    bar,
]
[
    foo,
]
[]
ListOptionMultilineCommaTwoAndMore
[
    foo,
    bar,
]
[
    foo
]
[]

func WithSpaceEqBinary

func WithSpaceEqBinary(value bool) Option

WithSpaceEqBinary sets the behavior of how the binary pairs foo=bar are rendered. when set to true, render results are

foo(bar = 1, baz = "z")

when set to false, render results are

foo(bar=1, baz="z")

This setting also applies to aliases in load(...) statement. The default value is false.

This setting does not affect the behavior of assignments, which always have the spaces around equality sign.

Example
// foo=bar
ex := &syntax.BinaryExpr{Op: syntax.EQ, X: &syntax.Ident{Name: "foo"}, Y: &syntax.Ident{Name: "bar"}}
exWithSpace, err := StarlarkExpr(ex, WithSpaceEqBinary(true))
if err != nil {
	log.Fatal(err)
}
exWithoutSpace, err := StarlarkExpr(ex, WithSpaceEqBinary(false)) // can be omitted, false is default
if err != nil {
	log.Fatal(err)
}

fmt.Println(exWithSpace)
fmt.Println(exWithoutSpace)
Output:

foo = bar
foo=bar

func WithTupleOption

func WithTupleOption(value TupleOption) Option

WithTupleOption sets the option to render tuple literals.

Example
matrix := map[TupleOption]string{
	TupleOptionMultiline:                        "TupleOptionMultiline",
	TupleOptionMultilineComma:                   "TupleOptionMultilineComma",
	TupleOptionMultilineCommaTwoAndMore:         "TupleOptionMultilineCommaTwoAndMore",
	TupleOptionMultilineMultiple:                "TupleOptionMultilineMultiple",
	TupleOptionMultilineMultipleComma:           "TupleOptionMultilineMultipleComma",
	TupleOptionMultilineMultipleCommaTwoAndMore: "TupleOptionMultilineMultipleCommaTwoAndMore",
	TupleOptionSingleLine:                       "TupleOptionSingleLine",
	TupleOptionSingleLineComma:                  "TupleOptionSingleLineComma",
	TupleOptionSingleLineCommaTwoAndMore:        "TupleOptionSingleLineCommaTwoAndMore",
}
for i := 0; i < len(matrix); i++ {
	opt, name := TupleOption(i), matrix[TupleOption(i)]

	tuple := &syntax.TupleExpr{
		List: []syntax.Expr{
			&syntax.Ident{Name: "foo"},
			&syntax.Ident{Name: "bar"},
		},
	}
	paren := &syntax.ParenExpr{X: tuple}

	fmt.Println(name)
	for {
		exp, err := StarlarkExpr(paren, WithTupleOption(opt))

		if err != nil {
			log.Fatal(err)
		}

		fmt.Println(exp)

		if len(tuple.List) == 0 {
			break
		}
		tuple.List = tuple.List[:len(tuple.List)-1]
	}
}
Output:

TupleOptionSingleLine
(foo, bar)
(foo)
()
TupleOptionSingleLineComma
(foo, bar,)
(foo,)
()
TupleOptionSingleLineCommaTwoAndMore
(foo, bar,)
(foo)
()
TupleOptionMultilineMultiple
(
    foo,
    bar
)
(foo)
()
TupleOptionMultilineMultipleComma
(
    foo,
    bar,
)
(foo,)
()
TupleOptionMultilineMultipleCommaTwoAndMore
(
    foo,
    bar,
)
(foo)
()
TupleOptionMultiline
(
    foo,
    bar
)
(
    foo
)
()
TupleOptionMultilineComma
(
    foo,
    bar,
)
(
    foo,
)
()
TupleOptionMultilineCommaTwoAndMore
(
    foo,
    bar,
)
(
    foo
)
()

type TupleOption

type TupleOption renderOption

TupleOption controls how the tuple literals are rendered. See examples for details on each specific option.

const (
	// TupleOptionSingleLine is the default, render as single line.
	TupleOptionSingleLine TupleOption = iota
	// TupleOptionSingleLineComma will render tuple as single line, with comma after last item.
	TupleOptionSingleLineComma
	// TupleOptionSingleLineCommaTwoAndMore will render tuple as single line, with comma after last item, if there are two or more items.
	TupleOptionSingleLineCommaTwoAndMore

	// TupleOptionMultilineMultiple will render single element tuples as single line,
	// and two and more elements as multiline.
	TupleOptionMultilineMultiple
	// TupleOptionMultilineMultipleComma will render single element tuples as single line,
	// and two and more elements as multiline, with comma after last item.
	TupleOptionMultilineMultipleComma
	// TupleOptionMultilineMultipleCommaTwoAndMore will render single element tuples as single line,
	// and two and more elements as multiline, with comma after last item if two or more elements are present.
	TupleOptionMultilineMultipleCommaTwoAndMore

	// TupleOptionMultiline will render tuple as multiline.
	TupleOptionMultiline
	// TupleOptionMultilineComma will render tuple as multiline, with comma after last item.
	TupleOptionMultilineComma
	// TupleOptionMultilineCommaTwoAndMore will render tuple as multiline, with comma after last item, if there are two or more items.
	TupleOptionMultilineCommaTwoAndMore
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL