SF.net SVN: geany: [2308] trunk

eht16 at users.sourceforge.net eht16 at xxxxx
Wed Mar 5 18:18:24 UTC 2008


Revision: 2308
          http://geany.svn.sourceforge.net/geany/?rev=2308&view=rev
Author:   eht16
Date:     2008-03-05 10:18:19 -0800 (Wed, 05 Mar 2008)

Log Message:
-----------
Backport js.c and asm.c from CTags SVN.
Fix Assembler tagmanager support and add appropriate symbol types.
Fix JavaScript parse bug (#1895242).
Change default return value of lookupKeyword() in keyword.c as it was done in CTags SVN(r339) and adjust affected parsers.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/src/symbols.c
    trunk/tagmanager/asm.c
    trunk/tagmanager/c.c
    trunk/tagmanager/fortran.c
    trunk/tagmanager/js.c
    trunk/tagmanager/keyword.c

Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/ChangeLog	2008-03-05 18:18:19 UTC (rev 2308)
@@ -6,6 +6,13 @@
    from this feature.
  * src/document.c:
    Don't open zero byte sized files read-only (e.g. files in /proc).
+ * src/symbols.c, tagmanager/fortran.c, tagmanager/keyword.c,
+   tagmanager/js.c, tagmanager/asm.c, tagmanager/c.c:
+   Backport js.c and asm.c from CTags SVN.
+   Fix Assembler tagmanager support and add appropriate symbol types.
+   Fix JavaScript parse bug (#1895242).
+   Change default return value of lookupKeyword() in keyword.c as it was
+   done in CTags SVN(r339) and adjust affected parsers.
 
 
 2008-03-03  Enrico Tröger  <enrico(dot)troeger(at)uvena(dot)de>

Modified: trunk/src/symbols.c
===================================================================
--- trunk/src/symbols.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/src/symbols.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -718,6 +718,16 @@
 				NULL);
 			break;
 		}
+		case GEANY_FILETYPES_ASM:
+		{
+			tag_list_add_groups(tag_store,
+				&(tv_iters.tag_namespace), _("Labels"), "classviewer-namespace",
+				&(tv_iters.tag_function), _("Macros"), "classviewer-method",
+				&(tv_iters.tag_macro), _("Defines"), "classviewer-macro",
+				&(tv_iters.tag_struct), _("Types"), "classviewer-struct",
+				NULL);
+			break;
+		}
 		case GEANY_FILETYPES_D:
 		default:
 		{

Modified: trunk/tagmanager/asm.c
===================================================================
--- trunk/tagmanager/asm.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/tagmanager/asm.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -1,6 +1,7 @@
 /*
+*   $Id$
 *
-*   Copyright (c) 2000-2001, Darren Hiebert
+*   Copyright (c) 2000-2003, Darren Hiebert
 *
 *   This source code is released for free distribution under the terms of the
 *   GNU General Public License.
@@ -12,94 +13,374 @@
 /*
 *   INCLUDE FILES
 */
-#include "general.h"	/* must always come first */
+#include "general.h"  /* must always come first */
 
 #include <string.h>
 
+#include "keyword.h"
 #include "parse.h"
 #include "read.h"
+#include "main.h"
 #include "vstring.h"
 
 /*
-*   DATA DEFINITIONS
+*   DATA DECLARATIONS
 */
 typedef enum {
-    K_DEFINE, K_LABEL, K_MACRO
-} asmKind;
+	K_NONE = -1, K_DEFINE, K_LABEL, K_MACRO, K_TYPE
+} AsmKind;
 
-/* indexed by asmKind */
+typedef enum {
+	OP_UNDEFINED = -1,
+	OP_ALIGN,
+	OP_COLON_EQUAL,
+	OP_END,
+	OP_ENDM,
+	OP_ENDMACRO,
+	OP_ENDP,
+	OP_ENDS,
+	OP_EQU,
+	OP_EQUAL,
+	OP_LABEL,
+	OP_MACRO,
+	OP_PROC,
+	OP_RECORD,
+	OP_SECTIONS,
+	OP_SET,
+	OP_STRUCT,
+	OP_LAST
+} opKeyword;
+
+typedef struct {
+	const char *operator;
+	opKeyword keyword;
+} asmKeyword;
+
+typedef struct {
+	opKeyword keyword;
+	AsmKind kind;
+} opKind;
+
+/*
+*   DATA DEFINITIONS
+*/
+static langType Lang_asm;
+
 static kindOption AsmKinds [] = {
-    { TRUE, 'd', "define", "defines (names assigned a specified value)"},
-    { TRUE, 'l', "label", "labels (names assigned an address)"},
-    { TRUE, 'm', "macro", "macros"}
+	{ TRUE, 'd', "macro", "defines" },
+	{ TRUE, 'l', "namespace",  "labels"  },
+	{ TRUE, 'm', "function",  "macros"  },
+	{ TRUE, 't', "struct",   "types (structs and records)"   }
 };
 
