diff --git a/src/core/org/luaj/vm2/Buffer.java b/src/core/org/luaj/vm2/Buffer.java index e077d224..8f5d2bd9 100644 --- a/src/core/org/luaj/vm2/Buffer.java +++ b/src/core/org/luaj/vm2/Buffer.java @@ -51,6 +51,8 @@ public final class Buffer { } public final void append( LuaValue val ) { + if ( ! val.isstring() ) + val.error("attempt to concatenate a '"+val.typename()+"' value"); append( val.strvalue() ); } diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java index f41fc5b9..31d93bed 100644 --- a/src/core/org/luaj/vm2/LuaClosure.java +++ b/src/core/org/luaj/vm2/LuaClosure.java @@ -240,7 +240,7 @@ public class LuaClosure extends LuaFunction { { Buffer sb = new Buffer(); for ( ; b<=c; ) - sb.append( stack[b++].checkstring() ); + sb.append( stack[b++] ); stack[a] = sb.tostring(); } continue; @@ -345,9 +345,9 @@ public class LuaClosure extends LuaFunction { case Lua.OP_FORPREP: /* A sBx R(A)-=R(A+2): pc+=sBx */ { - LuaValue init = stack[a].checknumber(); - LuaValue limit = stack[a + 1].checknumber(); - LuaValue step = stack[a + 2].checknumber(); + LuaValue init = stack[a].checknumber("'for' initial value must be a number"); + LuaValue limit = stack[a + 1].checknumber("'for' limit must be a number"); + LuaValue step = stack[a + 2].checknumber("'for' step must be a number"); stack[a] = init.sub(step); stack[a + 1] = limit; stack[a + 2] = step; diff --git a/src/core/org/luaj/vm2/LuaNumber.java b/src/core/org/luaj/vm2/LuaNumber.java index f3b8cd46..829d51f9 100644 --- a/src/core/org/luaj/vm2/LuaNumber.java +++ b/src/core/org/luaj/vm2/LuaNumber.java @@ -38,6 +38,10 @@ public class LuaNumber extends LuaValue { return this; } + public LuaNumber checknumber(String errmsg) { + return this; + } + public LuaNumber optnumber(LuaNumber defval) { return this; } diff --git a/src/core/org/luaj/vm2/LuaString.java b/src/core/org/luaj/vm2/LuaString.java index d0d1eca6..5382b38d 100644 --- a/src/core/org/luaj/vm2/LuaString.java +++ b/src/core/org/luaj/vm2/LuaString.java @@ -183,6 +183,12 @@ public class LuaString extends LuaValue { argerror("number"); return (LuaNumber) n; } + public LuaNumber checknumber(String msg) { + LuaValue n = tonumber(10); + if ( ! n.isnumber() ) + argerror(msg); + return (LuaNumber) n; + } public LuaValue tonumber() { return tonumber(10); } diff --git a/src/core/org/luaj/vm2/LuaValue.java b/src/core/org/luaj/vm2/LuaValue.java index f8727588..13037a5c 100644 --- a/src/core/org/luaj/vm2/LuaValue.java +++ b/src/core/org/luaj/vm2/LuaValue.java @@ -146,6 +146,7 @@ public class LuaValue extends Varargs { public LuaInteger checkinteger() { argerror("integer"); return null; } public long checklong() { argerror("long"); return 0; } public LuaNumber checknumber() { argerror("number"); return null; } + public LuaNumber checknumber(String msg) { throw new LuaError(msg); } public String checkjstring() { argerror("string"); return null; } public LuaString checkstring() { argerror("string"); return null; } public LuaTable checktable() { argerror("table"); return null; } @@ -170,6 +171,8 @@ public class LuaValue extends Varargs { protected LuaValue lenerror() { throw new LuaError("attempt to get length of "+typename()); } protected LuaValue aritherror() { throw new LuaError("attempt to perform arithmetic on "+typename()); } protected LuaValue aritherror(String fun) { throw new LuaError("attempt to perform arithmetic '"+fun+"' on "+typename()); } + protected LuaValue compareerror(String rhs) { throw new LuaError("attempt to compare "+typename()+" with "+rhs); } + protected LuaValue compareerror(LuaValue rhs) { throw new LuaError("attempt to compare "+typename()+" with "+rhs.typename()); } // table operations public LuaValue get( LuaValue key ) { return gettable(this,key); } @@ -271,22 +274,22 @@ public class LuaValue extends Varargs { public LuaValue modFrom(double lhs) { return aritherror("modFrom"); } // relational operators - public LuaValue lt( LuaValue rhs ) { return aritherror("lt"); } - public boolean lt_b( LuaValue rhs ) { aritherror("lt"); return false; } - public boolean lt_b( int rhs ) { aritherror("lt"); return false; } - public boolean lt_b( double rhs ) { aritherror("lt"); return false; } - public LuaValue lteq( LuaValue rhs ) { return aritherror("lteq"); } - public boolean lteq_b( LuaValue rhs ) { aritherror("lteq"); return false; } - public boolean lteq_b( int rhs ) { aritherror("lteq"); return false; } - public boolean lteq_b( double rhs ) { aritherror("lteq"); return false; } - public LuaValue gt( LuaValue rhs ) { return aritherror("gt"); } - public boolean gt_b( LuaValue rhs ) { aritherror("gt"); return false; } - public boolean gt_b( int rhs ) { aritherror("gt"); return false; } - public boolean gt_b( double rhs ) { aritherror("gt"); return false; } - public LuaValue gteq( LuaValue rhs ) { return aritherror("gteq"); } - public boolean gteq_b( LuaValue rhs ) { aritherror("gteq"); return false; } - public boolean gteq_b( int rhs ) { aritherror("gteq"); return false; } - public boolean gteq_b( double rhs ) { aritherror("gteq"); return false; } + public LuaValue lt( LuaValue rhs ) { return compareerror(rhs); } + public boolean lt_b( LuaValue rhs ) { compareerror(rhs); return false; } + public boolean lt_b( int rhs ) { compareerror("number"); return false; } + public boolean lt_b( double rhs ) { compareerror("number"); return false; } + public LuaValue lteq( LuaValue rhs ) { return compareerror(rhs); } + public boolean lteq_b( LuaValue rhs ) { compareerror(rhs); return false; } + public boolean lteq_b( int rhs ) { compareerror("number"); return false; } + public boolean lteq_b( double rhs ) { compareerror("number"); return false; } + public LuaValue gt( LuaValue rhs ) { return compareerror(rhs); } + public boolean gt_b( LuaValue rhs ) { compareerror(rhs); return false; } + public boolean gt_b( int rhs ) { compareerror("number"); return false; } + public boolean gt_b( double rhs ) { compareerror("number"); return false; } + public LuaValue gteq( LuaValue rhs ) { return compareerror(rhs); } + public boolean gteq_b( LuaValue rhs ) { compareerror(rhs); return false; } + public boolean gteq_b( int rhs ) { compareerror("number"); return false; } + public boolean gteq_b( double rhs ) { compareerror("number"); return false; } // string comparison public int strcmp( LuaValue rhs ) { error("attempt to compare "+typename()); return 0; } @@ -352,7 +355,7 @@ public class LuaValue extends Varargs { if ((!res.isnil()) || (tm = t.metatag(INDEX)).isnil()) return res; } else if ((tm = t.metatag(INDEX)).isnil()) - t.typerror("table"); + t.indexerror(); if (tm.isfunction()) return tm.call(t, key); t = tm; diff --git a/test/lua/errors/args.lua b/test/lua/errors/args.lua index b3efb2d2..f80f27fa 100644 --- a/test/lua/errors/args.lua +++ b/test/lua/errors/args.lua @@ -8,9 +8,9 @@ local badmsg = 'badmsg ' akey = 'aa' astring = 'abc' astrnum = '789' -anumber = 1.23 +anumber = 1.25 ainteger = 345 -adouble = 123.456 +adouble = 12.75 aboolean = true atable = {[akey]=456} afunction = function() end diff --git a/test/lua/errors/operators.lua b/test/lua/errors/operators.lua index 5a69b8d4..ba53b507 100644 --- a/test/lua/errors/operators.lua +++ b/test/lua/errors/operators.lua @@ -39,38 +39,38 @@ checkallerrors('concatop',{somestring,notastring},'attempt to concatenate') banner( '+' ) plusop = function(a,b) return a+b end checkallpass('plusop',{somenumber,somenumber}) -checkallerrors('plusop',{notanumber,somenumber},'attempt to perform arithmetic on') -checkallerrors('plusop',{somenumber,notanumber},'attempt to perform arithmetic on') +checkallerrors('plusop',{notanumber,somenumber},'attempt to perform arithmetic') +checkallerrors('plusop',{somenumber,notanumber},'attempt to perform arithmetic') banner( '-' ) minusop = function(a,b) return a-b end checkallpass('minusop',{somenumber,somenumber}) -checkallerrors('minusop',{notanumber,somenumber},'attempt to perform arithmetic on') -checkallerrors('minusop',{somenumber,notanumber},'attempt to perform arithmetic on') +checkallerrors('minusop',{notanumber,somenumber},'attempt to perform arithmetic') +checkallerrors('minusop',{somenumber,notanumber},'attempt to perform arithmetic') banner( '*' ) timesop = function(a,b) return a*b end checkallpass('timesop',{somenumber,somenumber}) -checkallerrors('timesop',{notanumber,somenumber},'attempt to perform arithmetic on') -checkallerrors('timesop',{somenumber,notanumber},'attempt to perform arithmetic on') +checkallerrors('timesop',{notanumber,somenumber},'attempt to perform arithmetic') +checkallerrors('timesop',{somenumber,notanumber},'attempt to perform arithmetic') banner( '/' ) divideop = function(a,b) return a/b end checkallpass('divideop',{somenumber,somenumber}) -checkallerrors('divideop',{notanumber,somenumber},'attempt to perform arithmetic on') -checkallerrors('divideop',{somenumber,notanumber},'attempt to perform arithmetic on') +checkallerrors('divideop',{notanumber,somenumber},'attempt to perform arithmetic') +checkallerrors('divideop',{somenumber,notanumber},'attempt to perform arithmetic') banner( '%' ) modop = function(a,b) return a%b end checkallpass('modop',{somenumber,somenumber}) -checkallerrors('modop',{notanumber,somenumber},'attempt to perform arithmetic on') -checkallerrors('modop',{somenumber,notanumber},'attempt to perform arithmetic on') +checkallerrors('modop',{notanumber,somenumber},'attempt to perform arithmetic') +checkallerrors('modop',{somenumber,notanumber},'attempt to perform arithmetic') banner( '^' ) powerop = function(a,b) return a^b end checkallpass('powerop',{{2,'2.5'},{3,'3.5'}}) -checkallerrors('powerop',{notanumber,{3,'3.1'}},'attempt to perform arithmetic on') -checkallerrors('powerop',{{2,'2.1'},notanumber},'attempt to perform arithmetic on') +checkallerrors('powerop',{notanumber,{3,'3.1'}},'attempt to perform arithmetic') +checkallerrors('powerop',{{2,'2.1'},notanumber},'attempt to perform arithmetic') banner( '==' ) equalsop = function(a,b) return a==b end