Changes in / [221c542e:bad9c8f]


Ignore:
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/enum.tex

    r221c542e rbad9c8f  
    245245
    246246
    247 \
     247\subsection{Aggressive Inline}
     248To avoid allocating memory for enumeration data structures, \CFA inline the result of enumeration attribute pseudo-function whenever it is possible.
     249\begin{lstlisting}[label=lst:enumeration_inline]
     250enum(int) OddNumber { A=1, B=3 };
     251sout | "A: " | OddNumber.A | "B: " | OddNumber.B | "A+B: " | OddNumber.A + OddNumber.B
     252\end{lstlisting}
     253Instead of calling pseudo-function @value@ on expression $OddNumber.A$ and $OddNumber.B$, because the result is known statistically, \CFA will inline the constant expression 1 and 3, respectively. Because no runtime lookup for enumeration value is necessary, \CFA will not generate data structure for enumeration OddNumber.
     254
     255\subsection{Weak Reference}
     256\begin{lstlisting}[label=lst:week_ref]
     257enum(int) OddNumber { A=1, B=3 };
     258enum OddNumber i = ...;
     259...
     260sout | OddNumber;
     261\end{lstlisting}
     262In this example, \CFA cannot determine the static value of the enum variable i, and Runtime lookup is necessary. The OddNumber can be referenced in multiple compilations, and allocating the arrays in all compilation units is not desirable. \CFA addresses this by declaring the value array as a weak reference. All compilation units reference OddNumber have weak references to the same enumeration data structure. No extra memory is allocated if more compilation units reference OddNumber, and the OddNumber is initialized once.
     263
    248264\section{Unification}
    249265
     
    622638\section{Implementation}
    623639
    624 \subsection{Static Attribute Expression}
    625 \begin{lstlisting}[label=lst:static_attr]
    626 enum( char * ) Colour {
    627     Red = "red", Blue = "blue", Green = "green" 
    628 };
    629 \end{lstlisting}
    630 An enumerator expression returns its enumerator value as a constant expression with no runtime cost. For example, @Colour.Red@ is equivalent to the constant expression "red", and \CFA finishes the expression evaluation before generating the corresponding C code. Applying a pseudo-function to a constant enumerator expression results in a constant expression as well. @value( Colour.Red )@, @position( Colour. Red )@, and @label( Colour.Red )@ are equivalent to constant expression with char * value "red", int value 0, and char * value "Red", respectively.
    631 
    632 \subsection{Runtime Attribute Expression and Weak Referenced Data}
    633 \begin{lstlisting}[label=lst:dynamic_attr]
    634 Colour c;
    635 ...
    636 value( c ); // or c
    637 \end{lstlisting}
    638 An enumeration variable c is equivalent to an integer variable with the value of @position( c )@ In Example~\ref{lst:dynamic_attr}, the value of enumeration variable c is unknown at compile time. In this case, the pseudo-function calls are reduced to expression that returns the enumerator values at runtime.
    639 
    640 \CFA stores the variables and labels in const arrays to provide runtime lookup for enumeration information.
    641 
    642 \begin{lstlisting}[label=lst:attr_array]
    643 const char * Colour_labels [3] = { "Red", "Blue", "Green" };
    644 const char * Colour_values [3] = { "red", "blue", "green" };
    645 \end{lstlisting}
    646 The \CFA compiles transforms the attribute expressions into array access.
    647 \begin{lstlisting}[label=lst:attr_array_access]
    648 position( c ) // c; an integer
    649 value( c ); // Colour_values[c]
    650 label( c ); // Colour_labels[c]
    651 \end{lstlisting}
    652 
    653 To avoid unnecessary memory usage, the labels and values array are only generated as needed, and only generate once across all compilation units. By default, \CFA defers the declaration of the label and value arrays until an call to attribute function with a dynamic value. If an attribute function is never called on a dynamic value of an enumerator, the array will never be allocated. Once the arrays are created, all compilation units share a weak reference to the allocation array.
    654 
    655 \subsection{Enum Prelude}
    656 
    657 \begin{lstlisting}[label=lst:enum_func_dec]
    658 forall( T ) {
    659     unsigned position( unsigned );
    660     T value( unsigned );
    661     char * label( unsigned );
    662 }
    663 \end{lstlisting}
    664 \CFA loads the declaration of enumeration function from the enum.hfa.
    665 
    666 \subsection{Internal Representation}
    667 
     640\subsection{Compiler Representation (Reworking)}
    668641The definition of an enumeration is represented by an internal type called @EnumDecl@. At the minimum, it stores all the information needed to construct the companion object. Therefore, an @EnumDecl@ can be represented as the following:
    669642\begin{lstlisting}[label=lst:EnumDecl]
     
    694667
    695668
    696 % \subsection{(Rework) Companion Object and Companion Function}
    697 
    698 % \begin{lstlisting}[caption={Enum Type Functions}, label=lst:cforall_enum_functions]
    699 % forall( T )
    700 % struct Companion {
    701 %       const T * const values;
    702 %         const char * label;
    703 %       int length;
    704 % };
    705 % \end{lstlisting}
    706 % \CFA generates companion objects, an instance of structure that encloses @necessary@ data to represent an enumeration. The size of the companion is unknown at the compilation time, and it "grows" in size to compensate for the @usage@.
    707 
    708 % The companion object is singleton across the compilation (investigation). 
    709 
    710 % \CFA generates the definition of companion functions.
    711 % Because \CFA implicitly stores an enumeration instance as its position, the companion function @position@ does nothing but return the position it is passed.
    712 % Companions function @value@ and @label@ return the array item at the given position of @values@ and @labels@, respectively.
    713 % \begin{lstlisting}[label=lst:companion_definition]
    714 % int position( Companion o, int pos ) { return pos; }
    715 % T value( Companion o, int pos ) { return o.values[ pos ]; }
    716 % char * label( Companion o, int pos ) { return o.labels[ pos ]; }
    717 % \end{lstlisting}
    718 % Notably, the @Companion@ structure definition, and all companion objects, are visible to users.
    719 % A user can retrieve values and labels defined in an enumeration by accessing the values and labels directly, or indirectly by calling @Companion@ functions @values@ and @labels@
    720 % \begin{lstlisting}[label=lst:companion_definition_values_labels]
    721 % Colour.values; // read the Companion's values
    722 % values( Colour ); // same as Colour.values
    723 % \end{lstlisting}
     669\subsection{(Rework) Companion Object and Companion Function}
     670
     671\begin{lstlisting}[caption={Enum Type Functions}, label=lst:cforall_enum_functions]
     672forall( T )
     673struct Companion {
     674        const T * const values;
     675        const char * label;
     676        int length;
     677};
     678\end{lstlisting}
     679\CFA generates companion objects, an instance of structure that encloses @necessary@ data to represent an enumeration. The size of the companion is unknown at the compilation time, and it "grows" in size to compensate for the @usage@.
     680
     681The companion object is singleton across the compilation (investigation). 
     682
     683\CFA generates the definition of companion functions.
     684Because \CFA implicitly stores an enumeration instance as its position, the companion function @position@ does nothing but return the position it is passed.
     685Companions function @value@ and @label@ return the array item at the given position of @values@ and @labels@, respectively.
     686\begin{lstlisting}[label=lst:companion_definition]
     687int position( Companion o, int pos ) { return pos; }
     688T value( Companion o, int pos ) { return o.values[ pos ]; }
     689char * label( Companion o, int pos ) { return o.labels[ pos ]; }
     690\end{lstlisting}
     691Notably, the @Companion@ structure definition, and all companion objects, are visible to users.
     692A user can retrieve values and labels defined in an enumeration by accessing the values and labels directly, or indirectly by calling @Companion@ functions @values@ and @labels@
     693\begin{lstlisting}[label=lst:companion_definition_values_labels]
     694Colour.values; // read the Companion's values
     695values( Colour ); // same as Colour.values
     696\end{lstlisting}
    724697
    725698\subsection{Companion Traits (experimental)}
  • src/AST/Decl.hpp

    r221c542e rbad9c8f  
    312312        ptr<Type> base;
    313313        enum class EnumHiding { Visible, Hide } hide;
     314
    314315        EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
    315316                std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall,
  • src/CodeGen/CodeGenerator.cpp

    r221c542e rbad9c8f  
    11351135                if ( clause->when_cond ) {
    11361136                        output << "when(";
    1137                         clause->when_cond->accept( *visitor );
     1137                        stmt->timeout_cond->accept( *visitor );
    11381138                        output << ") ";
    11391139                }
  • src/InitTweak/FixInit.cpp

    r221c542e rbad9c8f  
    4949        if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) {
    5050                return inst->base->params;
    51         } else if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
     51        }
     52        if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) {
    5253                return inst->base->params;
    5354        }
     
    244245const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) {
    245246        const CodeLocation loc = input->location;
     247        // unwrap implicit statement wrapper
     248        // Statement * dtor = input;
    246249        assert( input );
     250        // std::list< const ast::Expr * > matches;
    247251        auto matches = collectCtorDtorCalls( input );
    248252
    249         // The simple case requires a direct call and only one destructor call.
    250         if ( dynamic_cast< const ast::ExprStmt * >( input ) && matches.size() == 1 ) {
    251                 auto func = getFunction( matches.front() );
    252                 assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
    253 
    254                 // cleanup argument must be a function, not an object (including function pointer)
    255                 if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
    256                         if ( dtorFunc->type->forall.empty() ) {
    257                                 // simple case where the destructor is a monomorphic function call - can simply
    258                                 // use that function as the cleanup function.
    259                                 return func;
     253        if ( dynamic_cast< const ast::ExprStmt * >( input ) ) {
     254                // only one destructor call in the expression
     255                if ( matches.size() == 1 ) {
     256                        auto func = getFunction( matches.front() );
     257                        assertf( func, "getFunction failed to find function in %s", toString( matches.front() ).c_str() );
     258
     259                        // cleanup argument must be a function, not an object (including function pointer)
     260                        if ( auto dtorFunc = dynamic_cast< const ast::FunctionDecl * > ( func ) ) {
     261                                if ( dtorFunc->type->forall.empty() ) {
     262                                        // simple case where the destructor is a monomorphic function call - can simply
     263                                        // use that function as the cleanup function.
     264                                        return func;
     265                                }
    260266                        }
    261267                }
     
    295301        for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) {
    296302                try {
     303                        // maybeAccept( *i, fixer ); translationUnit should never contain null
    297304                        *i = (*i)->accept(fixer);
    298305                        translationUnit.decls.splice( i, fixer.core.staticDtorDecls );
     
    307314
    308315const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) {
     316        // we might loose the result expression here so add a pointer to trace back
    309317        assert( stmtExpr->result );
    310         if ( stmtExpr->result->isVoid() ) return stmtExpr;
    311 
    312         auto mutExpr = mutate( stmtExpr );
    313         const ast::CompoundStmt * body = mutExpr->stmts;
    314         assert( !body->kids.empty() );
    315         mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
    316         return mutExpr;
     318        const ast::Type * result = stmtExpr->result;
     319        if ( ! result->isVoid() ) {
     320                auto mutExpr = mutate(stmtExpr);
     321                const ast::CompoundStmt * body = mutExpr->stmts;
     322                assert( ! body->kids.empty() );
     323                mutExpr->resultExpr = body->kids.back().strict_as<ast::ExprStmt>();
     324                return mutExpr;
     325        }
     326        return stmtExpr;
    317327}
    318328
     
    320330        // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
    321331        // in the correct places
    322         return new ast::CompoundStmt( stmt->location, { stmt } );
     332        ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } );
     333        return ret;
    323334}
    324335
     
    545556        arg = cpCtor;
    546557        return destructRet( tmp, arg );
     558
     559        // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
    547560}
    548561
     
    595608        }
    596609        return nullptr;
     610        // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
    597611}
    598612
     
    611625        for ( auto & arg : appExpr->args ) {
    612626                const ast::Type * formal = nullptr;
    613                 // Do not copy construct C-style variadic arguments.
    614                 if ( iter != params.end() ) {
     627                if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
     628                        // DeclarationWithType * param = *iter++;
    615629                        formal = *iter++;
    616630                }
     
    645659        // deletion of wrapper should be handled by pass template now
    646660
     661        // impCpCtorExpr->callExpr = nullptr;
    647662        assert (appExpr->env == nullptr);
    648663        appExpr->env = impCpCtorExpr->env;
     664        // std::swap( impCpCtorExpr->env, appExpr->env );
     665        // assert( impCpCtorExpr->env == nullptr );
     666        // delete impCpCtorExpr;
    649667
    650668        if ( returnDecl ) {
     
    658676                }
    659677                // move env from appExpr to retExpr
     678                // std::swap( assign->env, appExpr->env );
    660679                assign->env = appExpr->env;
    661680                // actual env is handled by common routine that replaces WithTypeSubstitution
     
    697716
    698717        assert( stmtExpr->result );
    699         if ( stmtExpr->result->isVoid() ) {
    700                 assert( stmtExpr->returnDecls.empty() );
    701                 assert( stmtExpr->dtors.empty() );
    702 
    703                 return stmtExpr;
    704         }
    705 
    706         static UniqueName retNamer("_tmp_stmtexpr_ret");
    707 
    708         auto result = env->apply( stmtExpr->result.get() ).node;
    709         if ( ! InitTweak::isConstructable( result ) ) {
    710                 return stmtExpr;
    711         }
    712         auto mutResult = result.get_and_mutate();
    713         mutResult->set_const(false);
    714 
    715         // create variable that will hold the result of the stmt expr
    716         auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
    717         stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
    718 
    719         assertf(
    720                 stmtExpr->resultExpr,
    721                 "Statement-Expression should have a resulting expression at %s:%d",
    722                 stmtExpr->location.filename.c_str(),
    723                 stmtExpr->location.first_line
    724         );
    725 
    726         const ast::ExprStmt * last = stmtExpr->resultExpr;
    727         // xxx - if this is non-unique, need to copy while making resultExpr ref
    728         assertf(last->unique(), "attempt to modify weakly shared statement");
    729         auto mutLast = mutate(last);
    730         // above assertion means in-place mutation is OK
    731         try {
    732                 mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
    733         } catch(...) {
    734                 std::cerr << "*CFA internal error: ";
    735                 std::cerr << "can't resolve implicit constructor";
    736                 std::cerr << " at " << stmtExpr->location.filename;
    737                 std::cerr << ":" << stmtExpr->location.first_line << std::endl;
    738 
    739                 abort();
    740         }
    741 
    742         // add destructors after current statement
    743         stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
    744 
    745         // must have a non-empty body, otherwise it wouldn't have a result
    746         assert( ! stmts.empty() );
    747 
    748         // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
    749         stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
     718        // const ast::Type * result = stmtExpr->result;
     719        if ( ! stmtExpr->result->isVoid() ) {
     720                static UniqueName retNamer("_tmp_stmtexpr_ret");
     721
     722                // result = result->clone();
     723                auto result = env->apply( stmtExpr->result.get() ).node;
     724                if ( ! InitTweak::isConstructable( result ) ) {
     725                        // delete result;
     726                        return stmtExpr;
     727                }
     728                auto mutResult = result.get_and_mutate();
     729                mutResult->set_const(false);
     730
     731                // create variable that will hold the result of the stmt expr
     732                auto ret = new ast::ObjectDecl(loc, retNamer.newName(), mutResult, nullptr );
     733                stmtsToAddBefore.push_back( new ast::DeclStmt(loc, ret ) );
     734
     735                assertf(
     736                        stmtExpr->resultExpr,
     737                        "Statement-Expression should have a resulting expression at %s:%d",
     738                        stmtExpr->location.filename.c_str(),
     739                        stmtExpr->location.first_line
     740                );
     741
     742                const ast::ExprStmt * last = stmtExpr->resultExpr;
     743                // xxx - if this is non-unique, need to copy while making resultExpr ref
     744                assertf(last->unique(), "attempt to modify weakly shared statement");
     745                auto mutLast = mutate(last);
     746                // above assertion means in-place mutation is OK
     747                try {
     748                        mutLast->expr = makeCtorDtor( "?{}", ret, mutLast->expr );
     749                } catch(...) {
     750                        std::cerr << "*CFA internal error: ";
     751                        std::cerr << "can't resolve implicit constructor";
     752                        std::cerr << " at " << stmtExpr->location.filename;
     753                        std::cerr << ":" << stmtExpr->location.first_line << std::endl;
     754
     755                        abort();
     756                }
     757
     758                // add destructors after current statement
     759                stmtsToAddAfter.push_back( new ast::ExprStmt(loc, makeCtorDtor( "^?{}", ret ) ) );
     760
     761                // must have a non-empty body, otherwise it wouldn't have a result
     762                assert( ! stmts.empty() );
     763
     764                // if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
     765                stmts.push_back( new ast::ExprStmt(loc, new ast::VariableExpr(loc, ret ) ) );
     766        } // if
    750767
    751768        assert( stmtExpr->returnDecls.empty() );
     
    781798        auto mutExpr = mutate(unqExpr);
    782799        if ( ! unqMap.count( unqExpr->id ) ) {
     800                // resolve expr and find its
     801
    783802                auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>();
     803                // PassVisitor<ResolveCopyCtors> fixer;
     804
    784805                mutExpr->expr = mutExpr->expr->accept( *visitor );
    785806                // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
     
    799820        } else {
    800821                // take data from other UniqueExpr to ensure consistency
     822                // delete unqExpr->get_expr();
    801823                mutExpr->expr = unqMap[mutExpr->id]->expr;
     824                // delete unqExpr->result;
    802825                mutExpr->result = mutExpr->expr->result;
    803826        }
     
    809832
    810833        // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit)
    811         ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>();
    812 
    813         if ( nullptr == ctorInit ) return _objDecl;
    814 
    815         auto objDecl = mutate(_objDecl);
    816 
    817         // could this be non-unique?
    818         if (objDecl != _objDecl) {
    819                 std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
    820         }
    821         // a decision should have been made by the resolver, so ctor and init are not both non-NULL
    822         assert( ! ctorInit->ctor || ! ctorInit->init );
    823         if ( const ast::Stmt * ctor = ctorInit->ctor ) {
    824                 if ( objDecl->storage.is_static ) {
    825                         addDataSectionAttribute(objDecl);
    826                         // originally wanted to take advantage of gcc nested functions, but
    827                         // we get memory errors with this approach. To remedy this, the static
    828                         // variable is hoisted when the destructor needs to be called.
    829                         //
    830                         // generate:
    831                         // static T __objName_static_varN;
    832                         // void __objName_dtor_atexitN() {
    833                         //   __dtor__...;
    834                         // }
    835                         // int f(...) {
    836                         //   ...
    837                         //   static bool __objName_uninitialized = true;
    838                         //   if (__objName_uninitialized) {
    839                         //     __ctor(__objName);
    840                         //     __objName_uninitialized = false;
    841                         //     atexit(__objName_dtor_atexitN);
    842                         //   }
    843                         //   ...
    844                         // }
    845 
    846                         static UniqueName dtorCallerNamer( "_dtor_atexit" );
    847 
    848                         // static bool __objName_uninitialized = true
    849                         auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
    850                         auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
    851                         auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
    852                         isUninitializedVar->fixUniqueId();
    853 
    854                         // __objName_uninitialized = false;
    855                         auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
    856                         setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
    857                         setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
    858 
    859                         // generate body of if
    860                         auto initStmts = new ast::CompoundStmt(loc);
    861                         auto & body = initStmts->kids;
    862                         body.push_back( ctor );
    863                         body.push_back( new ast::ExprStmt(loc, setTrue ) );
    864 
    865                         // put it all together
    866                         auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
    867                         stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
    868                         stmtsToAddAfter.push_back( ifStmt );
    869 
    870                         const ast::Stmt * dtor = ctorInit->dtor;
    871                         if ( dtor ) {
    872                                 // if the object has a non-trivial destructor, have to
    873                                 // hoist it and the object into the global space and
    874                                 // call the destructor function with atexit.
    875 
    876                                 // void __objName_dtor_atexitN(...) {...}
    877                                 ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
    878                                 dtorCaller->fixUniqueId();
    879 
    880                                 // atexit(dtor_atexit);
    881                                 auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
    882                                 callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
    883 
    884                                 body.push_back( new ast::ExprStmt(loc, callAtexit ) );
    885 
    886                                 // hoist variable and dtor caller decls to list of decls that will be added into global scope
    887                                 staticDtorDecls.push_back( objDecl );
    888                                 staticDtorDecls.push_back( dtorCaller );
    889 
    890                                 // need to rename object uniquely since it now appears
    891                                 // at global scope and there could be multiple function-scoped
    892                                 // static variables with the same name in different functions.
    893                                 // Note: it isn't sufficient to modify only the mangleName, because
    894                                 // then subsequent SymbolTable passes can choke on seeing the object's name
    895                                 // if another object has the same name and type. An unfortunate side-effect
    896                                 // of renaming the object is that subsequent NameExprs may fail to resolve,
    897                                 // but there shouldn't be any remaining past this point.
    898                                 static UniqueName staticNamer( "_static_var" );
    899                                 objDecl->name = objDecl->name + staticNamer.newName();
    900                                 objDecl->mangleName = Mangle::mangle( objDecl );
    901                                 objDecl->init = nullptr;
    902 
    903                                 // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
    904                                 // create a new object which is never used
    905                                 static UniqueName dummyNamer( "_dummy" );
    906                                 auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
    907                                 return dummy;
     834        if ( ast::ptr<ast::ConstructorInit> ctorInit = _objDecl->init.as<ast::ConstructorInit>() ) {
     835                auto objDecl = mutate(_objDecl);
     836
     837                // could this be non-unique?
     838                if (objDecl != _objDecl) {
     839                        std::cerr << "FixInit: non-unique object decl " << objDecl->location << objDecl->name << std::endl;
     840                }
     841                // a decision should have been made by the resolver, so ctor and init are not both non-NULL
     842                assert( ! ctorInit->ctor || ! ctorInit->init );
     843                if ( const ast::Stmt * ctor = ctorInit->ctor ) {
     844                        if ( objDecl->storage.is_static ) {
     845                                addDataSectionAttribute(objDecl);
     846                                // originally wanted to take advantage of gcc nested functions, but
     847                                // we get memory errors with this approach. To remedy this, the static
     848                                // variable is hoisted when the destructor needs to be called.
     849                                //
     850                                // generate:
     851                                // static T __objName_static_varN;
     852                                // void __objName_dtor_atexitN() {
     853                                //   __dtor__...;
     854                                // }
     855                                // int f(...) {
     856                                //   ...
     857                                //   static bool __objName_uninitialized = true;
     858                                //   if (__objName_uninitialized) {
     859                                //     __ctor(__objName);
     860                                //     __objName_uninitialized = false;
     861                                //     atexit(__objName_dtor_atexitN);
     862                                //   }
     863                                //   ...
     864                                // }
     865
     866                                static UniqueName dtorCallerNamer( "_dtor_atexit" );
     867
     868                                // static bool __objName_uninitialized = true
     869                                auto boolType = new ast::BasicType( ast::BasicType::Kind::Bool );
     870                                auto boolInitExpr = new ast::SingleInit(loc, ast::ConstantExpr::from_int(loc, 1 ) );
     871                                auto isUninitializedVar = new ast::ObjectDecl(loc, objDecl->mangleName + "_uninitialized", boolType, boolInitExpr, ast::Storage::Static, ast::Linkage::Cforall);
     872                                isUninitializedVar->fixUniqueId();
     873
     874                                // __objName_uninitialized = false;
     875                                auto setTrue = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "?=?" ) );
     876                                setTrue->args.push_back( new ast::VariableExpr(loc, isUninitializedVar ) );
     877                                setTrue->args.push_back( ast::ConstantExpr::from_int(loc, 0 ) );
     878
     879                                // generate body of if
     880                                auto initStmts = new ast::CompoundStmt(loc);
     881                                auto & body = initStmts->kids;
     882                                body.push_back( ctor );
     883                                body.push_back( new ast::ExprStmt(loc, setTrue ) );
     884
     885                                // put it all together
     886                                auto ifStmt = new ast::IfStmt(loc, new ast::VariableExpr(loc, isUninitializedVar ), initStmts, 0 );
     887                                stmtsToAddAfter.push_back( new ast::DeclStmt(loc, isUninitializedVar ) );
     888                                stmtsToAddAfter.push_back( ifStmt );
     889
     890                                const ast::Stmt * dtor = ctorInit->dtor;
     891
     892                                // these should be automatically managed once reassigned
     893                                // objDecl->set_init( nullptr );
     894                                // ctorInit->set_ctor( nullptr );
     895                                // ctorInit->set_dtor( nullptr );
     896                                if ( dtor ) {
     897                                        // if the object has a non-trivial destructor, have to
     898                                        // hoist it and the object into the global space and
     899                                        // call the destructor function with atexit.
     900
     901                                        // Statement * dtorStmt = dtor->clone();
     902
     903                                        // void __objName_dtor_atexitN(...) {...}
     904                                        ast::FunctionDecl * dtorCaller = new ast::FunctionDecl(loc, objDecl->mangleName + dtorCallerNamer.newName(), {}, {}, {}, {}, new ast::CompoundStmt(loc, {dtor}), ast::Storage::Static, ast::Linkage::C );
     905                                        dtorCaller->fixUniqueId();
     906                                        // dtorCaller->stmts->push_back( dtor );
     907
     908                                        // atexit(dtor_atexit);
     909                                        auto callAtexit = new ast::UntypedExpr(loc, new ast::NameExpr(loc, "atexit" ) );
     910                                        callAtexit->args.push_back( new ast::VariableExpr(loc, dtorCaller ) );
     911
     912                                        body.push_back( new ast::ExprStmt(loc, callAtexit ) );
     913
     914                                        // hoist variable and dtor caller decls to list of decls that will be added into global scope
     915                                        staticDtorDecls.push_back( objDecl );
     916                                        staticDtorDecls.push_back( dtorCaller );
     917
     918                                        // need to rename object uniquely since it now appears
     919                                        // at global scope and there could be multiple function-scoped
     920                                        // static variables with the same name in different functions.
     921                                        // Note: it isn't sufficient to modify only the mangleName, because
     922                                        // then subsequent SymbolTable passes can choke on seeing the object's name
     923                                        // if another object has the same name and type. An unfortunate side-effect
     924                                        // of renaming the object is that subsequent NameExprs may fail to resolve,
     925                                        // but there shouldn't be any remaining past this point.
     926                                        static UniqueName staticNamer( "_static_var" );
     927                                        objDecl->name = objDecl->name + staticNamer.newName();
     928                                        objDecl->mangleName = Mangle::mangle( objDecl );
     929                                        objDecl->init = nullptr;
     930
     931                                        // xxx - temporary hack: need to return a declaration, but want to hoist the current object out of this scope
     932                                        // create a new object which is never used
     933                                        static UniqueName dummyNamer( "_dummy" );
     934                                        auto dummy = new ast::ObjectDecl(loc, dummyNamer.newName(), new ast::PointerType(new ast::VoidType()), nullptr, ast::Storage::Static, ast::Linkage::Cforall, 0, { new ast::Attribute("unused") } );
     935                                        // delete ctorInit;
     936                                        return dummy;
     937                                } else {
     938                                        objDecl->init = nullptr;
     939                                        return objDecl;
     940                                }
    908941                        } else {
    909                                 objDecl->init = nullptr;
    910                                 return objDecl;
    911                         }
     942                                auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
     943                                auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
     944                                const ast::ApplicationExpr * ctorCall = nullptr;
     945                                if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
     946                                        // clean up intrinsic copy constructor calls by making them into SingleInits
     947                                        const ast::Expr * ctorArg = ctorCall->args.back();
     948                                        // ctorCall should be gone afterwards
     949                                        auto mutArg = mutate(ctorArg);
     950                                        mutArg->env = ctorCall->env;
     951                                        // std::swap( ctorArg->env, ctorCall->env );
     952                                        objDecl->init = new ast::SingleInit(loc, mutArg );
     953
     954                                        // ctorCall->args.pop_back();
     955                                } else {
     956                                        stmtsToAddAfter.push_back( ctor );
     957                                        objDecl->init = nullptr;
     958                                        // ctorInit->ctor = nullptr;
     959                                }
     960
     961                                const ast::Stmt * dtor = ctorInit->dtor;
     962                                if ( dtor ) {
     963                                        auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
     964                                        const ast::Stmt * dtorStmt = implicit->callStmt;
     965
     966                                        // don't need to call intrinsic dtor, because it does nothing, but
     967                                        // non-intrinsic dtors must be called
     968                                        if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
     969                                                // set dtor location to the object's location for error messages
     970                                                auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
     971                                                objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
     972                                                // ctorInit->dtor = nullptr;
     973                                        } // if
     974                                }
     975                        } // if
     976                } else if ( const ast::Init * init = ctorInit->init ) {
     977                        objDecl->init = init;
     978                        // ctorInit->init = nullptr;
    912979                } else {
    913                         auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * > ( ctor );
    914                         auto ctorStmt = implicit->callStmt.as<ast::ExprStmt>();
    915                         const ast::ApplicationExpr * ctorCall = nullptr;
    916                         if ( ctorStmt && (ctorCall = isIntrinsicCallExpr( ctorStmt->expr )) && ctorCall->args.size() == 2 ) {
    917                                 // clean up intrinsic copy constructor calls by making them into SingleInits
    918                                 const ast::Expr * ctorArg = ctorCall->args.back();
    919                                 // ctorCall should be gone afterwards
    920                                 auto mutArg = mutate(ctorArg);
    921                                 mutArg->env = ctorCall->env;
    922                                 objDecl->init = new ast::SingleInit(loc, mutArg );
    923                         } else {
    924                                 stmtsToAddAfter.push_back( ctor );
    925                                 objDecl->init = nullptr;
    926                         }
    927 
    928                         const ast::Stmt * dtor = ctorInit->dtor;
    929                         if ( dtor ) {
    930                                 auto implicit = strict_dynamic_cast< const ast::ImplicitCtorDtorStmt * >( dtor );
    931                                 const ast::Stmt * dtorStmt = implicit->callStmt;
    932 
    933                                 // don't need to call intrinsic dtor, because it does nothing, but
    934                                 // non-intrinsic dtors must be called
    935                                 if ( ! isIntrinsicSingleArgCallStmt( dtorStmt ) ) {
    936                                         // set dtor location to the object's location for error messages
    937                                         auto dtorFunc = getDtorFunc( objDecl, dtorStmt, stmtsToAddBefore );
    938                                         objDecl->attributes.push_back( new ast::Attribute( "cleanup", { new ast::VariableExpr(loc, dtorFunc ) } ) );
    939                                 } // if
    940                         }
     980                        // no constructor and no initializer, which is okay
     981                        objDecl->init = nullptr;
    941982                } // if
    942         } else if ( const ast::Init * init = ctorInit->init ) {
    943                 objDecl->init = init;
    944         } else {
    945                 // no constructor and no initializer, which is okay
    946                 objDecl->init = nullptr;
     983                // delete ctorInit;
     984                return objDecl;
    947985        } // if
    948         return objDecl;
     986        return _objDecl;
    949987}
    950988
     
    9681006
    9691007void LabelFinder::previsit( const ast::CompoundStmt * stmt ) {
    970         previsit( (const ast::Stmt *)stmt );
     1008        previsit( (const ast::Stmt *) stmt );
    9711009        Parent::previsit( stmt );
    9721010}
     
    9841022        // its children manually.
    9851023        if (funcDecl->type) funcDecl->type->accept(finder);
    986         if (funcDecl->stmts) funcDecl->stmts->accept(finder);
     1024        // maybeAccept( funcDecl->type, finder );
     1025        if (funcDecl->stmts) funcDecl->stmts->accept(finder) ;
    9871026
    9881027        // all labels for this function have been collected, insert destructors as appropriate via implicit recursion.
     
    10391078}
    10401079
    1041 /// Should we check for warnings? (The function is user-defined constrctor or destructor.)
    10421080bool checkWarnings( const ast::FunctionDecl * funcDecl ) {
     1081        // only check for warnings if the current function is a user-defined constructor or destructor
    10431082        if ( ! funcDecl ) return false;
    10441083        if ( ! funcDecl->stmts ) return false;
     
    10661105
    10671106        isCtor = CodeGen::isConstructor( function->name );
    1068 
    1069         // Remaining code is only for warnings.
    1070         if ( ! checkWarnings( function ) ) return;
    1071         thisParam = function->params.front().strict_as<ast::ObjectDecl>();
    1072         auto thisType = getPointerBase( thisParam->get_type() );
    1073         auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
    1074         if ( structType ) {
    1075                 structDecl = structType->base;
    1076                 for ( auto & member : structDecl->members ) {
    1077                         if ( auto field = member.as<ast::ObjectDecl>() ) {
    1078                                 // record all of the struct type's members that need to be constructed or
    1079                                 // destructed by the end of the function
    1080                                 unhandled.insert( field );
     1107        if ( checkWarnings( function ) ) {
     1108                // const ast::FunctionType * type = function->type;
     1109                // assert( ! type->params.empty() );
     1110                thisParam = function->params.front().strict_as<ast::ObjectDecl>();
     1111                auto thisType = getPointerBase( thisParam->get_type() );
     1112                auto structType = dynamic_cast< const ast::StructInstType * >( thisType );
     1113                if ( structType ) {
     1114                        structDecl = structType->base;
     1115                        for ( auto & member : structDecl->members ) {
     1116                                if ( auto field = member.as<ast::ObjectDecl>() ) {
     1117                                        // record all of the struct type's members that need to be constructed or
     1118                                        // destructed by the end of the function
     1119                                        unhandled.insert( field );
     1120                                }
    10811121                        }
    10821122                }
     
    11241164
    11251165                        // insert and resolve default/copy constructor call for each field that's unhandled
     1166                        // std::list< const ast::Stmt * > stmt;
    11261167                        ast::Expr * arg2 = nullptr;
    11271168                        if ( function->name == "?{}" && isCopyFunction( function ) ) {
    11281169                                // if copy ctor, need to pass second-param-of-this-function.field
     1170                                // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();
    11291171                                assert( function->params.size() == 2 );
    11301172                                arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) );
     
    11371179
    11381180                        if ( callStmt ) {
     1181                                // auto & callStmt = stmt.front();
     1182
    11391183                                try {
    11401184                                        callStmt = callStmt->accept( *visitor );
     
    11421186                                                mutStmts->push_front( callStmt );
    11431187                                        } else { // TODO: don't generate destructor function/object for intrinsic calls
     1188                                                // destructor statements should be added at the end
     1189                                                // function->get_statements()->push_back( callStmt );
    11441190
    11451191                                                // Optimization: do not need to call intrinsic destructors on members
     
    11761222                throw errors;
    11771223        }
     1224        // return funcDecl;
    11781225        return function;
    11791226}
     
    12091256
    12101257        std::string fname = getFunctionName( appExpr );
    1211         if ( fname != function->name ) return;
    1212 
    1213         // call to same kind of function
    1214         const ast::Expr * firstParam = appExpr->args.front();
    1215         if ( isThisExpression( firstParam, thisParam ) ) {
    1216                 // if calling another constructor on thisParam, assume that function handles
    1217                 // all members - if it doesn't a warning will appear in that function.
    1218                 unhandled.clear();
    1219         } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
    1220                 // if first parameter is a member expression on the this parameter,
    1221                 // then remove the member from unhandled set.
    1222                 if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
    1223                         unhandled.erase( memberExpr->member );
     1258        if ( fname == function->name ) {
     1259                // call to same kind of function
     1260                const ast::Expr * firstParam = appExpr->args.front();
     1261
     1262                if ( isThisExpression( firstParam, thisParam ) ) {
     1263                        // if calling another constructor on thisParam, assume that function handles
     1264                        // all members - if it doesn't a warning will appear in that function.
     1265                        unhandled.clear();
     1266                } else if ( auto memberExpr = isThisMemberExpr( firstParam, thisParam ) ) {
     1267                        // if first parameter is a member expression on the this parameter,
     1268                        // then remove the member from unhandled set.
     1269                        if ( isThisExpression( memberExpr->aggregate, thisParam ) ) {
     1270                                unhandled.erase( memberExpr->member );
     1271                        }
    12241272                }
    12251273        }
     
    12671315        ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>();
    12681316        ast::ptr<ast::TypeSubstitution> env = ctorExpr->env;
     1317        // ctorExpr->set_callExpr( nullptr );
     1318        // ctorExpr->set_env( nullptr );
    12691319
    12701320        // xxx - ideally we would reuse the temporary generated from the copy constructor passes from within firstArg if it exists and not generate a temporary if it's unnecessary.
  • src/Parser/ExpressionNode.cc

    r221c542e rbad9c8f  
    673673                ast::LogicalFlag flag ) {
    674674        return new ast::LogicalExpr( location,
    675                 maybeMoveBuild( expr_node1 ),
    676                 maybeMoveBuild( expr_node2 ),
     675                notZeroExpr( maybeMoveBuild( expr_node1 ) ),
     676                notZeroExpr( maybeMoveBuild( expr_node2 ) ),
    677677                flag
    678678        );
     
    713713                ExpressionNode * expr_node3 ) {
    714714        return new ast::ConditionalExpr( location,
    715                 maybeMoveBuild( expr_node1 ),
     715                notZeroExpr( maybeMoveBuild( expr_node1 ) ),
    716716                maybeMoveBuild( expr_node2 ),
    717717                maybeMoveBuild( expr_node3 )
  • src/Parser/parserutility.cc

    r221c542e rbad9c8f  
    2727//    if ( (int)(x != 0) ) ...
    2828
    29 ast::Expr * notZeroExpr( const ast::Expr * orig ) {
     29ast::Expr * notZeroExpr( ast::Expr * orig ) {
    3030        return ( !orig ) ? nullptr : new ast::CastExpr( orig->location,
    3131                ast::UntypedExpr::createCall( orig->location,
  • src/Parser/parserutility.h

    r221c542e rbad9c8f  
    2121}
    2222
    23 ast::Expr * notZeroExpr( const ast::Expr *orig );
     23ast::Expr * notZeroExpr( ast::Expr *orig );
    2424
    2525template< typename T >
  • src/ResolvExpr/CandidateFinder.cpp

    r221c542e rbad9c8f  
    4646#include "AST/Type.hpp"
    4747#include "Common/utility.h"       // for move, copy
    48 #include "Parser/parserutility.h" // for notZeroExpr
    4948#include "SymTab/Mangler.h"
    5049#include "Tuples/Tuples.h"        // for handleTupleAssignment
     
    15031502        void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) {
    15041503                CandidateFinder finder1( context, tenv );
    1505                 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 );
    1506                 finder1.find( arg1, ResolveMode::withAdjustment() );
     1504                finder1.find( logicalExpr->arg1, ResolveMode::withAdjustment() );
    15071505                if ( finder1.candidates.empty() ) return;
    15081506
    15091507                CandidateFinder finder2( context, tenv );
    1510                 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 );
    1511                 finder2.find( arg2, ResolveMode::withAdjustment() );
     1508                finder2.find( logicalExpr->arg2, ResolveMode::withAdjustment() );
    15121509                if ( finder2.candidates.empty() ) return;
    15131510
     
    15351532                // candidates for condition
    15361533                CandidateFinder finder1( context, tenv );
    1537                 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 );
    1538                 finder1.find( arg1, ResolveMode::withAdjustment() );
     1534                finder1.find( conditionalExpr->arg1, ResolveMode::withAdjustment() );
    15391535                if ( finder1.candidates.empty() ) return;
    15401536
  • src/Validate/Autogen.cpp

    r221c542e rbad9c8f  
    803803}
    804804
     805struct PseudoFuncGenerateRoutine final :
     806                public ast::WithDeclsToAdd<>,
     807                public ast::WithShortCircuiting {
     808        void previsit( const ast::EnumDecl * enumDecl );
     809};
     810
     811void PseudoFuncGenerateRoutine::previsit( const ast::EnumDecl * enumDecl ) {
     812        const CodeLocation& location = enumDecl->location;
     813        if ( enumDecl->members.size() == 0 || !enumDecl->base || enumDecl->name == "" ) return;
     814
     815        std::vector<ast::ptr<ast::Init>> inits;
     816        std::vector<ast::ptr<ast::Init>> labels;
     817        for ( const ast::Decl * mem: enumDecl->members ) {
     818                auto memAsObjectDecl = dynamic_cast< const ast::ObjectDecl * >( mem );
     819                inits.emplace_back( memAsObjectDecl->init );
     820                labels.emplace_back( new ast::SingleInit(
     821                        location, ast::ConstantExpr::from_string(location, mem->name) ) );
     822        }
     823        auto init = new ast::ListInit( location, std::move( inits ) );
     824        auto label_strings = new ast::ListInit( location, std::move(labels) );
     825        auto values = new ast::ObjectDecl(
     826                location,
     827                "__enum_values_"+enumDecl->name,
     828                new ast::ArrayType(
     829                        // new ast::PointerType( new ast::BasicType{ ast::BasicType::Char} ),
     830                        enumDecl->base,
     831                        ast::ConstantExpr::from_int( location, enumDecl->members.size() ),
     832                        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim
     833                )
     834                ,init
     835                ,
     836                ast::Storage::Static,
     837                ast::Linkage::AutoGen
     838        );
     839        auto label_arr = new ast::ObjectDecl(
     840                location,
     841                "__enum_labels_"+enumDecl->name,
     842                new ast::ArrayType(
     843                        new ast::PointerType( new ast::BasicType{ ast::BasicType::Char} ),
     844                        ast::ConstantExpr::from_int( location, enumDecl->members.size() ),
     845                        ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim
     846                ),
     847                label_strings,
     848                ast::Storage::Static,
     849                ast::Linkage::AutoGen
     850        );
     851
     852        declsToAddAfter.push_back( values );
     853        declsToAddAfter.push_back( label_arr );
     854}
     855
    805856} // namespace
    806857
    807858void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
    808859        ast::Pass<AutogenerateRoutines>::run( translationUnit );
     860        // ast::Pass<PseudoFuncGenerateRoutine>::run( translationUnit );
    809861}
    810862
  • src/Validate/ReplacePseudoFunc.cpp

    r221c542e rbad9c8f  
     1#include "AST/Decl.hpp"
     2#include "AST/Pass.hpp"
     3#include "AST/Stmt.hpp"
     4#include "AST/Inspect.hpp"
     5#include "Common/utility.h"
    16#include "ReplacePseudoFunc.hpp"
    27
    3 #include <set>
    4 
    5 #include "AST/Decl.hpp"
    6 #include "AST/Inspect.hpp"
    7 #include "AST/Pass.hpp"
    8 #include "AST/Stmt.hpp"
    9 #include "Common/utility.h"
    10 #include "ResolvExpr/Resolver.h"
    11 #include "SymTab/Mangler.h"  // for Mangler
    128namespace Validate {
    139
    1410namespace {
    1511
    16 std::set<std::string> queryLabels;
    17 std::set<std::string> queryValues;
    18 
    19 struct FindGenEnumArray final : public ast::WithShortCircuiting {
    20     void previsit(const ast::ApplicationExpr* enumDecl);
     12struct ReplacePseudoFuncCore {
     13    ast::Expr const * postvisit( ast::ApplicationExpr const * decl );
    2114};
    22 
    23 void FindGenEnumArray::previsit(const ast::ApplicationExpr* expr) {
    24     auto fname = ast::getFunctionName(expr);
    25     if (fname == "labelE" || fname == "valueE") {
    26         if (expr->args.size() != 1) {
    27             SemanticError(expr, "Position Expression only take one parameter");
    28         }
    29         const ast::VariableExpr* arg =
    30             expr->args.front().as<const ast::VariableExpr>();
    31         if (!arg) {
    32             SemanticError(expr, "Unimplement Pseudo Function Cases");
    33         }
    34         const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
    35         const std::string referredName = argAsVar->name;
    36         const ast::EnumInstType* argType =
    37             argAsVar->type.as<const ast::EnumInstType>();
    38         if (!argType) {
    39             SemanticError(
    40                 argAsVar,
    41                 "Position can only be used on an enumeration instance");
    42         }
    43         ast::ptr<ast::EnumDecl> base = argType->base;
    44         assert(base);
    45         if (fname == "labelE") queryLabels.insert(base->name);
    46         if (fname == "valueE") queryValues.insert(base->name);
    47     }
    4815}
    4916
    50 struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
    51                                          public ast::WithSymbolTable,
    52                                          public ast::WithShortCircuiting {
    53     void previsit(const ast::EnumDecl* enumDecl);
    54 };
    55 
    56 void PseudoFuncGenerateRoutine::previsit(const ast::EnumDecl* enumDecl) {
    57     visit_children = false;
    58     const CodeLocation& location = enumDecl->location;
    59     if (enumDecl->members.size() == 0 || !enumDecl->base) return;
    60 
    61     std::vector<ast::ptr<ast::Init>> inits;
    62     std::vector<ast::ptr<ast::Init>> labels;
    63     for (const ast::Decl* mem : enumDecl->members) {
    64         auto memAsObjectDecl = dynamic_cast<const ast::ObjectDecl*>(mem);
    65         inits.emplace_back(memAsObjectDecl->init);
    66         labels.emplace_back(new ast::SingleInit(
    67             location, ast::ConstantExpr::from_string(location, mem->name)));
    68     }
    69     if (queryValues.count(enumDecl->name)) {
    70         auto init = new ast::ListInit(location, std::move(inits));
    71         auto values = new ast::ObjectDecl(
    72             location, "values_" + enumDecl->name,
    73             new ast::ArrayType(
    74                 enumDecl->base,
    75                 ast::ConstantExpr::from_int(location, enumDecl->members.size()),
    76                 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
    77             init, ast::Storage::Static, ast::Linkage::AutoGen);
    78         symtab.addId(values);
    79         values->mangleName = Mangle::mangle(values);
    80         declsToAddAfter.push_back(values);
    81     }
    82     if (queryLabels.count(enumDecl->name)) {
    83         auto label_strings = new ast::ListInit(location, std::move(labels));
    84         auto label_arr = new ast::ObjectDecl(
    85             location, "labels_" + enumDecl->name,
    86             new ast::ArrayType(
    87                 new ast::PointerType(new ast::BasicType{ast::BasicType::Char}),
    88                 ast::ConstantExpr::from_int(location, enumDecl->members.size()),
    89                 ast::LengthFlag::FixedLen, ast::DimensionFlag::DynamicDim),
    90             label_strings, ast::Storage::Static, ast::Linkage::AutoGen);
    91         symtab.addId(label_arr);
    92         label_arr->mangleName = Mangle::mangle(label_arr);
    93         declsToAddAfter.push_back(label_arr);
    94     }
    95 }
    96 
    97 struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
    98                                public ast::WithSymbolTable,
    99                                public ast::WithConstTranslationUnit {
    100     ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
    101 };
    102 
    103 ast::Expr const* ReplacePseudoFuncCore::postvisit(
    104     ast::ApplicationExpr const* expr) {
    105     auto fname = ast::getFunctionName(expr);
    106     auto location = expr->location;
    107     if (fname == "posE" || fname == "valueE" || fname == "labelE") {
    108         if (expr->args.size() != 1) {
    109             SemanticError(expr,
    110                           "Pseudo Enum Expression only take one parameter");
     17ast::Expr const * ReplacePseudoFuncCore::postvisit( ast::ApplicationExpr const * expr) {
     18    auto fname = ast::getFunctionName( expr );
     19    if ( fname == "posE" ) {
     20        // std::cerr << "Found App in ReplacePseudoFunc" << std::endl;
     21        if ( expr->args.size() != 1 ) {
     22            SemanticError( expr, "Position Expression only take one parameter" );
    11123        }
    112         ast::ptr<ast::VariableExpr> arg =
    113             expr->args.front().as<const ast::VariableExpr>();
    114         if (!arg) {
    115             SemanticError(expr, "Unimplement Pseudo Function Cases");
     24        const ast::VariableExpr * arg = expr->args.front().as<const ast::VariableExpr>();
     25        if ( !arg ) {
     26            SemanticError( expr, "Unimplement Pseudo Function Cases" );
    11627        }
    117         const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
     28        const ast::ObjectDecl * argAsVar = arg->var.as<const ast::ObjectDecl>();
    11829        const std::string referredName = argAsVar->name;
    119         const ast::EnumInstType* argType =
    120             argAsVar->type.as<const ast::EnumInstType>();
    121         if (!argType) {
    122             SemanticError(argAsVar,
    123                           "Pseudo Enum Expression can only be used on an "
    124                           "enumeration instance");
     30        const ast::EnumInstType * argType = argAsVar->type.as<const ast::EnumInstType>();
     31        if ( !argType ) {
     32            SemanticError( argAsVar, "Position can only be used on an enumeration instance" );
    12533        }
    126         const ast::EnumDecl* base = argType->base;
    127         for (size_t i = 0; i < base->members.size(); i++) {
    128             if (base->members[i]->name == referredName) {
    129                 if (fname == "posE")
    130                     return ast::ConstantExpr::from_int(expr->location, i);
    131                 else if (fname == "labelE")
    132                     return ast::ConstantExpr::from_string(expr->location,
    133                                                           referredName);
    134                 else
    135                     return new ast::TypeExpr(expr->location, argType);
    136             }
    137         }
    138 
    139         ResolvExpr::ResolveContext context{symtab, transUnit().global};
    140 
    141         if (fname == "labelE") {
    142             ast::Expr* toResolve =
    143                 new ast::NameExpr(expr->location, "labels_" + base->name);
    144             auto result = ResolvExpr::findVoidExpression(toResolve, context);
    145             if (result.get()) {
    146                 auto arrAsVar = result.strict_as<ast::VariableExpr>();
    147                 auto untyped = new ast::UntypedExpr(
    148                     location, new ast::NameExpr(location, "?[?]"),
    149                     {new ast::VariableExpr(*arrAsVar),
    150                      ast::ConstantExpr::from_int(
    151                          location,
    152                          0)});  /// TODO: dummy value.
    153                                 /// To make it works need to change the unifier
    154 
    155                 auto typedResult =
    156                     ResolvExpr::findVoidExpression(untyped, context);
    157                 if (result.get()) {
    158                     ast::ptr<ast::ApplicationExpr> ret =
    159                         typedResult.strict_as<ast::ApplicationExpr>();
    160                     return new ast::ApplicationExpr(*ret);
    161                 }
    162             }
    163         }
    164        
    165         if (fname == "valueE") {
    166             ast::Expr* toResolve =
    167                 new ast::NameExpr(expr->location, "values_" + base->name);
    168             auto result = ResolvExpr::findVoidExpression(toResolve, context);
    169             if (result.get()) {
    170                 auto arrAsVar = result.strict_as<ast::VariableExpr>();
    171                 auto untyped = new ast::UntypedExpr(
    172                     location, new ast::NameExpr(location, "?[?]"),
    173                     {new ast::VariableExpr(*arrAsVar),
    174                      ast::ConstantExpr::from_int(
    175                          location,
    176                          0)});  /// TODO: dummy value.
    177                                 /// To make it works need to change the unifier
    178 
    179                 auto typedResult =
    180                     ResolvExpr::findVoidExpression(untyped, context);
    181                 if (result.get()) {
    182                     ast::ptr<ast::ApplicationExpr> ret =
    183                         typedResult.strict_as<ast::ApplicationExpr>();
    184                     return new ast::ApplicationExpr(*ret);
    185                 }
     34        const ast::EnumDecl * base = argType->base;
     35        for ( size_t i = 0; i < base->members.size(); i++ ) {
     36            if ( base->members[i]->name == referredName ) {
     37                return ast::ConstantExpr::from_int( expr->location, i );
    18638            }
    18739        }
     
    19042}
    19143
    192 }  // namespace
    19344
    194 void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
    195     ast::Pass<FindGenEnumArray>::run(translationUnit);
    196     ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
    197     ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
     45
     46void replacePseudoFunc( ast::TranslationUnit & translationUnit ) {
     47    ast::Pass<ReplacePseudoFuncCore>::run( translationUnit );
    19848}
    199 }  // namespace Validate
     49
     50}
  • src/main.cc

    r221c542e rbad9c8f  
    8282#include "Validate/ReturnCheck.hpp"         // for checkReturnStatements
    8383#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
    84 #include "Validate/ReplacePseudoFunc.hpp"   // for replacePseudoFunc
     84#include "Validate/ReplacePseudoFunc.hpp"
    8585#include "Virtual/ExpandCasts.h"            // for expandCasts
    8686#include "Virtual/VirtualDtor.hpp"          // for implementVirtDtors
Note: See TracChangeset for help on using the changeset viewer.