diff --git a/compiler.go b/compiler.go index 564940bf..aed6be0b 100644 --- a/compiler.go +++ b/compiler.go @@ -1835,7 +1835,13 @@ func (c *Compiler) parseBinOp(frame *Frame, binop *ssa.BinOp) (llvm.Value, error } switch binop.Op { case token.ADD: // + - return c.builder.CreateAdd(x, y, ""), nil + if typ, ok := binop.X.Type().(*types.Basic); ok && typ.Kind() == types.String { + // string concatenation + fn := c.mod.NamedFunction("runtime.stringConcat") + return c.builder.CreateCall(fn, []llvm.Value{x, y}, ""), nil + } else { + return c.builder.CreateAdd(x, y, ""), nil + } case token.SUB: // - return c.builder.CreateSub(x, y, ""), nil case token.MUL: // * diff --git a/src/runtime/string.go b/src/runtime/string.go index aa5d34ad..e1196509 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -2,11 +2,17 @@ package runtime // This file implements functions related to Go strings. +import ( + "unsafe" +) + +// The underlying struct for the Go string type. type _string struct { length lenType ptr *uint8 } +// Return true iff the strings match. func stringEqual(x, y string) bool { if len(x) != len(y) { return false @@ -18,3 +24,18 @@ func stringEqual(x, y string) bool { } return true } + +// Add two strings together. +func stringConcat(x, y _string) _string { + if x.length == 0 { + return y + } else if y.length == 0 { + return x + } else { + length := uintptr(x.length + y.length) + buf := alloc(length) + memcpy(buf, unsafe.Pointer(x.ptr), uintptr(x.length)) + memcpy(unsafe.Pointer(uintptr(buf)+uintptr(x.length)), unsafe.Pointer(y.ptr), uintptr(y.length)) + return _string{lenType(length), (*uint8)(buf)} + } +}