func buildExprList(b *builder, list *ast.ExprList) tast.Expr { ret := tast.NewExprList() if list == nil { return ret } n := list.Len() if n == 0 { return ret } if n == 1 { return b.buildExpr(list.Exprs[0]) } for _, expr := range list.Exprs { ex := b.buildExpr(expr) if ex == nil { return nil } ref := ex.R() if !ref.IsSingle() { b.Errorf(ast.ExprPos(expr), "cannot put %s in a list", ref) return nil } ret.Append(ex) } return ret }
// allocPrepare checks if the provided types are all allocable, and insert // implicit type casts if needed. Only literay expression list needs alloc // prepare. func allocPrepare( b *builder, toks []*lex8.Token, lst *tast.ExprList, ) *tast.ExprList { ret := tast.NewExprList() for i, tok := range toks { e := lst.Exprs[i] t := e.Type() if types.IsNil(t) { b.Errorf(tok.Pos, "cannot infer type from nil for %q", tok.Lit) return nil } if v, ok := types.NumConst(t); ok { e = constCastInt(b, tok.Pos, v, e) if e == nil { return nil } } if !types.IsAllocable(t) { b.Errorf(tok.Pos, "cannot allocate for %s", t) return nil } ret.Append(e) } return ret }
func buildConstExprList(b *builder, list *ast.ExprList) tast.Expr { n := list.Len() if n == 0 { b.Errorf(ast.ExprPos(list), "const expression list of zero length") return nil } if n == 1 { return b.buildConst(list.Exprs[0]) } ret := tast.NewExprList() for _, expr := range list.Exprs { ex := b.buildConst(expr) if ex == nil { return nil } ref := ex.R() if !ref.IsSingle() { b.Errorf(ast.ExprPos(expr), "cannot put %s in a list", ref) return nil } ret.Append(ex) } return ret }
func assign(b *builder, dest, src tast.Expr, op *lex8.Token) tast.Stmt { destRef := dest.R() srcRef := src.R() ndest := destRef.Len() nsrc := srcRef.Len() if ndest != nsrc { b.Errorf(op.Pos, "cannot assign %s to %s", nsrc, ndest) return nil } for i := 0; i < ndest; i++ { r := destRef.At(i) if !r.Addressable { b.Errorf(op.Pos, "assigning to non-addressable") return nil } destType := r.Type() srcType := srcRef.At(i).Type() if !types.CanAssign(destType, srcType) { b.Errorf(op.Pos, "cannot assign %s to %s", srcType, destType) return nil } } // insert casting if needed if srcList, ok := tast.MakeExprList(src); ok { newList := tast.NewExprList() for i, e := range srcList.Exprs { t := e.Type() if types.IsNil(t) { e = tast.NewCast(e, destRef.At(i).Type()) } else if v, ok := types.NumConst(t); ok { e = constCast(b, nil, v, e, destRef.At(i).Type()) if e == nil { panic("bug") } } newList.Append(e) } src = newList } return &tast.AssignStmt{dest, op, src} }
func varDeclPrepare( b *builder, toks []*lex8.Token, lst *tast.ExprList, t types.T, ) *tast.ExprList { ret := tast.NewExprList() for i, tok := range toks { e := lst.Exprs[i] etype := e.Type() if types.IsNil(etype) { e = tast.NewCast(e, t) } else if v, ok := types.NumConst(etype); ok { e = constCast(b, tok.Pos, v, e, t) if e == nil { return nil } } ret.Append(e) } return ret }
func buildReturnStmt(b *builder, stmt *ast.ReturnStmt) tast.Stmt { pos := stmt.Kw.Pos if stmt.Exprs == nil { if b.retType == nil || b.retNamed { return &tast.ReturnStmt{} } b.Errorf(pos, "expects return %s", fmt8.Join(b.retType, ",")) return nil } if b.retType == nil { b.Errorf(pos, "function expects no return value") return nil } src := b.buildExpr(stmt.Exprs) if src == nil { return nil } srcRef := src.R() nret := len(b.retType) nsrc := srcRef.Len() if nret != nsrc { b.Errorf(pos, "expect (%s), returning (%s)", fmt8.Join(b.retType, ","), srcRef, ) return nil } for i := 0; i < nret; i++ { t := b.retType[i] srcType := srcRef.At(i).Type() if !types.CanAssign(t, srcType) { b.Errorf(pos, "expect (%s), returning (%s)", fmt8.Join(b.retType, ","), srcRef, ) return nil } } // insert implicit type casts if srcList, ok := tast.MakeExprList(src); ok { newList := tast.NewExprList() for i, e := range srcList.Exprs { t := e.Type() if types.IsNil(t) { e = tast.NewCast(e, b.retType[i]) } else if v, ok := types.NumConst(t); ok { e = constCast(b, nil, v, e, b.retType[i]) if e == nil { panic("bug") } } newList.Append(e) } src = newList } return &tast.ReturnStmt{src} }
func buildCallMake(b *builder, expr *ast.CallExpr, f tast.Expr) tast.Expr { args := buildExprList(b, expr.Args) if args == nil { return nil } n := args.R().Len() if n == 0 { b.Errorf(expr.Lparen.Pos, "make() takes at least one argument") return nil } argsList, ok := tast.MakeExprList(args) if !ok { b.Errorf(expr.Lparen.Pos, "make() only takes a literal list") return nil } arg0 := argsList.Exprs[0] t, ok := arg0.R().T.(*types.Type) if !ok { b.Errorf(expr.Lparen.Pos, "make() takes a type as the 1st argument") return nil } switch st := t.T.(type) { case *types.Slice: if n != 3 { b.Errorf(expr.Lparen.Pos, "make() slice takes 3 arguments") return nil } size := argsList.Exprs[1] pos := ast.ExprPos(expr.Args.Exprs[1]) size = checkArrayIndex(b, size, pos) if size == nil { return nil } start := argsList.Exprs[2] startType := start.R().T startPos := ast.ExprPos(expr.Args.Exprs[2]) if v, ok := types.NumConst(startType); ok { start = constCastUint(b, startPos, v, start) if start == nil { return nil } } else if !types.IsBasic(startType, types.Uint) { pt := types.PointerOf(startType) if pt == nil || !types.SameType(pt, st.T) { b.Errorf(startPos, "make() takes an uint or a typed pointer as the 3rd arg", ) return nil } } callArgs := tast.NewExprList() callArgs.Append(arg0) callArgs.Append(size) callArgs.Append(start) r := tast.NewRef(st) return &tast.CallExpr{f, callArgs, r} } b.Errorf(expr.Lparen.Pos, "cannot make() type %s", t.T) return nil }
func buildCallExpr(b *builder, expr *ast.CallExpr) tast.Expr { f := b.buildExpr(expr.Func) if f == nil { return nil } pos := ast.ExprPos(expr.Func) fref := f.R() if !fref.IsSingle() { b.Errorf(pos, "%s is not callable", fref) return nil } if t, ok := fref.T.(*types.Type); ok { return buildCast(b, expr, t.T) } builtin, ok := fref.T.(*types.BuiltInFunc) if ok { switch builtin.Name { case "len": return buildCallLen(b, expr, f) case "make": return buildCallMake(b, expr, f) } b.Errorf(pos, "builtin %s() not implemented", builtin.Name) return nil } funcType, ok := fref.T.(*types.Func) if !ok { b.Errorf(pos, "function call on non-callable: %s", fref) return nil } args := buildExprList(b, expr.Args) if args == nil { return nil } argsRef := args.R() nargs := argsRef.Len() if nargs != len(funcType.Args) { b.Errorf(ast.ExprPos(expr), "argument expects (%s), got (%s)", fmt8.Join(funcType.Args, ","), args, ) return nil } // type check on each argument for i := 0; i < nargs; i++ { argType := argsRef.At(i).Type() expect := funcType.Args[i].T if !types.CanAssign(expect, argType) { pos := ast.ExprPos(expr.Args.Exprs[i]) b.Errorf(pos, "argument %d expects %s, got %s", i+1, expect, argType, ) return nil } } // insert casting when it is a literal expression list. callArgs, ok := tast.MakeExprList(args) if ok { castedArgs := tast.NewExprList() for i := 0; i < nargs; i++ { argExpr := callArgs.Exprs[i] argType := argExpr.Type() expect := funcType.Args[i].T // insert auto casts for consts if types.IsNil(argType) { castedArgs.Append(tast.NewCast(argExpr, expect)) } else if _, ok := types.NumConst(argType); ok { castedArgs.Append(tast.NewCast(argExpr, expect)) } else { castedArgs.Append(argExpr) } } args = castedArgs } retRef := tast.Void for _, t := range funcType.RetTypes { retRef = tast.AppendRef(retRef, tast.NewRef(t)) } return &tast.CallExpr{f, args, retRef} }