// callBuiltin interprets a call to builtin fn with arguments args, // returning its result. func callBuiltin(caller *frame, callpos token.Pos, fn *ssa.Builtin, args []value) value { switch fn.Name() { case "append": if len(args) == 1 { return args[0] } if s, ok := args[1].(string); ok { // append([]byte, ...string) []byte arg0 := args[0].([]value) for i := 0; i < len(s); i++ { arg0 = append(arg0, s[i]) } return arg0 } // append([]T, ...[]T) []T return append(args[0].([]value), args[1].([]value)...) case "copy": // copy([]T, []T) int if _, ok := args[1].(string); ok { panic("copy([]byte, string) not yet implemented") } return copy(args[0].([]value), args[1].([]value)) case "close": // close(chan T) close(args[0].(chan value)) return nil case "delete": // delete(map[K]value, K) switch m := args[0].(type) { case map[value]value: delete(m, args[1]) case *hashmap: m.delete(args[1].(hashable)) default: panic(fmt.Sprintf("illegal map type: %T", m)) } return nil case "print", "println": // print(any, ...) ln := fn.Name() == "println" var buf bytes.Buffer for i, arg := range args { if i > 0 && ln { buf.WriteRune(' ') } buf.WriteString(toString(arg)) } if ln { buf.WriteRune('\n') } write(1, buf.Bytes()) return nil case "len": switch x := args[0].(type) { case string: return len(x) case array: return len(x) case *value: return len((*x).(array)) case []value: return len(x) case map[value]value: return len(x) case *hashmap: return x.len() case chan value: return len(x) default: panic(fmt.Sprintf("len: illegal operand: %T", x)) } case "cap": switch x := args[0].(type) { case array: return cap(x) case *value: return cap((*x).(array)) case []value: return cap(x) case chan value: return cap(x) default: panic(fmt.Sprintf("cap: illegal operand: %T", x)) } case "real": switch c := args[0].(type) { case complex64: return real(c) case complex128: return real(c) default: panic(fmt.Sprintf("real: illegal operand: %T", c)) } case "imag": switch c := args[0].(type) { case complex64: return imag(c) case complex128: return imag(c) default: panic(fmt.Sprintf("imag: illegal operand: %T", c)) } case "complex": switch f := args[0].(type) { case float32: return complex(f, args[1].(float32)) case float64: return complex(f, args[1].(float64)) default: panic(fmt.Sprintf("complex: illegal operand: %T", f)) } case "panic": // ssa.Panic handles most cases; this is only for "go // panic" or "defer panic". panic(targetPanic{args[0]}) case "recover": return doRecover(caller) } panic("unknown built-in: " + fn.Name()) }
// callBuiltin interprets a call to builtin fn with arguments args, // returning its result. func callBuiltin(caller *frame, callpos token.Pos, fn *ssa.Builtin, args []value) value { switch fn.Name() { case "append": if len(args) == 1 { return args[0] } if s, ok := args[1].(string); ok { // append([]byte, ...string) []byte arg0 := args[0].([]value) for i := 0; i < len(s); i++ { arg0 = append(arg0, s[i]) } return arg0 } // append([]T, ...[]T) []T return append(args[0].([]value), args[1].([]value)...) case "copy": // copy([]T, []T) int if _, ok := args[1].(string); ok { panic("copy([]byte, string) not yet implemented") } return copy(args[0].([]value), args[1].([]value)) case "close": // close(chan T) close(args[0].(chan value)) return nil case "delete": // delete(map[K]value, K) switch m := args[0].(type) { case map[value]value: delete(m, args[1]) case *hashmap: m.delete(args[1].(hashable)) default: panic(fmt.Sprintf("illegal map type: %T", m)) } return nil case "print", "println": // print(anytype, ...interface{}) ln := fn.Name() == "println" fmt.Print(toString(args[0])) if len(args) == 2 { for _, arg := range args[1].([]value) { if ln { fmt.Print(" ") } fmt.Print(toString(arg)) } } if ln { fmt.Println() } return nil case "len": switch x := args[0].(type) { case string: return len(x) case array: return len(x) case *value: return len((*x).(array)) case []value: return len(x) case map[value]value: return len(x) case *hashmap: return x.len() case chan value: return len(x) default: panic(fmt.Sprintf("len: illegal operand: %T", x)) } case "cap": switch x := args[0].(type) { case array: return cap(x) case *value: return cap((*x).(array)) case []value: return cap(x) case chan value: return cap(x) default: panic(fmt.Sprintf("cap: illegal operand: %T", x)) } case "real": switch c := args[0].(type) { case complex64: return real(c) case complex128: return real(c) default: panic(fmt.Sprintf("real: illegal operand: %T", c)) } case "imag": switch c := args[0].(type) { case complex64: return imag(c) case complex128: return imag(c) default: panic(fmt.Sprintf("imag: illegal operand: %T", c)) } case "complex": switch f := args[0].(type) { case float32: return complex(f, args[1].(float32)) case float64: return complex(f, args[1].(float64)) default: panic(fmt.Sprintf("complex: illegal operand: %T", f)) } case "panic": // ssa.Panic handles most cases; this is only for "go // panic" or "defer panic". panic(targetPanic{args[0]}) case "recover": // recover() must be exactly one level beneath the // deferred function (two levels beneath the panicking // function) to have any effect. Thus we ignore both // "defer recover()" and "defer f() -> g() -> // recover()". if caller.i.mode&DisableRecover == 0 && caller != nil && caller.status == stRunning && caller.caller != nil && caller.caller.status == stPanic { caller.caller.status = stComplete p := caller.caller.panic caller.caller.panic = nil switch p := p.(type) { case targetPanic: return p.v case runtime.Error: // TODO(adonovan): must box this up // inside instance of interface 'error'. return iface{types.Typ[types.String], p.Error()} case string: return iface{types.Typ[types.String], p} default: panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p)) } } return iface{} } panic("unknown built-in: " + fn.Name()) }