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 }