Skip to content

Commit

Permalink
Merge branch 'master' of https://gitee.com/wa-lang/wa
Browse files Browse the repository at this point in the history
  • Loading branch information
3dgen committed Apr 15, 2024
2 parents 29591d0 + 8351b2a commit 3ced970
Show file tree
Hide file tree
Showing 15 changed files with 225 additions and 36 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ci-test-all:
cd waroot && go run ../main.go run hello.wa

make -C ./waroot/examples ci-test-all
wa -v

clean:
-rm a.out*
17 changes: 15 additions & 2 deletions internal/app/appssa/appssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"wa-lang.org/wa/internal/3rdparty/cli"
"wa-lang.org/wa/internal/app/appbase"
"wa-lang.org/wa/internal/ast"
"wa-lang.org/wa/internal/loader"
"wa-lang.org/wa/internal/ssa"
)
Expand All @@ -20,6 +21,10 @@ var CmdSsa = &cli.Command{
Flags: []cli.Flag{
appbase.MakeFlag_target(),
appbase.MakeFlag_tags(),
&cli.BoolFlag{
Name: "ast",
Usage: "print ast",
},
},
Action: func(c *cli.Context) error {
if c.NArg() == 0 {
Expand All @@ -28,7 +33,7 @@ var CmdSsa = &cli.Command{
}

opt := appbase.BuildOptions(c)
err := SSARun(opt, c.Args().First())
err := SSARun(opt, c.Args().First(), c.Bool("ast"))
if err != nil {
fmt.Println(err)
os.Exit(1)
Expand All @@ -37,13 +42,21 @@ var CmdSsa = &cli.Command{
},
}

func SSARun(opt *appbase.Option, filename string) error {
func SSARun(opt *appbase.Option, filename string, printAST bool) error {
cfg := opt.Config()
prog, err := loader.LoadProgram(cfg, filename)
if err != nil {
return err
}

if printAST {
mainPkg := prog.Pkgs[prog.Manifest.MainPkg]
for _, f := range mainPkg.Files {
ast.Print(prog.Fset, f)
}
return nil
}

prog.SSAMainPkg.WriteTo(os.Stdout)

var funcNames []string
Expand Down
6 changes: 6 additions & 0 deletions internal/types/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ import (
// but x.expr is not set. If the call is invalid, the result is
// false, and *x is undefined.
func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
for i, arg := range call.Args {
if expr := check.tryFixOperatorCall(arg); expr != nil {
call.Args[i] = expr
}
}

// append is the only built-in that permits the use of ... for the last argument
bin := predeclaredFuncs[id]
if call.Ellipsis.IsValid() && id != _Append {
Expand Down
6 changes: 6 additions & 0 deletions internal/types/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ import (
func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
check.resolveExprOrTypeOrGenericCall(x, e)

for i, arg := range e.Args {
if expr := check.tryFixOperatorCall(arg); expr != nil {
e.Args[i] = expr
}
}

switch x.mode {
case invalid:
check.use(e.Args...)
Expand Down
8 changes: 0 additions & 8 deletions internal/types/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
return
}

if check.tryUnaryOperatorCall(x, e) {
return
}

if !check.op(unaryOpPredicates, x, op) {
x.mode = invalid
return
Expand Down Expand Up @@ -780,10 +776,6 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
return
}

if check.tryBinaryOperatorCall(x, &y, lhs, rhs, op) {
return
}

if isShift(op) {
check.shift(x, &y, e, op)
return
Expand Down
74 changes: 56 additions & 18 deletions internal/types/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,14 @@ func (check *Checker) tryFixOperatorCall(expr ast.Expr) ast.Expr {
switch expr := expr.(type) {
case *ast.BinaryExpr:
var x, y operand
check.rawExpr(&x, expr.X, nil)
check.rawExpr(&y, expr.Y, nil)
if check.tryBinaryOperatorCall(&x, &y, expr.X, expr.Y, expr.Op) {
return x.expr
}
case *ast.UnaryExpr:
var x operand
check.rawExpr(&x, expr.X, nil)
if check.tryUnaryOperatorCall(&x, expr) {
return x.expr
}
Expand Down Expand Up @@ -186,12 +189,21 @@ func (check *Checker) tryUnaryOperatorCall(x *operand, e *ast.UnaryExpr) bool {

x.mode = value
x.typ = fn.typ.(*Signature).results.vars[0].typ
x.expr = &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: &ast.Ident{Name: "#" + fn.pkg.path},
Sel: &ast.Ident{Name: fn.pkg.name},
},
Args: []ast.Expr{e.X},

if fn.pkg == check.pkg {
x.expr = &ast.CallExpr{
Fun: &ast.Ident{Name: "#{func}:" + fn.name},
Args: []ast.Expr{e.X},
}
} else {
check.ensureOperatorCallPkgImported(fn.pkg)
x.expr = &ast.CallExpr{
Fun: &ast.SelectorExpr{
X: &ast.Ident{Name: "#{pkg}:" + fn.pkg.path},
Sel: &ast.Ident{Name: fn.name},
},
Args: []ast.Expr{e.X},
}
}

check.hasCallOrRecv = true
Expand Down Expand Up @@ -221,39 +233,39 @@ func (check *Checker) tryBinaryOperatorCall(
return false
}

var fnMached *Func
var fnMatched *Func
for _, fn := range xFuncs {
if err := check.tryBinOpFunc(fn, x, y, lhs, rhs); err == nil {
fnMached = fn
fnMatched = fn
break
}
}
if fnMached == nil {
if fnMatched == nil {
for _, fn := range yFuncs {
if err := check.tryBinOpFunc(fn, x, y, lhs, rhs); err == nil {
fnMached = fn
fnMatched = fn
break
}
}
}
if fnMached == nil {
if fnMatched == nil {
return false
}

x.mode = value
x.typ = fnMached.typ.(*Signature).results.vars[0].typ
if fnMached.pkg == check.pkg {
// TODO(chai): 当前包/外部名字屏蔽
x.typ = fnMatched.typ.(*Signature).results.vars[0].typ

if fnMatched.pkg == check.pkg {
x.expr = &ast.CallExpr{
Fun: &ast.Ident{Name: fnMached.name},
Fun: &ast.Ident{Name: "#{func}:" + fnMatched.name},
Args: []ast.Expr{lhs, rhs},
}
} else {
check.ensureOperatorCallPkgImported(fnMatched.pkg)
x.expr = &ast.CallExpr{
// TODO(chai): 未导入包修复
Fun: &ast.SelectorExpr{
X: &ast.Ident{Name: fnMached.pkg.name},
Sel: &ast.Ident{Name: fnMached.name},
X: &ast.Ident{Name: "#{pkg}:" + fnMatched.pkg.path},
Sel: &ast.Ident{Name: fnMatched.name},
},
Args: []ast.Expr{lhs, rhs},
}
Expand Down Expand Up @@ -331,3 +343,29 @@ func (check *Checker) getBinOpFuncs(x *Named, op token.Token) []*Func {
}
return nil
}

// 确保运算符重载的函数对应的包被导入
func (check *Checker) ensureOperatorCallPkgImported(pkg *Package) {
assert(pkg != check.pkg)

pkgname := "#{pkg}:" + pkg.path
for _, x := range check.pkg.imports {
if x.path == pkg.path && x.name == pkgname {
return
}
}

obj := NewPkgName(token.NoPos, check.pkg, pkgname, pkg)
obj.setNode(&ast.ImportSpec{
Name: &ast.Ident{Name: pkgname},
Path: &ast.BasicLit{Kind: token.STRING, Value: pkg.path},
Comment: &ast.CommentGroup{
List: []*ast.Comment{
{Text: "internal: only for operator overloading call"},
},
},
})

check.declare(check.pkg.scope, nil, obj, token.NoPos)
check.pkg.imports = append(check.pkg.imports, pkg)
}
2 changes: 1 addition & 1 deletion internal/types/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ func (check *Checker) resolveExprOrTypeOrGenericCall(x *operand, e *ast.CallExpr
if fnObj, ok := obj.(*Func); ok && len(fnObj.generic) != 0 {
for _, genericFnObj := range fnObj.generic {
if err := check.tryGenericCall(x, genericFnObj, e); err == nil {
eCall.Name = genericFnObj.name
eCall.Name = "#{func}:" + genericFnObj.name
check.exprOrType(x, e.Fun)
return
}
Expand Down
18 changes: 17 additions & 1 deletion internal/types/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,16 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] }
// Lookup returns the object in scope s with the given name if such an
// object exists; otherwise the result is nil.
func (s *Scope) Lookup(name string) Object {
return s.elems[name]
if obj, ok := s.elems[name]; ok {
return obj
}
if s.parent == Universe {
if strings.HasPrefix(name, "#{func}:") {
return s.elems[name[len("#{func}:"):]]
}
}

return nil
}

// LookupParent follows the parent chain of scopes starting with s until
Expand All @@ -85,6 +94,13 @@ func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
return s, obj
}
if s.parent == Universe {
if strings.HasPrefix(name, "#{func}:") {
if obj, ok := s.elems[name[len("#{func}:"):]]; ok {
return s, obj
}
}
}
}
return nil, nil
}
Expand Down
43 changes: 43 additions & 0 deletions internal/types/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ func assignOp(op token.Token) token.Token {
}

func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
for i, x := range call.Args {
if expr := check.tryFixOperatorCall(x); expr != nil {
call.Args[i] = expr
}
}

var x operand
var msg string
switch check.rawExpr(&x, call, nil) {
Expand Down Expand Up @@ -343,6 +349,10 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.errorf(x.pos(), "%s %s", &x, msg)

case *ast.IncDecStmt:
if expr := check.tryFixOperatorCall(s.X); expr != nil {
s.X = expr
}

var op token.Token
switch s.Tok {
case token.INC:
Expand Down Expand Up @@ -372,6 +382,12 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.assignVar(s.X, &x)

case *ast.AssignStmt:
for i, x := range s.Rhs {
if expr := check.tryFixOperatorCall(x); expr != nil {
s.Rhs[i] = expr
}
}

switch s.Tok {
case token.ASSIGN, token.DEFINE:
if len(s.Lhs) == 0 {
Expand Down Expand Up @@ -408,6 +424,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.suspendedCall("defer", s.Call)

case *ast.ReturnStmt:
for i, x := range s.Results {
if expr := check.tryFixOperatorCall(x); expr != nil {
s.Results[i] = expr
}
}
res := check.sig.results
if res.Len() > 0 {
// function returns results
Expand Down Expand Up @@ -461,6 +482,11 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
defer check.closeScope()

check.simpleStmt(s.Init)

if expr := check.tryFixOperatorCall(s.Cond); expr != nil {
s.Cond = expr
}

var x operand
check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) {
Expand All @@ -486,6 +512,10 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.simpleStmt(s.Init)
var x operand
if s.Tag != nil {
if expr := check.tryFixOperatorCall(s.Tag); expr != nil {
s.Tag = expr
}

check.expr(&x, s.Tag)
// By checking assignment of x to an invisible temporary
// (as a compiler would), we get all the relevant checks.
Expand Down Expand Up @@ -539,6 +569,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
var rhs ast.Expr
switch guard := s.Assign.(type) {
case *ast.ExprStmt:
if expr := check.tryFixOperatorCall(guard.X); expr != nil {
guard.X = expr
}
rhs = guard.X
case *ast.AssignStmt:
if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
Expand All @@ -552,6 +585,12 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
return
}

for i, x := range guard.Rhs {
if expr := check.tryFixOperatorCall(x); expr != nil {
guard.Rhs[i] = expr
}
}

if lhs.Name == "_" {
// _ := x.(type) is an invalid short variable declaration
check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
Expand Down Expand Up @@ -644,6 +683,10 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {

check.simpleStmt(s.Init)
if s.Cond != nil {
if expr := check.tryFixOperatorCall(s.Cond); expr != nil {
s.Cond = expr
}

var x operand
check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) {
Expand Down
2 changes: 1 addition & 1 deletion waroot/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v0.10.0
v0.11.0
4 changes: 4 additions & 0 deletions waroot/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# 版本日志

- (dev)
- v0.11.0 (2024-04-13)
- 完善 `math/{Sin,Cos,Sqrt}` 等 API
- 增加 `math/vector`/`math/matrix`/`net` 标准库
- 实验性增加运算符重载功能
- v0.10.0 (2024-03-29)
- 补充基本类型读写胶水
- 修正 I64、U64 不应导出等一些错误
Expand Down
Loading

0 comments on commit 3ced970

Please sign in to comment.