source: src/AST/Inspect.cpp @ a50fdfb

ADTast-experimental
Last change on this file since a50fdfb was c02cef1, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Clean-up in AST/Inspect.

  • Property mode set to 100644
File size: 6.6 KB
RevLine 
[b70abaf]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[7b71402]7// Inspect.cpp -- Helpers to get information from the AST.
[b70abaf]8//
9// Author           : Thierry Delisle
10// Created On       : Fri Jun 24 13:16:31 2022
[7b71402]11// Last Modified By : Andrew Beach
[c02cef1]12// Last Modified On : Mon Oct  3 11:04:00 2022
13// Update Count     : 3
[b70abaf]14//
15
[e01eb4a]16#include "Inspect.hpp"
[b70abaf]17
18#include <iostream>
[c02cef1]19#include <iterator>
[e01eb4a]20
21#include "AST/Decl.hpp"
22#include "AST/Expr.hpp"
23#include "AST/Print.hpp"
24#include "AST/Stmt.hpp"
25#include "AST/Type.hpp"
26#include "CodeGen/OperatorTable.h"
[b70abaf]27
28namespace ast {
[7b71402]29
[c02cef1]30const Type * getPointerBase( const Type * type ) {
31        if ( const auto * p = dynamic_cast< const PointerType * >( type ) ) {
[e01eb4a]32                return p->base;
[c02cef1]33        } else if ( auto a = dynamic_cast< const ArrayType * >( type ) ) {
[e01eb4a]34                return a->base;
[c02cef1]35        } else if ( auto r = dynamic_cast< const ReferenceType * >( type ) ) {
[e01eb4a]36                return r->base;
37        } else {
38                return nullptr;
39        }
40}
41
42template<typename CallExpr, typename Ret>
43static Ret throughDeref( const CallExpr * expr, Ret(*func)( const Expr * ) ) {
44        // In `(*f)(x)` the function we want is `f`.
45        std::string name = getFunctionName( expr );
46        assertf( name == "*?", "Unexpected untyped expression: %s", name.c_str() );
[c02cef1]47        assertf( !expr->args.empty(), "Cannot pass through dereference with no arguments." );
[e01eb4a]48        return func( expr->args.front() );
49}
50
51static const DeclWithType * getCalledFunction( const Expr * expr ) {
52        assert( expr );
[c02cef1]53        if ( const auto * varExpr = dynamic_cast< const VariableExpr * >( expr ) ) {
[e01eb4a]54                return varExpr->var;
[c02cef1]55        } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( expr ) ) {
[e01eb4a]56                return memberExpr->member;
[c02cef1]57        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
[e01eb4a]58                return getCalledFunction( castExpr->arg );
[c02cef1]59        } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( expr ) ) {
[e01eb4a]60                return throughDeref( untypedExpr, getCalledFunction );
[c02cef1]61        } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * > ( expr ) ) {
[e01eb4a]62                return throughDeref( appExpr, getCalledFunction );
[c02cef1]63        } else if ( auto addrExpr = dynamic_cast< const AddressExpr * >( expr ) ) {
[e01eb4a]64                return getCalledFunction( addrExpr->arg );
[c02cef1]65        } else if ( auto commaExpr = dynamic_cast< const CommaExpr * >( expr ) ) {
[e01eb4a]66                return getCalledFunction( commaExpr->arg2 );
[c02cef1]67        } else {
68                return nullptr;
[e01eb4a]69        }
70}
71
72const DeclWithType * getFunction( const Expr * expr ) {
73        if ( auto app = dynamic_cast< const ApplicationExpr * >( expr ) ) {
74                return getCalledFunction( app->func );
75        } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
76                return getCalledFunction( untyped->func );
[c02cef1]77        } else {
78                assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
[e01eb4a]79        }
80}
81
82// There is a lot of overlap with getCalledFunction. Ideally it would use
83// it as a helper function and return the name of the DeclWithType. But the
84// NameExpr and UntypedMemberExpr only work on this version.
85static std::string funcName( const Expr * func ) {
86        assert( func );
[c02cef1]87        if ( const auto * nameExpr = dynamic_cast< const NameExpr * >( func ) ) {
[e01eb4a]88                return nameExpr->name;
[c02cef1]89        } else if ( auto varExpr = dynamic_cast< const VariableExpr * >( func ) ) {
[e01eb4a]90                return varExpr->var->name;
[c02cef1]91        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( func ) ) {
[e01eb4a]92                return funcName( castExpr->arg );
[c02cef1]93        } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( func ) ) {
[e01eb4a]94                return memberExpr->member->name;
[c02cef1]95        } else if ( auto memberExpr = dynamic_cast< const UntypedMemberExpr * >( func ) ) {
[e01eb4a]96                return funcName( memberExpr->member );
[c02cef1]97        } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( func ) ) {
[e01eb4a]98                return throughDeref( untypedExpr, funcName );
[c02cef1]99        } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * >( func ) ) {
[e01eb4a]100                return throughDeref( appExpr, funcName );
[c02cef1]101        } else if ( auto ctorExpr = dynamic_cast< const ConstructorExpr * >( func ) ) {
[e01eb4a]102                return funcName( getCallArg( ctorExpr->callExpr, 0 ) );
103        } else {
104                assertf( false, "Unexpected expression type being called as a function in call expression: %s", toString( func ).c_str() );
105        }
106}
107
108std::string getFunctionName( const Expr * expr ) {
[c02cef1]109        // There's some unforunate overlap here with getFunction. See above.
[e01eb4a]110        if ( auto app = dynamic_cast< const ApplicationExpr * >( expr ) ) {
111                return funcName( app->func );
112        } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( expr ) ) {
113                return funcName( untyped->func );
114        } else {
[c02cef1]115                assertf( false, "getFunctionName received unknown expression: %s", toString( expr ).c_str() );
[e01eb4a]116        }
117}
118
[c02cef1]119template<typename CallExpr>
120static const Expr * callArg( const CallExpr * call, unsigned int pos ) {
121        assertf( pos < call->args.size(),
122                "callArg for argument that doesn't exist: (%u); %s.",
123                pos, toString( call ).c_str() );
124        auto it = call->args.begin();
125        std::advance( it, pos );
126        return *it;
127}
128
[e01eb4a]129const Expr * getCallArg( const Expr * call, unsigned int pos ) {
130        if ( auto app = dynamic_cast< const ApplicationExpr * >( call ) ) {
131                return callArg( app, pos );
132        } else if ( auto untyped = dynamic_cast< const UntypedExpr * >( call ) ) {
133                return callArg( untyped, pos );
134        } else if ( auto tupleAssn = dynamic_cast< const TupleAssignExpr * >( call ) ) {
135                const std::list<ptr<Stmt>>& stmts = tupleAssn->stmtExpr->stmts->kids;
136                assertf( !stmts.empty(), "TupleAssignExpr missing statements." );
[c02cef1]137                auto stmt  = stmts.back().strict_as< ExprStmt >();
138                auto tuple = stmt->expr.strict_as< TupleExpr >();
[e01eb4a]139                assertf( !tuple->exprs.empty(), "TupleAssignExpr has empty tuple expr." );
140                return getCallArg( tuple->exprs.front(), pos );
141        } else if ( auto ctor = dynamic_cast< const ImplicitCopyCtorExpr * >( call ) ) {
142                return getCallArg( ctor->callExpr, pos );
143        } else {
[c02cef1]144                assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( call ).c_str() );
[e01eb4a]145        }
146}
147
[7b71402]148bool structHasFlexibleArray( const ast::StructDecl * decl ) {
149        if(decl->members.size() == 0) return false;
150        const auto & last = *decl->members.rbegin();
151        auto lastd = last.as<ast::DeclWithType>();
152        // I don't know what this is possible, but it might be.
153        if(!lastd) return false;
154        auto atype = dynamic_cast<const ast::ArrayType *>(lastd->get_type());
155        if(!atype) return false;
156        return !atype->isVarLen && !atype->dimension;
157}
158
[e01eb4a]159const ApplicationExpr * isIntrinsicCallExpr( const Expr * expr ) {
160        auto appExpr = dynamic_cast< const ApplicationExpr * >( expr );
161        if ( !appExpr ) return nullptr;
162
163        const DeclWithType * func = getCalledFunction( appExpr->func );
[c02cef1]164        assertf( func, "getCalledFunction returned nullptr: %s",
165                toString( appExpr->func ).c_str() );
[e01eb4a]166
[c02cef1]167        return func->linkage == Linkage::Intrinsic ? appExpr : nullptr;
[e01eb4a]168}
169
[7b71402]170} // namespace ast
Note: See TracBrowser for help on using the repository browser.