static ast_result_t flatten_isect(pass_opt_t* opt, ast_t* ast) { // Flatten intersections without testing subtyping. This is to preserve any // type guarantees that an element in the intersection might make. // If there are more than 2 children, this has already been flattened. if(ast_childcount(ast) > 2) return AST_OK; AST_EXTRACT_CHILDREN(ast, left, right); if((opt->check.frame->constraint == NULL) && (opt->check.frame->iftype_constraint == NULL) && (opt->check.frame->provides == NULL) && !is_compat_type(left, right)) { ast_add(ast, right); ast_add(ast, left); ast_error(opt->check.errors, ast, "intersection types cannot include reference capabilities that are not " "locally compatible"); return AST_ERROR; } flatten_typeexpr_element(ast, left, TK_ISECTTYPE); flatten_typeexpr_element(ast, right, TK_ISECTTYPE); return AST_OK; }
static ast_result_t sugar_update(ast_t** astp) { ast_t* ast = *astp; assert(ast_id(ast) == TK_ASSIGN); AST_GET_CHILDREN(ast, value, call); if(ast_id(call) != TK_CALL) return AST_OK; // We are of the form: x(y) = z // Replace us with: x.update(y where value = z) AST_EXTRACT_CHILDREN(call, positional, named, expr); // If there are no named arguments yet, named will be a TK_NONE. ast_setid(named, TK_NAMEDARGS); // Build a new namedarg. BUILD_NO_DEBUG(namedarg, ast, NODE(TK_UPDATEARG, ID("value") NODE(TK_SEQ, TREE(value)))); // Append the named arg to our existing list. ast_append(named, namedarg); // Replace with the update call. REPLACE(astp, NODE(TK_CALL, TREE(positional) TREE(named) NODE(TK_DOT, TREE(expr) ID("update")))); return AST_OK; }
static ast_result_t sugar_with(typecheck_t* t, ast_t** astp) { AST_EXTRACT_CHILDREN(*astp, withexpr, body, else_clause); token_id try_token; if(ast_id(else_clause) == TK_NONE) try_token = TK_TRY_NO_CHECK; else try_token = TK_TRY; expand_none(else_clause, false); // First build a skeleton try block without the "with" variables BUILD(replace, *astp, NODE(TK_SEQ, NODE(try_token, NODE(TK_SEQ, AST_SCOPE TREE(body)) NODE(TK_SEQ, AST_SCOPE TREE(else_clause)) NODE(TK_SEQ, AST_SCOPE)))); ast_t* tryexpr = ast_child(replace); AST_GET_CHILDREN(tryexpr, try_body, try_else, try_then); // Add the "with" variables from each with element for(ast_t* p = ast_child(withexpr); p != NULL; p = ast_sibling(p)) { assert(ast_id(p) == TK_SEQ); AST_GET_CHILDREN(p, idseq, init); const char* init_name = package_hygienic_id(t); BUILD(assign, idseq, NODE(TK_ASSIGN, AST_NODEBUG TREE(init) NODE(TK_LET, ID(init_name) NONE))); BUILD(local, idseq, NODE(TK_ASSIGN, AST_NODEBUG NODE(TK_REFERENCE, ID(init_name)) TREE(idseq))); ast_add(replace, assign); ast_add(try_body, local); ast_add(try_else, local); build_with_dispose(try_then, idseq); ast_add(try_then, local); } ast_replace(astp, replace); return AST_OK; }
static ast_result_t flatten_union(pass_opt_t* opt, ast_t* ast) { (void)opt; // Flatten unions without testing subtyping. This will be tested after the // traits pass, when we have full subtyping information. // If there are more than 2 children, this has already been flattened. if(ast_childcount(ast) > 2) return AST_OK; AST_EXTRACT_CHILDREN(ast, left, right); flatten_typeexpr_element(ast, left, TK_UNIONTYPE); flatten_typeexpr_element(ast, right, TK_UNIONTYPE); return AST_OK; }
static ast_result_t sugar_for(typecheck_t* t, ast_t** astp) { AST_EXTRACT_CHILDREN(*astp, for_idseq, for_iter, for_body, for_else); expand_none(for_else, true); const char* iter_name = package_hygienic_id(t); BUILD(try_next, for_iter, NODE(TK_TRY_NO_CHECK, NODE(TK_SEQ, AST_SCOPE NODE(TK_CALL, NONE NONE NODE(TK_DOT, NODE(TK_REFERENCE, ID(iter_name)) ID("next")))) NODE(TK_SEQ, AST_SCOPE NODE(TK_CONTINUE, NONE)) NONE)); sugar_try(try_next); REPLACE(astp, NODE(TK_SEQ, NODE(TK_ASSIGN, AST_NODEBUG TREE(for_iter) NODE(TK_LET, NICE_ID(iter_name, "for loop iterator") NONE)) NODE(TK_WHILE, AST_SCOPE NODE(TK_SEQ, NODE_ERROR_AT(TK_CALL, for_iter, NONE NONE NODE(TK_DOT, NODE(TK_REFERENCE, ID(iter_name)) ID("has_next")))) NODE(TK_SEQ, AST_SCOPE NODE_ERROR_AT(TK_ASSIGN, for_idseq, AST_NODEBUG TREE(try_next) TREE(for_idseq)) TREE(for_body)) TREE(for_else)))); return AST_OK; }