Beispiel #1
0
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
}
Beispiel #2
0
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")
	}
}
Beispiel #3
0
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
}
Beispiel #4
0
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")
	}
}
Beispiel #5
0
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()
}
Beispiel #6
0
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)
}
Beispiel #7
0
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
	}
}
Beispiel #8
0
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
}