Changes in / [221c542e:bad9c8f]
- Files:
-
- 11 edited
-
doc/proposals/enum.tex (modified) (3 diffs)
-
src/AST/Decl.hpp (modified) (1 diff)
-
src/CodeGen/CodeGenerator.cpp (modified) (1 diff)
-
src/InitTweak/FixInit.cpp (modified) (24 diffs)
-
src/Parser/ExpressionNode.cc (modified) (2 diffs)
-
src/Parser/parserutility.cc (modified) (1 diff)
-
src/Parser/parserutility.h (modified) (1 diff)
-
src/ResolvExpr/CandidateFinder.cpp (modified) (3 diffs)
-
src/Validate/Autogen.cpp (modified) (1 diff)
-
src/Validate/ReplacePseudoFunc.cpp (modified) (2 diffs)
-
src/main.cc (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/enum.tex
r221c542e rbad9c8f 245 245 246 246 247 \ 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 248 264 \section{Unification} 249 265 … … 622 638 \section{Implementation} 623 639 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)} 668 641 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: 669 642 \begin{lstlisting}[label=lst:EnumDecl] … … 694 667 695 668 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 values722 %values( Colour ); // same as Colour.values723 %\end{lstlisting}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 values 695 values( Colour ); // same as Colour.values 696 \end{lstlisting} 724 697 725 698 \subsection{Companion Traits (experimental)} -
src/AST/Decl.hpp
r221c542e rbad9c8f 312 312 ptr<Type> base; 313 313 enum class EnumHiding { Visible, Hide } hide; 314 314 315 EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false, 315 316 std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, -
src/CodeGen/CodeGenerator.cpp
r221c542e rbad9c8f 1135 1135 if ( clause->when_cond ) { 1136 1136 output << "when("; 1137 clause->when_cond->accept( *visitor );1137 stmt->timeout_cond->accept( *visitor ); 1138 1138 output << ") "; 1139 1139 } -
src/InitTweak/FixInit.cpp
r221c542e rbad9c8f 49 49 if ( auto inst = dynamic_cast<const ast::StructInstType *>( t ) ) { 50 50 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 ) ) { 52 53 return inst->base->params; 53 54 } … … 244 245 const ast::DeclWithType * getDtorFunc( const ast::ObjectDecl * objDecl, const ast::Stmt * input, std::list< ast::ptr<ast::Stmt> > & stmtsToAdd ) { 245 246 const CodeLocation loc = input->location; 247 // unwrap implicit statement wrapper 248 // Statement * dtor = input; 246 249 assert( input ); 250 // std::list< const ast::Expr * > matches; 247 251 auto matches = collectCtorDtorCalls( input ); 248 252 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 } 260 266 } 261 267 } … … 295 301 for ( auto i = translationUnit.decls.begin(); i != translationUnit.decls.end(); ++i ) { 296 302 try { 303 // maybeAccept( *i, fixer ); translationUnit should never contain null 297 304 *i = (*i)->accept(fixer); 298 305 translationUnit.decls.splice( i, fixer.core.staticDtorDecls ); … … 307 314 308 315 const ast::StmtExpr * StmtExprResult::previsit( const ast::StmtExpr * stmtExpr ) { 316 // we might loose the result expression here so add a pointer to trace back 309 317 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; 317 327 } 318 328 … … 320 330 // wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed 321 331 // 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; 323 334 } 324 335 … … 545 556 arg = cpCtor; 546 557 return destructRet( tmp, arg ); 558 559 // impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) ); 547 560 } 548 561 … … 595 608 } 596 609 return nullptr; 610 // impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) ); 597 611 } 598 612 … … 611 625 for ( auto & arg : appExpr->args ) { 612 626 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++; 615 629 formal = *iter++; 616 630 } … … 645 659 // deletion of wrapper should be handled by pass template now 646 660 661 // impCpCtorExpr->callExpr = nullptr; 647 662 assert (appExpr->env == nullptr); 648 663 appExpr->env = impCpCtorExpr->env; 664 // std::swap( impCpCtorExpr->env, appExpr->env ); 665 // assert( impCpCtorExpr->env == nullptr ); 666 // delete impCpCtorExpr; 649 667 650 668 if ( returnDecl ) { … … 658 676 } 659 677 // move env from appExpr to retExpr 678 // std::swap( assign->env, appExpr->env ); 660 679 assign->env = appExpr->env; 661 680 // actual env is handled by common routine that replaces WithTypeSubstitution … … 697 716 698 717 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 750 767 751 768 assert( stmtExpr->returnDecls.empty() ); … … 781 798 auto mutExpr = mutate(unqExpr); 782 799 if ( ! unqMap.count( unqExpr->id ) ) { 800 // resolve expr and find its 801 783 802 auto impCpCtorExpr = mutExpr->expr.as<ast::ImplicitCopyCtorExpr>(); 803 // PassVisitor<ResolveCopyCtors> fixer; 804 784 805 mutExpr->expr = mutExpr->expr->accept( *visitor ); 785 806 // it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought … … 799 820 } else { 800 821 // take data from other UniqueExpr to ensure consistency 822 // delete unqExpr->get_expr(); 801 823 mutExpr->expr = unqMap[mutExpr->id]->expr; 824 // delete unqExpr->result; 802 825 mutExpr->result = mutExpr->expr->result; 803 826 } … … 809 832 810 833 // 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 } 908 941 } 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; 912 979 } 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; 941 982 } // 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; 947 985 } // if 948 return objDecl;986 return _objDecl; 949 987 } 950 988 … … 968 1006 969 1007 void LabelFinder::previsit( const ast::CompoundStmt * stmt ) { 970 previsit( (const ast::Stmt *) stmt );1008 previsit( (const ast::Stmt *) stmt ); 971 1009 Parent::previsit( stmt ); 972 1010 } … … 984 1022 // its children manually. 985 1023 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) ; 987 1026 988 1027 // all labels for this function have been collected, insert destructors as appropriate via implicit recursion. … … 1039 1078 } 1040 1079 1041 /// Should we check for warnings? (The function is user-defined constrctor or destructor.)1042 1080 bool checkWarnings( const ast::FunctionDecl * funcDecl ) { 1081 // only check for warnings if the current function is a user-defined constructor or destructor 1043 1082 if ( ! funcDecl ) return false; 1044 1083 if ( ! funcDecl->stmts ) return false; … … 1066 1105 1067 1106 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 } 1081 1121 } 1082 1122 } … … 1124 1164 1125 1165 // insert and resolve default/copy constructor call for each field that's unhandled 1166 // std::list< const ast::Stmt * > stmt; 1126 1167 ast::Expr * arg2 = nullptr; 1127 1168 if ( function->name == "?{}" && isCopyFunction( function ) ) { 1128 1169 // if copy ctor, need to pass second-param-of-this-function.field 1170 // std::list< DeclarationWithType * > & params = function->get_functionType()->get_parameters(); 1129 1171 assert( function->params.size() == 2 ); 1130 1172 arg2 = new ast::MemberExpr(funcDecl->location, field, new ast::VariableExpr(funcDecl->location, function->params.back() ) ); … … 1137 1179 1138 1180 if ( callStmt ) { 1181 // auto & callStmt = stmt.front(); 1182 1139 1183 try { 1140 1184 callStmt = callStmt->accept( *visitor ); … … 1142 1186 mutStmts->push_front( callStmt ); 1143 1187 } 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 ); 1144 1190 1145 1191 // Optimization: do not need to call intrinsic destructors on members … … 1176 1222 throw errors; 1177 1223 } 1224 // return funcDecl; 1178 1225 return function; 1179 1226 } … … 1209 1256 1210 1257 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 } 1224 1272 } 1225 1273 } … … 1267 1315 ast::ptr<ast::ApplicationExpr> callExpr = ctorExpr->callExpr.strict_as<ast::ApplicationExpr>(); 1268 1316 ast::ptr<ast::TypeSubstitution> env = ctorExpr->env; 1317 // ctorExpr->set_callExpr( nullptr ); 1318 // ctorExpr->set_env( nullptr ); 1269 1319 1270 1320 // 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 673 673 ast::LogicalFlag flag ) { 674 674 return new ast::LogicalExpr( location, 675 maybeMoveBuild( expr_node1),676 maybeMoveBuild( expr_node2),675 notZeroExpr( maybeMoveBuild( expr_node1 ) ), 676 notZeroExpr( maybeMoveBuild( expr_node2 ) ), 677 677 flag 678 678 ); … … 713 713 ExpressionNode * expr_node3 ) { 714 714 return new ast::ConditionalExpr( location, 715 maybeMoveBuild( expr_node1),715 notZeroExpr( maybeMoveBuild( expr_node1 ) ), 716 716 maybeMoveBuild( expr_node2 ), 717 717 maybeMoveBuild( expr_node3 ) -
src/Parser/parserutility.cc
r221c542e rbad9c8f 27 27 // if ( (int)(x != 0) ) ... 28 28 29 ast::Expr * notZeroExpr( constast::Expr * orig ) {29 ast::Expr * notZeroExpr( ast::Expr * orig ) { 30 30 return ( !orig ) ? nullptr : new ast::CastExpr( orig->location, 31 31 ast::UntypedExpr::createCall( orig->location, -
src/Parser/parserutility.h
r221c542e rbad9c8f 21 21 } 22 22 23 ast::Expr * notZeroExpr( constast::Expr *orig );23 ast::Expr * notZeroExpr( ast::Expr *orig ); 24 24 25 25 template< typename T > -
src/ResolvExpr/CandidateFinder.cpp
r221c542e rbad9c8f 46 46 #include "AST/Type.hpp" 47 47 #include "Common/utility.h" // for move, copy 48 #include "Parser/parserutility.h" // for notZeroExpr49 48 #include "SymTab/Mangler.h" 50 49 #include "Tuples/Tuples.h" // for handleTupleAssignment … … 1503 1502 void Finder::postvisit( const ast::LogicalExpr * logicalExpr ) { 1504 1503 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() ); 1507 1505 if ( finder1.candidates.empty() ) return; 1508 1506 1509 1507 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() ); 1512 1509 if ( finder2.candidates.empty() ) return; 1513 1510 … … 1535 1532 // candidates for condition 1536 1533 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() ); 1539 1535 if ( finder1.candidates.empty() ) return; 1540 1536 -
src/Validate/Autogen.cpp
r221c542e rbad9c8f 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::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 805 856 } // namespace 806 857 807 858 void autogenerateRoutines( ast::TranslationUnit & translationUnit ) { 808 859 ast::Pass<AutogenerateRoutines>::run( translationUnit ); 860 // ast::Pass<PseudoFuncGenerateRoutine>::run( translationUnit ); 809 861 } 810 862 -
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" 1 6 #include "ReplacePseudoFunc.hpp" 2 7 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 Mangler12 8 namespace Validate { 13 9 14 10 namespace { 15 11 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); 12 struct ReplacePseudoFuncCore { 13 ast::Expr const * postvisit( ast::ApplicationExpr const * decl ); 21 14 }; 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 }48 15 } 49 16 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"); 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" ); 111 23 } 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" ); 116 27 } 117 const ast::ObjectDecl * argAsVar = arg->var.as<const ast::ObjectDecl>();28 const ast::ObjectDecl * argAsVar = arg->var.as<const ast::ObjectDecl>(); 118 29 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" ); 125 33 } 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 ); 186 38 } 187 39 } … … 190 42 } 191 43 192 } // namespace193 44 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 46 void replacePseudoFunc( ast::TranslationUnit & translationUnit ) { 47 ast::Pass<ReplacePseudoFuncCore>::run( translationUnit ); 198 48 } 199 } // namespace Validate 49 50 } -
src/main.cc
r221c542e rbad9c8f 82 82 #include "Validate/ReturnCheck.hpp" // for checkReturnStatements 83 83 #include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign 84 #include "Validate/ReplacePseudoFunc.hpp" // for replacePseudoFunc84 #include "Validate/ReplacePseudoFunc.hpp" 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.