+static const asmKeyword AsmKeywords [] = {
+	{ "align",    OP_ALIGN       },
+	{ "endmacro", OP_ENDMACRO    },
+	{ "endm",     OP_ENDM        },
+	{ "end",      OP_END         },
+	{ "endp",     OP_ENDP        },
+	{ "ends",     OP_ENDS        },
+	{ "equ",      OP_EQU         },
+	{ "label",    OP_LABEL       },
+	{ "macro",    OP_MACRO       },
+	{ ":=",       OP_COLON_EQUAL },
+	{ "=",        OP_EQUAL       },
+	{ "proc",     OP_PROC        },
+	{ "record",   OP_RECORD      },
+	{ "sections", OP_SECTIONS    },
+	{ "set",      OP_SET         },
+	{ "struct",   OP_STRUCT      }
+};
+
+static const opKind OpKinds [] = {
+	/* must be ordered same as opKeyword enumeration */
+	{ OP_ALIGN,       K_NONE   },
+	{ OP_COLON_EQUAL, K_DEFINE },
+	{ OP_END,         K_NONE   },
+	{ OP_ENDM,        K_NONE   },
+	{ OP_ENDMACRO,    K_NONE   },
+	{ OP_ENDP,        K_NONE   },
+	{ OP_ENDS,        K_NONE   },
+	{ OP_EQU,         K_DEFINE },
+	{ OP_EQUAL,       K_DEFINE },
+	{ OP_LABEL,       K_LABEL  },
+	{ OP_MACRO,       K_MACRO  },
+	{ OP_PROC,        K_LABEL  },
+	{ OP_RECORD,      K_TYPE   },
+	{ OP_SECTIONS,    K_NONE   },
+	{ OP_SET,         K_DEFINE },
+	{ OP_STRUCT,      K_TYPE   }
+};
+
 /*
 *   FUNCTION DEFINITIONS
 */
+static void buildAsmKeywordHash (void)
+{
+	const size_t count = sizeof (AsmKeywords) / sizeof (AsmKeywords [0]);
+	size_t i;
+	for (i = 0  ;  i < count  ;  ++i)
+	{
+		const asmKeyword* const p = AsmKeywords + i;
+		addKeyword (p->operator, Lang_asm, (int) p->keyword);
+	}
+}
 
-/* Algorithm adapted from from GNU etags.
- * By Bob Weiner, Motorola Inc., 4/3/94
- * Unix and microcontroller assembly tag handling
- * look for '^ [a-zA-Z_.$] [a-zA_Z0-9_.$]*[: ^I^J]'
- */
-static void findAsmTags (void)
+static opKeyword analyzeOperator (const vString *const op)
 {
-    vString *name = vStringNew ();
-    const unsigned char *line;
+	vString *keyword = vStringNew ();
+	opKeyword result;
 
-    while ((line = fileReadLine ()) != NULL)
-    {
+	vStringCopyToLower (keyword, op);
+	result = (opKeyword) lookupKeyword (vStringValue (keyword), Lang_asm);
+	vStringDelete (keyword);
+	return result;
+}
+
+static boolean isInitialSymbolCharacter (int c)
+{
+	return (boolean) (c != '\0' && (isalpha (c) || strchr ("_$", c) != NULL));
+}
+
+static boolean isSymbolCharacter (int c)
+{
+	/* '?' character is allowed in AMD 29K family */
+	return (boolean) (c != '\0' && (isalnum (c) || strchr ("_$?", c) != NULL));
+}
+
+static boolean readPreProc (const unsigned char *const line)
+{
+	boolean result;
 	const unsigned char *cp = line;
-	int c = *cp;
-
-	/*  If first char is alphabetic or one of [_.$], test for colon
-	 *  following identifier.
-	 */
-	if (isalpha (c) || c == '_' || c == '.' || c == '$')
+	vString *name = vStringNew ();
+	while (isSymbolCharacter ((int) *cp))
 	{
-	    vStringPut (name, c);
-	    c = *++cp;
-	    while (isalnum (c) || c == '_' || c == '.' || c == '$')
-	    {
-		vStringPut (name, c);
-		c = *++cp;
-	    }
-	    vStringTerminate (name);
-	    while (isspace (c))
-		c = *++cp;
-	    if (c == ':')
-		makeSimpleTag (name, AsmKinds, K_LABEL);
-	    else if (c == '=' ||
-		     strncmp ((const char*) cp, "equ", (size_t) 3) == 0)
-		makeSimpleTag (name, AsmKinds, K_DEFINE);
-	    else if (strcmp (vStringValue (name), ".macro") == 0)
-	    {
+		vStringPut (name, *cp);
+		++cp;
+	}
+	vStringTerminate (name);
+	result = (boolean) (strcmp (vStringValue (name), "define") == 0);
+	if (result)
+	{
+		while (isspace ((int) *cp))
+			++cp;
 		vStringClear (name);
-		while (isalnum (c) || c == '_')
+		while (isSymbolCharacter ((int) *cp))
 		{
-		    vStringPut (name, c);
-		    c = *++cp;
+			vStringPut (name, *cp);
+			++cp;
 		}
 		vStringTerminate (name);
-		if (vStringLength (name) > 0)
-		    makeSimpleTag (name, AsmKinds, K_MACRO);
-	    }
-	    vStringClear (name);
+		makeSimpleTag (name, AsmKinds, K_DEFINE);
 	}
-    }
-    vStringDelete (name);
+	vStringDelete (name);
+	return result;
 }
 
