Beispiel #1
0
func (caller *frame) callCommon(call *ssa.Call, common *ssa.CallCommon) {
	switch fn := common.Value.(type) {
	case *ssa.Builtin:
		caller.callBuiltin(common)

	case *ssa.MakeClosure:
		// TODO(nickng) Handle calling closure
		fmt.Fprintf(os.Stderr, "   # TODO (handle closure) %s\n", fn.String())

	case *ssa.Function:
		if common.StaticCallee() == nil {
			panic("Call with nil CallCommon!")
		}

		callee := &frame{
			fn:      common.StaticCallee(),
			locals:  make(map[ssa.Value]*utils.Definition),
			arrays:  make(map[*utils.Definition]Elems),
			structs: make(map[*utils.Definition]Fields),
			tuples:  make(map[ssa.Value]Tuples),
			phi:     make(map[ssa.Value][]ssa.Value),
			recvok:  make(map[ssa.Value]*sesstype.Chan),
			retvals: make(Tuples, common.Signature().Results().Len()),
			defers:  make([]*ssa.Defer, 0),
			caller:  caller,
			env:     caller.env,   // Use the same env as caller
			gortn:   caller.gortn, // Use the same role as caller
		}

		fmt.Fprintf(os.Stderr, "++ call %s(", orange(common.StaticCallee().String()))
		callee.translate(common)
		fmt.Fprintf(os.Stderr, ")\n")

		if callee.isRecursive() {
			fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(common.StaticCallee().String()))
			callee.printCallStack()
		} else {
			if hasCode := visitFunc(callee.fn, callee); hasCode {
				caller.handleRetvals(call.Value(), callee)
			} else {
				caller.handleExtRetvals(call.Value(), callee)
			}
			fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(common.StaticCallee().String()), len(callee.retvals))
		}

	default:
		if !common.IsInvoke() {
			fmt.Fprintf(os.Stderr, "Unknown call type %v\n", common)
			return
		}

		switch vd, kind := caller.get(common.Value); kind {
		case Struct, LocalStruct:
			fmt.Fprintf(os.Stderr, "++ invoke %s.%s, type=%s\n", reg(common.Value), common.Method.String(), vd.Var.Type().String())
			// If dealing with interfaces, check that the method is invokable
			if iface, ok := common.Value.Type().Underlying().(*types.Interface); ok {
				if meth, _ := types.MissingMethod(vd.Var.Type(), iface, true); meth != nil {
					fmt.Fprintf(os.Stderr, "     ^ interface not fully implemented\n")
				} else {
					fn := findMethod(common.Value.Parent().Prog, common.Method, vd.Var.Type())
					if fn != nil {
						fmt.Fprintf(os.Stderr, "     ^ found function %s\n", fn.String())

						callee := &frame{
							fn:      fn,
							locals:  make(map[ssa.Value]*utils.Definition),
							arrays:  make(map[*utils.Definition]Elems),
							structs: make(map[*utils.Definition]Fields),
							tuples:  make(map[ssa.Value]Tuples),
							phi:     make(map[ssa.Value][]ssa.Value),
							recvok:  make(map[ssa.Value]*sesstype.Chan),
							retvals: make(Tuples, common.Signature().Results().Len()),
							defers:  make([]*ssa.Defer, 0),
							caller:  caller,
							env:     caller.env,   // Use the same env as caller
							gortn:   caller.gortn, // Use the same role as caller
						}

						common.Args = append([]ssa.Value{common.Value}, common.Args...)
						fmt.Fprintf(os.Stderr, "++ call %s(", orange(fn.String()))
						callee.translate(common)
						fmt.Fprintf(os.Stderr, ")\n")

						if callee.isRecursive() {
							fmt.Fprintf(os.Stderr, "-- Recursive %s()\n", orange(fn.String()))
							callee.printCallStack()
						} else {
							if hasCode := visitFunc(callee.fn, callee); hasCode {
								caller.handleRetvals(call.Value(), callee)
							} else {
								caller.handleExtRetvals(call.Value(), callee)
							}
							fmt.Fprintf(os.Stderr, "-- return from %s (%d retvals)\n", orange(fn.String()), len(callee.retvals))
						}

					} else {
						panic(fmt.Sprintf("Cannot call function: %s.%s is abstract (program not well-formed)", common.Value, common.Method.String()))
					}
				}
			} else {
				fmt.Fprintf(os.Stderr, "     ^ method %s.%s does not exist\n", reg(common.Value), common.Method.String())
			}

		default:
			fmt.Fprintf(os.Stderr, "++ invoke %s.%s\n", reg(common.Value), common.Method.String())
		}
	}
}