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