+static AsmKind operatorKind (
+		const vString *const operator,
+		boolean *const found)
+{
+	AsmKind result = K_NONE;
+	const opKeyword kw = analyzeOperator (operator);
+	*found = (boolean) (kw != OP_UNDEFINED);
+	if (*found)
+	{
+		result = OpKinds [kw].kind;
+		Assert (OpKinds [kw].keyword == kw);
+	}
+	return result;
+}
+
+/*  We must check for "DB", "DB.L", "DCB.W" (68000)
+ */
+static boolean isDefineOperator (const vString *const operator)
+{
+	const unsigned char *const op =
+		(unsigned char*) vStringValue (operator);
+	const size_t length = vStringLength (operator);
+	const boolean result = (boolean) (length > 0  &&
+		toupper ((int) *op) == 'D'  &&
+		(length == 2 ||
+		 (length == 4  &&  (int) op [2] == '.') ||
+		 (length == 5  &&  (int) op [3] == '.')));
+	return result;
+}
+
+static void makeAsmTag (
+		const vString *const name,
+		const vString *const operator,
+		const boolean labelCandidate,
+		const boolean nameFollows)
+{
+	if (vStringLength (name) > 0)
+	{
+		boolean found;
+		const AsmKind kind = operatorKind (operator, &found);
+		if (found)
+		{
+			if (kind != K_NONE)
+				makeSimpleTag (name, AsmKinds, kind);
+		}
+		else if (isDefineOperator (operator))
+		{
+			if (! nameFollows)
+				makeSimpleTag (name, AsmKinds, K_DEFINE);
+		}
+		else if (labelCandidate)
+		{
+			operatorKind (name, &found);
+			if (! found)
+				makeSimpleTag (name, AsmKinds, K_LABEL);
+		}
+	}
+}
+
+static const unsigned char *readSymbol (
+		const unsigned char *const start,
+		vString *const sym)
+{
+	const unsigned char *cp = start;
+	vStringClear (sym);
+	if (isInitialSymbolCharacter ((int) *cp))
+	{
+		while (isSymbolCharacter ((int) *cp))
+		{
+			vStringPut (sym, *cp);
+			++cp;
+		}
+		vStringTerminate (sym);
+	}
+	return cp;
+}
+
+static const unsigned char *readOperator (
+		const unsigned char *const start,
+		vString *const operator)
+{
+	const unsigned char *cp = start;
+	vStringClear (operator);
+	while (*cp != '\0'  &&  ! isspace ((int) *cp))
+	{
+		vStringPut (operator, *cp);
+		++cp;
+	}
+	vStringTerminate (operator);
+	return cp;
+}
+
+static void findAsmTags (void)
+{
+	vString *name = vStringNew ();
+	vString *operator = vStringNew ();
+	const unsigned char *line;
+	boolean inCComment = FALSE;
+
+	while ((line = fileReadLine ()) != NULL)
+	{
+		const unsigned char *cp = line;
+		boolean labelCandidate = (boolean) (! isspace ((int) *cp));
+		boolean nameFollows = FALSE;
+		const boolean isComment = (boolean)
+				(*cp != '\0' && strchr (";*@", *cp) != NULL);
+
+		/* skip comments */
+		if (strncmp ((const char*) cp, "/*", (size_t) 2) == 0)
+		{
+			inCComment = TRUE;
+			cp += 2;
+		}
+		if (inCComment)
+		{
+			do
+			{
+				if (strncmp ((const char*) cp, "*/", (size_t) 2) == 0)
+				{
+					inCComment = FALSE;
+					cp += 2;
+					break;
+				}
+				++cp;
+			} while (*cp != '\0');
+		}
+		if (isComment || inCComment)
+			continue;
+
+		/* read preprocessor defines */
+		if (*cp == '#')
+		{
+			++cp;
+			readPreProc (cp);
+			continue;
+		}
+
+		/* skip white space */
+		while (isspace ((int) *cp))
+			++cp;
+
+		/* read symbol */
+		cp = readSymbol (cp, name);
+		if (vStringLength (name) > 0  &&  *cp == ':')
+		{
+			labelCandidate = TRUE;
+			++cp;
+		}
+
+		if (! isspace ((int) *cp)  &&  *cp != '\0')
+			continue;
+
+		/* skip white space */
+		while (isspace ((int) *cp))
+			++cp;
+
+		/* skip leading dot */
+#if 0
+		if (*cp == '.')
+			++cp;
+#endif
+
+		cp = readOperator (cp, operator);
+
+		/* attempt second read of symbol */
+		if (vStringLength (name) == 0)
+		{
+			while (isspace ((int) *cp))
+				++cp;
+			cp = readSymbol (cp, name);
+			nameFollows = TRUE;
+		}
+		makeAsmTag (name, operator, labelCandidate, nameFollows);
+	}
+	vStringDelete (name);
+	vStringDelete (operator);
+}
+
+static void initialize (const langType language)
+{
+	Lang_asm = language;
+	buildAsmKeywordHash ();
+}
+
 extern parserDefinition* AsmParser (void)
 {
-    static const char *const extensions [] = { "asm", "s", "S", NULL };
-    parserDefinition* def = parserNew ("ASM");
-    def->kinds      = AsmKinds;
-    def->kindCount  = KIND_COUNT (AsmKinds);
-    def->extensions = extensions;
-    def->parser     = findAsmTags;
-    return def;
+	static const char *const extensions [] = {
+		"asm", "ASM", "s", "S", NULL
+	};
+	static const char *const patterns [] = {
+		"*.A51",
+		"*.29[kK]",
+		"*.[68][68][kKsSxX]",
+		"*.[xX][68][68]",
+		NULL
+	};
+	parserDefinition* def = parserNew ("Asm");
+	def->kinds      = AsmKinds;
+	def->kindCount  = KIND_COUNT (AsmKinds);
+	def->extensions = extensions;
+	def->patterns   = patterns;
+	def->parser     = findAsmTags;
+	def->initialize = initialize;
+	return def;
 }
 
-/* vi:set tabstop=8 shiftwidth=4: */
+/* vi:set tabstop=4 shiftwidth=4: */

