Changeset 85855b0


Ignore:
Timestamp:
Jun 10, 2024, 2:43:13 AM (5 weeks ago)
Author:
JiadaL <j82liang@…>
Branches:
master
Children:
42cdd07d
Parents:
d68de59
Message:
  1. Implement enum cast; 2. Change valueE so that opague enum returns quasi_void; 3. change enum hiding interpretation and pass visiting scheme
Files:
24 edited

Legend:

Unmodified
Added
Removed
  • libcfa/prelude/builtins.c

    rd68de59 r85855b0  
    178178} // distribution
    179179
     180struct quasi_void {};
     181static inline void ?{}(quasi_void &) {}
     182static inline void ?{}(quasi_void &, quasi_void) {}
     183static inline void ^?{}(quasi_void &) {}
     184static inline quasi_void ?=?(quasi_void &, quasi_void & _src) { return _src; }
     185
    180186// Local Variables: //
    181187// mode: c //
  • libcfa/src/enum.cfa

    rd68de59 r85855b0  
    11#include "enum.hfa"
     2#include "fstream.hfa"
    23
    34#pragma GCC visibility push(default)
    45
    5 forall(T, E| TypedEnum(T, E)) {
    6     // constructors
     6forall(ostype & | basic_ostream(ostype), E, V| CfaEnum(E, V))
     7ostype & ?|?(ostype& os, E e) {
     8    return os | type_name(e) | "." | labelE(e);
     9}
    710
    8     // comparison
    9     int ?==?(E l, E r) { return posE(l) == posE(r); }
    10     int ?!=?(E l, E r) { return posE(l) != posE(r); }
    11     int ?!=?(E l, zero_t) { return !( posE(l) == 0 ); }
    12     int ?<?(E l, E r) { return posE(l) < posE(r); }
    13     int ?<=?(E l, E r) { return posE(l) <= posE(r); }
    14     int ?>?(E l, E r) { return posE(l) > posE(r); }
    15     int ?>=?(E l, E r) {  return posE(l) >= posE(r); }
     11forall(ostype & | basic_ostream(ostype), E| CfaEnum(E, quasi_void))
     12ostype & ?|?(ostype& os, E e) {
     13    return os | type_name(e) | "." | labelE(e);
    1614}
  • libcfa/src/enum.hfa

    rd68de59 r85855b0  
    11#pragma once
    22
    3 forall(T) { // T is the based type of enum(T)
    4     forall(E) trait Bounded {
    5         E lowerBound();
    6         E upperBound();
    7     };
     3#include "iostream.hfa"
    84
    9     forall(E| Bounded(T, E)) trait Serial {
    10         unsigned fromInstance(E e);
    11         E fromInt(unsigned i);
    12         E succ(E e);
    13         E pred(E e);
    14     };
     5forall(E) trait Bounded {
     6    E lowerBound();
     7    E upperBound();
     8};
    159
    16     // Opague Enum + TypedEnum
    17     forall(E | Serial(T, E)) trait CfaEnum {
    18         char * labelE(E e);
    19         unsigned int posE(E e);
    20     };
     10forall(E | Bounded(E)) trait Serial {
     11    unsigned fromInstance(E e);
     12    E fromInt(unsigned i);
     13    E succ(E e);
     14    E pred(E e);
     15};
    2116
    22     forall(E| CfaEnum(T, E)) trait TypedEnum {
    23         T valueE(E e);
    24     };
     17// Design one
     18forall(E, V | Serial(E)) trait CfaEnum {
     19    char* labelE(E e);
     20    unsigned int posE(E e);
     21    V valueE(E e);
     22    char* type_name(E e);
     23};
    2524
    26         forall(E | TypedEnum(T, E)) {
    27                 // comparison
    28                 int ?==?(E l, E r);                                                             // true if l and r are same enumerators
    29                 int ?!=?(E l, E r);                                                             // true if l and r are different enumerators
    30                 int ?!=?(E l, zero_t);                                                  // true if l is not the first enumerator
    31                 int ?<?(E l, E r);                                                              // true if l is an enuemerator before r
    32                 int ?<=?(E l, E r);                                                             // true if l before or the same as r
    33                 int ?>?(E l, E r);                                                              // true if l is an enuemrator after r
    34                 int ?>=?(E l, E r);                                                             // true if l after or the same as r
    35         }
    36 }
     25forall(ostype & | basic_ostream(ostype), E, V| CfaEnum(E, V))
     26ostype & ?|?(ostype&, E);
     27
     28forall(ostype & | basic_ostream(ostype), E| CfaEnum(E, quasi_void))
     29ostype & ?|?(ostype&, E);
     30
     31// Design two <- should go for this if we have change the cost model
     32// forall(E | Serial(E)) trait CfaEnum {
     33//     char* labelE(E e);
     34//     unsigned int posE(E e);
     35// };
     36
     37// forall(E, V| CfaEnum(E)) trait TypedEnum {
     38//     V valueE(E e);
     39// };
  • src/AST/Decl.cpp

    rd68de59 r85855b0  
    170170
    171171const std::string EnumDecl::getUnmangeldArrayName( const ast::EnumAttribute attr ) const {
    172                 switch( attr ) {
    173                         case ast::EnumAttribute::Value: return "values_" + name ;
    174                         case ast::EnumAttribute::Label: return "labels_" + name;
    175                         default: /* Posn does not generate array */
    176                                 return "";
     172        switch( attr ) {
     173                case ast::EnumAttribute::Value: return "values_" + name ;
     174                case ast::EnumAttribute::Label: return "labels_" + name;
     175                default: /* Posn does not generate array */
     176                        return "";
     177        }
     178}
     179
     180unsigned EnumDecl::calChildOffset(const std::string & target) const{
     181        unsigned offset = 0;
     182        for (auto childEnum: inlinedDecl) {
     183                auto childDecl = childEnum->base;
     184                if (childDecl->name == target) {
     185                        return offset;
    177186                }
    178         }
     187                offset += childDecl->members.size();
     188        }
     189    std::cerr << "Cannot find the target enum" << std::endl;
     190        return 0;
     191}
     192
     193unsigned EnumDecl::calChildOffset(const ast::EnumInstType * target) const{
     194        return calChildOffset(target->base->name);
     195}
     196
     197bool EnumDecl::isSubTypeOf(const ast::EnumDecl * other) const {
     198        if (name == other->name) return true;
     199        for (auto inlined: other->inlinedDecl) {
     200                if (isSubTypeOf(inlined->base)) return true;
     201        }
     202        return false;
     203}
    179204
    180205}
  • src/AST/Decl.hpp

    rd68de59 r85855b0  
    7575        bool isDeleted = false;
    7676        bool isTypeFixed = false;
     77        bool isHidden = false;
    7778
    7879        DeclWithType( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
     
    313314        ptr<Type> base;
    314315        enum class EnumHiding { Visible, Hide } hide;
     316        std::vector< ast::ptr<ast::EnumInstType>> inlinedDecl; // child enums
     317
    315318        EnumDecl( const CodeLocation& loc, const std::string& name, bool isTyped = false,
    316319                std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall,
     
    328331
    329332        const std::string getUnmangeldArrayName( const EnumAttribute attr ) const;
     333
     334        unsigned calChildOffset(const std::string & childEnum) const;
     335        unsigned calChildOffset(const ast::EnumInstType * childEnum) const;
     336
     337        bool isSubTypeOf(const ast::EnumDecl *) const;
    330338private:
    331339        EnumDecl * clone() const override { return new EnumDecl{ *this }; }
  • src/AST/Expr.hpp

    rd68de59 r85855b0  
    256256public:
    257257        ptr<Decl> type_decl;
    258         std::string name;
     258        const std::string type_name;
     259        const std::string name;
    259260
    260261        QualifiedNameExpr( const CodeLocation & loc, const Decl * d, const std::string & n )
    261         : Expr( loc ), type_decl( d ), name( n ) {}
     262        : Expr( loc ), type_decl( d ), type_name(""), name( n ) {}
     263
     264        QualifiedNameExpr( const CodeLocation & loc, const std::string & type_name, const std::string & name)
     265        : Expr( loc ), type_name( type_name ), name( name ) {}
    262266
    263267        const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
  • src/AST/Pass.impl.hpp

    rd68de59 r85855b0  
    560560
    561561        if ( __visit_children() ) {
    562                 if ( node->hide == ast::EnumDecl::EnumHiding::Hide ) {
    563                         guard_symtab guard { *this };
    564                         maybe_accept( node, &EnumDecl::base );
    565                         maybe_accept( node, &EnumDecl::params     );
    566                         maybe_accept( node, &EnumDecl::members    );
    567                         maybe_accept( node, &EnumDecl::attributes );
    568                 } else {
    569                         maybe_accept( node, &EnumDecl::base );
    570                         maybe_accept( node, &EnumDecl::params     );
    571                         maybe_accept( node, &EnumDecl::members    );
    572                         maybe_accept( node, &EnumDecl::attributes );
    573                 }
     562                maybe_accept( node, &EnumDecl::base        );
     563                maybe_accept( node, &EnumDecl::params      );
     564                maybe_accept( node, &EnumDecl::members     );
     565                maybe_accept( node, &EnumDecl::attributes  );
     566                maybe_accept( node, &EnumDecl::inlinedDecl );
    574567        }
    575568
  • src/AST/SymbolTable.cpp

    rd68de59 r85855b0  
    159159}
    160160
     161std::vector<SymbolTable::IdData> SymbolTable::lookupIdIgnoreHidden( const std::string &id ) const {
     162        std::vector<IdData> out;
     163        std::vector<IdData> lookupResult = lookupId(id);
     164        for ( auto candidate: lookupResult) {
     165                if ( candidate.id ) {
     166                        if (candidate.id->isHidden) continue;
     167                }
     168                out.push_back(candidate);
     169        }
     170        return out;
     171}
     172
    161173std::vector<SymbolTable::IdData> SymbolTable::specialLookupId( SymbolTable::SpecialFunctionKind kind, const std::string & otypeKey ) const {
    162174        static Stats::Counters::CounterGroup * special_stats = Stats::Counters::build<Stats::Counters::CounterGroup>("Special Lookups");
  • src/AST/SymbolTable.hpp

    rd68de59 r85855b0  
    121121        /// Gets all declarations with the given ID
    122122        std::vector<IdData> lookupId( const std::string &id ) const;
     123        /// Gets all declarations with the given ID, ignoring hidden members from enumeration
     124        std::vector<IdData> lookupIdIgnoreHidden( const std::string &id ) const;
    123125        /// Gets special functions associated with a type; if no key is given, returns everything
    124126        std::vector<IdData> specialLookupId( SpecialFunctionKind kind, const std::string & otypeKey = "" ) const;
  • src/AST/Util.cpp

    rd68de59 r85855b0  
    352352        void previsit( EnumDecl const * decl ) {
    353353                enumDecls.insert( decl );
    354                 if ( ast::EnumDecl::EnumHiding::Visible == decl->hide ) {
    355                         for ( auto & member : decl->members ) {
    356                                 typedDecls.insert( member.strict_as<ast::DeclWithType>() );
    357                         }
     354                for ( auto & member : decl->members ) {
     355                        typedDecls.insert( member.strict_as<ast::DeclWithType>() );
    358356                }
    359357                beginScope();
  • src/GenPoly/Lvalue.cpp

    rd68de59 r85855b0  
    389389                assert( 0 == diff );
    390390                // Remove useless generated casts.
    391                 if ( expr->isGenerated &&
     391                if ( expr->isGenerated == ast::GeneratedFlag::GeneratedCast &&
    392392                                ResolvExpr::typesCompatible(
    393393                                        expr->result,
     
    398398                                std::cerr << "-- " << expr->arg->result << std::endl;
    399399                        )
     400                        auto argAsEnum = expr->arg.as<ast::EnumInstType>();
     401                        auto resultAsEnum = expr->result.as<ast::EnumInstType>();
     402                        if (argAsEnum && resultAsEnum) {
     403                                if (argAsEnum->base->name != resultAsEnum->base->name) {
     404                                        return expr;
     405                                }
     406                        }
    400407                        return ast::mutate_field( expr->arg.get(),
    401408                                        &ast::Expr::env, expr->env.get() );
  • src/Parser/TypeData.cpp

    rd68de59 r85855b0  
    14651465        ret->hide = td->aggregate.hiding == EnumHiding::Hide ? ast::EnumDecl::EnumHiding::Hide : ast::EnumDecl::EnumHiding::Visible;
    14661466        for ( const DeclarationNode * cur = td->aggregate.fields ; cur != nullptr ; cur = cur->next, ++members ) {
    1467                 if ( cur->enumInLine ) {
    1468                         // Do Nothing
    1469                 } else if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
     1467                if (cur->enumInLine) continue;
     1468                ast::Decl * member = members->get_and_mutate();
     1469                ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
     1470                object->isHidden = ast::EnumDecl::EnumHiding::Hide == ret->hide;
     1471                if ( ret->isTyped && !ret->base && cur->has_enumeratorValue() ) {
    14701472                        SemanticError( td->location, "Enumerator of enum(void) cannot have an explicit initializer value." );
    14711473                } else if ( cur->has_enumeratorValue() ) {
    1472                         ast::Decl * member = members->get_and_mutate();
    1473                         ast::ObjectDecl * object = strict_dynamic_cast<ast::ObjectDecl *>( member );
    14741474                        object->init = new ast::SingleInit(
    14751475                                td->location,
     
    14771477                                ast::NoConstruct
    14781478                        );
    1479                 } else if ( !cur->initializer ) {
    1480                         if ( baseType && (!dynamic_cast<ast::BasicType *>(baseType) || !dynamic_cast<ast::BasicType *>(baseType)->isInteger())) {
    1481                                 SemanticError( td->location, "Enumerators of an non-integer typed enum must be explicitly initialized." );
    1482                         }
    1483                 }
     1479                }
    14841480                // else cur is a List Initializer and has been set as init in buildList()
    14851481                // if
  • src/Parser/parser.yy

    rd68de59 r85855b0  
    28272827        | enumerator_list ',' visible_hide_opt identifier_or_type_name enumerator_value_opt
    28282828                { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( $4, $5 ) ); }
    2829         | enumerator_list ',' INLINE type_name enumerator_value_opt
    2830                 { $$ = $1->set_last( DeclarationNode::newEnumValueGeneric( new string("inline"), nullptr ) ); }
     2829        | enumerator_list ',' INLINE type_name
     2830                { $$ = $1->set_last( DeclarationNode::newEnumInLine( $4->symbolic.name ) ); }
    28312831        ;
    28322832
  • src/ResolvExpr/CandidateFinder.cpp

    rd68de59 r85855b0  
    513513                                        // add new result
    514514                                        assert( common );
    515                                                 results.emplace_back(
    516                                                         i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
    517                                                         nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    518                                         //}
     515
     516                                        auto paramAsEnum = dynamic_cast<const ast::EnumInstType *>(paramType);
     517                                        auto argAsEnum =dynamic_cast<const ast::EnumInstType *>(argType);
     518                                        if (paramAsEnum && argAsEnum) {
     519                                                if (paramAsEnum->base->name != argAsEnum->base->name) {
     520                                                        Cost c = castCost(argType, paramType, expr, context.symtab, env);
     521                                                        if (c < Cost::infinity) {
     522                                                                CandidateFinder subFinder( context, env );
     523                                                                expr = subFinder.makeEnumOffsetCast(argAsEnum, paramAsEnum, expr, c);
     524                                                                results.emplace_back(
     525                                                                        i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     526                                                                        nextArg + 1, nTuples, expl.cost + c, expl.exprs.size() == 1 ? 0 : 1, j );
     527                                                                continue;
     528                                                        } else {
     529                                                                std::cerr << "Cannot instantiate " << paramAsEnum->base->name <<  " with " << argAsEnum->base->name << std::endl;
     530                                                        }
     531                                                }
     532                                        }
     533                                        results.emplace_back(
     534                                                i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
     535                                                nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
    519536                                }
    520537                        }
     
    632649                        const ast::BaseInstType * aggrInst, const ast::Expr * expr,
    633650                        const Candidate & cand, const Cost & addedCost, const std::string & name
     651                );
     652
     653                void addEnumValueAsCandidate(const ast::EnumInstType * instType, const ast::Expr * expr,
     654                        const Cost & addedCost
    634655                );
    635656
     
    676697                void postvisit( const ast::QualifiedNameExpr * qualifiedExpr );
    677698
     699                const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src,
     700                        const ast::EnumInstType * dst
     701                        , const ast::Expr * expr, Cost minCost );
     702
    678703                void postvisit( const ast::InitExpr * ) {
    679704                        assertf( false, "CandidateFinder should never see a resolved InitExpr." );
     
    876901        }
    877902
     903        void Finder::addEnumValueAsCandidate( const ast::EnumInstType * enumInst, const ast::Expr * expr,
     904                const Cost & addedCost
     905        ) {
     906                if ( enumInst->base->base ) {
     907                        CandidateFinder finder( context, tenv );
     908                        auto location = expr->location;
     909                        auto callExpr = new ast::UntypedExpr(
     910                                location, new ast::NameExpr( location, "valueE" ), {expr}
     911                        );
     912                        finder.find( callExpr );
     913                        CandidateList winners = findMinCost( finder.candidates );
     914                        if (winners.size() != 1) {
     915                                SemanticError( callExpr, "Ambiguous expression in valueE..." );
     916                        }
     917                        CandidateRef & choice = winners.front();
     918                        choice->cost += addedCost;
     919                        addAnonConversions(choice);
     920                        candidates.emplace_back( std::move(choice) );
     921                }
     922        }
     923
    878924        /// Adds implicit struct-conversions to the alternative list
    879925        void Finder::addAnonConversions( const CandidateRef & cand ) {
     
    894940                        addAggMembers( unionInst, aggrExpr, *cand, Cost::unsafe, "" );
    895941                } else if ( auto enumInst = aggrExpr->result.as< ast::EnumInstType >() ) {
    896                         if ( enumInst->base->base ) {
    897                                 CandidateFinder finder( context, tenv );
    898                                 auto location = aggrExpr->location;
    899                                 auto callExpr = new ast::UntypedExpr(
    900                                         location, new ast::NameExpr( location, "valueE" ), {aggrExpr}
    901                                 );
    902                                 finder.find( callExpr );
    903                                 CandidateList winners = findMinCost( finder.candidates );
    904                                 if (winners.size() != 1) {
    905                                         SemanticError( callExpr, "Ambiguous expression in valueE..." );
    906                                 }
    907                                 CandidateRef & choice = winners.front();
    908                                 choice->cost = Cost::unsafe;
    909                                 candidates.emplace_back( std::move(choice) );
    910                         }
    911 
    912                 }
    913         }
     942                        addEnumValueAsCandidate(enumInst, aggrExpr, Cost::unsafe);
     943                }
     944        }
     945       
    914946
    915947        /// Adds aggregate member interpretations
     
    11801212        }
    11811213
     1214        // src is a subset of dst
     1215        const ast::Expr * Finder::makeEnumOffsetCast( const ast::EnumInstType * src,
     1216                const ast::EnumInstType * dst,
     1217                const ast::Expr * expr,
     1218                Cost minCost ) {
     1219               
     1220                auto srcDecl = src->base;
     1221                auto dstDecl = dst->base;
     1222
     1223                if (srcDecl->name == dstDecl->name) return expr;
     1224
     1225                for (auto& dstChild: dstDecl->inlinedDecl) {
     1226                        Cost c = castCost(src, dstChild, false, symtab, tenv);
     1227                        ast::CastExpr * castToDst;
     1228                        if (c<minCost) {
     1229                                unsigned offset = dstDecl->calChildOffset(dstChild.get());
     1230                                if (offset > 0) {
     1231                                        auto untyped = ast::UntypedExpr::createCall(
     1232                                                expr->location,
     1233                                                "?+?",
     1234                                                { new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
     1235                                                ast::ConstantExpr::from_int(expr->location, offset)});
     1236                                        CandidateFinder finder(context, tenv);
     1237                                        finder.find( untyped );
     1238                                        CandidateList winners = findMinCost( finder.candidates );
     1239                                        CandidateRef & choice = winners.front();
     1240                                        // choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
     1241                                        choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
     1242                                        // castToDst = new ast::CastExpr(choice->expr, dstChild);
     1243                                        castToDst = new ast::CastExpr(
     1244                                                makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
     1245                                         dst);
     1246
     1247                                } else {
     1248                                        castToDst = new ast::CastExpr( expr, dst );
     1249                                }
     1250                                return castToDst;
     1251                        }
     1252                }
     1253                SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
     1254                return nullptr;
     1255        }
     1256
    11821257        void Finder::postvisit( const ast::CastExpr * castExpr ) {
    11831258                ast::ptr< ast::Type > toType = castExpr->result;
     
    12291304                                        ? conversionCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env )
    12301305                                        : castCost( cand->expr->result, toType, cand->expr->get_lvalue(), symtab, cand->env );
     1306                       
     1307                        // Redefine enum cast
     1308                        auto argAsEnum = cand->expr->result.as<ast::EnumInstType>();
     1309                        auto toAsEnum = toType.as<ast::EnumInstType>();
     1310                        if ( argAsEnum && toAsEnum && argAsEnum->name != toAsEnum->name ) {     
     1311                                ast::ptr<ast::Expr> offsetExpr = makeEnumOffsetCast(argAsEnum, toAsEnum, cand->expr, thisCost);
     1312                                cand->expr = offsetExpr;
     1313                        }
    12311314
    12321315                        PRINT(
     
    12461329                                        minCastCost = thisCost;
    12471330                                        matches.clear();
    1248 
    1249 
    1250                                 }
    1251                                 // ambiguous case, still output candidates to print in error message
     1331                                }
     1332                                // ambigious case, still output candidates to print in error message
    12521333                                if ( cand->cost == minExprCost && thisCost == minCastCost ) {
    12531334                                        CandidateRef newCand = std::make_shared<Candidate>(
     
    12641345                }
    12651346                candidates = std::move(matches);
    1266 
    12671347                //CandidateList minArgCost = findMinCost( matches );
    12681348                //promoteCvtCost( minArgCost );
     
    13741454                        }
    13751455                } else {
    1376                         declList = symtab.lookupId( nameExpr->name );
     1456                        declList = symtab.lookupIdIgnoreHidden( nameExpr->name );
    13771457                }
    13781458                PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
     
    13861466                        ast::Expr * newExpr = data.combine( nameExpr->location, cost );
    13871467
    1388                         // bool bentConversion = false;
    1389                         // if ( auto inst = newExpr->result.as<ast::EnumInstType>() ) {
    1390                         //      if ( inst->base && inst->base->base ) {
    1391                         //              bentConversion = true;
    1392                         //      }
    1393                         // }
    1394 
    1395                         // CandidateRef newCand = std::make_shared<Candidate>(
    1396                         //      newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, bentConversion? Cost::safe: Cost::zero,
    1397                         //      cost );
    13981468                        CandidateRef newCand = std::make_shared<Candidate>(
    13991469                                newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
     
    18131883                        if ( const ast::EnumInstType * enumInstType =
    18141884                                dynamic_cast<const ast::EnumInstType *>( t ) ) {
    1815                                 if ( enumInstType->base->name == expr->type_decl->name ) {
     1885                                if ( (enumInstType->base->name == expr->type_name)
     1886                                        || (expr->type_decl && enumInstType->base->name == expr->type_decl->name) ) {
    18161887                                        Cost cost = Cost::zero;
    18171888                                        ast::Expr * newExpr = data.combine( expr->location, cost );
    1818                                         // CandidateRef newCand =
    1819                                         //      std::make_shared<Candidate>(
    1820                                         //              newExpr, copy( tenv ), ast::OpenVarSet{},
    1821                                         //              ast::AssertionSet{}, Cost::safe, cost
    1822                                         //      );
    18231889                                        CandidateRef newCand =
    18241890                                                std::make_shared<Candidate>(
     
    20962162
    20972163        return expr;
     2164}
     2165
     2166const ast::Expr * CandidateFinder::makeEnumOffsetCast( const ast::EnumInstType * src,
     2167        const ast::EnumInstType * dst,
     2168        const ast::Expr * expr,
     2169        Cost minCost ) {
     2170       
     2171        auto srcDecl = src->base;
     2172        auto dstDecl = dst->base;
     2173
     2174        if (srcDecl->name == dstDecl->name) return expr;
     2175
     2176        for (auto& dstChild: dstDecl->inlinedDecl) {
     2177                Cost c = castCost(src, dstChild, false, context.symtab, env);
     2178                ast::CastExpr * castToDst;
     2179                if (c<minCost) {
     2180                        unsigned offset = dstDecl->calChildOffset(dstChild.get());
     2181                        if (offset > 0) {
     2182                                auto untyped = ast::UntypedExpr::createCall(
     2183                                        expr->location,
     2184                                        "?+?",
     2185                                        { new ast::CastExpr( expr, new ast::BasicType(ast::BasicKind::SignedInt) ),
     2186                                        ast::ConstantExpr::from_int(expr->location, offset)});
     2187                                CandidateFinder finder(context, env);
     2188                                finder.find( untyped );
     2189                                CandidateList winners = findMinCost( finder.candidates );
     2190                                CandidateRef & choice = winners.front();
     2191                                choice->expr = new ast::CastExpr(expr->location, choice->expr, dstChild, ast::GeneratedFlag::ExplicitCast);
     2192                                castToDst = new ast::CastExpr(
     2193                                        makeEnumOffsetCast( src, dstChild, choice->expr, minCost ),
     2194                                        dst);
     2195                        } else {
     2196                                castToDst = new ast::CastExpr( expr, dst );
     2197                        }
     2198                        return castToDst;
     2199                }
     2200        }
     2201        SemanticError(expr, src->base->name + " is not a subtype of " + dst->base->name);
     2202        return nullptr;
    20982203}
    20992204
  • src/ResolvExpr/CandidateFinder.hpp

    rd68de59 r85855b0  
    5858        iterator end() { return candidates.end(); }
    5959        const_iterator end() const { return candidates.end(); }
     60
     61        const ast::Expr * makeEnumOffsetCast( const ast::EnumInstType * src,
     62                const ast::EnumInstType * dst, const ast::Expr * expr, Cost minCost );
    6063};
    6164
  • src/ResolvExpr/CastCost.cpp

    rd68de59 r85855b0  
    3636namespace ResolvExpr {
    3737
     38Cost castCost(
     39        const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
     40        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     41);
     42
    3843namespace {
    3944        struct CastCost : public ConversionCost {
     
    4550                        const ast::TypeEnvironment & env, CostCalculation costFunc )
    4651                : ConversionCost( dst, srcIsLvalue, symtab, env, costFunc ) {}
     52
     53                void postvisit( const ast::EnumInstType * enumInst ) {
     54                        cost = conversionCost( enumInst, dst, srcIsLvalue, symtab, env );
     55                }
    4756
    4857                void postvisit( const ast::BasicType * basicType ) {
     
    104113                                        cost = Cost::unsafe;
    105114                                }
    106                         }
    107                 }
    108 
    109                 void postvist( const ast::EnumInstType * ) {
    110                         if ( auto basic = dynamic_cast< const ast::BasicType * >(dst) ) {
    111                                 if ( basic->isInteger() ) cost = Cost::unsafe;
    112115                        }
    113116                }
  • src/ResolvExpr/CommonType.cpp

    rd68de59 r85855b0  
    636636        void postvisit( const ast::UnionInstType * ) {}
    637637
    638         void postvisit( const ast::EnumInstType * enumInst ) {
    639                 if ( enumInst->base && !enumInst->base->isTyped ) {
     638        void postvisit( const ast::EnumInstType * param ) {
     639                auto argAsEnumInst = dynamic_cast<const ast::EnumInstType *>(type2);
     640                if ( argAsEnumInst ) {
     641                        const ast::EnumDecl* paramDecl = param->base;
     642                        const ast::EnumDecl* argDecl = argAsEnumInst->base;
     643                        if (argDecl->isSubTypeOf(paramDecl)) result = param;
     644                } else if ( param->base && !param->base->isTyped ) {
    640645                        auto basicType = new ast::BasicType( ast::BasicKind::UnsignedInt );
    641646                        result = commonType( basicType, type2, tenv, need, have, open, widen);
  • src/ResolvExpr/ConversionCost.cpp

    rd68de59 r85855b0  
    191191}
    192192
     193Cost enumCastCost (
     194        const ast::EnumInstType * src, const ast::EnumInstType * dst,
     195        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     196);
     197
    193198static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
    194199                int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
     
    359364
    360365void ConversionCost::postvisit( const ast::EnumInstType * inst ) {
    361         if ( auto dstAsInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
    362                 if (inst->base && dstAsInst->base) {
    363                         if (inst->base->name == dstAsInst->base->name) {
    364                                 cost = Cost::zero;
    365                                 return;
    366                         }
    367                 }
     366        if ( auto dstInst = dynamic_cast<const ast::EnumInstType *>( dst ) ) {
     367                cost = enumCastCost(inst, dstInst, symtab, env);
    368368                return;
    369369        }
     
    481481}
    482482
     483// (dst) src is safe is src is a subtype of dst, or dst {inline src, ...}
     484Cost enumCastCost (
     485        const ast::EnumInstType * src, const ast::EnumInstType * dst,
     486        const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
     487) {
     488        auto srcDecl = src->base;
     489        auto dstDecl = dst->base;
     490        if (srcDecl->name == dstDecl->name) return Cost::safe;
     491        Cost minCost = Cost::infinity;
     492        for (auto child: dstDecl->inlinedDecl) {
     493                Cost c = enumCastCost(src, child, symtab, env) + Cost::safe;
     494                if (c<minCost) minCost = c;
     495        }
     496        return minCost;
     497}
     498
     499
    483500// size_t ConversionCost::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
    484501
  • src/ResolvExpr/Resolver.cpp

    rd68de59 r85855b0  
    201201                                && typesCompatible( castExpr->arg->result, castExpr->result )
    202202                        ) {
     203                                auto argAsEnum = castExpr->arg.as<ast::EnumInstType>();
     204                                auto resultAsEnum = castExpr->result.as<ast::EnumInstType>();
     205                                if (argAsEnum && resultAsEnum) {
     206                                        if (argAsEnum->base->name != resultAsEnum->base->name) {
     207                                                std::cerr << "Enum Cast: " << argAsEnum->base->name << " to " << resultAsEnum->base->name << std::endl;
     208                                                return castExpr;
     209                                        }
     210                                }
    203211                                // generated cast is the same type as its argument, remove it after keeping env
    204212                                return ast::mutate_field(
  • src/Validate/Autogen.cpp

    rd68de59 r85855b0  
    410410}
    411411
    412 /// Use the current type T to create `T ?{}(T & _dst, T _src)`.
     412/// Use the current type T to create `T ?=?(T & _dst, T _src)`.
    413413ast::FunctionDecl * FuncGenerator::genAssignProto() const {
    414414        // Only the name is different, so just reuse the generation function.
  • src/Validate/EnumAndPointerDecay.cpp

    rd68de59 r85855b0  
    4747                                new ast::EnumInstType( decl, ast::CV::Const ) ) );
    4848                } else if ( auto value = member.as<ast::InlineMemberDecl>() ) {
    49                         if ( auto targetEnum = symtab.lookupEnum( value->name ) ) {
    50                                 for ( auto enumMember : targetEnum->members ) {
    51                                         auto enumObject = enumMember.strict_as<ast::ObjectDecl>();
    52                                         buffer.push_back( new ast::ObjectDecl(
    53                                                 // Get the location from the "inline" declaration.
    54                                                 value->location,
    55                                                 enumObject->name,
    56                                                 // Construct a new EnumInstType as the type.
    57                                                 new ast::EnumInstType( decl, ast::CV::Const ),
    58                                                 enumObject->init,
    59                                                 enumObject->storage,
    60                                                 enumObject->linkage,
    61                                                 enumObject->bitfieldWidth,
    62                                                 {},
    63                                                 enumObject->funcSpec
    64                                         ) );
    65                                 }
     49                        auto targetEnum = symtab.lookupEnum( value->name );
     50                        // assert( targetEnum );
     51                        if (!targetEnum) {
     52                                SemanticError(value, "Only another enum is allowed for enum inline syntax ");
     53                        }
     54                        const ast::EnumInstType * instType = new ast::EnumInstType(targetEnum);
     55                        mut->inlinedDecl.push_back( std::move(instType) );
     56                        for ( auto enumMember : targetEnum->members ) {
     57                                auto enumObject = enumMember.strict_as<ast::ObjectDecl>();
     58                                buffer.push_back(new ast::ObjectDecl(
     59                                        // Get the location from the "inline" declaration.
     60                                        value->location,
     61                                        enumObject->name,
     62                                        // Construct a new EnumInstType as the type.
     63                                        new ast::EnumInstType( decl, ast::CV::Const ),
     64                                        enumObject->init,
     65                                        enumObject->storage,
     66                                        enumObject->linkage,
     67                                        enumObject->bitfieldWidth,
     68                                        {},
     69                                        enumObject->funcSpec
     70                                ));
    6671                        }
    6772                }
  • src/Validate/ImplementEnumFunc.cpp

    rd68de59 r85855b0  
    1010        const ast::EnumDecl* decl;
    1111        unsigned int functionNesting;
     12        const ast::StructDecl* quasi_void_decl;
    1213        ast::Linkage::Spec proto_linkage;
    1314
     
    2425                : decl(decl),
    2526                  functionNesting{functionNesting},
     27                  quasi_void_decl(new ast::StructDecl(decl->location,
     28                        "quasi_void", ast::AggregateDecl::Struct,
     29                        {}, ast::Linkage::AutoGen)),
    2630                  proto_linkage{ast::Linkage::Cforall} {}
    2731
     
    5256        void genSuccPredBody(ast::FunctionDecl *, const char *) const;
    5357
     58        void genTypeNameFunc();
     59
    5460        // Implement TypedEnum trait
    5561        void genTypedEnumFuncs();
     
    5864        ast::FunctionDecl* genLabelProto() const;
    5965        ast::FunctionDecl* genValueProto() const;
     66        ast::FunctionDecl* genQuasiValueProto() const;
     67        ast::FunctionDecl* genTypeNameProto() const;
     68
    6069        void genValueOrLabelBody(
    6170                ast::FunctionDecl* func, ast::ObjectDecl* arrDecl) const;
    6271        void genPosnBody(ast::FunctionDecl* func) const;
    63 
    64         ////////////////
    65 
    66         // ---------------------------------------------------
    67         // ast::FunctionDecl* genAttrCtorProto() const;
    68         /// Changes the node inside a pointer so that it has the unused attribute.
    69         void addUnusedAttribute(ast::ptr<ast::DeclWithType>& declPtr) {
    70                 ast::DeclWithType* decl = declPtr.get_and_mutate();
    71                 decl->attributes.push_back(new ast::Attribute("unused"));
    72         }
     72        void genQuasiValueBody(ast::FunctionDecl* func) const;
     73        void genTypeNameBody(ast::FunctionDecl* func) const;
    7374
    7475        // ----------------------------------------------------
     
    117118        return inits;
    118119}
     120
    119121const ast::Init* EnumAttrFuncGenerator::getAutoInit(
    120122        const ast::Init* prev) const {
     
    189191
    190192ast::FunctionDecl* EnumAttrFuncGenerator::genValueProto() const {
     193        if (decl->base)
     194                return genProto(
     195                        "valueE",
     196                        {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     197                        {new ast::ObjectDecl(getLocation(), "_ret",
     198                                                                ast::deepCopy(decl->base))});
     199        else
     200                return genQuasiValueProto();
     201}
     202
     203ast::FunctionDecl* EnumAttrFuncGenerator::genQuasiValueProto() const {
    191204        return genProto(
    192205                "valueE",
    193206                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
    194207                {new ast::ObjectDecl(getLocation(), "_ret",
    195                                      ast::deepCopy(decl->base))});
     208                                                new ast::StructInstType(quasi_void_decl))});
    196209}
    197210
     
    210223                {new ast::ObjectDecl(getLocation(), "_ret", new ast::BasicType(ast::BasicKind::UnsignedInt))}
    211224        );
     225}
     226
     227ast::FunctionDecl* EnumAttrFuncGenerator::genTypeNameProto() const {
     228        return genProto(
     229                "type_name",
     230                {new ast::ObjectDecl(getLocation(), "_i", new ast::EnumInstType(decl))},
     231                {new ast::ObjectDecl(
     232                        getLocation(), "_ret",
     233                        new ast::PointerType(new ast::BasicType{ast::BasicKind::Char}))});
    212234}
    213235
     
    268290        );
    269291}
    270 
    271292
    272293void EnumAttrFuncGenerator::genSerialTraitFuncs() {
     
    302323        const CodeLocation & loc = func->location;
    303324        auto mem = func->name=="lowerBound"?  decl->members.front() : decl->members.back();
    304         auto expr = new ast::NameExpr( loc, mem->name );
     325        // auto expr = new ast::NameExpr( loc, mem->name );
     326        auto expr = new ast::QualifiedNameExpr( loc, decl->name, mem->name );
    305327        func->stmts = new ast::CompoundStmt( loc, {new ast::ReturnStmt(loc, expr)});
    306328}
     
    349371}
    350372
     373void EnumAttrFuncGenerator::genQuasiValueBody(ast::FunctionDecl* func) const {
     374        auto location = func->location;
     375        const ast::ObjectDecl * objDecl = new ast::ObjectDecl(
     376                location, "_out", new ast::StructInstType( quasi_void_decl ));
     377        const ast::DeclStmt * declStmt = new ast::DeclStmt(location, objDecl);
     378        const ast::VariableExpr * varExpr = new ast::VariableExpr(location, objDecl);
     379        const ast::ReturnStmt * retStmt = new ast::ReturnStmt(location, varExpr);
     380
     381        func->stmts = new ast::CompoundStmt(
     382                location, {declStmt, retStmt}
     383        );
     384}
     385
    351386void EnumAttrFuncGenerator::genPosnBody(ast::FunctionDecl* func) const {
    352387        auto castExpr = new ast::CastExpr(
     
    359394}
    360395
     396void EnumAttrFuncGenerator::genTypeNameBody(ast::FunctionDecl* func) const {
     397        const ast::Expr * type_name = ast::ConstantExpr::from_string(func->location, decl->name);
     398        func->stmts = new ast::CompoundStmt(
     399                func->location, {new ast::ReturnStmt(func->location, type_name)}
     400        );
     401}
     402
    361403void EnumAttrFuncGenerator::genTypedEnumFunction(const ast::EnumAttribute attr) {
    362         if (attr == ast::EnumAttribute::Value ||
    363                 attr == ast::EnumAttribute::Label) {
    364                 // TypedEnum's backing arrays
    365                 std::vector<ast::ptr<ast::Init>> inits =
    366                         attr == ast::EnumAttribute::Value ? genValueInit() : genLabelInit();
     404        if (attr == ast::EnumAttribute::Value) {
     405                if (decl->base) {
     406                        // TypedEnum's backing arrays
     407                        std::vector<ast::ptr<ast::Init>> inits = genValueInit();
     408                        ast::ObjectDecl* arrayProto =
     409                                genAttrArrayProto(attr, getLocation(), inits);
     410                        forwards.push_back(arrayProto);
     411
     412                        ast::FunctionDecl* funcProto = genValueProto();
     413                        produceForwardDecl(funcProto);
     414                        genValueOrLabelBody(funcProto, arrayProto);
     415                        produceDecl(funcProto);
     416                }  else {
     417                        ast::FunctionDecl* funcProto = genQuasiValueProto();
     418                        produceForwardDecl(funcProto);
     419                        genQuasiValueBody(funcProto);
     420                        produceDecl(funcProto);
     421                }
     422        } else if (attr == ast::EnumAttribute::Label) {
     423                std::vector<ast::ptr<ast::Init>> inits = genLabelInit();
    367424                ast::ObjectDecl* arrayProto =
    368425                        genAttrArrayProto(attr, getLocation(), inits);
    369426                forwards.push_back(arrayProto);
    370 
    371                 ast::FunctionDecl* funcProto = ( attr == ast::EnumAttribute::Value )
    372                                                ? genValueProto()
    373                                                : genLabelProto();
     427                ast::FunctionDecl* funcProto = genLabelProto();
    374428                produceForwardDecl(funcProto);
    375429                genValueOrLabelBody(funcProto, arrayProto);
     
    384438
    385439void EnumAttrFuncGenerator::genTypedEnumFuncs() {
    386         if (decl->base) genTypedEnumFunction(ast::EnumAttribute::Value);
     440        genTypedEnumFunction(ast::EnumAttribute::Value);
    387441        genTypedEnumFunction(ast::EnumAttribute::Label);
    388442        genTypedEnumFunction(ast::EnumAttribute::Posn);
     443}
     444
     445void EnumAttrFuncGenerator::genTypeNameFunc() {
     446        ast::FunctionDecl* funcProto = genTypeNameProto();
     447        produceForwardDecl(funcProto);
     448        genTypeNameBody(funcProto);
     449        produceDecl(funcProto);
    389450}
    390451
     
    392453        std::list<ast::ptr<ast::Decl>>& decls) {
    393454        // Generate the functions (they go into forwards and definitions).
     455        genTypeNameFunc();
    394456        genTypedEnumFuncs();
    395457        genSerialTraitFuncs();
  • tests/enum_tests/.expect/enumInlineValue.txt

    rd68de59 r85855b0  
    1 enumB.A is 5
    2 enumB.B is 6
    3 enumB.D is 11
    4 enumB.E is 12
     1Symbols (enumerator) should have the same values:
     2Symbol a: (10) 10, 10, 10
     3Symbol b: (20) 20, 20
     4Symbol ab: (30) 30
     5Symbol c: (40) 40, 40, 40
     6Symbol d: (50) 50, 50, 50
     7Symbol cd: (60) 60, 60
     8Symbol acd: (70) 70
     9Casting/Upcasting:
     10Symbol a: (10) 10, 10, 10
     11Symbol b: (20) 20, 20
     12Symbol ab: (30) 30
     13Symbol c: (40) 40, 40, 40, 40, 40
     14Symbol d: (50) 50, 50, 50, 50
     15Symbol cd: (60) 60, 60
     16Symbol acd: (70) 70
     17Function Call:
     18Symbol a: (10) 10, 10
     19Symbol c: (40) 40, 40
     20Symbol d: (50) 50, 50
     21Symbol cd: (60) 60, 60
     22Symbol acd: (70) 70
  • tests/enum_tests/enumInlineValue.cfa

    rd68de59 r85855b0  
    22#include <enum.hfa>
    33
    4 enum(int) A {
     4enum(int) A !{
    55    a = 10
    66};
     
    3636};
    3737
    38 int identity(A a) {
    39     return valueE(a);
     38// Note: variable name (cat in this case) cannot be overloaded with those declared in enum,
     39// Probably for the same reason as const overloading problem
     40// i.e. int identity_t(enum ACD a) would not work as the valueE(a) is ambigious currently
     41int identity_t(enum ACD cat) {
     42    return valueE(cat);
    4043}
    4144
     
    4346    // Note: We need to use qualified name syntax even if no ! hidding
    4447    // Because Inline introduce ambiguity on symbols
    45     // sout | "Symbols (enumerator) should have the same values:" |nl;
    46     // sout | "Symbol a: (10) " | valueE(A.a) | "," | valueE(AB.a) | "," | valueE(ACD.a) | nl;
    47     // sout | "Symbol b: (20) " | valueE(B.b) | "," | valueE(AB.b) | nl;
    48     // sout | "Symbol ab: (30) " | valueE(AB.ab) | nl;
    49     // sout | "Symbol c: (40) " | valueE(C.c) | "," | valueE(CD.c) | "," | valueE(ACD.c) | nl;
    50     // sout | "Symbol d: (50) " | valueE(D.d) | "," | valueE(CD.d) | "," | valueE(ACD.d) | nl;
    51     // sout | "Symbol cd: (60) " | valueE(CD.cd) | "," | valueE(ACD.cd) | nl;
    52     // sout | "Symbol acd: (70) " | valueE(ACD.acd) | nl;
     48    sout | "Symbols (enumerator) should have the same values:" |nl;
     49    sout | "Symbol a: (10) " | valueE(A.a) | "," | valueE(AB.a) | "," | valueE(ACD.a) | nl;
     50    sout | "Symbol b: (20) " | valueE(B.b) | "," | valueE(AB.b) | nl;
     51    sout | "Symbol ab: (30) " | valueE(AB.ab) | nl;
     52    sout | "Symbol c: (40) " | valueE(C.c) | "," | valueE(CD.c) | "," | valueE(ACD.c) | nl;
     53    sout | "Symbol d: (50) " | valueE(D.d) | "," | valueE(CD.d) | "," | valueE(ACD.d) | nl;
     54    sout | "Symbol cd: (60) " | valueE(CD.cd) | "," | valueE(ACD.cd) | nl;
     55    sout | "Symbol acd: (70) " | valueE(ACD.acd) | nl;
    5356
    54     // sout | "Casting/Upcasting:" | nl;
    55     // sout | "Symbol a: (10) " | valueE((A)A.a) | "," | valueE((AB)A.a) | "," | valueE((ACD)A.a) | nl;
    56     // sout | "Symbol b: (20) " | valueE((B)B.b) | "," | valueE((AB)B.b) | nl;
    57     // sout | "Symbol ab: (30) " | valueE((AB)AB.ab) | nl;
    58     // sout | "Symbol c: (40) " | valueE((C)C.c) | "," | valueE((CD)C.c) | "," | valueE((ACD)C.c) | "," | valueE((CD)CD.c)| "," | valueE((ACD)CD.c) | nl;
    59     // sout | "Symbol d: (50) " | valueE((D)D.d) | "," | valueE((CD)D.d) | "," | valueE((ACD)D.d) | "," | valueE((ACD)CD.d) | nl;
    60     // sout | "Symbol cd: (60) " | valueE((CD)CD.cd) | "," | valueE((ACD)CD.cd) | nl;
    61     // sout | "Symbol acd: (70) " | valueE((ACD)ACD.acd) | nl;
     57    sout | "Casting/Upcasting:" | nl;
     58    sout | "Symbol a: (10) " | valueE((A)A.a) | "," | valueE((AB)A.a) | "," | valueE((ACD)A.a) | nl;
     59    sout | "Symbol b: (20) " | valueE((B)B.b) | "," | valueE((AB)B.b) | nl;
     60    sout | "Symbol ab: (30) " | valueE((AB)AB.ab) | nl;
     61    sout | "Symbol c: (40) " | valueE((C)C.c) | "," | valueE((CD)C.c) | "," | valueE((ACD)C.c) | "," | valueE((CD)CD.c)| "," | valueE((ACD)CD.c) | nl;
     62    sout | "Symbol d: (50) " | valueE((D)D.d) | "," | valueE((CD)D.d) | "," | valueE((ACD)D.d) | "," | valueE((ACD)CD.d) | nl;
     63    sout | "Symbol cd: (60) " | valueE((CD)CD.cd) | "," | valueE((ACD)CD.cd) | nl;
     64    sout | "Symbol acd: (70) " | valueE((ACD)ACD.acd) | nl;
    6265
    63     // sout | "Function Call:" | nl;
    64     // sout | "Symbol a: (10) " | identity(A.a) | "," | identity(ACD.a);
    65     // sout | "Symbol c: (40) " | identity(C.c) | "," | identity(CD.c)| "," | identity(ACD.c);
    66     identity(A.a);
    67 
     66    sout | "Function Call:" | nl;
     67    sout | "Symbol a: (10) " | identity_t(A.a) | "," | identity_t(ACD.a) | nl;
     68    sout | "Symbol c: (40) " | identity_t(C.c) | "," | identity_t(ACD.c) | nl;
     69    sout | "Symbol d: (50) " | identity_t(D.d) | "," | identity_t(ACD.d) | nl;
     70    sout | "Symbol cd: (60) " | identity_t(CD.cd) | "," | identity_t(ACD.cd) | nl;
     71    sout | "Symbol acd: (70) " | identity_t(ACD.acd) | nl;
    6872}
Note: See TracChangeset for help on using the changeset viewer.