Giter Club home page Giter Club logo

gop's Introduction

Build Status Go Report Card Coverage Status GitHub release Discord

Our vision is to enable everyone to create production-level applications.

Easy to learn

  • Simple and easy to understand
  • Smaller syntax set than Python in best practices

Ready for large projects

  • Derived from Go and easy to build large projects from its good engineering foundation

The Go+ programming language is designed for engineering, STEM education, and data science.

  • For engineering: working in the simplest language that can be mastered by children.
  • For STEM education: studying an engineering language that can be used for work in the future.
  • For data science: communicating with engineers in the same language.

For more details, see Quick Start.

Command Style Code

Different from the function call style of most languages, Go+ recommends command style code:

println "Hello world"

To emphasize our preference for command style, we introduce echo as an alias for println:

echo "Hello world"

For more discussion on coding style, see https://tutorial.goplus.org/hello-world.

Go+ Classfiles

One language can change the whole world.
Go+ is a "DSL" for all domains.

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.

Sound a bit abstract? Let's see some Go+ classfiles.

yap: Yet Another HTTP Web Framework

This classfile has the file suffix .yap.

Create a file named get.yap with the following content:

html `<html><body>Hello, YAP!</body></html>`

Execute the following commands:

gop mod init hello
gop get github.com/goplus/yap@latest
gop mod tidy
gop run .

A simplest web program is running now. At this time, if you visit http://localhost:8080, you will get:

Hello, YAP!

YAP uses filenames to define routes. get.yap's route is get "/" (GET homepage), and get_p_#id.yap's route is get "/p/:id" (In fact, the filename can also be get_p_:id.yap, but it is not recommended because : is not allowed to exist in filenames under Windows).

Let's create a file named get_p_#id.yap with the following content:

json {
	"id": ${id},
}

Execute gop run . and visit http://localhost:8080/p/123, you will get:

{"id": "123"}

See yap: Yet Another HTTP Web Framework for more details.

spx: A Go+ 2D Game Engine

Screen Shot1 Screen Shot2

Through this example you can learn how to implement dialogues between multiple actors.

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.

See spx: A Go+ 2D Game Engine for more details.

gsh: Go+ DevOps Tools

Yes, now you can write shell script in Go+. It supports all shell commands.

Let's create a file named example.gsh and write the following code:

mkdir "testgsh"

Don't need a go.mod file, just enter gop run ./example.gsh directly to run.

See gsh: Go+ DevOps Tools for more details.

Key Features of Go+

How to install

on Windows

winget install goplus.gop

on Debian/Ubuntu

sudo bash -c ' echo "deb [trusted=yes] https://pkgs.goplus.org/apt/ /" > /etc/apt/sources.list.d/goplus.list'
sudo apt update
sudo apt install gop

on RedHat/CentOS/Fedora

sudo bash -c 'echo -e "[goplus]\nname=Go+ Repo\nbaseurl=https://pkgs.goplus.org/yum/\nenabled=1\ngpgcheck=0" > /etc/yum.repos.d/goplus.repo'
sudo yum install gop

on macOS/Linux (Homebrew)

Install via brew

$ brew install goplus

from source code

Note: Requires go1.18 or later

git clone https://github.com/goplus/gop.git
cd gop

# On mac/linux run:
./all.bash
# On Windows run:
all.bat

Go+ Applications

2D Games powered by Go+

Web Programming

DevOps Tools

Data Processing

IDE Plugins

Contributing

The Go+ project welcomes all contributors. We appreciate your help!

For more details, see Contributing & compiler design.

Give a Star! ⭐

If you like or are using Go+ to learn or start your projects, please give it a star. Thanks!

gop's People

Contributors

92hackers avatar aimuz avatar aofei avatar arthur-zhang avatar carlji avatar cpunion avatar cuishuang avatar damonchen avatar dependabot[bot] avatar dongm2ez avatar geometryolife avatar go-wyvern avatar jessonchan avatar jiangz222 avatar kevwan avatar libmonsoon-dev avatar liuscraft avatar luoliwoshang avatar lvheyang avatar myml avatar qiukeren avatar si9ma avatar skyjia avatar tsingbx avatar visualfc avatar wangkuiyi avatar writegr avatar xumingyu07 avatar xushiwei avatar zrcoder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gop's Issues

