source: src/ResolvExpr/CurrentObject.cc @ 8b4faf6

Last change on this file since 8b4faf6 was b1f2007, checked in by Peter A. Buhr <pabuhr@…>, 11 months ago

first attempt at simplifying SemanticError? and its usage

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