Merge pull request #1352 from nspcc-dev/compiler/make
Fix MEMCPY, support `copy` and `make` in compiler
This commit is contained in:
commit
a1fbe51bca
8 changed files with 187 additions and 7 deletions
|
@ -1313,6 +1313,44 @@ func (c *codegen) convertSyscall(expr *ast.CallExpr, api, name string) {
|
|||
emit.Opcode(c.prog.BinWriter, opcode.NOP)
|
||||
}
|
||||
|
||||
// emitSliceHelper emits 3 items on stack: slice, its first index, and its size.
|
||||
func (c *codegen) emitSliceHelper(e ast.Expr) {
|
||||
if !isByteSlice(c.typeOf(e)) {
|
||||
c.prog.Err = fmt.Errorf("copy is supported only for byte-slices")
|
||||
return
|
||||
}
|
||||
var hasLowIndex bool
|
||||
switch src := e.(type) {
|
||||
case *ast.SliceExpr:
|
||||
ast.Walk(c, src.X)
|
||||
if src.High != nil {
|
||||
ast.Walk(c, src.High)
|
||||
} else {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
}
|
||||
if src.Low != nil {
|
||||
ast.Walk(c, src.Low)
|
||||
hasLowIndex = true
|
||||
} else {
|
||||
emit.Int(c.prog.BinWriter, 0)
|
||||
}
|
||||
default:
|
||||
ast.Walk(c, src)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SIZE)
|
||||
emit.Int(c.prog.BinWriter, 0)
|
||||
}
|
||||
if !hasLowIndex {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
|
||||
} else {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ROT)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SWAP)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.SUB)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
||||
var name string
|
||||
switch t := expr.Fun.(type) {
|
||||
|
@ -1323,6 +1361,32 @@ func (c *codegen) convertBuiltin(expr *ast.CallExpr) {
|
|||
}
|
||||
|
||||
switch name {
|
||||
case "copy":
|
||||
// stack for MEMCPY is: dst, dst_index, src, src_index, count
|
||||
c.emitSliceHelper(expr.Args[0])
|
||||
c.emitSliceHelper(expr.Args[1])
|
||||
emit.Int(c.prog.BinWriter, 3)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ROLL)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.MIN)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.MEMCPY)
|
||||
case "make":
|
||||
typ := c.typeOf(expr.Args[0])
|
||||
switch {
|
||||
case isMap(typ):
|
||||
emit.Opcode(c.prog.BinWriter, opcode.NEWMAP)
|
||||
default:
|
||||
if len(expr.Args) == 3 {
|
||||
c.prog.Err = fmt.Errorf("`make()` with a capacity argument is not supported")
|
||||
return
|
||||
}
|
||||
ast.Walk(c, expr.Args[1])
|
||||
if isByteSlice(typ) {
|
||||
emit.Opcode(c.prog.BinWriter, opcode.NEWBUFFER)
|
||||
} else {
|
||||
neoT := toNeoType(typ.(*types.Slice).Elem())
|
||||
emit.Instruction(c.prog.BinWriter, opcode.NEWARRAYT, []byte{byte(neoT)})
|
||||
}
|
||||
}
|
||||
case "len":
|
||||
emit.Opcode(c.prog.BinWriter, opcode.DUP)
|
||||
emit.Opcode(c.prog.BinWriter, opcode.ISNULL)
|
||||
|
@ -1412,8 +1476,11 @@ func transformArgs(fun ast.Expr, args []ast.Expr) []ast.Expr {
|
|||
return args[1:]
|
||||
}
|
||||
case *ast.Ident:
|
||||
if f.Name == "panic" {
|
||||
switch f.Name {
|
||||
case "panic":
|
||||
return args[1:]
|
||||
case "make", "copy":
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue