Add skeleton for string library calls.
This commit is contained in:
@@ -78,8 +78,20 @@ public class LuaCompat extends LFunction {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public static final String[] STRING_NAMES = {
|
public static final String[] STRING_NAMES = {
|
||||||
|
"byte",
|
||||||
|
"char",
|
||||||
|
"dump",
|
||||||
|
"find",
|
||||||
|
"format",
|
||||||
|
"gmatch",
|
||||||
|
"gsub",
|
||||||
|
"len",
|
||||||
|
"lower",
|
||||||
|
"match",
|
||||||
"rep",
|
"rep",
|
||||||
|
"reverse",
|
||||||
"sub",
|
"sub",
|
||||||
|
"upper",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final int ASSERT = 0;
|
private static final int ASSERT = 0;
|
||||||
@@ -105,8 +117,21 @@ public class LuaCompat extends LFunction {
|
|||||||
private static final int SIN = MATH_BASE + 4;
|
private static final int SIN = MATH_BASE + 4;
|
||||||
|
|
||||||
private static final int STRING_BASE = 30;
|
private static final int STRING_BASE = 30;
|
||||||
private static final int REP = STRING_BASE + 0;
|
private static final int BYTE = STRING_BASE + 0;
|
||||||
private static final int SUB = STRING_BASE + 1;
|
private static final int CHAR = STRING_BASE + 1;
|
||||||
|
private static final int DUMP = STRING_BASE + 2;
|
||||||
|
private static final int FIND = STRING_BASE + 3;
|
||||||
|
private static final int FORMAT = STRING_BASE + 4;
|
||||||
|
private static final int GMATCH = STRING_BASE + 5;
|
||||||
|
private static final int GSUB = STRING_BASE + 6;
|
||||||
|
private static final int LEN = STRING_BASE + 7;
|
||||||
|
private static final int LOWER = STRING_BASE + 8;
|
||||||
|
private static final int MATCH = STRING_BASE + 9;
|
||||||
|
private static final int REP = STRING_BASE + 20;
|
||||||
|
private static final int REVERSE = STRING_BASE + 11;
|
||||||
|
private static final int SUB = STRING_BASE + 12;
|
||||||
|
private static final int UPPER = STRING_BASE + 13;
|
||||||
|
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
private LuaCompat( int id ) {
|
private LuaCompat( int id ) {
|
||||||
@@ -190,44 +215,49 @@ public class LuaCompat extends LFunction {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// String functions
|
// String functions
|
||||||
case REP: {
|
case BYTE:
|
||||||
LString s = vm.getArgAsLuaString( 0 );
|
StrLib.byte_( vm );
|
||||||
int n = vm.getArgAsInt( 1 );
|
break;
|
||||||
if ( n >= 0 ) {
|
case CHAR:
|
||||||
final byte[] bytes = new byte[ s.length() * n ];
|
StrLib.char_( vm );
|
||||||
int len = s.length();
|
break;
|
||||||
for ( int offset = 0; offset < bytes.length; offset += len ) {
|
case DUMP:
|
||||||
s.copyInto( 0, bytes, offset, len );
|
StrLib.dump( vm );
|
||||||
}
|
break;
|
||||||
|
case FIND:
|
||||||
|
StrLib.find( vm );
|
||||||
|
break;
|
||||||
|
case FORMAT:
|
||||||
|
StrLib.format( vm );
|
||||||
|
break;
|
||||||
|
case GMATCH:
|
||||||
|
StrLib.gmatch( vm );
|
||||||
|
break;
|
||||||
|
case GSUB:
|
||||||
|
StrLib.gsub( vm );
|
||||||
|
break;
|
||||||
|
case LEN:
|
||||||
|
StrLib.len( vm );
|
||||||
|
break;
|
||||||
|
case LOWER:
|
||||||
|
StrLib.lower( vm );
|
||||||
|
break;
|
||||||
|
case MATCH:
|
||||||
|
StrLib.match( vm );
|
||||||
|
break;
|
||||||
|
case REP:
|
||||||
|
StrLib.rep( vm );
|
||||||
|
break;
|
||||||
|
case REVERSE:
|
||||||
|
StrLib.reverse( vm );
|
||||||
|
break;
|
||||||
|
case SUB:
|
||||||
|
StrLib.sub( vm );
|
||||||
|
break;
|
||||||
|
case UPPER:
|
||||||
|
StrLib.upper( vm );
|
||||||
|
break;
|
||||||
|
|
||||||
vm.setResult( new LString( bytes ) );
|
|
||||||
} else {
|
|
||||||
vm.setResult( LNil.NIL );
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case SUB: {
|
|
||||||
final LString s = vm.getArgAsLuaString( 0 );
|
|
||||||
final int len = s.length();
|
|
||||||
|
|
||||||
int i = vm.getArgAsInt( 1 );
|
|
||||||
if ( i < 0 ) {
|
|
||||||
// start at -i characters from the end
|
|
||||||
i = Math.max( len + i, 0 );
|
|
||||||
} else if ( i > 0 ) {
|
|
||||||
// start at character i - 1
|
|
||||||
i = i - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int j = ( vm.getArgCount() > 2 ) ? vm.getArgAsInt( 2 ): -1;
|
|
||||||
if ( j < 0 ) {
|
|
||||||
j = Math.max( i, len + j + 1 );
|
|
||||||
} else {
|
|
||||||
j = Math.min( Math.max( i, j ), len );
|
|
||||||
}
|
|
||||||
|
|
||||||
LString result = s.substring( i, j );
|
|
||||||
vm.setResult( result );
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
luaUnsupportedOperation();
|
luaUnsupportedOperation();
|
||||||
|
|||||||
298
src/addon/java/lua/addon/luacompat/StrLib.java
Normal file
298
src/addon/java/lua/addon/luacompat/StrLib.java
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
package lua.addon.luacompat;
|
||||||
|
|
||||||
|
import lua.VM;
|
||||||
|
import lua.value.LInteger;
|
||||||
|
import lua.value.LNil;
|
||||||
|
import lua.value.LString;
|
||||||
|
|
||||||
|
public class StrLib {
|
||||||
|
/**
|
||||||
|
* string.byte (s [, i [, j]])
|
||||||
|
*
|
||||||
|
* Returns the internal numerical codes of the
|
||||||
|
* characters s[i], s[i+1], ···, s[j]. The default value for i is 1; the
|
||||||
|
* default value for j is i.
|
||||||
|
*
|
||||||
|
* Note that numerical codes are not necessarily portable across platforms.
|
||||||
|
*
|
||||||
|
* @param vm the calling vm
|
||||||
|
*/
|
||||||
|
static void byte_( VM vm ) {
|
||||||
|
LString ls = vm.getArgAsLuaString(1);
|
||||||
|
int i = vm.getArgAsInt(2);
|
||||||
|
int j = vm.getArgAsInt(3);
|
||||||
|
int n = ls.length();
|
||||||
|
i = Math.max(1, i);
|
||||||
|
j = Math.min(n, (j==0? i: j));
|
||||||
|
vm.setResult();
|
||||||
|
for ( int k=i; k<=j; k++ )
|
||||||
|
vm.push( new LInteger( ls.luaByte(k-1) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.char (···)
|
||||||
|
*
|
||||||
|
* Receives zero or more integers. Returns a string with length equal
|
||||||
|
* to the number of arguments, in which each character has the internal
|
||||||
|
* numerical code equal to its corresponding argument.
|
||||||
|
*
|
||||||
|
* Note that numerical codes are not necessarily portable across platforms.
|
||||||
|
*
|
||||||
|
* @param vm the calling VM
|
||||||
|
*/
|
||||||
|
public static void char_( VM vm) {
|
||||||
|
int nargs = vm.getArgCount();
|
||||||
|
byte[] bytes = new byte[nargs];
|
||||||
|
for ( int i=1; i<=nargs; i++ )
|
||||||
|
vm.getArgAsInt(i);
|
||||||
|
vm.setResult( new LString( bytes ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.dump (function)
|
||||||
|
*
|
||||||
|
* Returns a string containing a binary representation of the given function,
|
||||||
|
* so that a later loadstring on this string returns a copy of the function.
|
||||||
|
* function must be a Lua function without upvalues.
|
||||||
|
*
|
||||||
|
* TODO: port dumping code as optional add-on
|
||||||
|
*/
|
||||||
|
static void dump( VM vm ) {
|
||||||
|
vm.setResult( new LString("not supported") );
|
||||||
|
vm.lua_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.find (s, pattern [, init [, plain]])
|
||||||
|
*
|
||||||
|
* Looks for the first match of pattern in the string s.
|
||||||
|
* If it finds a match, then find returns the indices of s
|
||||||
|
* where this occurrence starts and ends; otherwise, it returns nil.
|
||||||
|
* A third, optional numerical argument init specifies where to start the search;
|
||||||
|
* its default value is 1 and may be negative. A value of true as a fourth,
|
||||||
|
* optional argument plain turns off the pattern matching facilities,
|
||||||
|
* so the function does a plain "find substring" operation,
|
||||||
|
* with no characters in pattern being considered "magic".
|
||||||
|
* Note that if plain is given, then init must be given as well.
|
||||||
|
*
|
||||||
|
* If the pattern has captures, then in a successful match the captured values
|
||||||
|
* are also returned, after the two indices.
|
||||||
|
*/
|
||||||
|
static void find( VM vm ) {
|
||||||
|
LString pattern = vm.getArgAsLuaString(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.format (formatstring, ···)
|
||||||
|
*
|
||||||
|
* Returns a formatted version of its variable number of arguments following
|
||||||
|
* the description given in its first argument (which must be a string).
|
||||||
|
* The format string follows the same rules as the printf family of standard C functions.
|
||||||
|
* The only differences are that the options/modifiers *, l, L, n, p, and h are not supported
|
||||||
|
* and that there is an extra option, q. The q option formats a string in a form suitable
|
||||||
|
* to be safely read back by the Lua interpreter: the string is written between double quotes,
|
||||||
|
* and all double quotes, newlines, embedded zeros, and backslashes in the string are correctly
|
||||||
|
* escaped when written. For instance, the call
|
||||||
|
* string.format('%q', 'a string with "quotes" and \n new line')
|
||||||
|
*
|
||||||
|
* will produce the string:
|
||||||
|
* "a string with \"quotes\" and \
|
||||||
|
* new line"
|
||||||
|
*
|
||||||
|
* The options c, d, E, e, f, g, G, i, o, u, X, and x all expect a number as argument,
|
||||||
|
* whereas q and s expect a string.
|
||||||
|
*
|
||||||
|
* This function does not accept string values containing embedded zeros,
|
||||||
|
* except as arguments to the q option.
|
||||||
|
*/
|
||||||
|
static void format( VM vm ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.gmatch (s, pattern)
|
||||||
|
*
|
||||||
|
* Returns an iterator function that, each time it is called, returns the next captures
|
||||||
|
* from pattern over string s. If pattern specifies no captures, then the
|
||||||
|
* whole match is produced in each call.
|
||||||
|
*
|
||||||
|
* As an example, the following loop
|
||||||
|
* s = "hello world from Lua"
|
||||||
|
* for w in string.gmatch(s, "%a+") do
|
||||||
|
* print(w)
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* will iterate over all the words from string s, printing one per line.
|
||||||
|
* The next example collects all pairs key=value from the given string into a table:
|
||||||
|
* t = {}
|
||||||
|
* s = "from=world, to=Lua"
|
||||||
|
* for k, v in string.gmatch(s, "(%w+)=(%w+)") do
|
||||||
|
* t[k] = v
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* For this function, a '^' at the start of a pattern does not work as an anchor,
|
||||||
|
* as this would prevent the iteration.
|
||||||
|
*/
|
||||||
|
static void gmatch( VM vm ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.gsub (s, pattern, repl [, n])
|
||||||
|
* Returns a copy of s in which all (or the first n, if given) occurrences of the
|
||||||
|
* pattern have been replaced by a replacement string specified by repl, which
|
||||||
|
* may be a string, a table, or a function. gsub also returns, as its second value,
|
||||||
|
* the total number of matches that occurred.
|
||||||
|
*
|
||||||
|
* If repl is a string, then its value is used for replacement.
|
||||||
|
* The character % works as an escape character: any sequence in repl of the form %n,
|
||||||
|
* with n between 1 and 9, stands for the value of the n-th captured substring (see below).
|
||||||
|
* The sequence %0 stands for the whole match. The sequence %% stands for a single %.
|
||||||
|
*
|
||||||
|
* If repl is a table, then the table is queried for every match, using the first capture
|
||||||
|
* as the key; if the pattern specifies no captures, then the whole match is used as the key.
|
||||||
|
*
|
||||||
|
* If repl is a function, then this function is called every time a match occurs,
|
||||||
|
* with all captured substrings passed as arguments, in order; if the pattern specifies
|
||||||
|
* no captures, then the whole match is passed as a sole argument.
|
||||||
|
*
|
||||||
|
* If the value returned by the table query or by the function call is a string or a number,
|
||||||
|
* then it is used as the replacement string; otherwise, if it is false or nil,
|
||||||
|
* then there is no replacement (that is, the original match is kept in the string).
|
||||||
|
*
|
||||||
|
* Here are some examples:
|
||||||
|
* x = string.gsub("hello world", "(%w+)", "%1 %1")
|
||||||
|
* --> x="hello hello world world"
|
||||||
|
*
|
||||||
|
* x = string.gsub("hello world", "%w+", "%0 %0", 1)
|
||||||
|
* --> x="hello hello world"
|
||||||
|
*
|
||||||
|
* x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
|
||||||
|
* --> x="world hello Lua from"
|
||||||
|
*
|
||||||
|
* x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
|
||||||
|
* --> x="home = /home/roberto, user = roberto"
|
||||||
|
*
|
||||||
|
* x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
|
||||||
|
* return loadstring(s)()
|
||||||
|
* end)
|
||||||
|
* --> x="4+5 = 9"
|
||||||
|
*
|
||||||
|
* local t = {name="lua", version="5.1"}
|
||||||
|
* x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
|
||||||
|
* --> x="lua-5.1.tar.gz"
|
||||||
|
*/
|
||||||
|
static void gsub( VM vm ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.len (s)
|
||||||
|
*
|
||||||
|
* Receives a string and returns its length. The empty string "" has length 0.
|
||||||
|
* Embedded zeros are counted, so "a\000bc\000" has length 5.
|
||||||
|
*/
|
||||||
|
static void len( VM vm ) {
|
||||||
|
vm.setResult( new LInteger( vm.getArgAsLuaString(1).length()) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.lower (s)
|
||||||
|
*
|
||||||
|
* Receives a string and returns a copy of this string with all uppercase letters
|
||||||
|
* changed to lowercase. All other characters are left unchanged.
|
||||||
|
* The definition of what an uppercase letter is depends on the current locale.
|
||||||
|
*/
|
||||||
|
static void lower( VM vm ) {
|
||||||
|
vm.setResult( new LString( vm.getArgAsString(1).toLowerCase() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.match (s, pattern [, init])
|
||||||
|
*
|
||||||
|
* Looks for the first match of pattern in the string s. If it finds one, then match returns the captures from the pattern; otherwise it returns nil. If pattern specifies no captures, then the whole match is returned. A third, optional numerical argument init specifies where to start the search; its default value is 1 and may be negative.
|
||||||
|
*/
|
||||||
|
static void match( VM vm ) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.rep (s, n)
|
||||||
|
*
|
||||||
|
* Returns a string that is the concatenation of n copies of the string s.
|
||||||
|
*/
|
||||||
|
static void rep( VM vm ) {
|
||||||
|
LString s = vm.getArgAsLuaString( 0 );
|
||||||
|
int n = vm.getArgAsInt( 1 );
|
||||||
|
if ( n >= 0 ) {
|
||||||
|
final byte[] bytes = new byte[ s.length() * n ];
|
||||||
|
int len = s.length();
|
||||||
|
for ( int offset = 0; offset < bytes.length; offset += len ) {
|
||||||
|
s.copyInto( 0, bytes, offset, len );
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.setResult( new LString( bytes ) );
|
||||||
|
} else {
|
||||||
|
vm.setResult( LNil.NIL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.reverse (s)
|
||||||
|
*
|
||||||
|
* Returns a string that is the string s reversed.
|
||||||
|
*/
|
||||||
|
static void reverse( VM vm ) {
|
||||||
|
LString s = vm.getArgAsLuaString(1);
|
||||||
|
int n = s.length();
|
||||||
|
byte[] b = new byte[n];
|
||||||
|
for ( int i=0, j=n; i<n; i++, j-- )
|
||||||
|
b[j] = (byte) s.luaByte(i);
|
||||||
|
vm.setResult( new LString(b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.sub (s, i [, j])
|
||||||
|
*
|
||||||
|
* Returns the substring of s that starts at i and continues until j;
|
||||||
|
* i and j may be negative. If j is absent, then it is assumed to be equal to -1
|
||||||
|
* (which is the same as the string length). In particular, the call
|
||||||
|
* string.sub(s,1,j)
|
||||||
|
* returns a prefix of s with length j, and
|
||||||
|
* string.sub(s, -i)
|
||||||
|
* returns a suffix of s with length i.
|
||||||
|
*/
|
||||||
|
static void sub( VM vm ) {
|
||||||
|
final LString s = vm.getArgAsLuaString( 0 );
|
||||||
|
final int len = s.length();
|
||||||
|
|
||||||
|
int i = vm.getArgAsInt( 1 );
|
||||||
|
if ( i < 0 ) {
|
||||||
|
// start at -i characters from the end
|
||||||
|
i = Math.max( len + i, 0 );
|
||||||
|
} else if ( i > 0 ) {
|
||||||
|
// start at character i - 1
|
||||||
|
i = i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j = ( vm.getArgCount() > 2 ) ? vm.getArgAsInt( 2 ): -1;
|
||||||
|
if ( j < 0 ) {
|
||||||
|
j = Math.max( i, len + j + 1 );
|
||||||
|
} else {
|
||||||
|
j = Math.min( Math.max( i, j ), len );
|
||||||
|
}
|
||||||
|
|
||||||
|
LString result = s.substring( i, j );
|
||||||
|
vm.setResult( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* string.upper (s)
|
||||||
|
*
|
||||||
|
* Receives a string and returns a copy of this string with all lowercase letters
|
||||||
|
* changed to uppercase. All other characters are left unchanged.
|
||||||
|
* The definition of what a lowercase letter is depends on the current locale.
|
||||||
|
*/
|
||||||
|
static void upper( VM vm ) {
|
||||||
|
vm.setResult( new LString( vm.getArgAsString(1).toUpperCase() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -146,4 +146,11 @@ public interface VM {
|
|||||||
* must be on the top of the stack.
|
* must be on the top of the stack.
|
||||||
*/
|
*/
|
||||||
public void lua_error();
|
public void lua_error();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raises an error. The message is pushed onto the stack and used as the error message.
|
||||||
|
* It also adds at the beginning of the message the file name and the line number where
|
||||||
|
* the error occurred, if this information is available.
|
||||||
|
*/
|
||||||
|
public void luaL_error(String message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import java.util.StringTokenizer;
|
|||||||
import lua.CallInfo;
|
import lua.CallInfo;
|
||||||
import lua.StackState;
|
import lua.StackState;
|
||||||
import lua.io.LocVars;
|
import lua.io.LocVars;
|
||||||
import lua.value.LValue;
|
|
||||||
|
|
||||||
public class DebugStackState extends StackState implements DebugRequestListener {
|
public class DebugStackState extends StackState implements DebugRequestListener {
|
||||||
|
|
||||||
@@ -18,7 +17,6 @@ public class DebugStackState extends StackState implements DebugRequestListener
|
|||||||
private int lastline = -1;
|
private int lastline = -1;
|
||||||
|
|
||||||
public DebugStackState() {
|
public DebugStackState() {
|
||||||
StackState.debugHooksEnabled = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug hooks
|
// debug hooks
|
||||||
|
|||||||
@@ -342,4 +342,8 @@ public class LString extends LValue {
|
|||||||
System.arraycopy( a, 0, newbytes, 0, Math.min( newSize, a.length ) );
|
System.arraycopy( a, 0, newbytes, 0, Math.min( newSize, a.length ) );
|
||||||
return newbytes;
|
return newbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int luaByte(int index) {
|
||||||
|
return m_bytes[m_offset + index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ public class StandardTest extends TestCase {
|
|||||||
for ( int i = 0; i <= state.cc; ++i ) {
|
for ( int i = 0; i <= state.cc; ++i ) {
|
||||||
CallInfo call = state.calls[i];
|
CallInfo call = state.calls[i];
|
||||||
Proto p = call.closure.p;
|
Proto p = call.closure.p;
|
||||||
int line = p.lineinfo[call.pc];
|
int line = p.lineinfo[call.pc-1];
|
||||||
String func = call.closure.luaAsString().toJavaString();
|
String func = call.closure.luaAsString().toJavaString();
|
||||||
stackTrace[state.cc - i] = new StackTraceElement(getName(), func, getName()+".lua", line );
|
stackTrace[state.cc - i] = new StackTraceElement(getName(), func, getName()+".lua", line );
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user