支持常规的 member assign 语法

当前:

set(slice, index, value)
set(map, key, value)
set(object, member, value)

需要支持:

slice[index] = value
map[key] = value
map.key = value
object.member = value

remove private variable concept

在 qlang 中我们引入了私有变量概念,实践证明并没有多大价值,反而在不了解该机制下会引起混淆。故干掉。

qlang shell doesn't support import?

例如,有 https://github.com/qlangio/libs/tree/master/tricks 这个模块。
输入 qlang 进入 qlang shell,然后输入

import "tricks"

报错:

line 14: match failed: `fn inherit(Base) {
        tbl = reflect.valueOf(Base).elem().fieldByName("Fns").interface()
        for name, method = range tbl {
            if this.tbl[name] == undefined {
                this.tbl[name] = method
            }
        }
    }
}
` doesn't match `"fn" IDENT fnbody ?';'`
line 14: match failed: `for name, method = range tbl {
            if this.tbl[name] == undefined {
                this.tbl[name] = method
            }
        }
    }
}

of = fn(Class) {
` doesn't match `'}'`

建议增加更多的自省机制

因为没有找到qlang的设计文档,在些提出自己对目前v2版本的一些看法,不知是否可行。
目前qlang版本有type自省机制,建议能否加入类似python的dir等更多的自省机制。
我尝试着对Go语言导入的package包写了简单的dir实现。

modules()
> [bufio strings md5 ioutil json strconv bytes errors path hex sync os extractor math reflect runtime]
s = strings.reader("hello")
> <nil>
dir(s)
> [len read readAt readByte readRune seek size unreadByte unreadRune writeTo]
type(s.len)
> func() int

简单的源码如下

var Exports = map[string]interface{}{
    "fntable": FnTable,
    "modules": Modules,
    "dir":     Dir,
}

// list qlang function table
func FnTable() (names []string) {
    for k, _ := range qlang.Fntable {
        names = append(names, k)
    }
    return
}

// list qlang go modules
func Modules() (names []string) {
    for k, v := range qlang.Fntable {
        if t := reflect.TypeOf(v); t != nil && t.Kind() == reflect.Map {
            names = append(names, k)
        }
    }
    return
}

func IsExported(name string) bool {
    ch, _ := utf8.DecodeRuneInString(name)
    return unicode.IsUpper(ch)
}

func LowerTitle(name string) string {
    return strings.ToLower(name[0:1]) + name[1:]
}

// list go module or struct members
// list qlang class members
func Dir(i interface{}) (names []string) {
    v := reflect.ValueOf(i)
    if v.Kind() == reflect.Map {
        for _, k := range v.MapKeys() {
            names = append(names, k.String())
        }
    } else {
        //check *exec.Object
        if e, ok := i.(*exec.Object); ok {
            for k, _ := range e.Cls.Fns {
                names = append(names, k)
            }
            return
        }
        t := v.Type()
        // struct field
        if t.Kind() == reflect.Ptr {
            e := t.Elem()
            if e != nil && e.Kind() == reflect.Struct {
                for i := 0; i < e.NumField(); i++ {
                    if IsExported(e.Field(i).Name) {
                        names = append(names, e.Field(i).Name)
                    }
                }

            }
        }
        // num method
        for i := 0; i < t.NumMethod(); i++ {
            names = append(names, LowerTitle(t.Method(i).Name))
        }
    }
    return
}

qexport 自动导出工具

我写了一个go package自动导出qlang模块的工具,目前使用go tool api进行导出标准包,但如果以后改用gotools的api则可以导出所有包https://github.com/visualfc/gotools/tree/master/goapi

因为是自动导出,所以导出规则仍不完善,与qlang自带的包不太一致。

https://github.com/visualfc/qexport

