ast_t* ast_get_case(ast_t* ast, const char* name, sym_status_t* status) { // Same as ast_get, but is partially case insensitive. That is, type names // are compared as uppercase and other symbols are compared as lowercase. if(status != NULL) *status = SYM_NONE; do { if(ast->symtab != NULL) { sym_status_t status2; ast_t* value = (ast_t*)symtab_find_case(ast->symtab, name, &status2); if((status != NULL) && (*status == SYM_NONE)) *status = status2; if(value != NULL) return value; } ast = ast->parent; } while((ast != NULL) && (token_get_id(ast->t) != TK_PROGRAM)); return NULL; }
static size_t length(ast_t* ast, size_t indent, bool type) { size_t len = (indent * in_len) + strlen(token_print(ast->t)); ast_t* child = ast->child; if(type || (child != NULL) || (ast->type != NULL)) len += 2; switch(token_get_id(ast->t)) { case TK_STRING: len += 6; break; case TK_ID: len += 5; break; default: {} } if(ast->symtab != NULL) len += 6; while(child != NULL) { len += 1 + length(child, 0, false); child = child->sibling; } if(ast->type != NULL) len += 1 + length(ast->type, 0, true); return len; }
ast_t* ast_nearest(ast_t* ast, token_id id) { while((ast != NULL) && (token_get_id(ast->t) != id)) ast = ast->parent; return ast; }
ast_t* ast_get(ast_t* ast, const char* name, sym_status_t* status) { // Searches all parent scopes, but not the program scope, because the name // space for paths is separate from the name space for all other IDs. // If called directly on the program scope, searches it. if(status != NULL) *status = SYM_NONE; do { if(ast->symtab != NULL) { sym_status_t status2; ast_t* value = (ast_t*)symtab_find(ast->symtab, name, &status2); if((status != NULL) && (*status == SYM_NONE)) *status = status2; if(value != NULL) return value; } ast = ast->parent; } while((ast != NULL) && (token_get_id(ast->t) != TK_PROGRAM)); return NULL; }
static void print_token(FILE* fp, token_t* token) { switch(token_get_id(token)) { case TK_STRING: fprintf(fp, "\"\"\"%s\"\"\"", token_print(token)); break; case TK_ID: fprintf(fp, "(id %s)", token_print(token)); break; default: fprintf(fp, "%s", token_print(token)); break; } }
ast_t* ast_token(token_t* t) { ast_t* ast = POOL_ALLOC(ast_t); memset(ast, 0, sizeof(ast_t)); ast->t = t; switch(token_get_id(t)) { case TK_PROGRAM: ast->data = program_create(); break; default: break; } return ast; }
bool ast_all_consumes_in_scope(ast_t* outer, ast_t* inner, errorframe_t* errorf) { ast_t* from = inner; bool ok = true; do { if(inner->symtab != NULL) { size_t i = HASHMAP_BEGIN; symbol_t* sym; while((sym = symtab_next(inner->symtab, &i)) != NULL) { // If it's consumed, and has a null value, it's from outside of this // scope. We need to know if it's outside the loop scope. if((sym->status == SYM_CONSUMED) && (sym->def == NULL)) { if(!ast_within_scope(outer, inner, sym->name)) { ast_t* def = ast_get(inner, sym->name, NULL); if(errorf != NULL) { ast_error_frame(errorf, from, "identifier '%s' is consumed when the loop exits", sym->name); ast_error_frame(errorf, def, "consumed identifier is defined here"); } ok = false; } } } } if(inner == outer) break; inner = inner->parent; } while((inner != NULL) && (token_get_id(inner->t) != TK_PROGRAM)); return ok; }
static void fetch_next_lexer_token(parser_t* parser, bool free_prev_token) { token_t* old_token = parser->token; token_t* new_token = lexer_next(parser->lexer); if(old_token != NULL) parser->last_token_line = token_line_number(old_token); if(old_token != NULL && token_get_id(new_token) == TK_EOF) { // Use location of last token for EOF to get better error reporting token_set_pos(new_token, token_source(old_token), token_line_number(old_token), token_line_position(old_token)); } if(free_prev_token) token_free(old_token); parser->token = new_token; }
bool ast_within_scope(ast_t* outer, ast_t* inner, const char* name) { do { if(inner->symtab != NULL) { sym_status_t status2; ast_t* value = (ast_t*)symtab_find(inner->symtab, name, &status2); if(value != NULL) return true; } if(inner == outer) break; inner = inner->parent; } while((inner != NULL) && (token_get_id(inner->t) != TK_PROGRAM)); return false; }
static void print_token(FILE* fp, token_t* token) { switch(token_get_id(token)) { case TK_STRING: { char* escaped = token_print_escaped(token); fprintf(fp, "\"%s\"", escaped); ponyint_pool_free_size(strlen(escaped), escaped); break; } case TK_ID: fprintf(fp, "(id %s)", token_print(token)); break; default: fprintf(fp, "%s", token_print(token)); break; } }
void ast_free(ast_t* ast) { if(ast == NULL) return; ast_t* child = ast->child; ast_t* next; while(child != NULL) { next = child->sibling; ast_free(child); child = next; } ast_free(ast->type); switch(token_get_id(ast->t)) { case TK_PROGRAM: program_free((program_t*)ast->data); break; case TK_PACKAGE: package_free((package_t*)ast->data); break; case TK_MODULE: source_close((source_t*)ast->data); break; default: break; } token_free(ast->t); symtab_free(ast->symtab); POOL_FREE(ast_t, ast); }
// Get the next token ready for when we need it static void get_next_token(build_parser_t* builder) { assert(builder != NULL); if(builder->have_token) return; if(builder->token != NULL) token_free(builder->token); builder->token = lexer_next(builder->lexer); assert(builder->token != NULL); ast_token_id id; switch(token_get_id(builder->token)) { case TK_LPAREN_NEW: case TK_LPAREN: id = AT_LPAREN; break; case TK_RPAREN: id = AT_RPAREN; break; case TK_LSQUARE_NEW: case TK_LSQUARE: id = AT_LSQUARE; break; case TK_RSQUARE: id = AT_RSQUARE; break; case TK_LBRACE: id = AT_LBRACE; break; case TK_RBRACE: id = AT_RBRACE; break; case TK_EOF: id = AT_EOF; break; case TK_LEX_ERROR: id = AT_ERROR; break; case TK_ID: id = AT_ID; break; case TK_STRING: id = AT_STRING; break; default: id = AT_TOKEN; break; } //printf("Got token %s %d -> %d\n", token_print(builder->token), // token_get_id(builder->token), id); builder->id = id; builder->have_token = true; builder->line = token_line_number(builder->token); builder->pos = token_line_position(builder->token); }
ast_t* ast_try_clause(ast_t* ast, size_t* clause) { ast_t* last = NULL; while(ast != NULL) { switch(token_get_id(ast->t)) { case TK_TRY: case TK_TRY_NO_CHECK: { *clause = ast_index(last); return ast; } default: {} } last = ast; ast = ast_parent(ast); } return NULL; }
token_id ast_id(ast_t* ast) { assert(ast != NULL); return token_get_id(ast->t); }
static token_id current_token_id(parser_t* parser) { return token_get_id(parser->token); }