Skip to content

Commit

Permalink
Merge branch 'master' into tadpole_to_match
Browse files Browse the repository at this point in the history
  • Loading branch information
st0012 committed Mar 1, 2020
2 parents b6e5979 + 7ec45dd commit 73fad60
Show file tree
Hide file tree
Showing 49 changed files with 879 additions and 478 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ profile.out
.tmp_benchmarks
.tmp_benchmark_comparison

vm/plugins
/plugins
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,35 @@ require 'net/http'



## To Run Tests

If you want to run Go tests, you can run:

```
$ go test PKG_NAME -run TestName
```

For example, this will run any tests in the `vm` package that matches `TestIncludeFail` with their names:

```
$ go test ./vm -run TestIncludeFail
```

You can run `go help test` to see more options.

And if you want to run Goby tests, you can use:

```
$ goby test specs
```

or if you want to test it against your latest changes in Goby source code, you can use

```
$ go run goby.go test specs
```

But we haven't support running single Goby test at the moment (contribution is welcomed 😉).



1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ install:
.PHONY: test
test:
go test $(TEST_OPTIONS) ./...
make clean

.PHONY: clean
clean:
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
=========

[![](https://goby-slack-invite.herokuapp.com/badge.svg)](https://goby-slack-invite.herokuapp.com)
[![Discord](https://img.shields.io/discord/678892628955103232?label=discord)](https://discord.gg/SS5HbYN)
[![Build Status](https://travis-ci.org/goby-lang/goby.svg?branch=master)](https://travis-ci.org/goby-lang/goby)
[![GoDoc](https://godoc.org/github.com/goby-lang/goby?status.svg)](https://godoc.org/github.com/goby-lang/goby)
[![Go Report Card](https://goreportcard.com/badge/github.com/goby-lang/goby)](https://goreportcard.com/report/github.com/goby-lang/goby)
Expand All @@ -13,10 +14,9 @@

**Goby** is an object-oriented interpreter language deeply inspired by **Ruby** as well as its core implementation by 100% pure **Go**. Moreover, it has standard libraries to provide several features such as the Plugin system. Note that we do not intend to reproduce whole of the honorable works of Ruby syntax/implementation/libraries.

One of our goal is to provide web developers a sort of small and handy environment that mainly focusing on creating **API servers or microservices**. For this, Goby includes the following native features:
The expected use case for Goby would be backend development. With this goal, it equips (but not limited to) the following features:

- Robust thread/channel mechanism powered by Go's goroutine
- Builtin high-performance HTTP server
- thread/channel mechanism powered by Go's goroutine
- Builtin database library (currently only support PostgreSQL adapter)
- JSON support
- [Plugin system](https://goby-lang.gitbooks.io/goby/content/plugin-system.html) that can load existing Go packages dynamically (Only for Linux and MacOS right now)
Expand Down Expand Up @@ -177,7 +177,6 @@ See the [guideline](https://github.com/goby-lang/goby/blob/master/CONTRIBUTING.m
- @st0012
- @hachi8833
- @saveriomiroddi
- @ear7h

## Designer
- [steward379](https://dribbble.com/steward379)
Expand Down Expand Up @@ -234,13 +233,12 @@ Support us with a monthly donation and help us continue our activities. [[Become

### Powered by

* JetBrains [Goland IDE](https://www.jetbrains.com/go/)
* JetBrains [Goland IDE](https://www.jetbrains.com/go/?from=goby)

[![JetBrains Goland](https://github.com/goby-lang/goby/blob/master/wiki/goland_logo-text.png)](https://www.jetbrains.com/go/)
[![JetBrains Goland](https://github.com/goby-lang/goby/blob/master/wiki/goland_logo-text.png)](https://www.jetbrains.com/go/?from=goby)

**Supporting Goby by sending your first PR! See [contribution guideline](https://github.com/goby-lang/goby/blob/master/CONTRIBUTING.md)**

**Or [support us on opencollective](https://opencollective.com/goby)**

## References

Expand Down
114 changes: 57 additions & 57 deletions cmd/binder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/fatih/camelcase"

// makes writing this easier
. "github.com/dave/jennifer/jen"
"github.com/dave/jennifer/jen"
)

var (
Expand Down Expand Up @@ -85,12 +85,12 @@ type Binding struct {

}

func (b *Binding) topCommentBlock() Code {
return Add(
Comment("DO NOT EDIT THIS FILE MANUALLY"),
Line(),
Commentf("This code has been generated by github.com/goby-lang/goby/cmd/binder"),
Line(),
func (b *Binding) topCommentBlock() jen.Code {
return jen.Add(
jen.Comment("DO NOT EDIT THIS FILE MANUALLY"),
jen.Line(),
jen.Commentf("This code has been generated by github.com/goby-lang/goby/cmd/binder"),
jen.Line(),
)

}
Expand All @@ -104,10 +104,10 @@ func (b *Binding) bindingName(f *ast.FuncDecl) string {
}

// BindMethods generates code that binds methods of a go structure to a goby class
func (b *Binding) BindMethods(f *File, x *ast.File) {
func (b *Binding) BindMethods(f *jen.File, x *ast.File) {
f.Add(b.topCommentBlock())
f.Add(mapping(b, x.Name.Name))
f.Var().Id(b.staticName()).Op("=").New(Id(b.ClassName))
f.Var().Id(b.staticName()).Op("=").New(jen.Id(b.ClassName))
for _, c := range b.ClassMethods {
f.Commentf("%s is a class method binding for %s.%s", b.bindingName(c), b.ClassName, c.Name.Name)
b.BindClassMethod(f, c)
Expand All @@ -122,108 +122,108 @@ func (b *Binding) BindMethods(f *File, x *ast.File) {

// BindClassMethod will generate class method bindings.
// This is a global static method associated with the class.
func (b *Binding) BindClassMethod(f *File, d *ast.FuncDecl) {
r := Id("r").Op(":=").Id(b.staticName()).Line()
func (b *Binding) BindClassMethod(f *jen.File, d *ast.FuncDecl) {
r := jen.Id("r").Op(":=").Id(b.staticName()).Line()
b.body(r, f, d)
}

// BindInstanceMethod will generate instance method bindings.
// This function will be bound to a spesific instantation of a goby class.
func (b *Binding) BindInstanceMethod(f *File, d *ast.FuncDecl) {
r := List(Id("r"), Id("ok")).Op(":=").Add(Id("receiver")).Assert(Op("*").Id(b.ClassName)).Line()
r = r.If(Op("!").Id("ok")).Block(
Panic(
Qual("fmt", "Sprintf").Call(Lit("Impossible receiver type. Wanted "+b.ClassName+" got %s"), Id("receiver")),
func (b *Binding) BindInstanceMethod(f *jen.File, d *ast.FuncDecl) {
r := jen.List(jen.Id("r"), jen.Id("ok")).Op(":=").Add(jen.Id("receiver")).Assert(jen.Op("*").Id(b.ClassName)).Line()
r = r.If(jen.Op("!").Id("ok")).Block(
jen.Panic(
jen.Qual("fmt", "Sprintf").Call(jen.Lit("Impossible receiver type. Wanted "+b.ClassName+" got %s"), jen.Id("receiver")),
),
).Line()
b.body(r, f, d)
}

func wrongArgNum(want int) Code {
return Return(Id("t").Dot("VM").Call().Dot("InitErrorObject").Call(
Qual(errorsPkg, "ArgumentError"),
Id("line"),
Qual(errorsPkg, "WrongNumberOfArgumentFormat"),
Lit(want),
Id("len").Call(Id("args")),
func wrongArgNum(want int) jen.Code {
return jen.Return(jen.Id("t").Dot("VM").Call().Dot("InitErrorObject").Call(
jen.Qual(errorsPkg, "ArgumentError"),
jen.Id("line"),
jen.Qual(errorsPkg, "WrongNumberOfArgumentFormat"),
jen.Lit(want),
jen.Id("len").Call(jen.Id("args")),
))
}

func wrongArgType(name, want string) Code {
return Return(Id("t").Dot("VM").Call().Dot("InitErrorObject").Call(
Qual(errorsPkg, "TypeError"),
Id("line"),
Qual(errorsPkg, "WrongArgumentTypeFormat"),
Lit(want),
Id(name).Dot("Class").Call().Dot("Name"),
func wrongArgType(name, want string) jen.Code {
return jen.Return(jen.Id("t").Dot("VM").Call().Dot("InitErrorObject").Call(
jen.Qual(errorsPkg, "TypeError"),
jen.Id("line"),
jen.Qual(errorsPkg, "WrongArgumentTypeFormat"),
jen.Lit(want),
jen.Id(name).Dot("Class").Call().Dot("Name"),
))
}

// body is a helper function for generating the common body of a method
func (b *Binding) body(receiver *Statement, f *File, d *ast.FuncDecl) {
func (b *Binding) body(receiver *jen.Statement, f *jen.File, d *ast.FuncDecl) {
s := f.Func().Id(b.bindingName(d))
s = s.Params(
Id("receiver").Qual(vmPkg, "Object"),
Id("line").Id("int"),
Id("t").Op("*").Qual(vmPkg, "Thread"),
Id("args").Index().Qual(vmPkg, "Object"),
jen.Id("receiver").Qual(vmPkg, "Object"),
jen.Id("line").Id("int"),
jen.Id("t").Op("*").Qual(vmPkg, "Thread"),
jen.Id("args").Index().Qual(vmPkg, "Object"),
).Qual(vmPkg, "Object")

var args []*Statement
var args []*jen.Statement
for i, a := range allArgs(d.Type.Params) {
if i == 0 {
continue
}
i--
c := List(Id(fmt.Sprintf("arg%d", i)), Id("ok")).Op(":=").Id("args").Index(Lit(i)).Assert(Id(a.kind))
c := jen.List(jen.Id(fmt.Sprintf("arg%d", i)), jen.Id("ok")).Op(":=").Id("args").Index(jen.Lit(i)).Assert(jen.Id(a.kind))
c = c.Line()
c = c.If(Op("!").Id("ok")).Block(
c = c.If(jen.Op("!").Id("ok")).Block(
wrongArgType(fmt.Sprintf("args[%d]", i), a.kind),
).Line()
args = append(args, c)
}

inner := receiver.If(Len(Id("args")).Op("!=").Lit(d.Type.Params.NumFields() - 1)).Block(
inner := receiver.If(jen.Len(jen.Id("args")).Op("!=").Lit(d.Type.Params.NumFields() - 1)).Block(
wrongArgNum(d.Type.Params.NumFields() - 1),
).Line()
argNames := []Code{
Id("t"),
argNames := []jen.Code{
jen.Id("t"),
}
for i, a := range args {
inner = inner.Add(a).Line()
argNames = append(argNames, Id(fmt.Sprintf("arg%d", i)))
argNames = append(argNames, jen.Id(fmt.Sprintf("arg%d", i)))
}

inner = inner.Return(Id("r").Dot(d.Name.Name).Call(argNames...))
inner = inner.Return(jen.Id("r").Dot(d.Name.Name).Call(argNames...))
s.Block(inner)
}

// mapping generates the "init" portion of the bindings.
// This will call hooks in the vm package to load the class definition at runtime.
func mapping(b *Binding, pkg string) Code {
func mapping(b *Binding, pkg string) jen.Code {
fnName := func(s string) string {
x := camelcase.Split(s)
return strings.ToLower(strings.Join(x, "_"))
}

cm := Dict{}
cm := jen.Dict{}
for _, d := range b.ClassMethods {
cm[Lit(fnName(d.Name.Name))] = Id(b.bindingName(d))
cm[jen.Lit(fnName(d.Name.Name))] = jen.Id(b.bindingName(d))
}
im := Dict{}
im := jen.Dict{}
for _, d := range b.InstanceMethods {
im[Lit(fnName(d.Name.Name))] = Id(b.bindingName(d))
im[jen.Lit(fnName(d.Name.Name))] = jen.Id(b.bindingName(d))
}
dm := Qual(vmPkg, "RegisterExternalClass").Call(
Line().Lit(pkg),
Qual(vmPkg, "ExternalClass").Call(
Line().Lit(b.ClassName),
Line().Lit(pkg+".gb"),
Line().Map(String()).Qual(vmPkg, "Method").Values(cm),
Line().Map(String()).Qual(vmPkg, "Method").Values(im),
dm := jen.Qual(vmPkg, "RegisterExternalClass").Call(
jen.Line().Lit(pkg),
jen.Qual(vmPkg, "ExternalClass").Call(
jen.Line().Lit(b.ClassName),
jen.Line().Lit(pkg+".gb"),
jen.Line().Map(jen.String()).Qual(vmPkg, "Method").Values(cm),
jen.Line().Map(jen.String()).Qual(vmPkg, "Method").Values(im),
),
)
l := Func().Id("init").Params().Block(
l := jen.Func().Id("init").Params().Block(
dm,
)
return l
Expand Down Expand Up @@ -301,7 +301,7 @@ func main() {
log.Fatal("Uknown type", *typeName)
}

o := NewFile(f.Name.Name)
o := jen.NewFile(f.Name.Name)
bnd.BindMethods(o, f)

err = o.Save("bindings.go")
Expand Down
4 changes: 4 additions & 0 deletions compiler/ast/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package ast

import (
"bytes"

"github.com/goby-lang/goby/compiler/token"
)

Expand Down Expand Up @@ -46,11 +47,13 @@ type node interface {
MarkAsExp()
}

// Statement satisfies "node" and statementNode
type Statement interface {
node
statementNode()
}

// Expression satisfies "node" and expressionNode
type Expression interface {
node
expressionNode()
Expand All @@ -61,6 +64,7 @@ type Program struct {
Statements []Statement
}

// TokenLiteral returns a token literal of the statement
func (p *Program) TokenLiteral() string {
if len(p.Statements) > 0 {
return p.Statements[0].TokenLiteral()
Expand Down
Loading

0 comments on commit 73fad60

Please sign in to comment.