Modified: trunk/tagmanager/c.c
===================================================================
--- trunk/tagmanager/c.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/tagmanager/c.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -54,7 +54,7 @@
 /*  Used to specify type of keyword.
  */
 typedef enum eKeywordId {
-	KEYWORD_NONE,
+	KEYWORD_NONE = -1,
 	KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
 	KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
 	KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,

Modified: trunk/tagmanager/fortran.c
===================================================================
--- trunk/tagmanager/fortran.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/tagmanager/fortran.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -58,7 +58,7 @@
 /*  Used to specify type of keyword.
  */
 typedef enum eKeywordId {
-    KEYWORD_NONE,
+    KEYWORD_NONE = -1,
     KEYWORD_allocatable,
     KEYWORD_assignment,
     KEYWORD_block,

Modified: trunk/tagmanager/js.c
===================================================================
--- trunk/tagmanager/js.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/tagmanager/js.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -1,4 +1,6 @@
 /*
+ *	 $Id$
+ *
  *	 Copyright (c) 2003, Darren Hiebert
  *
  *	 This source code is released for free distribution under the terms of the
@@ -9,6 +11,8 @@
  *
  *	 This is a good reference for different forms of the function statement:
  *		 http://www.permadi.com/tutorial/jsFunc/
+ *   Another good reference:
+ *       http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide
  */
 
 /*
@@ -21,11 +25,10 @@
 #include <stdio.h>
 #endif
 
-#include "main.h"
-#include "entry.h"
 #include "keyword.h"
 #include "parse.h"
 #include "read.h"
+#include "main.h"
 #include "vstring.h"
 
 /*
@@ -52,6 +55,8 @@
 	KEYWORD_NONE = -1,
 	KEYWORD_function,
 	KEYWORD_capital_function,
+	KEYWORD_object,
+	KEYWORD_capital_object,
 	KEYWORD_prototype,
 	KEYWORD_var,
 	KEYWORD_new,
@@ -61,7 +66,10 @@
 	KEYWORD_do,
 	KEYWORD_if,
 	KEYWORD_else,
-	KEYWORD_switch
+	KEYWORD_switch,
+	KEYWORD_try,
+	KEYWORD_catch,
+	KEYWORD_finally
 } keywordId;
 
 /*	Used to determine whether keyword is valid for the token language and
@@ -88,17 +96,20 @@
 	TOKEN_OPEN_CURLY,
 	TOKEN_CLOSE_CURLY,
 	TOKEN_EQUAL_SIGN,
-	TOKEN_FORWARD_SLASH
+	TOKEN_FORWARD_SLASH,
+	TOKEN_OPEN_SQUARE,
+	TOKEN_CLOSE_SQUARE
 } tokenType;
 
 typedef struct sTokenInfo {
-	tokenType	type;
-	keywordId	keyword;
-	vString *	string;
-	vString *	scope;
-	unsigned long lineNumber;
-	fpos_t filePosition;
-	int			nestLevel;
+	tokenType		type;
+	keywordId		keyword;
+	vString *		string;
+	vString *		scope;
+	unsigned long 	lineNumber;
+	fpos_t 			filePosition;
+	int				nestLevel;
+	boolean			ignoreTag;
 } tokenInfo;
 
 /*
@@ -113,21 +124,25 @@
 	JSTAG_FUNCTION,
 	JSTAG_CLASS,
 	JSTAG_METHOD,
+	JSTAG_PROPERTY,
 	JSTAG_VARIABLE,
 	JSTAG_COUNT
 } jsKind;
 
 static kindOption JsKinds [] = {
-	{ TRUE,  'f', "function",	  "functions"			   },
+	{ TRUE,  'f', "function",	  "functions"		   },
 	{ TRUE,  'c', "class",		  "classes"			   },
 	{ TRUE,  'm', "method",		  "methods"			   },
-	{ TRUE,  'v', "variable",	  "global variables"	   }
+	{ TRUE,  'p', "property",	  "properties"		   },
+	{ TRUE,  'v', "variable",	  "global variables"   }
 };
 
 static const keywordDesc JsKeywordTable [] = {
 	/* keyword		keyword ID */
 	{ "function",	KEYWORD_function			},
 	{ "Function",	KEYWORD_capital_function	},
+	{ "object",		KEYWORD_object				},
+	{ "Object",		KEYWORD_capital_object		},
 	{ "prototype",	KEYWORD_prototype			},
 	{ "var",		KEYWORD_var					},
 	{ "new",		KEYWORD_new					},
@@ -137,7 +152,10 @@
 	{ "do",			KEYWORD_do					},
 	{ "if",			KEYWORD_if					},
 	{ "else",		KEYWORD_else				},
-	{ "switch",		KEYWORD_switch				}
+	{ "switch",		KEYWORD_switch				},
+	{ "try",		KEYWORD_try					},
+	{ "catch",		KEYWORD_catch				},
+	{ "finally",	KEYWORD_finally				}
 };
 
 /*
@@ -149,18 +167,6 @@
 static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent);
 static boolean parseLine (tokenInfo *const token, boolean is_inside_class);
 
-static boolean isIdentChar1 (const int c)
-{
-	/*
-	 * Other databases are less restrictive on the first character of
-	 * an identifier.
-	 * isIdentChar1 is used to identify the first character of an
-	 * identifier, so we are removing some restrictions.
-	 */
-	return (boolean)
-		(isalpha (c) || c == '@' || c == '_' );
-}
-
 static boolean isIdentChar (const int c)
 {
 	return (boolean)
@@ -189,6 +195,9 @@
 	token->string		= vStringNew ();
 	token->scope		= vStringNew ();
 	token->nestLevel	= 0;
+	token->ignoreTag	= FALSE;
+	token->lineNumber   = getSourceLineNumber ();
+	token->filePosition = getInputFilePosition ();
 
 	return token;
 }
