Doxygen
Loading...
Searching...
No Matches
pycode.l
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15/* This code is based on the work done by the MoxyPyDoxy team
16 * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada)
17 * in Spring 2005 as part of CS 179E: Compiler Design Project
18 * at the University of California, Riverside; the course was
19 * taught by Peter H. Froehlich <phf@acm.org>.
20 */
21
22%option never-interactive
23%option prefix="pycodeYY"
24%option reentrant
25%option extra-type="struct pycodeYY_state *"
26%option noyy_top_state
27%top{
28#include <stdint.h>
29// forward declare yyscan_t to improve type safety
30#define YY_TYPEDEF_YY_SCANNER_T
31struct yyguts_t;
32typedef yyguts_t *yyscan_t;
yyguts_t * yyscan_t
Definition code.l:24
33}
34
35%{
36
37#include <vector>
38#include <unordered_map>
39#include <string>
40#include <stack>
41
42#include <stdio.h>
43
44#include "pycode.h"
45#include "message.h"
46#include "scanner.h"
47#include "entry.h"
48#include "doxygen.h"
49#include "outputlist.h"
50#include "util.h"
51#include "membername.h"
52#include "searchindex.h"
53#include "config.h"
54#include "groupdef.h"
55#include "classlist.h"
56#include "filedef.h"
57#include "namespacedef.h"
58#include "tooltip.h"
59#include "scopedtypevariant.h"
60#include "symbolresolver.h"
61#include "debug.h"
62
63// Toggle for some debugging info
64//#define DBG_CTX(x) fprintf x
65#define DBG_CTX(x) do { } while(0)
66
67#define YY_NO_INPUT 1
68#define YY_NO_UNISTD_H 1
69
71{
72 std::unordered_map< std::string, ScopedTypeVariant > codeClassMap;
75
76 OutputCodeList * code = nullptr;
77 const char * inputString = nullptr; //!< the code fragment as text
78 int inputPosition = 0; //!< read offset during parsing
80 const char * currentFontClass = nullptr;
82 const Definition *searchCtx = nullptr;
84 int inputLines = 0; //!< number of line in the code fragment
85 int yyLineNr = 0; //!< current line number
86 std::unique_ptr<FileDef> exampleFileDef;
87 const FileDef * sourceFileDef = nullptr;
88 const Definition * currentDefinition = nullptr;
89 const MemberDef * currentMemberDef = nullptr;
95 int paramParens = 0;
96
97 bool insideBody = false;
100
103
109
110 std::stack<yy_size_t> indents; //!< Tracks indentation levels for scoping in python
111
112 QCString docBlock; //!< contents of all lines of a documentation block
118 std::vector<const Definition *> foldStack;
119};
120
121
122[[maybe_unused]] static const char *stateToString(int state);
123
124static void startCodeLine(yyscan_t yyscanner);
125static int countLines(yyscan_t yyscanner);
126static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor);
127static void addToSearchIndex(yyscan_t yyscanner, const QCString &text);
128static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,Definition *d);
129static void codify(yyscan_t yyscanner,const QCString &text);
130static void endCodeLine(yyscan_t yyscanner);
131static void nextCodeLine(yyscan_t yyscanner);
132static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text);
133static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment=false);
134static void endFontClass(yyscan_t yyscanner,bool specialComment=false);
135static void codifyLines(yyscan_t yyscanner,const QCString &text);
136static bool getLinkInScope(yyscan_t yyscanner, const QCString &c, const QCString &m,
137 const QCString &memberText, OutputCodeList &ol, const QCString &text);
138static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName,
139 OutputCodeList &ol, const QCString &text=QCString());
140static void generateClassOrGlobalLink(yyscan_t yyscanner, OutputCodeList &ol,
141 const QCString &clName, bool typeOnly=FALSE);
142static void generateFunctionLink(yyscan_t yyscanner, OutputCodeList &ol,
143 const QCString &funcName);
144static bool findMemberLink(yyscan_t yyscanner, OutputCodeList &ol,
145 const Definition *sym, const QCString &symName);
146static void findMemberLink(yyscan_t yyscanner, OutputCodeList &ol,
147 const QCString &symName);
148static void incrementFlowKeyWordCount(yyscan_t yyscanner);
149static void adjustScopesAndSuites(yyscan_t yyscanner,unsigned indentLength);
150static int yyread(yyscan_t yyscanner,char *buf,int max_size);
151static inline void pop_state(yyscan_t yyscanner);
152
153#if 0 // TODO: call me to store local variables and get better syntax highlighting, see code.l
154static void addVariable(yyscan_t yyscanner, QCString type, QCString name);
155#endif
156
157//-------------------------------------------------------------------
158
159#undef YY_INPUT
160#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size);
161
162// otherwise the filename would be the name of the converted file (*.cpp instead of *.l)
163static inline const char *getLexerFILE() {return __FILE__;}
164#include "doxygen_lex.h"
165
Represents the call context.
A abstract class representing of a compound symbol.
Definition classdef.h:104
The common base class of all entity definitions found in the sources.
Definition definition.h:76
A model of a file symbol.
Definition filedef.h:99
A model of a class/file/namespace member symbol.
Definition memberdef.h:48
Class representing a list of different code generators.
Definition outputlist.h:164
This is an alternative implementation of QCString.
Definition qcstring.h:101
Class that manages the tooltips for a source file.
Definition tooltip.h:26
static void addVariable(yyscan_t yyscanner, QCString type, QCString name)
Definition code.l:2178
std::vector< std::string > StringVector
Definition containers.h:33
static void generateClassOrGlobalLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &clName, bool typeOnly=FALSE)
Definition pycode.l:1232
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text)
Definition pycode.l:1055
static void endCodeLine(yyscan_t yyscanner)
Definition pycode.l:1024
static void nextCodeLine(yyscan_t yyscanner)
Definition pycode.l:1034
static void startCodeLine(yyscan_t yyscanner)
Definition pycode.l:948
static void codifyLines(yyscan_t yyscanner, const QCString &text)
Definition pycode.l:1133
static void incrementFlowKeyWordCount(yyscan_t yyscanner)
Definition pycode.l:1476
static void codify(yyscan_t yyscanner, const QCString &text)
Definition pycode.l:1016
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition pycode.l:771
static int countLines(yyscan_t yyscanner)
Definition pycode.l:823
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition pycode.l:862
static const char * stateToString(int state)
static bool findMemberLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *sym, const QCString &symName)
Definition pycode.l:1416
static void pop_state(yyscan_t yyscanner)
Definition pycode.l:1621
static bool getLinkInScope(yyscan_t yyscanner, const QCString &c, const QCString &m, const QCString &memberText, OutputCodeList &ol, const QCString &text)
Definition pycode.l:1162
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
Definition pycode.l:1097
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition pycode.l:1116
static void generateFunctionLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &funcName)
Definition pycode.l:1373
static void adjustScopesAndSuites(yyscan_t yyscanner, unsigned indentLength)
Definition pycode.l:792
static const ClassDef * stripClassName(yyscan_t yyscanner, const QCString &s, Definition *d)
Definition pycode.l:872
static const char * getLexerFILE()
Definition pycode.l:163
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition pycode.l:844
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString())
Definition pycode.l:1204
#define FALSE
Definition qcstring.h:34
Web server based search engine.
const FileDef * sourceFileDef
Definition pycode.l:87
const Definition * currentDefinition
Definition pycode.l:88
bool exampleBlock
Definition pycode.l:98
bool endComment
Definition pycode.l:113
VariableContext theVarContext
Definition pycode.l:114
int yyLineNr
current line number
Definition pycode.l:85
QCString docBlock
contents of all lines of a documentation block
Definition pycode.l:112
bool insideBody
Definition pycode.l:97
std::unordered_map< std::string, ScopedTypeVariant > codeClassMap
Definition pycode.l:72
std::stack< yy_size_t > indents
Tracks indentation levels for scoping in python.
Definition pycode.l:110
bool includeCodeFragment
Definition pycode.l:90
std::vector< const Definition * > foldStack
Definition pycode.l:118
bool insideCodeLine
Definition pycode.l:81
TooltipManager tooltipManager
Definition pycode.l:117
StringVector curClassBases
Definition pycode.l:74
QCString name
Definition pycode.l:102
int stringContext
Definition pycode.l:107
QCString realScope
Definition pycode.l:91
OutputCodeList * code
Definition pycode.l:76
bool searchingForBody
Definition pycode.l:93
int inputLines
number of line in the code fragment
Definition pycode.l:84
const Definition * searchCtx
Definition pycode.l:82
bool doubleStringIsDoc
Definition pycode.l:104
const MemberDef * currentMemberDef
Definition pycode.l:89
bool insideSpecialComment
Definition pycode.l:108
SymbolResolver symbolResolver
Definition pycode.l:116
const char * inputString
the code fragment as text
Definition pycode.l:77
QCString exampleName
Definition pycode.l:99
QCString classScope
Definition pycode.l:94
QCString type
Definition pycode.l:101
bool collectXRefs
Definition pycode.l:83
bool noSuiteFound
Definition pycode.l:106
std::unique_ptr< FileDef > exampleFileDef
Definition pycode.l:86
CallContext theCallContext
Definition pycode.l:115
QCString fileName
Definition pycode.l:79
int paramParens
Definition pycode.l:95
bool doubleQuote
Definition pycode.l:105
QCString curClassName
Definition pycode.l:73
int bodyCurlyCount
Definition pycode.l:92
int inputPosition
read offset during parsing
Definition pycode.l:78
const char * currentFontClass
Definition pycode.l:80
A bunch of utility functions.
166%}
167
168
169BB [ \t]+
170B [ \t]*
171NEWLINE \n
172
173DIGIT [0-9]
174LETTER [A-Za-z\x80-\xFF]
175NONEMPTY [A-Za-z0-9_\x80-\xFF]
176EXPCHAR [#(){}\‍[\‍],:.%/\\=`*~|&<>!;+-]
177PARAMNONEMPTY [^ \t\n():]
178IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*
179SCOPE {IDENTIFIER}("."{IDENTIFIER})*
180CALLANY "("[^)\n]*")"
181
182POUNDCOMMENT "##"
183
184TRISINGLEQUOTE "'''"
185TRIDOUBLEQUOTE "\"\"\""
186LONGSTRINGCHAR [^\\"']
187ESCAPESEQ ("\\")(.)
188LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ})
189SMALLQUOTE ("\"\""|"\""|"'"|"''")
190LONGSTRINGBLOCK ({LONGSTRINGITEM}|{SMALLQUOTE})
191
192STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
193KEYWORD ("lambda"|"import"|"class"|"assert"|"with"|"as"|"from"|"global"|"async"|"def"|"True"|"False")
194FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
195
196%option noyywrap
197%option stack
198
199%x Body
200
201%x FunctionDec
202%x FunctionParams
203
204%x ClassDec
205%x ClassInheritance
206
207%x Suite
208%x SuiteCaptureIndent
209%x SuiteStart
210%x SuiteMaintain
211
212%x SingleQuoteString
213%x DoubleQuoteString
214%x TripleString
215
216%x DocBlock
218
219<Body,Suite>{
220 "def"{BB} {
221 startFontClass(yyscanner,"keyword");
222 codify(yyscanner,yytext);
223 endFontClass(yyscanner);
224 BEGIN( FunctionDec );
225 }
static void startFontClass(yyscan_t yyscanner, const char *s, bool specialComment=false)
Definition code.l:3487
static void endFontClass(yyscan_t yyscanner, bool specialComment=false)
Definition code.l:3472
226 "async"{BB}"def"{BB} {
227 startFontClass(yyscanner,"keyword");
228 codify(yyscanner,yytext);
229 endFontClass(yyscanner);
230 BEGIN( FunctionDec );
231 }
232
233 "class"{BB} {
234 startFontClass(yyscanner,"keyword");
235 codify(yyscanner,yytext);
236 endFontClass(yyscanner);
237 BEGIN( ClassDec );
238 }
239 "None" {
240 startFontClass(yyscanner,"keywordtype");
241 codify(yyscanner,yytext);
242 endFontClass(yyscanner);
243 }
244 "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" {
245 codify(yyscanner,"self.");
246 findMemberLink(yyscanner,*yyextra->code,&yytext[5]);
247 }
248 "self."{IDENTIFIER}/"(" {
249 codify(yyscanner,"self.");
250 findMemberLink(yyscanner,*yyextra->code,&yytext[5]);
251 }
252 "self."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} {
253 codify(yyscanner,"self.");
254 findMemberLink(yyscanner,*yyextra->code,&yytext[5]);
255 }
256 "self."{IDENTIFIER} {
257 codify(yyscanner,"self.");
258 findMemberLink(yyscanner,*yyextra->code,&yytext[5]);
259 }
260 "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER}"(" {
261 codify(yyscanner,"cls.");
262 findMemberLink(yyscanner,*yyextra->code,&yytext[4]);
263 }
264 "cls."{IDENTIFIER}/"(" {
265 codify(yyscanner,"cls.");
266 findMemberLink(yyscanner,*yyextra->code,&yytext[4]);
267 }
268 "cls."{IDENTIFIER}/"."({IDENTIFIER}".")*{IDENTIFIER} {
269 codify(yyscanner,"cls.");
270 findMemberLink(yyscanner,*yyextra->code,&yytext[4]);
271 }
272 "cls."{IDENTIFIER} {
273 codify(yyscanner,"cls.");
274 findMemberLink(yyscanner,*yyextra->code,&yytext[4]);
275 }
276 "@"{SCOPE}{CALLANY}? { // decorator
277 startFontClass(yyscanner,"preprocessor");
278 codify(yyscanner,yytext);
279 endFontClass(yyscanner);
280 }
281}
282
283<ClassDec>{IDENTIFIER} {
284 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
285 // codify(yyscanner,yytext);
286 yyextra->curClassName = yytext;
287 yyextra->curClassBases.clear();
288 BEGIN( ClassInheritance );
289 }
static void generateClassOrGlobalLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &clName, bool typeOnly=FALSE, bool varOnly=FALSE)
Definition code.l:2907
290
291<ClassInheritance>{
292 ({BB}|[(,)]) {
293 codify(yyscanner,yytext);
294 }
295
296 ({IDENTIFIER}".")*{IDENTIFIER} {
297 // The parser
298 // is assuming
299 // that ALL identifiers
300 // in this state
301 // are base classes;
302 // it doesn't check to see
303 // that the first parenthesis
304 // has been seen.
305
306 // This is bad - it should
307 // probably be more strict
308 // about what to accept.
309
310 yyextra->curClassBases.emplace_back(yytext);
311 yyextra->insideBody = true;
312 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
313 yyextra->insideBody = false;
314 // codify(yyscanner,yytext);
315 }
316
317 ":" {
318 codify(yyscanner,yytext);
319
320 // Assume this will
321 // be a one-line suite;
322 // found counter-example
323 // in SuiteStart.
324
325 // Push a class scope
326 ScopedTypeVariant var(yyextra->curClassName);
327 for (const auto &s : yyextra->curClassBases)
328 {
329 const ClassDef *baseDefToAdd = nullptr;
330 // find class in the local scope
331 auto it = yyextra->codeClassMap.find(s);
332 if (it != yyextra->codeClassMap.end())
333 {
334 baseDefToAdd = toClassDef(it->second.globalDef());
335 }
336 // Try to find class in global scope
337 if (baseDefToAdd==nullptr)
338 {
339 baseDefToAdd=yyextra->symbolResolver.resolveClass(yyextra->currentDefinition,s,true);
340 }
341
342 if (baseDefToAdd && baseDefToAdd->name()!=yyextra->curClassName)
343 {
344 var.localDef()->insertBaseClass(baseDefToAdd->name());
345 }
346 }
347 yyextra->codeClassMap.emplace(yyextra->curClassName.str(),std::move(var));
348
349 // Reset class-parsing variables.
350 yyextra->curClassName.clear();
351 yyextra->curClassBases.clear();
352
353 yyextra->noSuiteFound = TRUE;
354 BEGIN( SuiteStart );
355 }
virtual const QCString & name() const =0
ClassDef * toClassDef(Definition *d)
#define TRUE
Definition qcstring.h:37
356}
357
358
359<FunctionDec>{
360 {IDENTIFIER} {
361 generateFunctionLink(yyscanner,*yyextra->code,yytext);
362 }
static void generateFunctionLink(yyscan_t yyscanner, OutputCodeList &ol, const QCString &funcName)
Definition code.l:3344
363
364 {B}"(" {
365 codify(yyscanner,yytext);
366 BEGIN( FunctionParams );
367 }
368}
369
370<FunctionParams>{
371 ({BB}|",") {
372 // Parses delimiters
373 codify(yyscanner,yytext);
374 }
375
376 ({IDENTIFIER}|{PARAMNONEMPTY}+) {
377 codify(yyscanner,yytext);
378 }
379
380 ")" {
381 codify(yyscanner,yytext);
382 }
383
384 "\n" {
385 codifyLines(yyscanner,yytext);
386 }
static void codifyLines(yyscan_t yyscanner, const QCString &text)
Definition code.l:2505
387
388 ":" {
389 codify(yyscanner,yytext);
390
391 // Assume this will
392 // be a one-line suite;
393 // found counter-example
394 // in SuiteStart.
395 yyextra->noSuiteFound = TRUE;
396 BEGIN( SuiteStart );
397 }
398}
399
400<Body,Suite>{
401
402 {KEYWORD} {
403 // Position-sensitive rules!
404 // Must come AFTER keyword-triggered rules
405 // Must come BEFORE identifier NONEMPTY-like rules
406 // to syntax highlight.
407
408 startFontClass(yyscanner,"keyword");
409 codify(yyscanner,yytext);
410 endFontClass(yyscanner);
411 }
412
413 {FLOWKW} {
414 incrementFlowKeyWordCount(yyscanner);
415 startFontClass(yyscanner,"keywordflow");
416 codify(yyscanner,yytext);
417 endFontClass(yyscanner);
418 }
static void incrementFlowKeyWordCount(yyscan_t yyscanner)
Definition code.l:2532
419 ({IDENTIFIER}".")*{IDENTIFIER}/"(" {
420 yyextra->insideBody = true;
421 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext);
422 yyextra->insideBody = false;
423 }
424 ({IDENTIFIER}".")+{IDENTIFIER} {
425 yyextra->insideBody = true;
426 generateClassOrGlobalLink(yyscanner,*yyextra->code,yytext,TRUE);
427 yyextra->insideBody = false;
428 }
429 {IDENTIFIER} { codify(yyscanner,yytext); }
430
431}
432
433
434
435<SuiteStart>{
436
437 {BB} {
438 codify(yyscanner,yytext);
439 }
440 "pass" {
441 startFontClass(yyscanner,"keyword");
442 codifyLines(yyscanner,yytext);
443 endFontClass(yyscanner);
444 BEGIN(Body);
445 }
446 {KEYWORD} {
447 startFontClass(yyscanner,"keyword");
448 codifyLines(yyscanner,yytext);
449 endFontClass(yyscanner);
450
451 // No indentation necessary
452 yyextra->noSuiteFound = FALSE;
453 }
454
455 {FLOWKW} {
456 incrementFlowKeyWordCount(yyscanner);
457 startFontClass(yyscanner,"keywordflow");
458 codifyLines(yyscanner,yytext);
459 endFontClass(yyscanner);
460
461 // No indentation necessary
462 yyextra->noSuiteFound = FALSE;
463 }
464 {IDENTIFIER} {
465 codify(yyscanner,yytext);
466 }
467
468
469 {POUNDCOMMENT} {
470 if (YY_START==SingleQuoteString ||
471 YY_START==DoubleQuoteString ||
472 YY_START==TripleString
473 )
474 {
475 REJECT;
476 }
477 yy_push_state(YY_START,yyscanner);
478 BEGIN(DocBlock);
479 yyextra->docBlock=yytext;
480 }
481
482 {NEWLINE} {
483 codifyLines(yyscanner,yytext);
484 if ( yyextra->noSuiteFound )
485 {
486 // printf("New suite to capture! [%d]\n", yyextra->yyLineNr);
487 BEGIN ( SuiteCaptureIndent );
488 }
489 }
490}
491
492<SuiteCaptureIndent>{
493 "\n"|({BB}"\n") {
494 // Blankline - ignore, keep looking for indentation.
495 codifyLines(yyscanner,yytext);
496 }
497
498 {BB} {
499 // This state lasts momentarily,
500 // to check the indentation
501 // level that is about to be
502 // used.
503 codifyLines(yyscanner,yytext);
504 yyextra->indents.push(yyleng);
505 // printf("Captured indent of %d [line %d]\n", yyleng, yyextra->yyLineNr);
506 BEGIN( Suite );
507 }
508}
509
510<SuiteMaintain>{
511
512 {BB}/({NONEMPTY}|{EXPCHAR}) {
513 // This implements poor
514 // indentation-tracking;
515 // should be improved.
516 // (translate tabs to space, etc)
517 codifyLines(yyscanner,yytext);
518 adjustScopesAndSuites(yyscanner,static_cast<int>(yyleng));
519 }
520
521 "\n"|({BB}"\n") {
522 // If this ever succeeds,
523 // it means that this is
524 // a blank line, and
525 // can be ignored.
526 codifyLines(yyscanner,yytext);
527 }
528
529 ""/({NONEMPTY}|{EXPCHAR}) {
530 // Default rule; matches
531 // the empty string, assuming
532 // real text starts here.
533 // Just go straight to Body.
534 adjustScopesAndSuites(yyscanner,0);
535 }
536}
537
538
539<Suite>{NEWLINE} {
540 codifyLines(yyscanner,yytext);
541 BEGIN( SuiteMaintain );
542 }
543<Body>{IDENTIFIER} {
544 codify(yyscanner,yytext);
545 }
546<Body>{NEWLINE} {
547 codifyLines(yyscanner,yytext);
548 }
549
550<SingleQuoteString>{ // Single quoted string like 'That\'s a """nice""" string!'
551 \\{B}\n { // line continuation
552 codifyLines(yyscanner,yytext);
553 }
554 \\. { // escaped char
555 codify(yyscanner,yytext);
556 }
557 {STRINGPREFIX}?{TRIDOUBLEQUOTE} { // triple double quotes
558 codify(yyscanner,yytext);
559 }
560 "'" { // end of the string
561 codify(yyscanner,yytext);
562 endFontClass(yyscanner);
563 BEGIN(yyextra->stringContext);
564 }
565 [^"'\n\\‍]+ { // normal chars
566 codify(yyscanner,yytext);
567 }
568 . { // normal char
569 codify(yyscanner,yytext);
570 }
571}
572
573<DoubleQuoteString>{ // Double quoted string like "That's \"a '''nice'''\" string!"
574 \\{B}\n { // line continuation
575 codifyLines(yyscanner,yytext);
576 }
577 \\. { // escaped char
578 codify(yyscanner,yytext);
579 }
580 {STRINGPREFIX}?{TRISINGLEQUOTE} { // triple single quotes
581 codify(yyscanner,yytext);
582 }
583 "\"" { // end of the string
584 codify(yyscanner,yytext);
585 endFontClass(yyscanner);
586 BEGIN(yyextra->stringContext);
587 }
588 [^"'\n\\‍]+ { // normal chars
589 codify(yyscanner,yytext);
590 }
591 . { // normal char
592 codify(yyscanner,yytext);
593 }
594}
595
596<TripleString>{
597 {TRIDOUBLEQUOTE} |
598 {TRISINGLEQUOTE} {
599 codify(yyscanner,yytext);
600 if (yyextra->doubleQuote==(yytext[0]=='"'))
601 {
602 endFontClass(yyscanner);
603 BEGIN(yyextra->stringContext);
604 }
605 }
606 {LONGSTRINGBLOCK} {
607 codifyLines(yyscanner,yytext);
608 }
609 \n {
610 codifyLines(yyscanner,yytext);
611 }
612 [ \t]+ {
613 codify(yyscanner,yytext);
614 }
615 . {
616 codify(yyscanner,yytext);
617 }
618}
619
620
621<*>{STRINGPREFIX}?{TRISINGLEQUOTE} {
622 if (YY_START==SingleQuoteString) REJECT;
623 startFontClass(yyscanner,"stringliteral");
624 yyextra->stringContext=YY_START;
625 yyextra->doubleQuote=yytext[yyleng-1]=='"';
626 codify(yyscanner,yytext);
627 BEGIN(TripleString);
628 }
629<*>{STRINGPREFIX}?{TRIDOUBLEQUOTE} {
630 if (YY_START==DoubleQuoteString) REJECT;
631 startFontClass(yyscanner,"stringliteral");
632 yyextra->stringContext=YY_START;
633 yyextra->doubleQuote=yytext[yyleng-1]=='"';
634 codify(yyscanner,yytext);
635 BEGIN(TripleString);
636 }
637<*>{STRINGPREFIX}?"'" { // single quoted string
638 if (YY_START==SingleQuoteString ||
639 YY_START==DoubleQuoteString ||
640 YY_START==TripleString)
641 {
642 REJECT;
643 }
644 startFontClass(yyscanner,"stringliteral");
645 yyextra->stringContext=YY_START;
646 codify(yyscanner,yytext);
647 BEGIN(SingleQuoteString);
648 }
649<*>{STRINGPREFIX}?"\"" { // double quoted string
650 if (YY_START==SingleQuoteString ||
651 YY_START==DoubleQuoteString ||
652 YY_START==TripleString)
653 {
654 REJECT;
655 }
656 startFontClass(yyscanner,"stringliteral");
657 yyextra->stringContext=YY_START;
658 codify(yyscanner,yytext);
659 BEGIN(DoubleQuoteString);
660 }
661<DocBlock>.* { // contents of current comment line
662 yyextra->docBlock+=yytext;
663 }
664<DocBlock>"\n"{B}("#") { // comment block (next line is also comment line)
665 yyextra->docBlock+=yytext;
666 }
667<DocBlock>{NEWLINE} { // comment block ends at the end of this line
668 // remove special comment (default config)
669 startFontClass(yyscanner,"comment",true);
670 codifyLines(yyscanner,yyextra->docBlock);
671 endFontClass(yyscanner,true);
672 unput(*yytext);
673 pop_state(yyscanner);
674 }
static void pop_state(yyscan_t yyscanner)
675<*>{POUNDCOMMENT}.* {
676 if (YY_START==SingleQuoteString ||
677 YY_START==DoubleQuoteString ||
678 YY_START==TripleString)
679 {
680 REJECT;
681 }
682 yy_push_state(YY_START,yyscanner);
683 BEGIN(DocBlock);
684 yyextra->docBlock=yytext;
685 }
686<*>"#".* { // normal comment
687 if (YY_START==SingleQuoteString ||
688 YY_START==DoubleQuoteString ||
689 YY_START==TripleString)
690 {
691 REJECT;
692 }
693 startFontClass(yyscanner,"comment");
694 codifyLines(yyscanner,yytext);
695 endFontClass(yyscanner);
696 }
697<*>{NEWLINE} {
698 if (yyextra->endComment)
699 {
700 yyextra->endComment=FALSE;
701 }
702 else
703 {
704 codifyLines(yyscanner,yytext);
705 }
706 //printf("[pycode] %d NEWLINE [line %d] no match\n",
707 // YY_START, yyextra->yyLineNr);
708
709 BEGIN(Body);
710 }
711
712<*>[ \t]+ {
713 codify(yyscanner,yytext);
714 BEGIN(Body);
715 }
716<*>. {
717 codify(yyscanner,yytext);
718 // printf("[pycode] '%s' [ state %d ] [line %d] no match\n",
719 // yytext, YY_START, yyextra->yyLineNr);
720
721 BEGIN(Body);
722 }
723
724<*><<EOF>> {
725 if (YY_START==DocBlock)
726 {
727 startFontClass(yyscanner,"comment",true);
728 codifyLines(yyscanner,yyextra->docBlock);
729 endFontClass(yyscanner,true);
730 }
731 yyterminate();
732 }
#define yyterminate()
733%%
734
735/*@ ----------------------------------------------------------------------------
736 */
737
738#if 0 // TODO: call me to store local variables and get better syntax highlighting, see code.l
739static void addVariable(yyscan_t yyscanner, QCString type, QCString name)
740{
741 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
742 //printf("PyVariableContext::addVariable(%s,%s)\n",qPrint(type),qPrint(name));
743 QCString ltype = type.simplifyWhiteSpace();
744 QCString lname = name.simplifyWhiteSpace();
745
746 auto it = yyextra->codeClassMap.find(ltype.str());
747 if (it!=yyextra->codeClassMap.end())
748 {
749 yyextra->theVarContext.addVariable(lname,std::move(it->second));
750 }
751 else
752 {
753 const ClassDef *varType = getResolvedClass(yyextra->currentDefinition,yyextra->sourceFileDef,ltype); // look for global class definitions
754 if (varType)
755 {
756 yyextra->theVarContext.addVariable(lname,ScopedTypeVariant(varType));
757 }
758 else
759 {
760 if (!yyextra->theVarContext.atGlobalScope()) // for local variable add a dummy entry to avoid linking to a global that is shadowed.
761 {
762 yyextra->theVarContext.addVariable(lname.str(),ScopedTypeVariant());
763 }
764 }
765 }
766}
767#endif
768
769//-------------------------------------------------------------------------------
770
771static int yyread(yyscan_t yyscanner, char *buf,int max_size)
772{
773 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
774 int inputPosition = yyextra->inputPosition;
775 const char *s = yyextra->inputString + inputPosition;
776 int c=0;
777 while( c < max_size && *s )
778 {
779 *buf++ = *s++;
780 c++;
781 }
782 yyextra->inputPosition += c;
783 return c;
784}
785
786//-------------------------------------------------------------------------------
787
788/*!
789 Examines current stack of white-space indentations;
790 re-syncs the parser with the correct scope.
791*/
792static void adjustScopesAndSuites(yyscan_t yyscanner,unsigned indentLength)
793{
794 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
795 // States to pop
796 if (!yyextra->indents.empty() && indentLength < yyextra->indents.top())
797 {
798 while (!yyextra->indents.empty() && indentLength < yyextra->indents.top())
799 {
800 // printf("Exited scope indent of [%d]\n", yyextra->indents.top());
801 yyextra->indents.pop(); // Pop the old suite's indentation
802
803 yyextra->currentMemberDef=nullptr;
804 if (yyextra->currentDefinition)
805 yyextra->currentDefinition=yyextra->currentDefinition->getOuterScope();
806 }
807 }
808
809 // Are there any remaining indentation levels for suites?
810 if (!yyextra->indents.empty())
811 {
812 BEGIN( Suite );
813 }
814 else
815 {
816 BEGIN( Body );
817 }
818}
819
820//-------------------------------------------------------------------------------
821
822/*! counts the number of lines in the input */
823static int countLines(yyscan_t yyscanner)
824{
825 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
826 const char *p=yyextra->inputString;
827 char c=0;
828 int count=1;
829 while ((c=*p))
830 {
831 p++;
832 if (c=='\n') count++;
833 }
834 if (p>yyextra->inputString && *(p-1)!='\n')
835 { // last line does not end with a \n, so we add an extra
836 // line and explicitly terminate the line after parsing.
837 count++;
838 }
839 return count;
840}
841
842//-------------------------------------------------------------------------------
843
844static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
845{
846 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
847 if (Doxygen::searchIndex.enabled())
848 {
849 if (yyextra->searchCtx)
850 {
851 Doxygen::searchIndex.setCurrentDoc(yyextra->searchCtx,yyextra->searchCtx->anchor(),FALSE);
852 }
853 else
854 {
855 Doxygen::searchIndex.setCurrentDoc(yyextra->sourceFileDef,anchor,TRUE);
856 }
857 }
858}
859
860//-------------------------------------------------------------------------------
861
862static void addToSearchIndex(yyscan_t /* yyscanner */, const QCString &text)
863{
864 if (Doxygen::searchIndex.enabled())
865 {
866 Doxygen::searchIndex.addWord(text,FALSE);
867 }
868}
869
870//-------------------------------------------------------------------------------
871
872static const ClassDef *stripClassName(yyscan_t yyscanner,const QCString &s,Definition *d)
873{
874 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
875 int pos=0;
876 QCString type = s;
877 QCString className;
878 QCString templSpec;
879 while (extractClassNameFromType(type,pos,className,templSpec)!=-1)
880 {
881 QCString clName=className+templSpec;
882 const ClassDef *cd=nullptr;
883 if (!yyextra->classScope.isEmpty())
884 {
885 cd=yyextra->symbolResolver.resolveClass(d,yyextra->classScope+"::"+clName,true);
886 }
887 if (cd==nullptr)
888 {
889 cd=yyextra->symbolResolver.resolveClass(d,clName,true);
890 }
891 if (cd)
892 {
893 return cd;
894 }
895 }
896
897 return nullptr;
898}
899
900//-------------------------------------------------------------------------------
901static void codeFolding(yyscan_t yyscanner,const Definition *d)
902{
903 if (Config_getBool(HTML_CODE_FOLDING))
904 {
905 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
906 while (!yyextra->foldStack.empty())
907 {
908 const Definition *dd = yyextra->foldStack.back();
909 if (dd->getEndBodyLine()+1==yyextra->yyLineNr) // +1 to close the section after the end of the body
910 {
911 yyextra->code->endFold();
912 //printf("%d: end codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(dd->name()),dd->getStartDefLine(),dd->getEndBodyLine());
913 yyextra->foldStack.pop_back();
914 }
915 else
916 {
917 break;
918 }
919 }
920 if (d)
921 {
922 int startLine = d->getStartDefLine();
923 int endLine = d->getEndBodyLine();
924 if (endLine!=-1 && startLine!=endLine &&
925 // since the end of a section is closed after the last line, we need to avoid starting a
926 // new section if the previous section ends at the same line, i.e. something like
927 // struct X {
928 // ...
929 // }; struct S { <- start of S and end of X at the same line
930 // ...
931 // };
932 (yyextra->foldStack.empty() || yyextra->foldStack.back()->getEndBodyLine()!=startLine))
933 {
934 //printf("%d: start codeFolding for %s [%d..%d]\n",yyextra->yyLineNr,qPrint(d->name()),d->getStartDefLine(),d->getEndBodyLine());
935 yyextra->code->startFold(yyextra->yyLineNr,"", "");
936 yyextra->foldStack.push_back(d);
937 }
938 }
939 }
940}
941
942//-------------------------------------------------------------------------------
943
944/*! start a new line of code, inserting a line number if yyextra->sourceFileDef
945 * is TRUE. If a definition starts at the current line, then the line
946 * number is linked to the documentation of that definition.
947 */
948static void startCodeLine(yyscan_t yyscanner)
949{
950 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
951 //if (yyextra->currentFontClass) { yyextra->code->endFontClass(yyscanner); }
952 if (yyextra->sourceFileDef)
953 {
954 //QCString lineNumber,lineAnchor;
955 //lineNumber.sprintf("%05d",yyextra->yyLineNr);
956 //lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
957
958 const Definition *d = yyextra->sourceFileDef->getSourceDefinition(yyextra->yyLineNr);
959 //printf("startCodeLine %d d=%p\n",yyextra->yyLineNr,d);
960 //yyextra->code->startLineNumber();
961
962 if (!yyextra->includeCodeFragment && d && d->isLinkableInProject())
963 {
964 yyextra->currentDefinition = d;
965 yyextra->currentMemberDef = yyextra->sourceFileDef->getSourceMember(yyextra->yyLineNr);
966 yyextra->insideBody = false;
967 yyextra->endComment = FALSE;
968 yyextra->searchingForBody = TRUE;
969 yyextra->realScope = d->name();
970 yyextra->classScope = d->name();
971 //printf("Real scope: '%s'\n",qPrint(yyextra->realScope));
972 yyextra->bodyCurlyCount = 0;
973 QCString lineAnchor;
974 lineAnchor.sprintf("l%05d",yyextra->yyLineNr);
975 if (yyextra->currentMemberDef)
976 {
977 codeFolding(yyscanner,yyextra->currentMemberDef);
978 yyextra->code->writeLineNumber(yyextra->currentMemberDef->getReference(),
979 yyextra->currentMemberDef->getOutputFileBase(),
980 yyextra->currentMemberDef->anchor(),yyextra->yyLineNr,
981 !yyextra->includeCodeFragment);
982 setCurrentDoc(yyscanner,lineAnchor);
983 }
984 else if (d->isLinkableInProject())
985 {
986 codeFolding(yyscanner,d);
987 yyextra->code->writeLineNumber(d->getReference(),
989 QCString(),yyextra->yyLineNr,
990 !yyextra->includeCodeFragment);
991 setCurrentDoc(yyscanner,lineAnchor);
992 }
993 else
994 {
995 codeFolding(yyscanner,nullptr);
996 }
997 }
998 else
999 {
1000 codeFolding(yyscanner,nullptr);
1001 yyextra->code->writeLineNumber(QCString(),QCString(),QCString(),yyextra->yyLineNr,
1002 !yyextra->includeCodeFragment);
1003 }
1004 }
1005 yyextra->code->startCodeLine(yyextra->yyLineNr);
1006 yyextra->insideCodeLine=true;
1007
1008 if (yyextra->currentFontClass)
1009 {
1010 yyextra->code->startFontClass(yyextra->currentFontClass);
1011 }
1012}
1013
1014//-------------------------------------------------------------------------------
1015
1016static void codify(yyscan_t yyscanner,const QCString &text)
1017{
1018 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1019 yyextra->code->codify(text);
1020}
1021
1022//-------------------------------------------------------------------------------
1023
1024static void endCodeLine(yyscan_t yyscanner)
1025{
1026 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1027 endFontClass(yyscanner);
1028 yyextra->code->endCodeLine();
1029 yyextra->insideCodeLine=false;
1030}
1031
1032//-------------------------------------------------------------------------------
1033
1034static void nextCodeLine(yyscan_t yyscanner)
1035{
1036 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1037 const char *fc = yyextra->currentFontClass;
1038 if (yyextra->insideCodeLine)
1039 {
1040 endCodeLine(yyscanner);
1041 }
1042 if (yyextra->yyLineNr<yyextra->inputLines)
1043 {
1044 yyextra->currentFontClass = fc;
1045 startCodeLine(yyscanner);
1046 }
1047}
1048
1049//-------------------------------------------------------------------------------
1050
1051/*! writes a link to a fragment \a text that may span multiple lines, inserting
1052 * line numbers for each line. If \a text contains newlines, the link will be
1053 * split into multiple links with the same destination, one for each line.
1054 */
1055static void writeMultiLineCodeLink(yyscan_t yyscanner,
1056 OutputCodeList &ol,
1057 const Definition *d,
1058 const QCString &text)
1059{
1060 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1061 if (text.isEmpty()) return;
1062 bool sourceTooltips = Config_getBool(SOURCE_TOOLTIPS);
1063 yyextra->tooltipManager.addTooltip(d);
1064 QCString ref = d->getReference();
1065 QCString file = d->getOutputFileBase();
1066 QCString anchor = d->anchor();
1067 QCString tooltip;
1068 if (!sourceTooltips) // fall back to simple "title" tooltips
1069 {
1070 tooltip = d->briefDescriptionAsTooltip();
1071 }
1072 bool done=FALSE;
1073 const char *p=text.data();
1074 while (!done)
1075 {
1076 const char *sp=p;
1077 char c=0;
1078 while ((c=*p++) && c!='\n') { }
1079 if (c=='\n')
1080 {
1081 yyextra->yyLineNr++;
1082 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1083 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,QCString(sp,p-sp-1),tooltip);
1084 nextCodeLine(yyscanner);
1085 }
1086 else
1087 {
1088 //printf("writeCodeLink(%s,%s,%s,%s)\n",ref,file,anchor,sp);
1089 ol.writeCodeLink(d->codeSymbolType(),ref,file,anchor,sp,tooltip);
1090 done=TRUE;
1091 }
1092 }
1093}
1094
1095//-------------------------------------------------------------------------------
1096
1097static void startFontClass(yyscan_t yyscanner,const char *s,bool specialComment)
1098{
1099 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1100 if (specialComment)
1101 {
1102 yyextra->code->startSpecialComment();
1103 yyextra->insideSpecialComment = true;
1104 }
1105 // if font class is already set don't stop and start it.
1106 if (qstrcmp(yyextra->currentFontClass,s)!=0)
1107 {
1108 endFontClass(yyscanner);
1109 yyextra->code->startFontClass(s);
1110 yyextra->currentFontClass=s;
1111 }
1112}
1113
1114//-------------------------------------------------------------------------------
1115
1116static void endFontClass(yyscan_t yyscanner,bool specialComment)
1117{
1118 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1119 if (yyextra->currentFontClass)
1120 {
1121 yyextra->code->endFontClass();
1122 yyextra->currentFontClass=nullptr;
1123 }
1124 if (specialComment && yyextra->insideSpecialComment)
1125 {
1126 yyextra->code->endSpecialComment();
1127 yyextra->insideSpecialComment=false;
1128 }
1129}
1130
1131//-------------------------------------------------------------------------------
1132
1133static void codifyLines(yyscan_t yyscanner,const QCString &text)
1134{
1135 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1136 if (text.isEmpty()) return;
1137 //printf("codifyLines(%d,\"%s\")\n",yyextra->yyLineNr,text);
1138 const char *p=text.data(),*sp=p;
1139 char c=0;
1140 bool done=FALSE;
1141 while (!done)
1142 {
1143 sp=p;
1144 while ((c=*p++) && c!='\n') { }
1145 if (c=='\n')
1146 {
1147 yyextra->yyLineNr++;
1148 size_t l = static_cast<size_t>(p-sp-1);
1149 yyextra->code->codify(QCString(sp,l));
1150 nextCodeLine(yyscanner);
1151 }
1152 else
1153 {
1154 yyextra->code->codify(sp);
1155 done=TRUE;
1156 }
1157 }
1158}
1159
1160//-------------------------------------------------------------------------------
1161
1162static bool getLinkInScope(yyscan_t yyscanner,
1163 const QCString &c, // scope
1164 const QCString &m, // member
1165 const QCString &memberText, // exact text
1166 OutputCodeList &ol,
1167 const QCString &text
1168 )
1169{
1170 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1171 GetDefInput input(c,m,"()");
1172 input.currentFile = yyextra->sourceFileDef;
1173 input.insideCode = true;
1174 GetDefResult result = getDefs(input);
1175 //printf("Trying '%s'::'%s'\n",qPrint(c),qPrint(m));
1176 if (result.found && result.md && result.md->isLinkable())
1177 {
1178 const Definition *d = result.md->getOuterScope()==Doxygen::globalScope ?
1179 result.md->getBodyDef() : result.md->getOuterScope();
1180 //printf("Found! d=%s\n",d?qPrint(d->name()):"<none>");
1181 if (result.md->getGroupDef()) d = result.md->getGroupDef();
1182 if (d && d->isLinkable())
1183 {
1184 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,result.md->typeString(),result.md->getOuterScope())));
1185 //printf("yyextra->currentDefinition=%p yyextra->currentMemberDef=%p\n",
1186 // yyextra->currentDefinition,yyextra->currentMemberDef);
1187
1188 if (yyextra->currentDefinition && yyextra->currentMemberDef && yyextra->collectXRefs && yyextra->insideBody)
1189 {
1190 addDocCrossReference(yyextra->currentMemberDef,result.md);
1191 }
1192 //printf("d->getReference()='%s' d->getOutputBase()='%s' name='%s' member name='%s'\n",qPrint(d->getReference()),qPrint(d->getOutputFileBase()),qPrint(d->name()),qPrint(md->name()));
1193
1194 writeMultiLineCodeLink(yyscanner,ol,result.md, !text.isEmpty() ? text : memberText);
1195 addToSearchIndex(yyscanner,!text.isEmpty() ? text : memberText);
1196 return TRUE;
1197 }
1198 }
1199 return FALSE;
1200}
1201
1202//-------------------------------------------------------------------------------
1203
1204static bool getLink(yyscan_t yyscanner,
1205 const QCString &className,
1206 const QCString &memberName,
1207 OutputCodeList &ol,
1208 const QCString &text)
1209{
1210 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1211 QCString m=removeRedundantWhiteSpace(memberName);
1212 QCString c=className;
1213 if (!getLinkInScope(yyscanner,c,m,memberName,ol,text))
1214 {
1215 if (!yyextra->curClassName.isEmpty())
1216 {
1217 if (!c.isEmpty()) c.prepend("::");
1218 c.prepend(yyextra->curClassName);
1219 return getLinkInScope(yyscanner,c,m,memberName,ol,text);
1220 }
1221 return FALSE;
1222 }
1223 return TRUE;
1224}
1225
1226//-------------------------------------------------------------------------------
1227
1228/*
1229 For a given string in the source code,
1230 finds its class or global id and links to it.
1231*/
1233 OutputCodeList &ol,
1234 const QCString &clName,
1235 bool typeOnly)
1236{
1237 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1238 QCString className=clName;
1239
1240 // Don't do anything for empty text
1241 if (className.isEmpty()) return;
1242
1243 DBG_CTX((stderr,"generateClassOrGlobalLink(className=%s)\n",qPrint(className)));
1244
1245 const ScopedTypeVariant *lcd = nullptr;
1246 const ClassDef *cd=nullptr; // Class def that we may find
1247 const MemberDef *md=nullptr; // Member def that we may find
1248 //bool isLocal=FALSE;
1249
1250 if ((lcd=yyextra->theVarContext.findVariable(className))==nullptr) // not a local variable
1251 {
1252 const Definition *d = yyextra->currentDefinition;
1253 QCString scope = substitute(className,".","::");
1254
1255 cd = yyextra->symbolResolver.resolveClass(d,substitute(className,".","::"),true);
1256 md = yyextra->symbolResolver.getTypedef();
1257
1258 DBG_CTX((stderr,"d=%s yyextra->sourceFileDef=%s\n",
1259 d?qPrint(d->displayName()):"<null>",
1260 yyextra->currentDefinition?qPrint(yyextra->currentDefinition->displayName()):"<null>"));
1261 DBG_CTX((stderr,"is found as a type %s\n",cd?qPrint(cd->name()):"<null>"));
1262
1263 if (cd==nullptr && md==nullptr) // also see if it is variable or enum or enum value
1264 {
1265 const NamespaceDef *nd = getResolvedNamespace(scope);
1266 if (nd)
1267 {
1268 writeMultiLineCodeLink(yyscanner,ol,nd,clName);
1269 addToSearchIndex(yyscanner,className);
1270 return;
1271 }
1272 else if (getLink(yyscanner,yyextra->classScope,clName,ol,clName))
1273 {
1274 return;
1275 }
1276 }
1277 }
1278 else
1279 {
1280 if (!lcd->isDummy())
1281 {
1282 yyextra->theCallContext.setScope(*lcd);
1283 }
1284 //isLocal=TRUE;
1285 DBG_CTX((stderr,"is a local variable cd=%p!\n",cd));
1286 }
1287
1288 if (cd && cd->isLinkable()) // is it a linkable class
1289 {
1290 writeMultiLineCodeLink(yyscanner,ol,cd,clName);
1291 addToSearchIndex(yyscanner,className);
1292 if (md)
1293 {
1295 md->getBodyDef() : md->getOuterScope();
1296 if (md->getGroupDef()) d = md->getGroupDef();
1297 if (d && d->isLinkable() && md->isLinkable() &&
1298 yyextra->currentMemberDef && yyextra->collectXRefs && yyextra->insideBody)
1299 {
1300 addDocCrossReference(yyextra->currentMemberDef,md);
1301 }
1302 }
1303 }
1304 else // not a class, maybe a global member
1305 {
1306 int scopeEnd = className.findRev(".");
1307 if (scopeEnd!=-1 && !typeOnly) // name with explicit scope
1308 {
1309 QCString scope = substitute(className.left(scopeEnd),".","::");
1310 QCString locName = className.right(className.length()-scopeEnd-1);
1311 ClassDef *mcd = getClass(scope);
1312 DBG_CTX((stderr,"scope=%s locName=%s mcd=%p\n",qPrint(scope),qPrint(locName),mcd));
1313 if (mcd)
1314 {
1315 const MemberDef *mmd = mcd->getMemberByName(locName);
1316 if (mmd)
1317 {
1318 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())));
1319 writeMultiLineCodeLink(yyscanner,ol,mmd,clName);
1320 addToSearchIndex(yyscanner,className);
1321 const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ?
1322 mmd->getBodyDef() : mmd->getOuterScope();
1323 if (mmd->getGroupDef()) d = mmd->getGroupDef();
1324 if (d && d->isLinkable() && mmd->isLinkable() &&
1325 yyextra->currentMemberDef && yyextra->collectXRefs && yyextra->insideBody)
1326 {
1327 addDocCrossReference(yyextra->currentMemberDef,mmd);
1328 }
1329 return;
1330 }
1331 }
1332 else // check namespace as well
1333 {
1334 const NamespaceDef *mnd = getResolvedNamespace(scope);
1335 if (mnd)
1336 {
1337 const MemberDef *mmd=mnd->getMemberByName(locName);
1338 if (mmd)
1339 {
1340 //printf("name=%s scope=%s\n",qPrint(locName),qPrint(scope));
1341 yyextra->theCallContext.setScope(ScopedTypeVariant(stripClassName(yyscanner,mmd->typeString(),mmd->getOuterScope())));
1342 writeMultiLineCodeLink(yyscanner,ol,mmd,clName);
1343 addToSearchIndex(yyscanner,className);
1344 const Definition *d = mmd->getOuterScope()==Doxygen::globalScope ?
1345 mmd->getBodyDef() : mmd->getOuterScope();
1346 if (mmd->getGroupDef()) d = mmd->getGroupDef();
1347 if (d && d->isLinkable() && mmd->isLinkable() &&
1348 yyextra->currentMemberDef && yyextra->collectXRefs && yyextra->insideBody)
1349 {
1350 addDocCrossReference(yyextra->currentMemberDef,mmd);
1351 }
1352 return;
1353 }
1354 }
1355 }
1356 }
1357
1358 // nothing found, just write out the word
1359 codifyLines(yyscanner,clName);
1360 addToSearchIndex(yyscanner,clName);
1361 }
1362}
1363
1364//-------------------------------------------------------------------------------
1365
1366/*
1367 As of June 1, this function seems to work
1368 for file members, but scopes are not
1369 being correctly tracked for classes
1370 so it doesn't work for classes yet.
1371
1372*/
1373static void generateFunctionLink(yyscan_t yyscanner,
1374 OutputCodeList &ol,
1375 const QCString &funcName)
1376{
1377 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1378 QCString locScope=yyextra->classScope;
1379 QCString locFunc=removeRedundantWhiteSpace(funcName);
1380 DBG_CTX((stdout,"*** locScope=%s locFunc=%s\n",qPrint(locScope),qPrint(locFunc)));
1381 int i=locFunc.findRev("::");
1382 if (i>0)
1383 {
1384 locScope=locFunc.left(i);
1385 locFunc=locFunc.right(locFunc.length()-i-2).stripWhiteSpace();
1386 }
1387 //printf("generateFunctionLink(%s) classScope='%s'\n",qPrint(locFunc),qPrint(locScope));
1388 if (!locScope.isEmpty())
1389 {
1390 auto it = yyextra->codeClassMap.find(locScope.str());
1391 if (it!=yyextra->codeClassMap.end())
1392 {
1393 ScopedTypeVariant ccd = it->second;
1394 //printf("using classScope %s\n",qPrint(yyextra->classScope));
1395 if (ccd.localDef() && !ccd.localDef()->baseClasses().empty())
1396 {
1397 for (const auto &bcName : ccd.localDef()->baseClasses())
1398 {
1399 if (getLink(yyscanner,bcName,locFunc,ol,funcName))
1400 {
1401 return;
1402 }
1403 }
1404 }
1405 }
1406 }
1407 if (!getLink(yyscanner,locScope,locFunc,ol,funcName))
1408 {
1409 generateClassOrGlobalLink(yyscanner,ol,funcName);
1410 }
1411 return;
1412}
1413
1414//-------------------------------------------------------------------------------
1415
1416static bool findMemberLink(yyscan_t yyscanner,
1417 OutputCodeList &ol,
1418 const Definition *sym,
1419 const QCString &symName)
1420{
1421 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1422 //printf("sym %s outerScope=%s equal=%d\n",
1423 // qPrint(sym->name()),qPrint(sym->getOuterScope()->name()),
1424 // sym->getOuterScope()==yyextra->currentDefinition);
1425
1426 if (sym->getOuterScope() &&
1428 yyextra->currentDefinition->definitionType()==Definition::TypeClass)
1429 {
1430 const ClassDef *cd = toClassDef(sym->getOuterScope());
1431 const ClassDef *thisCd = toClassDef(yyextra->currentDefinition);
1433 {
1434 if (yyextra->currentMemberDef && yyextra->collectXRefs)
1435 {
1436 addDocCrossReference(yyextra->currentMemberDef,toMemberDef(sym));
1437 }
1438 }
1439 DBG_CTX((stderr,"cd=%s thisCd=%s\n",cd?qPrint(cd->name()):"<none>",thisCd?qPrint(thisCd->name()):"<none>"));
1440
1441 // TODO: find the nearest base class in case cd is a base class of
1442 // thisCd
1443 if (cd==thisCd || (thisCd && thisCd->isBaseClass(cd,TRUE)))
1444 {
1445 writeMultiLineCodeLink(yyscanner,ol,sym,symName);
1446 return TRUE;
1447 }
1448 }
1449 return FALSE;
1450}
1451
1452//-------------------------------------------------------------------------------
1453
1454static void findMemberLink(yyscan_t yyscanner,
1455 OutputCodeList &ol,
1456 const QCString &symName)
1457{
1458 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1459 //printf("Member reference: %s scope=%s member=%s\n",
1460 // yytext,
1461 // yyextra->currentDefinition?qPrint(yyextra->currentDefinition->name()):"<none>",
1462 // yyextra->currentMemberDef?qPrint(yyextra->currentMemberDef->name()):"<none>"
1463 // );
1464 if (yyextra->currentDefinition)
1465 {
1466 const auto &v = Doxygen::symbolMap->find(symName);
1467 for (const auto &p : v)
1468 {
1469 if (findMemberLink(yyscanner,ol,p,symName)) return;
1470 }
1471 }
1472 //printf("sym %s not found\n",&yytext[5]);
1473 codify(yyscanner,symName);
1474}
1475
1477{
1478 std::lock_guard<std::mutex> lock(Doxygen::countFlowKeywordsMutex);
1479 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1480 if (yyextra->currentMemberDef && yyextra->currentMemberDef->isFunction())
1481 {
1482 MemberDefMutable *md = toMemberDefMutable(const_cast<MemberDef*>(yyextra->currentMemberDef));
1483 if (md)
1484 {
1486 }
1487 }
1488}
1489
1490
1491//-------------------------------------------------------------------------------
1492
1498
1500{
1501 pycodeYYlex_init_extra(&p->state,&p->yyscanner);
1502#ifdef FLEX_DEBUG
1503 pycodeYYset_debug(Debug::isFlagSet(Debug::Lex_pycode)?1:0,p->yyscanner);
1504#endif
1506}
1507
1509{
1510 pycodeYYlex_destroy(p->yyscanner);
1511}
1512
1514{
1515 struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner;
1516 yyextra->codeClassMap.clear();
1517 yyextra->currentDefinition = nullptr;
1518 yyextra->currentMemberDef = nullptr;
1519 yyextra->doubleStringIsDoc = FALSE;
1520 yyextra->paramParens = 0;
1521 while (!yyextra->indents.empty()) yyextra->indents.pop();
1522 BEGIN( Body );
1523}
1524
1526 const QCString &/* scopeName */,
1527 const QCString &input,
1528 SrcLangExt /*lang*/,
1529 bool stripCodeComments,
1530 bool isExampleBlock,
1531 const QCString &exampleName,
1532 const FileDef *fileDef,
1533 int startLine,
1534 int endLine,
1535 bool inlineFragment,
1536 const MemberDef * /* memberDef */,
1537 bool /* showLineNumbers */,
1538 const Definition *searchCtx,
1539 bool collectXRefs
1540 )
1541{
1542 yyscan_t yyscanner = p->yyscanner;
1543 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1544
1545 //printf("***parseCode(%s)\n",qPrint(input));
1546
1547 codeOutIntf.stripCodeComments(stripCodeComments);
1548 if (input.isEmpty()) return;
1549 DebugLex debugLex(Debug::Lex_pycode, __FILE__, fileDef ? qPrint(fileDef->fileName()): nullptr);
1550 yyextra->fileName = fileDef ? fileDef->fileName():"";
1551 yyextra->code = &codeOutIntf;
1552 yyextra->inputString = input.data();
1553 yyextra->inputPosition = 0;
1554 yyextra->currentFontClass = nullptr;
1555 yyextra->insideCodeLine = FALSE;
1556 yyextra->searchCtx=searchCtx;
1557 yyextra->collectXRefs=collectXRefs;
1558 if (startLine!=-1)
1559 yyextra->yyLineNr = startLine;
1560 else
1561 yyextra->yyLineNr = 1;
1562 if (endLine!=-1)
1563 yyextra->inputLines = endLine+1;
1564 else
1565 yyextra->inputLines = yyextra->yyLineNr + countLines(yyscanner) - 1;
1566
1567
1568 yyextra->exampleBlock = isExampleBlock;
1569 yyextra->exampleName = exampleName;
1570 yyextra->sourceFileDef = fileDef;
1571 yyextra->symbolResolver.setFileScope(fileDef);
1572 yyextra->foldStack.clear();
1573 yyextra->insideSpecialComment = false;
1574
1575 if (yyextra->exampleBlock && fileDef==nullptr)
1576 {
1577 // create a dummy filedef for the example
1578 yyextra->exampleFileDef = createFileDef("",(!exampleName.isEmpty()?qPrint(exampleName):"generated"));
1579 yyextra->sourceFileDef = yyextra->exampleFileDef.get();
1580 }
1581 if (yyextra->sourceFileDef)
1582 {
1583 setCurrentDoc(yyscanner,"l00001");
1584 }
1585
1586 yyextra->includeCodeFragment = inlineFragment;
1587 // Starts line 1 on the output
1588 startCodeLine(yyscanner);
1589
1590 pycodeYYrestart(nullptr,yyscanner);
1591
1592 pycodeYYlex(yyscanner);
1593
1594 if (!yyextra->indents.empty())
1595 {
1596 // printf("Exited pysourceparser in inconsistent state!\n");
1597 }
1598
1599 if (yyextra->insideCodeLine)
1600 {
1601 endCodeLine(yyscanner);
1602 }
1603 if (Config_getBool(HTML_CODE_FOLDING))
1604 {
1605 while (!yyextra->foldStack.empty())
1606 {
1607 yyextra->code->endFold();
1608 yyextra->foldStack.pop_back();
1609 }
1610 }
1611 if (yyextra->exampleFileDef)
1612 {
1613 // delete the temporary file definition used for this example
1614 yyextra->exampleFileDef.reset();
1615 yyextra->sourceFileDef=nullptr;
1616 }
1617 // write the tooltips
1618 yyextra->tooltipManager.writeTooltips(codeOutIntf);
1619}
1620
1621static inline void pop_state(yyscan_t yyscanner)
1622{
1623 struct yyguts_t *yyg = (struct yyguts_t*)yyscanner;
1624 if ( yyg->yy_start_stack_ptr <= 0 )
1625 warn(yyextra->fileName,yyextra->yyLineNr,"Unexpected statement '{}'",yytext );
1626 else
1627 yy_pop_state(yyscanner);
1628}
1629
1630#include "pycode.l.h"
virtual const MemberDef * getMemberByName(const QCString &) const =0
Returns the member with the given name.
virtual int isBaseClass(const ClassDef *bcd, bool followInstances, const QCString &templSpec=QCString()) const =0
Returns TRUE iff bcd is a direct or indirect base class of this class.
@ Lex_pycode
Definition debug.h:65
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
virtual int getEndBodyLine() const =0
virtual bool isLinkable() const =0
virtual DefType definitionType() const =0
virtual QCString anchor() const =0
virtual QCString briefDescriptionAsTooltip() const =0
virtual const FileDef * getBodyDef() const =0
virtual bool isLinkableInProject() const =0
virtual int getStartDefLine() const =0
virtual QCString getReference() const =0
virtual QCString displayName(bool includeScope=TRUE) const =0
virtual CodeSymbolType codeSymbolType() const =0
virtual QCString getOutputFileBase() const =0
virtual Definition * getOuterScope() const =0
static NamespaceDefMutable * globalScope
Definition doxygen.h:121
static std::mutex countFlowKeywordsMutex
Definition doxygen.h:141
static SymbolMap< Definition > * symbolMap
Definition doxygen.h:125
static SearchIndexIntf searchIndex
Definition doxygen.h:124
virtual QCString fileName() const =0
std::vector< QCString > baseClasses() const
virtual QCString typeString() const =0
virtual GroupDef * getGroupDef()=0
virtual void incrementFlowKeyWordCount()=0
An abstract interface of a namespace symbol.
virtual const MemberDef * getMemberByName(const QCString &) const =0
void writeCodeLink(CodeSymbolType type, const QCString &ref, const QCString &file, const QCString &anchor, const QCString &name, const QCString &tooltip)
Definition outputlist.h:249
void stripCodeComments(bool b)
Definition outputlist.h:237
void resetCodeParserState() override
Resets the state of the code parser.
Definition pycode.l:1513
~PythonCodeParser() override
Definition pycode.l:1508
void parseCode(OutputCodeList &codeOutIntf, const QCString &scopeName, const QCString &input, SrcLangExt lang, bool stripCodeComments, bool isExampleBlock, const QCString &exampleName=QCString(), const FileDef *fileDef=nullptr, int startLine=-1, int endLine=-1, bool inlineFragment=FALSE, const MemberDef *memberDef=nullptr, bool showLineNumbers=TRUE, const Definition *searchCtx=nullptr, bool collectXrefs=TRUE) override
Parses a source file or fragment with the goal to produce highlighted and cross-referenced output.
Definition pycode.l:1525
std::unique_ptr< Private > p
Definition pycode.h:59
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
QCString & prepend(const char *s)
Definition qcstring.h:422
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition qcstring.h:260
const std::string & str() const
Definition qcstring.h:552
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:190
QCString right(size_t len) const
Definition qcstring.h:234
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
QCString left(size_t len) const
Definition qcstring.h:229
ClassDef * getClass(const QCString &n)
static void writeMultiLineCodeLink(yyscan_t yyscanner, OutputCodeList &ol, const Definition *d, const QCString &text)
Definition code.l:2550
static void endCodeLine(yyscan_t yyscanner)
Definition code.l:2478
#define DBG_CTX(x)
Definition code.l:73
static void nextCodeLine(yyscan_t yyscanner)
Definition code.l:2487
static void startCodeLine(yyscan_t yyscanner)
Definition code.l:2409
static int yyread(yyscan_t yyscanner, char *buf, int max_size)
Definition code.l:3963
static int countLines(yyscan_t yyscanner)
Definition code.l:3454
static void addToSearchIndex(yyscan_t yyscanner, const QCString &text)
Definition code.l:2293
static bool getLinkInScope(yyscan_t yyscanner, const QCString &c, const QCString &m, const QCString &memberText, OutputCodeList &ol, const QCString &text, bool varOnly=FALSE)
Definition code.l:2798
static const ClassDef * stripClassName(yyscan_t yyscanner, const QCString &s, const Definition *d)
Definition code.l:2640
static bool getLink(yyscan_t yyscanner, const QCString &className, const QCString &memberName, OutputCodeList &ol, const QCString &text=QCString(), bool varOnly=FALSE)
Definition code.l:2882
static void setCurrentDoc(yyscan_t yyscanner, const QCString &anchor)
Definition code.l:2277
static void codeFolding(yyscan_t yyscanner, const Definition *d)
Definition code.l:2351
#define Config_getBool(name)
Definition config.h:33
std::unique_ptr< FileDef > createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition filedef.cpp:268
void addDocCrossReference(const MemberDef *s, const MemberDef *d)
MemberDefMutable * toMemberDefMutable(Definition *d)
MemberDef * toMemberDef(Definition *d)
#define warn(file, line, fmt,...)
Definition message.h:97
NamespaceDef * getResolvedNamespace(const QCString &name)
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:482
const char * qPrint(const char *s)
Definition qcstring.h:687
int qstrcmp(const char *str1, const char *str2)
Definition qcstring.h:69
const FileDef * currentFile
Definition util.h:117
bool insideCode
Definition util.h:119
const MemberDef * md
Definition util.h:125
bool found
Definition util.h:124
pycodeYY_state state
Definition pycode.l:1496
SrcLangExt
Definition types.h:207
QCString removeRedundantWhiteSpace(const QCString &s)
Definition util.cpp:579
int extractClassNameFromType(const QCString &type, int &pos, QCString &name, QCString &templSpec, SrcLangExt lang)
Definition util.cpp:4731
GetDefResult getDefs(const GetDefInput &input)
Definition util.cpp:2823