Changes in / [61e362f:71b5aad5]


Ignore:
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • doc/proposals/enum.tex

    r61e362f r71b5aad5  
    245245
    246246
    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\
    264248\section{Unification}
    265249
     
    638622\section{Implementation}
    639623
    640 \subsection{Compiler Representation (Reworking)}
     624\subsection{Static Attribute Expression}
     625\begin{lstlisting}[label=lst:static_attr]
     626enum( char * ) Colour {
     627    Red = "red", Blue = "blue", Green = "green" 
     628};
     629\end{lstlisting}
     630An 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]
     634Colour c;
     635...
     636value( c ); // or c
     637\end{lstlisting}
     638An 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]
     643const char * Colour_labels [3] = { "Red", "Blue", "Green" };
     644const char * Colour_values [3] = { "red", "blue", "green" };
     645\end{lstlisting}
     646The \CFA compiles transforms the attribute expressions into array access.
     647\begin{lstlisting}[label=lst:attr_array_access]
     648position( c ) // c; an integer
     649value( c ); // Colour_values[c]
     650label( c ); // Colour_labels[c]
     651\end{lstlisting}
     652
     653To 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]
     658forall( 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
    641668The 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:
    642669\begin{lstlisting}[label=lst:EnumDecl]
     
    667694
    668695
    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}
     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}
    697724
    698725\subsection{Companion Traits (experimental)}
  • src/AST/Decl.hpp

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

    r61e362f r71b5aad5  
    803803}
    804804
    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 
    856805} // namespace
    857806
    858807void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
    859808        ast::Pass<AutogenerateRoutines>::run( translationUnit );
    860         // ast::Pass<PseudoFuncGenerateRoutine>::run( translationUnit );
    861809}
    862810
  • src/Validate/ReplacePseudoFunc.cpp

    r61e362f r71b5aad5  
     1#include "ReplacePseudoFunc.hpp"
     2
     3#include <set>
     4
    15#include "AST/Decl.hpp"
     6#include "AST/Inspect.hpp"
    27#include "AST/Pass.hpp"
    38#include "AST/Stmt.hpp"
    4 #include "AST/Inspect.hpp"
    59#include "Common/utility.h"
    6 #include "ReplacePseudoFunc.hpp"
    7 
     10#include "ResolvExpr/Resolver.h"
     11#include "SymTab/Mangler.h"  // for Mangler
    812namespace Validate {
    913
    1014namespace {
    1115
    12 struct ReplacePseudoFuncCore {
    13     ast::Expr const * postvisit( ast::ApplicationExpr const * decl );
     16std::set<std::string> queryLabels;
     17std::set<std::string> queryValues;
     18
     19struct FindGenEnumArray final : public ast::WithShortCircuiting {
     20    void previsit(const ast::ApplicationExpr* enumDecl);
    1421};
     22
     23void 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    }
    1548}
    1649
    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" );
     50struct PseudoFuncGenerateRoutine final : public ast::WithDeclsToAdd<>,
     51                                         public ast::WithSymbolTable,
     52                                         public ast::WithShortCircuiting {
     53    void previsit(const ast::EnumDecl* enumDecl);
     54};
     55
     56void 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
     97struct ReplacePseudoFuncCore : public ast::WithShortCircuiting,
     98                               public ast::WithSymbolTable,
     99                               public ast::WithConstTranslationUnit {
     100    ast::Expr const* postvisit(ast::ApplicationExpr const* decl);
     101};
     102
     103ast::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");
    23111        }
    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");
    27116        }
    28         const ast::ObjectDecl * argAsVar = arg->var.as<const ast::ObjectDecl>();
     117        const ast::ObjectDecl* argAsVar = arg->var.as<const ast::ObjectDecl>();
    29118        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");
    33125        }
    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                }
    38186            }
    39187        }
     
    42190}
    43191
     192}  // namespace
    44193
    45 
    46 void replacePseudoFunc( ast::TranslationUnit & translationUnit ) {
    47     ast::Pass<ReplacePseudoFuncCore>::run( translationUnit );
     194void replacePseudoFunc(ast::TranslationUnit& translationUnit) {
     195    ast::Pass<FindGenEnumArray>::run(translationUnit);
     196    ast::Pass<PseudoFuncGenerateRoutine>::run(translationUnit);
     197    ast::Pass<ReplacePseudoFuncCore>::run(translationUnit);
    48198}
    49 
    50 }
     199}  // namespace Validate
Note: See TracChangeset for help on using the changeset viewer.