@@ -206,7 +215,7 @@
 
 static void makeConstTag (tokenInfo *const token, const jsKind kind)
 {
-	if (JsKinds [kind].enabled)
+	if (JsKinds [kind].enabled && ! token->ignoreTag )
 	{
 		const char *const name = vStringValue (token->string);
 		tagEntryInfo e;
@@ -225,7 +234,7 @@
 {
 	vString *	fulltag;
 
-	if (JsKinds [kind].enabled)
+	if (JsKinds [kind].enabled && ! token->ignoreTag )
 	{
 		/*
 		 * If a scope has been added to the token, change the token
@@ -247,19 +256,25 @@
 
 static void makeClassTag (tokenInfo *const token)
 {
-	if ( ! stringListHas(ClassNames, vStringValue (token->string)) )
+	if ( ! token->ignoreTag )
 	{
-		stringListAdd (ClassNames, vStringNewCopy (token->string));
-		makeJsTag (token, JSTAG_CLASS);
+		if ( ! stringListHas(ClassNames, vStringValue (token->string)) )
+		{
+			stringListAdd (ClassNames, vStringNewCopy (token->string));
+			makeJsTag (token, JSTAG_CLASS);
+		}
 	}
 }
 
 static void makeFunctionTag (tokenInfo *const token)
 {
-	if ( ! stringListHas(FunctionNames, vStringValue (token->string)) )
+	if ( ! token->ignoreTag )
 	{
-		stringListAdd (FunctionNames, vStringNewCopy (token->string));
-		makeJsTag (token, JSTAG_FUNCTION);
+		if ( ! stringListHas(FunctionNames, vStringValue (token->string)) )
+		{
+			stringListAdd (FunctionNames, vStringNewCopy (token->string));
+			makeJsTag (token, JSTAG_FUNCTION);
+		}
 	}
 }
 
@@ -280,12 +295,16 @@
 static void parseString (vString *const string, const int delimiter)
 {
 	boolean end = FALSE;
-	int c;
 	while (! end)
 	{
-		c = fileGetc ();
+		int c = fileGetc ();
 		if (c == EOF)
 			end = TRUE;
+		else if (c == '\\')
+		{
+			c = fileGetc(); /* This maybe a ' or ". */
+			vStringPut(string, c);
+		}
 		else if (c == delimiter)
 			end = TRUE;
 		else
@@ -300,7 +319,7 @@
 static void parseIdentifier (vString *const string, const int firstChar)
 {
 	int c = firstChar;
-	Assert (isIdentChar1 (c));
+	Assert (isIdentChar (c));
 	do
 	{
 		vStringPut (string, c);
@@ -313,11 +332,12 @@
 
 static keywordId analyzeToken (vString *const name)
 {
-	static vString *keyword = NULL;
-	if (keyword == NULL)
-		keyword = vStringNew ();
+	vString *keyword = vStringNew ();
+	keywordId result;
 	vStringCopyToLower (keyword, name);
-	return (keywordId) lookupKeyword (vStringValue (keyword), Lang_js);
+	result = (keywordId) lookupKeyword (vStringValue (keyword), Lang_js);
+	vStringDelete (keyword);
+	return result;
 }
 
 static void readToken (tokenInfo *const token)
@@ -332,26 +352,25 @@
 	do
 	{
 		c = fileGetc ();
-		/*
-		 * Added " to the list of ignores, not sure what this
-		 * might break but it gets by this issue:
-		 *	  create table "t1" (...)
-		 */
+		token->lineNumber   = getSourceLineNumber ();
+		token->filePosition = getInputFilePosition ();
 	}
 	while (c == '\t'  ||  c == ' ' ||  c == '\n');
 
 	switch (c)
 	{
 		case EOF: longjmp (Exception, (int)ExceptionEOF);	break;
-		case '(': token->type = TOKEN_OPEN_PAREN;		break;
-		case ')': token->type = TOKEN_CLOSE_PAREN;		break;
-		case ';': token->type = TOKEN_SEMICOLON;		break;
-		case ',': token->type = TOKEN_COMMA;			break;
+		case '(': token->type = TOKEN_OPEN_PAREN;			break;
+		case ')': token->type = TOKEN_CLOSE_PAREN;			break;
+		case ';': token->type = TOKEN_SEMICOLON;			break;
+		case ',': token->type = TOKEN_COMMA;				break;
 		case '.': token->type = TOKEN_PERIOD;				break;
-		case ':': token->type = TOKEN_COLON;			break;
-		case '{': token->type = TOKEN_OPEN_CURLY;		break;
-		case '}': token->type = TOKEN_CLOSE_CURLY;		break;
+		case ':': token->type = TOKEN_COLON;				break;
+		case '{': token->type = TOKEN_OPEN_CURLY;			break;
+		case '}': token->type = TOKEN_CLOSE_CURLY;			break;
 		case '=': token->type = TOKEN_EQUAL_SIGN;			break;
+		case '[': token->type = TOKEN_OPEN_SQUARE;			break;
+		case ']': token->type = TOKEN_CLOSE_SQUARE;			break;
 
 		case '\'':
 		case '"':
@@ -361,6 +380,15 @@
 				  token->filePosition = getInputFilePosition ();
 				  break;
 
+		case '\\':
+				  c = fileGetc ();
+				  if (c != '\\'  && c != '"'  &&  !isspace (c))
+					  fileUngetc (c);
+				  token->type = TOKEN_CHARACTER;
+				  token->lineNumber = getSourceLineNumber ();
+				  token->filePosition = getInputFilePosition ();
+				  break;
+
 		case '/':
 				  {
 					  int d = fileGetc ();
@@ -395,7 +423,7 @@
 				  }
 
 		default:
-				  if (! isIdentChar1 (c))
+				  if (! isIdentChar (c))
 					  token->type = TOKEN_UNDEFINED;
 				  else
 				  {
@@ -460,6 +488,38 @@
 	}
 }
 
+static void skipArrayList (tokenInfo *const token)
+{
+	int nest_level = 0;
+
+	/*
+	 * Handle square brackets
+	 *	 var name[1]
+	 * So we must check for nested open and closing square brackets
+	 */
+
+	if (isType (token, TOKEN_OPEN_SQUARE))	/* arguments? */
+	{
+		nest_level++;
+		while (! (isType (token, TOKEN_CLOSE_SQUARE) && (nest_level == 0)))
+		{
+			readToken (token);
+			if (isType (token, TOKEN_OPEN_SQUARE))
+			{
+				nest_level++;
+			}
+			if (isType (token, TOKEN_CLOSE_SQUARE))
+			{
+				if (nest_level > 0)
+				{
+					nest_level--;
+				}
+			}
+		}
+		readToken (token);
+	}
+}
+
 static void addContext (tokenInfo* const parent, const tokenInfo* const child)
 {
 	if (vStringLength (parent->string) > 0)
@@ -498,6 +558,10 @@
 		{
 			parseBlock (token, token);
 		}
+		else if ( isType (token, TOKEN_OPEN_PAREN) )
+		{
+			skipArgumentList(token);
+		}
 		else
 		{
 			readToken (token);
@@ -632,22 +696,40 @@
 	}
 }
 
-static void parseIf (tokenInfo *const token)
+static boolean parseIf (tokenInfo *const token)
 {
+	boolean read_next_token = TRUE;
 	/*
 	 * If statements have two forms
 	 *	   if ( ... )
 	 *		   one line;
 	 *
+	 *	   if ( ... )
+	 *		  statement;
+	 *	   else
+	 *		  statement
+	 *
 	 *	   if ( ... ) {
 	 *		  multiple;
 	 *		  statements;
 	 *	   }
 	 *
+	 *
 	 *	   if ( ... ) {
 	 *		  return elem
 	 *	   }
 	 *
+	 *     This example if correctly written, but the
+	 *     else contains only 1 statement without a terminator
+	 *     since the function finishes with the closing brace.
+	 *
+     *     function a(flag){
+     *         if(flag)
+     *             test(1);
+     *         else
+     *             test(2)
+     *     }
+	 *
 	 * TODO:  Deal with statements that can optional end
 	 *		  without a semi-colon.  Currently this messes up
 	 *		  the parsing of blocks.
@@ -681,7 +763,39 @@
 	else
 	{
 		findCmdTerm (token);
+
+		/*
+		 * The IF could be followed by an ELSE statement.
+		 * This too could have two formats, a curly braced
+		 * multiline section, or another single line.
+		 */
+
+		if (isType (token, TOKEN_CLOSE_CURLY))
+		{
+			/*
+			 * This statement did not have a line terminator.
+			 */
+			read_next_token = FALSE;
+		}
+		else
+		{
+			readToken (token);
+
+			if (isType (token, TOKEN_CLOSE_CURLY))
+			{
+				/*
+				* This statement did not have a line terminator.
+				*/
+				read_next_token = FALSE;
+			}
+			else
+			{
+				if (isKeyword (token, KEYWORD_else))
+					read_next_token = parseIf (token);
+			}
+		}
 	}
+	return read_next_token;
 }
 
 static void parseFunction (tokenInfo *const token)
@@ -756,20 +870,19 @@
 			if (isKeyword (token, KEYWORD_this))
 			{
 				/*
-				 * Then we are inside a class and we have found
+				 * Means we are inside a class and have found
 				 * a class, not a function
 				 */
 				is_class = TRUE;
 				vStringCopy(saveScope, token->scope);
 				addToScope (token, parent->string);
-				/* Move past this */
-				readToken(token);
 
-				/* Move past a potential . */
-				if ( isType (token, TOKEN_PERIOD) )
-					readToken(token);
+				/*
+				 * Ignore the remainder of the line
+				 * findCmdTerm(token);
+				 */
+				parseLine (token, is_class);
 
-				parseLine (token, is_class);
 				vStringCopy(token->scope, saveScope);
 			}
 			else if (isKeyword (token, KEYWORD_var))
@@ -832,13 +945,15 @@
 
 	/*
 	 * This deals with these formats
-	 *	   'validMethod' : function(a,b) {}
+	 *	   validProperty  : 2,
+	 *	   validMethod    : function(a,b) {}
+	 *	   'validMethod2' : function(a,b) {}
 	 */
 
 	do
 	{
 		readToken (token);
-		if (isType (token, TOKEN_STRING))
+		if (isType (token, TOKEN_STRING) || isKeyword(token, KEYWORD_NONE))
 		{
 			copyToken(name, token);
 
@@ -862,11 +977,22 @@
 
 						/*
 						 * Read to the closing curly, check next
-						 * token, if comma, we must loop again
+						 * token, if a comma, we must loop again
 						 */
 						readToken (token);
 					}
 				}
+				else
+				{
+						addToScope (name, class->string);
+						makeJsTag (name, JSTAG_PROPERTY);
+
+						/*
+						 * Read the next token, if a comma
+						 * we must loop again
+						 */
+						readToken (token);
+				}
 			}
 		}
 	} while ( isType(token, TOKEN_COMMA) );
@@ -884,6 +1010,7 @@
 	boolean is_class = FALSE;
 	boolean is_terminated = TRUE;
 	boolean is_global = FALSE;
+	boolean is_prototype = FALSE;
 
 	vStringClear(saveScope);
 	/*
@@ -905,7 +1032,13 @@
 	 *		   'validMethodOne' : function(a,b) {},
 	 *		   'validMethodTwo' : function(a,b) {}
 	 *	   }
-	 *	   Database.prototype.getTodaysDate = Database_getTodaysDate;
+     *     ValidClassTwo = function ()
+     *     {
+     *         this.validMethodThree = function() {}
+     *         // unnamed method
+     *         this.validMethodFour = () {}
+     *     }
+	 *	   Database.prototype.validMethodThree = Database_getTodaysDate;
 	 */
 
 	if ( is_inside_class )
@@ -925,43 +1058,178 @@
 		readToken(token);
 	}
 
