Skip to content

Commit

Permalink
#17 goroutine
Browse files Browse the repository at this point in the history
  • Loading branch information
xushiwei committed Apr 3, 2016
1 parent 02c60fb commit 3913906
Show file tree
Hide file tree
Showing 16 changed files with 404 additions and 74 deletions.
31 changes: 30 additions & 1 deletion README.md
Expand Up @@ -454,7 +454,7 @@ defer f.close()

所谓匿名函数,是指:

```
```go
fn {
... // 一段复杂代码
}
Expand Down Expand Up @@ -528,6 +528,35 @@ foo = new Foo(3, "hello")
println(foo.a) // 输出 3
```

## goroutine

和 Go 语言一样,qlang 中通过 go 关键字启动一个新的 goroutine。如:

```go
go println("this is a goroutine")
```

一个比较复杂的例子:

```go
wg = sync.waitGroup()
wg.add(2)

go fn {
defer wg.done()
println("in goroutine1")
}

go fn {
defer wg.done()
println("in goroutine2")
}

wg.wait()
```

这是一个经典的 goroutine 使用场景,把一个 task 分为 2 个子 task,交给 2 个 goroutine 执行。


## include

Expand Down
1 change: 1 addition & 0 deletions exec.v2/code.go
Expand Up @@ -166,6 +166,7 @@ type Context struct {
export []string
ip int
base int
onsel bool // on select
}

func NewContext() *Context {
Expand Down
55 changes: 55 additions & 0 deletions exec.v2/goroutine.go
@@ -0,0 +1,55 @@
package exec

import (
"qlang.io/qlang.spec.v1"
)

// -----------------------------------------------------------------------------

type iGo struct {
start int
end int
}

func (p *iGo) Exec(stk *Stack, ctx *Context) {

go func() {
fn := NewFunction(nil, p.start, p.end, nil, false)
fn.parent = ctx
fn.ExtCall(nil)
}()
stk.Push(nil)
}

func Go(start, end int) Instr {

return &iGo{start, end}
}

// -----------------------------------------------------------------------------

type iChanIn int
type iChanOut int

func (p iChanIn) Exec(stk *Stack, ctx *Context) {

v, _ := stk.Pop()
ch, _ := stk.Pop()
ret := qlang.ChanIn(ch, v, ctx.onsel)
stk.Push(ret)
}

func (p iChanOut) Exec(stk *Stack, ctx *Context) {

ch, _ := stk.Pop()
ret := qlang.ChanOut(ch, ctx.onsel)
stk.Push(ret)
}

var (
ChanIn Instr = iChanIn(0)
ChanOut Instr = iChanOut(0)
)

// -----------------------------------------------------------------------------

10 changes: 10 additions & 0 deletions qlang.spec.v1/spec.go
Expand Up @@ -33,9 +33,19 @@ func dummySet(m interface{}, args ...interface{}) {
panic("function not implemented")
}

func dummyChanIn(ch, val interface{}, try bool) interface{} {
panic("operator ch<-value not implemented")
}

func dummyChanOut(ch interface{}, try bool) interface{} {
panic("operator <-ch not implemented")
}

var (
fnDummy1 = reflect.ValueOf(dummy1).Pointer()
fnDummy2 = reflect.ValueOf(dummy2).Pointer()
ChanIn = dummyChanIn
ChanOut = dummyChanOut
Set = dummySet
MapFrom = dummyN
SliceFrom = dummyN
Expand Down
66 changes: 0 additions & 66 deletions qlang.v2/function2.go
Expand Up @@ -7,72 +7,6 @@ import (

// -----------------------------------------------------------------------------

func (p *Compiler) Clear() {

p.code.Block(exec.Clear)
}

func (p *Compiler) Unset(name string) {

p.code.Block(exec.Unset(name))
}

func (p *Compiler) Inc(name string) {

p.code.Block(exec.Inc(name))
}

func (p *Compiler) Dec(name string) {

p.code.Block(exec.Dec(name))
}

func (p *Compiler) AddAssign(name string) {

p.code.Block(exec.AddAssign(name))
}

func (p *Compiler) SubAssign(name string) {

p.code.Block(exec.SubAssign(name))
}

func (p *Compiler) MulAssign(name string) {

p.code.Block(exec.MulAssign(name))
}

func (p *Compiler) QuoAssign(name string) {

p.code.Block(exec.QuoAssign(name))
}

func (p *Compiler) ModAssign(name string) {

p.code.Block(exec.ModAssign(name))
}

func (p *Compiler) MultiAssign() {

arity := p.popArity() + 1
names := p.gstk.PopFnArgs(arity)
p.code.Block(exec.MultiAssign(names))
}

func (p *Compiler) Assign(name string) {

p.code.Block(exec.Assign(name))
}

func (p *Compiler) Ref(name string) {

if val, ok := p.gvars[name]; ok {
p.code.Block(exec.Push(val))
} else {
p.code.Block(exec.Ref(name))
}
}

func (p *Compiler) Function(e interpreter.Engine) {

fnb, _ := p.gstk.Pop()
Expand Down
33 changes: 33 additions & 0 deletions qlang.v2/goroutine2.go
@@ -0,0 +1,33 @@
package qlang

import (
"qlang.io/exec.v2"
"qiniupkg.com/text/tpl.v1/interpreter.util"
)

// -----------------------------------------------------------------------------

func (p *Compiler) Go(e interpreter.Engine) {

src, _ := p.gstk.Pop()
instr := p.code.Reserve()
p.exits = append(p.exits, func() {
start, end := p.cl(e, "expr", src)
instr.Set(exec.Go(start, end))
})
}

// -----------------------------------------------------------------------------

func (p *Compiler) ChanIn() {

p.code.Block(exec.ChanIn)
}

func (p *Compiler) ChanOut() {

p.code.Block(exec.ChanOut)
}

// -----------------------------------------------------------------------------

52 changes: 52 additions & 0 deletions qlang.v2/goroutine_test.go
@@ -0,0 +1,52 @@
package qlang_test

import (
"testing"

_ "qlang.io/qlang/builtin"
"qlang.io/qlang/sync"
"qlang.io/qlang.v2/qlang"
)

// -----------------------------------------------------------------------------

const testGoroutineCode = `
wg = sync.waitGroup()
wg.add(2)
x = 1
go fn {
defer wg.done()
x; x++
}
go fn {
defer wg.done()
x; x++
}
wg.wait()
`

func TestGoroutine(t *testing.T) {

lang, err := qlang.New(qlang.InsertSemis)
if err != nil {
t.Fatal("qlang.New:", err)
}
qlang.Import("sync", sync.Exports)

err = lang.SafeExec([]byte(testGoroutineCode), "")
if err != nil {
t.Fatal("qlang.SafeExec:", err)
}
if v, ok := lang.Var("x"); !ok || v != 3 {
t.Fatal("x != 3, x =", v)
}
}

// -----------------------------------------------------------------------------


39 changes: 35 additions & 4 deletions qlang.v2/qlang/engine2.go
Expand Up @@ -32,18 +32,18 @@ func SetFindEntry(fn func(file string, libs []string) (string, error)) {

type Qlang struct {
*exec.Context
cl *qlangv2.Compiler
options *Options
cl *qlangv2.Compiler
}

func New(options *Options) (lang *Qlang, err error) {

cl := qlangv2.New()
cl.Opts = (*interpreter.Options)(options)
stk := exec.NewStack()
ctx := exec.NewContext()
ctx.Stack = stk
ctx.Code = cl.Code()
return &Qlang{ctx, cl, options}, nil
return &Qlang{ctx, cl}, nil
}

func (p *Qlang) SetLibs(libs string) {
Expand Down Expand Up @@ -101,6 +101,23 @@ func (p *Qlang) Exec(codeText []byte, fname string) (err error) {
return
}

func (p *Qlang) Eval(expr string) (err error) {

code := p.cl.Code()
start := code.Len()
end, err := p.Cl([]byte(expr), "")
if err != nil {
return
}

if DumpCode {
code.Dump()
}

code.Exec(start, end, p.Stack, p.Context)
return
}

func (p *Qlang) SafeExec(code []byte, fname string) (err error) {

defer func() {
Expand All @@ -122,7 +139,21 @@ func (p *Qlang) SafeExec(code []byte, fname string) (err error) {

func (p *Qlang) SafeEval(expr string) (err error) {

return p.SafeExec([]byte(expr), "")
defer func() {
if e := recover(); e != nil {
switch v := e.(type) {
case string:
err = errors.New(v)
case error:
err = v
default:
panic(e)
}
}
}()

err = p.Eval(expr)
return
}

func Import(mod string, table map[string]interface{}) {
Expand Down
9 changes: 8 additions & 1 deletion qlang.v2/qlang2.go
Expand Up @@ -18,7 +18,9 @@ term1 = factor *('*' factor/mul | '/' factor/quo | '%' factor/mod)
term2 = term1 *('+' term1/add | '-' term1/sub)
term3 = term2 *('<' term2/lt | '>' term2/gt | "==" term2/eq | "<=" term2/le | ">=" term2/ge | "!=" term2/ne)
term31 = term2 *('<' term2/lt | '>' term2/gt | "==" term2/eq | "<=" term2/le | ">=" term2/ge | "!=" term2/ne)
term3 = term31 *("<-" term31/chin)
term4 = term3 *("&&"/_mute term3/_code/_unmute/and)
Expand All @@ -39,6 +41,7 @@ s = (
"import"! (STRING ?("as" IDENT/name)/ARITY)/import |
"export"! IDENT/name % ','/ARITY /export |
"defer"/_mute! expr/_code/_unmute/defer |
"go"/_mute! expr/_code/_unmute/go |
expr)/xline
doc = s *(';'/clear s | ';'/pushn)
Expand Down Expand Up @@ -79,6 +82,7 @@ factor =
'{'! (expr ':' expr) %= ','/ARITY ?',' '}'/map |
'!' factor/not |
'-' factor/neg |
"<-" factor/chout |
'+' factor
`

Expand Down Expand Up @@ -220,6 +224,9 @@ var exports = map[string]interface{}{
"$quoa": (*Compiler).QuoAssign,
"$moda": (*Compiler).ModAssign,
"$defer": (*Compiler).Defer,
"$go": (*Compiler).Go,
"$chin": (*Compiler).ChanIn,
"$chout": (*Compiler).ChanOut,
"$recover": (*Compiler).Recover,
"$return": (*Compiler).Return,
"$fn": (*Compiler).Function,
Expand Down

0 comments on commit 3913906

Please sign in to comment.