source: src/AST/Inspect.cpp@ e2887a9

ADT ast-experimental
Last change on this file since e2887a9 was fb4dc28, checked in by Andrew Beach <ajbeach@…>, 2 years 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
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
[fb4dc28]12// Last Modified On : Fri Apr 14 15:09:00 2023
13// Update Count : 4
[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
[fb4dc28]170bool isUnnamedBitfield( const ast::ObjectDecl * obj ) {
171 return obj && obj->name.empty() && obj->bitfieldWidth;
172}
173
[7b71402]174} // namespace ast
Note: See TracBrowser for help on using the repository browser.