epy

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Nov 19, 2023 License: MIT Imports: 13 Imported by: 0

README

go-epy, an embeddable Python

Starlark in Go, a Python-like script language, is an interpreter for Starlark implemented in pure Go.

go-epy is a package extending the starlark-go and making it a pragmatic embeddable language. With some helper functions provided by go-epy, calling Golang functions or modules from Starlark, or calling Starlark functions from Golang are both very simple. So, with the help of go-epy, starlark-go can be looked as an embeddable Python.

Usage

The package is fully go-getable, so, just type

go get github.com/rosbit/go-epy

to install.

1. Evaluate expressions
package main

import (
  "github.com/rosbit/go-epy"
  "fmt"
)

func main() {
  ctx := epy.New()

  res, _ := ctx.Eval("1 + 2", nil)
  fmt.Println("result is:", res)
}
2. Go calls Starlark function

Suppose there's a Starlark file named a.py like this:

def add(a, b):
    return a+b

one can call the Starlark function add() in Go code like the following:

package main

import (
  "github.com/rosbit/go-epy"
  "fmt"
)

var add func(int, int)int

func main() {
  ctx := epy.New()
  if err := ctx.LoadFile("a.py", nil); err != nil {
     fmt.Printf("%v\n", err)
     return
  }

  if err := ctx.BindFunc("add", &add); err != nil {
     fmt.Printf("%v\n", err)
     return
  }

  res := add(1, 2)
  fmt.Println("result is:", res)
}
3. Starlark calls Go function

Starlark calling Go function is also easy. In the Go code, make a Golang function as Starlark built-in function by calling MakeBuiltinFunc("funcname", function). There's the example:

package main

import "github.com/rosbit/go-epy"

// function to be called by Starlark
func adder(a1 float64, a2 float64) float64 {
    return a1 + a2
}

func main() {
  ctx := epy.New()

  ctx.MakeBuiltinFunc("adder", adder)
  ctx.EvalFile("b.py", nil)  // b.py containing code calling "adder"
}

In Starlark code, one can call the registered function directly. There's the example b.py.

r = adder(1, 100)   # the function "adder" is implemented in Go
print(r)
4. Make Go struct instance as a Starlark module

This package provides a function SetModule which will convert a Go struct instance into a Starlark module. There's the example c.py, m is the module provided by Go code:

m.incAge(10)
print(m)

print('m.name', m.name)
print('m.age', m.age)

The Go code is like this:

package main

import "github.com/rosbit/go-epy"

type M struct {
   Name string
   Age int
}
func (m *M) IncAge(a int) {
   m.Age += a
}

func main() {
  ctx := epy.New()
  ctx.SetModule("m", &M{Name:"rosbit", Age: 1}) // "m" is the module name

  ctx.EvalFile("c.py", nil)
}
5. Set many built-in functions and modules at one time

If there're a lot of functions and modules to be registered, a map could be constructed and put as an argument for functions LoadFile, LoadScript, EvalFile or Eval.

package main

import "github.com/rosbit/go-epy"
import "fmt"

type M struct {
   Name string
   Age int
}
func (m *M) IncAge(a int) {
   m.Age += a
}

func adder(a1 float64, a2 float64) float64 {
    return a1 + a2
}

func main() {
  vars := map[string]interface{}{
     "m": &M{Name:"rosbit", Age:1}, // to Starlark module
     "adder": adder,                // to Starlark built-in function
     "a": []int{1,2,3}              // to Starlark array
  }

  ctx := epy.New()
  if err := ctx.LoadFile("file.py", vars); err != nil {
     fmt.Printf("%v\n", err)
     return
  }

  res, err := ctx.GetGlobal("a") // get the value of var named "a". Any variables in script could be get by GetGlobal
  if err != nil {
     fmt.Printf("%v\n", err)
     return
  }
  fmt.Printf("res:", res)
}
6. Wrap Go functions as Starlark module

This package also provides a function CreateModule which will create a Starlark module integrating any Go functions as module methods. There's the example d.py which will use module tm provided by Go code:

a = tm.newA("rosbit", 10)
a.incAge(10)
print(a)

tm.printf('a.name: %s\n', a.name)
tm.printf('a.age: %d\n', a.age)

The Go code is like this:

package main

import (
  "github.com/rosbit/go-epy"
  "fmt"
)

type A struct {
   Name string
   Age int
}
func (m *A) IncAge(a int) {
   m.Age += a
}
func newA(name string, age int) *A {
   return &A{Name: name, Age: age}
}

func main() {
  ctx := epy.New()
  ctx.CreateModule("tm", map[string]interface{}{ // module name is "tm"
     "newA": newA,            // make user defined function as module method named "tm.newA"
     "printf": fmt.Printf,    // make function in a standard package named "tm.printf"
  })

  ctx.EvalFile("d.py", nil)
}
Status

The package is not fully tested, so be careful.

Contribution

Pull requests are welcome! Also, if you want to discuss something send a pull request with proposal and changes.

Convention: fork the repository and make changes on your fork in a feature branch.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func InitPyCache added in v0.0.4

func InitPyCache()

Types

type XStarlark

type XStarlark struct {
	// contains filtered or unexported fields
}

func LoadFileFromCache added in v0.0.4

func LoadFileFromCache(path string, vars map[string]interface{}) (ctx *XStarlark, existing bool, err error)

func New

func New() *XStarlark

func (*XStarlark) BindFunc

func (slw *XStarlark) BindFunc(funcName string, funcVarPtr interface{}) (err error)

bind a var of golang func with a Starlark function name, so calling Starlark function is just calling the related golang func. @param funcVarPtr in format `var funcVar func(....) ...; funcVarPtr = &funcVar`

func (*XStarlark) BindFuncs added in v0.1.3

func (slw *XStarlark) BindFuncs(funcName2FuncVarPtr map[string]interface{}) (err error)

func (*XStarlark) CallFunc

func (slw *XStarlark) CallFunc(funcName string, args ...interface{}) (res interface{}, err error)

func (*XStarlark) CreateModule

func (slw *XStarlark) CreateModule(modName string, name2FuncVarPtr map[string]interface{}) (err error)

wrapper some `name2FuncVarPtr` to a module named `modName` @param name2FuncVarPtr must be string => func

func (*XStarlark) Eval

func (slw *XStarlark) Eval(script string, env map[string]interface{}) (res interface{}, err error)

func (*XStarlark) EvalFile

func (slw *XStarlark) EvalFile(path string, env map[string]interface{}) (res interface{}, err error)

func (*XStarlark) GetGlobal

func (slw *XStarlark) GetGlobal(name string) (res interface{}, err error)

func (*XStarlark) LoadFile

func (slw *XStarlark) LoadFile(path string, vars map[string]interface{}) (err error)

func (*XStarlark) LoadScript

func (slw *XStarlark) LoadScript(script string, vars map[string]interface{}) (err error)

func (*XStarlark) MakeBuiltinFunc

func (slw *XStarlark) MakeBuiltinFunc(funcName string, funcVar interface{}) (err error)

make a golang func as a built-in Starlark function, so the function can be called in Starlark script.

func (*XStarlark) SetModule

func (slw *XStarlark) SetModule(modName string, structVarPtr interface{}) (err error)

make a golang pointer of sturct instance as a Starlark module. @param structVarPtr pointer of struct instance is recommended.

Jump to

Keyboard shortcuts

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