source: src/AST/Inspect.cpp @ 1756e08

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

Moved some functions from InitTweak? to Inspect.

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