Examples:

    export sync
    > qexport sync

    export html and html/template package
    > qexport html html/template

    export all package
    > qexport std

anonymfn (匿名函数)

当前有 main { ... } 作为匿名函数,其实更一般的文法可以是 fn { ... }。这样在 defer 语句中可以简写很多。如:

defer fn() {
    ... // 复杂代码
}()

可以简写为:

defer fn {
    ... // 复杂代码
}

qlang shell 增强

比如,和其他shell类似,需要能够通过上下键翻历史输入的指令,以及指令支持多行输入,多行指令的拷贝粘贴

qlang中支持uint32等类型

有些历史代码中会试用uint32等类型的变量,这种函数直接export 给 golang 时会参数不匹配:
NewRequestPing(uint32(19988))
而目前强制类型转换不支持 uint32等类型

parser字符串出错

对于parser的分割,有些错误:

如果是下面的代码:


a = "test"
   "bb"
println(a)

可以运行成功,但输出似乎也不是很理想

$qlang ql.ql
test

`a = "test"  "bb"`

则运行失败

line 1: match failed: `"bb"
println(a)
` doesn't match `EOF`

自动为 go package 生成 qlang 版本的 module

qlang -genlib <GoPackageName> [<TargetDir>]
  • 如果 <TargetDir> 为空,则为 '.' (当前目录)

例子:

qlang -genlib encoding/json

这将自动在 GOPATH 中找到 encoding/json 并且生成 module 到 ./encoding/json 下。

qlang包变量引用时关键字冲突

    "default": build.Default,

如果导出包里面包含关键字,那么只能通过索引方式引用

>>> build.default
line 1: match failed: `.default` doesn't match `'.' member`
line 1: match failed: `default` doesn't match `IDENT | "class" | "new" | "recove
r" | "main" | "import" | "as" | "export" | "include" | "type"`
>>> build["default"]
{amd64 windows c:\go\go1.6  true false gc [] [go1.1 go1.2 go1.3 go1.4 go1.5 go1.
6]  <nil> <nil> <nil> <nil> <nil> <nil> <nil>}
>>>

module 支持

设计 module 的 specification,讨论并定稿实现

把qlang.io的https证书搞一下?

https://qlang.io 的证书好像不正确。执行 go get -v -u qlang.io/qlang 会报错:

Fetching https://qlang.io/qlang?go-get=1
https fetch failed: Get https://qlang.io/qlang?go-get=1: x509: certificate is valid for www.qiniupkg.com, qiniupkg.com, not qlang.io
package qlang.io/qlang: unrecognized import path "qlang.io/qlang" (https fetch: Get https://qlang.io/qlang?go-get=1: x509: certificate is valid for www.qiniupkg.com, qiniupkg.com, not qlang.io)

需要 go get -v -u -insecure qlang.io/qlang 才能get到

写个Hello world 咋就这么难呢?


    script := `
x = fn(a) {
    b = 1 + a
    return b
}

println(x(3)) 
`
    var Exports_log = map[string]interface{}{
        "Println": log.Println,
    }
    qlang.Import("log", Exports_log)
    lang, err := qlang.New(nil) // 参数 nil 也可以改为 qlang.InsertSemis
    if err != nil {

        log.Println(err)
        return
    }

    started := time.Now()

    err = lang.Eval(script)
    if err != nil {

        log.Println(err)
        return
    }
    log.Printf("qlang_fib %v", time.Since(started))

报错


` doesn't match `"fn" (~'{' fnbody | afn)`
line 4: match failed: `return b
}

