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