diff --git a/compiler/compiler.go b/compiler/compiler.go index efbdbccd..f14193a8 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -3054,7 +3054,7 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value) ( } else if typ.Info()&types.IsFloat != 0 { // Operations on floats switch op { - case token.ADD: + case token.ADD: // + return c.builder.CreateFAdd(x, y, ""), nil case token.SUB: // - return c.builder.CreateFSub(x, y, ""), nil @@ -3102,14 +3102,23 @@ func (c *Compiler) parseBinOp(op token.Token, typ types.Type, x, y llvm.Value) ( } else if typ.Info()&types.IsString != 0 { // Operations on strings switch op { - case token.ADD: + case token.ADD: // + return c.createRuntimeCall("stringConcat", []llvm.Value{x, y}, ""), nil - case token.EQL, token.NEQ: // ==, != + case token.EQL: // == + return c.createRuntimeCall("stringEqual", []llvm.Value{x, y}, ""), nil + case token.NEQ: // != result := c.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "") - if op == token.NEQ { - result = c.builder.CreateNot(result, "") - } - return result, nil + return c.builder.CreateNot(result, ""), nil + case token.LSS: // < + return c.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil + case token.LEQ: // <= + result := c.createRuntimeCall("stringLess", []llvm.Value{y, x}, "") + return c.builder.CreateNot(result, ""), nil + case token.GTR: // > + result := c.createRuntimeCall("stringLess", []llvm.Value{x, y}, "") + return c.builder.CreateNot(result, ""), nil + case token.GEQ: // >= + return c.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil default: return llvm.Value{}, errors.New("todo: binop on string: " + op.String()) } diff --git a/src/runtime/string.go b/src/runtime/string.go index 540c6410..f3e42df7 100644 --- a/src/runtime/string.go +++ b/src/runtime/string.go @@ -32,6 +32,24 @@ func stringEqual(x, y string) bool { return true } +// Return true iff x < y. +//go:nobounds +func stringLess(x, y string) bool { + l := len(x) + if m := len(y); m < l { + l = m + } + for i := 0; i < l; i++ { + if x[i] < y[i] { + return true + } + if x[i] > y[i] { + return false + } + } + return len(x) < len(y) +} + // Add two strings together. func stringConcat(x, y _string) _string { if x.length == 0 { diff --git a/testdata/binop.go b/testdata/binop.go index 5526d13b..24774aad 100644 --- a/testdata/binop.go +++ b/testdata/binop.go @@ -1,13 +1,30 @@ package main func main() { - // string equality + println("string equality") println(a == "a") println(a == "b") println(a != "a") println(a != "b") + println("string inequality") + println(a > "b") + println("b" > a) + println("b" > "b") + println(a <= "b") + println("b" <= a) + println("b" <= "b") + println(a > "b") + println("b" > a) + println("b" > "b") + println(a <= "b") + println("b" <= a) + println("b" <= "b") + println(a < "aa") + println("aa" < a) + println("ab" < "aa") + println("aa" < "ab") - // struct equality + println("struct equality") println(s1 == Struct1{3, true}) println(s1 == Struct1{4, true}) println(s1 == Struct1{3, false}) @@ -17,7 +34,7 @@ func main() { println(s1 != Struct1{3, false}) println(s1 != Struct1{4, false}) - // blank fields in structs + println("blank fields in structs") println(s2 == Struct2{"foo", 0.0, 5}) println(s2 == Struct2{"foo", 0.0, 7}) println(s2 == Struct2{"foo", 1.0, 5}) diff --git a/testdata/binop.txt b/testdata/binop.txt index ef3bec46..1e2f40e7 100644 --- a/testdata/binop.txt +++ b/testdata/binop.txt @@ -1,7 +1,26 @@ +string equality true false false true +string inequality +false +true +false +true +false +true +false +true +false +true +false +true +true +false +false +true +struct equality true false false @@ -10,6 +29,7 @@ false true true true +blank fields in structs true false true