println(x(3))
` doesn't match `'}'`

环境

go version
go version go1.5.2 windows/amd64

qlang的代码没有注释,文档连个How to use qlang in your Go program都没有

建议支持引用符 & * 操作

Go本身的函数参数支持引用,建议qlang支持引用和解引用,以便更好的利用Go语言提供的库。
即 & 和 * 操作

doc 函数增强

当前:

>>> doc(os.create)
func(string) (*os.File, error)

>>> doc("os.create")
string

可以考虑加强下 doc("os.create") 这种情况,打印该函数的完整帮助。

支持 goroutine

主要是将 qlang 改为多线程安全的工作。包括:

1、exec.Module(...) 指令的多线程安全;
2、qlang.v1 中 interpreter.EvalCode 不支持重入,是多线程不安全的;但是如果我们只考虑在 qlang.v2 中支持 goroutine,则无此问题;

import 关键字无法识别 $QLANG_PATH

  1. import 无法识别 $QLANG_PATH,应该是个bug,这里是不是应该加上对 $QLANG_PATH 的支持?
  2. import 成功后(修改了 1. 链接处的代码),无法识别 new module.Class() 语法:
// $QLANG_PATH/types/main.ql
Slice = class {}
export Slice

// $$QLANG_PATH/play.ql
import "types"
slice = new types.Slice("int")

// 报错:
2016/04/18 18:26:23 line 2: match failed: `.Slice("int")
println(slice)` doesn't match `EOF`
panic: line 2: match failed: `.Slice("int")
println(slice)` doesn't match `EOF`

何时能开放代码呢?

内核居然只有1k行, 语言特性也很有意思.
请问许大何时可以开放代码呢?

感谢分享.

在 Go 语言中如何调用 qlang 的类?

预期的使用方式如下:

1、创建对象:

obj := lang.Var("FooClass").(*exec.Class).New(arg1, arg2, ...) // 其中 FooClass 是 qlang 的类

2、访问成员变量:

member := obj.Member("a") // 相当于 obj.a

3、调用成员方法:

result := obj.Member("method").(*exec.Method).Call(arg1, arg2, ...) // 相当于 obj.method(arg1, arg2, ...)

type(['a', 'b']) gets []int

a = type(['a', 'b'])
println(a)

我们得到 []int 类型,而不是 []byte 类型。
原因:同 issue #52
解决思路:[] 的指令改为非普通函数调用

Go包按值导出时无法调用函数

如下,按指针返回在qlang中可以调用函数,按值返回则无法调用。

"newContext":              newContext,
"varContext":               varContext,

func newContext() *build.Context {
    return new(build.Context)
}
func varContext() build.Context {
    var ctx build.Context
    return ctx
}

调用Go函数时无法进行兼容性类型转换

兼容性类型无法正确转换。

type ImportMode uint
const ( 
    FindOnly ImportMode = 1 << iota
    AllowBinary
……
}
func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Package, error) {

在Go中我们通常需要将 mode 设置为0,以获取正确结果,int型将正确转换为ImportMode类型。

build.Import("fmt","",0)

而在qlang我们无法使用0值进行输入,也无法进行转换,这样导致 build.import 无法使用。

>>> build.import("fmt","",0)
line 1: invalid argument type: require `build.ImportMode`, but we got `int`

qlang 的静态类型声明,及创建 slice/map 的风格调整

首先,目前 qlang 的函数是弱类型的,比如:

foo = fn(a, b) {
    return a+b
}

未来可以考虑支持:

foo = fn(a int, b int) int {
    return a+b
}

另外,由于引入类型,可能可以考虑提供和go大致兼容的 slice/map 创建文法。比如:

slice1 := make(int[], len, cap)
slice2 := make(UserType[][], len)
map1 := make(map[string]int, len)
map2 := make(map[string]map[string]int, len)

注意slice类型的表达和go是不太一样的,这是因为:

  • 在qlang里面[]是slice初始化语法,表示空slice,这个如果用 []int 表达可能会带来解析过程的歧义。而放在类型后面可以非常方便地区分到底表达的是空slice,还是slice类型。

改进复合语句的语义

a = if x < y {
    x
} else {
    y
}

当前的结果为 nil。如果我们认为:复合语句 { s1; s2; ...; sN; } 的值为 sN,那么以上表达式就等价于:

a = min(x, y)

另外,函数的语义也可以调整:

foo = fn() { s1; s2; ...; sN; }

如果中间没有出现 return,那么 foo() 的结果为 nil。但是我们可以调整为值也是 sN。这样 qlang 的 fn 就有点类似函数式的味道了。示例:

min = fn(x, y) {
    if x < y { x } else { y }
}

性能啊,测试完大吃一惊啊,需要改善哪

测试 fib(30),分别用 Go(native),gopher-lua, qlang, otto

fib = fn(n) {
    if n < 2 {
        return n
    }
    return fib(n-2) + fib(n-1)
}

fib(30)

结果:

BenchmarkGolang-4           1000           1723098 ns/op               1 B/op          0 allocs/op   
BenchmarkGopherlua-4           5         230613180 ns/op          539003 B/op       1391 allocs/op   
BenchmarkQlang-4               1        12594720400 ns/op       2801072688 B/op 52523860 allocs/op   
BenchmarkOtto-4                1        14532831200 ns/op       4954536800 B/op 75394539 allocs/op   

没想到, gopher-lua 速度比 qlang快50多倍,otto 和qlang倒是一个数量级别的。
实在想不通,qlang为什么比 同样是 pure-go 实现的 gopher-lua 慢如此多?

qexport 增强建议:支持合并既有的导出包

既有的导出包如果已经存在,里面可能有部分代码是手工改动后的,直接覆盖不是很合适。建议:

如果已经存在目标的包,则找到目标包的 Exports 表,如果里面已经存在某个函数就不必再导出。例如假设我们要导出一个名为 foo 的包,但是这个目标包已经存在,内容如下:

package foo
...

// Exports is the export table of this module.
//
var Exports = map[string]interface{}{
    "bar": newBar,
    ...
}

比较适合的执行流程是:

  • 在 Exports 表前插入可能新增的一些代码
  • 在 Exports 表尾部插入还没有添加到表中的函数

另外还有一个需要注意的细节是:有些 Exports 函数由于是特定版本增加的,它未必出现在 Exports 表中,而是通过 func init() 函数添加。例如:

// +build go1.6

package runtime

import "runtime"

func init() {
    Exports["readTrace"] = runtime.ReadTrace
    Exports["startTrace"] = runtime.StartTrace
    Exports["stopTrace"] = runtime.StopTrace
}

对于这样的函数,也没有必要在 Exports 表中重复添加。

建议 doc(pkg) 不返回 _ 开头的符号

>>> doc(os)
package os
_name   string 
args    []string 
open    func(string) (*os.File, error) 
exit    func(int) 
_initSafe   func(qlang.Module) 
stdin   *os.File 
stderr  *os.File 
stdout  *os.File 
create  func(string) (*os.File, error) 

qlang shell 支持多行输入

1、在行未是这些标点 ; ) ] } ++ -- 之外的标点,则当前行与后续行合并执行。
2、在不在字符串内的 () [] {} 没有达成匹配,则当前行也与后续行合并执行。

提升变量访问性能

为了快速推出一个编译执行版本的 qlang,我们没有调整任何功能的实现机理,只是完成从解析执行到基于编译执行(编译=>执行器解析执行编译结果)的改变。

考虑到 qlang.v1 版本的变量机制从字节码执行角度来说仍然有很大的提升空间:可从map查询改为基于stack 偏移的地址定位。

type(uint32(1)) gets int

a = type(uint32(1))
println(a)

我们得到 int 类型,而不是 uint32 类型。
原因:当一个函数的输入参数为 interface{} 时,输入的各种整数类型会被归一到 int,输入的浮点数归一到 float64。

qexport 增强建议:更智能的 NewXXX

有些类虽然没有 NewXXX 创建函数,但是有其他初始化函数,那么不必自动添加 new 函数。例如 runtime 包 的 runtime.Func 类,虽然它没有 runtime.NewFunc,但是有 runtime.FuncForPC 可以创建 *runtime.Func,则我们不必自动生成 NewFunc 导出函数(如果需要,用户可自行手工添加)。

multi assignment

x, y, z = 1, 2, 3

或:

foo = fn() {
    return 1, 2, 3
}

x, y, z = foo()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.