void AstWalker<TypecheckVisitor, Type*>::walk_forall(ForallNode *node) { visitor.forall_head = true; walk_expression_base(node->in_expr); visitor.forall_head = false; Type list_t = new Type(TypeType::LIST, new Type(TypeType::UNKNOWN)); if (node->in_expr->type_ == TypeType::INT || node->in_expr->type_ == TypeType::ENUM) { node->type_.unify(&node->in_expr->type_); } else if (node->in_expr->type_.unify(&list_t)) { node->type_.unify(node->in_expr->type_.subtypes[0]); } else { visitor.driver_.error(node->location, "expression must be a List, an Int or enum, but is " +node->in_expr->type_.to_str()); } auto current_rule_binding_types = visitor.rule_binding_types.back(); auto current_rule_binding_offsets = visitor.rule_binding_offsets.back(); current_rule_binding_offsets->insert( std::pair<std::string, size_t>(node->identifier, current_rule_binding_types->size()) ); current_rule_binding_types->push_back(&node->type_); walk_statement(node->statement); if (!node->type_.is_complete()) { visitor.driver_.error(node->location, "type inference for `"+node->identifier+"` failed"); } visitor.rule_binding_types.back()->pop_back(); visitor.rule_binding_offsets.back()->erase(node->identifier); }
void walk_statements(statement_t *statement, statement_callback func, void *env) { walk_env_t walk_env = { pset_new_ptr_default(), null_declaration_func, func, null_expression_func, env }; walk_statement(statement, &walk_env); del_pset(walk_env.visited_types); }
static void walk_entity(entity_t *entity, const walk_env_t *const env) { env->declaration_func(entity, env->env); switch (entity->kind) { case ENTITY_VARIABLE: { const variable_t *variable = &entity->variable; const initializer_t *initializer = variable->initializer; walk_type(entity->declaration.type, env); if (initializer != NULL) { walk_initializer(initializer, env); } return; } case ENTITY_ENUM_VALUE: if (entity->enum_value.value != NULL) walk_expression(entity->enum_value.value, env); return; case ENTITY_TYPEDEF: walk_type(entity->declaration.type, env); return; case ENTITY_FUNCTION: walk_type(entity->declaration.type, env); if (entity->function.body != NULL) walk_statement(entity->function.body, env); return; case ENTITY_COMPOUND_MEMBER: case ENTITY_PARAMETER: walk_type(entity->declaration.type, env); return; case ENTITY_CLASS: case ENTITY_STRUCT: case ENTITY_UNION: walk_scope(&entity->compound.members, env); return; case ENTITY_NAMESPACE: walk_scope(&entity->namespacee.members, env); return; case ENTITY_ENUM: for (entity_t *entry = entity->enume.first_value; entry != NULL && entry->kind == ENTITY_ENUM_VALUE; entry = entry->base.next) { walk_entity(entry, env); } return; case ENTITY_LABEL: case ENTITY_LOCAL_LABEL: return; case ENTITY_ASM_ARGUMENT: walk_expression(entity->asm_argument.expression, env); return; } panic("invalid entity"); }
static void walk_expression(expression_t *const expr, const walk_env_t *const env) { env->expression_func(expr, env->env); switch (expr->base.kind) { case EXPR_STATEMENT: walk_statement(expr->statement.statement, env); return; case EXPR_BINARY_CASES: walk_expression(expr->binary.left, env); walk_expression(expr->binary.right, env); return; case EXPR_UNARY_CASES_OPTIONAL: if (expr->unary.value == NULL) return; /* FALLTHROUGH */ case EXPR_UNARY_CASES_MANDATORY: walk_expression(expr->unary.value, env); return; case EXPR_CALL: walk_expression(expr->call.function, env); for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) { walk_expression(arg->expression, env); } return; case EXPR_COMPOUND_LITERAL: walk_initializer(expr->compound_literal.initializer, env); return; case EXPR_CONDITIONAL: walk_expression(expr->conditional.condition, env); /* may be NULL because of gnu extension */ if (expr->conditional.true_expression != NULL) walk_expression(expr->conditional.true_expression, env); walk_expression(expr->conditional.false_expression, env); return; case EXPR_BUILTIN_CONSTANT_P: walk_expression(expr->builtin_constant.value, env); return; case EXPR_BUILTIN_TYPES_COMPATIBLE_P: walk_type(expr->builtin_types_compatible.left, env); walk_type(expr->builtin_types_compatible.right, env); return; case EXPR_SELECT: walk_expression(expr->select.compound, env); return; case EXPR_ARRAY_ACCESS: walk_expression(expr->array_access.array_ref, env); walk_expression(expr->array_access.index, env); return; case EXPR_CLASSIFY_TYPE: walk_expression(expr->classify_type.type_expression, env); return; case EXPR_SIZEOF: case EXPR_ALIGNOF: { expression_t *tp_expression = expr->typeprop.tp_expression; if (tp_expression != NULL) { walk_expression(tp_expression, env); } return; } case EXPR_VA_START: walk_expression(expr->va_starte.ap, env); return; case EXPR_VA_ARG: walk_expression(expr->va_arge.ap, env); return; case EXPR_VA_COPY: walk_expression(expr->va_copye.src, env); walk_expression(expr->va_copye.dst, env); return; case EXPR_OFFSETOF: walk_designator(expr->offsetofe.designator, env); return; case EXPR_LITERAL_CASES: case EXPR_LITERAL_CHARACTER: case EXPR_REFERENCE: case EXPR_ENUM_CONSTANT: case EXPR_STRING_LITERAL: case EXPR_FUNCNAME: case EXPR_LABEL_ADDRESS: case EXPR_ERROR: return; } panic("invalid expr kind"); }
static void walk_statement(statement_t *const stmt, const walk_env_t *const env) { env->statement_func(stmt, env->env); switch (stmt->kind) { case STATEMENT_COMPOUND: for (statement_t *s = stmt->compound.statements; s != NULL; s = s->base.next) { walk_statement(s, env); } return; case STATEMENT_FOR: walk_declarations(stmt->fors.scope.first_entity, NULL, env); if (stmt->fors.initialisation != NULL) walk_expression(stmt->fors.initialisation, env); if (stmt->fors.condition != NULL) walk_expression(stmt->fors.condition, env); if (stmt->fors.step != NULL) walk_expression(stmt->fors.step, env); walk_statement(stmt->fors.body, env); return; case STATEMENT_IF: walk_expression(stmt->ifs.condition, env); walk_statement(stmt->ifs.true_statement, env); if (stmt->ifs.false_statement != NULL) walk_statement(stmt->ifs.false_statement, env); return; case STATEMENT_SWITCH: walk_expression(stmt->switchs.expression, env); walk_statement(stmt->switchs.body, env); return; case STATEMENT_LABEL: walk_statement(stmt->label.statement, env); return; case STATEMENT_CASE_LABEL: if (stmt->case_label.expression) { walk_expression(stmt->case_label.expression, env); if (stmt->case_label.end_range) walk_expression(stmt->case_label.end_range, env); } walk_statement(stmt->case_label.statement, env); return; case STATEMENT_DO_WHILE: walk_statement(stmt->do_while.body, env); walk_expression(stmt->do_while.condition, env); return; case STATEMENT_EXPRESSION: walk_expression(stmt->expression.expression, env); return; case STATEMENT_RETURN: if (stmt->returns.value != NULL) walk_expression(stmt->returns.value, env); return; case STATEMENT_DECLARATION: walk_declarations(stmt->declaration.declarations_begin, stmt->declaration.declarations_end, env); return; case STATEMENT_COMPUTED_GOTO: walk_expression(stmt->computed_goto.expression, env); return; case STATEMENT_ERROR: case STATEMENT_EMPTY: case STATEMENT_CONTINUE: case STATEMENT_BREAK: case STATEMENT_ASM: case STATEMENT_GOTO: return; } panic("unhandled statement"); }