+	if ( isKeyword(token, KEYWORD_this) )
+	{
+		readToken(token);
+		if (isType (token, TOKEN_PERIOD))
+		{
+			readToken(token);
+		}
+	}
+
 	copyToken(name, token);
 
-	/* Potentially the name of the function */
-	readToken (token);
-	if (isType (token, TOKEN_PERIOD))
+	while (! isType (token, TOKEN_CLOSE_CURLY) &&
+	       ! isType (token, TOKEN_SEMICOLON)   &&
+	       ! isType (token, TOKEN_EQUAL_SIGN)  )
 	{
-		/*
-		 * Cannot be a global variable is it has dot references in the name
-		 */
-		is_global = FALSE;
-		do
+		/* Potentially the name of the function */
+		readToken (token);
+		if (isType (token, TOKEN_PERIOD))
 		{
-			readToken (token);
-			if ( isKeyword(token, KEYWORD_NONE) )
+			/*
+			 * Cannot be a global variable is it has dot references in the name
+			 */
+			is_global = FALSE;
+			do
 			{
-				if ( is_class )
+				readToken (token);
+				if ( isKeyword(token, KEYWORD_NONE) )
 				{
-					vStringCopy(saveScope, token->scope);
-					addToScope(token, name->string);
-					makeJsTag (token, JSTAG_METHOD);
+					if ( is_class )
+					{
+						vStringCopy(saveScope, token->scope);
+						addToScope(token, name->string);
+					}
+					else
+						addContext (name, token);
+				}
+				else if ( isKeyword(token, KEYWORD_prototype) )
+				{
+					/*
+					 * When we reach the "prototype" tag, we infer:
+					 *     "BindAgent" is a class
+					 *     "build"     is a method
+					 *
+					 * function BindAgent( repeatableIdName, newParentIdName ) {
+					 * }
+					 *
+					 * CASE 1
+					 * Specified function name: "build"
+					 *     BindAgent.prototype.build = function( mode ) {
+					 *     	  ignore everything within this function
+					 *     }
+					 *
+					 * CASE 2
+					 * Prototype listing
+					 *     ValidClassOne.prototype = {
+					 *         'validMethodOne' : function(a,b) {},
+					 *         'validMethodTwo' : function(a,b) {}
+					 *     }
+					 *
+					 */
+					makeClassTag (name);
+					is_class = TRUE;
+					is_prototype = TRUE;
 
-					/* Find to the end of the statement */
-					findCmdTerm (token);
-					goto cleanUp;
+					/*
+					 * There should a ".function_name" next.
+					 */
+					readToken (token);
+					if (isType (token, TOKEN_PERIOD))
+					{
+						/*
+						 * Handle CASE 1
+						 */
+						readToken (token);
+						if ( isKeyword(token, KEYWORD_NONE) )
+						{
+							vStringCopy(saveScope, token->scope);
+							addToScope(token, name->string);
+
+							makeJsTag (token, JSTAG_METHOD);
+							/*
+							 * We can read until the end of the block / statement.
+							 * We need to correctly parse any nested blocks, but
+							 * we do NOT want to create any tags based on what is
+							 * within the blocks.
+							 */
+							token->ignoreTag = TRUE;
+							/*
+							 * Find to the end of the statement
+							 */
+							findCmdTerm (token);
+							token->ignoreTag = FALSE;
+							is_terminated = TRUE;
+							goto cleanUp;
+						}
+					}
+					else if (isType (token, TOKEN_EQUAL_SIGN))
+					{
+						readToken (token);
+						if (isType (token, TOKEN_OPEN_CURLY))
+						{
+							/*
+							 * Handle CASE 2
+							 *
+							 * Creates tags for each of these class methods
+							 *     ValidClassOne.prototype = {
+							 *         'validMethodOne' : function(a,b) {},
+							 *         'validMethodTwo' : function(a,b) {}
+							 *     }
+							 */
+							parseMethods(token, name);
+							/*
+							 * Find to the end of the statement
+							 */
+							findCmdTerm (token);
+							token->ignoreTag = FALSE;
+							is_terminated = TRUE;
+							goto cleanUp;
+						}
+					}
 				}
-				else
-					addContext (name, token);
-			}
-			else if ( isKeyword(token, KEYWORD_prototype) )
-			{
-				makeClassTag (name);
-				is_class = TRUE;
-			}
-			readToken (token);
-		} while (isType (token, TOKEN_PERIOD));
+				readToken (token);
+			} while (isType (token, TOKEN_PERIOD));
+		}
+
+		if ( isType (token, TOKEN_OPEN_PAREN) )
+			skipArgumentList(token);
+
+		if ( isType (token, TOKEN_OPEN_SQUARE) )
+			skipArrayList(token);
+
+		/*
+		if ( isType (token, TOKEN_OPEN_CURLY) )
+		{
+			is_class = parseBlock (token, name);
+		}
+		*/
 	}
 
