src/AstTypeAnalysis.cpp
AstClause* createAnnotatedClause(
        const AstClause* clause, const std::map<const AstArgument*, TypeSet> argumentTypes) {
    // Annotates each variable with its type based on a given type analysis result
    struct TypeAnnotator : public AstNodeMapper {
        const std::map<const AstArgument*, TypeSet>& types;

        TypeAnnotator(const std::map<const AstArgument*, TypeSet>& types) : types(types) {}

        std::unique_ptr<AstNode> operator()(std::unique_ptr<AstNode> node) const override {
            if (auto* var = dynamic_cast<AstVariable*>(node.get())) {
                std::stringstream newVarName;
                newVarName << var->getName() << "&isin;" << types.find(var)->second;
                return std::make_unique<AstVariable>(newVarName.str());
            } else if (auto* var = dynamic_cast<AstUnnamedVariable*>(node.get())) {
                std::stringstream newVarName;
                newVarName << "_"
                           << "&isin;" << types.find(var)->second;
                return std::make_unique<AstVariable>(newVarName.str());
            }
            node->apply(*this);
            return node;
        }
    };

    /* Note:
     * Because the type of each argument is stored in the form [address -> type-set],
     * the type-analysis result does not immediately apply to the clone due to differing
     * addresses.
     * Two ways around this:
     *  (1) Perform the type-analysis again for the cloned clause
     *  (2) Keep track of the addresses of equivalent arguments in the cloned clause
     * Method (2) was chosen to avoid having to recompute the analysis each time.
     */
    AstClause* annotatedClause = clause->clone();

    // Maps x -> y, where x is the address of an argument in the original clause, and y
    // is the address of the equivalent argument in the clone.
    std::map<const AstArgument*, const AstArgument*> memoryMap;

    std::vector<const AstArgument*> originalAddresses;
    visitDepthFirst(*clause, [&](const AstArgument& arg) { originalAddresses.push_back(&arg); });

    std::vector<const AstArgument*> cloneAddresses;
    visitDepthFirst(*annotatedClause, [&](const AstArgument& arg) { cloneAddresses.push_back(&arg); });

    assert(cloneAddresses.size() == originalAddresses.size());

    for (size_t i = 0; i < originalAddresses.size(); i++) {
        memoryMap[originalAddresses[i]] = cloneAddresses[i];
    }

    // Map the types to the clause clone
    std::map<const AstArgument*, TypeSet> cloneArgumentTypes;
    for (auto& pair : argumentTypes) {
        cloneArgumentTypes[memoryMap[pair.first]] = pair.second;
    }

    // Create the type-annotated clause
    TypeAnnotator annotator(cloneArgumentTypes);
    annotatedClause->apply(annotator);
    return annotatedClause;
}
/* Return a new clause with type-annotated variables */
Return a new clause with type-annotated variables
Return a new clause with type - annotated variables
AstClause* createAnnotatedClause(
        const AstClause* clause, const std::map<const AstArgument*, TypeSet> argumentTypes) {
    struct TypeAnnotator : public AstNodeMapper {
        const std::map<const AstArgument*, TypeSet>& types;
        TypeAnnotator(const std::map<const AstArgument*, TypeSet>& types) : types(types) {}
        std::unique_ptr<AstNode> operator()(std::unique_ptr<AstNode> node) const override {
            if (auto* var = dynamic_cast<AstVariable*>(node.get())) {
                std::stringstream newVarName;
                newVarName << var->getName() << "&isin;" << types.find(var)->second;
                return std::make_unique<AstVariable>(newVarName.str());
            } else if (auto* var = dynamic_cast<AstUnnamedVariable*>(node.get())) {
                std::stringstream newVarName;
                newVarName << "_"
                           << "&isin;" << types.find(var)->second;
                return std::make_unique<AstVariable>(newVarName.str());
            }
            node->apply(*this);
            return node;
        }
    };
    AstClause* annotatedClause = clause->clone();
    std::map<const AstArgument*, const AstArgument*> memoryMap;
    std::vector<const AstArgument*> originalAddresses;
    visitDepthFirst(*clause, [&](const AstArgument& arg) { originalAddresses.push_back(&arg); });
    std::vector<const AstArgument*> cloneAddresses;
    visitDepthFirst(*annotatedClause, [&](const AstArgument& arg) { cloneAddresses.push_back(&arg); });
    assert(cloneAddresses.size() == originalAddresses.size());
    for (size_t i = 0; i < originalAddresses.size(); i++) {
        memoryMap[originalAddresses[i]] = cloneAddresses[i];
    }
    std::map<const AstArgument*, TypeSet> cloneArgumentTypes;
    for (auto& pair : argumentTypes) {
        cloneArgumentTypes[memoryMap[pair.first]] = pair.second;
    }
    TypeAnnotator annotator(cloneArgumentTypes);
    annotatedClause->apply(annotator);
    return annotatedClause;
}
AstClause * createAnnotatedClause ( const AstClause * clause , const std :: map < const AstArgument * , TypeSet > argumentTypes ) { struct TypeAnnotator : public AstNodeMapper { const std :: map < const AstArgument * , TypeSet > & types ; TypeAnnotator ( const std :: map < const AstArgument * , TypeSet > & types ) : types ( types ) { } std :: unique_ptr < AstNode > operator () ( std :: unique_ptr < AstNode > node ) const override { if ( auto * var = dynamic_cast < AstVariable * > ( node . get ( ) ) ) { std :: stringstream newVarName ; newVarName << var -> getName ( ) << " " << types . find ( var ) -> second ; return std :: make_unique < AstVariable > ( newVarName . str ( ) ) ; } else if ( auto * var = dynamic_cast < AstUnnamedVariable * > ( node . get ( ) ) ) { std :: stringstream newVarName ; newVarName << " " << " " << types . find ( var ) -> second ; return std :: make_unique < AstVariable > ( newVarName . str ( ) ) ; } node -> apply ( * this ) ; return node ; } } ; AstClause * annotatedClause = clause -> clone ( ) ; std :: map < const AstArgument * , const AstArgument * > memoryMap ; std :: vector < const AstArgument * > originalAddresses ; visitDepthFirst ( * clause , [ & ] ( const AstArgument & arg ) { originalAddresses . push_back ( & arg ) ; } ) ; std :: vector < const AstArgument * > cloneAddresses ; visitDepthFirst ( * annotatedClause , [ & ] ( const AstArgument & arg ) { cloneAddresses . push_back ( & arg ) ; } ) ; assert ( cloneAddresses . size ( ) == originalAddresses . size ( ) ) ; for ( size_t i = 0 ; i < originalAddresses . size ( ) ; i ++ ) { memoryMap [ originalAddresses [ i ] ] = cloneAddresses [ i ] ; } std :: map < const AstArgument * , TypeSet > cloneArgumentTypes ; for ( auto & pair : argumentTypes ) { cloneArgumentTypes [ memoryMap [ pair . first ] ] = pair . second ; } TypeAnnotator annotator ( cloneArgumentTypes ) ; annotatedClause -> apply ( annotator ) ; return annotatedClause ; }
Return a new clause with type-annotated variables
Return a new clause with type - annotated variables
// Annotates each variable with its type based on a given type analysis result /* Note:
     * Because the type of each argument is stored in the form [address -> type-set],
     * the type-analysis result does not immediately apply to the clone due to differing
     * addresses.
     * Two ways around this:
     *  (1) Perform the type-analysis again for the cloned clause
     *  (2) Keep track of the addresses of equivalent arguments in the cloned clause
     * Method (2) was chosen to avoid having to recompute the analysis each time.
     */ // Maps x -> y, where x is the address of an argument in the original clause, and y // is the address of the equivalent argument in the clone. // Map the types to the clause clone // Create the type-annotated clause