geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

geany_php.c
Go to the documentation of this file.
1/*
2* Copyright (c) 2013, Colomban Wendling <ban@herbesfolles.org>
3*
4* This source code is released for free distribution under the terms of the
5* GNU General Public License version 2 or (at your option) any later version.
6*
7* This module contains code for generating tags for the PHP scripting
8* language.
9*/
10
11/*
12* INCLUDE FILES
13*/
14#include "general.h" /* must always come first */
15#include "parse.h"
16#include "read.h"
17#include "vstring.h"
18#include "keyword.h"
19#include "entry.h"
20#include "routines.h"
21#include "debug.h"
22
23
24#define SCOPE_SEPARATOR "::"
25
26
27enum {
87};
88typedef int keywordId; /* to allow KEYWORD_NONE */
89
90typedef enum {
97
98typedef enum {
103
104typedef enum {
115
117 { true, 'c', "class", "classes" },
118 { true, 'd', "define", "constant definitions" },
119 { true, 'f', "function", "functions" },
120 { true, 'i', "interface", "interfaces" },
121 { false, 'l', "local", "local variables" },
122 { true, 'n', "namespace", "namespaces" },
123 { true, 't', "trait", "traits" },
124 { true, 'v', "variable", "variables" }
125};
126
128 /* keyword keyword ID */
129 { "abstract", KEYWORD_abstract },
130 { "and", KEYWORD_and },
131 { "as", KEYWORD_as },
132 { "break", KEYWORD_break },
133 { "callable", KEYWORD_callable },
134 { "case", KEYWORD_case },
135 { "catch", KEYWORD_catch },
136 { "cfunction", KEYWORD_function }, /* nobody knows what the hell this is, but it seems to behave much like "function" so bind it to it */
137 { "class", KEYWORD_class },
138 { "clone", KEYWORD_clone },
139 { "const", KEYWORD_const },
140 { "continue", KEYWORD_continue },
141 { "declare", KEYWORD_declare },
142 { "define", KEYWORD_define }, /* this isn't really a keyword but we handle it so it's easier this way */
143 { "default", KEYWORD_default },
144 { "do", KEYWORD_do },
145 { "echo", KEYWORD_echo },
146 { "else", KEYWORD_else },
147 { "elseif", KEYWORD_elif },
148 { "enddeclare", KEYWORD_enddeclare },
149 { "endfor", KEYWORD_endfor },
150 { "endforeach", KEYWORD_endforeach },
151 { "endif", KEYWORD_endif },
152 { "endswitch", KEYWORD_endswitch },
153 { "endwhile", KEYWORD_endwhile },
154 { "extends", KEYWORD_extends },
155 { "final", KEYWORD_final },
156 { "finally", KEYWORD_finally },
157 { "for", KEYWORD_for },
158 { "foreach", KEYWORD_foreach },
159 { "function", KEYWORD_function },
160 { "global", KEYWORD_global },
161 { "goto", KEYWORD_goto },
162 { "if", KEYWORD_if },
163 { "implements", KEYWORD_implements },
164 { "include", KEYWORD_include },
165 { "include_once", KEYWORD_include_once },
166 { "instanceof", KEYWORD_instanceof },
167 { "insteadof", KEYWORD_insteadof },
168 { "interface", KEYWORD_interface },
169 { "namespace", KEYWORD_namespace },
170 { "new", KEYWORD_new },
171 { "or", KEYWORD_or },
172 { "print", KEYWORD_print },
173 { "private", KEYWORD_private },
174 { "protected", KEYWORD_protected },
175 { "public", KEYWORD_public },
176 { "require", KEYWORD_require },
177 { "require_once", KEYWORD_require_once },
178 { "return", KEYWORD_return },
179 { "static", KEYWORD_static },
180 { "switch", KEYWORD_switch },
181 { "throw", KEYWORD_throw },
182 { "trait", KEYWORD_trait },
183 { "try", KEYWORD_try },
184 { "use", KEYWORD_use },
185 { "var", KEYWORD_var },
186 { "while", KEYWORD_while },
187 { "xor", KEYWORD_xor },
188 { "yield", KEYWORD_yield }
189};
190
191
192typedef enum eTokenType {
214
215typedef struct {
216 tokenType type;
218 vString * string;
219 vString * scope;
220 unsigned long lineNumber;
222 int parentKind; /* -1 if none */
223} tokenInfo;
224
227
228static bool InPhp = false; /* whether we are between <? ?> */
229
230/* current statement details */
231static struct {
235
236/* Current namespace */
238
239
240static const char *accessToString (const accessType access)
241{
242 static const char *const names[COUNT_ACCESS] = {
243 "undefined",
244 "private",
245 "protected",
246 "public"
247 };
248
250
251 return names[access];
252}
253
254static const char *implToString (const implType impl)
255{
256 static const char *const names[COUNT_IMPL] = {
257 "undefined",
258 "abstract"
259 };
260
262
263 return names[impl];
264}
265
266static void initPhpEntry (tagEntryInfo *const e, const tokenInfo *const token,
267 const phpKind kind, const accessType access)
268{
269 static vString *fullScope = NULL;
270 int parentKind = -1;
271
272 if (fullScope == NULL)
273 fullScope = vStringNew ();
274 else
275 vStringClear (fullScope);
276
278 {
279 vStringCopy (fullScope, CurrentNamespace);
280 parentKind = K_NAMESPACE;
281 }
282
283 initTagEntry (e, vStringValue (token->string), kind);
284
285 e->lineNumber = token->lineNumber;
286 e->filePosition = token->filePosition;
287
290 if (vStringLength (token->scope) > 0)
291 {
292 parentKind = token->parentKind;
293 if (vStringLength (fullScope) > 0)
294 vStringCatS (fullScope, SCOPE_SEPARATOR);
295 vStringCat (fullScope, token->scope);
296 }
297 if (vStringLength (fullScope) > 0)
298 {
299 Assert (parentKind >= 0);
300
301 e->extensionFields.scopeKindIndex = parentKind;
302 e->extensionFields.scopeName = vStringValue (fullScope);
303 }
304}
305
306static void makeSimplePhpTag (const tokenInfo *const token, const phpKind kind,
307 const accessType access)
308{
309 if (PhpKinds[kind].enabled)
310 {
311 tagEntryInfo e;
312
313 initPhpEntry (&e, token, kind, access);
314 makeTagEntry (&e);
315 }
316}
317
318static void makeNamespacePhpTag (const tokenInfo *const token, const vString *const name)
319{
320 if (PhpKinds[K_NAMESPACE].enabled)
321 {
322 tagEntryInfo e;
323
325
326 e.lineNumber = token->lineNumber;
327 e.filePosition = token->filePosition;
328
329 makeTagEntry (&e);
330 }
331}
332
333static void makeClassOrIfaceTag (const phpKind kind, const tokenInfo *const token,
334 vString *const inheritance, const implType impl)
335{
336 if (PhpKinds[kind].enabled)
337 {
338 tagEntryInfo e;
339
340 initPhpEntry (&e, token, kind, ACCESS_UNDEFINED);
341
342 if (impl != IMPL_UNDEFINED)
344 if (vStringLength (inheritance) > 0)
345 e.extensionFields.inheritance = vStringValue (inheritance);
346
347 makeTagEntry (&e);
348 }
349}
350
351static void makeFunctionTag (const tokenInfo *const token,
352 const vString *const arglist,
353 const accessType access, const implType impl)
354{
355 if (PhpKinds[K_FUNCTION].enabled)
356 {
357 tagEntryInfo e;
358
359 initPhpEntry (&e, token, K_FUNCTION, access);
360
361 if (impl != IMPL_UNDEFINED)
363 if (arglist)
365
366 makeTagEntry (&e);
367 }
368}
369
370static tokenInfo *newToken (void)
371{
372 tokenInfo *const token = xMalloc (1, tokenInfo);
373
374 token->type = TOKEN_UNDEFINED;
375 token->keyword = KEYWORD_NONE;
376 token->string = vStringNew ();
377 token->scope = vStringNew ();
378 token->lineNumber = getInputLineNumber ();
380 token->parentKind = -1;
381
382 return token;
383}
384
385static void deleteToken (tokenInfo *const token)
386{
387 vStringDelete (token->string);
388 vStringDelete (token->scope);
389 eFree (token);
390}
391
392static void copyToken (tokenInfo *const dest, const tokenInfo *const src,
393 bool scope)
394{
395 dest->lineNumber = src->lineNumber;
396 dest->filePosition = src->filePosition;
397 dest->type = src->type;
398 dest->keyword = src->keyword;
399 vStringCopy(dest->string, src->string);
400 dest->parentKind = src->parentKind;
401 if (scope)
402 vStringCopy(dest->scope, src->scope);
403}
404
405#if 0
406#include <stdio.h>
407
408static const char *tokenTypeName (const tokenType type)
409{
410 switch (type)
411 {
412 case TOKEN_UNDEFINED: return "undefined";
413 case TOKEN_EOF: return "EOF";
414 case TOKEN_CHARACTER: return "character";
415 case TOKEN_CLOSE_PAREN: return "')'";
416 case TOKEN_SEMICOLON: return "';'";
417 case TOKEN_COLON: return "':'";
418 case TOKEN_COMMA: return "','";
419 case TOKEN_OPEN_PAREN: return "'('";
420 case TOKEN_OPERATOR: return "operator";
421 case TOKEN_IDENTIFIER: return "identifier";
422 case TOKEN_KEYWORD: return "keyword";
423 case TOKEN_STRING: return "string";
424 case TOKEN_PERIOD: return "'.'";
425 case TOKEN_OPEN_CURLY: return "'{'";
426 case TOKEN_CLOSE_CURLY: return "'}'";
427 case TOKEN_EQUAL_SIGN: return "'='";
428 case TOKEN_OPEN_SQUARE: return "'['";
429 case TOKEN_CLOSE_SQUARE: return "']'";
430 case TOKEN_VARIABLE: return "variable";
431 }
432 return NULL;
433}
434
435static void printToken (const tokenInfo *const token)
436{
437 fprintf (stderr, "%p:\n\ttype:\t%s\n\tline:\t%lu\n\tscope:\t%s\n", (void *) token,
438 tokenTypeName (token->type),
439 token->lineNumber,
440 vStringValue (token->scope));
441 switch (token->type)
442 {
443 case TOKEN_IDENTIFIER:
444 case TOKEN_STRING:
445 case TOKEN_VARIABLE:
446 fprintf (stderr, "\tcontent:\t%s\n", vStringValue (token->string));
447 break;
448
449 case TOKEN_KEYWORD:
450 {
451 size_t n = ARRAY_SIZE (PhpKeywordTable);
452 size_t i;
453
454 fprintf (stderr, "\tkeyword:\t");
455 for (i = 0; i < n; i++)
456 {
457 if (PhpKeywordTable[i].id == token->keyword)
458 {
459 fprintf (stderr, "%s\n", PhpKeywordTable[i].name);
460 break;
461 }
462 }
463 if (i >= n)
464 fprintf (stderr, "(unknown)\n");
465 }
466
467 default: break;
468 }
469}
470#endif
471
472static void addToScope (tokenInfo *const token, const vString *const extra)
473{
474 if (vStringLength (token->scope) > 0)
476 vStringCatS (token->scope, vStringValue (extra));
477}
478
479static bool isIdentChar (const int c)
480{
481 return (isalnum (c) || c == '_' || c >= 0x80);
482}
483
484static void parseString (vString *const string, const int delimiter)
485{
486 while (true)
487 {
488 int c = getcFromInputFile ();
489
490 if (c == '\\' && (c = getcFromInputFile ()) != EOF)
491 vStringPut (string, (char) c);
492 else if (c == EOF || c == delimiter)
493 break;
494 else
495 vStringPut (string, (char) c);
496 }
497}
498
499/* reads an HereDoc or a NowDoc (the part after the <<<).
500 * <<<[ \t]*(ID|'ID'|"ID")
501 * ...
502 * ID;?
503 *
504 * note that:
505 * 1) starting ID must be immediately followed by a newline;
506 * 2) closing ID is the same as opening one;
507 * 3) closing ID must be immediately followed by a newline or a semicolon
508 * then a newline.
509 *
510 * Example of a *single* valid heredoc:
511 * <<< FOO
512 * something
513 * something else
514 * FOO this is not an end
515 * FOO; this isn't either
516 * FOO; # neither this is
517 * FOO;
518 * # previous line was the end, but the semicolon wasn't required
519 */
520static void parseHeredoc (vString *const string)
521{
522 int c;
523 unsigned int len;
524 char delimiter[64]; /* arbitrary limit, but more is crazy anyway */
525 int quote = 0;
526
527 do
528 {
529 c = getcFromInputFile ();
530 }
531 while (c == ' ' || c == '\t');
532
533 if (c == '\'' || c == '"')
534 {
535 quote = c;
536 c = getcFromInputFile ();
537 }
538 for (len = 0; len < ARRAY_SIZE (delimiter) - 1; len++)
539 {
540 if (! isIdentChar (c))
541 break;
542 delimiter[len] = (char) c;
543 c = getcFromInputFile ();
544 }
545 delimiter[len] = 0;
546
547 if (len == 0) /* no delimiter, give up */
548 goto error;
549 if (quote)
550 {
551 if (c != quote) /* no closing quote for quoted identifier, give up */
552 goto error;
553 c = getcFromInputFile ();
554 }
555 if (c != '\r' && c != '\n') /* missing newline, give up */
556 goto error;
557
558 do
559 {
560 c = getcFromInputFile ();
561
562 if (c != '\r' && c != '\n')
563 vStringPut (string, (char) c);
564 else
565 {
566 /* new line, check for a delimiter right after */
567 int nl = c;
568 int extra = EOF;
569
570 c = getcFromInputFile ();
571 for (len = 0; c != 0 && (c - delimiter[len]) == 0; len++)
572 c = getcFromInputFile ();
573
574 if (delimiter[len] != 0)
576 else
577 {
578 /* line start matched the delimiter, now check whether there
579 * is anything after it */
580 if (c == '\r' || c == '\n')
581 {
583 break;
584 }
585 else if (c == ';')
586 {
587 int d = getcFromInputFile ();
588 if (d == '\r' || d == '\n')
589 {
590 /* put back the semicolon since it's not part of the
591 * string. we can't put back the newline, but it's a
592 * whitespace character nobody cares about it anyway */
593 ungetcToInputFile (';');
594 break;
595 }
596 else
597 {
598 /* put semicolon in the string and continue */
599 extra = ';';
601 }
602 }
603 }
604 /* if we are here it wasn't a delimiter, so put everything in the
605 * string */
606 vStringPut (string, (char) nl);
607 vStringNCatS (string, delimiter, len);
608 if (extra != EOF)
609 vStringPut (string, (char) extra);
610 }
611 }
612 while (c != EOF);
613
614 return;
615
616error:
618}
619
620static void parseIdentifier (vString *const string, const int firstChar)
621{
622 int c = firstChar;
623 do
624 {
625 vStringPut (string, (char) c);
626 c = getcFromInputFile ();
627 } while (isIdentChar (c));
629}
630
631static keywordId analyzeToken (vString *const name, langType language)
632{
633 vString *keyword = vStringNew ();
634 keywordId result;
635 vStringCopyToLower (keyword, name);
636 result = lookupKeyword (vStringValue (keyword), language);
637 vStringDelete (keyword);
638 return result;
639}
640
641static bool isSpace (int c)
642{
643 return (c == '\t' || c == ' ' || c == '\v' ||
644 c == '\n' || c == '\r' || c == '\f');
645}
646
647static int skipWhitespaces (int c)
648{
649 while (isSpace (c))
650 c = getcFromInputFile ();
651 return c;
652}
653
654/* <script[:white:]+language[:white:]*=[:white:]*(php|'php'|"php")[:white:]*>
655 *
656 * This is ugly, but the whole "<script language=php>" tag is and we can't
657 * really do better without adding a lot of code only for this */
658static bool isOpenScriptLanguagePhp (int c)
659{
660 int quote = 0;
661
662 /* <script[:white:]+language[:white:]*= */
663 if (c != '<' ||
664 tolower ((c = getcFromInputFile ())) != 's' ||
665 tolower ((c = getcFromInputFile ())) != 'c' ||
666 tolower ((c = getcFromInputFile ())) != 'r' ||
667 tolower ((c = getcFromInputFile ())) != 'i' ||
668 tolower ((c = getcFromInputFile ())) != 'p' ||
669 tolower ((c = getcFromInputFile ())) != 't' ||
670 ! isSpace ((c = getcFromInputFile ())) ||
671 tolower ((c = skipWhitespaces (c))) != 'l' ||
672 tolower ((c = getcFromInputFile ())) != 'a' ||
673 tolower ((c = getcFromInputFile ())) != 'n' ||
674 tolower ((c = getcFromInputFile ())) != 'g' ||
675 tolower ((c = getcFromInputFile ())) != 'u' ||
676 tolower ((c = getcFromInputFile ())) != 'a' ||
677 tolower ((c = getcFromInputFile ())) != 'g' ||
678 tolower ((c = getcFromInputFile ())) != 'e' ||
679 (c = skipWhitespaces (getcFromInputFile ())) != '=')
680 return false;
681
682 /* (php|'php'|"php")> */
684 if (c == '"' || c == '\'')
685 {
686 quote = c;
687 c = getcFromInputFile ();
688 }
689 if (tolower (c) != 'p' ||
690 tolower ((c = getcFromInputFile ())) != 'h' ||
691 tolower ((c = getcFromInputFile ())) != 'p' ||
692 (quote != 0 && (c = getcFromInputFile ()) != quote) ||
693 (c = skipWhitespaces (getcFromInputFile ())) != '>')
694 return false;
695
696 return true;
697}
698
699static int findPhpStart (void)
700{
701 int c;
702 do
703 {
704 if ((c = getcFromInputFile ()) == '<')
705 {
706 c = getcFromInputFile ();
707 /* <? and <?php, but not <?xml */
708 if (c == '?')
709 {
710 /* don't enter PHP mode on "<?xml", yet still support short open tags (<?) */
711 if (tolower ((c = getcFromInputFile ())) != 'x' ||
712 tolower ((c = getcFromInputFile ())) != 'm' ||
713 tolower ((c = getcFromInputFile ())) != 'l')
714 {
715 break;
716 }
717 }
718 /* <script language="php"> */
719 else
720 {
722 if (isOpenScriptLanguagePhp ('<'))
723 break;
724 }
725 }
726 }
727 while (c != EOF);
728
729 return c;
730}
731
732static int skipSingleComment (void)
733{
734 int c;
735 do
736 {
737 c = getcFromInputFile ();
738 if (c == '\r')
739 {
740 int next = getcFromInputFile ();
741 if (next != '\n')
742 ungetcToInputFile (next);
743 else
744 c = next;
745 }
746 /* ?> in single-line comments leaves PHP mode */
747 else if (c == '?')
748 {
749 int next = getcFromInputFile ();
750 if (next == '>')
751 InPhp = false;
752 else
753 ungetcToInputFile (next);
754 }
755 } while (InPhp && c != EOF && c != '\n' && c != '\r');
756 return c;
757}
758
759static void readToken (tokenInfo *const token)
760{
761 int c;
762
763 token->type = TOKEN_UNDEFINED;
764 token->keyword = KEYWORD_NONE;
765 vStringClear (token->string);
766
767getNextChar:
768
769 if (! InPhp)
770 {
771 c = findPhpStart ();
772 if (c != EOF)
773 InPhp = true;
774 }
775 else
776 c = getcFromInputFile ();
777
778 c = skipWhitespaces (c);
779
780 token->lineNumber = getInputLineNumber ();
782
783 switch (c)
784 {
785 case EOF: token->type = TOKEN_EOF; break;
786 case '(': token->type = TOKEN_OPEN_PAREN; break;
787 case ')': token->type = TOKEN_CLOSE_PAREN; break;
788 case ';': token->type = TOKEN_SEMICOLON; break;
789 case ',': token->type = TOKEN_COMMA; break;
790 case '.': token->type = TOKEN_PERIOD; break;
791 case ':': token->type = TOKEN_COLON; break;
792 case '{': token->type = TOKEN_OPEN_CURLY; break;
793 case '}': token->type = TOKEN_CLOSE_CURLY; break;
794 case '[': token->type = TOKEN_OPEN_SQUARE; break;
795 case ']': token->type = TOKEN_CLOSE_SQUARE; break;
796 case '&': token->type = TOKEN_AMPERSAND; break;
797
798 case '=':
799 {
800 int d = getcFromInputFile ();
801 if (d == '=' || d == '>')
802 token->type = TOKEN_OPERATOR;
803 else
804 {
806 token->type = TOKEN_EQUAL_SIGN;
807 }
808 break;
809 }
810
811 case '\'':
812 case '"':
813 token->type = TOKEN_STRING;
814 parseString (token->string, c);
815 token->lineNumber = getInputLineNumber ();
817 break;
818
819 case '<':
820 {
821 int d = getcFromInputFile ();
822 if (d == '/')
823 {
824 /* </script[:white:]*> */
825 if (tolower ((d = getcFromInputFile ())) == 's' &&
826 tolower ((d = getcFromInputFile ())) == 'c' &&
827 tolower ((d = getcFromInputFile ())) == 'r' &&
828 tolower ((d = getcFromInputFile ())) == 'i' &&
829 tolower ((d = getcFromInputFile ())) == 'p' &&
830 tolower ((d = getcFromInputFile ())) == 't' &&
831 (d = skipWhitespaces (getcFromInputFile ())) == '>')
832 {
833 InPhp = false;
834 goto getNextChar;
835 }
836 else
837 {
839 token->type = TOKEN_UNDEFINED;
840 }
841 }
842 else if (d == '<' && (d = getcFromInputFile ()) == '<')
843 {
844 token->type = TOKEN_STRING;
845 parseHeredoc (token->string);
846 }
847 else
848 {
850 token->type = TOKEN_UNDEFINED;
851 }
852 break;
853 }
854
855 case '#': /* comment */
857 goto getNextChar;
858 break;
859
860 case '+':
861 case '-':
862 case '*':
863 case '%':
864 {
865 int d = getcFromInputFile ();
866 if (d != '=')
868 token->type = TOKEN_OPERATOR;
869 break;
870 }
871
872 case '/': /* division or comment start */
873 {
874 int d = getcFromInputFile ();
875 if (d == '/') /* single-line comment */
876 {
878 goto getNextChar;
879 }
880 else if (d == '*')
881 {
882 do
883 {
885 if (c != EOF)
886 {
887 c = getcFromInputFile ();
888 if (c == '/')
889 break;
890 else
892 }
893 } while (c != EOF && c != '\0');
894 goto getNextChar;
895 }
896 else
897 {
898 if (d != '=')
900 token->type = TOKEN_OPERATOR;
901 }
902 break;
903 }
904
905 case '$': /* variable start */
906 {
907 int d = getcFromInputFile ();
908 if (! isIdentChar (d))
909 {
911 token->type = TOKEN_UNDEFINED;
912 }
913 else
914 {
915 parseIdentifier (token->string, d);
916 token->type = TOKEN_VARIABLE;
917 }
918 break;
919 }
920
921 case '?': /* maybe the end of the PHP chunk */
922 {
923 int d = getcFromInputFile ();
924 if (d == '>')
925 {
926 InPhp = false;
927 goto getNextChar;
928 }
929 else
930 {
932 token->type = TOKEN_UNDEFINED;
933 }
934 break;
935 }
936
937 default:
938 if (! isIdentChar (c))
939 token->type = TOKEN_UNDEFINED;
940 else
941 {
942 parseIdentifier (token->string, c);
943 token->keyword = analyzeToken (token->string, getInputLanguage ());
944 if (token->keyword == KEYWORD_NONE)
945 token->type = TOKEN_IDENTIFIER;
946 else
947 token->type = TOKEN_KEYWORD;
948 }
949 break;
950 }
951
952 if (token->type == TOKEN_SEMICOLON ||
953 token->type == TOKEN_OPEN_CURLY ||
954 token->type == TOKEN_CLOSE_CURLY)
955 {
956 /* reset current statement details on statement end, and when entering
957 * a deeper scope.
958 * it is a bit ugly to do this in readToken(), but it makes everything
959 * a lot simpler. */
962 }
963}
964
965static void enterScope (tokenInfo *const parentToken,
966 const vString *const extraScope,
967 const int parentKind);
968
969/* parses a class or an interface:
970 * class Foo {}
971 * class Foo extends Bar {}
972 * class Foo extends Bar implements iFoo, iBar {}
973 * interface iFoo {}
974 * interface iBar extends iFoo {} */
975static bool parseClassOrIface (tokenInfo *const token, const phpKind kind)
976{
977 bool readNext = true;
980 vString *inheritance = NULL;
981
982 readToken (token);
983 if (token->type != TOKEN_IDENTIFIER)
984 return false;
985
986 name = newToken ();
987 copyToken (name, token, true);
988
989 inheritance = vStringNew ();
990 /* skip until the open bracket and assume every identifier (not keyword)
991 * is an inheritance (like in "class Foo extends Bar implements iA, iB") */
992 do
993 {
994 readToken (token);
995
996 if (token->type == TOKEN_IDENTIFIER)
997 {
998 if (vStringLength (inheritance) > 0)
999 vStringPut (inheritance, ',');
1000 vStringCat (inheritance, token->string);
1001 }
1002 }
1003 while (token->type != TOKEN_EOF &&
1004 token->type != TOKEN_OPEN_CURLY);
1005
1006 makeClassOrIfaceTag (kind, name, inheritance, impl);
1007
1008 if (token->type == TOKEN_OPEN_CURLY)
1009 enterScope (token, name->string, K_CLASS);
1010 else
1011 readNext = false;
1012
1013 deleteToken (name);
1014 vStringDelete (inheritance);
1015
1016 return readNext;
1017}
1018
1019/* parses a trait:
1020 * trait Foo {} */
1021static bool parseTrait (tokenInfo *const token)
1022{
1023 bool readNext = true;
1024 tokenInfo *name;
1025
1026 readToken (token);
1027 if (token->type != TOKEN_IDENTIFIER)
1028 return false;
1029
1030 name = newToken ();
1031 copyToken (name, token, true);
1032
1034
1035 readToken (token);
1036 if (token->type == TOKEN_OPEN_CURLY)
1037 enterScope (token, name->string, K_TRAIT);
1038 else
1039 readNext = false;
1040
1041 deleteToken (name);
1042
1043 return readNext;
1044}
1045
1046/* parse a function
1047 *
1048 * if @name is NULL, parses a normal function
1049 * function myfunc($foo, $bar) {}
1050 * function &myfunc($foo, $bar) {}
1051 *
1052 * if @name is not NULL, parses an anonymous function with name @name
1053 * $foo = function($foo, $bar) {}
1054 * $foo = function&($foo, $bar) {}
1055 * $foo = function($foo, $bar) use ($x, &$y) {} */
1056static bool parseFunction (tokenInfo *const token, const tokenInfo *name)
1057{
1058 bool readNext = true;
1061 tokenInfo *nameFree = NULL;
1062
1063 readToken (token);
1064 /* skip a possible leading ampersand (return by reference) */
1065 if (token->type == TOKEN_AMPERSAND)
1066 readToken (token);
1067
1068 if (! name)
1069 {
1070 if (token->type != TOKEN_IDENTIFIER)
1071 return false;
1072
1073 name = nameFree = newToken ();
1074 copyToken (nameFree, token, true);
1075 readToken (token);
1076 }
1077
1078 if (token->type == TOKEN_OPEN_PAREN)
1079 {
1080 vString *arglist = vStringNew ();
1081 int depth = 1;
1082
1083 vStringPut (arglist, '(');
1084 do
1085 {
1086 readToken (token);
1087
1088 switch (token->type)
1089 {
1090 case TOKEN_OPEN_PAREN: depth++; break;
1091 case TOKEN_CLOSE_PAREN: depth--; break;
1092 default: break;
1093 }
1094 /* display part */
1095 switch (token->type)
1096 {
1097 case TOKEN_AMPERSAND: vStringPut (arglist, '&'); break;
1098 case TOKEN_CLOSE_CURLY: vStringPut (arglist, '}'); break;
1099 case TOKEN_CLOSE_PAREN: vStringPut (arglist, ')'); break;
1100 case TOKEN_CLOSE_SQUARE: vStringPut (arglist, ']'); break;
1101 case TOKEN_COLON: vStringPut (arglist, ':'); break;
1102 case TOKEN_COMMA: vStringCatS (arglist, ", "); break;
1103 case TOKEN_EQUAL_SIGN: vStringCatS (arglist, " = "); break;
1104 case TOKEN_OPEN_CURLY: vStringPut (arglist, '{'); break;
1105 case TOKEN_OPEN_PAREN: vStringPut (arglist, '('); break;
1106 case TOKEN_OPEN_SQUARE: vStringPut (arglist, '['); break;
1107 case TOKEN_PERIOD: vStringPut (arglist, '.'); break;
1108 case TOKEN_SEMICOLON: vStringPut (arglist, ';'); break;
1109 case TOKEN_STRING: vStringCatS (arglist, "'...'"); break;
1110
1111 case TOKEN_IDENTIFIER:
1112 case TOKEN_KEYWORD:
1113 case TOKEN_VARIABLE:
1114 {
1115 switch (vStringLast (arglist))
1116 {
1117 case 0:
1118 case ' ':
1119 case '{':
1120 case '(':
1121 case '[':
1122 case '.':
1123 /* no need for a space between those and the identifier */
1124 break;
1125
1126 default:
1127 vStringPut (arglist, ' ');
1128 break;
1129 }
1130 if (token->type == TOKEN_VARIABLE)
1131 vStringPut (arglist, '$');
1132 vStringCat (arglist, token->string);
1133 break;
1134 }
1135
1136 default: break;
1137 }
1138 }
1139 while (token->type != TOKEN_EOF && depth > 0);
1140
1141 makeFunctionTag (name, arglist, access, impl);
1142 vStringDelete (arglist);
1143
1144 readToken (token); /* normally it's an open brace or "use" keyword */
1145 }
1146
1147 /* if parsing Zephir, skip function return type hint */
1148 if (getInputLanguage () == Lang_zephir && token->type == TOKEN_OPERATOR)
1149 {
1150 do
1151 readToken (token);
1152 while (token->type != TOKEN_EOF &&
1153 token->type != TOKEN_OPEN_CURLY &&
1154 token->type != TOKEN_CLOSE_CURLY &&
1155 token->type != TOKEN_SEMICOLON);
1156 }
1157
1158 /* skip use(...) */
1159 if (token->type == TOKEN_KEYWORD && token->keyword == KEYWORD_use)
1160 {
1161 readToken (token);
1162 if (token->type == TOKEN_OPEN_PAREN)
1163 {
1164 int depth = 1;
1165
1166 do
1167 {
1168 readToken (token);
1169 switch (token->type)
1170 {
1171 case TOKEN_OPEN_PAREN: depth++; break;
1172 case TOKEN_CLOSE_PAREN: depth--; break;
1173 default: break;
1174 }
1175 }
1176 while (token->type != TOKEN_EOF && depth > 0);
1177
1178 readToken (token);
1179 }
1180 }
1181
1182 if (token->type == TOKEN_OPEN_CURLY)
1183 enterScope (token, name->string, K_FUNCTION);
1184 else
1185 readNext = false;
1186
1187 if (nameFree)
1188 deleteToken (nameFree);
1189
1190 return readNext;
1191}
1192
1193/* parses declarations of the form
1194 * const NAME = VALUE */
1195static bool parseConstant (tokenInfo *const token)
1196{
1197 tokenInfo *name;
1198
1199 readToken (token); /* skip const keyword */
1200 if (token->type != TOKEN_IDENTIFIER)
1201 return false;
1202
1203 name = newToken ();
1204 copyToken (name, token, true);
1205
1206 readToken (token);
1207 if (token->type == TOKEN_EQUAL_SIGN)
1209
1210 deleteToken (name);
1211
1212 return token->type == TOKEN_EQUAL_SIGN;
1213}
1214
1215/* parses declarations of the form
1216 * define('NAME', 'VALUE')
1217 * define(NAME, 'VALUE) */
1218static bool parseDefine (tokenInfo *const token)
1219{
1220 int depth = 1;
1221
1222 readToken (token); /* skip "define" identifier */
1223 if (token->type != TOKEN_OPEN_PAREN)
1224 return false;
1225
1226 readToken (token);
1227 if (token->type == TOKEN_STRING ||
1228 token->type == TOKEN_IDENTIFIER)
1229 {
1231 readToken (token);
1232 }
1233
1234 /* skip until the close parenthesis.
1235 * no need to handle nested blocks since they would be invalid
1236 * in this context anyway (the VALUE may only be a scalar, like
1237 * 42
1238 * (42)
1239 * and alike) */
1240 while (token->type != TOKEN_EOF && depth > 0)
1241 {
1242 switch (token->type)
1243 {
1244 case TOKEN_OPEN_PAREN: depth++; break;
1245 case TOKEN_CLOSE_PAREN: depth--; break;
1246 default: break;
1247 }
1248 readToken (token);
1249 }
1250
1251 return false;
1252}
1253
1254/* parses declarations of the form
1255 * $var = VALUE
1256 * $var; */
1257static bool parseVariable (tokenInfo *const token)
1258{
1259 tokenInfo *name;
1260 bool readNext = true;
1262
1263 name = newToken ();
1264 copyToken (name, token, true);
1265
1266 readToken (token);
1267 if (token->type == TOKEN_EQUAL_SIGN)
1268 {
1269 phpKind kind = K_VARIABLE;
1270
1271 if (token->parentKind == K_FUNCTION)
1272 kind = K_LOCAL_VARIABLE;
1273
1274 readToken (token);
1275 if (token->type == TOKEN_KEYWORD &&
1276 token->keyword == KEYWORD_function &&
1277 PhpKinds[kind].enabled)
1278 {
1279 if (parseFunction (token, name))
1280 readToken (token);
1281 readNext = (bool) (token->type == TOKEN_SEMICOLON);
1282 }
1283 else
1284 {
1285 makeSimplePhpTag (name, kind, access);
1286 readNext = false;
1287 }
1288 }
1289 else if (token->type == TOKEN_SEMICOLON)
1290 {
1291 /* generate tags for variable declarations in classes
1292 * class Foo {
1293 * protected $foo;
1294 * }
1295 * but don't get fooled by stuff like $foo = $bar; */
1296 if (token->parentKind == K_CLASS || token->parentKind == K_INTERFACE)
1298 }
1299 else
1300 readNext = false;
1301
1302 deleteToken (name);
1303
1304 return readNext;
1305}
1306
1307/* parses namespace declarations
1308 * namespace Foo {}
1309 * namespace Foo\Bar {}
1310 * namespace Foo;
1311 * namespace Foo\Bar;
1312 * namespace;
1313 * napespace {} */
1314static bool parseNamespace (tokenInfo *const token)
1315{
1316 tokenInfo *nsToken = newToken ();
1317
1319 copyToken (nsToken, token, false);
1320
1321 do
1322 {
1323 readToken (token);
1324 if (token->type == TOKEN_IDENTIFIER)
1325 {
1329 }
1330 }
1331 while (token->type != TOKEN_EOF &&
1332 token->type != TOKEN_SEMICOLON &&
1333 token->type != TOKEN_OPEN_CURLY);
1334
1337
1338 if (token->type == TOKEN_OPEN_CURLY)
1339 enterScope (token, NULL, -1);
1340
1341 deleteToken (nsToken);
1342
1343 return true;
1344}
1345
1346static void enterScope (tokenInfo *const parentToken,
1347 const vString *const extraScope,
1348 const int parentKind)
1349{
1350 tokenInfo *token = newToken ();
1351 int origParentKind = parentToken->parentKind;
1352
1353 copyToken (token, parentToken, true);
1354
1355 if (extraScope)
1356 {
1357 addToScope (token, extraScope);
1358 token->parentKind = parentKind;
1359 }
1360
1361 readToken (token);
1362 while (token->type != TOKEN_EOF &&
1363 token->type != TOKEN_CLOSE_CURLY)
1364 {
1365 bool readNext = true;
1366
1367 switch (token->type)
1368 {
1369 case TOKEN_OPEN_CURLY:
1370 enterScope (token, NULL, -1);
1371 break;
1372
1373 case TOKEN_KEYWORD:
1374 switch (token->keyword)
1375 {
1376 case KEYWORD_class: readNext = parseClassOrIface (token, K_CLASS); break;
1377 case KEYWORD_interface: readNext = parseClassOrIface (token, K_INTERFACE); break;
1378 case KEYWORD_trait: readNext = parseTrait (token); break;
1379 case KEYWORD_function: readNext = parseFunction (token, NULL); break;
1380 case KEYWORD_const: readNext = parseConstant (token); break;
1381 case KEYWORD_define: readNext = parseDefine (token); break;
1382
1383 case KEYWORD_namespace: readNext = parseNamespace (token); break;
1384
1385 case KEYWORD_private: CurrentStatement.access = ACCESS_PRIVATE; break;
1387 case KEYWORD_public: CurrentStatement.access = ACCESS_PUBLIC; break;
1388 case KEYWORD_var: CurrentStatement.access = ACCESS_PUBLIC; break;
1389
1391
1392 default: break;
1393 }
1394 break;
1395
1396 case TOKEN_VARIABLE:
1397 readNext = parseVariable (token);
1398 break;
1399
1400 default: break;
1401 }
1402
1403 if (readNext)
1404 readToken (token);
1405 }
1406
1407 copyToken (parentToken, token, false);
1408 parentToken->parentKind = origParentKind;
1409 deleteToken (token);
1410}
1411
1412static void findTags (void)
1413{
1414 tokenInfo *const token = newToken ();
1415
1419
1420 do
1421 {
1422 enterScope (token, NULL, -1);
1423 }
1424 while (token->type != TOKEN_EOF); /* keep going even with unmatched braces */
1425
1427 deleteToken (token);
1428}
1429
1430static void findPhpTags (void)
1431{
1432 InPhp = false;
1433 findTags ();
1434}
1435
1436static void findZephirTags (void)
1437{
1438 InPhp = true;
1439 findTags ();
1440}
1441
1442static void initializePhpParser (const langType language)
1443{
1444 Lang_php = language;
1445}
1446
1447static void initializeZephirParser (const langType language)
1448{
1449 Lang_zephir = language;
1450}
1451
1453{
1454 static const char *const extensions [] = { "php", "php3", "php4", "php5", "phtml", NULL };
1455 parserDefinition* def = parserNew ("PHP");
1456 def->kindTable = PhpKinds;
1457 def->kindCount = ARRAY_SIZE (PhpKinds);
1458 def->extensions = extensions;
1459 def->parser = findPhpTags;
1463 return def;
1464}
1465
1467{
1468 static const char *const extensions [] = { "zep", NULL };
1469 parserDefinition* def = parserNew ("Zephir");
1470 def->kindTable = PhpKinds;
1471 def->kindCount = ARRAY_SIZE (PhpKinds);
1472 def->extensions = extensions;
1473 def->parser = findZephirTags;
1477 return def;
1478}
#define Assert(c)
Definition: debug.h:47
const gchar * name
Definition: document.c:3219
int makeTagEntry(const tagEntryInfo *const tag)
Definition: entry.c:1675
void initTagEntry(tagEntryInfo *const e, const char *const name, int kindIndex)
Definition: entry.c:1823
void error(const errorSelection selection, const char *const format,...)
Definition: error.c:53
eTokenType
Definition: geany_bibtex.c:63
unsigned long int lineNumber
Definition: geany_cobol.c:134
MIOPos filePosition
Definition: geany_cobol.c:135
tokenType
Definition: geany_css.c:42
static vString * scope
Definition: geany_go.c:78
keywordId
Definition: geany_html.c:44
static void initializeZephirParser(const langType language)
Definition: geany_php.c:1447
static void findPhpTags(void)
Definition: geany_php.c:1430
static vString * CurrentNamespace
Definition: geany_php.c:237
#define SCOPE_SEPARATOR
Definition: geany_php.c:24
static void enterScope(tokenInfo *const parentToken, const vString *const extraScope, const int parentKind)
Definition: geany_php.c:1346
implType impl
Definition: geany_php.c:233
static bool parseDefine(tokenInfo *const token)
Definition: geany_php.c:1218
static int skipSingleComment(void)
Definition: geany_php.c:732
static const char * accessToString(const accessType access)
Definition: geany_php.c:240
static tokenInfo * newToken(void)
Definition: geany_php.c:370
static void parseHeredoc(vString *const string)
Definition: geany_php.c:520
parserDefinition * ZephirParser(void)
Definition: geany_php.c:1466
static bool InPhp
Definition: geany_php.c:228
static void findZephirTags(void)
Definition: geany_php.c:1436
static bool parseNamespace(tokenInfo *const token)
Definition: geany_php.c:1314
static keywordId analyzeToken(vString *const name, langType language)
Definition: geany_php.c:631
static void initializePhpParser(const langType language)
Definition: geany_php.c:1442
static langType Lang_php
Definition: geany_php.c:225
@ TOKEN_CLOSE_CURLY
Definition: geany_php.c:207
@ TOKEN_KEYWORD
Definition: geany_php.c:200
@ TOKEN_OPEN_CURLY
Definition: geany_php.c:206
@ TOKEN_CLOSE_SQUARE
Definition: geany_php.c:210
@ TOKEN_UNDEFINED
Definition: geany_php.c:193
@ TOKEN_OPEN_SQUARE
Definition: geany_php.c:209
@ TOKEN_CLOSE_PAREN
Definition: geany_php.c:196
@ TOKEN_IDENTIFIER
Definition: geany_php.c:203
@ TOKEN_CHARACTER
Definition: geany_php.c:195
@ TOKEN_COMMA
Definition: geany_php.c:199
@ TOKEN_COLON
Definition: geany_php.c:198
@ TOKEN_EQUAL_SIGN
Definition: geany_php.c:208
@ TOKEN_EOF
Definition: geany_php.c:194
@ TOKEN_AMPERSAND
Definition: geany_php.c:212
@ TOKEN_PERIOD
Definition: geany_php.c:205
@ TOKEN_OPEN_PAREN
Definition: geany_php.c:201
@ TOKEN_SEMICOLON
Definition: geany_php.c:197
@ TOKEN_OPERATOR
Definition: geany_php.c:202
@ TOKEN_VARIABLE
Definition: geany_php.c:211
@ TOKEN_STRING
Definition: geany_php.c:204
accessType
Definition: geany_php.c:90
@ ACCESS_PROTECTED
Definition: geany_php.c:93
@ ACCESS_PRIVATE
Definition: geany_php.c:92
@ ACCESS_PUBLIC
Definition: geany_php.c:94
@ COUNT_ACCESS
Definition: geany_php.c:95
@ ACCESS_UNDEFINED
Definition: geany_php.c:91
parserDefinition * PhpParser(void)
Definition: geany_php.c:1452
static int skipWhitespaces(int c)
Definition: geany_php.c:647
static void deleteToken(tokenInfo *const token)
Definition: geany_php.c:385
static void makeFunctionTag(const tokenInfo *const token, const vString *const arglist, const accessType access, const implType impl)
Definition: geany_php.c:351
enum eTokenType tokenType
static bool isOpenScriptLanguagePhp(int c)
Definition: geany_php.c:658
accessType access
Definition: geany_php.c:232
static void makeNamespacePhpTag(const tokenInfo *const token, const vString *const name)
Definition: geany_php.c:318
static void addToScope(tokenInfo *const token, const vString *const extra)
Definition: geany_php.c:472
static void copyToken(tokenInfo *const dest, const tokenInfo *const src, bool scope)
Definition: geany_php.c:392
@ KEYWORD_public
Definition: geany_php.c:73
@ KEYWORD_echo
Definition: geany_php.c:43
@ KEYWORD_insteadof
Definition: geany_php.c:65
@ KEYWORD_include_once
Definition: geany_php.c:63
@ KEYWORD_enddeclare
Definition: geany_php.c:46
@ KEYWORD_var
Definition: geany_php.c:83
@ KEYWORD_for
Definition: geany_php.c:55
@ KEYWORD_interface
Definition: geany_php.c:66
@ KEYWORD_namespace
Definition: geany_php.c:67
@ KEYWORD_and
Definition: geany_php.c:29
@ KEYWORD_private
Definition: geany_php.c:71
@ KEYWORD_endif
Definition: geany_php.c:49
@ KEYWORD_yield
Definition: geany_php.c:86
@ KEYWORD_static
Definition: geany_php.c:77
@ KEYWORD_function
Definition: geany_php.c:57
@ KEYWORD_endfor
Definition: geany_php.c:47
@ KEYWORD_clone
Definition: geany_php.c:36
@ KEYWORD_else
Definition: geany_php.c:44
@ KEYWORD_finally
Definition: geany_php.c:54
@ KEYWORD_implements
Definition: geany_php.c:61
@ KEYWORD_define
Definition: geany_php.c:40
@ KEYWORD_elif
Definition: geany_php.c:45
@ KEYWORD_throw
Definition: geany_php.c:79
@ KEYWORD_default
Definition: geany_php.c:41
@ KEYWORD_require
Definition: geany_php.c:74
@ KEYWORD_while
Definition: geany_php.c:84
@ KEYWORD_new
Definition: geany_php.c:68
@ KEYWORD_endforeach
Definition: geany_php.c:48
@ KEYWORD_foreach
Definition: geany_php.c:56
@ KEYWORD_extends
Definition: geany_php.c:52
@ KEYWORD_trait
Definition: geany_php.c:80
@ KEYWORD_endswitch
Definition: geany_php.c:50
@ KEYWORD_break
Definition: geany_php.c:31
@ KEYWORD_endwhile
Definition: geany_php.c:51
@ KEYWORD_protected
Definition: geany_php.c:72
@ KEYWORD_do
Definition: geany_php.c:42
@ KEYWORD_try
Definition: geany_php.c:81
@ KEYWORD_use
Definition: geany_php.c:82
@ KEYWORD_const
Definition: geany_php.c:37
@ KEYWORD_goto
Definition: geany_php.c:59
@ KEYWORD_print
Definition: geany_php.c:70
@ KEYWORD_if
Definition: geany_php.c:60
@ KEYWORD_as
Definition: geany_php.c:30
@ KEYWORD_abstract
Definition: geany_php.c:28
@ KEYWORD_global
Definition: geany_php.c:58
@ KEYWORD_final
Definition: geany_php.c:53
@ KEYWORD_class
Definition: geany_php.c:35
@ KEYWORD_callable
Definition: geany_php.c:32
@ KEYWORD_instanceof
Definition: geany_php.c:64
@ KEYWORD_case
Definition: geany_php.c:33
@ KEYWORD_catch
Definition: geany_php.c:34
@ KEYWORD_return
Definition: geany_php.c:76
@ KEYWORD_or
Definition: geany_php.c:69
@ KEYWORD_switch
Definition: geany_php.c:78
@ KEYWORD_xor
Definition: geany_php.c:85
@ KEYWORD_continue
Definition: geany_php.c:38
@ KEYWORD_require_once
Definition: geany_php.c:75
@ KEYWORD_include
Definition: geany_php.c:62
@ KEYWORD_declare
Definition: geany_php.c:39
static void findTags(void)
Definition: geany_php.c:1412
static void parseString(vString *const string, const int delimiter)
Definition: geany_php.c:484
static void makeSimplePhpTag(const tokenInfo *const token, const phpKind kind, const accessType access)
Definition: geany_php.c:306
static int findPhpStart(void)
Definition: geany_php.c:699
static bool parseTrait(tokenInfo *const token)
Definition: geany_php.c:1021
static void makeClassOrIfaceTag(const phpKind kind, const tokenInfo *const token, vString *const inheritance, const implType impl)
Definition: geany_php.c:333
static void parseIdentifier(vString *const string, const int firstChar)
Definition: geany_php.c:620
phpKind
Definition: geany_php.c:104
@ K_VARIABLE
Definition: geany_php.c:112
@ K_TRAIT
Definition: geany_php.c:111
@ K_INTERFACE
Definition: geany_php.c:108
@ K_DEFINE
Definition: geany_php.c:106
@ COUNT_KIND
Definition: geany_php.c:113
@ K_CLASS
Definition: geany_php.c:105
@ K_FUNCTION
Definition: geany_php.c:107
@ K_NAMESPACE
Definition: geany_php.c:110
@ K_LOCAL_VARIABLE
Definition: geany_php.c:109
static bool parseVariable(tokenInfo *const token)
Definition: geany_php.c:1257
static const char * implToString(const implType impl)
Definition: geany_php.c:254
static void initPhpEntry(tagEntryInfo *const e, const tokenInfo *const token, const phpKind kind, const accessType access)
Definition: geany_php.c:266
static bool isIdentChar(const int c)
Definition: geany_php.c:479
static kindDefinition PhpKinds[COUNT_KIND]
Definition: geany_php.c:116
static bool parseFunction(tokenInfo *const token, const tokenInfo *name)
Definition: geany_php.c:1056
static struct @25 CurrentStatement
static bool parseConstant(tokenInfo *const token)
Definition: geany_php.c:1195
int keywordId
Definition: geany_php.c:88
static bool parseClassOrIface(tokenInfo *const token, const phpKind kind)
Definition: geany_php.c:975
implType
Definition: geany_php.c:98
@ COUNT_IMPL
Definition: geany_php.c:101
@ IMPL_ABSTRACT
Definition: geany_php.c:100
@ IMPL_UNDEFINED
Definition: geany_php.c:99
static bool isSpace(int c)
Definition: geany_php.c:641
static const keywordTable PhpKeywordTable[]
Definition: geany_php.c:127
static langType Lang_zephir
Definition: geany_php.c:226
static void readToken(tokenInfo *const token)
Definition: geany_php.c:759
int lookupKeyword(const char *const string, langType language)
Definition: keyword.c:160
#define KEYWORD_NONE
Definition: keyword.h:21
parserDefinition * parserNew(const char *name)
Definition: parse.c:237
#define NULL
Definition: rbtree.h:150
unsigned long getInputLineNumber(void)
Definition: read.c:142
int getcFromInputFile(void)
Definition: read.c:923
langType getInputLanguage(void)
Definition: read.c:196
MIOPos getInputFilePosition(void)
Definition: read.c:161
void ungetcToInputFile(int c)
Definition: read.c:813
int skipToCharacterInInputFile(int c)
Definition: read.c:972
void eFree(void *const ptr)
Definition: routines.c:252
#define xMalloc(n, Type)
Definition: routines.h:23
#define ARRAY_SIZE(X)
Definition: routines.h:27
MIOPos:
Definition: mio.h:101
bool enabled
Definition: kind.h:72
parserInitialize initialize
Definition: parse.h:81
const char *const * extensions
Definition: parse.h:78
simpleParser parser
Definition: parse.h:83
const keywordTable * keywordTable
Definition: parse.h:93
kindDefinition * kindTable
Definition: parse.h:76
unsigned int kindCount
Definition: parse.h:77
unsigned int keywordCount
Definition: parse.h:94
struct sTagEntryInfo::@3 extensionFields
const char * implementation
Definition: entry.h:71
MIOPos filePosition
Definition: entry.h:60
const char * access
Definition: entry.h:69
unsigned long lineNumber
Definition: entry.h:56
int scopeKindIndex
Definition: entry.h:78
const char * inheritance
Definition: entry.h:72
const char * signature
Definition: entry.h:85
const char * scopeName
Definition: entry.h:79
int parentKind
Definition: geany_php.c:222
tokenType type
Definition: geany_css.c:50
vString * string
Definition: geany_css.c:51
vString * scope
Definition: geany_json.c:59
MIOPos filePosition
Definition: geany_json.c:61
unsigned long lineNumber
Definition: geany_json.c:60
keywordId keyword
Definition: geany_php.c:217
struct sTokenInfo tokenInfo
int langType
Definition: types.h:13
void vStringNCatS(vString *const string, const char *const s, const size_t length)
Definition: vstring.c:124
vString * vStringNew(void)
Definition: vstring.c:70
void vStringDelete(vString *const string)
Definition: vstring.c:60
void vStringCatS(vString *const string, const char *const s)
Definition: vstring.c:146
void vStringCopyToLower(vString *const dest, const vString *const src)
Definition: vstring.c:233
void vStringCat(vString *const string, const vString *const s)
Definition: vstring.c:139
void vStringCopy(vString *const string, const vString *const s)
Definition: vstring.c:207
#define vStringClear(string)
Definition: vstring.h:36
#define vStringLength(vs)
Definition: vstring.h:31
#define vStringValue(vs)
Definition: vstring.h:28
static void vStringPut(vString *const string, const int c)
Definition: vstring.h:101
#define vStringLast(vs)
Definition: vstring.h:30