+	if ( isType (token, TOKEN_CLOSE_CURLY) )
+	{
+		/*
+		 * Reaching this section without having
+		 * processed an open curly brace indicates
+		 * the statement is most likely not terminated.
+		 */
+		is_terminated = FALSE;
+		goto cleanUp;
+	}
+
+	if ( isType (token, TOKEN_SEMICOLON) )
+	{
+		/*
+		 * Only create variables for global scope
+		 */
+		if ( token->nestLevel == 0 && is_global )
+		{
+			/*
+			 * Handles this syntax:
+			 *	   var g_var2;
+			 */
+			if (isType (token, TOKEN_SEMICOLON))
+				makeJsTag (name, JSTAG_VARIABLE);
+		}
+		/*
+		 * Statement has ended.
+		 * This deals with calls to functions, like:
+		 *     alert(..);
+		 */
+		goto cleanUp;
+	}
+
 	if ( isType (token, TOKEN_EQUAL_SIGN) )
 	{
 		readToken (token);
@@ -975,14 +1243,14 @@
 			{
 				/*
 				 * Functions of this format:
-				 *	   var D2A=function theAdd(a, b)
+				 *	   var D2A = function theAdd(a, b)
 				 *	   {
 				 *		  return a+b;
 				 *	   }
-				 * Are really two separately defined functions and
+				 * Are really two separate defined functions and
 				 * can be referenced in two ways:
-				 *	   alert(D2A(1,2));			  // produces 3
-				 *	   alert(theAdd(1,2));		  // also produces 3
+				 *	   alert( D2A(1,2) );			  // produces 3
+				 *	   alert( theAdd(1,2) );		  // also produces 3
 				 * So it must have two tags:
 				 *	   D2A
 				 *	   theAdd
@@ -1022,24 +1290,26 @@
 
 					if ( vStringLength(secondary_name->string) > 0 )
 						makeFunctionTag (secondary_name);
+
+					/*
+					 * Find to the end of the statement
+					 */
+					goto cleanUp;
 				}
 			}
 		}
 		else if (isType (token, TOKEN_OPEN_PAREN))
 		{
 			/*
-			 * Handle nameless functions, these will only
-			 * be considered methods.
+			 * Handle nameless functions
+			 *     this.method_name = () {}
 			 */
 			skipArgumentList(token);
 
 			if (isType (token, TOKEN_OPEN_CURLY))
 			{
 				/*
-				 * This will be either a function or a class.
-				 * We can only determine this by checking the body
-				 * of the function.  If we find a "this." we know
-				 * it is a class, otherwise it is a function.
+				 * Nameless functions are only setup as methods.
 				 */
 				makeJsTag (name, JSTAG_METHOD);
 				parseBlock (token, name);
@@ -1047,20 +1317,40 @@
 		}
 		else if (isType (token, TOKEN_OPEN_CURLY))
 		{
+			/*
+			 * Creates tags for each of these class methods
+			 *     ValidClassOne.prototype = {
+			 *         'validMethodOne' : function(a,b) {},
+			 *         'validMethodTwo' : function(a,b) {}
+			 *     }
+			 */
 			parseMethods(token, name);
 		}
 		else if (isKeyword (token, KEYWORD_new))
 		{
 			readToken (token);
 			if ( isKeyword (token, KEYWORD_function) ||
-					isKeyword (token, KEYWORD_capital_function) )
+					isKeyword (token, KEYWORD_capital_function) ||
+					isKeyword (token, KEYWORD_object) ||
+					isKeyword (token, KEYWORD_capital_object) )
 			{
+				if ( isKeyword (token, KEYWORD_object) ||
+						isKeyword (token, KEYWORD_capital_object) )
+					is_class = TRUE;
+
 				readToken (token);
 				if ( isType (token, TOKEN_OPEN_PAREN) )
 					skipArgumentList(token);
 
 				if (isType (token, TOKEN_SEMICOLON))
-					makeFunctionTag (name);
+				{
+					if ( is_class )
+					{
+						makeClassTag (name);
+					} else {
+						makeFunctionTag (name);
+					}
+				}
 			}
 		}
 		else if (isKeyword (token, KEYWORD_NONE))
