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