source: src/AST/Inspect.cpp @ c4570af3

Last change on this file since c4570af3 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 15 months ago

Moved new ast code out of one of the old files. The new file may have to change if SymTab? is removed entirely, but for now at least, there is a lot less template code in headers.

  • Property mode set to 100644
File size: 6.7 KB
Line 
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//
7// Inspect.cpp -- Helpers to get information from the AST.
8//
9// Author           : Thierry Delisle
10// Created On       : Fri Jun 24 13:16:31 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Apr 14 15:09:00 2023
13// Update Count     : 4
14//
15
16#include "Inspect.hpp"
17
18#include <iostream>
19#include <iterator>
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"
27
28namespace ast {
29
30const Type * getPointerBase( const Type * type ) {
31        if ( const auto * p = dynamic_cast< const PointerType * >( type ) ) {
32                return p->base;
33        } else if ( auto a = dynamic_cast< const ArrayType * >( type ) ) {
34                return a->base;
35        } else if ( auto r = dynamic_cast< const ReferenceType * >( type ) ) {
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() );
47        assertf( !expr->args.empty(), "Cannot pass through dereference with no arguments." );
48        return func( expr->args.front() );
49}
50
51static const DeclWithType * getCalledFunction( const Expr * expr ) {
52        assert( expr );
53        if ( const auto * varExpr = dynamic_cast< const VariableExpr * >( expr ) ) {
54                return varExpr->var;
55        } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( expr ) ) {
56                return memberExpr->member;
57        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
58                return getCalledFunction( castExpr->arg );
59        } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( expr ) ) {
60                return throughDeref( untypedExpr, getCalledFunction );
61        } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * > ( expr ) ) {
62                return throughDeref( appExpr, getCalledFunction );
63        } else if ( auto addrExpr = dynamic_cast< const AddressExpr * >( expr ) ) {
64                return getCalledFunction( addrExpr->arg );
65        } else if ( auto commaExpr = dynamic_cast< const CommaExpr * >( expr ) ) {
66                return getCalledFunction( commaExpr->arg2 );
67        } else {
68                return nullptr;
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 );
77        } else {
78                assertf( false, "getFunction received unknown expression: %s", toString( expr ).c_str() );
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 );
87        if ( const auto * nameExpr = dynamic_cast< const NameExpr * >( func ) ) {
88                return nameExpr->name;
89        } else if ( auto varExpr = dynamic_cast< const VariableExpr * >( func ) ) {
90                return varExpr->var->name;
91        } else if ( auto castExpr = dynamic_cast< const CastExpr * >( func ) ) {
92                return funcName( castExpr->arg );
93        } else if ( auto memberExpr = dynamic_cast< const MemberExpr * >( func ) ) {
94                return memberExpr->member->name;
95        } else if ( auto memberExpr = dynamic_cast< const UntypedMemberExpr * >( func ) ) {
96                return funcName( memberExpr->member );
97        } else if ( auto untypedExpr = dynamic_cast< const UntypedExpr * >( func ) ) {
98                return throughDeref( untypedExpr, funcName );
99        } else if ( auto appExpr = dynamic_cast< const ApplicationExpr * >( func ) ) {
100                return throughDeref( appExpr, funcName );
101        } else if ( auto ctorExpr = dynamic_cast< const ConstructorExpr * >( func ) ) {
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 ) {
109        // There's some unforunate overlap here with getFunction. See above.
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 {
115                assertf( false, "getFunctionName received unknown expression: %s", toString( expr ).c_str() );
116        }
117}
118
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
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." );
137                auto stmt  = stmts.back().strict_as< ExprStmt >();
138                auto tuple = stmt->expr.strict_as< TupleExpr >();
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 {
144                assertf( false, "Unexpected expression type passed to getCallArg: %s", toString( call ).c_str() );
145        }
146}
147
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
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 );
164        assertf( func, "getCalledFunction returned nullptr: %s",
165                toString( appExpr->func ).c_str() );
166
167        return func->linkage == Linkage::Intrinsic ? appExpr : nullptr;
168}
169
170bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
171        return obj && obj->name.empty() && obj->bitfieldWidth;
172}
173
174} // namespace ast
Note: See TracBrowser for help on using the repository browser.