func buildCallExpr(b *builder, expr *ast.CallExpr) *ref { f := b.buildExpr(expr.Func) if f == nil { return nil } pos := ast.ExprPos(expr.Func) if !f.IsSingle() { b.Errorf(pos, "expression list is not callable") return nil } funcType, ok := f.Type().(*types.Func) // the func sig in the builder if !ok { // not a function b.Errorf(pos, "function call on non-callable") return nil } args := buildExprList(b, expr.Args) if args == nil { return nil } if args.Len() != len(funcType.Args) { b.Errorf(ast.ExprPos(expr), "argument expects (%s), got (%s)", fmt8.Join(funcType.Args, ","), fmt8.Join(args.typ, ","), ) return nil } // type check on parameters for i, argType := range args.typ { 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, ) } } ret := new(ref) ret.typ = funcType.RetTypes for _, t := range funcType.RetTypes { ret.ir = append(ret.ir, b.f.NewTemp(t.Size(), types.IsByte(t))) } // call the func in IR b.b.Call(ret.ir, f.IR(), funcType.Sig, args.ir...) return ret }
func buildExprStmt(b *builder, expr ast.Expr) { if e, ok := expr.(*ast.CallExpr); ok { buildCallExpr(b, e) } else { b.Errorf(ast.ExprPos(expr), "invalid expression statement") } }
func buildIf(b *builder, cond ast.Expr, ifs ast.Stmt, elses *ast.ElseStmt) { c := buildExpr(b, cond) if !c.IsBool() { pos := ast.ExprPos(cond) b.Errorf(pos, "expect boolean expression, got %s", c) return } if elses == nil { body := b.f.NewBlock(b.b) after := b.f.NewBlock(body) b.b.JumpIfNot(c.IR(), after) b.b = body switch ifs := ifs.(type) { case *ast.Block: buildBlock(b, ifs) case *ast.ReturnStmt: buildReturnStmt(b, ifs) case *ast.BreakStmt: buildBreakStmt(b, ifs) case *ast.ContinueStmt: buildContinueStmt(b, ifs) default: b.Errorf(ast.ExprPos(cond), "short if statement not implemented") } b.b = after return } ifBody := b.f.NewBlock(b.b) elseBody := b.f.NewBlock(ifBody) after := b.f.NewBlock(elseBody) b.b.JumpIfNot(c.IR(), elseBody) ifBody.Jump(after) b.b = ifBody // switch to if body buildBlock(b, ifs.(*ast.Block)) b.b = elseBody buildElseStmt(b, elses) b.b = after }
func buildForStmt(b *builder, stmt *ast.ForStmt) { if stmt.Init == nil && stmt.Iter == nil { if stmt.Cond == nil { body := b.f.NewBlock(b.b) after := b.f.NewBlock(body) body.Jump(body) b.b = body b.breaks.push(after, "") b.continues.push(body, "") buildBlock(b, stmt.Body) b.breaks.pop() b.continues.pop() b.b = after } else { condBlock := b.f.NewBlock(b.b) body := b.f.NewBlock(condBlock) after := b.f.NewBlock(body) body.Jump(condBlock) b.b = condBlock c := buildExpr(b, stmt.Cond) if !c.IsBool() { pos := ast.ExprPos(stmt.Cond) b.Errorf(pos, "expect boolean expression, got %s", c) b.b = after return } condBlock.JumpIfNot(c.IR(), after) b.b = body b.breaks.push(after, "") b.continues.push(condBlock, "") buildBlock(b, stmt.Body) b.breaks.pop() b.continues.pop() b.b = after } } else { b.Errorf(stmt.Kw.Pos, "advanced for statement not implemented yet") } }
func buildType(b *builder, expr ast.Expr) types.T { if expr == nil { panic("bug") } var ret *ref switch expr := expr.(type) { case *ast.Operand: ret = buildOperand(b, expr) default: b.Errorf(ast.ExprPos(expr), "expect a type") return nil } if ret == nil { return nil } else if !ret.IsType() { b.Errorf(ast.ExprPos(expr), "expect a type") return nil } return ret.TypeType() }
func buildDefineStmt(b *builder, stmt *ast.DefineStmt) { right := buildExprList(b, stmt.Right) if right == nil { // an error occured on the expression list return } idents, err := buildIdentExprList(b, stmt.Left) if err != nil { b.Errorf(ast.ExprPos(err), "left side of := must be identifer") return } define(b, idents, right, stmt.Define) }
func buildExpr(b *builder, expr ast.Expr) *ref { 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.OpExpr: return buildOpExpr(b, expr) case *ast.CallExpr: return buildCallExpr(b, expr) default: 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 := buildType(b, 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 ret }