Skip to content

v1.2.0-pre.2

Pre-release
Pre-release
Compare
Choose a tag to compare
@xushiwei xushiwei released this 28 Jan 13:33
· 403 commits to v1.2 since this release
5db9564

features:

articles:

ci/cd tools:

changes:

  • parser: fix ParseFSEntry for new classfile tech (#1618)
  • parser: fix ParseFSDir/ParseFSEntry set class kind if file valid (#1634)
  • parser: fix parse println x... (#1644 #1659)
  • parser: ast.FuncDecl add IsClass for check set recv by class (#1620)
  • cl preloadGopFile optimization (#1661)
  • cl preloadGopFile bugfix: pkg.SetCurFile (#1669)
  • cl: toType error return types.Invalid (#1628)
  • cl: instantiate use gox pkg.Instantiate (#1654)
  • cl newGmx bugfix: use classNameAndExt (#1610)
  • cl: call gmxMainFunc only if no main func (#1648 #1658)
  • cl: NewPackage preload Go+ first and then Go files (#1630)
  • ast: fix Walk ast.File if NoPkgDecl (#1624)
  • ast.Walk: support OverloadFuncDecl (#1671)
  • format: gop fmt .gox bugfix (#1643)
  • x/typesutil: fix checker.Files skip bad file (#1623)
  • x/build: use modfile.ClassExt (#1664)
  • iOverloadType/iSubstType (goplus/gogen#350 #1665)
  • gox.Context (#1640 #1641 #1645)

Goodbye printf

For professional programmers, printf is a very familiar function, and it can be found in basically every language. However, printf is one of the most difficult functions for beginners to master:

age := 10
printf "age = %d\n", age

Here %d means to format an integer value and \n means a newline.

To simplify format information in most cases, Go+ introduces ${expr} expressions in string literals:

age := 10
println "age = ${age}"

This is a bit like how you feel at the *nix command line, right? To be more like it, we introduced a new builtin echo as an alias for println:

age := 10
echo "age = ${age}"

Go+ Classfiles

Rob Pike once said that if he could only introduce one feature to Go, he would choose interface instead of goroutine. classfile is as important to Go+ as interface is to Go.

In the design philosophy of Go+, we do not recommend DSL (Domain Specific Language). But SDF (Specific Domain Friendliness) is very important. The Go+ philosophy about SDF is:

Don't define a language for specific domain.
Abstract domain knowledge for it.

Go+ introduces classfile to abstract domain knowledge.

classfile: Unit Test

Go+ has a built-in classfile to simplify unit testing. This classfile has the file suffix _test.gox.

Suppose you have a function named foo:

func foo(v int) int {
	return v * 2
}

Then you can create a foo_test.gox file to test it (see unit-test/foo_test.gox):

if v := foo(50); v != 100 {
	t.error "foo(50) ret: ${v}"
}

t.run "foo -10", t => {
	if foo(-10) != -20 {
		t.fatal "foo(-10) != -20"
	}
}

You don't need to define a series of TestXXX functions like Go, just write your test code directly.

If you want to run a subtest case, use t.run.

yap: Yet Another Go/Go+ HTTP Web Framework

This classfile has the file suffix _yap.gox.

Before using yap, you need to add it to go.mod by using go get:

go get github.com/goplus/yap@latest

Find require github.com/goplus/yap statement in go.mod and add //gop:class at the end of the line:

require github.com/goplus/yap v0.7.2 //gop:class

Router and Parameters

demo (hello_yap.gox):

get "/p/:id", ctx => {
	ctx.json {
		"id": ctx.param("id"),
	}
}

run ":8080"

Static files

Static files server demo (staticfile_yap.gox):

static "/foo", FS("public")
static "/"

run ":8080"

YAP Template

demo (blog_yap.gox, article_yap.html):

get "/p/:id", ctx => {
	ctx.yap "article", {
		"id": ctx.param("id"),
	}
}

run ":8080"

yaptest: HTTP Test Framework

This classfile has the file suffix _ytest.gox.

Before using yaptest, you need to add yap to go.mod:

require github.com/goplus/yap v0.7.2 //gop:class

demo to test your HTTP server (example_ytest.gox):

title := Var(string)
author := Var(string)
id := "123"
get "https://example.com/p/${id}"
ret 200
json {
	"title":  title,
	"author": author,
}
echo "title:", title
echo "author:", author

spx: A Go+ 2D Game Engine for STEM education

This classfile has the file suffix .spx. It is the earliest classfile in the world.

Before using spx, you need to add it to go.mod by using go get:

go get github.com/goplus/spx@latest

It's also a built-in classfile so you don't need append //gop:class after require github.com/goplus/spx.

Screen Shot1 Screen Shot2

Through this example you can learn how to listen events and do somethings.

Here are some codes in Kai.spx:

onStart => {
	say "Where do you come from?", 2
	broadcast "1"
}

onMsg "2", => {
	say "What's the climate like in your country?", 3
	broadcast "3"
}

We call onStart and onMsg to listen events. onStart is called when the program is started. And onMsg is called when someone calls broadcast to broadcast a message.

When the program starts, Kai says Where do you come from?, and then broadcasts the message 1. Who will recieve this message? Let's see codes in Jaime.spx:

onMsg "1", => {
	say "I come from England.", 2
	broadcast "2"
}

Yes, Jaime recieves the message 1 and says I come from England.. Then he broadcasts the message 2. Kai recieves it and says What's the climate like in your country?.

The following procedures are very similar. In this way you can implement dialogues between multiple actors.

Overload Func/Method/Operators in Go+

Overload Funcs

Define overload func in inline func literal style (see overloadfunc1/add.gop):

func add = (
	func(a, b int) int {
		return a + b
	}
	func(a, b string) string {
		return a + b
	}
)

println add(100, 7)
println add("Hello", "World")

Define overload func in ident style (see overloadfunc2/mul.gop):

func mulInt(a, b int) int {
	return a * b
}

func mulFloat(a, b float64) float64 {
	return a * b
}

func mul = (
	mulInt
	mulFloat
)

println mul(100, 7)
println mul(1.2, 3.14)

Overload Methods

Define overload method (see overloadmethod/method.gop):

type foo struct {
}

func (a *foo) mulInt(b int) *foo {
	println "mulInt"
	return a
}

func (a *foo) mulFoo(b *foo) *foo {
	println "mulFoo"
	return a
}

func (foo).mul = (
	(foo).mulInt
	(foo).mulFoo
)

var a, b *foo
var c = a.mul(100)
var d = a.mul(c)

Overload Unary Operators

Define overload unary operator (see overloadop1/overloadop.gop):

type foo struct {
}

func -(a foo) (ret foo) {
	println "-a"
	return
}

func ++(a foo) {
	println "a++"
}

var a foo
var b = -a
a++

Overload Binary Operators

Define overload binary operator (see overloadop1/overloadop.gop):

type foo struct {
}

func (a foo) * (b foo) (ret foo) {
	println "a * b"
	return
}

func (a foo) != (b foo) bool {
	println "a != b"
	return true
}

var a, b foo
var c = a * b
var d = a != b

However, binary operator usually need to support interoperability between multiple types. In this case it becomes more complex (see overloadop2/overloadop.gop):

type foo struct {
}

func (a foo) mulInt(b int) (ret foo) {
	println "a * int"
	return
}

func (a foo) mulFoo(b foo) (ret foo) {
	println "a * b"
	return
}

func intMulFoo(a int, b foo) (ret foo) {
	println "int * b"
	return
}

func (foo).* = (
	(foo).mulInt
	(foo).mulFoo
	intMulFoo
)

var a, b foo
var c = a * 10
var d = a * b
var e = 10 * a