github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/stdlib/table/table.go (about) 1 package table 2 3 import ( 4 "bytes" 5 "fmt" 6 7 "github.com/hirochachacha/plua/internal/arith" 8 "github.com/hirochachacha/plua/internal/limits" 9 "github.com/hirochachacha/plua/internal/version" 10 "github.com/hirochachacha/plua/object" 11 "github.com/hirochachacha/plua/object/fnutil" 12 ) 13 14 func concat(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 15 ap := fnutil.NewArgParser(th, args) 16 17 t, err := ap.ToTable(0) 18 if err != nil { 19 return nil, err 20 } 21 22 sep, err := ap.OptGoString(1, "") 23 if err != nil { 24 return nil, err 25 } 26 27 i, err := ap.OptGoInt(2, 1) 28 if err != nil { 29 return nil, err 30 } 31 32 tlen, err := callLen(th, t) 33 if err != nil { 34 return nil, err 35 } 36 37 j, err := ap.OptGoInt(3, tlen) 38 if err != nil { 39 return nil, err 40 } 41 42 if i > j { 43 return []object.Value{object.String("")}, nil 44 } 45 46 var buf bytes.Buffer 47 48 var val object.Value 49 var ok bool 50 var tmp string 51 52 for { 53 val, err = arith.CallGettable(th, t, object.Integer(i)) 54 if err != nil { 55 return nil, err 56 } 57 58 tmp, ok = object.ToGoString(val) 59 if !ok { 60 return nil, object.NewRuntimeError(fmt.Sprintf("invalid value (%s) at index %d in table for 'concat'", object.ToType(val), i)) 61 } 62 63 buf.WriteString(tmp) 64 65 if i == j { 66 break 67 } 68 69 buf.WriteString(sep) 70 71 i++ 72 } 73 74 return []object.Value{object.String(buf.String())}, nil 75 } 76 77 // table.insert (list, [pos,] value) 78 func insert(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 79 ap := fnutil.NewArgParser(th, args) 80 81 t, err := ap.ToTable(0) 82 if err != nil { 83 return nil, err 84 } 85 86 tlen, err := callLen(th, t) 87 if err != nil { 88 return nil, err 89 } 90 91 switch len(args) { 92 case 2: 93 val, err := ap.ToValue(1) 94 if err != nil { 95 return nil, err 96 } 97 98 err = arith.CallSettable(th, t, object.Integer(tlen+1), val) 99 if err != nil { 100 return nil, err 101 } 102 103 return nil, nil 104 case 3: 105 pos, err := ap.OptGoInt(1, tlen+1) 106 if err != nil { 107 return nil, err 108 } 109 110 if pos < 1 || pos > tlen+1 { 111 return nil, ap.ArgError(1, "position out of bounds") 112 } 113 114 for i := tlen + 1; i > pos; i-- { 115 v, err := arith.CallGettable(th, t, object.Integer(i-1)) 116 if err != nil { 117 return nil, err 118 } 119 err = arith.CallSettable(th, t, object.Integer(i), v) 120 if err != nil { 121 return nil, err 122 } 123 } 124 125 val, err := ap.ToValue(2) 126 if err != nil { 127 return nil, err 128 } 129 130 err = arith.CallSettable(th, t, object.Integer(pos), val) 131 if err != nil { 132 return nil, err 133 } 134 135 return nil, nil 136 default: 137 return nil, object.NewRuntimeError("wrong number of arguments to 'insert'") 138 } 139 } 140 141 // TODO support for not table type 142 func move(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 143 ap := fnutil.NewArgParser(th, args) 144 145 a1, err := ap.ToTable(0) 146 if err != nil { 147 return nil, err 148 } 149 150 f, err := ap.ToGoInt(1) 151 if err != nil { 152 return nil, err 153 } 154 155 e, err := ap.ToGoInt(2) 156 if err != nil { 157 return nil, err 158 } 159 160 t, err := ap.ToGoInt(3) 161 if err != nil { 162 return nil, err 163 } 164 165 a2 := a1 166 if _, ok := ap.Get(4); ok { 167 a2, err = ap.ToTable(4) 168 if err != nil { 169 return nil, err 170 } 171 } 172 173 // copy(a2[t:], a1[f:e]) 174 if e >= f { 175 if f <= 0 && e > version.MAXMOVE+f || f > 0 && e-f > version.MAXMOVE { 176 return nil, ap.ArgError(2, "too many elements to move") 177 } 178 179 if t > int(limits.MaxInt)-(e-f) { 180 return nil, ap.ArgError(3, "destination wrap around") 181 } 182 183 if t > e || t <= f || a1 != a2 { // no overwrap 184 for i := 0; i <= e-f; i++ { 185 v, err := arith.CallGettable(th, a1, object.Integer(f+i)) 186 if err != nil { 187 return nil, err 188 } 189 err = arith.CallSettable(th, a2, object.Integer(t+i), v) 190 if err != nil { 191 return nil, err 192 } 193 } 194 } else { 195 for i := e - f; i >= 0; i-- { 196 v, err := arith.CallGettable(th, a1, object.Integer(f+i)) 197 if err != nil { 198 return nil, err 199 } 200 err = arith.CallSettable(th, a2, object.Integer(t+i), v) 201 if err != nil { 202 return nil, err 203 } 204 } 205 } 206 } 207 208 return []object.Value{a2}, nil 209 } 210 211 func pack(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 212 t := th.NewTableArray(append([]object.Value{}, args...)) 213 214 t.Set(object.String("n"), object.Integer(len(args))) 215 216 return []object.Value{t}, nil 217 } 218 219 func remove(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 220 ap := fnutil.NewArgParser(th, args) 221 222 t, err := ap.ToTable(0) 223 if err != nil { 224 return nil, err 225 } 226 227 tlen, err := callLen(th, t) 228 if err != nil { 229 return nil, err 230 } 231 232 pos, err := ap.OptGoInt(1, tlen) 233 if err != nil { 234 return nil, err 235 } 236 237 if tlen == pos { 238 val, err := arith.CallGettable(th, t, object.Integer(pos)) 239 if err != nil { 240 return nil, err 241 } 242 if val != nil { 243 err = arith.CallSettable(th, t, object.Integer(pos), nil) 244 if err != nil { 245 return nil, err 246 } 247 } 248 return []object.Value{val}, nil 249 } 250 251 if pos < 1 || pos > tlen+1 { 252 return nil, ap.ArgError(1, "position out of bounds") 253 } 254 255 val, err := arith.CallGettable(th, t, object.Integer(pos)) 256 if err != nil { 257 return nil, err 258 } 259 260 for i := pos; i < tlen+1; i++ { 261 v, err := arith.CallGettable(th, t, object.Integer(i+1)) 262 if err != nil { 263 return nil, err 264 } 265 err = arith.CallSettable(th, t, object.Integer(i), v) 266 if err != nil { 267 return nil, err 268 } 269 } 270 271 return []object.Value{val}, nil 272 } 273 274 func unpack(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 275 ap := fnutil.NewArgParser(th, args) 276 277 t, err := ap.ToTable(0) 278 if err != nil { 279 return nil, err 280 } 281 282 i, err := ap.OptGoInt(1, 1) 283 if err != nil { 284 return nil, err 285 } 286 287 tlen, err := callLen(th, t) 288 if err != nil { 289 return nil, err 290 } 291 292 j, err := ap.OptGoInt(2, tlen) 293 if err != nil { 294 return nil, err 295 } 296 297 if i > j { 298 return nil, nil 299 } 300 301 if i <= 0 && j > version.MAXUNPACK+i || i > 0 && j-i > version.MAXUNPACK { 302 return nil, object.NewRuntimeError("too many results to unpack") 303 } 304 305 rets := make([]object.Value, 0, j-i+1) 306 307 for { 308 val, err := arith.CallGettable(th, t, object.Integer(i)) 309 if err != nil { 310 return nil, err 311 } 312 313 rets = append(rets, val) 314 315 if i == j { 316 break 317 } 318 319 i++ 320 } 321 322 return rets, nil 323 } 324 325 func Open(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 326 m := th.NewTableSize(0, 7) 327 328 m.Set(object.String("concat"), object.GoFunction(concat)) 329 m.Set(object.String("insert"), object.GoFunction(insert)) 330 m.Set(object.String("move"), object.GoFunction(move)) 331 m.Set(object.String("pack"), object.GoFunction(pack)) 332 m.Set(object.String("remove"), object.GoFunction(remove)) 333 m.Set(object.String("sort"), object.GoFunction(sort)) 334 m.Set(object.String("unpack"), object.GoFunction(unpack)) 335 336 return []object.Value{m}, nil 337 }