Mercurial Hosting > luan
changeset 35:e51906de0f11
implement metatables
git-svn-id: https://luan-java.googlecode.com/svn/trunk@36 21e917c8-12df-6dd8-5cb6-c86387c605b9
author | fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9> |
---|---|
date | Tue, 18 Dec 2012 07:05:58 +0000 |
parents | 0cdc1da466ee |
children | 2a35154aec14 |
files | src/luan/CmdLine.java src/luan/Lua.java src/luan/LuaTable.java src/luan/interp/AddExpr.java src/luan/interp/BinaryOpExpr.java src/luan/interp/ConcatExpr.java src/luan/interp/DivExpr.java src/luan/interp/EqExpr.java src/luan/interp/ExpressionsExpr.java src/luan/interp/FnCall.java src/luan/interp/GetExpr.java src/luan/interp/IndexExpr.java src/luan/interp/LeExpr.java src/luan/interp/LenExpr.java src/luan/interp/LtExpr.java src/luan/interp/LuaParser.java src/luan/interp/ModExpr.java src/luan/interp/MulExpr.java src/luan/interp/PowExpr.java src/luan/interp/SetTableEntry.java src/luan/interp/SubExpr.java src/luan/interp/TableExpr.java src/luan/interp/UnmExpr.java src/luan/interp/Utils.java src/luan/lib/BasicLib.java |
diffstat | 25 files changed, 289 insertions(+), 111 deletions(-) [+] |
line wrap: on
line diff
--- a/src/luan/CmdLine.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/CmdLine.java Tue Dec 18 07:05:58 2012 +0000 @@ -8,7 +8,6 @@ public class CmdLine { - static final String version = "Luan 0.0"; public static void main(String[] args) throws Exception { LuaState lua = LuaCompiler.newLuaState(); @@ -56,16 +55,16 @@ } } if( showVersion ) - System.out.println(version); + System.out.println(Lua.version); if( i < args.length ) { String file = args[i++]; Object[] varArgs = new Object[args.length-1]; System.arraycopy(args,1,varArgs,0,varArgs.length); LuaTable argsTable = new LuaTable(); for( int j=0; j<args.length; j++ ) { - argsTable.set( new LuaNumber(j), args[j] ); + argsTable.put( new LuaNumber(j), args[j] ); } - lua.global().set("arg",argsTable); + lua.global().put("arg",argsTable); try { LuaFunction fn = BasicLib.loadfile(lua,file); fn.call(lua,varArgs);
--- a/src/luan/Lua.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/Lua.java Tue Dec 18 07:05:58 2012 +0000 @@ -2,6 +2,7 @@ public class Lua { + public static final String version = "Luan 0.0"; public static String type(Object obj) { if( obj == null ) @@ -63,4 +64,11 @@ throw new LuaException( "attempt to call a " + type(obj) + " value" ); } + public static LuaTable getMetatable(Object obj) { + if( !(obj instanceof LuaTable) ) + return null; + LuaTable table = (LuaTable)obj; + return table.getMetatable(); + } + }
--- a/src/luan/LuaTable.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/LuaTable.java Tue Dec 18 07:05:58 2012 +0000 @@ -7,6 +7,7 @@ public class LuaTable { private final Map<Object,Object> map = new HashMap<Object,Object>(); + private LuaTable metatable; @Override public String toString() { return "table: " + Integer.toHexString(hashCode()); @@ -16,11 +17,11 @@ return map.get(key); } - public void set(Object key,Object val) { + public Object put(Object key,Object val) { if( val == null ) { - map.remove(key); + return map.remove(key); } else { - map.put(key,val); + return map.put(key,val); } } @@ -36,4 +37,11 @@ return map.entrySet().iterator(); } + public LuaTable getMetatable() { + return metatable; + } + + public void setMetatable(LuaTable metatable) { + this.metatable = metatable; + } }
--- a/src/luan/interp/AddExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/AddExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( n1 + n2 ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( n1.value() + n2.value() ); + return arithmetic(lua,"__add",o1,o2); } }
--- a/src/luan/interp/BinaryOpExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/BinaryOpExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -1,5 +1,10 @@ package luan.interp; +import luan.Lua; +import luan.LuaTable; +import luan.LuaFunction; +import luan.LuaException; + abstract class BinaryOpExpr implements Expr { final Expr op1; @@ -9,4 +14,19 @@ this.op1 = op1; this.op2 = op2; } + + static final LuaFunction getBinHandler(String op,Object o1,Object o2) throws LuaException { + LuaFunction f1 = Utils.getHandler(op,o1); + if( f1 != null ) + return f1; + return Utils.getHandler(op,o2); + } + + static final Object arithmetic(LuaStateImpl lua,String op,Object o1,Object o2) throws LuaException { + LuaFunction fn = getBinHandler(op,o1,o2); + if( fn != null ) + return Utils.first(fn.call(lua,o1,o2)); + String type = Lua.toNumber(o1)==null ? Lua.type(o1) : Lua.type(o2); + throw new LuaException("attempt to perform arithmetic on a "+type+" value"); + } }
--- a/src/luan/interp/ConcatExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/ConcatExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -1,7 +1,7 @@ package luan.interp; import luan.Lua; -import luan.LuaNumber; +import luan.LuaFunction; import luan.LuaException; @@ -12,13 +12,16 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - return toString(op1.eval(lua)) + toString(op2.eval(lua)); - } - - private static String toString(Object v) throws LuaException { - String s = Lua.asString(v); - if( s==null ) - throw new LuaException( "attempt to concatenate a " + Lua.type(v) + " value" ); - return s; + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + String s1 = Lua.asString(o1); + String s2 = Lua.asString(o2); + if( s1 != null && s2 != null ) + return s1 + s2; + LuaFunction fn = getBinHandler("__concat",o1,o2); + if( fn != null ) + return Utils.first(fn.call(lua,o1,o2)); + String type = s1==null ? Lua.type(o1) : Lua.type(o2); + throw new LuaException( "attempt to concatenate a " + type + " value" ); } }
--- a/src/luan/interp/DivExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/DivExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( n1 / n2 ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( n1.value() / n2.value() ); + return arithmetic(lua,"__div",o1,o2); } }
--- a/src/luan/interp/EqExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/EqExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -2,6 +2,8 @@ import luan.Lua; import luan.LuaNumber; +import luan.LuaFunction; +import luan.LuaTable; import luan.LuaException; @@ -12,8 +14,20 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - Object v1 = op1.eval(lua); - Object v2 = op2.eval(lua); - return v1 == v2 || v1 != null && v1.equals(v2); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + if( o1 == o2 || o1 != null && o1.equals(o2) ) + return true; + if( !o1.getClass().equals(o2.getClass()) ) + return false; + LuaTable mt1 = Lua.getMetatable(o1); + LuaTable mt2 = Lua.getMetatable(o2); + if( mt1==null || mt2==null ) + return false; + Object f = mt1.get("__eq"); + if( f == null || !f.equals(mt2.get("__eq")) ) + return null; + LuaFunction fn = Lua.checkFunction(f); + return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) ); } }
--- a/src/luan/interp/ExpressionsExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/ExpressionsExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -13,7 +13,6 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - Object[] a = expressions.eval(lua); - return a.length==0 ? null : a[0]; + return Utils.first( expressions.eval(lua) ); } }
--- a/src/luan/interp/FnCall.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/FnCall.java Tue Dec 18 07:05:58 2012 +0000 @@ -15,7 +15,17 @@ } @Override public Object[] eval(LuaStateImpl lua) throws LuaException { - LuaFunction fn = Lua.checkFunction( fnExpr.eval(lua) ); - return fn.call( lua, args.eval(lua) ); + return call( lua, fnExpr.eval(lua) ); + } + + private Object[] call(LuaStateImpl lua,Object o) throws LuaException { + if( o instanceof LuaFunction ) { + LuaFunction fn = (LuaFunction)o; + return fn.call( lua, args.eval(lua) ); + } + Object h = Utils.getHandlerObject("__call",o); + if( h != null ) + return call(lua,h); + throw new LuaException( "attempt to call a " + Lua.type(o) + " value" ); } }
--- a/src/luan/interp/GetExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -package luan.interp; - -import luan.Lua; -import luan.LuaException; -import luan.LuaTable; - - -final class GetExpr extends BinaryOpExpr { - - GetExpr(Expr op1,Expr op2) { - super(op1,op2); - } - - @Override public Object eval(LuaStateImpl lua) throws LuaException { - Object t = op1.eval(lua); - if( t instanceof LuaTable ) { - LuaTable tbl = (LuaTable)t; - Object key = op2.eval(lua); - return tbl.get(key); - } - throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); - } -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/IndexExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -0,0 +1,40 @@ +package luan.interp; + +import luan.Lua; +import luan.LuaException; +import luan.LuaTable; +import luan.LuaFunction; + + +final class IndexExpr extends BinaryOpExpr { + + IndexExpr(Expr op1,Expr op2) { + super(op1,op2); + } + + @Override public Object eval(LuaStateImpl lua) throws LuaException { + return index(lua,op1.eval(lua),op2.eval(lua)); + } + + private static Object index(LuaStateImpl lua,Object t,Object key) throws LuaException { + Object h; + if( t instanceof LuaTable ) { + LuaTable tbl = (LuaTable)t; + Object value = tbl.get(key); + if( value != null ) + return value; + h = Utils.getHandlerObject("__index",t); + if( h==null ) + return null; + } else { + h = Utils.getHandlerObject("__index",t); + if( h==null ) + throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); + } + if( h instanceof LuaFunction ) { + LuaFunction fn = (LuaFunction)h; + return Utils.first(fn.call(lua,t,key)); + } + return index(lua,h,key); + } +}
--- a/src/luan/interp/LeExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/LeExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -2,6 +2,7 @@ import luan.Lua; import luan.LuaNumber; +import luan.LuaFunction; import luan.LuaException; @@ -12,18 +13,24 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - Object v1 = op1.eval(lua); - Object v2 = op2.eval(lua); - if( v1 instanceof LuaNumber && v2 instanceof LuaNumber ) { - LuaNumber n1 = (LuaNumber)v1; - LuaNumber n2 = (LuaNumber)v2; + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + if( o1 instanceof LuaNumber && o2 instanceof LuaNumber ) { + LuaNumber n1 = (LuaNumber)o1; + LuaNumber n2 = (LuaNumber)o2; return n1.compareTo(n2) <= 0; } - if( v1 instanceof String && v2 instanceof String ) { - String s1 = (String)v1; - String s2 = (String)v2; + if( o1 instanceof String && o2 instanceof String ) { + String s1 = (String)o1; + String s2 = (String)o2; return s1.compareTo(s2) <= 0; } - throw new LuaException( "attempt to compare " + Lua.type(v1) + " with " + Lua.type(v2) ); + LuaFunction fn = getBinHandler("__le",o1,o2); + if( fn != null ) + return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) ); + fn = getBinHandler("__lt",o1,o2); + if( fn != null ) + return !Lua.toBoolean( Utils.first(fn.call(lua,o2,o1)) ); + throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) ); } }
--- a/src/luan/interp/LenExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/LenExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -3,6 +3,7 @@ import luan.Lua; import luan.LuaNumber; import luan.LuaTable; +import luan.LuaFunction; import luan.LuaException; @@ -13,18 +14,18 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - return new LuaNumber( length(op.eval(lua)) ); - } - - private static int length(Object obj) throws LuaException { - if( obj instanceof String ) { - String s = (String)obj; - return s.length(); + Object o = op.eval(lua); + if( o instanceof String ) { + String s = (String)o; + return new LuaNumber( s.length() ); } - if( obj instanceof LuaTable ) { - LuaTable t = (LuaTable)obj; + LuaFunction fn = Utils.getHandler("__len",o); + if( fn != null ) + return Utils.first(fn.call(lua,o)); + if( o instanceof LuaTable ) { + LuaTable t = (LuaTable)o; return t.length(); } - throw new LuaException( "attempt to get length of a " + Lua.type(obj) + " value" ); + throw new LuaException( "attempt to get length of a " + Lua.type(o) + " value" ); } }
--- a/src/luan/interp/LtExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/LtExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -2,6 +2,7 @@ import luan.Lua; import luan.LuaNumber; +import luan.LuaFunction; import luan.LuaException; @@ -12,18 +13,21 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - Object v1 = op1.eval(lua); - Object v2 = op2.eval(lua); - if( v1 instanceof LuaNumber && v2 instanceof LuaNumber ) { - LuaNumber n1 = (LuaNumber)v1; - LuaNumber n2 = (LuaNumber)v2; + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + if( o1 instanceof LuaNumber && o2 instanceof LuaNumber ) { + LuaNumber n1 = (LuaNumber)o1; + LuaNumber n2 = (LuaNumber)o2; return n1.compareTo(n2) < 0; } - if( v1 instanceof String && v2 instanceof String ) { - String s1 = (String)v1; - String s2 = (String)v2; + if( o1 instanceof String && o2 instanceof String ) { + String s1 = (String)o1; + String s2 = (String)o2; return s1.compareTo(s2) < 0; } - throw new LuaException( "attempt to compare " + Lua.type(v1) + " with " + Lua.type(v2) ); + LuaFunction fn = getBinHandler("__lt",o1,o2); + if( fn != null ) + return Lua.toBoolean( Utils.first(fn.call(lua,o1,o2)) ); + throw new LuaException( "attempt to compare " + Lua.type(o1) + " with " + Lua.type(o2) ); } }
--- a/src/luan/interp/LuaParser.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/LuaParser.java Tue Dec 18 07:05:58 2012 +0000 @@ -23,7 +23,6 @@ class LuaParser extends BaseParser<Object> { - static final String _G = "_G"; static final String _ENV = "_ENV"; static final class Frame { @@ -37,8 +36,6 @@ Frame() { this.parent = null; - upValueSymbols.add(_G); - upValueGetters.add(UpValue.globalGetter); upValueSymbols.add(_ENV); upValueGetters.add(UpValue.globalGetter); } @@ -673,7 +670,7 @@ return true; Object obj1 = pop(); if( obj1 != null ) - return push( new GetExpr( expr(obj1), expr(obj2) ) ); + return push( new IndexExpr( expr(obj1), expr(obj2) ) ); String name = (String)obj2; int index = stackIndex(name); if( index != -1 ) @@ -681,7 +678,7 @@ index = upValueIndex(name); if( index != -1 ) return push( new GetUpVar(index) ); - return push( new GetExpr( env(), new ConstExpr(name) ) ); + return push( new IndexExpr( env(), new ConstExpr(name) ) ); } // function should be on top of the stack
--- a/src/luan/interp/ModExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/ModExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( n1 % n2 ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( n1.value() % n2.value() ); + return arithmetic(lua,"__mod",o1,o2); } }
--- a/src/luan/interp/MulExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/MulExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( n1 * n2 ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( n1.value() * n2.value() ); + return arithmetic(lua,"__mul",o1,o2); } }
--- a/src/luan/interp/PowExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/PowExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( Math.pow(n1,n2) ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( Math.pow( n1.value(), n2.value() ) ); + return arithmetic(lua,"__pow",o1,o2); } }
--- a/src/luan/interp/SetTableEntry.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/SetTableEntry.java Tue Dec 18 07:05:58 2012 +0000 @@ -3,6 +3,7 @@ import luan.LuaException; import luan.LuaTable; import luan.Lua; +import luan.LuaFunction; final class SetTableEntry implements Settable { @@ -15,12 +16,30 @@ } @Override public void set(LuaStateImpl lua,Object value) throws LuaException { - Object t = tableExpr.eval(lua); - if( !(t instanceof LuaTable) ) - throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); - LuaTable table = (LuaTable)t; - Object key = keyExpr.eval(lua); - table.set(key,value); + newindex( lua, tableExpr.eval(lua), keyExpr.eval(lua), value ); + } + + private static void newindex(LuaStateImpl lua,Object t,Object key,Object value) throws LuaException { + Object h; + if( t instanceof LuaTable ) { + LuaTable table = (LuaTable)t; + Object old = table.put(key,value); + if( old != null ) + return; + h = Utils.getHandlerObject("__newindex",t); + if( h==null ) + return; + table.put(key,old); + } else { + h = Utils.getHandlerObject("__newindex",t); + if( h==null ) + throw new LuaException( "attempt to index a " + Lua.type(t) + " value" ); + } + if( h instanceof LuaFunction ) { + LuaFunction fn = (LuaFunction)h; + fn.call(lua,t,key,value); + } + newindex(lua,h,key,value); } }
--- a/src/luan/interp/SubExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/SubExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -12,8 +12,12 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n1 = Lua.checkNumber(op1.eval(lua)).value(); - double n2 = Lua.checkNumber(op2.eval(lua)).value(); - return new LuaNumber( n1 - n2 ); + Object o1 = op1.eval(lua); + Object o2 = op2.eval(lua); + LuaNumber n1 = Lua.toNumber(o1); + LuaNumber n2 = Lua.toNumber(o2); + if( n1 != null && n2 != null ) + return new LuaNumber( n1.value() - n2.value() ); + return arithmetic(lua,"__sub",o1,o2); } }
--- a/src/luan/interp/TableExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/TableExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -28,11 +28,11 @@ @Override public Object eval(LuaStateImpl lua) throws LuaException { LuaTable table = new LuaTable(); for( Field field : fields ) { - table.set( field.key.eval(lua), field.value.eval(lua) ); + table.put( field.key.eval(lua), field.value.eval(lua) ); } Object[] a = expressions.eval(lua); for( int i=0; i<a.length; i++ ) { - table.set( new LuaNumber(i+1), a[i] ); + table.put( new LuaNumber(i+1), a[i] ); } return table; }
--- a/src/luan/interp/UnmExpr.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/interp/UnmExpr.java Tue Dec 18 07:05:58 2012 +0000 @@ -2,6 +2,7 @@ import luan.Lua; import luan.LuaNumber; +import luan.LuaFunction; import luan.LuaException; @@ -13,7 +14,13 @@ } @Override public Object eval(LuaStateImpl lua) throws LuaException { - double n = Lua.checkNumber(op.eval(lua)).value(); - return new LuaNumber( -n ); + Object o = op.eval(lua); + LuaNumber n = Lua.toNumber(o); + if( n != null ) + return new LuaNumber( -n.value() ); + LuaFunction fn = Utils.getHandler("__unm",o); + if( fn != null ) + return Utils.first(fn.call(lua,o)); + throw new LuaException("attempt to perform arithmetic on a "+Lua.type(o)+" value"); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/luan/interp/Utils.java Tue Dec 18 07:05:58 2012 +0000 @@ -0,0 +1,28 @@ +package luan.interp; + +import luan.Lua; +import luan.LuaFunction; +import luan.LuaTable; +import luan.LuaException; + + +final class Utils { + private Utils() {} // never + + static Object first(Object[] a) { + return a.length==0 ? null : a[0]; + } + + static final Object getHandlerObject(String op,Object obj) throws LuaException { + LuaTable t = Lua.getMetatable(obj); + return t==null ? null : t.get(op); + } + + static final LuaFunction getHandler(String op,Object obj) throws LuaException { + Object f = getHandlerObject(op,obj); + if( f == null ) + return null; + return Lua.checkFunction(f); + } + +}
--- a/src/luan/lib/BasicLib.java Sun Dec 16 09:23:56 2012 +0000 +++ b/src/luan/lib/BasicLib.java Tue Dec 18 07:05:58 2012 +0000 @@ -21,17 +21,21 @@ public static void register(LuaState lua) { LuaTable t = lua.global(); - add( t, "print", new Object[0].getClass() ); - add( t, "type", Object.class ); + t.put( "_G", t ); + add( t, "getmetatable", Object.class ); + add( t, "ipairs", LuaTable.class ); add( t, "load", LuaState.class, String.class ); add( t, "loadfile", LuaState.class, String.class ); add( t, "pairs", LuaTable.class ); - add( t, "ipairs", LuaTable.class ); + add( t, "print", new Object[0].getClass() ); + add( t, "setmetatable", LuaTable.class, LuaTable.class ); + add( t, "type", Object.class ); + t.put( "_VERSION", Lua.version ); } private static void add(LuaTable t,String method,Class<?>... parameterTypes) { try { - t.set( method, new LuaJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) ); + t.put( method, new LuaJavaFunction(BasicLib.class.getMethod(method,parameterTypes),null) ); } catch(NoSuchMethodException e) { throw new RuntimeException(e); } @@ -131,4 +135,13 @@ throw new RuntimeException(e); } } + + public static LuaTable getmetatable(Object obj) { + return Lua.getMetatable(obj); + } + + public static LuaTable setmetatable(LuaTable table,LuaTable metatable) { + table.setMetatable(metatable); + return table; + } }