source: src/ControlStruct/ExceptDecl.cpp

Last change on this file was 7a780ad, checked in by Andrew Beach <ajbeach@…>, 9 days ago

Moved ast::BasicType::Kind to ast::BasicKind? in its own hearder. This is more consistent with other utility enums (although we still use this as a enum class) and reduces what some files need to include. Also did a upgrade in a comment with MAX_INTEGER_TYPE, it is now part of the enum.

  • Property mode set to 100644
File size: 15.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2018 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// ExceptDecl.cpp --
8//
9// Author           : Andrew Beach
10// Created On       : Tue Jul 12 15:50:00 2022
11// Last Modified By : Andrew Beach
12// Last Modified On : Mon Jul 18 11:01:00 2022
13// Update Count     : 0
14//
15
16#include "ExceptDecl.h"
17
18#include <sstream>
19
20#include "AST/Copy.hpp"
21#include "AST/Decl.hpp"
22#include "AST/Pass.hpp"
23#include "AST/Print.hpp"
24#include "AST/Type.hpp"
25#include "Virtual/Tables.h"
26
27namespace ControlStruct {
28
29namespace {
30
31std::vector<ast::ptr<ast::Expr>> forallToParams(
32                std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
33        return map_range<std::vector<ast::ptr<ast::Expr>>>( forall,
34                []( ast::ptr<ast::TypeDecl> const & decl ) {
35                        return new ast::TypeExpr( decl->location,
36                                new ast::TypeInstType( decl->name, decl->kind ) );
37                }
38        );
39}
40
41// A slightly argumented extra constructor, adds a deepCopy.
42ast::StructInstType * namedStructInstType(
43                std::string const & name, ast::CV::Qualifiers qualifiers,
44                std::vector<ast::ptr<ast::Expr>> const & params ) {
45        ast::StructInstType * type = new ast::StructInstType( name, qualifiers );
46        for ( ast::ptr<ast::Expr> const & param : params ) {
47                type->params.push_back( ast::deepCopy( param ) );
48        }
49        return type;
50}
51
52ast::StructInstType * createExceptionInstType(
53                std::string const & exceptionName,
54                std::vector<ast::ptr<ast::Expr>> const & params ) {
55        return namedStructInstType( exceptionName, ast::CV::Qualifiers(), params );
56}
57
58ast::StructInstType * createVTableInstType(
59                std::string const & exceptionName,
60                std::vector<ast::ptr<ast::Expr>> const & params ) {
61        std::string name = Virtual::vtableTypeName( exceptionName );
62        return namedStructInstType( name, ast::CV::Const, params );
63}
64
65ast::StructInstType * createTypeIdInstType(
66                std::string const & exceptionName,
67                std::vector<ast::ptr<ast::Expr>> const & params ) {
68        std::string name = Virtual::typeIdType( exceptionName );
69        return namedStructInstType( name, ast::CV::Const, params );
70}
71
72ast::FunctionType const * createCopyFuncType(
73                std::string const & exceptionName,
74                std::vector<ast::ptr<ast::Expr>> const & params ) {
75        ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
76        type->params.push_back( new ast::PointerType(
77                createExceptionInstType( exceptionName, params ) ) );
78        type->params.push_back( new ast::PointerType(
79                createExceptionInstType( exceptionName, params ) ) );
80        type->returns.push_back( new ast::VoidType() );
81        return type;
82}
83
84ast::FunctionType const * createDtorFuncType(
85                std::string const & exceptionName,
86                std::vector<ast::ptr<ast::Expr>> const & params ) {
87        ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
88        type->params.push_back( new ast::ReferenceType(
89                createExceptionInstType( exceptionName, params ) ) );
90        type->returns.push_back( new ast::VoidType() );
91        return type;
92}
93
94ast::FunctionType const * createMsgFuncType(
95                std::string const & exceptionName,
96                std::vector<ast::ptr<ast::Expr>> const & params ) {
97        ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
98        type->params.push_back( new ast::PointerType(
99                createExceptionInstType( exceptionName, params ) ) );
100        type->returns.push_back( new ast::PointerType(
101                new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) ) );
102        return type;
103}
104
105ast::StructDecl const * createTypeIdStruct(
106                CodeLocation const & location,
107                std::string const & exceptionName,
108                std::vector<ast::ptr<ast::TypeDecl>> const & forallClause ) {
109        ast::StructDecl * decl = new ast::StructDecl( location,
110                        Virtual::typeIdType( exceptionName ) );
111        decl->members.push_back( new ast::ObjectDecl(
112                location,
113                "parent",
114                new ast::PointerType(
115                        new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) )
116        ) );
117        decl->body = true;
118        for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
119                decl->params.push_back( ast::deepCopy( param ) );
120        }
121        return decl;
122}
123
124ast::ObjectDecl const * createTypeIdValue(
125                CodeLocation const & location,
126                std::string const & exceptionName,
127                std::vector<ast::ptr<ast::Expr>> const & params ) {
128        ast::StructInstType * typeIdType =
129                createTypeIdInstType( exceptionName, params );
130        return new ast::ObjectDecl(
131                location,
132                Virtual::typeIdName( exceptionName ),
133                typeIdType,
134                new ast::ListInit( location, {
135                        new ast::SingleInit( location,
136                                new ast::AddressExpr( location,
137                                        new ast::NameExpr( location, "__cfatid_exception_t" ) ),
138                                ast::MaybeConstruct ),
139                }, {}, ast::MaybeConstruct ),
140                ast::Storage::Classes(),
141                ast::Linkage::Cforall,
142                nullptr,
143                { new ast::Attribute( "cfa_linkonce" ) }
144        );
145}
146
147ast::StructDecl const * createExceptionStructForward(
148                CodeLocation const & location,
149                std::string const & exceptionName,
150                std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
151        ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
152        for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
153                decl->params.push_back( ast::deepCopy( param ) );
154        }
155        return decl;
156}
157
158ast::StructDecl const * createVirtualTableStruct(
159                CodeLocation const & location,
160                std::string const & exceptionName,
161                std::vector<ast::ptr<ast::TypeDecl>> const & forall,
162                std::vector<ast::ptr<ast::Expr>> const & params ) {
163        ast::StructInstType * typeIdType =
164                createTypeIdInstType( exceptionName, params );
165        ast::ObjectDecl * typeId = new ast::ObjectDecl(
166                location,
167                "__cfavir_typeid",
168                new ast::PointerType( typeIdType )
169        );
170        ast::ObjectDecl * size = new ast::ObjectDecl(
171                location,
172                "size",
173                new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype )
174        );
175        ast::ObjectDecl * copy = new ast::ObjectDecl(
176                location,
177                "copy",
178                new ast::PointerType( createCopyFuncType( exceptionName, params ) )
179        );
180        ast::ObjectDecl * dtor = new ast::ObjectDecl(
181                location,
182                "^?{}",
183                new ast::PointerType( createDtorFuncType( exceptionName, params ) )
184        );
185        ast::ObjectDecl * msg = new ast::ObjectDecl(
186                location,
187                "msg",
188                new ast::PointerType( createMsgFuncType( exceptionName, params ) )
189        );
190        ast::StructDecl * decl = new ast::StructDecl(
191                location,
192                Virtual::vtableTypeName( exceptionName ) );
193        decl->members.push_back( typeId );
194        decl->members.push_back( size );
195        decl->members.push_back( copy );
196        decl->members.push_back( dtor );
197        decl->members.push_back( msg );
198        decl->body = true;
199        for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
200                decl->params.push_back( param );
201        }
202        return decl;
203}
204
205ast::StructDecl const * createExceptionStruct(
206                CodeLocation const & location,
207                std::string const & exceptionName,
208                std::vector<ast::ptr<ast::TypeDecl>> const & forallClause,
209                std::vector<ast::ptr<ast::Expr>> const & params,
210                std::vector<ast::ptr<ast::Decl>> const & members ) {
211        ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
212        decl->members.push_back( new ast::ObjectDecl(
213                location,
214                "virtual_table",
215                new ast::PointerType(
216                        createVTableInstType( exceptionName, params ) )
217        ) );
218        for ( ast::ptr<ast::Decl> const & member : members ) {
219                decl->members.push_back( ast::deepCopy( member ) );
220        }
221        decl->body = true;
222        for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
223                decl->params.push_back( ast::deepCopy( param ) );
224        }
225        return decl;
226}
227
228ast::ObjectDecl const * createExternTypeId(
229                CodeLocation const & location,
230                std::string const & exceptionName,
231                std::vector<ast::ptr<ast::Expr>> const & params ) {
232        return new ast::ObjectDecl(
233                location,
234                Virtual::typeIdName( exceptionName ),
235                createVTableInstType( exceptionName, params ),
236                nullptr,
237                ast::Storage::Extern,
238                ast::Linkage::Cforall,
239                nullptr,
240                { new ast::Attribute( "cfa_linkonce" ) }
241        );
242}
243
244ast::ObjectDecl * createExternVTable(
245                CodeLocation const & location,
246                std::string const & exceptionName,
247                std::vector<ast::ptr<ast::Expr>> const & params,
248                std::string const & tableName ) {
249        return new ast::ObjectDecl(
250                location,
251                tableName,
252                createVTableInstType( exceptionName, params ),
253                nullptr,
254                ast::Storage::Extern,
255                ast::Linkage::Cforall
256        );
257}
258
259ast::FunctionDecl const * createCopy(
260                CodeLocation const & location,
261                std::string const & exceptionName,
262                std::vector<ast::ptr<ast::Expr>> const & params ) {
263        return new ast::FunctionDecl(
264                location,
265                "copy",
266                {/* forall */},
267                {/* assertions */},
268                {
269                        new ast::ObjectDecl(
270                                location,
271                                "this",
272                                new ast::PointerType(
273                                        createExceptionInstType( exceptionName, params ) )
274                        ),
275                        new ast::ObjectDecl(
276                                location,
277                                "that",
278                                new ast::PointerType(
279                                        createExceptionInstType( exceptionName, params ) )
280                        ),
281                },
282                {
283                        new ast::ObjectDecl( location, "", new ast::VoidType() ),
284                },
285                new ast::CompoundStmt( location, {
286                        new ast::ExprStmt( location,
287                                new ast::UntypedExpr( location,
288                                        new ast::NameExpr( location, "?=?" ),
289                                        {
290                                                new ast::UntypedExpr( location,
291                                                        new ast::NameExpr( location, "*?" ),
292                                                        { new ast::NameExpr( location, "this" ) } ),
293                                                new ast::UntypedExpr( location,
294                                                        new ast::NameExpr( location, "*?" ),
295                                                        { new ast::NameExpr( location, "that" ) } ),
296                                        }
297                                )
298                        ),
299                } ),
300                ast::Storage::Classes(),
301                ast::Linkage::Cforall,
302                { new ast::Attribute( "cfa_linkonce" ) }
303        );
304}
305
306ast::FunctionDecl const * createMsg(
307                CodeLocation const & location,
308                std::string const & exceptionName,
309                std::vector<ast::ptr<ast::Expr>> const & params ) {
310        std::stringstream msg;
311        msg << exceptionName;
312        // The forall variant, add parameters to the string.
313        if ( !params.empty() ) {
314                msg << "(";
315                bool first = true;
316                for ( auto & param : params ) {
317                        // Seperator Logic: A comma proceeds all but the first object.
318                        if ( first ) {
319                                first = false;
320                        } else {
321                                msg << ", ";
322                        }
323
324                        ast::print( msg, param.get() );
325                }
326                msg << ")";
327        }
328        return new ast::FunctionDecl(
329                location,
330                "msg",
331                {/* forall */},
332                {/* assertions */},
333                {
334                        new ast::ObjectDecl(
335                                location,
336                                "this",
337                                new ast::PointerType(
338                                        createExceptionInstType( exceptionName, params ) )
339                        ),
340                },
341                {
342                        new ast::ObjectDecl(
343                                location,
344                                "",
345                                new ast::PointerType(
346                                        new ast::BasicType( ast::BasicKind::Char, ast::CV::Const ) )
347                        ),
348                },
349                new ast::CompoundStmt( location, {
350                        new ast::ReturnStmt( location,
351                                ast::ConstantExpr::from_string( location, msg.str() )
352                        ),
353                } ),
354                ast::Storage::Classes(),
355                ast::Linkage::Cforall,
356                { new ast::Attribute( "cfa_linkonce" ) }
357        );
358}
359
360ast::ObjectDecl * createVirtualTable(
361                CodeLocation const & location,
362                std::string const & exceptionName,
363                std::vector<ast::ptr<ast::Expr>> const & params,
364                std::string const & tableName ) {
365        ast::StructInstType * sizeType = new ast::StructInstType( exceptionName );
366        for ( ast::ptr<ast::Expr> const & param : params ) {
367                sizeType->params.push_back( ast::deepCopy( param ) );
368        }
369        std::vector<ast::ptr<ast::Init>> inits {
370                new ast::SingleInit( location,
371                        new ast::AddressExpr( location,
372                                new ast::NameExpr( location,
373                                        Virtual::typeIdName( exceptionName ) ) ) ),
374                new ast::SingleInit( location,
375                        new ast::SizeofExpr( location, sizeType )  ),
376                new ast::SingleInit( location,
377                        new ast::NameExpr( location, "copy" ) ),
378                new ast::SingleInit( location,
379                        new ast::NameExpr( location, "^?{}" ) ),
380                new ast::SingleInit( location,
381                        new ast::NameExpr( location, "msg" ) ),
382        };
383        std::vector<ast::ptr<ast::Designation>> dsigs {
384                new ast::Designation( location, {
385                        new ast::NameExpr( location, "__cfavir_typeid" ) } ),
386                new ast::Designation( location, {
387                        new ast::NameExpr( location, "size" ) } ),
388                new ast::Designation( location, {
389                        new ast::NameExpr( location, "copy" ) } ),
390                new ast::Designation( location, {
391                        new ast::NameExpr( location, "^?{}" ) } ),
392                new ast::Designation( location, {
393                        new ast::NameExpr( location, "msg" ) } ),
394        };
395        return new ast::ObjectDecl(
396                location,
397                tableName,
398                createVTableInstType( exceptionName, params ),
399                new ast::ListInit( location, std::move( inits ), std::move( dsigs ) )
400        );
401}
402
403struct ExceptDeclCore : public ast::WithDeclsToAdd<> {
404        ast::StructDecl const * transformExcept( ast::StructDecl const * decl );
405        ast::ObjectDecl const * transformVTable(
406                ast::ObjectDecl const * decl, ast::VTableType const * type );
407
408        ast::StructDecl const * postvisit( ast::StructDecl const * decl ) {
409                // Exceptions don't get their own node type, so filter that.
410                if ( ast::AggregateDecl::Exception == decl->kind ) {
411                        return transformExcept( decl );
412                }
413                return decl;
414        }
415
416        ast::ObjectDecl const * postvisit( ast::ObjectDecl const * decl ) {
417                // Modify remaining objects that have a vtable type.
418                if ( auto * type = decl->type.as<ast::VTableType>() ) {
419                        return transformVTable( decl, type );
420                }
421                return decl;
422        }
423};
424
425ast::StructDecl const * ExceptDeclCore::transformExcept(
426                ast::StructDecl const * decl ) {
427        CodeLocation const & location = decl->location;
428        std::string const & exceptionName = decl->name;
429        std::vector<ast::ptr<ast::TypeDecl>> const & forall = decl->params;
430        std::vector<ast::ptr<ast::Expr>> params = forallToParams( forall );
431        std::vector<ast::ptr<ast::Decl>> const & members = decl->members;
432
433        declsToAddBefore.push_back(
434                createTypeIdStruct( location, exceptionName, forall ) );
435        if ( forall.empty() ) {
436                // Non-forall variant.
437                declsToAddBefore.push_back(
438                        createTypeIdValue( location, exceptionName, params ) );
439        }
440        declsToAddBefore.push_back(
441                createExceptionStructForward( location, exceptionName, forall ) );
442        declsToAddBefore.push_back(
443                createVirtualTableStruct( location, exceptionName, forall, params ) );
444        return createExceptionStruct( location, exceptionName, forall, params, members );
445}
446
447ast::ObjectDecl const * ExceptDeclCore::transformVTable(
448                ast::ObjectDecl const * decl, ast::VTableType const * type ) {
449        CodeLocation const & location = decl->location;
450        auto base = type->base.strict_as<ast::TypeInstType>();
451        std::string const & exceptionName = base->name;
452        std::vector<ast::ptr<ast::Expr>> const & params = base->params;
453        std::string const & tableName = decl->name;
454
455        ast::ObjectDecl * retDecl;
456        if ( decl->storage.is_extern ) {
457                // Unique type-ids are only needed for polymorphic instances.
458                if ( !params.empty() ) {
459                        declsToAddBefore.push_back(
460                                createExternTypeId( location, exceptionName, params ) );
461                }
462                retDecl = createExternVTable( location, exceptionName, params, tableName );
463        } else {
464                // Unique type-ids are only needed for polymorphic instances.
465                if ( !params.empty() ) {
466                        declsToAddBefore.push_back(
467                                createTypeIdValue( location, exceptionName, params ) );
468                }
469                declsToAddBefore.push_back(
470                        createCopy( location, exceptionName, params ) );
471                declsToAddBefore.push_back(
472                        createMsg( location, exceptionName, params ) );
473                retDecl = createVirtualTable(
474                        location, exceptionName, params, tableName );
475        }
476
477        for ( ast::ptr<ast::Attribute> const & attr : decl->attributes ) {
478                retDecl->attributes.push_back( attr );
479        }
480
481        return retDecl;
482}
483
484struct VTableCore {
485        ast::StructInstType const * postvisit( ast::VTableType const * type ) {
486                auto inst = type->base.as<ast::BaseInstType>();
487
488                std::string vtableName = Virtual::vtableTypeName( inst->name );
489
490                auto newType = new ast::StructInstType( vtableName );
491                for ( ast::ptr<ast::Expr> const & param : inst->params ) {
492                        newType->params.push_back( param );
493                }
494
495                return newType;
496        }
497};
498
499} // namespace
500
501void translateExcept( ast::TranslationUnit & translationUnit ) {
502        // Can I combine these?
503        // Second pass really only covers what the first has missed.
504        // Maybe if the first one is all previsits and the second all postvisit.
505        ast::Pass<ExceptDeclCore>::run( translationUnit );
506        ast::Pass<VTableCore>::run( translationUnit );
507}
508
509} // namespace ControlStruct
510
511// Local Variables: //
512// tab-width: 4 //
513// mode: c++ //
514// compile-command: "make install" //
515// End: //
Note: See TracBrowser for help on using the repository browser.