private static int BGetMetatable( Thread l ) { var mt = GetMetatableImp( l[1] ); Value vmt; if( mt != null ) { int loc = mt.FindValue( Literals.TagInfo_Metatable ); if( loc != 0 ) mt.ReadValue( loc, out vmt ); else vmt = mt; } else { vmt = new Value(); } return l.SetReturnValues( vmt ); }
public int MRandom( Thread l ) { if( rng == null ) rng = new Random(); double max, min, n = rng.NextDouble(); switch( l.StackTop ) { case 0: break; case 1: max = (double)l[1]; if( max < 1 ) throw new ArgumentException( "interval is empty" ); n = Math.Floor( n * max ) + 1; break; case 2: min = (double)l[1]; max = (double)l[2]; if( min > max ) throw new ArgumentException( "interval is empty" ); n = Math.Floor( n * (max - min + 1) ) + min; break; default: throw new ArgumentException( "wrong number of arguments" ); } return l.SetReturnValues( n ); }
private static int BCollectGarbage_Nop( Thread l ) { switch( (GcOpt)Helpers.CheckOpt( l[1], (int)GcOpt.Collect, GcOptNames ) ) { case GcOpt.Count: return l.SetReturnValues( 0, 0 ); default: break; } return l.SetReturnValues( 0 ); }
private static int BToString( Thread l ) { var ret = ToStringCore( l[1], l ); return l.SetReturnValues( ret ); }
private static int SChar( Thread l ) { var buf = LString.InternalAllocBuffer( l.StackTop ); for( int i = LString.BufferDataOffset; i < buf.Length; i++ ) { var cch = (int)l[i - LString.BufferDataOffset + 1]; if( cch < 0 || cch > 0xFF ) throw new ArgumentException( "value out of range" ); buf[i] = (byte)cch; } return l.SetReturnValues( LString.InternalFinishBuffer( buf ) ); }
private static int BNext( Thread l ) { var tbl = (Table)l[1]; if( tbl == null ) throw new ArgumentNullException(); Value key = l[2]; Value val; if( tbl.GetNext( ref key, out val ) ) return l.SetReturnValues( key, val ); else return l.SetNilReturnValue(); }
private static int BSelect( Thread l ) { var selector = l[1]; if( selector == Literals.Symbol_Hash ) return l.SetReturnValues( l.StackTop - 1 ); var sel = (int)selector; var top = l.StackTop; if( sel < 0 ) sel = top + sel; else if( sel > top ) sel = top; if( sel <= 1 ) throw new ArgumentOutOfRangeException( "index", "index out of range" ); return top - sel; }
private static int SUpper( Thread l ) { var str = (LString)l[1]; var strDat = str.InternalData; var ret = LString.InternalAllocBuffer( str.Length ); for( int i = LString.BufferDataOffset; i < ret.Length; i++ ) { var ch = strDat[i]; if( ch >= (byte)'a' && ch <= (byte)'z' ) ch = (byte)((byte)'A' + (ch - (byte)'a')); ret[i] = ch; } return l.SetReturnValues( LString.InternalFinishBuffer( ret ) ); }
private static int TRemove( Thread l ) { var t = (Table)l[1]; int pos, n = t.GetLen(); switch( l.StackTop ) { case 1: pos = n; break; case 2: pos = (int)l[2]; break; default: throw new ArgumentException( "Incorrect number of args for table.remove." ); } var ret = t[pos]; for( int i = pos; i < n; i++ ) t[i] = t[i + 1]; t[n] = new Value(); return l.SetReturnValues( ret ); }
private static int SRep( Thread l ) { var str = (LString)l[1]; int n = (int)l[2]; if( n == 0 ) return l.SetReturnValues( LString.Empty ); if( n < 0 ) throw new ArgumentOutOfRangeException( "negative repeat count" ); var sep = l.StackTop >= 3 ? (LString)l[3] : LString.Empty; if( n == 1 ) return l.SetReturnValues( str ); int strOfs, strLen, sepOfs, sepLen; byte[] strBuf, sepBuf; str.UnsafeGetDataBuffer( out strBuf, out strOfs, out strLen ); sep.UnsafeGetDataBuffer( out sepBuf, out sepOfs, out sepLen ); var retLen = strLen * n + sepLen * (n - 1); var retBuf = LString.InternalAllocBuffer( retLen ); int retOfs = LString.BufferDataOffset; Buffer.BlockCopy( strBuf, strOfs, retBuf, retOfs, strLen ); if( sepLen == 0 ) { for( int i = 1; i < n; i++ ) Buffer.BlockCopy( strBuf, strOfs, retBuf, retOfs += strLen, strLen ); } else { for( int i = 1; i < n; i++ ) { Buffer.BlockCopy( sepBuf, sepOfs, retBuf, retOfs += strLen, sepLen ); Buffer.BlockCopy( strBuf, strOfs, retBuf, retOfs += sepLen, strLen ); } } Debug.Assert( retOfs + strLen == retBuf.Length ); return l.SetReturnValues( LString.InternalFinishBuffer( retBuf ) ); }
private static int SSub( Thread l ) { var str = (LString)l[1]; var beg = StrIdxArg( str, (int)l[2] ); var end = l.StackTop >= 3 ? StrIdxArg( str, (int)l[3] ) : str.Length - 1; if( beg <= end ) return l.SetReturnValues( str.Substring( beg, end - beg + 1 ) ); else return l.SetReturnValues( LString.Empty ); }
private static int SLen( Thread l ) { var str = (LString)l[1]; return l.SetReturnValues( str.Length ); }
private static int SGsub( Thread l ) { var str = (LString)l[1]; var pat = (LString)l[2]; var subst = l[3]; var subTy = subst.ValueType; switch( subTy ) { case LValueType.Number: l.ConvertToString( ref subst ); break; case LValueType.String: case LValueType.Function: case LValueType.Table: break; default: throw new ArgumentException( "string/function/table expected" ); } var max = l.StackTop >= 4 ? (int)l[4] : int.MaxValue; MatchState ms; InitMatchState( out ms, l ); ms.Str = str.InternalData; ms.StrInit = LString.BufferDataOffset; ms.Pat = pat.InternalData; int patInit = LString.BufferDataOffset; bool anchor = patInit < ms.Pat.Length && ms.Pat[patInit] == (byte)'^'; if( anchor ) patInit++; var strBuilder = l.GetStrBuilder( str.Length * 2 ); int sPos = LString.BufferDataOffset; int n = 0; while( n < max ) { ms.Level = 0; Debug.Assert( ms.MatchDepth == MaxCCalls ); var e = SMatch( ref ms, sPos, patInit ); if( e != -1 ) { n++; Value substVal; switch( subTy ) { case LValueType.Function: { l.Push( subst ); var nCap = PushCaptures( ref ms, sPos, e, false ); l.Call( nCap, 1 ); substVal = l.PopValue(); } break; case LValueType.Table: PushCapture( ref ms, 0, sPos, e ); substVal = l.GetTable( (Table)subst, l.PopValue() ); break; case LValueType.Number: //it's already been made a string substVal = subst; break; case LValueType.String: //need to handle escape sequences { var sb = (byte[])subst.RefVal; for( int i = LString.BufferDataOffset; i < sb.Length; i++ ) { var ch = sb[i]; if( ch != (byte)'%' ) { strBuilder.Append( ch ); continue; } if( ++i == sb.Length ) throw new ArgumentException( "Invalid use of % in replacement string" ); ch = sb[i]; if( ch == (byte)'%' ) { strBuilder.Append( ch ); continue; } switch( ch ) { case (byte)'0': strBuilder.Append( ms.Str, sPos, e - sPos ); break; case (byte)'1': case (byte)'2': case (byte)'3': case (byte)'4': case (byte)'5': case (byte)'6': case (byte)'7': case (byte)'8': case (byte)'9': { int idx = ch - (byte)'1'; PushCapture( ref ms, idx, sPos, e ); substVal = l.PopValue(); l.ConvertToString( ref substVal ); strBuilder.Append( (LString)substVal ); } break; default: throw new ArgumentException( "Invalid use o f% in replacement string" ); } } } substVal = new Value(); //hush, little compiler break; default: substVal = new Value(); break; } if( subTy != LValueType.String ) { //strings already appended, need to handle this case now if( !substVal.ToBool() ) { strBuilder.Append( ms.Str, sPos, e - sPos ); } else { l.ConvertToString( ref substVal ); strBuilder.Append( (LString)substVal ); } } } if( e != -1 && e > sPos ) sPos = e; else if( sPos < ms.Str.Length ) strBuilder.Append( ms.Str[sPos++] ); else break; if( anchor ) break; } strBuilder.Append( ms.Str, sPos, ms.Str.Length - sPos ); var ret = strBuilder.ToLString(); l.RetireStrBuilder( strBuilder ); RetireMatchState( ref ms ); return l.SetReturnValues( ret, n ); }
private static int SGMatch( Thread l ) { var str = (LString)l[1]; var pat = (LString)l[2]; return l.SetReturnValues( (Callable)new GMatcher( str, pat ) ); }
private static int BINext( Thread l ) { l.StackTop = 2; var tbl = (Table)l[1]; if( tbl == null ) throw new InvalidCastException(); var key = (int)(double)l[2] + 1; Value val; if( tbl.TryGetValue( key, out val ) ) return l.SetReturnValues( key, val ); else return l.SetNilReturnValue(); }
private static int MFrexp( Thread l ) { var n = (double)l[1]; //extract the actual bits long bits = BitConverter.DoubleToInt64Bits( n ); var isNeg = (bits < 0); var exp = (int)((bits >> 52) & 0x7FFL); var mant = bits & 0xFFFFFFFFFFFFFL; if( exp == 0 ) //denormal, exponent is actually 1 exp++; else //normal number, add the leading 1 to the mantissa mant = mant | (1L << 52); //deal with the exponent's bias (1023) //also compensate for the fact that the mantissa is coming //through as a whole number rather (therefore the extra 52) exp -= 1023 + 52; if( mant == 0 ) l.SetReturnValues( 0, 0 ); //partially normalize the mantissa (that is, move trailing 0s //into the exponent so that the mantissa is as small as can be) while( (mant & 0x1) == 0 ) { mant >>= 1; exp++; } //can't do much more in bits alone, the rest of the normalization //with the doubles we'll return (this is exactly the same loop //as above, only with fractions (because odd numbers) var nMant = (double)mant; var nExp = (double)exp; while( nMant >= 1 ) { nMant *= 0.5; nExp++; } if( isNeg ) nMant = -nMant; return l.SetReturnValues( nMant, nExp ); }
private static int BIPairs( Thread l ) { var val = l[1]; var mt = GetMetatableImp( val ); Value mmt; if( mt != null && mt.TryGetValue( Literals.TagMethod_IPairs, out mmt ) ) { l.StackTop = 1; l.Call( (Callable)mmt, 1, 3 ); return 3; } else { return l.SetReturnValues( INext, val, 0 ); } }
private static int MLog( Thread l ) { var n = (double)l[1]; if( l.StackTop == 1 ) return l.SetReturnValues( Math.Log( n ) ); var b = (double)l[2]; if( b == 10 ) return l.SetReturnValues( Math.Log10( n ) ); return l.SetReturnValues( Math.Log( n, b ) ); }
private static int BRawGet( Thread l ) { var ta = (Table)l[1]; return l.SetReturnValues( ta[l[2]] ); }
private static int MMin( Thread l ) { var ret = (double)l[1]; for( int i = 2; i <= l.StackTop; i++ ) { var n = (double)l[i]; if( n < ret ) ret = n; } return l.SetReturnValues( ret ); }
private static int BToNumber( Thread l ) { var nval = l[1]; if( nval.ValueType == LValueType.Number ) return l.SetReturnValues( nval ); var nstr = nval.ToLString(); if( nstr.IsNil ) return l.SetNilReturnValue(); byte[] nbuf; int nIndex, nCount; nstr.UnsafeGetDataBuffer( out nbuf, out nIndex, out nCount ); double num; if( l.StackTop < 2 ) { if( !Helpers.StrToNum( nbuf, nIndex, nCount, out num ) ) return l.SetNilReturnValue(); } else { int radix = (int)l[2]; if( radix < 2 || radix > 36 ) throw new ArgumentOutOfRangeException( "base out of range" ); if( !Helpers.StrToInt( nbuf, nIndex, nCount, out num, radix ) ) return l.SetNilReturnValue(); } return l.SetReturnValues( num ); }
private static int MModf( Thread l ) { var n = (double)l[1]; var i = Math.Truncate( n ); var f = n - i; return l.SetReturnValues( i, f ); }
public override int Execute( Thread l ) { var tbl = (Table)l[1]; if( tbl == null ) throw new ArgumentNullException(); Value key, val; if( tbl.GetNext( ref loc, out key, out val ) ) return l.SetReturnValues( key, val ); else return l.SetNilReturnValue(); }
private static int FindCore( Thread l, bool isFind ) { var str = (LString)l[1]; var pat = (LString)l[2]; int init = l.StackTop >= 3 ? StrIdxArg( str, (int)l[3] ) : 0; if( init == -1 ) init = 0; if( init == str.Length && init != 0 ) return l.SetNilReturnValue(); if( isFind && (l[4].ToBool() || !HasPatternSpecials( pat )) ) { //do a plain search int idx = str.IndexOf( pat, init ); if( idx != -1 ) return l.SetReturnValues( idx + 1, idx + pat.Length ); else return l.SetNilReturnValue(); } else { MatchState ms; InitMatchState( out ms, l ); ms.Str = str.InternalData; ms.StrInit = LString.BufferDataOffset; ms.Pat = pat.InternalData; int patInit = LString.BufferDataOffset; bool anchor = patInit < ms.Pat.Length && ms.Pat[patInit] == (byte)'^'; if( anchor ) patInit++; int sPos = LString.BufferDataOffset + init; do { Debug.Assert( ms.MatchDepth == MaxCCalls ); ms.Level = 0; var res = SMatch( ref ms, sPos, patInit ); if( res != -1 ) { if( isFind ) { l.StackTop = 0; l.Push( sPos - LString.BufferDataOffset + 1 ); l.Push( res - LString.BufferDataOffset ); return PushCaptures( ref ms, -1, -1 ) + 2; } else { return PushCaptures( ref ms, sPos, res ); } } } while( sPos++ < ms.Str.Length && !anchor ); RetireMatchState( ref ms ); return l.SetNilReturnValue(); } }