1 /******************************************************************************
5 * Copyright (C) 1997-2015 by Dimitri van Heesch.
7 * Permission to use, copy, modify, and distribute this software and its
8 * documentation under the terms of the GNU General Public License is hereby
9 * granted. No representations are made about the suitability of this software
10 * for any purpose. It is provided "as is" without express or implied warranty.
11 * See the GNU General Public License for more details.
13 * Documents produced by Doxygen are derivative works derived from the
14 * input used in their production; they are not affected by this license.
17 /* This code is based on the work done by the MoxyPyDoxy team
18 * (Linda Leong, Mike Rivera, Kim Truong, and Gabriel Estrada)
19 * in Spring 2005 as part of CS 179E: Compiler Design Project
20 * at the University of California, Riverside; the course was
21 * taught by Peter H. Froehlich <phf@acm.org>.
24 %option never-interactive
25 %option prefix="pyscannerYY"
41 #include <qfileinfo.h>
43 #include "pyscanner.h"
51 #include "commentscan.h"
53 #include "arguments.h"
55 // Toggle for some debugging info
56 //#define DBG_CTX(x) fprintf x
57 #define DBG_CTX(x) do { } while(0)
60 #define YY_NO_UNISTD_H 1
62 /* -----------------------------------------------------------------
68 static ParserInterface *g_thisParser;
69 static const char * inputString;
70 static int inputPosition;
71 static QFile inputFile;
73 static Protection protection;
75 static Entry* current_root = 0 ;
76 static Entry* current = 0 ;
77 static Entry* previous = 0 ;
78 static Entry* bodyEntry = 0 ;
79 static int yyLineNr = 1 ;
80 static QCString yyFileName;
81 static MethodTypes mtype;
83 static Specifier virt;
85 static int docBlockContext;
86 static QCString docBlock;
87 static bool docBlockInBody;
88 static bool docBlockJavaStyle;
90 static bool docBlockSpecial;
92 static bool g_doubleQuote;
93 static bool g_specialBlock;
94 static int g_stringContext;
95 static QGString * g_copyString;
96 static int g_indent = 0;
97 static int g_curIndent = 0;
99 static QDict<QCString> g_packageNameCache(257);
101 static char g_atomStart;
102 static char g_atomEnd;
103 static int g_atomCount;
105 //static bool g_insideConstructor;
107 static QCString g_moduleScope;
108 static QCString g_packageName;
110 //static bool g_hideClassDocs;
112 static QCString g_defVal;
113 static int g_braceCount;
115 static bool g_lexInit = FALSE;
116 static bool g_packageCommentAllowed;
118 static bool g_start_init = FALSE;
119 static int g_search_count = 0;
121 //-----------------------------------------------------------------------------
124 static void initParser()
131 g_packageCommentAllowed = TRUE;
132 g_packageNameCache.setAutoDelete(TRUE);
135 static void initEntry()
137 //current->python = TRUE;
138 current->protection = protection ;
139 current->mtype = mtype;
140 current->virt = virt;
141 current->stat = gstat;
142 current->lang = SrcLangExt_Python;
143 current->setParent(current_root);
144 initGroupInfo(current);
148 static void newEntry()
151 current_root->addSubEntry(current);
152 current = new Entry ;
156 static void newVariable()
158 if (!current->name.isEmpty() && current->name.at(0)=='_') // mark as private
160 current->protection=Private;
162 if (current_root->section&Entry::COMPOUND_MASK) // mark as class variable
164 current->stat = TRUE;
169 static void newFunction()
171 if (current->name.left(2)=="__" && current->name.right(2)=="__")
173 // special method name, see
174 // http://docs.python.org/ref/specialnames.html
175 current->protection=Public;
177 else if (current->name.at(0)=='_')
179 current->protection=Private;
183 static inline int computeIndent(const char *s)
186 static int tabSize=Config_getInt(TAB_SIZE);
192 else if (c=='\t') col+=tabSize-(col%tabSize);
198 static QCString findPackageScopeFromPath(const QCString &path)
200 QCString *pScope = g_packageNameCache.find(path);
205 QFileInfo pf(path+"/__init__.py"); // found package initialization file
208 int i=path.findRev('/');
211 QCString scope = findPackageScopeFromPath(path.left(i));
212 if (!scope.isEmpty())
216 scope+=path.mid(i+1);
217 g_packageNameCache.insert(path,new QCString(scope));
224 static QCString findPackageScope(const char *fileName)
226 if (fileName==0) return "";
227 QFileInfo fi(fileName);
228 return findPackageScopeFromPath(fi.dirPath(TRUE).data());
231 //-----------------------------------------------------------------------------
233 static void lineCount()
235 DBG_CTX((stderr,"yyLineNr=%d\n",yyLineNr));
236 for (const char *p = yytext; *p; ++p)
238 yyLineNr += (*p == '\n') ;
242 static void incLineNr()
244 DBG_CTX((stderr,"yyLineNr=%d\n",yyLineNr));
249 // Appends the current-name to current-type;
250 // Destroys current-name.
251 // Destroys current->args and current->argList
252 static void addType( Entry* current )
254 uint tl=current->type.length();
255 if ( tl>0 && !current->name.isEmpty() && current->type.at(tl-1)!='.')
257 current->type += ' ' ;
259 current->type += current->name ;
260 current->name.resize(0) ;
261 tl=current->type.length();
262 if ( tl>0 && !current->args.isEmpty() && current->type.at(tl-1)!='.')
264 current->type += ' ' ;
266 current->type += current->args ;
267 current->args.resize(0) ;
268 current->argList->clear();
271 static QCString stripQuotes(const char *s)
274 if (s==0 || *s==0) return name;
276 if (name.at(0)=='"' && name.at(name.length()-1)=='"')
278 name=name.mid(1,name.length()-2);
283 //-----------------------------------------------------------------
285 //-----------------------------------------------------------------
286 static void startCommentBlock(bool brief)
290 current->briefFile = yyFileName;
291 current->briefLine = yyLineNr;
295 current->docFile = yyFileName;
296 current->docLine = yyLineNr;
301 static void appendDocBlock() {
303 current_root->addSubEntry(current);
309 static void handleCommentBlock(const QCString &doc,bool brief)
311 //printf("handleCommentBlock(doc=[%s] brief=%d docBlockInBody=%d docBlockJavaStyle=%d\n",
312 // doc.data(),brief,docBlockInBody,docBlockJavaStyle);
315 docBlockInBody=FALSE;
317 if (docBlockInBody && previous && !previous->doc.isEmpty())
319 previous->doc=previous->doc.stripWhiteSpace()+"\n\n";
324 int lineNr = brief ? current->briefLine : current->docLine;
325 while (parseCommentBlock(
327 (docBlockInBody && previous) ? previous : current,
331 docBlockInBody ? FALSE : brief,
332 docBlockJavaStyle, // javadoc style // or FALSE,
337 ) // need to start a new entry
351 static void endOfDef(int correction=0)
353 //printf("endOfDef at=%d\n",yyLineNr);
356 bodyEntry->endBodyLine = yyLineNr-correction;
360 //g_insideConstructor = FALSE;
363 static inline void addToString(const char *s)
365 if (g_copyString) (*g_copyString)+=s;
368 static void initTriDoubleQuoteBlock()
370 docBlockContext = YY_START;
371 docBlockInBody = FALSE;
372 docBlockJavaStyle = TRUE;
373 docBlockSpecial = yytext[strlen(yytext) - 1]=='!';
375 g_doubleQuote = TRUE;
376 startCommentBlock(FALSE);
379 static void initTriSingleQuoteBlock()
381 docBlockContext = YY_START;
382 docBlockInBody = FALSE;
383 docBlockJavaStyle = TRUE;
384 docBlockSpecial = yytext[strlen(yytext) - 1]=='!';
386 g_doubleQuote = FALSE;
387 startCommentBlock(FALSE);
390 static void initSpecialBlock()
392 docBlockContext = YY_START;
393 docBlockInBody = FALSE;
394 docBlockJavaStyle = TRUE;
397 startCommentBlock(TRUE);
400 static void searchFoundDef()
402 current->fileName = yyFileName;
403 current->startLine = yyLineNr;
404 current->bodyLine = yyLineNr;
405 current->section = Entry::FUNCTION_SEC;
406 current->lang = SrcLangExt_Python;
407 current->virt = Normal;
408 current->stat = gstat;
409 current->mtype = mtype = Method;
410 current->type.resize(0);
411 current->name.resize(0);
412 current->args.resize(0);
413 current->argList->clear();
414 g_packageCommentAllowed = FALSE;
416 //printf("searchFoundDef at=%d\n",yyLineNr);
419 static void searchFoundClass()
421 current->section = Entry::CLASS_SEC;
422 current->argList->clear();
423 current->type += "class" ;
424 current->fileName = yyFileName;
425 current->startLine = yyLineNr;
426 current->bodyLine = yyLineNr;
427 g_packageCommentAllowed = FALSE;
430 //-----------------------------------------------------------------------------
431 /* ----------------------------------------------------------------- */
433 #define YY_INPUT(buf,result,max_size) result=yyread(buf,max_size);
435 static int yyread(char *buf,int max_size)
438 while ( c < max_size && inputString[inputPosition] )
440 *buf = inputString[inputPosition++] ;
441 //printf("%d (%c)\n",*buf,*buf);
449 /* start command character */
460 HEXNUMBER "0"[xX][0-9a-fA-F]+[lL]?
461 OCTNUMBER "0"[0-7]+[lL]?
462 NUMBER {DIGIT}+[lLjJ]?
463 INTNUMBER {HEXNUMBER}|{OCTNUMBER}|{NUMBER}
464 FLOATNUMBER {DIGIT}+"."{DIGIT}+([eE][+\-]?{DIGIT}+)?[jJ]?
465 BOOL ("True"|"False")
466 LETTER [A-Za-z\x80-\xFF]
467 NONEMPTY [A-Za-z0-9_\x80-\xFF]
468 EXPCHAR [#(){}\[\],:.%/\\=`*~|&<>!;+-]
469 NONEMPTYEXP [^ \t\n:]
470 PARAMNONEMPTY [^ \t\n():]
471 IDENTIFIER ({LETTER}|"_")({LETTER}|{DIGIT}|"_")*
472 SCOPE {IDENTIFIER}("."{IDENTIFIER})*
473 BORDER ([^A-Za-z0-9])
475 TRISINGLEQUOTE {STRINGPREFIX}?"'''"(!)?
476 TRIDOUBLEQUOTE {STRINGPREFIX}?"\"\"\""(!)?
477 ENDTRISINGLEQUOTE "'''"
478 ENDTRIDOUBLEQUOTE "\"\"\""
479 LONGSTRINGCHAR [^\\"']
481 LONGSTRINGITEM ({LONGSTRINGCHAR}|{ESCAPESEQ})
482 SMALLQUOTE ("\"\""|"\""|"'"|"''")
483 LONGSTRINGBLOCK ({LONGSTRINGITEM}+|{SMALLQUOTE})
485 SHORTSTRING ("'"{SHORTSTRINGITEM}*"'"|'"'{SHORTSTRINGITEM}*'"')
486 SHORTSTRINGITEM ({SHORTSTRINGCHAR}|{ESCAPESEQ})
487 SHORTSTRINGCHAR [^\\\n"]
488 STRINGLITERAL {STRINGPREFIX}?( {SHORTSTRING} | {LONGSTRING})
489 STRINGPREFIX ("r"|"u"|"ur"|"R"|"U"|"UR"|"Ur"|"uR")
490 KEYWORD ("lambda"|"import"|"class"|"assert"|"as"|"from"|"global"|"def"|"True"|"False")
491 FLOWKW ("or"|"and"|"is"|"not"|"print"|"for"|"in"|"if"|"try"|"except"|"yield"|"raise"|"break"|"continue"|"pass"|"if"|"return"|"while"|"elif"|"else"|"finally")
492 POUNDCOMMENT "#"[^#\n][^\n]*
499 /* Main start state */
504 /* Mid-comment states */
506 /* %x FuncDoubleComment */
507 /* %x ClassDoubleComment */
512 /* Function states */
517 %x FunctionParamDefVal
523 %x ClassCaptureIndent
526 /* Variable states */
544 /* ------------ Function recognition rules -------------- */
548 ^{B}"def"{BB} { // start of a function/method definition with indent
549 DBG_CTX((stderr,"Found def at %d\n",yyLineNr));
550 g_indent=computeIndent(yytext);
552 BEGIN( FunctionDec );
554 "def"{BB} { // start of a function/method definition
556 BEGIN( FunctionDec );
559 ^{B}"class"{BB} { // start of a class definition with indent
560 DBG_CTX((stderr,"Found class at %d\n",yyLineNr));
561 g_indent=computeIndent(yytext);
565 "class"{BB} { // start of a class definition
570 "from"{BB} { // start of an from import
571 g_packageCommentAllowed = FALSE;
576 "import"{BB} { // start of an import statement
577 g_packageCommentAllowed = FALSE;
580 ^{B}{IDENTIFIER}/{B}"="{B}"property" { // property
581 current->section = Entry::VARIABLE_SEC;
582 current->mtype = Property;
583 current->name = QCString(yytext).stripWhiteSpace();
584 current->fileName = yyFileName;
585 current->startLine = yyLineNr;
586 current->bodyLine = yyLineNr;
587 g_packageCommentAllowed = FALSE;
590 ^{B}{IDENTIFIER}/{B}"="[^=] { // variable
591 if (g_search_count) REJECT;
592 g_indent=computeIndent(yytext);
593 current->section = Entry::VARIABLE_SEC;
594 current->name = QCString(yytext).stripWhiteSpace();
595 current->fileName = yyFileName;
596 current->startLine = yyLineNr;
597 current->bodyLine = yyLineNr;
598 g_packageCommentAllowed = FALSE;
601 {B}{IDENTIFIER}/({B},{B}{IDENTIFIER})*{B}")"*{B}"="[^=] { // list of variables, we cannot place the default value
602 // so we will skip it later on in a general rule
603 // Also note ")" this is to catch also (a,b). the "("
604 // is caught in the rule: [(], the ")" will be handled in [)]
605 if (g_search_count > 1) REJECT;
606 g_indent=computeIndent(yytext);
607 current->section = Entry::VARIABLE_SEC;
608 current->name = QCString(yytext).stripWhiteSpace();
609 current->fileName = yyFileName;
610 current->startLine = yyLineNr;
611 current->bodyLine = yyLineNr;
612 g_packageCommentAllowed = FALSE;
615 "'" { // start of a single quoted string
616 g_stringContext=YY_START;
618 g_packageCommentAllowed = FALSE;
619 BEGIN( SingleQuoteString );
621 "\"" { // start of a double quoted string
622 g_stringContext=YY_START;
624 g_packageCommentAllowed = FALSE;
625 BEGIN( DoubleQuoteString );
630 {SCRIPTCOMMENT} { // Unix type script comment
631 if (yyLineNr != 1) REJECT;
633 {POUNDCOMMENT} { // normal comment
634 g_packageCommentAllowed = FALSE;
636 {IDENTIFIER} { // some other identifier
637 g_packageCommentAllowed = FALSE;
640 g_curIndent=computeIndent(yytext);
643 {NEWLINE}+ { // new line
647 {TRIDOUBLEQUOTE} { // start of a comment block
648 initTriDoubleQuoteBlock();
649 BEGIN(TripleComment);
652 {TRISINGLEQUOTE} { // start of a comment block
653 initTriSingleQuoteBlock();
654 BEGIN(TripleComment);
657 {STARTDOCSYMS}/[^#] { // start of a special comment
658 g_curIndent=computeIndent(yytext);
659 g_packageCommentAllowed = FALSE;
661 BEGIN(SpecialComment);
663 [(] { // we have to do something with (
666 [)] { // we have to do something with )
669 [^\n] { // any other character...
670 // This is the major default
671 // that should catch everything
677 "." { // python3 style imports
679 {IDENTIFIER}({B}"."{B}{IDENTIFIER})* { // from package import
680 g_packageName=yytext;
699 QCString item=g_packageName;
700 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
701 current->fileName = yyFileName;
702 //printf("Adding using directive: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
703 current->section=Entry::USINGDIR_SEC;
704 current_root->addSubEntry(current);
705 current = new Entry ;
709 {IDENTIFIER}/{B}","{B} {
710 QCString item=g_packageName+"."+yytext;
711 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
712 current->fileName = yyFileName;
713 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
714 current->section=Entry::USINGDECL_SEC;
715 current_root->addSubEntry(current);
716 current = new Entry ;
720 QCString item=g_packageName+"."+yytext;
721 current->name=removeRedundantWhiteSpace(substitute(item,".","::"));
722 current->fileName = yyFileName;
723 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
724 current->section=Entry::USINGDECL_SEC;
725 current_root->addSubEntry(current);
726 current = new Entry ;
745 {IDENTIFIER}({B}"."{B}{IDENTIFIER})* {
746 current->name=removeRedundantWhiteSpace(substitute(yytext,".","::"));
747 current->fileName = yyFileName;
748 //printf("Adding using declaration: found:%s:%d name=%s\n",yyFileName.data(),yyLineNr,current->name.data());
749 current->section=Entry::USINGDECL_SEC;
750 current_root->addSubEntry(current);
751 current = new Entry ;
768 "self."{IDENTIFIER}/{B}"=" {
769 DBG_CTX((stderr,"Found instance method variable %s in %s at %d\n",&yytext[5],current_root->name.data(),yyLineNr));
770 current->name=&yytext[5];
771 current->section=Entry::VARIABLE_SEC;
772 current->fileName = yyFileName;
773 current->startLine = yyLineNr;
774 current->bodyLine = yyLineNr;
775 current->type.resize(0);
776 if (current->name.at(0)=='_') // mark as private
778 current->protection=Private;
782 "cls."{IDENTIFIER}/{B}"=" {
783 DBG_CTX((stderr,"Found class method variable %s in %s at %d\n",&yytext[4],current_root->name.data(),yyLineNr));
784 current->name=&yytext[4];
785 current->section=Entry::VARIABLE_SEC;
786 current->fileName = yyFileName;
787 current->startLine = yyLineNr;
788 current->bodyLine = yyLineNr;
789 current->type.resize(0);
790 if (current->name.at(0)=='_') // mark as private
792 current->protection=Private;
796 {TRIDOUBLEQUOTE} { // start of a comment block
797 initTriDoubleQuoteBlock();
798 BEGIN(TripleComment);
801 {TRISINGLEQUOTE} { // start of a comment block
802 initTriSingleQuoteBlock();
803 BEGIN(TripleComment);
806 {STARTDOCSYMS}/[^#] { // start of a special comment
808 BEGIN(SpecialComment);
810 {POUNDCOMMENT} { // #
812 "'" { // start of a single quoted string
813 g_stringContext=YY_START;
815 BEGIN( SingleQuoteString );
817 "\"" { // start of a double quoted string
818 g_stringContext=YY_START;
820 BEGIN( DoubleQuoteString );
823 {IDENTIFIER} // identifiers
824 [^'"\.#a-z_A-Z\n]+ // other uninteresting stuff
829 \n{B}/{IDENTIFIER}{BB} {
830 DBG_CTX((stderr,"indent %d<=%d\n",computeIndent(&yytext[1]),g_indent));
831 if (computeIndent(&yytext[1])<=g_indent)
834 for (i=(int)yyleng-1;i>=0;i--)
839 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
845 current->program+=yytext;
849 if (computeIndent(&yytext[1])<=g_indent)
852 for (i=(int)yyleng-1;i>=0;i--)
857 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
863 current->program+=yytext;
870 ^{BB}/\n { // skip empty line
871 current->program+=yytext;
873 ^{BB} { // something at indent >0
874 current->program+=yytext;
875 g_curIndent = computeIndent(yytext);
876 if (g_curIndent<=g_indent)
877 // jumped out of the function
883 "'" { // start of a single quoted string
884 current->program+=yytext;
885 g_stringContext=YY_START;
886 g_specialBlock = FALSE;
887 g_copyString=¤t->program;
888 BEGIN( SingleQuoteString );
890 "\"" { // start of a double quoted string
891 current->program+=yytext;
892 g_stringContext=YY_START;
893 g_specialBlock = FALSE;
894 g_copyString=¤t->program;
895 BEGIN( DoubleQuoteString );
897 [^ \t\n#'".]+ { // non-special stuff
898 current->program+=yytext;
899 g_specialBlock = FALSE;
901 ^{POUNDCOMMENT} { // normal comment
902 current->program+=yytext;
904 "#".* { // comment half way
905 current->program+=yytext;
909 current->program+=yytext;
912 current->program+=*yytext;
913 g_specialBlock = FALSE;
916 {TRIDOUBLEQUOTE} { // start of a comment block
917 current->program+=yytext;
918 initTriDoubleQuoteBlock();
919 BEGIN(TripleComment);
922 {TRISINGLEQUOTE} { // start of a comment block
923 current->program+=yytext;
924 initTriSingleQuoteBlock();
925 BEGIN(TripleComment);
928 {STARTDOCSYMS}/[^#] { // start of a special comment
930 BEGIN(SpecialComment);
938 //found function name
939 if (current->type.isEmpty())
941 current->type = "def";
943 current->name = yytext;
944 current->name = current->name.stripWhiteSpace();
947 {B}":" { // function without arguments
948 g_specialBlock = TRUE; // expecting a docstring
950 current->bodyLine = yyLineNr;
951 BEGIN( FunctionBody );
955 BEGIN( FunctionParams );
963 {IDENTIFIER} { // Name of parameter
965 Argument *a = new Argument;
966 current->argList->append(a);
967 current->argList->getLast()->name = QCString(yytext).stripWhiteSpace();
968 current->argList->getLast()->type = "";
970 "=" { // default value
971 // TODO: this rule is too simple, need to be able to
972 // match things like =")" as well!
975 BEGIN(FunctionParamDefVal);
978 ")" { // end of parameter list
979 current->args = argListToString(current->argList);
983 g_specialBlock = TRUE; // expecting a docstring
985 current->bodyLine = yyLineNr;
986 BEGIN( FunctionBody );
988 {POUNDCOMMENT} { // a comment
990 {PARAMNONEMPTY} { // Default rule inside arguments.
995 <FunctionParamDefVal>{
996 "(" { // internal opening brace
1002 if (g_braceCount==0) // end of default argument
1004 if (current->argList->getLast())
1006 current->argList->getLast()->defval=g_defVal.stripWhiteSpace();
1009 current->args = argListToString(current->argList);
1010 BEGIN(FunctionParams);
1014 if (*yytext == ')')g_braceCount--;
1029 \n/{IDENTIFIER}{BB} { // new def at indent 0
1032 //g_hideClassDocs = FALSE;
1033 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
1036 \n/"##"[^#] { // start of a special comment at indent 0
1039 //g_hideClassDocs = FALSE;
1040 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
1043 ^{BB}/\n { // skip empty line
1044 current->program+=yytext;
1050 ^{BB} { // something at indent >0
1051 g_curIndent=computeIndent(yytext);
1052 DBG_CTX((stderr,"g_curIndent=%d g_indent=%d\n",g_curIndent,g_indent));
1053 if (g_curIndent<=g_indent)
1054 // jumped out of the class/method
1057 g_indent=g_curIndent;
1058 // make sure the next rule matches ^...
1059 //YY_CURRENT_BUFFER->yy_at_bol=TRUE;
1060 //g_hideClassDocs = FALSE;
1065 current->program+=yytext;
1068 "'" { // start of a single quoted string
1069 current->program+=*yytext;
1070 g_stringContext=YY_START;
1071 g_specialBlock = FALSE;
1072 g_copyString=¤t->program;
1073 BEGIN( SingleQuoteString );
1075 "\"" { // start of a double quoted string
1076 current->program+=*yytext;
1077 g_stringContext=YY_START;
1078 g_specialBlock = FALSE;
1079 g_copyString=¤t->program;
1080 BEGIN( DoubleQuoteString );
1082 [^ \t\n#'"]+ { // non-special stuff
1083 current->program+=yytext;
1084 g_specialBlock = FALSE;
1085 //g_hideClassDocs = FALSE;
1088 current->program+=*yytext;
1091 {POUNDCOMMENT} { // normal comment
1092 current->program+=yytext;
1094 . { // any character
1095 g_specialBlock = FALSE;
1096 current->program+=*yytext;
1098 {TRIDOUBLEQUOTE} { // start of a comment block
1099 //if (!g_hideClassDocs)
1100 current->program+=yytext;
1101 initTriDoubleQuoteBlock();
1102 BEGIN(TripleComment);
1105 {TRISINGLEQUOTE} { // start of a comment block
1106 //if (!g_hideClassDocs)
1107 current->program+=yytext;
1108 initTriSingleQuoteBlock();
1109 BEGIN(TripleComment);
1113 <ClassDec>{IDENTIFIER} {
1114 if (current->type.isEmpty())
1116 current->type = "class";
1119 current->section = Entry::CLASS_SEC;
1120 current->name = yytext;
1122 // prepend scope in case of nested classes
1123 if (current_root->section&Entry::SCOPE_MASK)
1125 //printf("*** Prepending scope %s to class %s\n",current_root->name.data(),current->name.data());
1126 current->name.prepend(current_root->name+"::");
1129 current->name = current->name.stripWhiteSpace();
1130 current->fileName = yyFileName;
1131 docBlockContext = YY_START;
1132 docBlockInBody = FALSE;
1133 docBlockJavaStyle = FALSE;
1136 BEGIN(ClassInheritance);
1140 ({BB}|[\(,\)]) { // syntactic sugar for the list
1143 ":" { // begin of the class definition
1144 g_specialBlock = TRUE; // expecting a docstring
1145 current->bodyLine = yyLineNr;
1146 current->program.resize(0);
1147 BEGIN(ClassCaptureIndent);
1151 current->extends->append(
1152 new BaseInfo(substitute(yytext,".","::"),Public,Normal)
1154 //Has base class-do stuff
1159 <ClassCaptureIndent>{
1161 // Blankline - ignore, keep looking for indentation.
1163 current->program+=yytext;
1166 {TRIDOUBLEQUOTE} { // start of a comment block
1167 initTriDoubleQuoteBlock();
1168 current->program+=yytext;
1169 BEGIN(TripleComment);
1172 {TRISINGLEQUOTE} { // start of a comment block
1173 initTriSingleQuoteBlock();
1174 current->program+=yytext;
1175 BEGIN(TripleComment);
1179 current->program+=yytext;
1180 //current->startLine = yyLineNr;
1181 g_curIndent=computeIndent(yytext);
1182 bodyEntry = current;
1183 DBG_CTX((stderr,"setting indent %d\n",g_curIndent));
1184 //printf("current->program=[%s]\n",current->program.data());
1185 //g_hideClassDocs = TRUE;
1189 ""/({NONEMPTY}|{EXPCHAR}) {
1191 // Just pushback an empty class, and
1192 // resume parsing the body.
1194 current->program+=yytext;
1196 // printf("Failed to find indent - skipping!");
1203 "=" { // the assignment operator
1204 //printf("====== VariableDec at line %d\n",yyLineNr);
1205 g_start_init = TRUE;
1206 current->initializer = yytext;
1207 current->initializer += " ";
1210 current->initializer += yytext;
1212 {INTNUMBER} { // integer value
1213 if (current-> type.isEmpty()) current->type = "int";
1214 current->initializer += yytext;
1216 {FLOATNUMBER} { // floating point value
1217 if (current->type.isEmpty()) current->type = "float";
1218 current->initializer += yytext;
1220 {BOOL} { // boolean value
1221 if (current->type.isEmpty()) current->type = "bool";
1222 current->initializer += yytext;
1224 {STRINGPREFIX}?"'" { // string
1225 if (current->type.isEmpty()) current->type = "string";
1226 current->initializer += yytext;
1227 g_copyString=¤t->initializer;
1228 g_stringContext=VariableDec;
1229 BEGIN( SingleQuoteString );
1231 {STRINGPREFIX}?"\"" { // string
1232 if (current->type.isEmpty()) current->type = "string";
1233 current->initializer += yytext;
1234 g_copyString=¤t->initializer;
1235 g_stringContext=VariableDec;
1236 BEGIN( DoubleQuoteString );
1238 {TRIDOUBLEQUOTE} { // start of a comment block
1239 if (current->type.isEmpty()) current->type = "string";
1240 current->initializer += yytext;
1242 g_copyString=¤t->initializer;
1243 g_stringContext=VariableDec;
1244 BEGIN(TripleString);
1247 {TRISINGLEQUOTE} { // start of a comment block
1248 if (current->type.isEmpty()) current->type = "string";
1249 current->initializer += yytext;
1250 g_doubleQuote=FALSE;
1251 g_copyString=¤t->initializer;
1252 g_stringContext=VariableDec;
1253 BEGIN(TripleString);
1255 "(" { // tuple, only when direct after =
1256 if (current->mtype!=Property && g_start_init)
1258 current->type = "tuple";
1260 current->initializer+=*yytext;
1264 BEGIN( VariableAtom );
1267 if (g_start_init) current->type = "list";
1268 current->initializer+=*yytext;
1272 BEGIN( VariableAtom );
1275 if (g_start_init) current->type = "dictionary";
1276 current->initializer+=*yytext;
1280 BEGIN( VariableAtom );
1283 BEGIN( VariableEnd );
1286 // do something based on the type of the IDENTIFIER
1287 if (current->type.isEmpty())
1289 QListIterator<Entry> eli(*(current_root->children()));
1291 for (eli.toFirst();(child=eli.current());++eli)
1293 if (child->name == QCString(yytext))
1295 current->type = child->type;
1300 g_start_init = FALSE;
1301 current->initializer+=yytext;
1304 g_start_init = FALSE;
1305 current->initializer+=*yytext;
1309 BEGIN( VariableEnd );
1315 current->initializer+=*yytext;
1316 if (g_atomStart==*yytext)
1322 current->initializer+=*yytext;
1323 if (g_atomEnd==*yytext)
1329 g_start_init = FALSE;
1333 {TRIDOUBLEQUOTE} { // start of a comment block
1334 g_specialBlock = FALSE;
1335 current->program+=yytext;
1336 initTriDoubleQuoteBlock();
1337 BEGIN(TripleComment);
1340 {TRISINGLEQUOTE} { // start of a comment block
1341 g_specialBlock = FALSE;
1342 current->program+=yytext;
1343 initTriSingleQuoteBlock();
1344 BEGIN(TripleComment);
1347 g_stringContext=YY_START;
1348 current->initializer+="'";
1349 g_copyString=¤t->initializer;
1350 BEGIN( SingleQuoteString );
1353 g_stringContext=YY_START;
1354 current->initializer+="\"";
1355 g_copyString=¤t->initializer;
1356 BEGIN( DoubleQuoteString );
1359 current->initializer+=yytext;
1362 current->initializer+=*yytext;
1365 current->initializer+=*yytext;
1382 <<EOF>> { yyterminate();
1388 {ENDTRIDOUBLEQUOTE} |
1389 {ENDTRISINGLEQUOTE} {
1390 // printf("Expected module block %d special=%d\n",g_expectModuleDocs,g_specialBlock);
1391 if (g_doubleQuote==(yytext[0]=='"'))
1393 if (g_specialBlock) // expecting a docstring
1395 QCString actualDoc=docBlock;
1396 if (!docBlockSpecial) // legacy unformatted docstring
1398 actualDoc.prepend("\\verbatim ");
1399 actualDoc.append("\\endverbatim ");
1401 //printf("-------> current=%p bodyEntry=%p\n",current,bodyEntry);
1402 handleCommentBlock(actualDoc, FALSE);
1404 else if (g_packageCommentAllowed) // expecting module docs
1406 QCString actualDoc=docBlock;
1407 if (!docBlockSpecial) // legacy unformatted docstring
1409 actualDoc.prepend("\\verbatim ");
1410 actualDoc.append("\\endverbatim ");
1412 actualDoc.prepend("\\namespace "+g_moduleScope+"\\_linebr ");
1413 handleCommentBlock(actualDoc, FALSE);
1415 if ((docBlockContext==ClassBody /*&& !g_hideClassDocs*/) ||
1416 docBlockContext==FunctionBody)
1418 current->program+=docBlock;
1419 current->program+=yytext;
1421 //if (g_hideClassDocs)
1423 // current->startLine = yyLineNr;
1425 //g_hideClassDocs=FALSE;
1426 BEGIN(docBlockContext);
1432 g_packageCommentAllowed = FALSE;
1436 ^{BB} { // leading whitespace
1437 int indent = computeIndent(yytext);
1438 if (indent>=g_curIndent)
1439 { // strip g_curIndent amount of whitespace
1441 for (i=0;i<indent-g_curIndent;i++) docBlock+=' ';
1442 DBG_CTX((stderr,"stripping indent %d\n",g_curIndent));
1446 DBG_CTX((stderr,"not stripping: %d<%d\n",indent,g_curIndent));
1457 \\. { // espaced char
1466 ^{B}"#"("#")* { // skip leading hashes
1468 \n/{B}"#" { // continuation of the comment on the next line
1471 startCommentBlock(FALSE);
1474 [^#\n]+ { // any other stuff
1477 \n { // new line that ends the comment
1478 handleCommentBlock(docBlock, docBrief);
1480 BEGIN(docBlockContext);
1482 . { // anything we missed
1487 <SingleQuoteString>{
1488 \\{B}\n { // line continuation
1489 addToString(yytext);
1492 \\. { // espaced char
1493 addToString(yytext);
1495 "\"\"\"" { // tripple double quotes
1496 addToString(yytext);
1498 "'" { // end of the string
1499 addToString(yytext);
1500 BEGIN(g_stringContext);
1502 [^"'\n\\]+ { // normal chars
1503 addToString(yytext);
1506 addToString(yytext);
1510 <DoubleQuoteString>{
1511 \\{B}\n { // line continuation
1512 addToString(yytext);
1515 \\. { // espaced char
1516 addToString(yytext);
1518 "'''" { // tripple single quotes
1519 addToString(yytext);
1521 "\"" { // end of the string
1522 addToString(yytext);
1523 BEGIN(g_stringContext);
1525 [^"'\n\\]+ { // normal chars
1526 addToString(yytext);
1529 addToString(yytext);
1534 {ENDTRIDOUBLEQUOTE} |
1535 {ENDTRISINGLEQUOTE} {
1536 *g_copyString += yytext;
1537 if (g_doubleQuote==(yytext[0]=='"'))
1539 BEGIN(g_stringContext);
1544 ({LONGSTRINGBLOCK}) {
1546 *g_copyString += yytext;
1550 *g_copyString += yytext;
1553 *g_copyString += *yytext;
1557 /* ------------ End rules -------------- */
1560 <*>({NONEMPTY}|{EXPCHAR}|{BB}) { // This should go one character at a time.
1561 // printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
1562 // yytext, YY_START, yyLineNr);
1568 //printf("[pyscanner] %d NEWLINE [line %d] no match\n",
1569 // YY_START, yyLineNr);
1575 //printf("[pyscanner] '%s' [ state %d ] [line %d] no match\n",
1576 // yytext, YY_START, yyLineNr);
1583 //----------------------------------------------------------------------------
1585 static void parseCompounds(Entry *rt)
1587 //printf("parseCompounds(%s)\n",rt->name.data());
1588 EntryListIterator eli(*rt->children());
1590 for (;(ce=eli.current());++eli)
1592 if (!ce->program.isEmpty())
1594 //printf("-- %s ---------\n%s\n---------------\n",
1595 // ce->name.data(),ce->program.data());
1596 // init scanner state
1597 inputString = ce->program;
1599 pyscannerYYrestart( pyscannerYYin ) ;
1600 if (ce->section&Entry::COMPOUND_MASK)
1605 else if (ce->parent())
1607 current_root = ce->parent();
1608 //printf("Searching for member variables in %s parent=%s\n",
1609 // ce->name.data(),ce->parent->name.data());
1610 BEGIN( SearchMemVars );
1612 yyFileName = ce->fileName;
1613 yyLineNr = ce->bodyLine ;
1614 if (current) delete current;
1615 current = new Entry;
1618 groupEnterCompound(yyFileName,yyLineNr,ce->name);
1622 delete current; current=0;
1623 ce->program.resize(0);
1625 groupLeaveCompound(yyFileName,yyLineNr,ce->name);
1632 //----------------------------------------------------------------------------
1635 static void parseMain(const char *fileName,const char *fileBuf,Entry *rt)
1639 inputString = fileBuf;
1642 protection = Public;
1647 g_specialBlock = FALSE;
1650 inputFile.setName(fileName);
1651 if (inputFile.open(IO_ReadOnly))
1654 yyFileName = fileName;
1656 msg("Parsing file %s...\n",yyFileName.data());
1658 QFileInfo fi(fileName);
1659 g_moduleScope = findPackageScope(fileName);
1660 QCString baseName=fi.baseName().utf8();
1661 if (baseName!="__init__") // package initializer file is not a package itself
1663 if (!g_moduleScope.isEmpty())
1665 g_moduleScope+="::";
1667 g_moduleScope+=baseName;
1670 current = new Entry;
1672 current->name = g_moduleScope;
1673 current->section = Entry::NAMESPACE_SEC;
1674 current->type = "namespace";
1675 current->fileName = yyFileName;
1676 current->startLine = yyLineNr;
1677 current->bodyLine = yyLineNr;
1679 rt->addSubEntry(current);
1681 current_root = current ;
1683 current = new Entry;
1685 groupEnterFile(yyFileName,yyLineNr);
1689 pyscannerYYrestart( pyscannerYYin );
1694 groupLeaveFile(yyFileName,yyLineNr);
1696 current_root->program.resize(0);
1697 delete current; current=0;
1699 parseCompounds(current_root);
1706 //----------------------------------------------------------------------------
1708 static void parsePrototype(const QCString &text)
1710 //printf("**** parsePrototype(%s) begin\n",text.data());
1713 warn(yyFileName,yyLineNr,"Empty prototype found!");
1717 g_specialBlock = FALSE;
1718 g_packageCommentAllowed = FALSE;
1720 const char *orgInputString;
1721 int orgInputPosition;
1722 YY_BUFFER_STATE orgState;
1724 // save scanner state
1725 orgState = YY_CURRENT_BUFFER;
1726 yy_switch_to_buffer(yy_create_buffer(pyscannerYYin, YY_BUF_SIZE));
1727 orgInputString = inputString;
1728 orgInputPosition = inputPosition;
1733 pyscannerYYrestart( pyscannerYYin );
1735 BEGIN( FunctionDec );
1740 current->name = current->name.stripWhiteSpace();
1741 if (current->section == Entry::MEMBERDOC_SEC && current->args.isEmpty())
1742 current->section = Entry::VARIABLEDOC_SEC;
1744 // restore original scanner state
1746 YY_BUFFER_STATE tmpBuf = YY_CURRENT_BUFFER;
1747 yy_switch_to_buffer(orgState);
1748 yy_delete_buffer(tmpBuf);
1750 inputString = orgInputString;
1751 inputPosition = orgInputPosition;
1753 //printf("**** parsePrototype end\n");
1756 void pyscanFreeScanner()
1758 #if defined(YY_FLEX_SUBMINOR_VERSION)
1761 pyscannerYYlex_destroy();
1766 //----------------------------------------------------------------------------
1768 void PythonLanguageScanner::parseInput(const char *fileName,
1769 const char *fileBuf,
1771 bool /*sameTranslationUnit*/,
1772 QStrList & /*filesInSameTranslationUnit*/)
1774 g_thisParser = this;
1775 printlex(yy_flex_debug, TRUE, __FILE__, fileName);
1776 ::parseMain(fileName,fileBuf,root);
1777 printlex(yy_flex_debug, FALSE, __FILE__, fileName);
1779 // May print the AST for debugging purposes
1780 // printAST(global_root);
1783 bool PythonLanguageScanner::needsPreprocessing(const QCString &)
1788 void PythonLanguageScanner::parseCode(CodeOutputInterface &codeOutIntf,
1789 const char *scopeName,
1790 const QCString &input,
1791 SrcLangExt /*lang*/,
1792 bool isExampleBlock,
1793 const char *exampleName,
1797 bool inlineFragment,
1798 MemberDef *memberDef,
1799 bool showLineNumbers,
1800 Definition *searchCtx,
1804 ::parsePythonCode(codeOutIntf,scopeName,input,isExampleBlock,exampleName,
1805 fileDef,startLine,endLine,inlineFragment,memberDef,
1806 showLineNumbers,searchCtx,collectXRefs);
1809 void PythonLanguageScanner::parsePrototype(const char *text)
1811 ::parsePrototype(text);
1815 void PythonLanguageScanner::resetCodeParserState()
1817 ::resetPythonCodeParserState();
1820 //----------------------------------------------------------------------------
1822 #if !defined(YY_FLEX_SUBMINOR_VERSION)
1823 //----------------------------------------------------------------------------
1824 extern "C" { // some bogus code to keep the compiler happy
1825 void pyscannerYYdummy() { yy_flex_realloc(0,0); }