Changes in / [61e362f:71b5aad5]
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/proposals/enum.tex
r61e362f r71b5aad5 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
r61e362f r71b5aad5 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/Validate/Autogen.cpp
r61e362f r71b5aad5 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
r61e362f r71b5aad5 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
Note: See TracChangeset
for help on using the changeset viewer.