source: src/ResolvExpr/CurrentObject.cc@ bdc8591

Last change on this file since bdc8591 was b1f2007d, checked in by Peter A. Buhr <pabuhr@…>, 22 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.