void addScopeToScopeStack(DbgRsScope& stack, exec_list *scope, void* mem_ctx) { if (!scope) return; foreach_in_list(scope_item, sc_item, scope) addToScope(stack, sc_item, mem_ctx); }
/** Declare a symbol in a scope. @param scope The scope to add the symbol to. @param key The symbol. @param data The data to be associated with the symbol. @return A boolean that indicates whether the @a declare action was successful. The difference from the @a addToScope function is that @a declare checks that the symbol does not already exist in the @a scope, while @a addToScope blindly adds the symbol. If memory for the new data item cannot be allocated, the function will not return. */ bool declare(Scope *scope, const char *key, void *data) { if (lookup(scope, key)) return false; addToScope(scope, key, data); return true; }
/* Impl format: * "impl" [<type_bounds>] <qualified_ident>[<type_bounds>] ["for" <qualified_ident>[<type_bounds>]] "{" [<body>] "}" */ static void parseImpl (lexerState *lexer, vString *scope, int parent_kind) { unsigned long line; fpos_t pos; vString *name; advanceToken(lexer, TRUE); line = lexer->line; pos = lexer->pos; skipTypeBlock(lexer); name = vStringNew(); parseQualifiedType(lexer, name); if (lexer->cur_token == TOKEN_IDENT && strcmp(lexer->token_str->buffer, "for") == 0) { advanceToken(lexer, TRUE); parseQualifiedType(lexer, name); } addTag(name, NULL, K_IMPL, line, pos, scope, parent_kind); addToScope(scope, name); parseBlock(lexer, TRUE, K_IMPL, scope); vStringDelete(name); }
bool ast_debugvar_traverser_visitor::enter(class ast_declaration* node) { ShVariable* var = findShVariable(node->debug_id); assert(var); VPRINT(3, "%c%sdeclaration of %s <%i>%c%s\n", ESC_CHAR, ESC_BOLD, node->identifier, var->uniqueId, ESC_CHAR, ESC_RESET); // Add variable to the global list of all seen variables addShVariableCtx(vl, var, var->builtin, shader); if (node->initializer) { node->initializer->accept(this); exec_list* scope = &node->initializer->scope; (void)scope; /* * Actually do not add declared variable to the list here, because * Code Generation would access the data before it is declared. This should * not be needed anyway, since the data would be uninitialized * // Dont forget to check for double ids scopeList::iterator e = find(sl->begin(), sl->end(), v->getUniqueId()); // Finally at it to the list if (e == sl->end()) { sl->push_back(v->getUniqueId()); } */ } // Now add the list to the actual scope and proceed addToScope(var); dumpScope(); return false; }
void setDbgScope(DbgRsScope& scope, exec_list *s, void* mem_ctx) { assert(s || !"no scopeList"); VPRINT(3, "SET GLOBAL SCOPE LIST: "); foreach_in_list(scope_item, item, s) { addToScope(scope, item, mem_ctx); VPRINT(3, "<%i,%s> ", item->id, item->name); }
ast_debugvar_traverser_visitor::ast_debugvar_traverser_visitor(AstShader* _sh, ShVariableList* _vl) : vl(_vl), shader(_sh) { for(int i = 0; i < _sh->globals.numVariables; ++i) { ShVariable* var = _sh->globals.variables[i]; addShVariableCtx(vl, var, var->builtin, _sh); addToScope(var); } }
/* Mod format: * "mod" <ident> "{" [<body>] "}" * "mod" <ident> ";"*/ static void parseMod (lexerState *lexer, vString *scope, int parent_kind) { advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) return; addTag(lexer->token_str, NULL, K_MOD, lexer->line, lexer->pos, scope, parent_kind); addToScope(scope, lexer->token_str); advanceToken(lexer, TRUE); parseBlock(lexer, TRUE, K_MOD, scope); }
bool ast_debugvar_traverser_visitor::enter(class ast_parameter_declarator* node) { // No variable when void if (node->is_void) return false; ShVariable* var = findShVariable(node->debug_id); assert(var); VPRINT(3, "%c%sparameter %s <%i> %c%s\n", ESC_CHAR, ESC_BOLD, node->identifier, var->uniqueId, ESC_CHAR, ESC_RESET); addShVariableCtx(vl, var, var->builtin, shader); addToScope(var); dumpScope(); return false; }
static void parseFunction (tokenInfo *const token) { tokenInfo *const name = newToken (); vString *const signature = vStringNew (); boolean is_class = FALSE; /* * This deals with these formats * function validFunctionTwo(a,b) {} */ readToken (name); if (!isType (name, TOKEN_IDENTIFIER)) goto cleanUp; /* Add scope in case this is an INNER function */ addToScope(name, token->scope); readToken (token); while (isType (token, TOKEN_PERIOD)) { readToken (token); if ( isKeyword(token, KEYWORD_NONE) ) { addContext (name, token); readToken (token); } } if ( isType (token, TOKEN_OPEN_PAREN) ) skipArgumentList(token, FALSE, signature); if ( isType (token, TOKEN_OPEN_CURLY) ) { is_class = parseBlock (token, name); if ( is_class ) makeClassTag (name, signature); else makeFunctionTag (name, signature); } findCmdTerm (token, FALSE, FALSE); cleanUp: vStringDelete (signature); deleteToken (name); }
/* Trait format: * "trait" <ident> [<type_bounds>] "{" [<body>] "}" */ static void parseTrait (lexerState *lexer, vString *scope, int parent_kind) { int goal_tokens[] = {'{'}; advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) return; addTag(lexer->token_str, NULL, K_TRAIT, lexer->line, lexer->pos, scope, parent_kind); addToScope(scope, lexer->token_str); advanceToken(lexer, TRUE); skipUntil(lexer, goal_tokens, 1); parseBlock(lexer, TRUE, K_TRAIT, scope); }
static void enterScope (tokenInfo *const parentToken, const vString *const extraScope, const int parentKind) { tokenInfo *token = newToken (); int origParentKind = parentToken->parentKind; copyToken (token, parentToken, true); if (extraScope) { addToScope (token, extraScope); token->parentKind = parentKind; } readToken (token); while (token->type != TOKEN_EOF && token->type != TOKEN_CLOSE_CURLY) { bool readNext = true; switch (token->type) { case TOKEN_OPEN_CURLY: enterScope (token, NULL, -1); break; case TOKEN_KEYWORD: readNext = parseFunction (token); break; case TOKEN_VARIABLE: readNext = parseVariable (token); break; default: break; } if (readNext) readToken (token); } copyToken (parentToken, token, false); parentToken->parentKind = origParentKind; deleteToken (token); }
static boolean parseBlock (tokenInfo *const token, tokenInfo *const parent) { boolean is_class = FALSE; boolean read_next_token = TRUE; vString * saveScope = vStringNew (); token->nestLevel++; /* * Make this routine a bit more forgiving. * If called on an open_curly advance it */ if ( isType (token, TOKEN_OPEN_CURLY) && isKeyword(token, KEYWORD_NONE) ) readToken(token); if (! isType (token, TOKEN_CLOSE_CURLY)) { /* * Read until we find the closing brace, * any nested braces will be handled within */ do { read_next_token = TRUE; if (isKeyword (token, KEYWORD_this)) { /* * 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); /* * Ignore the remainder of the line * findCmdTerm(token); */ parseLine (token, is_class); vStringCopy(token->scope, saveScope); } else if (isKeyword (token, KEYWORD_var)) { /* * Potentially we have found an inner function. * Set something to indicate the scope */ vStringCopy(saveScope, token->scope); addToScope (token, parent->string); parseLine (token, is_class); vStringCopy(token->scope, saveScope); } else if (isKeyword (token, KEYWORD_function)) { vStringCopy(saveScope, token->scope); addToScope (token, parent->string); parseFunction (token); vStringCopy(token->scope, saveScope); } else if (isType (token, TOKEN_OPEN_CURLY)) { /* Handle nested blocks */ parseBlock (token, parent); } else { /* * It is possible for a line to have no terminator * if the following line is a closing brace. * parseLine will detect this case and indicate * whether we should read an additional token. */ read_next_token = parseLine (token, is_class); } /* * Always read a new token unless we find a statement without * a ending terminator */ if( read_next_token ) readToken(token); /* * If we find a statement without a terminator consider the * block finished, otherwise the stack will be off by one. */ } while (! isType (token, TOKEN_CLOSE_CURLY) && read_next_token ); } vStringDelete(saveScope); token->nestLevel--; return is_class; }
/* Structs and enums are very similar syntax-wise. * It is possible to parse variants a bit more cleverly (e.g. make tuple variants functions and * struct variants structs) but it'd be too clever and the signature wouldn't make too much sense without * the enum's definition (e.g. for the type bounds) * * Struct/Enum format: * "struct/enum" <ident>[<type_bounds>] "{" [<ident>,]+ "}" * "struct/enum" <ident>[<type_bounds>] ";" * */ static void parseStructOrEnum (lexerState *lexer, vString *scope, int parent_kind, boolean is_struct) { int kind = is_struct ? K_STRUCT : K_ENUM; int field_kind = is_struct ? K_FIELD : K_VARIANT; int goal_tokens1[] = {';', '{'}; advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) return; addTag(lexer->token_str, NULL, kind, lexer->line, lexer->pos, scope, parent_kind); addToScope(scope, lexer->token_str); skipUntil(lexer, goal_tokens1, 2); if (lexer->cur_token == '{') { vString *field_name = vStringNew(); while (lexer->cur_token != TOKEN_EOF) { int goal_tokens2[] = {'}', ','}; /* Skip attributes. Format: * #[..] or #![..] * */ if (lexer->cur_token == '#') { advanceToken(lexer, TRUE); if (lexer->cur_token == '!') advanceToken(lexer, TRUE); if (lexer->cur_token == '[') { /* It's an attribute, skip it. */ skipUntil(lexer, NULL, 0); } else { /* Something's up with this field, skip to the next one */ skipUntil(lexer, goal_tokens2, 2); continue; } } if (lexer->cur_token == TOKEN_IDENT) { if (strcmp(lexer->token_str->buffer, "priv") == 0 || strcmp(lexer->token_str->buffer, "pub") == 0) { advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) { /* Something's up with this field, skip to the next one */ skipUntil(lexer, goal_tokens2, 2); continue; } } vStringClear(field_name); vStringCat(field_name, lexer->token_str); addTag(field_name, NULL, field_kind, lexer->line, lexer->pos, scope, kind); skipUntil(lexer, goal_tokens2, 2); } if (lexer->cur_token == '}') { advanceToken(lexer, TRUE); break; } advanceToken(lexer, TRUE); } vStringDelete(field_name); } }
/* Function format: * "fn" <ident>[<type_bounds>] "(" [<args>] ")" ["->" <ret_type>] "{" [<body>] "}"*/ static void parseFn (lexerState *lexer, vString *scope, int parent_kind) { int kind = (parent_kind == K_TRAIT || parent_kind == K_IMPL) ? K_METHOD : K_FN; vString *name; vString *arg_list; unsigned long line; fpos_t pos; int paren_level = 0; boolean found_paren = FALSE; boolean valid_signature = TRUE; advanceToken(lexer, TRUE); if (lexer->cur_token != TOKEN_IDENT) return; name = vStringNewCopy(lexer->token_str); arg_list = vStringNew(); line = lexer->line; pos = lexer->pos; advanceToken(lexer, TRUE); /* HACK: This is a bit coarse as far as what tag entry means by * 'arglist'... */ while (lexer->cur_token != '{' && lexer->cur_token != ';') { if (lexer->cur_token == '}') { valid_signature = FALSE; break; } else if (lexer->cur_token == '(') { found_paren = TRUE; paren_level++; } else if (lexer->cur_token == ')') { paren_level--; if (paren_level < 0) { valid_signature = FALSE; break; } } else if (lexer->cur_token == TOKEN_EOF) { valid_signature = FALSE; break; } writeCurTokenToStr(lexer, arg_list); advanceToken(lexer, FALSE); } if (!found_paren || paren_level != 0) valid_signature = FALSE; if (valid_signature) { vStringStripTrailing(arg_list); addTag(name, arg_list->buffer, kind, line, pos, scope, parent_kind); addToScope(scope, name); parseBlock(lexer, TRUE, kind, scope); } vStringDelete(name); vStringDelete(arg_list); }
static void enterScope (tokenInfo *const parentToken, const vString *const extraScope, const int parentKind) { tokenInfo *token = newToken (); int origParentKind = parentToken->parentKind; copyToken (token, parentToken, TRUE); if (extraScope) { token->parentKind = parentKind; addToScope (token, extraScope, origParentKind); } readToken (token); while (token->type != TOKEN_EOF && token->type != TOKEN_CLOSE_CURLY) { boolean readNext = TRUE; switch (token->type) { case TOKEN_OPEN_CURLY: enterScope (token, NULL, -1); break; case TOKEN_KEYWORD: switch (token->keyword) { /* handle anonymous classes */ case KEYWORD_new: readToken (token); if (token->keyword != KEYWORD_class) readNext = FALSE; else { char buf[32]; tokenInfo *name = newToken (); copyToken (name, token, TRUE); snprintf (buf, sizeof buf, "AnonymousClass%u", ++AnonymousID); vStringCopyS (name->string, buf); readNext = parseClassOrIface (token, K_CLASS, name); deleteToken (name); } break; case KEYWORD_class: readNext = parseClassOrIface (token, K_CLASS, NULL); break; case KEYWORD_interface: readNext = parseClassOrIface (token, K_INTERFACE, NULL); break; case KEYWORD_trait: readNext = parseTrait (token); break; case KEYWORD_function: readNext = parseFunction (token, NULL); break; case KEYWORD_const: readNext = parseConstant (token); break; case KEYWORD_define: readNext = parseDefine (token); break; case KEYWORD_namespace: readNext = parseNamespace (token); break; case KEYWORD_private: CurrentStatement.access = ACCESS_PRIVATE; break; case KEYWORD_protected: CurrentStatement.access = ACCESS_PROTECTED; break; case KEYWORD_public: CurrentStatement.access = ACCESS_PUBLIC; break; case KEYWORD_var: CurrentStatement.access = ACCESS_PUBLIC; break; case KEYWORD_abstract: CurrentStatement.impl = IMPL_ABSTRACT; break; default: break; } break; case TOKEN_VARIABLE: readNext = parseVariable (token); break; default: break; } if (readNext) readToken (token); } copyToken (parentToken, token, FALSE); parentToken->parentKind = origParentKind; deleteToken (token); }