@@ -1086,28 +1376,13 @@
 				if ( ! stringListHas(FunctionNames, vStringValue (token->string)) &&
 						! stringListHas(ClassNames, vStringValue (token->string)) )
 				{
-					readToken (token);
+					findCmdTerm (token);
 					if (isType (token, TOKEN_SEMICOLON))
 						makeJsTag (name, JSTAG_VARIABLE);
 				}
 			}
 		}
 	}
-	else
-	{
-		/*
-		 * Only create variables for global scope
-		 */
-		if ( token->nestLevel == 0 && is_global )
-		{
-			/*
-			 * Handles this syntax:
-			 *	   var g_var2;
-			 */
-			if (isType (token, TOKEN_SEMICOLON))
-				makeJsTag (name, JSTAG_VARIABLE);
-		}
-	}
 	findCmdTerm (token);
 
 	/*
@@ -1159,7 +1434,11 @@
 				break;
 			case KEYWORD_if:
 			case KEYWORD_else:
-				parseIf (token);
+			case KEYWORD_try:
+			case KEYWORD_catch:
+			case KEYWORD_finally:
+				/* Common semantics */
+				is_terminated = parseIf (token);
 				break;
 			case KEYWORD_switch:
 				parseSwitch (token);
@@ -1173,7 +1452,7 @@
 	{
 		/*
 		 * Special case where single line statements may not be
-		 * SEMICOLON termianted.  parseBlock needs to know this
+		 * SEMICOLON terminated.  parseBlock needs to know this
 		 * so that it does not read the next token.
 		 */
 		is_terminated = parseStatement (token, is_inside_class);
@@ -1212,10 +1491,12 @@
 static void findJsTags (void)
 {
 	tokenInfo *const token = newToken ();
-	exception_t exception = (exception_t) (setjmp (Exception));
+	exception_t exception;
+
 	ClassNames = stringListNew ();
 	FunctionNames = stringListNew ();
 
+	exception = (exception_t) (setjmp (Exception));
 	while (exception == ExceptionNone)
 		parseJsFile (token);
 
@@ -1230,8 +1511,7 @@
 extern parserDefinition* JavaScriptParser (void)
 {
 	static const char *const extensions [] = { "js", NULL };
-
-	parserDefinition *const def = parserNew ("Javascript");
+	parserDefinition *const def = parserNew ("JavaScript");
 	def->extensions = extensions;
 	/*
 	 * New definitions for parsing instead of regex
@@ -1243,5 +1523,4 @@
 
 	return def;
 }
-
 /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */

Modified: trunk/tagmanager/keyword.c
===================================================================
--- trunk/tagmanager/keyword.c	2008-03-05 17:34:00 UTC (rev 2307)
+++ trunk/tagmanager/keyword.c	2008-03-05 18:18:19 UTC (rev 2308)
@@ -162,7 +162,7 @@
 {
     const unsigned long hashedValue = hashValue (string);
     hashEntry *entry = getHashTableEntry (hashedValue);
-    int value = 0;
+    int value = -1;
 
     while (entry != NULL)
     {


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.



More information about the Commits mailing list