func (fr *frame) callBuiltin(typ types.Type, builtin *ssa.Builtin, args []ssa.Value) []*govalue { switch builtin.Name() { case "print", "println": llargs := make([]*govalue, len(args)) for i, arg := range args { llargs[i] = fr.value(arg) } fr.printValues(builtin.Name() == "println", llargs...) return nil case "panic": fr.callPanic(fr.value(args[0])) return nil case "recover": return []*govalue{fr.callRecover(false)} case "append": return []*govalue{fr.callAppend(fr.value(args[0]), fr.value(args[1]))} case "close": fr.chanClose(fr.value(args[0])) return nil case "cap": return []*govalue{fr.callCap(fr.value(args[0]))} case "len": return []*govalue{fr.callLen(fr.value(args[0]))} case "copy": return []*govalue{fr.callCopy(fr.value(args[0]), fr.value(args[1]))} case "delete": fr.mapDelete(fr.value(args[0]), fr.value(args[1])) return nil case "real": return []*govalue{fr.extractRealValue(fr.value(args[0]))} case "imag": return []*govalue{fr.extractImagValue(fr.value(args[0]))} case "complex": r := fr.llvmvalue(args[0]) i := fr.llvmvalue(args[1]) cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ)) cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "") cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "") return []*govalue{newValue(cmplx, typ)} case "ssa:wrapnilchk": ptr := fr.value(args[0]) fr.nilCheck(args[0], ptr.value) return []*govalue{ptr} default: panic("unimplemented: " + builtin.Name()) } }
func (f *Function) Builtin(call *ssa.Call, builtin *ssa.Builtin) (string, *Error) { obj := builtin.Object() if builtin.Name() == "len" && obj.String() == "builtin len" { return f.Len(call) } else { return ErrorMsg(fmt.Sprintf("builtin (%v) not supported", builtin.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 or copy([]byte, string) int src := args[1] if _, ok := src.(string); ok { params := fn.Type().(*types.Signature).Params() src = conv(params.At(0).Type(), params.At(1).Type(), src) } return copy(args[0].([]value), src.([]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) case "ssa:wrapnilchk": recv := args[0] if recv.(*value) == nil { recvType := args[1] methodName := args[2] panic(fmt.Sprintf("value method (%s).%s called using nil *%s pointer", recvType, methodName, recvType)) } return recv } panic("unknown built-in: " + fn.Name()) }