Skip to content

Commit

Permalink
Merge pull request #8 from zhulik/refactoring
Browse files Browse the repository at this point in the history
Refactoring and improvements
  • Loading branch information
zhulik authored Aug 6, 2024
2 parents 21d591e + ed0adc5 commit 9448ca0
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 139 deletions.
9 changes: 7 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
golang: ["1.22"]
golang:
- "1.21"
- "1.22"

steps:
- uses: actions/checkout@v4
Expand All @@ -52,4 +54,7 @@ jobs:

build:
runs-on: ubuntu-latest
needs: [lint, test]
needs: [lint, test]
steps:
- name: Build
run: echo "Done"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

.vscode/
build_config.rb
libmruby.a
mruby-build
Expand Down
14 changes: 0 additions & 14 deletions args.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package gruby

import "sync"

// #include "gruby.h"
import "C"

Expand Down Expand Up @@ -40,15 +38,3 @@ func ArgsReq(n int) ArgSpec {
func ArgsOpt(n int) ArgSpec {
return ArgSpec(C._go_MRB_ARGS_OPT(C.int(n)))
}

// The global accumulator when Mrb.GetArgs is called. There is a
// global lock around this so that the access to it is safe.
var (
getArgAccumulator []C.mrb_value //nolint:gochecknoglobals
getArgLock = new(sync.Mutex) //nolint:gochecknoglobals
)

//export goGetArgAppend
func goGetArgAppend(v C.mrb_value) {
getArgAccumulator = append(getArgAccumulator, v)
}
2 changes: 1 addition & 1 deletion class.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c *Class) New(args ...Value) (Value, error) {
}

result := C.mrb_obj_new(c.Mrb().state, c.class, C.mrb_int(len(argv)), argvPtr)
if exc := checkException(c.Mrb().state); exc != nil {
if exc := checkException(c.Mrb()); exc != nil {
return nil, exc
}

Expand Down
5 changes: 2 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,20 @@ import (

"github.com/chzyer/readline"
"github.com/k0kubun/pp"

"github.com/zhulik/gruby"
)

func main() {
grb := gruby.NewMrb()
defer grb.Close()

wd, err := os.Getwd()
workDir, err := os.Getwd()
if err != nil {
panic(err)
}

ctx := gruby.NewCompileContext(grb)
ctx.SetFilename(path.Join(wd, "main.rb"))
ctx.SetFilename(path.Join(workDir, "main.rb"))
defer ctx.Close()

rln, err := readline.New(">> ")
Expand Down
78 changes: 11 additions & 67 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ package gruby
import "C"

import (
"fmt"
"sync"
"unsafe"
)

Expand All @@ -18,104 +16,50 @@ import (
// The second return value is an exception, if any. This will be raised.
type Func func(m *GRuby, self Value) (Value, Value)

type (
classMethodMap map[*C.struct_RClass]*methods
methodMap map[C.mrb_sym]Func
stateMethodMap map[*C.mrb_state]*classMethods
)

type classMethods struct {
Map classMethodMap
Mutex *sync.Mutex
}

type methods struct {
Map methodMap
Mutex *sync.Mutex
}

type stateMethods struct {
Map stateMethodMap
Mutex *sync.Mutex
}

// stateMethodTable is the lookup table for methods that we define in Go and
// expose in Ruby. This is cleaned up by Mrb.Close.
var stateMethodTable = &stateMethods{ //nolint:gochecknoglobals
Mutex: new(sync.Mutex),
Map: make(stateMethodMap),
}

//export goMRBFuncCall
func goMRBFuncCall(state *C.mrb_state, value C.mrb_value) C.mrb_value {
// Lookup the classes that we've registered methods for in this state
stateMethodTable.Mutex.Lock()
classTable := stateMethodTable.Map[state]
stateMethodTable.Mutex.Unlock()
if classTable == nil {
panic(fmt.Sprintf("func call from unknown state: %p", state))
}

grb := states.Get(state)
// Get the call info, which we use to lookup the proc
callInfo := state.c.ci

// Lookup the class itself
classTable.Mutex.Lock()

class := *(**C.struct_RClass)(unsafe.Pointer(&callInfo.u[0]))
methodTable := classTable.Map[class]
classTable.Mutex.Unlock()
methodTable := grb.classes[class]
if methodTable == nil {
panic("func call on unknown class")
}

// Lookup the method
methodTable.Mutex.Lock()
method := methodTable.Map[callInfo.mid]
methodTable.Mutex.Unlock()
method := methodTable[callInfo.mid]
if method == nil {
panic("func call on unknown method")
}

// Call the method to get our *Value
// TODO(mitchellh): reuse the Mrb instead of allocating every time
mrb := &GRuby{state}
result, exc := method(mrb, mrb.value(value))
result, exc := method(grb, grb.value(value))

if result == nil {
result = mrb.NilValue()
result = grb.NilValue()
}

if exc != nil {
state.exc = C._go_mrb_getobj(exc.CValue())
return mrb.NilValue().CValue()
return grb.NilValue().CValue()
}

return result.CValue()
}

func insertMethod(state *C.mrb_state, class *C.struct_RClass, name string, callback Func) {
stateMethodTable.Mutex.Lock()
classLookup := stateMethodTable.Map[state]
if classLookup == nil {
classLookup = &classMethods{Map: make(classMethodMap), Mutex: new(sync.Mutex)}
stateMethodTable.Map[state] = classLookup
}
stateMethodTable.Mutex.Unlock()

classLookup.Mutex.Lock()
methodLookup := classLookup.Map[class]
grb := states.Get(state)
methodLookup := grb.classes[class]
if methodLookup == nil {
methodLookup = &methods{Map: make(methodMap), Mutex: new(sync.Mutex)}
classLookup.Map[class] = methodLookup
methodLookup = make(methodMap)
grb.classes[class] = methodLookup
}
classLookup.Mutex.Unlock()

cstr := C.CString(name)
defer C.free(unsafe.Pointer(cstr))

sym := C.mrb_intern_cstr(state, cstr)
methodLookup.Mutex.Lock()
methodLookup.Map[sym] = callback
methodLookup.Mutex.Unlock()
methodLookup[sym] = callback
}
Loading

0 comments on commit 9448ca0

Please sign in to comment.