Changes in / [71b5aad5:61e362f]


Ignore:
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/enum.tex

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

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

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

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