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 ); }
public void PushPop() { var thread = new Thread(); Assert.AreEqual( 0, thread.StackTop ); thread.Push( Math.PI ); Assert.AreEqual( 1, thread.StackTop ); Assert.AreEqual( Math.PI, thread.PopValue() ); Assert.AreEqual( 0, thread.StackTop ); }
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(); } }