diff --git a/Makefile b/Makefile index 40495d7..ffcb0c0 100644 --- a/Makefile +++ b/Makefile @@ -133,6 +133,7 @@ test/example: ${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/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/func.cell && ckb-debugger --bin func | grep "999" ${CELL} -t riscv tests/examples/cell-data.cell && ckb-debugger --bin cell-data ${CELL} -t riscv tests/examples/inputs.cell && ckb-debugger --bin inputs diff --git a/compiler/compiler/alloc.go b/compiler/compiler/alloc.go index 69d7bd7..ae6857c 100644 --- a/compiler/compiler/alloc.go +++ b/compiler/compiler/alloc.go @@ -62,7 +62,10 @@ func (c *Compiler) compileAllocNode(v *parser.AllocNode) { // Set to zero values // TODO: Make slices less special if sliceType, ok := treType.(*types.Slice); ok { - sliceType.SliceZero(block, c.osFuncs.Malloc.Value.(llvmValue.Named), 2, val) + sliceType.SliceZero(block, c.osFuncs.Malloc.Value.(llvmValue.Named), + constant.NewInt(irTypes.I32, 0), // len + constant.NewInt(irTypes.I32, 2), // cap + val) } else { treType.Zero(block, val) } @@ -161,7 +164,7 @@ func (c *Compiler) compileAllocConstNode(v *parser.AllocNode) { cnst := v.Val[i].(*parser.ConstantNode) c.setVar(varName, value.Value{ Type: &types.UntypedConstantNumber{}, - Value: constant.NewInt(i64.LLVM().(*irTypes.IntType), cnst.Value), + Value: constant.NewInt(irTypes.I64, cnst.Value), }) } } diff --git a/compiler/compiler/func.go b/compiler/compiler/func.go index d8be467..81bbe3d 100644 --- a/compiler/compiler/func.go +++ b/compiler/compiler/func.go @@ -475,7 +475,10 @@ func (c *Compiler) compileCallNode(v *parser.CallNode) value.Value { variadicType := fnType.ArgumentTypes[variadicArgIndex].(*types.Slice) // Convert last argument to a slice. - variadicSlice := c.compileInitializeSliceWithValues(variadicType.Type, args[variadicArgIndex:]...) + variadicSlice := c.compileInitializeSliceWithValues(variadicType.Type, + value.Value{Type: i32, Value: constant.NewInt(llvmTypes.I32, int64(len(args[variadicArgIndex:])))}, + value.Value{Type: i32, Value: constant.NewInt(llvmTypes.I32, int64(len(args[variadicArgIndex:])))}, + args[variadicArgIndex:]...) // Remove "pre-sliceified" arguments from the list of arguments args = args[0:variadicArgIndex] diff --git a/compiler/compiler/slice.go b/compiler/compiler/slice.go index 9bedb64..b614a86 100644 --- a/compiler/compiler/slice.go +++ b/compiler/compiler/slice.go @@ -362,10 +362,18 @@ func (c *Compiler) compileInitializeSliceNode(v *parser.InitializeSliceNode) val c.contextAssignDest = c.contextAssignDest[0 : len(c.contextAssignDest)-1] } - return c.compileInitializeSliceWithValues(itemType, values...) + len := value.Value{Type: i32, Value: constant.NewInt(llvmTypes.I32, 0)} + if v.Len != nil { + len = c.compileValue(v.Len) + } + cap := value.Value{Type: i32, Value: constant.NewInt(llvmTypes.I32, 0)} + if v.Cap != nil { + cap = c.compileValue(v.Cap) + } + return c.compileInitializeSliceWithValues(itemType, len, cap, values...) } -func (c *Compiler) compileInitializeSliceWithValues(itemType types.Type, values ...value.Value) value.Value { +func (c *Compiler) compileInitializeSliceWithValues(itemType types.Type, initLen, initCap value.Value, values ...value.Value) value.Value { sliceType := &types.Slice{ Type: itemType, LlvmType: internal.Slice(itemType.LLVM()), @@ -373,7 +381,7 @@ func (c *Compiler) compileInitializeSliceWithValues(itemType types.Type, values // Create slice with cap set to the requested size allocSlice := c.contextBlock.NewAlloca(sliceType.LLVM()) - sliceType.SliceZero(c.contextBlock, c.osFuncs.Malloc.Value.(llvmValue.Named), len(values), allocSlice) + sliceType.SliceZero(c.contextBlock, c.osFuncs.Malloc.Value.(llvmValue.Named), initLen.Value, initCap.Value, allocSlice) backingArrayPtr := c.contextBlock.NewGetElementPtr(pointer.ElemType(allocSlice), allocSlice, constant.NewInt(llvmTypes.I32, 0), @@ -399,7 +407,22 @@ func (c *Compiler) compileInitializeSliceWithValues(itemType types.Type, values constant.NewInt(llvmTypes.I32, 0), ) lenPtr.SetName(name.Var("len")) - c.contextBlock.NewStore(constant.NewInt(llvmTypes.I32, int64(len(values))), lenPtr) + len32 := initLen.Value + if len32.Type() != llvmTypes.I32 { + len32 = c.contextBlock.NewTrunc(len32, i32.LLVM()) + } + c.contextBlock.NewStore(len32, lenPtr) + + capPtr := c.contextBlock.NewGetElementPtr(pointer.ElemType(allocSlice), allocSlice, + constant.NewInt(llvmTypes.I32, 0), + constant.NewInt(llvmTypes.I32, 1), + ) + capPtr.SetName(name.Var("cap")) + cap32 := initCap.Value + if cap32.Type() != llvmTypes.I32 { + cap32 = c.contextBlock.NewTrunc(cap32, i32.LLVM()) + } + c.contextBlock.NewStore(cap32, capPtr) return value.Value{ Value: allocSlice, diff --git a/compiler/lexer/keywords.go b/compiler/lexer/keywords.go index 02e35c5..12a18a1 100644 --- a/compiler/lexer/keywords.go +++ b/compiler/lexer/keywords.go @@ -20,4 +20,5 @@ var keywords = map[string]struct{}{ "false": {}, "interface": {}, "range": {}, + "make": {}, } diff --git a/compiler/parser/node.go b/compiler/parser/node.go index 5ad82c6..83a163e 100644 --- a/compiler/parser/node.go +++ b/compiler/parser/node.go @@ -397,11 +397,13 @@ func (sn SubNode) String() string { type InitializeSliceNode struct { baseNode Type TypeNode + Len Node + Cap Node Items []Node } func (i InitializeSliceNode) String() string { - return fmt.Sprintf("InitializeSliceNode-[]%s{%+v}", i.Type, i.Items) + return fmt.Sprintf("InitializeSliceNode-[]%s{%+v}(%d)", i.Type, i.Items, i.Cap) } type InitializeArrayNode struct { diff --git a/compiler/parser/parser.go b/compiler/parser/parser.go index 4903a75..8eb92db 100644 --- a/compiler/parser/parser.go +++ b/compiler/parser/parser.go @@ -181,8 +181,14 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif items := p.parseUntil(lexer.Item{Type: lexer.OPERATOR, Val: "}"}) p.inAllocRightHand = prevInAlloc + len := &ConstantNode{ + Type: NUMBER, + Value: int64(len(items)), + } res = &InitializeSliceNode{ Type: sliceItemType, + Len: len, + Cap: len, Items: items, } if withAheadParse { @@ -329,6 +335,42 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif return outerConditionNode } + // "make" is a construtor command for composed types + if current.Val == "make" { + p.i++ + + lParent := p.lookAhead(0) + p.expect(lParent, lexer.Item{Type: lexer.OPERATOR, Val: "("}) + p.i++ + + ty, err := p.parseOneType() + if err != nil { + panic(err) + } + p.i++ + + items := p.parseUntil(lexer.Item{Type: lexer.OPERATOR, Val: ")"}) + switch t := ty.(type) { + case *SliceTypeNode: + if len(items) == 2 { + return &InitializeSliceNode{ + Type: t, + Len: items[0], + Cap: items[1], + } + } else if len(items) == 1 { + return &InitializeSliceNode{ + Type: t, + Len: items[0], + Cap: items[0], + } + } else { + panic("wrong argument for slice constructor") + } + default: + panic("not supported") + } + } // "extern" is external function without function body // single extern: extern func foo() int32 @@ -385,7 +427,7 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif retVals = append(retVals, p.parseOne(true)) p.i++ - + checkIfComma := p.lookAhead(0) if checkIfComma.Type == lexer.OPERATOR && checkIfComma.Val == "," { p.i++ diff --git a/tests/examples/make-slice.cell b/tests/examples/make-slice.cell new file mode 100644 index 0000000..3ae3b63 --- /dev/null +++ b/tests/examples/make-slice.cell @@ -0,0 +1,10 @@ +package main + +import "debug" + +func main() { + s := make([]int64, 0, 4) + s1 := make([]int64, 2) + debug.Printf("%d%d%d%d", len(s), cap(s), len(s1), cap(s1)) + return 0 +}