diff --git a/Makefile b/Makefile index fc9dd62..c6af150 100644 --- a/Makefile +++ b/Makefile @@ -127,6 +127,7 @@ test/example: ${CELL} -d -t riscv tests/examples/helloworld.cell && ckb-debugger --bin helloworld | grep "hello world! 1" ${CELL} -t riscv tests/examples/table.cell && ckb-debugger --bin table ${CELL} -d -t riscv tests/examples/string.cell && ckb-debugger --bin string | grep "eq" + ${CELL} -d -t riscv tests/examples/string-ctor.cell && ckb-debugger --bin string-ctor | grep "s=12" ${CELL} -d -t riscv tests/examples/strings.cell && ckb-debugger --bin strings | grep "aa-bb" ${CELL} -d -t riscv tests/examples/make-slice.cell && ckb-debugger --bin make-slice | grep "0422" ${CELL} -d -t riscv tests/examples/panic.cell && ckb-debugger --bin panic | grep "runtime panic: hah" diff --git a/compiler/compiler/compiler.go b/compiler/compiler/compiler.go index 2cabb66..0fe3099 100644 --- a/compiler/compiler/compiler.go +++ b/compiler/compiler/compiler.go @@ -359,6 +359,8 @@ func (c *Compiler) compileValue(node parser.Node) value.Value { return c.compileNegateBoolNode(v) case *parser.InitializeSliceNode: return c.compileInitializeSliceNode(v) + case *parser.InitializeStringWithSliceNode: + return c.compileInitializeStringWithSliceNode(v) case *parser.SliceArrayNode: src := c.compileValue(v.Val) diff --git a/compiler/compiler/strings.go b/compiler/compiler/strings.go new file mode 100644 index 0000000..eae1258 --- /dev/null +++ b/compiler/compiler/strings.go @@ -0,0 +1,51 @@ +package compiler + +import ( + "github.com/llir/llvm/ir/constant" + llvmTypes "github.com/llir/llvm/ir/types" + llvmValue "github.com/llir/llvm/ir/value" + + "github.com/cell-labs/cell-script/compiler/compiler/internal" + "github.com/cell-labs/cell-script/compiler/compiler/internal/pointer" + "github.com/cell-labs/cell-script/compiler/compiler/name" + "github.com/cell-labs/cell-script/compiler/compiler/value" + "github.com/cell-labs/cell-script/compiler/parser" +) + +func (c *Compiler) compileInitializeStringWithSliceNode(v *parser.InitializeStringWithSliceNode) value.Value { + sliceValue := c.compileValue(v.Items[0]) + srcVal := internal.LoadIfVariable(c.contextBlock, sliceValue) + srcLen := c.contextBlock.NewExtractValue(srcVal, 0) + srcOff := c.contextBlock.NewExtractValue(srcVal, 2) + srcArr := c.contextBlock.NewExtractValue(srcVal, 3) + srcArrStartPtr := c.contextBlock.NewGetElementPtr(pointer.ElemType(srcArr), srcArr, srcOff) + length := c.contextBlock.NewSub(srcLen, srcOff) + // create new string + strVal := c.contextBlock.NewCall(c.osFuncs.Strndup.Value.(llvmValue.Named), srcArrStartPtr, length) + // construct a new string {i64, i8*} + sType, ok := c.packages["global"].GetPkgType("string", true) + if !ok { + panic("string type not found") + } + alloc := c.contextBlock.NewAlloca(sType.LLVM()) + + // Save length of the string + lenItem := c.contextBlock.NewGetElementPtr(pointer.ElemType(alloc), alloc, constant.NewInt(llvmTypes.I32, 0), constant.NewInt(llvmTypes.I32, 0)) + lenItem.SetName(name.Var("len")) + if length.Type() != llvmTypes.I64 { + c.contextBlock.NewStore(c.contextBlock.NewZExt(length, i64.LLVM()), lenItem) + } else { + c.contextBlock.NewStore(length, lenItem) + } + + // Save i8* version of string + strItem := c.contextBlock.NewGetElementPtr(pointer.ElemType(alloc), alloc, constant.NewInt(llvmTypes.I32, 0), constant.NewInt(llvmTypes.I32, 1)) + strItem.SetName(name.Var("str")) + c.contextBlock.NewStore(strVal, strItem) + + return value.Value{ + Value: c.contextBlock.NewLoad(pointer.ElemType(alloc), alloc), + Type: sType, + IsVariable: false, + } +} \ No newline at end of file diff --git a/compiler/parser/node.go b/compiler/parser/node.go index 83a163e..ea0929e 100644 --- a/compiler/parser/node.go +++ b/compiler/parser/node.go @@ -427,6 +427,15 @@ func (i InitializeStructNode) String() string { return fmt.Sprintf("InitializeStructNode-%s{%+v}", i.Type, i.Items) } +type InitializeStringWithSliceNode struct { + baseNode + Items []Node +} + +func (i InitializeStringWithSliceNode) String() string { + return fmt.Sprintf("InitializeStringWithSliceNode-%s{%+v}", i.Items) +} + type DeVariadicSliceNode struct { baseNode Item Node diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 371b049..0e65f78 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -390,6 +390,12 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif } else { panic("wrong argument for slice constructor") } + case *SingleTypeNode: + if t.TypeName == "string" { + return &InitializeStringWithSliceNode{ + Items: items, + } + } default: panic("not supported") } diff --git a/compiler/parser/walk.go b/compiler/parser/walk.go index 633f440..3a29ea5 100644 --- a/compiler/parser/walk.go +++ b/compiler/parser/walk.go @@ -151,6 +151,10 @@ func Walk(v Visitor, node Node) (r Node) { for i, a := range n.Items { n.Items[i] = Walk(v, a) } + case *InitializeStringWithSliceNode: + for i, a := range n.Items { + n.Items[i] = Walk(v, a) + } case *ExternNode: for _, fn := range n.FuncNodes { Walk(v, fn) diff --git a/tests/examples/string-ctor.cell b/tests/examples/string-ctor.cell new file mode 100644 index 0000000..db27e14 --- /dev/null +++ b/tests/examples/string-ctor.cell @@ -0,0 +1,13 @@ +import ( + "debug" +) + +func main() { + b := []byte{'1','2'} + s := make(string, b) + debug.Printf("s=%s",s) + s1 := make(string, b[0:1]) + debug.Printf("%s",s1) + debug.Printf("s1=%s",s) + return 0 +}