protected Reply <string> ParseRestOfString(CharStream <TUserState> stream, char firstChar, ErrorMessageList error) { #if LOW_TRUST var sb = new StringBuilder(16); sb.Append(firstChar); #else _16CharBuffer buffer_; // produces more efficient code on .NET than stackalloc char[16] char * buffer = (char *)(&buffer_); buffer[0] = firstChar; char[] chars = null; uint n = 1; #endif for (;;) { var tag = stream.StateTag; var reply = CharParser.Invoke(stream); if (reply.Status == ReplyStatus.Ok) { if (tag == stream.StateTag) { throw Internal.ParserCombinatorInInfiniteLoopHelper.CreateException("manyChars", stream); } error = reply.Error; #if LOW_TRUST sb.Append(reply.Result); #else var i = n % 16; if (i != 0) { buffer[i] = reply.Result; ++n; } else { if (chars == null) { chars = new char[32]; } else if (n == chars.Length) { var newChars = new char[2 * chars.Length]; Array.Copy(chars, newChars, chars.Length); chars = newChars; } for (i = 0; i < 16; ++i) { chars[n - 16 + i] = buffer[i]; } buffer[0] = reply.Result; ++n; } #endif } else if (reply.Status == ReplyStatus.Error && tag == stream.StateTag) { string str; #if LOW_TRUST str = sb.ToString(); #else if (n <= 16) { str = new String(buffer, 0, (int)n); } else { for (uint i = (n - 1) & 0x7ffffff0u; i < n; ++i) { chars[i] = buffer[i % 16]; } str = new string(chars, 0, (int)n); } #endif error = ErrorMessageList.Merge(error, reply.Error); return(new Reply <string> { Status = ReplyStatus.Ok, Result = str, Error = error }); } else { error = tag == stream.StateTag ? ErrorMessageList.Merge(error, reply.Error) : reply.Error; return(new Reply <string> { Status = reply.Status, Error = error }); } } }
internal unsafe static T RunParserOnSubstream<T,TUserState,TSubStreamUserState>( Microsoft.FSharp.Core.FSharpFunc<State<TSubStreamUserState>,T> parser, TSubStreamUserState userState, State<TUserState> stateBeforeSubStream, State<TUserState> stateAfterSubStream) { CharStream.Anchor subStreamAnchor; var s0 = stateBeforeSubStream; var data0 = s0.data; var data = new State<TSubStreamUserState>.Data{Line = data0.Line, LineBegin = data0.LineBegin, UserState = userState, StreamName = data0.StreamName}; var state = new State<TSubStreamUserState>{data = data}; // the Iter member is assigned below CharStream.Anchor* anchor = s0.Iter.Anchor; var s1 = stateAfterSubStream; if (anchor != s1.Iter.Anchor) throw new ArgumentException("The states are associated with different CharStreams."); if (anchor->LastBlock == 0) { // the CharStream has only one block, so its safe to // construct a new CharStream from a pointer into the original buffer char* ptr = s0.Iter.Ptr; if (ptr == null) ptr = anchor->BufferEnd; char* end = s1.Iter.Ptr; if (end == null) end = anchor->BufferEnd; if (end < ptr) throw new ArgumentException("The position of the second state lies before the position of the first state."); int length = CharStream.PositiveDistance(ptr, end); CharStream stream = (CharStream)anchor->StreamHandle.Target; using (var subStream = new CharStream(stream.BufferString, stream.BufferStringPointer, ptr, length, s0.Index, &subStreamAnchor)) { // state.Iter = subStream.Begin state.Iter.Anchor = &subStreamAnchor; state.Iter.Ptr = subStreamAnchor.BufferBegin; // will be null if length is 0 state.Iter.Block = length == 0 ? -1 : 0; return parser.Invoke(state); } } else if (s0.Iter.Block == s1.Iter.Block && anchor->Block == s1.Iter.Block) { char* ptr = s0.Iter.Ptr; char* end = s1.Iter.Ptr; if (end < ptr) throw new ArgumentException("The position of the second state lies before the position of the first state."); int length = CharStream.PositiveDistance(ptr, end); string subString = new String(ptr, 0, length); fixed (char* pSubString = subString) using (var subStream = new CharStream(subString, pSubString, pSubString, length, s0.Index, &subStreamAnchor)) { // state.Iter = subStream.Begin state.Iter.Anchor = &subStreamAnchor; state.Iter.Ptr = subStreamAnchor.BufferBegin; // will be null if length is 0 state.Iter.Block = length == 0 ? -1 : 0; return parser.Invoke(state); } } else { ulong index1 = (ulong)s0.Iter.Index; ulong index2 = (ulong)s1.Iter.Index; if (index2 < index1) throw new ArgumentException("The position of the second state lies before the position of the first state."); ulong length_ = index2 - index1; // length >= Int32.MaxValue will trigger an exception anyway (because the string is too large) int length = length_ > (uint)System.Int32.MaxValue ? System.Int32.MaxValue : (int)length_; string subString = new String('\u0000', length); fixed (char* pSubString = subString) { s0.Iter.Read(pSubString, length); using (var subStream = new CharStream(subString, pSubString, pSubString, length, s0.Index, &subStreamAnchor)) { // state.Iter = subStream.Begin state.Iter.Anchor = &subStreamAnchor; state.Iter.Ptr = subStreamAnchor.BufferBegin; // will be null if length is 0 state.Iter.Block = length == 0 ? -1 : 0; return parser.Invoke(state); } } } }