Changeset 221c542e
- Timestamp:
- Jan 24, 2024, 8:19:18 AM (3 months ago)
- Branches:
- master
- Children:
- 64c4b4d
- Parents:
- bad9c8f (diff), 71b5aad5 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/enum.tex
rbad9c8f r221c542e 245 245 246 246 247 \subsection{Aggressive Inline} 248 To 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] 250 enum(int) OddNumber { A=1, B=3 }; 251 sout | "A: " | OddNumber.A | "B: " | OddNumber.B | "A+B: " | OddNumber.A + OddNumber.B 252 \end{lstlisting} 253 Instead 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] 257 enum(int) OddNumber { A=1, B=3 }; 258 enum OddNumber i = ...; 259 ... 260 sout | OddNumber; 261 \end{lstlisting} 262 In 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 247 \ 264 248 \section{Unification} 265 249 … … 638 622 \section{Implementation} 639 623 640 \subsection{Compiler Representation (Reworking)} 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 641 668 The 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: 642 669 \begin{lstlisting}[label=lst:EnumDecl] … … 667 694 668 695 669 \subsection{(Rework) Companion Object and Companion Function}670 671 \begin{lstlisting}[caption={Enum Type Functions}, label=lst:cforall_enum_functions]672 forall( T )673 struct 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 681 The companion object is singleton across the compilation (investigation).682 683 \CFA generates the definition of companion functions.684 Because \CFA implicitly stores an enumeration instance as its position, the companion function @position@ does nothing but return the position it is passed.685 Companions function @value@ and @label@ return the array item at the given position of @values@ and @labels@, respectively.686 \begin{lstlisting}[label=lst:companion_definition]687 int position( Companion o, int pos ) { return pos; }688 T value( Companion o, int pos ) { return o.values[ pos ]; }689 char * label( Companion o, int pos ) { return o.labels[ pos ]; }690 \end{lstlisting}691 Notably, the @Companion@ structure definition, and all companion objects, are visible to users.692 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@693 \begin{lstlisting}[label=lst:companion_definition_values_labels]694 Colour.values; // read the Companion's values695 values( Colour ); // same as Colour.values696 \end{lstlisting}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} 697 724 698 725 \subsection{Companion Traits (experimental)} -
src/AST/Decl.hpp
rbad9c8f r221c542e 312 312 ptr<Type> base; 313 313 enum class EnumHiding { Visible, Hide } hide; 314 315 314 EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false, 316 315 std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, -
src/CodeGen/CodeGenerator.cpp
rbad9c8f r221c542e 1135 1135 if ( clause->when_cond ) { 1136 1136 output << "when("; 1137 stmt->timeout_cond->accept( *visitor );1137 clause->when_cond->accept( *visitor ); 1138 1138 output << ") "; 1139 1139 } -
src/InitTweak/FixInit.cpp
rbad9c8f r221c542e 49 49 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 50 50 return inst->base->params; 51 } 52 if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) { 51 } else if ( auto inst = dynamic_cast<const ast::UnionInstType *>( t ) ) { 53 52 return inst->base->params; 54 53 } … … 245 244 const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) { 246 245 const CodeLocation loc = input->location; 247 // unwrap implicit statement wrapper248 // Statement * dtor = input;249 246 assert( input ); 250 // std::list< const ast::Expr * > matches;251 247 auto matches = collectCtorDtorCalls( input ); 252 248 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 } 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; 266 260 } 267 261 } … … 301 295 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) { 302 296 try { 303 // maybeAccept( *i, fixer ); translationUnit should never contain null304 297 *i = (*i)->accept(fixer); 305 298 translationUnit.decls.splice( i, fixer.core.staticDtorDecls ); … … 314 307 315 308 const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) { 316 // we might loose the result expression here so add a pointer to trace back317 309 assert( stmtExpr->result ); 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; 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; 327 317 } 328 318 … … 330 320 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed 331 321 // in the correct places 332 ast::CompoundStmt * ret = new ast::CompoundStmt( stmt->location, { stmt } ); 333 return ret; 322 return new ast::CompoundStmt( stmt->location, { stmt } ); 334 323 } 335 324 … … 556 545 arg = cpCtor; 557 546 return destructRet( tmp, arg ); 558 559 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );560 547 } 561 548 … … 608 595 } 609 596 return nullptr; 610 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );611 597 } 612 598 … … 625 611 for ( auto & arg : appExpr->args ) { 626 612 const ast::Type * formal = nullptr; 627 if ( iter != params.end() ) { // does not copy construct C-style variadic arguments628 // DeclarationWithType * param = *iter++;613 // Do not copy construct C-style variadic arguments. 614 if ( iter != params.end() ) { 629 615 formal = *iter++; 630 616 } … … 659 645 // deletion of wrapper should be handled by pass template now 660 646 661 // impCpCtorExpr->callExpr = nullptr;662 647 assert (appExpr->env == nullptr); 663 648 appExpr->env = impCpCtorExpr->env; 664 // std::swap( impCpCtorExpr->env, appExpr->env );665 // assert( impCpCtorExpr->env == nullptr );666 // delete impCpCtorExpr;667 649 668 650 if ( returnDecl ) { … … 676 658 } 677 659 // move env from appExpr to retExpr 678 // std::swap( assign->env, appExpr->env );679 660 assign->env = appExpr->env; 680 661 // actual env is handled by common routine that replaces WithTypeSubstitution … … 716 697 717 698 assert( stmtExpr->result ); 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 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 ) ) ); 767 750 768 751 assert( stmtExpr->returnDecls.empty() ); … … 798 781 auto mutExpr = mutate(unqExpr); 799 782 if ( ! unqMap.count( unqExpr->id ) ) { 800 // resolve expr and find its801 802 783 auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>(); 803 // PassVisitor<ResolveCopyCtors> fixer;804 805 784 mutExpr->expr = mutExpr->expr->accept( *visitor ); 806 785 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought … … 820 799 } else { 821 800 // take data from other UniqueExpr to ensure consistency 822 // delete unqExpr->get_expr();823 801 mutExpr->expr = unqMap[mutExpr->id]->expr; 824 // delete unqExpr->result;825 802 mutExpr->result = mutExpr->expr->result; 826 803 } … … 832 809 833 810 // since this removes the init field from objDecl, it must occur after children are mutated (i.e. postvisit) 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 } 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; 941 908 } else { 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; 909 objDecl->init = nullptr; 910 return objDecl; 911 } 979 912 } else { 980 // no constructor and no initializer, which is okay 981 objDecl->init = nullptr; 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 } 982 941 } // if 983 // delete ctorInit; 984 return objDecl; 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; 985 947 } // if 986 return _objDecl;948 return objDecl; 987 949 } 988 950 … … 1006 968 1007 969 void LabelFinder::previsit( const ast::CompoundStmt * stmt ) { 1008 previsit( (const ast::Stmt *) 970 previsit( (const ast::Stmt *)stmt ); 1009 971 Parent::previsit( stmt ); 1010 972 } … … 1022 984 // its children manually. 1023 985 if (funcDecl->type) funcDecl->type->accept(finder); 1024 // maybeAccept( funcDecl->type, finder ); 1025 if (funcDecl->stmts) funcDecl->stmts->accept(finder) ; 986 if (funcDecl->stmts) funcDecl->stmts->accept(finder); 1026 987 1027 988 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion. … … 1078 1039 } 1079 1040 1041 /// Should we check for warnings? (The function is user-defined constrctor or destructor.) 1080 1042 bool checkWarnings( const ast::FunctionDecl * funcDecl ) { 1081 // only check for warnings if the current function is a user-defined constructor or destructor1082 1043 if ( ! funcDecl ) return false; 1083 1044 if ( ! funcDecl->stmts ) return false; … … 1105 1066 1106 1067 isCtor = CodeGen::isConstructor( function->name ); 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 } 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 ); 1121 1081 } 1122 1082 } … … 1164 1124 1165 1125 // insert and resolve default/copy constructor call for each field that's unhandled 1166 // std::list< const ast::Stmt * > stmt;1167 1126 ast::Expr * arg2 = nullptr; 1168 1127 if ( function->name == "?{}" && isCopyFunction( function ) ) { 1169 1128 // if copy ctor, need to pass second-param-of-this-function.field 1170 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters();1171 1129 assert( function->params.size() == 2 ); 1172 1130 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); … … 1179 1137 1180 1138 if ( callStmt ) { 1181 // auto & callStmt = stmt.front();1182 1183 1139 try { 1184 1140 callStmt = callStmt->accept( *visitor ); … … 1186 1142 mutStmts->push_front( callStmt ); 1187 1143 } else { // TODO: don't generate destructor function/object for intrinsic calls 1188 // destructor statements should be added at the end1189 // function->get_statements()->push_back( callStmt );1190 1144 1191 1145 // Optimization: do not need to call intrinsic destructors on members … … 1222 1176 throw errors; 1223 1177 } 1224 // return funcDecl;1225 1178 return function; 1226 1179 } … … 1256 1209 1257 1210 std::string fname = getFunctionName( appExpr ); 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 } 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 ); 1272 1224 } 1273 1225 } … … 1315 1267 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>(); 1316 1268 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env; 1317 // ctorExpr->set_callExpr( nullptr );1318 // ctorExpr->set_env( nullptr );1319 1269 1320 1270 // 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
rbad9c8f r221c542e 673 673 ast::LogicalFlag flag ) { 674 674 return new ast::LogicalExpr( location, 675 notZeroExpr( maybeMoveBuild( expr_node1 )),676 notZeroExpr( maybeMoveBuild( expr_node2 )),675 maybeMoveBuild( expr_node1 ), 676 maybeMoveBuild( expr_node2 ), 677 677 flag 678 678 ); … … 713 713 ExpressionNode * expr_node3 ) { 714 714 return new ast::ConditionalExpr( location, 715 notZeroExpr( maybeMoveBuild( expr_node1 )),715 maybeMoveBuild( expr_node1 ), 716 716 maybeMoveBuild( expr_node2 ), 717 717 maybeMoveBuild( expr_node3 ) -
src/Parser/parserutility.cc
rbad9c8f r221c542e 27 27 // if ( (int)(x != 0) ) ... 28 28 29 ast::Expr * notZeroExpr( ast::Expr * orig ) {29 ast::Expr * notZeroExpr( const ast::Expr * orig ) { 30 30 return ( !orig ) ? nullptr : new ast::CastExpr( orig->location, 31 31 ast::UntypedExpr::createCall( orig->location, -
src/Parser/parserutility.h
rbad9c8f r221c542e 21 21 } 22 22 23 ast::Expr * notZeroExpr( ast::Expr *orig );23 ast::Expr * notZeroExpr( const ast::Expr *orig ); 24 24 25 25 template< typename T > -
src/ResolvExpr/CandidateFinder.cpp
rbad9c8f r221c542e 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr 48 49 #include "SymTab/Mangler.h" 49 50 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1502 1503 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1503 1504 CandidateFinder finder1( context, tenv ); 1504 finder1.find( logicalExpr->arg1, ResolveMode::withAdjustment() ); 1505 ast::ptr<ast::Expr> arg1 = notZeroExpr( logicalExpr->arg1 ); 1506 finder1.find( arg1, ResolveMode::withAdjustment() ); 1505 1507 if ( finder1.candidates.empty() ) return; 1506 1508 1507 1509 CandidateFinder finder2( context, tenv ); 1508 finder2.find( logicalExpr->arg2, ResolveMode::withAdjustment() ); 1510 ast::ptr<ast::Expr> arg2 = notZeroExpr( logicalExpr->arg2 ); 1511 finder2.find( arg2, ResolveMode::withAdjustment() ); 1509 1512 if ( finder2.candidates.empty() ) return; 1510 1513 … … 1532 1535 // candidates for condition 1533 1536 CandidateFinder finder1( context, tenv ); 1534 finder1.find( conditionalExpr->arg1, ResolveMode::withAdjustment() ); 1537 ast::ptr<ast::Expr> arg1 = notZeroExpr( conditionalExpr->arg1 ); 1538 finder1.find( arg1, ResolveMode::withAdjustment() ); 1535 1539 if ( finder1.candidates.empty() ) return; 1536 1540 -
src/Validate/Autogen.cpp
rbad9c8f r221c542e 803 803 } 804 804 805 struct PseudoFuncGenerateRoutine final :806 public ast::WithDeclsToAdd<>,807 public ast::WithShortCircuiting {808 void previsit( const ast::EnumDecl * enumDecl );809 };810 811 void 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::DynamicDim833 )834 ,init835 ,836 ast::Storage::Static,837 ast::Linkage::AutoGen838 );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::DynamicDim846 ),847 label_strings,848 ast::Storage::Static,849 ast::Linkage::AutoGen850 );851 852 declsToAddAfter.push_back( values );853 declsToAddAfter.push_back( label_arr );854 }855 856 805 } // namespace 857 806 858 807 void autogenerateRoutines( ast::TranslationUnit & translationUnit ) { 859 808 ast::Pass<AutogenerateRoutines>::run( translationUnit ); 860 // ast::Pass<PseudoFuncGenerateRoutine>::run( translationUnit );861 809 } 862 810 -
src/Validate/ReplacePseudoFunc.cpp
rbad9c8f r221c542e 1 #include "ReplacePseudoFunc.hpp" 2 3 #include <set> 4 1 5 #include "AST/Decl.hpp" 6 #include "AST/Inspect.hpp" 2 7 #include "AST/Pass.hpp" 3 8 #include "AST/Stmt.hpp" 4 #include "AST/Inspect.hpp"5 9 #include "Common/utility.h" 6 #include "Re placePseudoFunc.hpp"7 10 #include "ResolvExpr/Resolver.h" 11 #include "SymTab/Mangler.h" // for Mangler 8 12 namespace Validate { 9 13 10 14 namespace { 11 15 12 struct ReplacePseudoFuncCore { 13 ast::Expr const * postvisit( ast::ApplicationExpr const * decl ); 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); 14 21 }; 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 } 15 48 } 16 49 17 ast::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" ); 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"); 23 111 } 24 const ast::VariableExpr * arg = expr->args.front().as<const ast::VariableExpr>(); 25 if ( !arg ) { 26 SemanticError( expr, "Unimplement Pseudo Function Cases" ); 112 ast::ptr<ast::VariableExpr> arg = 113 expr->args.front().as<const ast::VariableExpr>(); 114 if (!arg) { 115 SemanticError(expr, "Unimplement Pseudo Function Cases"); 27 116 } 28 const ast::ObjectDecl 117 const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>(); 29 118 const std::string referredName = argAsVar->name; 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" ); 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"); 33 125 } 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 ); 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 } 38 186 } 39 187 } … … 42 190 } 43 191 192 } // namespace 44 193 45 46 void replacePseudoFunc( ast::TranslationUnit & translationUnit ) { 47 ast::Pass<ReplacePseudoFuncCore>::run( translationUnit ); 194 void replacePseudoFunc(ast::TranslationUnit& translationUnit) { 195 ast::Pass<FindGenEnumArray>::run(translationUnit); 196 ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit); 197 ast::Pass<ReplacePseudoFuncCore>::run(translationUnit); 48 198 } 49 50 } 199 } // namespace Validate -
src/main.cc
rbad9c8f r221c542e 82 82 #include "Validate/ReturnCheck.hpp" // for checkReturnStatements 83 83 #include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign 84 #include "Validate/ReplacePseudoFunc.hpp" 84 #include "Validate/ReplacePseudoFunc.hpp" // for replacePseudoFunc 85 85 #include "Virtual/ExpandCasts.h" // for expandCasts 86 86 #include "Virtual/VirtualDtor.hpp" // for implementVirtDtors
Note: See TracChangeset
for help on using the changeset viewer.