/// <summary> /// Main block, definitions block... /// </summary> /// <param name="pars"></param> public void Visit(ParsedScopePreProcBlock pars) { if (pars.Flags.HasFlag(ParseFlag.FromInclude)) { return; } // only display special blocks on the explorer if (pars.Type == ParsedPreProcBlockType.Prototype || pars.Type == ParsedPreProcBlockType.Block) { return; } // convert to explorer type CodeExplorerIconType type; if (!Enum.TryParse(pars.Type.ToString(), out type)) { return; } // to code explorer CodeItem parentNode = type == CodeExplorerIconType.MainBlock ? null : GetExplorerListNode("AppBuilder blocks", CodeExplorerIconType.Block); CodeItem newNode = CodeItem.Factory.New(type); newNode.DisplayText = pars.Name; newNode.Flags = pars.Flags; newNode.SubText = null; newNode.DocumentOwner = pars.FilePath; newNode.GoToLine = pars.Line; newNode.GoToColumn = pars.Column; if (type != CodeExplorerIconType.MainBlock) { newNode.Type = type; } PushToCodeExplorer(parentNode, newNode); }
public void Visit(ParsedScopePreProcBlock pars) { AppendEverything(pars); }
/// <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); }