static ast_result_t sugar_semi(pass_opt_t* options, ast_t** astp) { ast_t* ast = *astp; assert(ast_id(ast) == TK_SEMI); // Semis are pointless, discard them assert(ast_child(ast) == NULL); *astp = ast_sibling(ast); ast_remove(ast); // Since we've effectively replaced ast with its successor we need to process // that too return pass_sugar(astp, options); }
// Determine which branch of the given ifdef to use and convert the ifdef into // an if. static bool resolve_ifdef(pass_opt_t* opt, ast_t* ast) { assert(ast != NULL); // We turn the ifdef node into an if so that codegen doesn't need to know // about ifdefs at all. // We need to determine which branch to take. Note that since normalisation // adds the conditions of outer ifdefs (if any) it may be that BOTH our then // and else conditions fail. In this case we can pick either one, since an // outer ifdef will throw away the whole branch this ifdef is in anyway. AST_GET_CHILDREN(ast, cond, then_clause, else_clause, else_cond); bool then_value = ifdef_cond_eval(cond, opt); ast_setid(ast, TK_IF); REPLACE(&cond, NODE(TK_SEQ, NODE(then_value ? TK_TRUE : TK_FALSE))); // Don't need to set condition type since we've finished type checking it. // Don't need else condition any more. ast_remove(else_cond); return true; }
static void append_one_to_isect(ast_t* ast, ast_t* append) { ast_t* child = ast_child(ast); while(child != NULL) { ast_t* next = ast_sibling(child); if(is_subtype(child, append)) { // If the incoming type is a supertype of a type that is already in the // intersection, then do not bother to append it. return; } else if(is_subtype(append, child)) { // If a type in the intersection is a supertype of the incoming type, // then remove it from the intersection. ast_remove(child); } child = next; } ast_append(ast, append); }
static ast_result_t sugar_module(ast_t* ast) { ast_t* docstring = ast_child(ast); ast_t* package = ast_parent(ast); assert(ast_id(package) == TK_PACKAGE); if(strcmp(package_name(package), "$0") != 0) { // Every module not in builtin has an implicit use builtin command. // Since builtin is always the first package processed it is $0. BUILD(builtin, ast, NODE(TK_USE, NONE STRING(stringtab("builtin")) NONE)); ast_add(ast, builtin); } if((docstring == NULL) || (ast_id(docstring) != TK_STRING)) return AST_OK; ast_t* package_docstring = ast_childlast(package); if(ast_id(package_docstring) == TK_STRING) { ast_error(docstring, "the package already has a docstring"); ast_error(package_docstring, "the existing docstring is here"); return AST_ERROR; } ast_append(package, docstring); ast_remove(docstring); return AST_OK; }
// Normalise the given ifdef condition. static void cond_normalise(ast_t** astp) { pony_assert(astp != NULL); ast_t* ast = *astp; pony_assert(ast != NULL); switch(ast_id(ast)) { case TK_AND: { ast_setid(ast, TK_IFDEFAND); AST_GET_CHILDREN(ast, left, right, question); pony_assert(ast_id(question) == TK_NONE); ast_remove(question); cond_normalise(&left); cond_normalise(&right); break; } case TK_OR: { ast_setid(ast, TK_IFDEFOR); AST_GET_CHILDREN(ast, left, right, question); pony_assert(ast_id(question) == TK_NONE); ast_remove(question); cond_normalise(&left); cond_normalise(&right); break; } case TK_NOT: { ast_setid(ast, TK_IFDEFNOT); AST_GET_CHILDREN(ast, child); cond_normalise(&child); break; } case TK_STRING: { ast_setid(ast, TK_ID); REPLACE(astp, NODE(TK_IFDEFFLAG, TREE(*astp))); break; } case TK_REFERENCE: { const char* name = ast_name(ast_child(ast)); if(strcmp(name, OS_POSIX_NAME) == 0) { REPLACE(astp, NODE(TK_IFDEFOR, NODE(TK_IFDEFOR, NODE(TK_IFDEFFLAG, ID(OS_LINUX_NAME)) NODE(TK_IFDEFFLAG, ID(OS_MACOSX_NAME))) NODE(TK_IFDEFFLAG, ID(OS_BSD_NAME)))); break; } ast_setid(ast, TK_IFDEFFLAG); break; } case TK_SEQ: { // Remove the sequence node. pony_assert(ast_childcount(ast) == 1); ast_t* child = ast_pop(ast); pony_assert(child != NULL); cond_normalise(&child); ast_replace(astp, child); break; } case TK_IFDEFAND: case TK_IFDEFOR: case TK_IFDEFNOT: case TK_IFDEFFLAG: // Already normalised. break; default: pony_assert(0); break; } }