source: src/ResolvExpr/CurrentObject.cpp @ 4175659

Last change on this file since 4175659 was d031f7f, checked in by Andrew Beach <ajbeach@…>, 8 weeks ago

Renamed CurrentObject?'s MemberIterator::operator* to getOptions because that is a more descriptive name.

  • Property mode set to 100644
File size: 19.8 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// CurrentObject.cpp --
8//
9// Author           : Rob Schluntz
10// Created On       : Tue Jun 13 15:28:32 2017
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sat Dec  9 17:49:51 2023
13// Update Count     : 20
14//
15
16#include "CurrentObject.hpp"
17
18#include <stddef.h>                    // for size_t
19#include <cassert>                     // for assertf, assert, safe_dynamic_...
20#include <deque>
21#include <iostream>                    // for ostream, operator<<, basic_ost...
22#include <stack>                       // for stack
23#include <string>                      // for string, operator<<, allocator
24
25#include "AST/Copy.hpp"                // for shallowCopy
26#include "AST/Expr.hpp"                // for InitAlternative
27#include "AST/GenericSubstitution.hpp" // for genericSubstitution
28#include "AST/Init.hpp"                // for Designation
29#include "AST/Node.hpp"                // for readonly
30#include "AST/Print.hpp"               // for readonly
31#include "AST/Type.hpp"
32#include "Common/Eval.hpp"             // for eval
33#include "Common/Indenter.hpp"         // for Indenter, operator<<
34#include "Common/SemanticError.hpp"    // for SemanticError
35#include "Common/Utility.hpp"          // for toString
36
37#if 0
38#define PRINT(x) x
39#else
40#define PRINT(x)
41#endif
42
43namespace ast {
44
45/// Iterates members of a type by initializer.
46class MemberIterator {
47public:
48        virtual ~MemberIterator() {}
49
50        /// Internal set position based on iterator ranges.
51        virtual void setPosition(
52                std::deque< ptr< Expr > >::const_iterator it,
53                std::deque< ptr< Expr > >::const_iterator end ) = 0;
54
55        /// Walks the current object using the given designators as a guide.
56        void setPosition( const std::deque< ptr< Expr > > & designators ) {
57                setPosition( designators.begin(), designators.end() );
58        }
59
60        /// Retrieve the list of possible (Type,Designation) pairs for the
61        /// current position in the current object.
62        virtual std::deque< InitAlternative > getOptions() const = 0;
63
64        /// True if the iterator is not currently at the end.
65        virtual operator bool() const = 0;
66
67        /// Moves the iterator by one member in the current object.
68        virtual MemberIterator & bigStep() = 0;
69
70        /// Moves the iterator by one member in the current subobject.
71        virtual MemberIterator & smallStep() = 0;
72
73        /// The type of the current object.
74        virtual const Type * getType() = 0;
75
76        /// The type of the current subobject.
77        virtual const Type * getNext() = 0;
78
79        /// Helper for getOptions; aggregates must add designator to each init
80        /// alternative, but adding designators in getOptions creates duplicates.
81        virtual std::deque< InitAlternative > first() const = 0;
82};
83
84namespace {
85
86/// create a new MemberIterator that traverses a type correctly
87MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type );
88
89/// Iterates "other" types (e.g. basic, pointer) which do not change at list initializer entry
90class SimpleIterator final : public MemberIterator {
91        CodeLocation location;
92        const Type * type = nullptr;
93public:
94        SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
95
96        void setPosition(
97                std::deque< ptr< Expr > >::const_iterator begin,
98                std::deque< ptr< Expr > >::const_iterator end
99        ) override {
100                if ( begin != end ) {
101                        SemanticError( location, "Un-designated initializer given non-empty designator" );
102                }
103        }
104
105        std::deque< InitAlternative > getOptions() const override { return first(); }
106
107        operator bool() const override { return type; }
108
109        SimpleIterator & bigStep() override { return smallStep(); }
110        SimpleIterator & smallStep() override {
111                type = nullptr;  // empty on increment because no members
112                return *this;
113        }
114
115        const Type * getType() override { return type; }
116
117        const Type * getNext() override { return type; }
118
119        std::deque< InitAlternative > first() const override {
120                if ( type ) return { InitAlternative{ type, new Designation{ location } } };
121                return {};
122        }
123};
124
125/// Iterates over an indexed type:
126class IndexIterator : public MemberIterator {
127protected:
128        CodeLocation location;
129        size_t index = 0;
130        size_t size = 0;
131        std::unique_ptr<MemberIterator> memberIter;
132public:
133        IndexIterator( const CodeLocation & loc, size_t size ) :
134                location( loc ), size( size )
135        {}
136
137        void setPosition( const Expr * expr ) {
138                // need to permit integer-constant-expressions, including: integer constants,
139                // enumeration constants, character constants, sizeof expressions, alignof expressions,
140                // cast expressions
141
142                auto arg = eval( expr );
143                assertf( arg.hasKnownValue, "Non-evaluable expression made it to IndexIterator" );
144                index = arg.knownValue;
145
146                // if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
147                //      try {
148                //              index = constExpr->intValue();
149                //      } catch ( SemanticErrorException & ) {
150                //              SemanticError( expr, "Constant expression of non-integral type in array designator: " );
151                //      }
152                // } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
153                //      setPosition( castExpr->arg );
154                // } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
155                //      index = 0;
156                // } else {
157                //      assertf( false, "2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
158                // }
159        }
160
161        void setPosition(
162                std::deque<ast::ptr<ast::Expr>>::const_iterator begin,
163                std::deque<ast::ptr<ast::Expr>>::const_iterator end
164        ) override {
165                if ( begin == end ) return;
166
167                setPosition( *begin );
168                memberIter->setPosition( ++begin, end );
169        }
170
171        std::deque< InitAlternative > getOptions() const override { return first(); }
172
173        operator bool() const override { return index < size; }
174};
175
176/// Iterates over the members of array types:
177class ArrayIterator final : public IndexIterator {
178        const ArrayType * array = nullptr;
179        const Type * base = nullptr;
180
181        size_t getSize( const Expr * expr ) {
182                auto res = eval( expr );
183                if ( !res.hasKnownValue ) {
184                        SemanticError( location, "Array designator must be a constant expression %s", toString( expr ).c_str() );
185                }
186                return res.knownValue;
187        }
188
189public:
190        ArrayIterator( const CodeLocation & loc, const ArrayType * at ) :
191                        IndexIterator( loc, getSize( at->dimension) ),
192                        array( at ), base( at->base ) {
193                PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
194                memberIter.reset( createMemberIterator( loc, base ) );
195                if ( at->isVarLen ) {
196                        SemanticError( location, at, "VLA initialization does not support @=: " );
197                }
198        }
199
200        ArrayIterator & bigStep() override {
201                PRINT( std::cerr << "bigStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
202                ++index;
203                memberIter.reset( index < size ? createMemberIterator( location, base ) : nullptr );
204                return *this;
205        }
206
207        ArrayIterator & smallStep() override {
208                PRINT( std::cerr << "smallStep in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
209                if ( memberIter ) {
210                        PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
211                        memberIter->smallStep();
212                        if ( *memberIter ) {
213                                PRINT( std::cerr << "has valid member iter" << std::endl; )
214                                return *this;
215                        }
216                }
217                return bigStep();
218        }
219
220        const Type * getType() override { return array; }
221
222        const Type * getNext() override { return base; }
223
224        std::deque< InitAlternative > first() const override {
225                PRINT( std::cerr << "first in ArrayIterator (" << index << "/" << size << ")" << std::endl; )
226                if ( memberIter && *memberIter ) {
227                        std::deque< InitAlternative > ret = memberIter->first();
228                        for ( InitAlternative & alt : ret ) {
229                                alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
230                        }
231                        return ret;
232                }
233                return {};
234        }
235};
236
237class AggregateIterator : public MemberIterator {
238protected:
239        using MemberList = std::vector< ptr< Decl > >;
240
241        CodeLocation location;
242        std::string kind;  // for debug
243        std::string name;
244        const Type * inst;
245        const MemberList & members;
246        MemberList::const_iterator curMember;
247        bool atbegin = true;  // false at first {small,big}Step
248        const Type * curType = nullptr;
249        std::unique_ptr< MemberIterator > memberIter = nullptr;
250        TypeSubstitution sub;
251
252        bool init() {
253                PRINT( std::cerr << "--init()--" << members.size() << std::endl; )
254                if ( curMember != members.end() ) {
255                        if ( auto field = curMember->as< ObjectDecl >() ) {
256                                PRINT( std::cerr << "incremented to field: " << field << std::endl; )
257                                curType = field->get_type();
258                                memberIter.reset( createMemberIterator( location, curType ) );
259                                return true;
260                        }
261                }
262                return false;
263        }
264
265        AggregateIterator(
266                const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
267                const MemberList & ms )
268        : location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
269          sub( genericSubstitution( i ) ) {
270                PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
271                init();
272        }
273
274public:
275        void setPosition(
276                std::deque< ptr< Expr > >::const_iterator begin,
277                std::deque< ptr< Expr > >::const_iterator end
278        ) final {
279                if ( begin == end ) return;
280
281                if ( auto varExpr = begin->as< VariableExpr >() ) {
282                        for ( curMember = members.begin(); curMember != members.end(); ++curMember ) {
283                                if ( *curMember != varExpr->var ) continue;
284
285                                ++begin;
286
287                                memberIter.reset( createMemberIterator( location, varExpr->result ) );
288                                curType = varExpr->result;
289                                atbegin = curMember == members.begin() && begin == end;
290                                memberIter->setPosition( begin, end );
291                                return;
292                        }
293                        assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
294                } else {
295                        assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
296                }
297        }
298
299        std::deque< InitAlternative > getOptions() const final {
300                if ( memberIter && *memberIter ) {
301                        std::deque< InitAlternative > ret = memberIter->first();
302                        PRINT( std::cerr << "sub: " << sub << std::endl; )
303                        for ( InitAlternative & alt : ret ) {
304                                PRINT( std::cerr << "iterating and adding designators" << std::endl; )
305                                alt.designation.get_and_mutate()->designators.emplace_front(
306                                        new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
307                                // need to substitute for generic types so that casts are to concrete types
308                                alt.type = shallowCopy(alt.type.get());
309                                PRINT( std::cerr << "  type is: " << alt.type; )
310                                sub.apply( alt.type ); // also apply to designation??
311                                PRINT( std::cerr << " ==> " << alt.type << std::endl; )
312                        }
313                        return ret;
314                }
315                return {};
316        }
317
318        AggregateIterator & smallStep() final {
319                PRINT( std::cerr << "smallStep in " << kind << std::endl; )
320                atbegin = false;
321                if ( memberIter ) {
322                        PRINT( std::cerr << "has member iter, incrementing..." << std::endl; )
323                        memberIter->smallStep();
324                        if ( *memberIter ) {
325                                PRINT( std::cerr << "success!" << std::endl; )
326                                return *this;
327                        }
328                }
329                return bigStep();
330        }
331
332        AggregateIterator & bigStep() override = 0;
333
334        const Type * getType() final { return inst; }
335
336        const Type * getNext() final {
337                bool hasMember = memberIter && *memberIter;
338                return hasMember ? memberIter->getType() : nullptr;
339        }
340
341        std::deque< InitAlternative > first() const final {
342                std::deque< InitAlternative > ret;
343                PRINT( std::cerr << "first " << kind << std::endl; )
344                if ( memberIter && *memberIter ) {
345                        PRINT( std::cerr << "adding children" << std::endl; )
346                        ret = memberIter->first();
347                        for ( InitAlternative & alt : ret ) {
348                                PRINT( std::cerr << "iterating and adding designators" << std::endl; )
349                                alt.designation.get_and_mutate()->designators.emplace_front(
350                                        new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
351                        }
352                }
353                if ( atbegin ) {
354                        // only add self if at the very beginning of the structure
355                        PRINT( std::cerr << "adding self" << std::endl; )
356                        ret.emplace_front( inst, new Designation{ location } );
357                }
358                return ret;
359        }
360};
361
362class StructIterator final : public AggregateIterator {
363public:
364        StructIterator( const CodeLocation & loc, const StructInstType * inst )
365        : AggregateIterator( loc, "StructIterator", inst->name, inst, inst->base->members ) {}
366
367        operator bool() const override {
368                return curMember != members.end() || (memberIter && *memberIter);
369        }
370
371        StructIterator & bigStep() override {
372                PRINT( std::cerr << "bigStep in " << kind << std::endl; )
373                atbegin = false;
374                memberIter = nullptr;
375                curType = nullptr;
376                while ( curMember != members.end() ) {
377                        ++curMember;
378                        if ( init() ) return *this;
379                }
380                return *this;
381        }
382};
383
384class UnionIterator final : public AggregateIterator {
385public:
386        UnionIterator( const CodeLocation & loc, const UnionInstType * inst )
387        : AggregateIterator( loc, "UnionIterator", inst->name, inst, inst->base->members ) {}
388
389        operator bool() const override { return memberIter && *memberIter; }
390
391        UnionIterator & bigStep() override {
392                // unions only initialize one member
393                PRINT( std::cerr << "bigStep in " << kind << std::endl; )
394                atbegin = false;
395                memberIter = nullptr;
396                curType = nullptr;
397                curMember = members.end();
398                return *this;
399        }
400};
401
402/// Iterates across the positions in a tuple:
403class TupleIterator final : public IndexIterator {
404        ast::TupleType const * const tuple;
405
406        const ast::Type * typeAtIndex() const {
407                assert( index < size );
408                return tuple->types[ index ].get();
409        }
410
411public:
412        TupleIterator( const CodeLocation & loc, const TupleType * type )
413        : IndexIterator( loc, type->size() ), tuple( type ) {
414                PRINT( std::cerr << "Creating tuple iterator: " << type << std::endl; )
415                memberIter.reset( createMemberIterator( loc, typeAtIndex() ) );
416        }
417
418        TupleIterator & bigStep() override {
419                ++index;
420                memberIter.reset( index < size ?
421                        createMemberIterator( location, typeAtIndex() ) : nullptr );
422                return *this;
423        }
424
425        TupleIterator & smallStep() override {
426                if ( memberIter ) {
427                        PRINT( std::cerr << "has member iter: " << *memberIter << std::endl; )
428                        memberIter->smallStep();
429                        if ( !memberIter ) {
430                                PRINT( std::cerr << "has valid member iter" << std::endl; )
431                                return *this;
432                        }
433                }
434                return bigStep();
435        }
436
437        const ast::Type * getType() override {
438                return tuple;
439        }
440
441        const ast::Type * getNext() override {
442                bool hasMember = memberIter && *memberIter;
443                return hasMember ? memberIter->getType() : nullptr;
444        }
445
446        std::deque< InitAlternative > first() const override {
447                PRINT( std::cerr << "first in TupleIterator (" << index << "/" << size << ")" << std::endl; )
448                if ( memberIter && *memberIter ) {
449                        std::deque< InitAlternative > ret = memberIter->first();
450                        for ( InitAlternative & alt : ret ) {
451                                alt.designation.get_and_mutate()->designators.emplace_front(
452                                        ConstantExpr::from_ulong( location, index ) );
453                        }
454                        return ret;
455                }
456                return {};
457        }
458};
459
460MemberIterator * createMemberIterator( const CodeLocation & loc, const Type * type ) {
461        if ( auto aggr = dynamic_cast< const BaseInstType * >( type ) ) {
462                if ( auto sit = dynamic_cast< const StructInstType * >( aggr ) ) {
463                        assert( sit->base );
464                        return new StructIterator{ loc, sit };
465                } else if ( auto uit = dynamic_cast< const UnionInstType * >( aggr ) ) {
466                        assert( uit->base );
467                        return new UnionIterator{ loc, uit };
468                } else {
469                        assertf(
470                                dynamic_cast< const EnumInstType * >( type )
471                                        || dynamic_cast< const TypeInstType * >( type ),
472                                "Encountered unhandled BaseInstType in createMemberIterator: %s",
473                                        toString( type ).c_str() );
474                        return new SimpleIterator{ loc, type };
475                }
476        } else if ( auto at = dynamic_cast< const ArrayType * >( type ) ) {
477                return new ArrayIterator{ loc, at };
478        } else if ( auto tt = dynamic_cast< const TupleType * >( type ) ) {
479                return new TupleIterator{ loc, tt };
480        } else {
481                return new SimpleIterator{ loc, type };
482        }
483}
484
485} // namespace
486
487CurrentObject::CurrentObject( const CodeLocation & loc, const Type * type ) : objStack() {
488        objStack.emplace_back( new SimpleIterator{ loc, type } );
489}
490
491const Designation * CurrentObject::findNext( const Designation * designation ) {
492        using DesignatorChain = std::deque< ptr< Expr > >;
493        PRINT( std::cerr << "___findNext" << std::endl; )
494
495        // find all the d's
496        std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
497        std::deque< const Type * > curTypes{ objStack.back()->getType() }, newTypes;
498        for ( const Expr * expr : designation->designators ) {
499                PRINT( std::cerr << "____untyped: " << expr << std::endl; )
500                auto dit = desigAlts.begin();
501                auto nexpr = dynamic_cast< const NameExpr * >( expr );
502
503                for ( const Type * t : curTypes ) {
504                        assert( dit != desigAlts.end() );
505                        DesignatorChain & d = *dit;
506                        // Name Designation:
507                        if ( nexpr ) {
508                                PRINT( std::cerr << "____actual: " << t << std::endl; )
509                                if ( auto refType = dynamic_cast< const BaseInstType * >( t ) ) {
510                                        // concatenate identical field names
511                                        for ( const Decl * mem : refType->lookup( nexpr->name ) ) {
512                                                if ( auto field = dynamic_cast< const ObjectDecl * >( mem ) ) {
513                                                        PRINT( std::cerr << "____alt: " << field->type << std::endl; )
514                                                        DesignatorChain d2 = d;
515                                                        d2.emplace_back( new VariableExpr{ expr->location, field } );
516                                                        newDesigAlts.emplace_back( std::move( d2 ) );
517                                                        newTypes.emplace_back( field->type );
518                                                }
519                                        }
520                                }
521
522                                ++dit;
523                        // Index Designation:
524                        } else {
525                                if ( auto at = dynamic_cast< const ArrayType * >( t ) ) {
526                                        PRINT( std::cerr << "____alt: " << at->get_base() << std::endl; )
527                                        d.emplace_back( expr );
528                                        newDesigAlts.emplace_back( d );
529                                        newTypes.emplace_back( at->base );
530                                }
531                        }
532                }
533
534                // reset queue
535                desigAlts = std::move( newDesigAlts );
536                newDesigAlts.clear();
537                curTypes = std::move( newTypes );
538                newTypes.clear();
539                assertf( desigAlts.size() == curTypes.size(), "Designator alternatives (%zu) and current types (%zu) out of sync", desigAlts.size(), curTypes.size() );
540        }
541
542        if ( desigAlts.size() > 1 ) {
543                SemanticError( designation, toString("Too many alternatives (", desigAlts.size(), ") for designation: ") );
544        } else if ( desigAlts.empty() ) {
545                SemanticError( designation, "No reasonable alternatives for designation: " );
546        }
547
548        DesignatorChain & d = desigAlts.back();
549        PRINT( for ( Expression * expr : d ) {
550                std::cerr << "____desig: " << expr << std::endl;
551        } ) // for
552        assertf( ! curTypes.empty(), "empty designator chosen");
553
554        // set new designators
555        assertf( ! objStack.empty(), "empty object stack when setting designation" );
556        Designation * actualDesignation =
557                new Designation{ designation->location, DesignatorChain{d} };
558        objStack.back()->setPosition( d ); // destroys d
559        return actualDesignation;
560}
561
562void CurrentObject::setNext( const Designation * designation ) {
563        PRINT( std::cerr << "____setNext" << designation << std::endl; )
564        assertf( ! objStack.empty(), "obj stack empty in setNext" );
565        objStack.back()->setPosition( designation->designators );
566}
567
568void CurrentObject::increment() {
569        PRINT( std::cerr << "____increment" << std::endl; )
570        if ( objStack.empty() ) return;
571        PRINT( std::cerr << *objStack.back() << std::endl; )
572        objStack.back()->smallStep();
573}
574
575void CurrentObject::enterListInit( const CodeLocation & loc ) {
576        PRINT( std::cerr << "____entering list init" << std::endl; )
577        assertf( ! objStack.empty(), "empty obj stack entering list init" );
578        const ast::Type * type = objStack.back()->getNext();
579        assert( type );
580        objStack.emplace_back( createMemberIterator( loc, type ) );
581}
582
583void CurrentObject::exitListInit() {
584        PRINT( std::cerr << "____exiting list init" << std::endl; )
585        assertf( ! objStack.empty(), "objstack empty" );
586        objStack.pop_back();
587        if ( ! objStack.empty() ) {
588                PRINT( std::cerr << *objStack.back() << std::endl; )
589                objStack.back()->bigStep();
590        }
591}
592
593std::deque< InitAlternative > CurrentObject::getOptions() {
594        PRINT( std::cerr << "____getting current options" << std::endl; )
595        assertf( ! objStack.empty(), "objstack empty in getOptions" );
596        return objStack.back()->getOptions();
597}
598
599const Type * CurrentObject::getCurrentType() {
600        PRINT( std::cerr << "____getting current type" << std::endl; )
601        assertf( ! objStack.empty(), "objstack empty in getCurrentType" );
602        return objStack.back()->getNext();
603}
604
605} // namespace ast
606
607// Local Variables: //
608// tab-width: 4 //
609// mode: c++ //
610// compile-command: "make install" //
611// End: //
Note: See TracBrowser for help on using the repository browser.