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> /// 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> /// 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; string extend = null; 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")) { flags |= ParseFlag.Extent; } // 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; } else if (flags.HasFlag(ParseFlag.Extent) && token is TokenNumber) { extend = token.Value; } 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, Extend = extend, 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, Extend = extend, 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.Extend.EqualsCi(proto.Extend) && 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); }