github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/lib/golib/golib.go (about)

     1  package golib
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"path"
     8  
     9  	"github.com/arnodel/golua/lib/golib/goimports"
    10  	"github.com/arnodel/golua/lib/packagelib"
    11  	rt "github.com/arnodel/golua/runtime"
    12  )
    13  
    14  // LibLoader loads this library.
    15  var LibLoader = packagelib.Loader{
    16  	Load: load,
    17  	Name: "golib",
    18  }
    19  
    20  type govalueKeyType struct{}
    21  
    22  // TODO: a better value?
    23  var govalueKey = rt.AsValue(govalueKeyType{})
    24  
    25  func load(r *rt.Runtime) (rt.Value, func()) {
    26  	pkg := rt.NewTable()
    27  
    28  	if goimports.Supported {
    29  		r.SetEnvGoFunc(pkg, "import", goimport, 1, false)
    30  	}
    31  
    32  	meta := rt.NewTable()
    33  	r.SetEnvGoFunc(meta, "__index", goValueIndex, 2, false)
    34  	r.SetEnvGoFunc(meta, "__newindex", goValueSetIndex, 3, false)
    35  	r.SetEnvGoFunc(meta, "__call", goValueCall, 1, true)
    36  	r.SetEnvGoFunc(meta, "__tostring", goValueToString, 1, false)
    37  
    38  	r.SetRegistry(govalueKey, rt.TableValue(meta))
    39  
    40  	return rt.TableValue(pkg), nil
    41  }
    42  
    43  func getMeta(r *rt.Runtime) *rt.Table {
    44  	return r.Registry(govalueKey).AsTable()
    45  }
    46  
    47  // NewGoValue will return a UserData representing the go value.
    48  func NewGoValue(r *rt.Runtime, x interface{}) rt.Value {
    49  	return r.NewUserDataValue(x, getMeta(r))
    50  }
    51  
    52  func goValueToString(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
    53  	if err := c.Check1Arg(); err != nil {
    54  		return nil, err
    55  	}
    56  	u, err := c.UserDataArg(0)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	return c.PushingNext1(t.Runtime, rt.StringValue(fmt.Sprintf("%#v", u.Value()))), nil
    61  }
    62  
    63  func goValueIndex(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
    64  	if err := c.CheckNArgs(2); err != nil {
    65  		return nil, err
    66  	}
    67  	u, err := c.UserDataArg(0)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	val, indexErr := goIndex(t, u, c.Arg(1))
    72  	if indexErr != nil {
    73  		return nil, indexErr
    74  	}
    75  	return c.PushingNext1(t.Runtime, val), nil
    76  }
    77  
    78  func goValueSetIndex(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
    79  	if err := c.CheckNArgs(3); err != nil {
    80  		return nil, err
    81  	}
    82  	u, err := c.UserDataArg(0)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	setIndexErr := goSetIndex(t, u, c.Arg(1), c.Arg(2))
    87  	if setIndexErr != nil {
    88  		return nil, setIndexErr
    89  	}
    90  	return c.Next(), nil
    91  }
    92  
    93  func goValueCall(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
    94  	if err := c.Check1Arg(); err != nil {
    95  		return nil, err
    96  	}
    97  	u, err := c.UserDataArg(0)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	res, callErr := goCall(t, u, c.Etc())
   102  	if callErr != nil {
   103  		return nil, callErr
   104  	}
   105  	return c.PushingNext(t.Runtime, res...), nil
   106  }
   107  
   108  func goimport(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
   109  	if pluginsRoot == "" {
   110  		return nil, rt.NewError(rt.StringValue("cannot import go packages: plugins root not set"))
   111  	}
   112  	if err := c.Check1Arg(); err != nil {
   113  		return nil, err
   114  	}
   115  	path, err := c.StringArg(0)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  	forceBuild := c.NArgs() >= 2 && rt.Truth(c.Arg(1))
   120  	exports, loadErr := goimports.LoadGoPackage(string(path), pluginsRoot, forceBuild)
   121  	if loadErr != nil {
   122  		return nil, fmt.Errorf("cannot import go package %s: %s", path, loadErr)
   123  	}
   124  	return c.PushingNext1(t.Runtime, NewGoValue(t.Runtime, exports)), nil
   125  }
   126  
   127  var pluginsRoot string
   128  
   129  func init() {
   130  	var ok bool
   131  	pluginsRoot, ok = os.LookupEnv("GOLUA_PLUGINS_ROOT")
   132  	if ok {
   133  		return
   134  	}
   135  	home, err := os.UserHomeDir()
   136  	if err == nil {
   137  		pluginsRoot = path.Join(home, ".golua/goplugins")
   138  		return
   139  	}
   140  	pluginsRoot = ""
   141  	log.Print("Unable to set go plugins root")
   142  }