/// <summary> /// Create a new parsed define item according to its type /// </summary> private ParsedDefine NewParsedDefined(string name, ParseFlag flags, Token token, ParsedAsLike asLike, string left, ParseDefineType type, string tempPrimitiveType, string viewAs, string bufferFor) { // set flags flags |= _context.Scope is ParsedFile ? ParseFlag.FileScope : ParseFlag.LocalScope; switch (type) { case ParseDefineType.Parameter: flags |= ParseFlag.Parameter; break; case ParseDefineType.Buffer: flags |= ParseFlag.Buffer; var newBuffer = new ParsedBuffer(name, token, asLike, left, type, tempPrimitiveType, viewAs, bufferFor, ConvertStringToParsedPrimitiveType(tempPrimitiveType, asLike == ParsedAsLike.Like)) { TargetTable = FindAnyTableByName(bufferFor) }; flags |= !bufferFor.Contains(".") && newBuffer.TargetTable != null && !newBuffer.TargetTable.IsTempTable ? ParseFlag.MissingDbName : 0; newBuffer.Flags = flags; return(newBuffer); } var newDefine = new ParsedDefine(name, token, asLike, left, type, tempPrimitiveType, viewAs, ConvertStringToParsedPrimitiveType(tempPrimitiveType, asLike == ParsedAsLike.Like)) { Flags = flags }; return(newDefine); }
/// <summary> /// Create a new parsed define item according to its type /// </summary> private ParsedDefine NewParsedDefined(string name, ParseFlag flags, Token defineToken, Token endToken, ParsedAsLike asLike, string left, ParseDefineType type, string tempPrimitiveType, string viewAs, string bufferFor, int extent) { // set flags flags |= GetCurrentBlock <ParsedScopeBlock>() is ParsedFile ? ParseFlag.FileScope : ParseFlag.LocalScope; if (type == ParseDefineType.Parameter) { flags |= ParseFlag.Parameter; } if (tempPrimitiveType.Equals("buffer")) { flags |= ParseFlag.Buffer; return(new ParsedBuffer(name, defineToken, asLike, left, type, null, viewAs, bufferFor) { Flags = flags, EndPosition = endToken.EndPosition, PrimitiveType = ParsedPrimitiveType.Buffer }); } var newDefine = new ParsedDefine(name, defineToken, asLike, left, type, tempPrimitiveType, viewAs, extent) { Flags = flags, EndPosition = endToken.EndPosition }; return(newDefine); }
public ExprSeq ParseExprSeq(ParseFlag flags = ParseFlag.None) { CurrentState.ParseFlags |= flags; // ExprSeq = new ExprSeq(); Expression expr = null; if (CurrentToken.Kind == TokenKind.RoundList) { if (CurrentList.Count != 0) { CreateState(CurrentList); expr = ParseExpression(); PopState(); } Advance(); } else { expr = ParseExpression(); } if (expr == null) { return(null); } if (!(expr is ClauseExpr)) { //Debug.Print(expr.ToString()); ExprSeq.AddChild(expr); } return(ExprSeq); }
/// <summary> /// Adds the "external" flag if needed /// </summary> private ParseFlag AddExternalFlag(ParseFlag flag) { if (_isBaseFile) { return(flag); } return(flag | ParseFlag.External); }
public ParsedField(string name, string lcTempPrimitiveType, string format, int order, ParseFlag flags, string initialValue, string description, ParsedAsLike asLike) : base(name) { TempPrimitiveType = lcTempPrimitiveType; Format = format; Order = order; Flags = flags; InitialValue = initialValue; Description = description; AsLike = asLike; }
/// <summary> /// Matches a procedure definition /// </summary> private ParsedDestructor CreateParsedDestructor(Token destructorToken, ParsedScope parentScope) { /* * DESTRUCTOR [ PUBLIC ] class-name ( ) : * Destructor-body */ // info we will extract from the current statement : string name = ""; ParseFlag flags = 0; Token token; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } if (token is TokenWord) { switch (token.Value.ToLower()) { case "public": flags |= ParseFlag.Public; break; default: name = token.Value; break; } } } while (MoveNext()); if (name == "") { return(null); } var newDestructor = new ParsedDestructor(name, destructorToken, parentScope) { // = end position of the EOS of the statement Flags = flags, EndPosition = token.EndPosition }; AddParsedItem(newDestructor, destructorToken.OwnerNumber); return(newDestructor); }
public static void ForEachFlag(Action <string, ParseFlag> toApplyOnFlag) { foreach (var name in Enum.GetNames(typeof(ParseFlag))) { ParseFlag flag = (ParseFlag)Enum.Parse(typeof(ParseFlag), name); if (flag == 0) { continue; } toApplyOnFlag(name, flag); } }
public EbmlSig(byte[] sig, string name, ParseFlag flag = ParseFlag.None, EbmlType type = EbmlType.Master) { this.Name = name; this.Type = type; this.Flag = flag; this.sig = sig; this.Signature = new ReadOnlyCollection <byte> (this.sig); this.Sig32 = this.sig[0]; for (var bx = 1; bx < this.sig.Length; ++bx) { this.Sig32 = this.Sig32 << 8 | this.sig[bx]; } }
static bool TryParseUInt(ref UString s, ref ulong result, int radix, ParseFlag flags, out int numDigits) { numDigits = 0; if ((flags & ParseFlag.SkipSpacesInFront) != 0) { s = SkipSpaces(s); } bool overflow = false; int oldStart = s.InternalStart; for (;; s = s.Slice(1)) { char c = s[0, '\0']; uint digit = (uint)Base36DigitValue(c); if (digit >= radix) { if ((c == ' ' || c == '\t') && (flags & ParseFlag.SkipSpacesInsideNumber) != 0) { continue; } else if (c == '_' && (flags & ParseFlag.SkipUnderscores) != 0) { continue; } else { break; } } ulong next; try { next = checked (result * (uint)radix + digit); } catch (OverflowException) { overflow = true; if ((flags & ParseFlag.StopBeforeOverflow) != 0) { return(false); } next = result * (uint)radix + digit; } numDigits++; result = next; } return(!overflow && numDigits > 0); }
public static string HtmlFormatRowParam(ParseFlag flags, string text) { var image = ParseFlag.Input.ToString(); if (flags.HasFlag(ParseFlag.InputOutput)) { image = ParseFlag.InputOutput.ToString(); } else if (flags.HasFlag(ParseFlag.Output)) { image = ParseFlag.Output.ToString(); } else if (flags.HasFlag(ParseFlag.Return)) { image = ParseFlag.Return.ToString(); } return("<div class='ToolTipRowWithImg'><img style='padding-right: 2px; padding-left: 5px;' src='" + image + "' height='15px'>" + text + "</div>"); }
/// <summary> /// Determines flags /// </summary> private static ParseFlag SetFlags(ParseFlag flag, string lcFlagString) { if (lcFlagString.Contains("global")) { flag = flag | ParseFlag.Global; } if (lcFlagString.Contains("shared")) { flag = flag | ParseFlag.Shared; } if (lcFlagString.Contains("private")) { flag = flag | ParseFlag.Private; } if (lcFlagString.Contains("new")) { flag = flag | ParseFlag.Private; } return(flag); }
private static int SkipExtraDigits(ref UString s, int radix, ParseFlag flags) { for (int skipped = 0;; skipped++, s = s.Slice(1)) { char c = s[0, '\0']; uint digit = (uint)Base36DigitValue(c); if (digit >= radix) { if ((c == ' ' || c == '\t') && (flags & ParseFlag.SkipSpacesInsideNumber) != 0) { continue; } else if (c == '_' && (flags & ParseFlag.SkipUnderscores) != 0) { continue; } else { return(skipped); } } } }
/// <summary>Parses a string to a single-precision float, returning NaN on /// failure or an infinity value on overflow.</summary> /// <param name="radix">Base of the number to parse; must be 2 (binary), /// 4, 8 (octal), 10 (decimal), 16 (hexadecimal) or 32.</param> /// <param name="flags">Alters parsing behavior, see <see cref="ParseFlags"/>.</param> public static float TryParseFloat(ref UString source, int radix, ParseFlag flags = 0) { ulong mantissa; int exponentBase2, exponentBase10, numDigits; bool negative; if (!TryParseFloatParts(ref source, radix, out negative, out mantissa, out exponentBase2, out exponentBase10, out numDigits, flags)) { return(float.NaN); } else { float num = MathEx.ShiftLeft((float)mantissa, exponentBase2); if (negative) { num = -num; } if (exponentBase10 == 0) { return(num); } return(num * (float)System.Math.Pow(10, exponentBase10)); } }
public EbmlSig(byte[] sig, EbmlType type, string name, ParseFlag flag = ParseFlag.None) : this(sig, name, flag, type) { }
/// <inheritdoc cref="TryParseInt(string, ref int, out int, int, bool)"/> public static bool TryParseInt(ref UString input, out long result, int radix = 10, ParseFlag flags = 0) { if ((flags & ParseFlag.SkipSpacesInFront) != 0) { input = SkipSpaces(input); } UString s = input; bool negative = false; char c = s[0, '\0']; if (c == '-' || c == '+') { negative = c == '-'; s = s.Slice(1); } ulong resultU = 0; int numDigits; bool ok = TryParseUInt(ref s, ref resultU, radix, flags, out numDigits); result = negative ? -(long)resultU : (long)resultU; if (numDigits != 0) { input = s; } return(ok && ((result < 0) == negative || result == 0)); }
public static bool TryParseUInt(ref UString s, out ulong result, int radix = 10, ParseFlag flags = 0) { int _; result = 0; return(TryParseUInt(ref s, ref result, radix, flags, out _)); }
/// <summary> /// Matches a procedure definition /// </summary> private ParsedProcedure CreateParsedProcedure(Token procToken) { /* * PROCEDURE proc-name[ PRIVATE ] : * [procedure-body] * * PROCEDURE proc-name * { EXTERNAL "dllname" [ CDECL | PASCAL | STDCALL ] * [ ORDINAL n ][ PERSISTENT ][ THREAD-SAFE ] | IN SUPER } : * [ procedure-body ] */ // info we will extract from the current statement : string name = ""; ParseFlag flags = 0; string externalDllName = null; _lastTokenWasSpace = true; StringBuilder leftStr = new StringBuilder(); Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // matching name if (token is TokenWord || token is TokenString) { name = token is TokenWord ? token.Value : GetTokenStrippedValue(token); state++; } continue; case 1: // matching external if (!(token is TokenWord)) { continue; } switch (token.Value.ToLower()) { case "external": flags |= ParseFlag.External; state++; break; case "private": flags |= ParseFlag.Private; break; } break; case 2: // matching the name of the external dll if (!(token is TokenString)) { continue; } externalDllName = GetTokenStrippedValue(token); state--; break; } AddTokenToStringBuilder(leftStr, token); } while (MoveNext()); if (state < 1) { return(null); } var newProc = new ParsedProcedure(name, procToken, leftStr.ToString(), externalDllName) { // = end position of the EOS of the statement EndPosition = token.EndPosition, Flags = flags }; AddParsedItem(newProc, procToken.OwnerNumber); return(newProc); }
/// <summary> /// Analyse a preprocessed directive (analyses the whole statement) /// This method does not use the MoveNext because we don't want to analyse the words in a preprocess directive /// (in case of a scope-define we will analyse the words in the variable value when we actually use the variable, /// and in the other directive the words are garbage) /// </summary> private ParsedScopePreProcBlock CreateParsedPreProcDirective(Token directiveToken) { ParsedScopePreProcBlock newBlock = null; // info we will extract from the current statement : string variableName = null; StringBuilder definition = new StringBuilder(); var count = 0; while (true) { count++; // need to replace in case we use for instance a {&var} in a scope-define value ReplaceIncludeAndPreprocVariablesAhead(count); var token = PeekAt(count); if (token is TokenEof) { break; } if (token is TokenComment) { continue; } // a ~ allows for a eol but we don't control if it's an eol because if it's something else we probably parsed it wrong anyway (in the lexer) if (token is TokenSymbol && token.Value == "~") { if (PeekAt(count + 1) is TokenEol) { count++; } continue; } if (token is TokenEol) { break; } // read the first word after the directive if (string.IsNullOrEmpty(variableName) && token is TokenWord) { variableName = token.Value; continue; } definition.Append(token.Value); } ParseFlag flags = 0; // match first word of the statement switch (directiveToken.Value.ToUpper()) { case "&GLOBAL-DEFINE": case "&GLOBAL": case "&GLOB": flags |= ParseFlag.Global; break; case "&SCOPED-DEFINE": case "&SCOPED": flags |= ParseFlag.FileScope; break; case "&ANALYZE-SUSPEND": // we don't care about the blocks of include files if (directiveToken.OwnerNumber > 0) { break; } // it marks the beginning of an appbuilder block, it can only be at a root/File level, otherwise flag error if (!(GetCurrentBlock <ParsedScopeBlock>() is ParsedFile)) { _parserErrors.Add(new ParserError(ParserErrorType.NotAllowedUibBlockStart, directiveToken, _context.BlockStack.Count, _parsedIncludes)); } // we match a new block start but we didn't match the previous block end, flag error if (GetCurrentBlock <ParsedScopePreProcBlock>() != null) { _parserErrors.Add(new ParserError(ParserErrorType.UnexpectedUibBlockStart, directiveToken, _context.BlockStack.Count, _parsedIncludes)); } // matching different intersting blocks var textAfterDirective = variableName + " " + definition.ToString().Trim(); ParsedPreProcBlockType type = ParsedPreProcBlockType.Block; string blockName = "Appbuilder block"; if (textAfterDirective.ContainsFast("_FUNCTION-FORWARD")) { type = ParsedPreProcBlockType.Prototype; blockName = "Function prototype"; } else if (textAfterDirective.ContainsFast("_MAIN-BLOCK")) { type = ParsedPreProcBlockType.MainBlock; blockName = "Main block"; } else if (textAfterDirective.ContainsFast("_DEFINITIONS")) { type = ParsedPreProcBlockType.DefinitionBlock; blockName = "Definitions"; } else if (textAfterDirective.ContainsFast("_UIB-PREPROCESSOR-BLOCK")) { type = ParsedPreProcBlockType.UibPreprocessorBlock; blockName = "Pre-processor definitions"; } else if (textAfterDirective.ContainsFast("_XFTR")) { type = ParsedPreProcBlockType.XtfrBlock; blockName = "Xtfr"; } else if (textAfterDirective.ContainsFast("_PROCEDURE-SETTINGS")) { type = ParsedPreProcBlockType.SettingsBlock; blockName = "Procedure settings"; } else if (textAfterDirective.ContainsFast("_CREATE-WINDOW")) { type = ParsedPreProcBlockType.CreateWindowBlock; blockName = "Window settings"; } else if (textAfterDirective.ContainsFast("_RUN-TIME-ATTRIBUTES")) { type = ParsedPreProcBlockType.RuntimeBlock; blockName = "Runtime attributes"; } newBlock = new ParsedScopePreProcBlock(blockName, directiveToken) { Type = type, BlockDescription = textAfterDirective }; // save the block description AddParsedItem(newBlock, directiveToken.OwnerNumber); break; case "&UNDEFINE": if (variableName != null) { var found = (ParsedPreProcVariable)_parsedItemList.FindLast(item => (item is ParsedPreProcVariable && item.Name.Equals(variableName))); if (found != null) { found.UndefinedLine = _context.CurrentStatement.FirstToken.Line; } } break; } // We matched a new preprocessed variable? if (flags > 0 && !string.IsNullOrEmpty(variableName)) { var newVar = new ParsedPreProcVariable(variableName, directiveToken, 0, definition.ToString().Trim()) { Flags = flags }; AddParsedItem(newVar, directiveToken.OwnerNumber); // add it to the know variables (either to the global scope or to the local scope) SetPreProcVariableValue(flags.HasFlag(ParseFlag.Global) ? 0 : directiveToken.OwnerNumber, variableName, newVar.Value); } // we directly set the new token position there (it will be the EOL after this directive) _tokenPos += count; AddLineInfo(PeekAt(0)); // since we didn't use MoveNext we also manually replace the includes ahead ReplaceIncludeAndPreprocVariablesAhead(1); ReplaceIncludeAndPreprocVariablesAhead(2); return(newBlock); }
/// <summary> /// Matches a procedure definition /// </summary> private ParsedClass CreateParsedClass(Token classToken) { /* * CLASS class-type-name [ INHERITS super-type-name ] * [ IMPLEMENTS interface-type-name [ , interface-type-name ] ... ] * [ USE-WIDGET-POOL ] * [ ABSTRACT | FINAL ] : * [ class-body ] */ // info we will extract from the current statement : string name = ""; string Inherits = ""; ParseFlag flags = 0; List <string> Implements = new List <string>(); Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } if (token is TokenWord) { if (state == 0) { name = token.Value; state++; } else { switch (token.Value.ToLower()) { case "inherits": state = 2; break; case "implements": state = 3; break; case "abstract": flags |= ParseFlag.Abstract; break; case "final": flags |= ParseFlag.Final; break; default: if (state == 2) { Inherits = token.Value; state--; } else if (state == 3) { Implements.Add(token.Value); } break; } } continue; } if (token is TokenString) { if (state == 0) { name = GetTokenStrippedValue(token); state++; } continue; } } while (MoveNext()); if (state < 1) { return(null); } var newClass = new ParsedClass(name, classToken, Inherits, Implements) { // = end position of the EOS of the statement Flags = flags, EndPosition = token.EndPosition }; AddParsedItem(newClass, classToken.OwnerNumber); return(newClass); }
/// <summary> /// Matches a procedure definition /// </summary> private ParsedConstructor CreateParsedConstructor(Token constructorToken, ParsedScope parentScope) { /* * CONSTRUCTOR [ PRIVATE | PROTECTED | PUBLIC | STATIC ] class-name * ( [ parameter [ , parameter ] ... ] ) : * constructor-body */ // info we will extract from the current statement : string name = ""; ParseFlag flags = 0; StringBuilder parameters = new StringBuilder(); List <ParsedDefine> parametersList = null; Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // default state if (token is TokenWord) { switch (token.Value.ToLower()) { case "private": flags |= ParseFlag.Private; break; case "public": flags |= ParseFlag.Public; break; case "protected": flags |= ParseFlag.Protected; break; case "static": flags |= ParseFlag.Static; break; default: name = token.Value; break; } } if (token is TokenSymbol && token.Value.Equals("(")) { state = 1; } break; case 1: // read parameters, define a ParsedDefineItem for each parametersList = GetParsedParameters(constructorToken, parameters); state = 2; break; } } while (MoveNext()); if (state < 1) { return(null); } var newConstructor = new ParsedConstructor(name, constructorToken, parentScope) { // = end position of the EOS of the statement Flags = flags, EndPosition = token.EndPosition }; if (parametersList != null) { newConstructor.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { newConstructor.Parameters.Add(parsedItem); } } AddParsedItem(newConstructor, constructorToken.OwnerNumber); return(newConstructor); }
/// <summary> /// Creates a parsed item for RUN statements /// </summary> /// <param name="runToken"></param> private void CreateParsedRun(Token runToken) { /* * RUN * { extern-proc-name | VALUE ( extern-expression ) | path-name<<member-name>> | } | [ PERSISTENT | SINGLE-RUN | SINGLETON [ SET proc-handle]] | [ ON [ SERVER ] {server-handle | session-handle } | [ TRANSACTION DISTINCT ] | [ ASYNCHRONOUS | [ SET async-request-handle] | [ EVENT-PROCEDURE event-internal-procedure | [ IN procedure-context]] | ] | ] | [ ( parameter[ , parameter]... ) ] | [ argument ]... | [ NO-ERROR ] | | RUN | { intern-proc-name | VALUE ( intern-expression) } | [ IN proc-handle] | [ ASYNCHRONOUS | [ SET async-request-handle] | [ EVENT-PROCEDURE event-internal-procedure | [ IN procedure-context]] | ] | [ ( parameter[ , parameter]... ) ] | [ NO-ERROR ] | | RUN portTypeName[ SET hPortType ] ON SERVER hWebService[ NO-ERROR ] . | | RUN operationName IN hPortType | [ ASYNCHRONOUS | [ SET async-request-handle] | [ EVENT-PROCEDURE event-internal-procedure | [ IN procedure-context]] | [ ( parameter[ , parameter]... ) ] | [ NO-ERROR ]. | | | RUN SUPER [ ( parameter[ , parameter]... ) ][ NO-ERROR ] | | TODO : | RUN STORED-PROCEDURE procedure | [integer-field = PROC-HANDLE ] | [ NO-ERROR ] | [ ( parameter[ , parameter]... ) ] | */ // info we will extract from the current statement : string name = ""; ParseFlag flag = 0; _lastTokenWasSpace = true; int state = 0; do { var token = PeekAt(1); // next token if (state == 2) { break; // stop after finding the RUN name to be able to match other words in the statement } if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // matching proc name (or VALUE) if (token is TokenSymbol && token.Value.Equals(")")) { state++; } else if (flag.HasFlag(ParseFlag.Uncertain) && !(token is TokenWhiteSpace || token is TokenSymbol)) { name += GetTokenStrippedValue(token); } else if (token is TokenWord) { if (token.Value.ToLower().Equals("value")) { flag |= ParseFlag.Uncertain; } else { name += token.Value; state++; } } else if (token is TokenString) { name = GetTokenStrippedValue(token); state++; } break; case 1: // matching PERSISTENT (or a path instead of a file) if (token is TokenSymbol && (token.Value.Equals("/") || token.Value.Equals("\\"))) { // if it's a path, append it to the name of the run name += token.Value; state = 0; break; } if (!(token is TokenWord)) { break; } if (token.Value.EqualsCi("persistent")) { flag |= ParseFlag.Persistent; } state++; break; } } while (MoveNext()); if (state == 0) { return; } AddParsedItem(new ParsedRun(name, runToken, null) { Flags = flag }, runToken.OwnerNumber); }
/// <summary> /// Matches a function definition (not the FORWARD prototype) /// </summary> private ParsedFunction CreateParsedFunction(Token functionToken) { // info we will extract from the current statement : string name = null; string parsedReturnType = null; int extent = 0; ParseFlag flags = 0; StringBuilder parameters = new StringBuilder(); List <ParsedDefine> parametersList = null; ParsedImplementation createdImp = null; _lastTokenWasSpace = true; Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // matching name if (!(token is TokenWord)) { break; } name = token.Value; state++; break; case 1: // matching return type if (!(token is TokenWord)) { break; } if (token.Value.EqualsCi("returns") || token.Value.EqualsCi("class")) { continue; } parsedReturnType = token.Value; state++; break; case 2: // matching parameters (start) if (token is TokenWord) { if (token.Value.EqualsCi("private")) { flags |= ParseFlag.Private; } if (token.Value.EqualsCi("extent")) { extent = GetExtentNumber(2); } // we didn't match any opening (, but we found a forward if (token.Value.EqualsCi("forward")) { state = 99; } else if (token.Value.EqualsCi("in")) { state = 100; } } else if (token is TokenSymbol && token.Value.Equals("(")) { state = 3; } break; case 3: // read parameters, define a ParsedDefineItem for each parametersList = GetParsedParameters(functionToken, parameters); state = 10; break; case 10: // matching prototype, we dont want to create a ParsedItem for prototype if (token is TokenWord) { if (token.Value.EqualsCi("forward")) { state = 99; } else if (token.Value.EqualsCi("in")) { state = 100; } } break; } } while (MoveNext()); if (name == null || parsedReturnType == null) { return(null); } // otherwise it needs to ends with : or . if (!(token is TokenEos)) { return(null); } // New prototype, we matched a forward or a IN if (state >= 99) { ParsedPrototype createdProto = new ParsedPrototype(name, functionToken, parsedReturnType) { Scope = GetCurrentBlock <ParsedScopeBlock>(), FilePath = FilePathBeingParsed, SimpleForward = state == 99, // allows us to know if we expect an implementation in this .p or not EndPosition = token.EndPosition, EndBlockLine = token.Line, EndBlockPosition = token.EndPosition, Flags = flags, Extent = extent, ParametersString = parameters.ToString() }; if (!_functionPrototype.ContainsKey(name)) { _functionPrototype.Add(name, createdProto); } AddParsedItem(createdProto, functionToken.OwnerNumber); // case of a IN if (!createdProto.SimpleForward) { // add the parameters to the list if (parametersList != null) { createdProto.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { createdProto.Parameters.Add(parsedItem); } } } } else { // New function createdImp = new ParsedImplementation(name, functionToken, parsedReturnType) { EndPosition = token.EndPosition, Flags = flags, Extent = extent, ParametersString = parameters.ToString() }; // it has a prototype? if (_functionPrototype.ContainsKey(name)) { // make sure it was a prototype! var proto = _functionPrototype[name] as ParsedPrototype; if (proto != null && proto.SimpleForward) { createdImp.HasPrototype = true; createdImp.PrototypeLine = proto.Line; createdImp.PrototypeColumn = proto.Column; createdImp.PrototypePosition = proto.Position; createdImp.PrototypeEndPosition = proto.EndPosition; // boolean to know if the implementation matches the prototype createdImp.PrototypeUpdated = ( createdImp.Flags == proto.Flags && createdImp.Extent.Equals(proto.Extent) && createdImp.TempReturnType.EqualsCi(proto.TempReturnType) && createdImp.ParametersString.EqualsCi(proto.ParametersString)); } } else { _functionPrototype.Add(name, createdImp); } // add the parameters to the list if (parametersList != null) { createdImp.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { createdImp.Parameters.Add(parsedItem); } } AddParsedItem(createdImp, functionToken.OwnerNumber); } return(createdImp); }
/// <summary> /// Matches a procedure definition /// </summary> private ParsedMethod CreateParsedMethod(Token methodToken, ParsedScope parentScope) { /* * METHOD [ PRIVATE | PROTECTED | PUBLIC ] [ STATIC | ABSTRACT ] * [ OVERRIDE ] [ FINAL ] * { VOID | return-type } method-name * ( [ parameter [ , parameter ] ... ] ) : */ // info we will extract from the current statement : string name = ""; string parsedReturnType = "CLASS"; ParseFlag flags = 0; StringBuilder parameters = new StringBuilder(); List <ParsedDefine> parametersList = null; Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } switch (state) { case 0: // default state if (token is TokenWord) { switch (token.Value.ToLower()) { case "private": flags |= ParseFlag.Private; break; case "public": flags |= ParseFlag.Public; break; case "protected": flags |= ParseFlag.Protected; break; case "static": flags |= ParseFlag.Static; break; case "abstract": flags |= ParseFlag.Abstract; break; case "override": flags |= ParseFlag.Override; break; case "final": flags |= ParseFlag.Final; break; case "void": case "class": case "character": case "integer": case "int64": case "decimal": case "date": case "datetime": case "datetime-tz": case "handle": case "logical": case "longchar": case "memptr": case "recid": case "rowid": case "raw": parsedReturnType = token.Value.ToUpper(); break; default: name = token.Value; break; } } if (token is TokenSymbol && token.Value.Equals("(")) { state = 1; } break; case 1: // read parameters, define a ParsedDefineItem for each parametersList = GetParsedParameters(methodToken, parameters); state = 2; break; } } while (MoveNext()); if (state < 1) { return(null); } var newMethod = new ParsedMethod(name, methodToken, parentScope, parsedReturnType) { // = end position of the EOS of the statement Flags = flags, EndPosition = token.EndPosition }; if (parametersList != null) { newMethod.Parameters = new List <ParsedDefine>(); foreach (var parsedItem in parametersList) { newMethod.Parameters.Add(parsedItem); } } AddParsedItem(newMethod, methodToken.OwnerNumber); return(newMethod); }
/// <summary>Parses the parts of a floating-point string. See the other /// overload for details.</summary> /// <param name="radix">Base of the number to parse; must be 2 (binary), /// 4, 8 (octal), 10 (decimal), 16 (hexadecimal) or 32.</param> /// <param name="negative">true if the string began with '-'.</param> /// <param name="mantissa">Integer magnitude of the number.</param> /// <param name="exponentBase2">Base-2 exponent to apply.</param> /// <param name="exponentBase10">Base-10 exponent to apply.</param> /// <param name="numDigits">Set to the number of digits in the number, not including the exponent part.</param> /// <param name="flags">Alters parsing behavior, see <see cref="ParseFlags"/>.</param> /// <remarks> /// This method is a wrapper around the other overload that combines /// the 'exponentBaseR' parameter with 'exponentBase2' or 'exponentBase10' /// depending on the radix. For example, when radix=10, this method /// adds <c>exponentBaseR</c> to <c>exponentBase10</c>. /// </remarks> public static bool TryParseFloatParts(ref UString source, int radix, out bool negative, out ulong mantissa, out int exponentBase2, out int exponentBase10, out int numDigits, ParseFlag flags = 0) { int radixShift = 0; if (radix != 10) { radixShift = MathEx.Log2Floor(radix); if (radix > 32 || radix != 1 << radixShift) { throw new ArgumentOutOfRangeException("radix"); } } int exponentBaseR; bool success = TryParseFloatParts(ref source, radix, out negative, out mantissa, out exponentBaseR, out exponentBase2, out exponentBase10, out numDigits, flags); try { checked { if (radix == 10) { exponentBase10 += exponentBaseR; } else { exponentBase2 += exponentBaseR * radixShift; } } } catch (OverflowException) { return(false); } return(success); }
/// <summary> /// Matches a new definition /// </summary> private void CreateParsedDefine(Token defineToken, bool isDynamic) { /* * all DEFINE and CREATE statement */ // info we will extract from the current statement : string name = ""; ParseFlag flags = isDynamic ? ParseFlag.Dynamic : 0; ParsedAsLike asLike = ParsedAsLike.None; ParseDefineType type = ParseDefineType.None; string tempPrimitiveType = ""; string viewAs = ""; string bufferFor = ""; int extent = 0; _lastTokenWasSpace = true; StringBuilder left = new StringBuilder(); // for temp tables: string likeTable = ""; bool isTempTable = false; var fields = new List <ParsedField>(); ParsedField currentField = new ParsedField("", "", "", 0, 0, "", "", ParsedAsLike.None); StringBuilder useIndex = new StringBuilder(); // for tt indexes var indexList = new List <ParsedIndex>(); string indexName = ""; var indexFields = new List <string>(); ParsedIndexFlag indexFlags = ParsedIndexFlag.None; var indexSort = "+"; // + for ascending, - for descending Token token; int state = 0; do { token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenComment) { continue; } string lowerToken; bool matchedLikeTable = false; switch (state) { case 0: // matching until type of define is found if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); switch (lowerToken) { case "buffer": case "browse": case "stream": case "button": case "dataset": case "frame": case "query": case "event": case "image": case "menu": case "rectangle": case "property": case "sub-menu": case "parameter": if (!Enum.TryParse(lowerToken, true, out type)) { type = ParseDefineType.None; } state++; break; case "data-source": type = ParseDefineType.DataSource; state++; break; case "var": case "variable": type = ParseDefineType.Variable; state++; break; case "temp-table": case "work-table": case "workfile": isTempTable = true; state++; break; case "new": flags |= ParseFlag.New; break; case "global": flags |= ParseFlag.Global; break; case "shared": flags |= ParseFlag.Shared; break; case "private": flags |= ParseFlag.Private; break; case "protected": flags |= ParseFlag.Protected; break; case "public": flags |= ParseFlag.Public; break; case "static": flags |= ParseFlag.Static; break; case "abstract": flags |= ParseFlag.Abstract; break; case "override": flags |= ParseFlag.Override; break; case "serializable": flags |= ParseFlag.Serializable; break; case "input": flags |= ParseFlag.Input; break; case "return": flags |= ParseFlag.Return; break; case "output": flags |= ParseFlag.Output; break; case "input-output": flags |= ParseFlag.InputOutput; break; /*default: * ParseFlag parsedFlag; * if (Enum.TryParse(lowerToken, true, out parsedFlag)) * flags |= parsedFlag; * break;*/ } break; case 1: // matching the name if (!(token is TokenWord)) { break; } name = token.Value; if (type == ParseDefineType.Variable) { state = 10; } if (type == ParseDefineType.Buffer) { tempPrimitiveType = "buffer"; state = 81; } if (type == ParseDefineType.Parameter) { lowerToken = token.Value.ToLower(); switch (lowerToken) { case "buffer": tempPrimitiveType = lowerToken; type = ParseDefineType.Buffer; flags |= ParseFlag.Parameter; state = 80; break; case "table": case "table-handle": case "dataset": case "dataset-handle": tempPrimitiveType = lowerToken; state = 80; break; default: state = 10; break; } } if (isTempTable) { state = 20; } if (state != 1) { break; } state = 99; break; case 10: // define variable : match as or like if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); if (lowerToken.Equals("as")) { asLike = ParsedAsLike.As; } else if (lowerToken.Equals("like")) { asLike = ParsedAsLike.Like; } if (asLike != ParsedAsLike.None) { state = 11; } break; case 11: // define variable : match a primitive type or a field in db if (!(token is TokenWord)) { break; } tempPrimitiveType = token.Value; state = 12; break; case 12: // define variable : match a view-as (or extent) AddTokenToStringBuilder(left, token); if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); if (lowerToken.Equals("view-as")) { state = 13; } if (lowerToken.Equals("extent")) { extent = GetExtentNumber(2); } break; case 13: // define variable : match a view-as AddTokenToStringBuilder(left, token); if (!(token is TokenWord)) { break; } viewAs = token.Value; state = 99; break; case 20: // define temp-table if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); switch (lowerToken) { case "field": // matches FIELD state = 22; break; case "index": // matches INDEX state = 25; break; case "use-index": // matches USE-INDEX (after a like/like-sequential, we can have this keyword) state = 26; break; case "help": // a field has a help text: state = 27; break; case "initial": // a field has an initial value state = 29; break; case "format": // a field has a format state = 30; break; case "extent": // a field is extent: currentField.Extent = GetExtentNumber(2); break; default: // matches a LIKE table // ReSharper disable once ConditionIsAlwaysTrueOrFalse, resharper doesn't get this one if ((lowerToken.Equals("like") || lowerToken.Equals("like-sequential")) && !matchedLikeTable) { state = 21; } // After a USE-UNDEX and the index name, we can match a AS PRIMARY for the previously defined index if (lowerToken.Equals("primary") && useIndex.Length > 0) { useIndex.Append("!"); } break; } break; case 21: // define temp-table : match a LIKE table, get the table name in asLike // ReSharper disable once RedundantAssignment matchedLikeTable = true; if (!(token is TokenWord)) { break; } likeTable = token.Value.ToLower(); state = 20; break; case 22: // define temp-table : matches a FIELD name if (!(token is TokenWord)) { break; } currentField = new ParsedField(token.Value, "", "", 0, 0, "", "", ParsedAsLike.None); state = 23; break; case 23: // define temp-table : matches a FIELD AS or LIKE if (!(token is TokenWord)) { break; } currentField.AsLike = token.Value.EqualsCi("like") ? ParsedAsLike.Like : ParsedAsLike.As; state = 24; break; case 24: // define temp-table : match a primitive type or a field in db if (!(token is TokenWord)) { break; } currentField.TempPrimitiveType = token.Value; // push the field to the fields list fields.Add(currentField); state = 20; break; case 25: // define temp-table : match an index name if (!(token is TokenWord)) { break; } indexName = token.Value; state = 28; break; case 28: // define temp-table : match the definition of the index if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); if (lowerToken.Equals("unique")) { indexFlags = indexFlags | ParsedIndexFlag.Unique; } else if (lowerToken.Equals("primary")) { indexFlags = indexFlags | ParsedIndexFlag.Primary; } else if (lowerToken.Equals("word-index")) { indexFlags = indexFlags | ParsedIndexFlag.WordIndex; } else if (lowerToken.Equals("ascending")) { // match a sort order for a field indexSort = "+"; var lastField = indexFields.LastOrDefault(); if (lastField != null) { indexFields.RemoveAt(indexFields.Count - 1); indexFields.Add(lastField.Replace("-", "+")); } } else if (lowerToken.Equals("descending")) { // match a sort order for a field indexSort = "-"; var lastField = indexFields.LastOrDefault(); if (lastField != null) { indexFields.RemoveAt(indexFields.Count - 1); indexFields.Add(lastField.Replace("+", "-")); } } else if (lowerToken.Equals("index")) { // matching a new index if (!String.IsNullOrEmpty(indexName)) { indexList.Add(new ParsedIndex(indexName, indexFlags, indexFields.ToList())); } indexName = ""; indexFields.Clear(); indexFlags = ParsedIndexFlag.None; indexSort = "+"; state = 25; } else { // Otherwise, it's a field name indexFields.Add(token.Value + indexSort); } break; case 26: // define temp-table : match a USE-INDEX name if (!(token is TokenWord)) { break; } useIndex.Append(","); useIndex.Append(token.Value); state = 20; break; case 27: // define temp-table : match HELP for a field if (!(token is TokenString)) { break; } currentField.Description = GetTokenStrippedValue(token); state = 20; break; case 29: // define temp-table : match INITIAL for a field if (!(token is TokenWhiteSpace)) { currentField.InitialValue = GetTokenStrippedValue(token); state = 20; } break; case 30: // define temp-table : match FORMAT for a field if (!(token is TokenWhiteSpace)) { currentField.Format = GetTokenStrippedValue(token); state = 20; } break; case 80: // define parameter : match a temptable, table, dataset or buffer name if (!(token is TokenWord)) { break; } if (token.Value.ToLower().Equals("for")) { break; } name = token.Value; state++; break; case 81: // match the table/dataset name that the buffer or handle is FOR if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); if (lowerToken.Equals("for") || lowerToken.Equals("temp-table")) { break; } bufferFor = lowerToken; state = 99; break; case 99: // matching the rest of the define AddTokenToStringBuilder(left, token); break; } } while (MoveNext()); if (state <= 1) { return; } if (!string.IsNullOrEmpty(indexName)) { indexList.Add(new ParsedIndex(indexName, indexFlags, indexFields)); } if (isTempTable) { // TEMP-TABLE var newTable = new ParsedTable(name, defineToken, ParsedTableType.TT, null, null, name, null, likeTable, fields, indexList, new List <ParsedTrigger>(), useIndex.ToString(), false, false) { // = end position of the EOS of the statement EndPosition = token.EndPosition, Flags = flags }; AddParsedItem(newTable, defineToken.OwnerNumber); } else { // other DEFINE var newDefine = NewParsedDefined(name, flags, defineToken, token, asLike, left.ToString(), type, tempPrimitiveType, viewAs, bufferFor, extent); AddParsedItem(newDefine, defineToken.OwnerNumber); // case of a parameters, add it to the current scope (if procedure) var currentScope = GetCurrentBlock <ParsedScopeBlock>() as ParsedProcedure; if (type == ParseDefineType.Parameter && currentScope != null) { if (currentScope.Parameters == null) { currentScope.Parameters = new List <ParsedDefine>(); } currentScope.Parameters.Add(newDefine); } } }
/// <inheritdoc cref="TryParseInt(string, ref int, out int, int, bool)"/> public static bool TryParseInt(ref UString s, out int result, int radix = 10, ParseFlag flags = 0) { long resultL; bool ok = TryParseInt(ref s, out resultL, radix, flags); result = (int)resultL; return(ok && result == resultL); }
/// <summary> /// Parses a parameter definition (used in function, class method, class event) /// Returns a list of define parsed items representing the parameters of the function /// </summary> private List <ParsedDefine> GetParsedParameters(Token functionToken, StringBuilder parameters) { /* * ( parameter [ , parameter ] ... ) * * { INPUT | OUTPUT | INPUT-OUTPUT } * { parameter-name AS {primitive-type-name|[ CLASS ]object-type-name} | { LIKE field } | [ EXTENT [ constant ] ] | TABLE temp-table-name [ APPEND ] [ BIND ] [ BY-VALUE ] | TABLE-HANDLE temp-table-handle [ APPEND ] [ BIND ] [ BY-VALUE ] | DATASET dataset-name [ APPEND ] [ BIND ] [ BY-VALUE ] | DATASET-HANDLE dataset-handle [ APPEND ] [ BIND ] [ BY-VALUE ] | } | | BUFFER buffer-name FOR table-name[ PRESELECT ] */ // info the parameters string paramName = ""; ParseFlag flags = 0; ParsedAsLike paramAsLike = ParsedAsLike.None; string paramPrimitiveType = ""; string parameterFor = ""; var parametersList = new List <ParsedDefine>(); int state = 0; do { var token = PeekAt(1); // next token if (token is TokenEos) { break; } if (token is TokenSymbol && token.Value.Equals(")")) { state = 99; } if (token is TokenComment) { continue; } switch (state) { case 0: // matching parameters type if (!(token is TokenWord)) { break; } var lwToken = token.Value.ToLower(); switch (lwToken) { case "buffer": paramPrimitiveType = lwToken; state = 10; break; case "table": case "table-handle": case "dataset": case "dataset-handle": paramPrimitiveType = lwToken; state = 20; break; case "input": flags |= ParseFlag.Input; break; case "return": flags |= ParseFlag.Return; break; case "output": flags |= ParseFlag.Output; break; case "input-output": flags |= ParseFlag.InputOutput; break; default: paramName = token.Value; state = 2; break; } break; case 2: // matching parameters as or like if (!(token is TokenWord)) { break; } var lowerToken = token.Value.ToLower(); if (lowerToken.Equals("as")) { paramAsLike = ParsedAsLike.As; } else if (lowerToken.Equals("like")) { paramAsLike = ParsedAsLike.Like; } if (paramAsLike != ParsedAsLike.None) { state++; } break; case 3: // matching parameters primitive type or a field in db if (!(token is TokenWord)) { break; } paramPrimitiveType = token.Value; state = 99; break; case 10: // match a buffer name if (!(token is TokenWord)) { break; } paramName = token.Value; state++; break; case 11: // match the table/dataset name that the buffer is FOR if (!(token is TokenWord)) { break; } lowerToken = token.Value.ToLower(); if (lowerToken.Equals("for")) { break; } parameterFor = lowerToken; state = 99; break; case 20: // match a table/dataset name if (!(token is TokenWord)) { break; } paramName = token.Value; state = 99; break; case 99: // matching parameters "," that indicates a next param if (token is TokenWord && token.Value.EqualsCi("extent")) { flags |= ParseFlag.Extent; } else if (token is TokenSymbol && (token.Value.Equals(")") || token.Value.Equals(","))) { // create a variable for this function scope if (!string.IsNullOrEmpty(paramName)) { parametersList.Add(NewParsedDefined(paramName, flags, functionToken, token, paramAsLike, "", ParseDefineType.Parameter, paramPrimitiveType, "", parameterFor)); } paramName = ""; paramAsLike = ParsedAsLike.None; paramPrimitiveType = ""; parameterFor = ""; flags = 0; if (token.Value.Equals(",")) { state = 0; } else { return(parametersList); } } break; } AddTokenToStringBuilder(parameters, token); } while (MoveNext()); return(parametersList); }
/// <summary> /// Sort the given list and group similar consecutive items into sub groups /// </summary> private List <CodeItem> SortAndGroupConsecutiveItems(List <CodeItem> list) { var outList = new List <CodeItem>(); // apply custom sorting list.Sort(CodeExplorerSortingClass <CodeItem> .GetInstance(Config.Instance.CodeExplorerSortingType)); var iItem = 0; while (iItem < list.Count) { var item = list[iItem]; if (item.Children != null) { item.Children = SortAndGroupConsecutiveItems(item.Children.Cast <CodeItem>().ToList()).Cast <FilteredTypeTreeListItem>().ToList(); } // For each duplicated item (same Icon and same displayText), we create a new branch var iIdentical = iItem + 1; ParseFlag flags = 0; // while we match identical items while (iIdentical < list.Count && list[iItem].Type == list[iIdentical].Type && list[iItem].DisplayText.EqualsCi(list[iIdentical].DisplayText)) { flags = flags | list[iIdentical].Flags; iIdentical++; } // if we found identical item if (iIdentical > iItem + 1) { // we create a branch for them var group = new BranchCodeItem { DisplayText = list[iItem].DisplayText, Type = list[iItem].Type, IsExpanded = false, // by default, the group are NOT expanded SubText = "x" + (iIdentical - iItem), Flags = flags, Children = new List <FilteredTypeTreeListItem>() }; outList.Add(group); // add child items to the newly created group branch for (int i = iItem; i < iIdentical; i++) { group.Children.Add(list[i]); } iItem += (iIdentical - iItem); continue; } // single item, add it normally outList.Add(item); iItem++; } return(outList); }
/// <summary>Low-level method that identifies the parts of a float literal /// of arbitrary base (typically base 2, 10, or 16) with no prefix or /// suffix, such as <c>2.Cp0</c> (which means 2.75 in base 16).</summary> /// <param name="radix">Base of the number to parse; must be between 2 /// and 36.</param> /// <param name="mantissa">Integer magnitude of the number.</param> /// <param name="exponentBase2">Base-2 exponent to apply, as specified by /// the 'p' suffix, or 0 if there is no 'p' suffix..</param> /// <param name="exponentBase10">Base-10 exponent to apply, as specified by /// the 'e' suffix, or 0 if there is no 'e' suffix..</param> /// <param name="exponentBaseR">Base-radix exponent to apply. This number /// is based on the front part of the number only (not including the 'p' or /// 'e' suffix). Negative values represent digits after the decimal point, /// while positive numbers represent 64-bit overflow. For example, if the /// input is <c>12.3456</c> with <c>radix=10</c>, the output will be /// <c>mantissa=123456</c> and <c>exponentBaseR=-4</c>. If the input is /// <c>0123_4567_89AB_CDEF_1234.5678</c> with <c>radix=16</c>, the mantissa /// overflows, and the result is <c>mantissa = 0x1234_5678_9ABC_DEF1</c> /// with <c>exponentBaseR=3</c>.</param> /// <param name="numDigits">Set to the number of digits in the number, not /// including the exponent part.</param> /// <param name="flags">Alters parsing behavior, see <see cref="ParseFlags"/>.</param> /// <remarks> /// The syntax required is /// <code> /// ( '+'|'-' )? /// ( Digits ('.' Digits?)? | '.' Digits ) /// ( ('p'|'P') ('-'|'+')? DecimalDigits+ )? /// ( ('e'|'E') ('-'|'+')? DecimalDigits+ )? /// </code> /// where Digits refers to one digits in the requested base, possibly /// including underscores or spaces if the flags allow it; similarly, /// DecimalDigits refers to base-10 digits and is also affected by the /// flags. /// <para/> /// Returns false if there was an error interpreting the input. /// <para/> /// To keep the parser relatively simple, it does not roll back in case of /// error the way the int parser does. For example, given the input "23p", /// the 'p' is consumed and causes the method to return false, even though /// the parse could have been successful if it had ignored the 'p'. /// </remarks> public static bool TryParseFloatParts(ref UString source, int radix, out bool negative, out ulong mantissa, out int exponentBaseR, out int exponentBase2, out int exponentBase10, out int numDigits, ParseFlag flags = 0) { flags |= G.ParseFlag.StopBeforeOverflow; if ((flags & ParseFlag.SkipSpacesInFront) != 0) { source = SkipSpaces(source); } negative = false; char c = source[0, '\0']; if (c == '-' || c == '+') { negative = c == '-'; source = source.Slice(1); } int numDigits2 = 0; mantissa = 0; exponentBase2 = 0; exponentBase10 = 0; exponentBaseR = 0; bool success = TryParseUInt(ref source, ref mantissa, radix, flags, out numDigits); if (!success) // possible overflow, extra digits remain if so { numDigits += (exponentBaseR = SkipExtraDigits(ref source, radix, flags)); } c = source[0, '\0']; if (c == '.' || (c == ',' && (flags & ParseFlag.AllowCommaDecimalPoint) != 0)) { source = source.Slice(1); if (exponentBaseR == 0) { success = TryParseUInt(ref source, ref mantissa, radix, flags, out numDigits2); if ((numDigits += numDigits2) == 0) { return(false); } exponentBaseR = -numDigits2; } else { Debug.Assert(!success); } if (!success) // possible overflow, extra digits remain if so { numDigits += SkipExtraDigits(ref source, radix, flags); } c = source[0, '\0']; } if (numDigits == 0) { return(false); } success = true; if (c == 'p' || c == 'P') { source = source.Slice(1); success = TryParseInt(ref source, out exponentBase2, 10, flags) && success; c = source[0, '\0']; } if (c == 'e' || c == 'E') { source = source.Slice(1); success = TryParseInt(ref source, out exponentBase10, 10, flags) && success; } return(success); }