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 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 }
func buildPkgConstDecl(b *builder, d *ast.ConstDecl) []*pkgConst { if d.Type != nil { b.Errorf(ast.ExprPos(d.Type), "typed const not implemented") return nil } nident := len(d.Idents.Idents) nexpr := len(d.Exprs.Exprs) if nident != nexpr { b.Errorf(d.Eq.Pos, "%d consts with %d expressions", nident, nexpr, ) return nil } var ret []*pkgConst zero := types.NewNumber(0) // place holding the const for i, ident := range d.Idents.Idents { s := declareConst(b, ident, zero) if s == nil { return nil } expr := d.Exprs.Exprs[i] c := &pkgConst{ sym: s, tok: ident, expr: expr, deps: symUse(expr), } ret = append(ret, c) } return ret }
func buildForStmt(b *builder, stmt *ast.ForStmt) tast.Stmt { b.scope.Push() defer b.scope.Pop() ret := new(tast.ForStmt) if stmt.Init != nil { ret.Init = b.buildStmt(stmt.Init) } if stmt.Cond != nil { ret.Cond = b.buildExpr(stmt.Cond) if ret.Cond == nil { return nil } ref := ret.Cond.R() if !ref.IsBool() { pos := ast.ExprPos(stmt.Cond) b.Errorf(pos, "expect boolean expression, got %s", ref) return nil } } b.nloop++ ret.Body = buildBlock(b, stmt.Body) b.nloop-- if stmt.Iter != nil { ret.Iter = b.buildStmt(stmt.Iter) } return ret }
func (b *builder) buildConst(expr ast.Expr) *tast.Const { ret, ok := b.buildConstExpr(expr).(*tast.Const) if !ok { b.Errorf(ast.ExprPos(expr), "expect a const") return nil } return ret }
func buildArrayType(b *builder, expr *ast.ArrayTypeExpr) types.T { t := buildType(b, expr.Type) if t == nil { return nil } if expr.Len == nil { // slice return &types.Slice{t} } // array n := b.buildConstExpr(expr.Len) if n == nil { return nil } ntype := n.R().T c, ok := ntype.(*types.Const) if !ok { // might be true, false, or other builtin consts b.Errorf(ast.ExprPos(expr), "array index is not a constant") return nil } if v, ok := types.NumConst(ntype); ok { if v < 0 { b.Errorf(ast.ExprPos(expr), "array index is negative: %d", c.Value, ) return nil } else if !types.InRange(v, types.Int) { b.Errorf(ast.ExprPos(expr), "index out of range of int32") return nil } return &types.Array{T: t, N: int32(v)} } // TODO: support typed const b.Errorf(ast.ExprPos(expr), "typed const not implemented yet") return nil }
func buildExprStmt(b *builder, expr ast.Expr) tast.Stmt { if e, ok := expr.(*ast.CallExpr); ok { ret := buildExpr(b, e) if ret == nil { return nil } return &tast.ExprStmt{ret} } b.Errorf(ast.ExprPos(expr), "invalid expression statement") return nil }
func buildConstDecl(b *builder, d *ast.ConstDecl) *tast.Define { if d.Type != nil { b.Errorf(ast.ExprPos(d.Type), "typed const not implemented yet") return nil } right := buildConstExprList(b, d.Exprs) if right == nil { return nil } nright := right.R().Len() idents := d.Idents.Idents nleft := len(idents) if nleft != nright { b.Errorf(d.Eq.Pos, "%d values for %d identifiers", nright, nleft, ) return nil } var syms []*sym8.Symbol for i, ident := range idents { t := right.R().At(i).Type() if !types.IsConst(t) { b.Errorf(ast.ExprPos(d.Exprs.Exprs[i]), "not a const") return nil } sym := declareConst(b, ident, t) if sym == nil { return nil } syms = append(syms, sym) } return &tast.Define{syms, right} }
func buildPkgConst(b *builder, c *pkgConst) *sym8.Symbol { right := b.buildConstExpr(c.expr) if right == nil { return nil } res, ok := right.(*tast.Const) if !ok { b.Errorf(ast.ExprPos(c.expr), "expect a const") return nil } t := res.Ref.Type() c.sym.ObjType = t return c.sym }
func buildDefineStmt(b *builder, stmt *ast.DefineStmt) tast.Stmt { right := b.buildExpr(stmt.Right) if right == nil { return nil } idents, err := buildIdentExprList(b, stmt.Left) if err != nil { b.Errorf(ast.ExprPos(err), "left side of := must be identifier") return nil } ret := define(b, idents, right, stmt.Define) if ret == nil { return nil } return ret }
func buildConstExpr(b *builder, expr ast.Expr) tast.Expr { if expr == nil { panic("bug") } switch expr := expr.(type) { case *ast.ParenExpr: return buildConstExpr(b, expr.Expr) case *ast.Operand: return buildConstOperand(b, expr) case *ast.MemberExpr: return buildConstMember(b, expr) case *ast.OpExpr: return buildConstOpExpr(b, expr) } b.Errorf(ast.ExprPos(expr), "expect a const expression") return nil }
func buildExpr(b *builder, expr ast.Expr) tast.Expr { if expr == nil { panic("bug") } switch expr := expr.(type) { case *ast.Operand: return buildOperand(b, expr) case *ast.ParenExpr: return buildExpr(b, expr.Expr) case *ast.MemberExpr: return buildMember(b, expr) case *ast.OpExpr: return buildOpExpr(b, expr) case *ast.StarExpr: return buildStarExpr(b, expr) case *ast.IndexExpr: return buildIndexExpr(b, expr) case *ast.CallExpr: return buildCallExpr(b, expr) case *ast.ArrayTypeExpr: t := b.buildType(expr) if t == nil { return nil } return tast.NewType(t) case *ast.FuncTypeExpr: t := b.buildType(expr) if t == nil { return nil } return tast.NewType(t) case *ast.ExprList: return buildExprList(b, expr) case *ast.ArrayLiteral: return buildArrayLit(b, expr) } b.Errorf(ast.ExprPos(expr), "invalid or not implemented: %T", expr) return nil }
func buildNamedParaList(b *builder, lst *ast.ParaList) []*types.Arg { ret := make([]*types.Arg, lst.Len()) // named typeed list for i, para := range lst.Paras { if para.Ident == nil { b.Errorf(ast.ExprPos(para.Type), "expect identifer as argument name", ) return nil } name := para.Ident.Lit if name == "_" { name = "" } ret[i] = &types.Arg{Name: name} if para.Type == nil { continue } t := b.buildType(para.Type) if t == nil { return nil } // go back and assign types for j := i; j >= 0 && ret[j].T == nil; j-- { ret[j].T = t } } // check that everything has a type if len(ret) > 0 && ret[len(ret)-1].T == nil { b.Errorf(lst.Rparen.Pos, "missing type in argument list") return nil } return ret }
func buildVarDecl(b *builder, d *ast.VarDecl) *tast.Define { ids := d.Idents.Idents if d.Eq != nil { right := b.buildExpr(d.Exprs) if right == nil { return nil } if d.Type == nil { ret := define(b, ids, right, d.Eq) if ret == nil { return nil } return ret } tdest := b.buildType(d.Type) if tdest == nil { return nil } if !types.IsAllocable(tdest) { pos := ast.ExprPos(d.Type) b.Errorf(pos, "%s is not allocatable", tdest) return nil } // assignable check ts := right.R().TypeList() for _, t := range ts { if !types.CanAssign(tdest, t) { b.Errorf(d.Eq.Pos, "cannot assign %s to %s", t, tdest) return nil } } // cast literal expression lists // after the casting, all types should be matching to tdest if exprList, ok := tast.MakeExprList(right); ok { exprList = varDeclPrepare(b, ids, exprList, tdest) if exprList == nil { return nil } right = exprList } syms := declareVars(b, ids, tdest, false) if syms == nil { return nil } return &tast.Define{syms, right} } if d.Type == nil { panic("type missing") } t := b.buildType(d.Type) if t == nil { return nil } syms := declareVars(b, ids, t, false) if syms == nil { return nil } return &tast.Define{syms, nil} }
func buildArrayLit(b *builder, lit *ast.ArrayLiteral) tast.Expr { hold := b.lhsSwap(false) defer b.lhsRestore(hold) if lit.Type.Len != nil { b.Errorf( ast.ExprPos(lit), "array literal with length not supported yet", ) return nil } buf := new(bytes.Buffer) t := buildType(b, lit.Type.Type) if t == nil { return nil } if !types.IsInteger(t) { pos := ast.ExprPos(lit.Type.Type) b.Errorf(pos, "array literal must be integer type") return nil } bt := t.(types.Basic) if lit.Exprs != nil { for _, expr := range lit.Exprs.Exprs { n := b.buildConstExpr(expr) if n == nil { return nil } ntype := n.R().T if _, ok := ntype.(*types.Const); !ok { b.Errorf(ast.ExprPos(expr), "array literal not a constant") return nil } if v, ok := types.NumConst(ntype); ok { if !types.InRange(v, t) { b.Errorf( ast.ExprPos(expr), "constant out of range of %s", t, ) return nil } switch bt { case types.Int, types.Uint: var bs [4]byte binary.LittleEndian.PutUint32(bs[:], uint32(v)) buf.Write(bs[:]) case types.Int8, types.Uint8: buf.Write([]byte{byte(v)}) default: panic("not integer") } } } } ref := tast.NewConstRef(&types.Slice{bt}, buf.Bytes()) return &tast.Const{ref} }
func buildType(b *builder, expr ast.Expr) types.T { if expr == nil { panic("bug") } switch expr := expr.(type) { case *ast.Operand: ret := buildOperand(b, expr) if ret == nil { return nil } ref := ret.R() t, ok := ref.T.(*types.Type) if !ok { b.Errorf(ast.ExprPos(expr), "expect a type, got %s", ref.T) return nil } return t.T case *ast.StarExpr: t := buildType(b, expr.Expr) if t == nil { return nil } return &types.Pointer{t} case *ast.ArrayTypeExpr: return buildArrayType(b, expr) case *ast.ParenExpr: return buildType(b, expr.Expr) case *ast.FuncTypeExpr: return buildFuncType(b, nil, expr.FuncSig) case *ast.MemberExpr: op, ok := expr.Expr.(*ast.Operand) if !ok { b.Errorf(ast.ExprPos(expr.Expr), "expect a package") return nil } pkg := buildPkgRef(b, op.Token) if pkg == nil { return nil } name := expr.Sub.Lit s := pkg.Syms.Query(name) if s == nil { b.Errorf(expr.Sub.Pos, "symbol %s not found", name) return nil } if !sym8.IsPublic(name) && s.Pkg() != b.path { b.Errorf(expr.Sub.Pos, "symbol %s is not public", name) return nil } if s.Type != tast.SymStruct { b.Errorf(expr.Sub.Pos, "symbol %s is a %s, not a struct", name, tast.SymStr(s.Type), ) return nil } return s.ObjType.(*types.Type).T } b.Errorf(ast.ExprPos(expr), "expect a type") return nil }
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} }