feat: begin initial port to c lua

pull/314/merge^2
sammyette 2024-07-21 11:37:08 -04:00
parent 17a3e2c0c4
commit 1f9fd80fbb
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
46 changed files with 651 additions and 205 deletions

View File

@ -14,6 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
midnight: [false, true]
goos: [linux, windows, darwin]
goarch: ["386", amd64, arm64]
exclude:
@ -33,7 +34,7 @@ jobs:
- name: Download Task
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
- name: Build
run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} ./bin/task
run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} ./bin/task ${{ matrix.midnight == 'true' && 'midnight' || ''}}
- uses: actions/upload-artifact@v4
if: matrix.goos == 'windows'
with:

View File

@ -16,7 +16,8 @@
Functionality **will** be missing if you use this branch,
and you may see crashes too. Tread lightly.
Progress on Midnight Edition is tracked in this PR: [#314](https://github.com/Rosettea/Hilbish/pull/314)
Build instructions and progress on Midnight Edition is tracked in this PR:
[#314](https://github.com/Rosettea/Hilbish/pull/314)
Hilbish: Midinight Edition is a version of Hilbish meant to be compatible with
the original C implementation of Lua by using a Go library binding. The end goal
@ -70,13 +71,13 @@ go get -d ./...
To build, run:
```
task
go-task
```
Or, if you want a stable branch, run these commands:
```
git checkout $(git describe --tags `git rev-list --tags --max-count=1`)
task build
go-task build
```
After you did all that, run `sudo task install` to install Hilbish globally.

View File

@ -10,6 +10,8 @@ vars:
LIBDIR: '{{default .libdir__ .LIBDIR}}'
goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"'
GOFLAGS: '{{default .goflags__ .GOFLAGS}}'
lua__: 'lua'
LUA: '{{default .lua__ .LUA}}'
tasks:
default:
@ -24,6 +26,12 @@ tasks:
vars:
GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"'
midnight:
cmds:
- go build -tags midnight,{{.LUA}} {{.GOFLAGS}}
vars:
GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"'
build:
cmds:
- go build {{.GOFLAGS}}

View File

@ -97,10 +97,12 @@ func (a *aliasModule) Resolve(cmdstr string) string {
func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
// create a lua module with our functions
hshaliasesLua := map[string]util.LuaExport{
//"add": util.LuaExport{hlalias, 2, false},
/*
"add": util.LuaExport{hlalias, 2, false},
"list": util.LuaExport{a.luaList, 0, false},
"del": util.LuaExport{a.luaDelete, 1, false},
"resolve": util.LuaExport{a.luaResolve, 1, false},
*/
}
mod := rt.NewTable()

4
api.go
View File

@ -149,12 +149,12 @@ func getenv(key, fallback string) string {
}
func setVimMode(mode string) {
hshMod.SetField("vimMode", rt.StringValue(mode))
hshMod.SetField("vimMode", moonlight.StringValue(mode))
hooks.Emit("hilbish.vimMode", mode)
}
func unsetVimMode() {
hshMod.SetField("vimMode", rt.NilValue)
hshMod.SetField("vimMode", moonlight.NilValue)
}
func handleStream(v rt.Value, strms *streams, errStream bool) error {

View File

@ -12,11 +12,13 @@ import (
// directly interact with the line editor in use.
func editorLoader(rtm *rt.Runtime) *rt.Table {
exports := map[string]util.LuaExport{
/*
"insert": {editorInsert, 1, false},
"setVimRegister": {editorSetRegister, 1, false},
"getVimRegister": {editorGetRegister, 2, false},
"getLine": {editorGetLine, 0, false},
"readChar": {editorReadChar, 0, false},
*/
}
mod := rt.NewTable()

52
exec.go
View File

@ -28,7 +28,7 @@ import (
var errNotExec = errors.New("not executable")
var errNotFound = errors.New("not found")
var runnerMode rt.Value = rt.StringValue("hybrid")
var runnerMode moonlight.Value = moonlight.StringValue("hybrid")
type streams struct {
stdout io.Writer
@ -101,7 +101,7 @@ func runInput(input string, priv bool) {
var cont bool
// save incase it changes while prompting (For some reason)
currentRunner := runnerMode
if currentRunner.Type() == rt.StringType {
if currentRunner.Type() == moonlight.StringType {
switch currentRunner.AsString() {
case "hybrid":
_, _, err = handleLua(input)
@ -171,69 +171,41 @@ func reprompt(input string) (string, error) {
}
}
func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) {
func runLuaRunner(runr moonlight.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) {
runnerRet, err := l.Call1(runr, moonlight.StringValue(userInput))
if err != nil {
return "", 124, false, nil, err
}
var runner *rt.Table
var runner *moonlight.Table
var ok bool
if runner, ok = runnerRet.TryTable(); !ok {
if runner, ok = moonlight.TryTable(runnerRet); !ok {
fmt.Fprintln(os.Stderr, "runner did not return a table")
exitCode = 125
input = userInput
return
}
if code, ok := runner.Get(rt.StringValue("exitCode")).TryInt(); ok {
if code, ok := runner.Get(moonlight.StringValue("exitCode")).TryInt(); ok {
exitCode = uint8(code)
}
if inp, ok := runner.Get(rt.StringValue("input")).TryString(); ok {
if inp, ok := runner.Get(moonlight.StringValue("input")).TryString(); ok {
input = inp
}
if errStr, ok := runner.Get(rt.StringValue("err")).TryString(); ok {
if errStr, ok := runner.Get(moonlight.StringValue("err")).TryString(); ok {
runnerErr = fmt.Errorf("%s", errStr)
}
if c, ok := runner.Get(rt.StringValue("continue")).TryBool(); ok {
if c, ok := runner.Get(moonlight.StringValue("continue")).TryBool(); ok {
continued = c
}
return
}
func handleLua(input string) (string, uint8, error) {
cmdString := aliases.Resolve(input)
// First try to load input, essentially compiling to bytecode
rtm := l.UnderlyingRuntime()
chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(cmdString), moonlight.TableValue(l.GlobalTable()))
if err != nil && noexecute {
fmt.Println(err)
/* if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
print(perr.Pos.Line == parse.EOF)
}
}
*/
return cmdString, 125, err
}
// And if there's no syntax errors and -n isnt provided, run
if !noexecute {
if chunk != nil {
_, err = l.Call1(rt.FunctionValue(chunk))
}
}
if err == nil {
return cmdString, 0, nil
}
return cmdString, 125, err
}
func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr error) {
shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh"))
shRunner := hshMod.Get(moonlight.StringValue("runner")).AsTable().Get(moonlight.StringValue("sh"))
var err error
input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString)
if err != nil {
@ -607,9 +579,9 @@ func splitInput(input string) ([]string, string) {
}
func cmdFinish(code uint8, cmdstr string, private bool) {
hshMod.SetField("exitCode", rt.IntValue(int64(code)))
hshMod.SetField("exitCode", moonlight.IntValue(int64(code)))
// using AsValue (to convert to lua type) on an interface which is an int
// results in it being unknown in lua .... ????
// so we allow the hook handler to take lua runtime Values
hooks.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private)
hooks.Emit("command.exit", moonlight.IntValue(int64(code)), cmdstr, private)
}

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.21
toolchain go1.22.2
require (
github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765
github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504
github.com/blackfireio/osinfo v1.0.5

2
go.sum
View File

@ -2,6 +2,8 @@ github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749 h1:jIFnWBTsYw8s7RX7
github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE=
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240720131751-805c301321fd h1:THNle0FR2g7DMO1y3Bx1Zr7rYeiLXt3st3UkxEsMzL4=
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240720131751-805c301321fd/go.mod h1:YZalN5H7WNQw3DGij6IvHsEhn5YMW7M2FCwG6gnfKy4=
github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765 h1:N6gB4UCRBZz8twlJbMFiCKj0zX5Et2nFU/LRafT4x80=
github.com/aarzilli/golua v0.0.0-20210507130708-11106aa57765/go.mod h1:hMjfaJVSqVnxenMlsxrq3Ni+vrm9Hs64tU4M7dhUoO4=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw=

View File

@ -82,16 +82,17 @@ func (b *Bait) Emit(event string, args ...interface{}) {
}()
if handle.typ == luaListener {
funcVal := rt.FunctionValue(handle.luaCaller)
//funcVal := moonlight.FunctionValue(handle.luaCaller)
var luaArgs []moonlight.Value
for _, arg := range args {
var luarg moonlight.Value
switch arg.(type) {
case moonlight.Value: luarg = arg.(moonlight.Value)
default: luarg = rt.AsValue(arg)
default: luarg = moonlight.AsValue(arg)
}
luaArgs = append(luaArgs, luarg)
}
/*
_, err := b.rtm.Call1(funcVal, luaArgs...)
if err != nil {
if event != "error" {
@ -102,6 +103,7 @@ func (b *Bait) Emit(event string, args ...interface{}) {
// (calls the go recoverer function)
panic(err)
}
*/
} else {
handle.caller(args...)
}
@ -146,7 +148,7 @@ func (b *Bait) Off(event string, listener *Listener) {
}
// OffLua removes a Lua function handler for an event.
func (b *Bait) OffLua(event string, handler *rt.Closure) {
func (b *Bait) OffLua(event string, handler *moonlight.Closure) {
handles := b.handlers[event]
for i, handle := range handles {
@ -169,7 +171,7 @@ func (b *Bait) Once(event string, handler func(...interface{})) *Listener {
}
// OnceLua adds a Lua function listener for an event that only runs once.
func (b *Bait) OnceLua(event string, handler *rt.Closure) *Listener {
func (b *Bait) OnceLua(event string, handler *moonlight.Closure) *Listener {
listener := &Listener{
typ: luaListener,
once: true,

View File

@ -36,19 +36,17 @@ import (
"hilbish/moonlight"
"hilbish/util"
"hilbish/golibs/bait"
rt "github.com/arnodel/golua/runtime"
)
type Commander struct{
Events *bait.Bait
Commands map[string]*rt.Closure
Commands map[string]*moonlight.Closure
}
func New(rtm *moonlight.Runtime) *Commander {
c := &Commander{
Events: bait.New(rtm),
Commands: make(map[string]*rt.Closure),
Commands: make(map[string]*moonlight.Closure),
}
return c
@ -119,7 +117,9 @@ func (c *Commander) cregistry(mlr *moonlight.Runtime, ct *moonlight.GoCont) (moo
registryLua := moonlight.NewTable()
for cmdName, cmd := range c.Commands {
cmdTbl := moonlight.NewTable()
cmdTbl.SetField("exec", rt.FunctionValue(cmd))
//cmdTbl.SetField("exec", moonlight.FunctionValue(cmd))
print(cmd)
cmdTbl.SetField("exec", moonlight.StringValue("placeholder"))
registryLua.SetField(cmdName, moonlight.TableValue(cmdTbl))
}

View File

@ -55,8 +55,8 @@ func (f *fs) Loader(rtm *moonlight.Runtime) moonlight.Value {
mod := moonlight.NewTable()
rtm.SetExports(mod, exports)
mod.SetField("pathSep", rt.StringValue(string(os.PathSeparator)))
mod.SetField("pathListSep", rt.StringValue(string(os.PathListSeparator)))
mod.SetField("pathSep", moonlight.StringValue(string(os.PathSeparator)))
mod.SetField("pathListSep", moonlight.StringValue(string(os.PathListSeparator)))
return moonlight.TableValue(mod)
}
@ -280,7 +280,7 @@ func (f *fs) freaddir(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Co
return nil, err
}
for i, entry := range dirEntries {
names.Set(rt.IntValue(int64(i + 1)), rt.StringValue(entry.Name()))
names.Set(moonlight.IntValue(int64(i + 1)), moonlight.StringValue(entry.Name()))
}
return mlr.PushNext1(c, moonlight.TableValue(names)), nil

View File

@ -7,7 +7,6 @@ import (
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
"golang.org/x/term"
)
@ -37,8 +36,8 @@ func termsize(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, erro
}
dimensions := moonlight.NewTable()
dimensions.Set(rt.StringValue("width"), rt.IntValue(int64(w)))
dimensions.Set(rt.StringValue("height"), rt.IntValue(int64(h)))
dimensions.SetField("width", moonlight.IntValue(int64(w)))
dimensions.SetField("height", moonlight.IntValue(int64(h)))
return mlr.PushNext1(c, moonlight.TableValue(dimensions)), nil
}

View File

@ -7,17 +7,17 @@ import (
"path/filepath"
"strings"
rt "github.com/arnodel/golua/runtime"
"hilbish/moonlight"
)
type luaHistory struct {}
func (h *luaHistory) Write(line string) (int, error) {
histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add"))
ln, err := l.Call1(histWrite, rt.StringValue(line))
histWrite := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("add"))
ln, err := l.Call1(histWrite, moonlight.StringValue(line))
var num int64
if ln.Type() == rt.IntType {
if ln.Type() == moonlight.IntType {
num = ln.AsInt()
}
@ -25,11 +25,11 @@ func (h *luaHistory) Write(line string) (int, error) {
}
func (h *luaHistory) GetLine(idx int) (string, error) {
histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get"))
lcmd, err := l.Call1(histGet, rt.IntValue(int64(idx)))
histGet := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("get"))
lcmd, err := l.Call1(histGet, moonlight.IntValue(int64(idx)))
var cmd string
if lcmd.Type() == rt.StringType {
if lcmd.Type() == moonlight.StringType {
cmd = lcmd.AsString()
}
@ -37,11 +37,11 @@ func (h *luaHistory) GetLine(idx int) (string, error) {
}
func (h *luaHistory) Len() int {
histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size"))
histSize := hshMod.Get(moonlight.StringValue("history")).AsTable().Get(moonlight.StringValue("size"))
ln, _ := l.Call1(histSize)
var num int64
if ln.Type() == rt.IntType {
if ln.Type() == moonlight.IntType {
num = ln.AsInt()
}

4
job.go
View File

@ -261,7 +261,7 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job {
stdout: &bytes.Buffer{},
stderr: &bytes.Buffer{},
}
jb.ud = jobUserData(jb)
//jb.ud = jobUserData(jb)
j.jobs[j.latestID] = jb
hooks.Emit("job.add", rt.UserDataValue(jb.ud))
@ -389,10 +389,12 @@ func valueToJob(val rt.Value) (*job, bool) {
return j, ok
}
/*
func jobUserData(j *job) *rt.UserData {
jobMeta := l.UnderlyingRuntime().Registry(jobMetaKey)
return rt.NewUserData(j, jobMeta.AsTable())
}
*/
// #interface jobs
// get(id) -> @Job

36
lua_exec.go 100644
View File

@ -0,0 +1,36 @@
//go:build !midnight
package main
import (
"fmt"
"hilbish/moonlight"
)
func handleLua(input string) (string, uint8, error) {
cmdString := aliases.Resolve(input)
// First try to load input, essentially compiling to bytecode
rtm := l.UnderlyingRuntime()
chunk, err := rtm.CompileAndLoadLuaChunk("", []byte(cmdString), moonlight.TableValue(l.GlobalTable()))
if err != nil && noexecute {
fmt.Println(err)
/* if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
print(perr.Pos.Line == parse.EOF)
}
}
*/
return cmdString, 125, err
}
// And if there's no syntax errors and -n isnt provided, run
if !noexecute {
if chunk != nil {
_, err = l.Call1(rt.FunctionValue(chunk))
}
}
if err == nil {
return cmdString, 0, nil
}
return cmdString, 125, err
}

View File

@ -0,0 +1,10 @@
//go:build midnight
package main
import (
"errors"
)
func handleLua(input string) (string, uint8, error) {
return "", 7, errors.New("lua input in midnight placeholder")
}

View File

@ -170,12 +170,12 @@ func main() {
}
if getopt.NArgs() > 0 {
luaArgs := rt.NewTable()
luaArgs := moonlight.NewTable()
for i, arg := range getopt.Args() {
luaArgs.Set(rt.IntValue(int64(i)), rt.StringValue(arg))
luaArgs.Set(moonlight.IntValue(int64(i)), moonlight.StringValue(arg))
}
l.GlobalTable().SetField("args", rt.TableValue(luaArgs))
l.GlobalTable().SetField("args", moonlight.TableValue(luaArgs))
err := l.DoFile(getopt.Arg(0))
if err != nil {
fmt.Fprintln(os.Stderr, err)

View File

@ -0,0 +1,28 @@
//go:build midnight
package moonlight
import (
"fmt"
)
type Callable interface{
Continuation(*Runtime, Cont) Cont
}
type Closure struct{
refIdx int // so since we cant store the actual lua closure,
// we need a index to the ref in the lua registry... or something like that.
}
func (mlr *Runtime) ClosureArg(c *GoCont, num int) (*Closure, error) {
fmt.Println("type at ", num, "is", mlr.state.LTypename(num))
return &Closure{
refIdx: -1,
}, nil
}
/*
func (c *Closure) Continuation(mlr *Runtime, c Cont) Cont {
}
*/

View File

@ -0,0 +1,12 @@
//go:build midnight
package moonlight
type GoCont struct{
vals []Value
f GoFunctionFunc
}
type Cont interface{}
func (gc *GoCont) Next() Cont {
return gc
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (
@ -8,6 +9,7 @@ type GoCont struct{
cont *rt.GoCont
thread *rt.Thread
}
type Cont = rt.Cont
type Closure = rt.Closure

View File

@ -0,0 +1,7 @@
package moonlight
type Export struct{
Function GoToLuaFunc
ArgNum int
Variadic bool
}

View File

@ -0,0 +1,8 @@
//go:build midnight
package moonlight
func (mlr *Runtime) SetExports(tbl *Table, exports map[string]Export) {
for name, export := range exports {
tbl.SetField(name, FunctionValue(mlr.GoFunction(export.Function)))
}
}

View File

@ -1,11 +1,6 @@
//go:build !midnight
package moonlight
type Export struct{
Function GoToLuaFunc
ArgNum int
Variadic bool
}
func (mlr *Runtime) SetExports(tbl *Table, exports map[string]Export) {
for name, export := range exports {
mlr.rt.SetEnvGoFunc(tbl.lt, name, mlr.GoFunction(export.Function), export.ArgNum, export.Variadic)

View File

@ -0,0 +1,61 @@
//go:build midnight
package moonlight
import (
"fmt"
"github.com/aarzilli/golua/lua"
)
type GoFunctionFunc struct{
cf lua.LuaGoFunction
}
func (gf GoFunctionFunc) Continuation(mlr *Runtime, c Cont) Cont {
return &GoCont{
f: gf,
vals: []Value{},
}
}
func (mlr *Runtime) CheckNArgs(c *GoCont, num int) error {
args := mlr.state.GetTop()
if args < num {
return fmt.Errorf("%d arguments needed", num)
}
return nil
}
func (mlr *Runtime) Check1Arg(c *GoCont) error {
return mlr.CheckNArgs(c, 1)
}
func (mlr *Runtime) StringArg(c *GoCont, num int) (string, error) {
return mlr.state.CheckString(num + 1), nil
}
func (mlr *Runtime) Arg(c *GoCont, num int) Value {
return c.vals[num]
}
func (mlr *Runtime) GoFunction(fun GoToLuaFunc) GoFunctionFunc {
return GoFunctionFunc{
cf: func(L *lua.State) int {
cont, err := fun(mlr, &GoCont{})
if err != nil {
L.RaiseError(err.Error())
return 0
}
for _, val := range cont.(*GoCont).vals {
switch Type(val) {
case StringType:
L.PushString(val.AsString())
}
}
return len(cont.(*GoCont).vals)
},
}
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (
@ -26,7 +27,7 @@ func (mlr *Runtime) Arg(c *GoCont, num int) Value {
return c.cont.Arg(num)
}
func (mlr *Runtime) GoFunction(fun GoToLuaFunc) rt.GoFunctionFunc {
func (mlr *Runtime) GoFunction(fun GoToLuaFunc) GoFunctionFunc {
return func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
gocont := GoCont{
cont: c,
@ -35,7 +36,3 @@ func (mlr *Runtime) GoFunction(fun GoToLuaFunc) rt.GoFunctionFunc {
return fun(mlr, &gocont)
}
}
func (mlr *Runtime) Call1(val Value, args ...Value) (Value, error) {
return rt.Call1(mlr.rt.MainThread(), val, args...)
}

View File

@ -0,0 +1,21 @@
//go:build midnight
package moonlight
import (
"github.com/aarzilli/golua/lua"
)
type Loader func(*Runtime) Value
func (mlr *Runtime) LoadLibrary(ldr Loader, name string) {
cluaLoader := func (L *lua.State) int {
mlr.pushToState(ldr(mlr))
return 1
}
mlr.state.GetGlobal("package")
mlr.state.GetField(-1, "preload")
mlr.state.PushGoFunction(cluaLoader)
mlr.state.SetField(-2, name)
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (

View File

@ -0,0 +1,49 @@
//go:build midnight
package moonlight
import (
"github.com/aarzilli/golua/lua"
)
type Runtime struct{
state *lua.State
}
func NewRuntime() *Runtime {
L := lua.NewState()
L.OpenLibs()
return &Runtime{
state: L,
}
}
func (mlr *Runtime) PushNext1(c *GoCont, v Value) Cont {
c.vals = []Value{v}
return c
}
func (mlr *Runtime) Call1(f Value, args ...Value) (Value, error) {
for _, arg := range args {
mlr.pushToState(arg)
}
if f.refIdx > 0 {
mlr.state.RawGeti(lua.LUA_REGISTRYINDEX, f.refIdx)
mlr.state.Call(len(args), 1)
}
if mlr.state.GetTop() == 0 {
return NilValue, nil
}
return NilValue, nil
}
func (mlr *Runtime) pushToState(v Value) {
switch v.Type() {
case NilType: mlr.state.PushNil()
case StringType: mlr.state.PushString(v.AsString())
}
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (
@ -42,3 +43,7 @@ func (mlr *Runtime) Push(c *GoCont, v Value) {
func (mlr *Runtime) PushNext1(c *GoCont, v Value) Cont {
return c.cont.PushingNext1(c.thread.Runtime, v)
}
func (mlr *Runtime) Call1(val Value, args ...Value) (Value, error) {
return rt.Call1(mlr.rt.MainThread(), val, args...)
}

View File

@ -0,0 +1,43 @@
//go:build midnight
package moonlight
//import "github.com/aarzilli/golua/lua"
type Table struct{
refIdx int
}
func NewTable() *Table {
return &Table{
refIdx: -1,
}
}
func (t *Table) Get(val Value) Value {
return NilValue
}
func (t *Table) SetField(key string, value Value) {
}
func (t *Table) Set(key Value, value Value) {
}
func ForEach(tbl *Table, cb func(key Value, val Value)) {
}
func (mlr *Runtime) GlobalTable() *Table {
return &Table{
refIdx: -1,
}
}
func ToTable(v Value) *Table {
return &Table{
refIdx: -1,
}
}
func TryTable(v Value) (*Table, bool) {
return nil, false
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (
@ -50,3 +51,9 @@ func convertToMoonlightTable(t *rt.Table) *Table {
lt: t,
}
}
func TryTable(v Value) (*Table, bool) {
t, ok := v.TryTable()
return convertToMoonlightTable(t), ok
}

View File

@ -0,0 +1,12 @@
//go:build midnight
package moonlight
func (mlr *Runtime) DoString(code string) (Value, error) {
err := mlr.state.DoString(code)
return NilValue, err
}
func (mlr *Runtime) DoFile(filename string) error {
return mlr.state.DoFile(filename)
}

View File

@ -1,3 +1,4 @@
//go:build !midnight
package moonlight
import (
@ -9,7 +10,7 @@ import (
)
// DoString runs the code string in the Lua runtime.
func (mlr *Runtime) DoString(code string) (rt.Value, error) {
func (mlr *Runtime) DoString(code string) (Value, error) {
chunk, err := mlr.rt.CompileAndLoadLuaChunk("<string>", []byte(code), rt.TableValue(mlr.rt.GlobalEnv()))
var ret rt.Value
if chunk != nil {

View File

@ -0,0 +1,121 @@
//go:build midnight
package moonlight
type Value struct{
iface interface{}
relIdx int
refIdx int
}
var NilValue = Value{nil, -1, -1}
type ValueType uint8
const (
NilType ValueType = iota
BoolType
IntType
StringType
TableType
FunctionType
UnknownType
)
func Type(v Value) ValueType {
return v.Type()
}
func BoolValue(b bool) Value {
return Value{iface: b}
}
func IntValue(i int64) Value {
return Value{iface: i}
}
func StringValue(str string) Value {
return Value{iface: str}
}
func TableValue(t *Table) Value {
return Value{iface: t}
}
func FunctionValue(f Callable) Value {
return NilValue
}
func AsValue(i interface{}) Value {
if i == nil {
return NilValue
}
switch v := i.(type) {
case bool: return BoolValue(v)
case int64: return IntValue(v)
case string: return StringValue(v)
case *Table: return TableValue(v)
case Value: return v
default:
return Value{iface: i}
}
}
func (v Value) Type() ValueType {
if v.iface == nil {
return NilType
}
switch v.iface.(type) {
case bool: return BoolType
case int: return IntType
case string: return StringType
case *Table: return TableType
case *Closure: return FunctionType
default: return UnknownType
}
}
func (v Value) AsInt() int64 {
return v.iface.(int64)
}
func (v Value) AsString() string {
if v.Type() != StringType {
panic("value type was not string")
}
return v.iface.(string)
}
func (v Value) AsTable() *Table {
panic("Value.AsTable unimplemented in midnight")
}
func ToString(v Value) string {
return v.AsString()
}
func (v Value) TypeName() string {
switch v.iface.(type) {
case bool: return "bool"
case int: return "number"
case string: return "string"
case *Table: return "table"
default: return "<unknown type>"
}
}
func (v Value) TryBool() (n bool, ok bool) {
n, ok = v.iface.(bool)
return
}
func (v Value) TryInt() (n int, ok bool) {
n, ok = v.iface.(int)
return
}
func (v Value) TryString() (n string, ok bool) {
n, ok = v.iface.(string)
return
}

View File

@ -1,17 +1,25 @@
//go:build !midnight
package moonlight
import (
rt "github.com/arnodel/golua/runtime"
)
var NilValue = rt.NilValue
type Value = rt.Value
type ValueType = rt.ValueType
const (
IntType = rt.IntType
StringType = rt.StringType
FunctionType = rt.FunctionType
TableType = rt.TableType
)
func Type(v Value) ValueType {
return ValueType(v.Type())
}
func StringValue(str string) Value {
return rt.StringValue(str)
}
@ -28,10 +36,6 @@ func TableValue(t *Table) Value {
return rt.TableValue(t.lt)
}
func Type(v Value) ValueType {
return ValueType(v.Type())
}
func ToString(v Value) string {
return v.AsString()
}
@ -39,3 +43,7 @@ func ToString(v Value) string {
func ToTable(v Value) *Table {
return convertToMoonlightTable(v.AsTable())
}
func AsValue(v interface{}) Value {
return rt.AsValue(v)
}

7
os.go
View File

@ -4,7 +4,6 @@ import (
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
"github.com/blackfireio/osinfo"
)
@ -19,9 +18,9 @@ func hshosLoader() *moonlight.Table {
info, _ := osinfo.GetOSInfo()
mod := moonlight.NewTable()
mod.SetField("family", rt.StringValue(info.Family))
mod.SetField("name", rt.StringValue(info.Name))
mod.SetField("version", rt.StringValue(info.Version))
mod.SetField("family", moonlight.StringValue(info.Family))
mod.SetField("name", moonlight.StringValue(info.Name))
mod.SetField("version", moonlight.StringValue(info.Version))
return mod
}

99
rl.go
View File

@ -5,6 +5,7 @@ import (
"io"
"strings"
"hilbish/moonlight"
"hilbish/util"
rt "github.com/arnodel/golua/runtime"
@ -70,8 +71,8 @@ func newLineReader(prompt string, noHist bool) *lineReader {
hooks.Emit("hilbish.vimAction", actionStr, args)
}
rl.HintText = func(line []rune, pos int) []rune {
hinter := hshMod.Get(rt.StringValue("hinter"))
retVal, err := l.Call1(hinter, rt.StringValue(string(line)), rt.IntValue(int64(pos)))
hinter := hshMod.Get(moonlight.StringValue("hinter"))
retVal, err := l.Call1(hinter, moonlight.StringValue(string(line)), moonlight.IntValue(int64(pos)))
if err != nil {
fmt.Println(err)
return []rune{}
@ -85,8 +86,8 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return []rune(hintText)
}
rl.SyntaxHighlighter = func(line []rune) string {
highlighter := hshMod.Get(rt.StringValue("highlighter"))
retVal, err := l.Call1(highlighter, rt.StringValue(string(line)))
highlighter := hshMod.Get(moonlight.StringValue("highlighter"))
retVal, err := l.Call1(highlighter, moonlight.StringValue(string(line)))
if err != nil {
fmt.Println(err)
return string(line)
@ -99,93 +100,7 @@ func newLineReader(prompt string, noHist bool) *lineReader {
return highlighted
}
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
term := rt.NewTerminationWith(l.UnderlyingRuntime().MainThread().CurrentCont(), 2, false)
compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler"))
err := rt.Call(l.UnderlyingRuntime().MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
rt.IntValue(int64(pos))}, term)
var compGroups []*readline.CompletionGroup
if err != nil {
return "", compGroups
}
luaCompGroups := term.Get(0)
luaPrefix := term.Get(1)
if luaCompGroups.Type() != rt.TableType {
return "", compGroups
}
groups := luaCompGroups.AsTable()
// prefix is optional
pfx, _ := luaPrefix.TryString()
util.ForEach(groups, func(key rt.Value, val rt.Value) {
if key.Type() != rt.IntType || val.Type() != rt.TableType {
return
}
valTbl := val.AsTable()
luaCompType := valTbl.Get(rt.StringValue("type"))
luaCompItems := valTbl.Get(rt.StringValue("items"))
if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType {
return
}
items := []string{}
itemDescriptions := make(map[string]string)
util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) {
if keytyp := lkey.Type(); keytyp == rt.StringType {
// ['--flag'] = {'description', '--flag-alias'}
itemName, ok := lkey.TryString()
vlTbl, okk := lval.TryTable()
if !ok && !okk {
// TODO: error
return
}
items = append(items, itemName)
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
if !ok {
// TODO: error
return
}
itemDescriptions[itemName] = itemDescription
} else if keytyp == rt.IntType {
vlStr, ok := lval.TryString()
if !ok {
// TODO: error
return
}
items = append(items, vlStr)
} else {
// TODO: error
return
}
})
var dispType readline.TabDisplayType
switch luaCompType.AsString() {
case "grid": dispType = readline.TabDisplayGrid
case "list": dispType = readline.TabDisplayList
// need special cases, will implement later
//case "map": dispType = readline.TabDisplayMap
}
compGroups = append(compGroups, &readline.CompletionGroup{
DisplayType: dispType,
Descriptions: itemDescriptions,
Suggestions: items,
TrimSlash: false,
NoSpace: true,
})
})
return pfx, compGroups
}
setupTabCompleter(rl)
return lr
}
@ -244,11 +159,13 @@ func (lr *lineReader) Resize() {
// method of saving history.
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
lrLua := map[string]util.LuaExport{
/*
"add": {lr.luaAddHistory, 1, false},
"all": {lr.luaAllHistory, 0, false},
"clear": {lr.luaClearHistory, 0, false},
"get": {lr.luaGetHistory, 1, false},
"size": {lr.luaSize, 0, false},
*/
}
mod := rt.NewTable()

10
rl_midnight.go 100644
View File

@ -0,0 +1,10 @@
//go:build midnight
package main
import (
"github.com/maxlandon/readline"
)
func setupTabCompleter(rl *readline.Instance) {
// TODO
}

97
rl_notmidnight.go 100644
View File

@ -0,0 +1,97 @@
//go:build !midnight
package main
import (
rt "github.com/arnodel/golua/runtime"
"github.com/maxlandon/readline"
)
func setupTabCompleter(rl *readline.Instance) {
rl.TabCompleter = func(line []rune, pos int, _ readline.DelayedTabContext) (string, []*readline.CompletionGroup) {
term := rt.NewTerminationWith(l.UnderlyingRuntime().MainThread().CurrentCont(), 2, false)
compHandle := hshMod.Get(rt.StringValue("completion")).AsTable().Get(rt.StringValue("handler"))
err := rt.Call(l.UnderlyingRuntime().MainThread(), compHandle, []rt.Value{rt.StringValue(string(line)),
rt.IntValue(int64(pos))}, term)
var compGroups []*readline.CompletionGroup
if err != nil {
return "", compGroups
}
luaCompGroups := term.Get(0)
luaPrefix := term.Get(1)
if luaCompGroups.Type() != rt.TableType {
return "", compGroups
}
groups := luaCompGroups.AsTable()
// prefix is optional
pfx, _ := luaPrefix.TryString()
util.ForEach(groups, func(key rt.Value, val rt.Value) {
if key.Type() != rt.IntType || val.Type() != rt.TableType {
return
}
valTbl := val.AsTable()
luaCompType := valTbl.Get(rt.StringValue("type"))
luaCompItems := valTbl.Get(rt.StringValue("items"))
if luaCompType.Type() != rt.StringType || luaCompItems.Type() != rt.TableType {
return
}
items := []string{}
itemDescriptions := make(map[string]string)
util.ForEach(luaCompItems.AsTable(), func(lkey rt.Value, lval rt.Value) {
if keytyp := lkey.Type(); keytyp == rt.StringType {
// ['--flag'] = {'description', '--flag-alias'}
itemName, ok := lkey.TryString()
vlTbl, okk := lval.TryTable()
if !ok && !okk {
// TODO: error
return
}
items = append(items, itemName)
itemDescription, ok := vlTbl.Get(rt.IntValue(1)).TryString()
if !ok {
// TODO: error
return
}
itemDescriptions[itemName] = itemDescription
} else if keytyp == rt.IntType {
vlStr, ok := lval.TryString()
if !ok {
// TODO: error
return
}
items = append(items, vlStr)
} else {
// TODO: error
return
}
})
var dispType readline.TabDisplayType
switch luaCompType.AsString() {
case "grid": dispType = readline.TabDisplayGrid
case "list": dispType = readline.TabDisplayList
// need special cases, will implement later
//case "map": dispType = readline.TabDisplayMap
}
compGroups = append(compGroups, &readline.CompletionGroup{
DisplayType: dispType,
Descriptions: itemDescriptions,
Suggestions: items,
TrimSlash: false,
NoSpace: true,
})
})
return pfx, compGroups
}
}

View File

@ -2,8 +2,6 @@ package main
import (
"hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
// #interface runner
@ -86,13 +84,13 @@ func shRunner(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, erro
}
_, exitCode, cont, err := execSh(aliases.Resolve(cmd))
var luaErr moonlight.Value = rt.NilValue
var luaErr moonlight.Value = moonlight.NilValue
if err != nil {
luaErr = moonlight.StringValue(err.Error())
}
runnerRet := moonlight.NewTable()
runnerRet.SetField("input", moonlight.StringValue(cmd))
runnerRet.SetField("exitCode", moonlight.IntValue(int(exitCode)))
runnerRet.SetField("exitCode", moonlight.IntValue(int64(exitCode)))
runnerRet.SetField("continue", moonlight.BoolValue(cont))
runnerRet.SetField("err", luaErr)
@ -114,13 +112,13 @@ func luaRunner(mlr *moonlight.Runtime, c *moonlight.GoCont) (moonlight.Cont, err
}
input, exitCode, err := handleLua(cmd)
var luaErr moonlight.Value = rt.NilValue
var luaErr moonlight.Value = moonlight.NilValue
if err != nil {
luaErr = moonlight.StringValue(err.Error())
}
runnerRet := moonlight.NewTable()
runnerRet.SetField("input", moonlight.StringValue(input))
runnerRet.SetField("exitCode", moonlight.IntValue(int(exitCode)))
runnerRet.SetField("exitCode", moonlight.IntValue(int64(exitCode)))
runnerRet.SetField("err", luaErr)

View File

@ -220,7 +220,7 @@ func newSinkInput(r io.Reader) *sink {
s := &sink{
reader: bufio.NewReader(r),
}
s.ud = sinkUserData(s)
//s.ud = sinkUserData(s)
if f, ok := r.(*os.File); ok {
s.file = f
@ -234,7 +234,7 @@ func newSinkOutput(w io.Writer) *sink {
writer: bufio.NewWriter(w),
autoFlush: true,
}
s.ud = sinkUserData(s)
//s.ud = sinkUserData(s)
return s
}
@ -258,7 +258,9 @@ func valueToSink(val rt.Value) (*sink, bool) {
return s, ok
}
/*
func sinkUserData(s *sink) *rt.UserData {
sinkMeta := l.UnderlyingRuntime().Registry(sinkMetaKey)
return rt.NewUserData(s, sinkMeta.AsTable())
}
*/

View File

@ -2,10 +2,12 @@ package main
import (
"errors"
"fmt"
"os"
// "fmt"
// "os"
"time"
// "hilbish/moonlight"
rt "github.com/arnodel/golua/runtime"
)
@ -47,7 +49,8 @@ func (t *timer) start() error {
for {
select {
case <-t.ticker.C:
_, err := l.Call1(rt.FunctionValue(t.fun))
/*
_, err := l.Call1(moonlight.FunctionValue(t.fun))
if err != nil {
fmt.Fprintln(os.Stderr, "Error in function:\n", err)
t.stop()
@ -56,6 +59,7 @@ func (t *timer) start() error {
if t.typ == timerTimeout {
t.stop()
}
*/
case <-t.channel:
t.ticker.Stop()
return

View File

@ -48,7 +48,7 @@ func (th *timersModule) create(typ timerType, dur time.Duration, fun *rt.Closure
th: th,
id: th.latestID,
}
t.ud = timerUserData(t)
//t.ud = timerUserData(t)
th.timers[th.latestID] = t
@ -144,6 +144,7 @@ func (th *timersModule) loader() *moonlight.Table {
}
l.SetExports(timerMethods, timerFuncs)
/*
timerMeta := rt.NewTable()
timerIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
ti, _ := timerArg(c, 0)
@ -168,6 +169,7 @@ func (th *timersModule) loader() *moonlight.Table {
timerMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(timerIndex, "__index", 2, false)))
l.UnderlyingRuntime().SetRegistry(timerMetaKey, rt.TableValue(timerMeta))
*/
thExports := map[string]moonlight.Export{
/*
@ -179,8 +181,8 @@ func (th *timersModule) loader() *moonlight.Table {
luaTh := moonlight.NewTable()
l.SetExports(luaTh, thExports)
luaTh.SetField("INTERVAL", rt.IntValue(0))
luaTh.SetField("TIMEOUT", rt.IntValue(1))
luaTh.SetField("INTERVAL", moonlight.IntValue(0))
luaTh.SetField("TIMEOUT", moonlight.IntValue(1))
return luaTh
}
@ -204,7 +206,9 @@ func valueToTimer(val rt.Value) (*timer, bool) {
return j, ok
}
/*
func timerUserData(j *timer) *rt.UserData {
timerMeta := l.UnderlyingRuntime().Registry(timerMetaKey)
return rt.NewUserData(j, timerMeta.AsTable())
}
*/

View File

@ -2,9 +2,6 @@ package main
import (
"hilbish/moonlight"
//"hilbish/util"
rt "github.com/arnodel/golua/runtime"
)
// #interface userDir
@ -17,8 +14,8 @@ import (
func userDirLoader() *moonlight.Table {
mod := moonlight.NewTable()
mod.SetField("config", rt.StringValue(confDir))
mod.SetField("data", rt.StringValue(userDataDir))
mod.SetField("config", moonlight.StringValue(confDir))
mod.SetField("data", moonlight.StringValue(userDataDir))
return mod
}

View File

@ -15,7 +15,9 @@ type LuaExport struct {
// SetExports puts the Lua function exports in the table.
func SetExports(rtm *rt.Runtime, tbl *rt.Table, exports map[string]LuaExport) {
/*
for name, export := range exports {
rtm.SetEnvGoFunc(tbl, name, export.Function, export.ArgNum, export.Variadic)
}
*/
}