Mercurial Hosting > luan
comparison core/src/luan/LuanTable.java @ 432:d9df6d6cb927
finish fixing LuanTable to use metatables
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sat, 02 May 2015 23:41:59 -0600 |
parents | 3ffe8ba5b297 |
children | c6bcb8859b93 |
comparison
equal
deleted
inserted
replaced
431:3ffe8ba5b297 | 432:d9df6d6cb927 |
---|---|
13 import java.util.HashSet; | 13 import java.util.HashSet; |
14 import java.util.IdentityHashMap; | 14 import java.util.IdentityHashMap; |
15 import java.util.regex.Pattern; | 15 import java.util.regex.Pattern; |
16 | 16 |
17 | 17 |
18 public final class LuanTable implements Iterable<Map.Entry<Object,Object>>, DeepCloneable<LuanTable> { | 18 public final class LuanTable implements DeepCloneable<LuanTable> { |
19 private Map<Object,Object> map = null; | 19 private Map<Object,Object> map = null; |
20 private List<Object> list = null; | 20 private List<Object> list = null; |
21 private LuanTable metatable = null; | 21 private LuanTable metatable = null; |
22 private boolean hasJava = false; | 22 private boolean hasJava = false; |
23 | 23 |
24 public LuanTable() {} | 24 public LuanTable() {} |
25 | 25 |
26 public LuanTable(List<Object> list) { | 26 public LuanTable(List<Object> list) { |
27 this.list = list; | 27 int n = list.size(); |
28 this.map = newMap(); | 28 for( int i=0; i<n; i++ ) { |
29 map.put("n",list.size()); | 29 Object val = list.get(i); |
30 for( int i=0; i<list.size(); i++ ) { | 30 if( val != null ) |
31 if( list.get(i) == null ) { | 31 rawPut(i+1,val); |
32 listToMap(i); | 32 } |
33 break; | 33 } |
34 } | 34 |
35 public LuanTable(Map<Object,Object> map) { | |
36 for( Map.Entry<Object,Object> entry : map.entrySet() ) { | |
37 Object key = entry.getKey(); | |
38 Object value = entry.getValue(); | |
39 if( key != null && value != null ) | |
40 rawPut(key,value); | |
41 } | |
42 } | |
43 | |
44 public LuanTable(Set<Object> set) { | |
45 for( Object el : set ) { | |
46 if( el != null ) | |
47 rawPut(el,Boolean.TRUE); | |
35 } | 48 } |
36 } | 49 } |
37 | 50 |
38 public LuanTable(LuanTable tbl) { | 51 public LuanTable(LuanTable tbl) { |
39 if( tbl.map != null && !tbl.map.isEmpty() ) | 52 if( tbl.map != null && !tbl.map.isEmpty() ) |
40 this.map = new LinkedHashMap<Object,Object>(tbl.map); | 53 this.map = new LinkedHashMap<Object,Object>(tbl.map); |
41 if( tbl.length() > 0 ) | 54 if( tbl.rawLength() > 0 ) |
42 this.list = new ArrayList<Object>(tbl.list); | 55 this.list = new ArrayList<Object>(tbl.list); |
43 this.metatable = tbl.metatable; | 56 this.metatable = tbl.metatable; |
44 } | 57 } |
45 | 58 |
46 @Override public LuanTable shallowClone() { | 59 @Override public LuanTable shallowClone() { |
221 throw new IllegalArgumentException("can't insert a nil value"); | 234 throw new IllegalArgumentException("can't insert a nil value"); |
222 list().add(pos-1,value); | 235 list().add(pos-1,value); |
223 mapToList(); | 236 mapToList(); |
224 } | 237 } |
225 | 238 |
226 public void rawAdd(Object value) { | |
227 if( value==null ) | |
228 throw new IllegalArgumentException("can't add a nil value"); | |
229 list().add(value); | |
230 mapToList(); | |
231 } | |
232 | |
233 public Object rawRemove(int pos) { | 239 public Object rawRemove(int pos) { |
234 return list().remove(pos-1); | 240 return list().remove(pos-1); |
235 } | 241 } |
236 | 242 |
237 public void rawSort(Comparator<Object> cmp) { | 243 public void rawSort(Comparator<Object> cmp) { |
238 Collections.sort(list(),cmp); | 244 Collections.sort(list(),cmp); |
239 } | 245 } |
240 | 246 |
241 public int length() { | 247 public int length(LuanState luan) throws LuanException { |
248 Object h = getHandler("__len"); | |
249 if( h != null ) { | |
250 LuanFunction fn = luan.checkFunction(h); | |
251 return (Integer)Luan.first(luan.call(fn,"__len",new Object[]{this})); | |
252 } | |
253 return rawLength(); | |
254 } | |
255 | |
256 public int rawLength() { | |
242 return list==null ? 0 : list.size(); | 257 return list==null ? 0 : list.size(); |
243 } | 258 } |
244 | 259 |
245 @Override public Iterator<Map.Entry<Object,Object>> iterator() { | 260 public Iterable<Map.Entry<Object,Object>> iterable(LuanState luan) throws LuanException { |
261 final Iterator<Map.Entry<Object,Object>> iter = iterator(luan); | |
262 return new Iterable<Map.Entry<Object,Object>>() { | |
263 public Iterator<Map.Entry<Object,Object>> iterator() { | |
264 return iter; | |
265 } | |
266 }; | |
267 } | |
268 | |
269 public Iterator<Map.Entry<Object,Object>> iterator(final LuanState luan) throws LuanException { | |
270 if( getHandler("__pairs") == null ) | |
271 return rawIterator(); | |
272 final LuanFunction fn = pairs(luan); | |
273 return new Iterator<Map.Entry<Object,Object>>() { | |
274 private Map.Entry<Object,Object> next = getNext(); | |
275 | |
276 private Map.Entry<Object,Object> getNext() { | |
277 try { | |
278 Object obj = luan.call(fn); | |
279 if( obj==null ) | |
280 return null; | |
281 Object[] a = (Object[])obj; | |
282 if( a.length == 0 ) | |
283 return null; | |
284 return new AbstractMap.SimpleEntry<Object,Object>(a[0],a[1]); | |
285 } catch(LuanException e) { | |
286 throw new LuanRuntimeException(e); | |
287 } | |
288 } | |
289 | |
290 public boolean hasNext() { | |
291 return next != null; | |
292 } | |
293 | |
294 public Map.Entry<Object,Object> next() { | |
295 Map.Entry<Object,Object> rtn = next; | |
296 next = getNext(); | |
297 return rtn; | |
298 } | |
299 | |
300 public void remove() { | |
301 throw new UnsupportedOperationException(); | |
302 } | |
303 }; | |
304 } | |
305 | |
306 public LuanFunction pairs(final LuanState luan) throws LuanException { | |
307 Object h = getHandler("__pairs"); | |
308 if( h != null ) { | |
309 if( h instanceof LuanFunction ) { | |
310 Object obj = Luan.first(luan.call((LuanFunction)h,"__pairs",new Object[]{this})); | |
311 if( !(obj instanceof LuanFunction) ) | |
312 throw luan.exception( "metamethod __pairs should return function but returned " + Luan.type(obj) ); | |
313 return (LuanFunction)obj; | |
314 } | |
315 if( h instanceof LuanMeta ) { | |
316 LuanMeta meta = (LuanMeta)h; | |
317 return meta.__pairs(luan,this); | |
318 } | |
319 throw luan.exception( "invalid type of metamethod __pairs: " + Luan.type(h) ); | |
320 } | |
321 return rawPairs(); | |
322 } | |
323 | |
324 private LuanFunction rawPairs() { | |
325 return new LuanFunction() { | |
326 final Iterator<Map.Entry<Object,Object>> iter = rawIterator(); | |
327 | |
328 @Override public Object[] call(LuanState luan,Object[] args) { | |
329 if( !iter.hasNext() ) | |
330 return LuanFunction.NOTHING; | |
331 Map.Entry<Object,Object> entry = iter.next(); | |
332 return new Object[]{entry.getKey(),entry.getValue()}; | |
333 } | |
334 }; | |
335 } | |
336 | |
337 public Iterator<Map.Entry<Object,Object>> rawIterator() { | |
246 if( list == null ) { | 338 if( list == null ) { |
247 if( map == null ) | 339 if( map == null ) |
248 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); | 340 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); |
249 return map.entrySet().iterator(); | 341 return map.entrySet().iterator(); |
250 } | 342 } |
251 if( map == null ) | 343 if( map == null ) |
252 return listIterator(); | 344 return listIterator(); |
253 return new Iterator<Map.Entry<Object,Object>>() { | 345 return new Iterator<Map.Entry<Object,Object>>() { |
254 Iterator<Map.Entry<Object,Object>> iter = listIterator(); | 346 Iterator<Map.Entry<Object,Object>> iter = listIterator(); |
255 boolean isList = true; | 347 boolean isList = true; |
348 | |
256 public boolean hasNext() { | 349 public boolean hasNext() { |
257 boolean b = iter.hasNext(); | 350 boolean b = iter.hasNext(); |
258 if( !b && isList ) { | 351 if( !b && isList ) { |
259 iter = map.entrySet().iterator(); | 352 iter = map.entrySet().iterator(); |
260 isList = false; | 353 isList = false; |
261 b = iter.hasNext(); | 354 b = iter.hasNext(); |
262 } | 355 } |
263 return b; | 356 return b; |
264 } | 357 } |
358 | |
265 public Map.Entry<Object,Object> next() { | 359 public Map.Entry<Object,Object> next() { |
266 return iter.next(); | 360 return iter.next(); |
267 } | 361 } |
362 | |
268 public void remove() { | 363 public void remove() { |
269 throw new UnsupportedOperationException(); | 364 throw new UnsupportedOperationException(); |
270 } | 365 } |
271 }; | 366 }; |
272 } | 367 } |
274 private Iterator<Map.Entry<Object,Object>> listIterator() { | 369 private Iterator<Map.Entry<Object,Object>> listIterator() { |
275 if( list == null ) | 370 if( list == null ) |
276 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); | 371 return Collections.<Map.Entry<Object,Object>>emptyList().iterator(); |
277 final ListIterator iter = list.listIterator(); | 372 final ListIterator iter = list.listIterator(); |
278 return new Iterator<Map.Entry<Object,Object>>() { | 373 return new Iterator<Map.Entry<Object,Object>>() { |
374 | |
279 public boolean hasNext() { | 375 public boolean hasNext() { |
280 return iter.hasNext(); | 376 return iter.hasNext(); |
281 } | 377 } |
378 | |
282 public Map.Entry<Object,Object> next() { | 379 public Map.Entry<Object,Object> next() { |
283 Double key = Double.valueOf(iter.nextIndex()+1); | 380 Integer key = iter.nextIndex()+1; |
284 return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next()); | 381 return new AbstractMap.SimpleEntry<Object,Object>(key,iter.next()); |
285 } | 382 } |
383 | |
286 public void remove() { | 384 public void remove() { |
287 throw new UnsupportedOperationException(); | 385 throw new UnsupportedOperationException(); |
288 } | 386 } |
289 }; | 387 }; |
290 } | 388 } |
302 public void setMetatable(LuanTable metatable) { | 400 public void setMetatable(LuanTable metatable) { |
303 this.metatable = metatable; | 401 this.metatable = metatable; |
304 } | 402 } |
305 | 403 |
306 public Object getHandler(String op) { | 404 public Object getHandler(String op) { |
307 LuanTable t = getMetatable(); | 405 return metatable==null ? null : metatable.rawGet(op); |
308 return t==null ? null : t.rawGet(op); | |
309 } | 406 } |
310 | 407 |
311 public boolean hasJava() { | 408 public boolean hasJava() { |
312 return hasJava; | 409 return hasJava; |
313 } | 410 } |
321 | 418 |
322 private Map<Object,Object> newMap() { | 419 private Map<Object,Object> newMap() { |
323 return new LinkedHashMap<Object,Object>(); | 420 return new LinkedHashMap<Object,Object>(); |
324 } | 421 } |
325 | 422 |
326 public boolean isSet() { | 423 public boolean isSet(LuanState luan) throws LuanException { |
327 for( Map.Entry<Object,Object> entry : this ) { | 424 for( Map.Entry<Object,Object> entry : iterable(luan) ) { |
328 if( !entry.getValue().equals(Boolean.TRUE) ) | 425 if( !entry.getValue().equals(Boolean.TRUE) ) |
329 return false; | 426 return false; |
330 } | 427 } |
331 return true; | 428 return true; |
332 } | 429 } |
333 | 430 |
334 public Set<Object> asSet() { | 431 public Set<Object> asSet(LuanState luan) throws LuanException { |
335 Set<Object> set = new HashSet<Object>(); | 432 Set<Object> set = new HashSet<Object>(); |
336 for( Map.Entry<Object,Object> entry : this ) { | 433 for( Map.Entry<Object,Object> entry : iterable(luan) ) { |
337 set.add(entry.getKey()); | 434 set.add(entry.getKey()); |
338 } | 435 } |
339 return set; | 436 return set; |
340 } | 437 } |
341 | 438 |
342 public Map<Object,Object> asMap() { | 439 public Map<Object,Object> asMap(LuanState luan) throws LuanException { |
343 Map<Object,Object> map = newMap(); | 440 Map<Object,Object> map = newMap(); |
344 for( Map.Entry<Object,Object> entry : this ) { | 441 for( Map.Entry<Object,Object> entry : iterable(luan) ) { |
345 map.put(entry.getKey(),entry.getValue()); | 442 map.put(entry.getKey(),entry.getValue()); |
346 } | 443 } |
347 return map; | 444 return map; |
348 } | 445 } |
349 | 446 |