📄 jscript.c
字号:
*/ if ( is_inside_class ) is_class = TRUE; /* * var can preceed an inner function */ if ( isKeyword(token, KEYWORD_var) ) { /* * Only create variables for global scope */ if ( token->nestLevel == 0 ) { is_global = TRUE; } readToken(token); } if ( isKeyword(token, KEYWORD_this) ) { readToken(token); if (isType (token, TOKEN_PERIOD)) { readToken(token); } } copyToken(name, token); while (! isType (token, TOKEN_CLOSE_CURLY) && ! isType (token, TOKEN_SEMICOLON) && ! isType (token, TOKEN_EQUAL_SIGN) ) { /* Potentially the name of the function */ readToken (token); if (isType (token, TOKEN_PERIOD)) { /* * Cannot be a global variable is it has dot references in the name */ is_global = FALSE; do { readToken (token); if ( isKeyword(token, KEYWORD_NONE) ) { 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; /* * 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; } } } 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); if ( isKeyword (token, KEYWORD_function) ) { readToken (token); if ( isKeyword (token, KEYWORD_NONE) && ! isType (token, TOKEN_OPEN_PAREN) ) { /* * Functions of this format: * var D2A = function theAdd(a, b) * { * return a+b; * } * 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 * So it must have two tags: * D2A * theAdd * Save the reference to the name for later use, once * we have established this is a valid function we will * create the secondary reference to it. */ copyToken(secondary_name, token); readToken (token); } if ( isType (token, TOKEN_OPEN_PAREN) ) 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. */ if ( is_inside_class ) { makeJsTag (name, JSTAG_METHOD); if ( vStringLength(secondary_name->string) > 0 ) makeFunctionTag (secondary_name); parseBlock (token, name); } else { is_class = parseBlock (token, name); if ( is_class ) makeClassTag (name); else makeFunctionTag (name); 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 * this.method_name = () {} */ skipArgumentList(token); if (isType (token, TOKEN_OPEN_CURLY)) { /* * Nameless functions are only setup as methods. */ makeJsTag (name, JSTAG_METHOD); parseBlock (token, name); } } 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_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)) { if ( is_class ) { makeClassTag (name); } else { makeFunctionTag (name); } } } } else if (isKeyword (token, KEYWORD_NONE)) { /* * Only create variables for global scope */ if ( token->nestLevel == 0 && is_global ) { /* * A pointer can be created to the function. * If we recognize the function/class name ignore the variable. * This format looks identical to a variable definition. * A variable defined outside of a block is considered * a global variable: * var g_var1 = 1; * var g_var2; * This is not a global variable: * var g_var = function; * This is a global variable: * var g_var = different_var_name; */ if ( ! stringListHas(FunctionNames, vStringValue (token->string)) && ! stringListHas(ClassNames, vStringValue (token->string)) ) { findCmdTerm (token); if (isType (token, TOKEN_SEMICOLON)) makeJsTag (name, JSTAG_VARIABLE); } } } } findCmdTerm (token); /* * Statements can be optionally terminated in the case of * statement prior to a close curly brace as in the * document.write line below: * * function checkForUpdate() { * if( 1==1 ) { * document.write("hello from checkForUpdate<br>") * } * return 1; * } */ if (isType (token, TOKEN_CLOSE_CURLY)) is_terminated = FALSE;cleanUp: vStringCopy(token->scope, saveScope); deleteToken (name); deleteToken (secondary_name); vStringDelete(saveScope); return is_terminated;}static boolean parseLine (tokenInfo *const token, boolean is_inside_class){ boolean is_terminated = TRUE; /* * Detect the common statements, if, while, for, do, ... * This is necessary since the last statement within a block "{}" * can be optionally terminated. * * If the statement is not terminated, we need to tell * the calling routine to prevent reading an additional token * looking for the end of the statement. */ if (isType(token, TOKEN_KEYWORD)) { switch (token->keyword) { case KEYWORD_for: case KEYWORD_while: case KEYWORD_do: parseLoop (token); break; case KEYWORD_if: case KEYWORD_else: case KEYWORD_try: case KEYWORD_catch: case KEYWORD_finally: /* Common semantics */ parseIf (token); break; case KEYWORD_switch: parseSwitch (token); break; default: parseStatement (token, is_inside_class); break; } } else { /* * Special case where single line statements may not be * SEMICOLON termianted. parseBlock needs to know this * so that it does not read the next token. */ is_terminated = parseStatement (token, is_inside_class); } return is_terminated;}static void parseJsFile (tokenInfo *const token){ do { readToken (token); if (isType(token, TOKEN_KEYWORD)) { switch (token->keyword) { case KEYWORD_function: parseFunction (token); break; default: parseLine (token, FALSE); break; } } else { parseLine (token, FALSE); } } while (TRUE);}static void initialize (const langType language){ Assert (sizeof (JsKinds) / sizeof (JsKinds [0]) == JSTAG_COUNT); Lang_js = language; buildJsKeywordHash ();}static void findJsTags (void){ tokenInfo *const token = newToken (); exception_t exception; ClassNames = stringListNew (); FunctionNames = stringListNew (); exception = (exception_t) (setjmp (Exception)); while (exception == ExceptionNone) parseJsFile (token); stringListDelete (ClassNames); stringListDelete (FunctionNames); ClassNames = NULL; FunctionNames = NULL; deleteToken (token);}/* Create parser definition stucture */extern parserDefinition* JavaScriptParser (void){ static const char *const extensions [] = { "js", NULL }; parserDefinition *const def = parserNew ("JavaScript"); def->extensions = extensions; /* * New definitions for parsing instead of regex */ def->kinds = JsKinds; def->kindCount = KIND_COUNT (JsKinds); def->parser = findJsTags; def->initialize = initialize; return def;}/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -